/*
 * Generated by P2C
 * Version 1.00 - Copyright (C) 2002, Benjamin Rosseaux
 */
 /* program synth  */ 
/* A(CONSOLE) */   
#ifdef FPC   
/* M(DELPHI) */   
/* H(OFF) */   
#endif   
#undef CLEAN   
/* O(ON) */   

#define psingle struct single * 
     typedef byte *pbyte; 

     typedef wavehdr twavehdr; 

#define max4kchannels 16  

typedef struct t4kfiledata { 
      byte         waveform[max4kchannels - 1+1]; 
      byte         link[max4kchannels - 1+1]; 
      single       linkfactor[max4kchannels - 1+1]; 
      single       outfactor[max4kchannels - 1+1]; 
      single       startvolume[max4kchannels - 1+1]; 
      single       startvolumefactor[max4kchannels - 1+1]; 
      single       startphasefactor[max4kchannels - 1+1]; 
      byte         panning[max4kchannels - 1+1]; 
      integer      eventoffset[max4kchannels - 1+1]; 
      integer      noteoffset[max4kchannels - 1+1]; 
      integer      volumeoffset[max4kchannels - 1+1]; 
     } t4kfiledata;
     #undef psingle
     typedef struct single *psingle; 

     typedef struct t4kfilter { 
      single       fd1, fd2, fd3, fd4; 
      single       fblp, fbhp; 
      single       clp, chp; 
      single       rlp, rhp; 
     } t4kfilter; 

     typedef struct t4kadsrdata { 
      single       attackstep[max4kchannels - 1+1]; 
      single       decaystep[max4kchannels - 1+1]; 
      single       destdecay[max4kchannels - 1+1]; 
      boolean      sustain[max4kchannels - 1+1]; 
      single       releasestep[max4kchannels - 1+1]; 
     } t4kadsrdata; 

     typedef struct t4krealtimedata { 
      boolean      linkfirst[max4kchannels - 1+1]; 
      single       linkvalues[max4kchannels - 1+1]; 
      single       volume[max4kchannels - 1+1]; 
      single       volumevalue[max4kchannels - 1+1]; 
      single       volumefactor[max4kchannels - 1+1]; 
      single       channellastleft[max4kchannels - 1+1]; 
      single       channellastright[max4kchannels - 1+1]; 
      integer      adsrmode[max4kchannels - 1+1]; 
      single       adsrvalue[max4kchannels - 1+1]; 
      single       phase[max4kchannels - 1+1]; 
      single       phaseincrement[max4kchannels - 1+1]; 
      single       phasefactor[max4kchannels - 1+1]; 
      t4kfilter    filter[max4kchannels - 1+1]; 
      single       lastleft; 
      single       lastright; 
      longint      tickcounter[max4kchannels - 1+1]; 
      pbyte        
/* P2C: S.PAS(63): Warning: Redeclaration not identical, tok=eventoffset */
      eventoffset[max4kchannels - 1+1]; 
      pbyte        
/* P2C: S.PAS(64): Warning: Redeclaration not identical, tok=noteoffset */
      noteoffset[max4kchannels - 1+1]; 
      pbyte        
/* P2C: S.PAS(65): Warning: Redeclaration not identical, tok=volumeoffset */
      volumeoffset[max4kchannels - 1+1]; 
      longword     bpmsamples; 
      longword     currentbpmsamples; 
     } t4krealtimedata; 

     typedef byte t4keventdata[0x1FFFFF+1]; 

#ifdef TRACKER   
     typedef single t4koscil[0xFFFF+1]; 
#endif   

     #define p4ksynthdata struct t4ksynthdata * 
     typedef struct t4ksynthdata { 
      t4kfiledata  filedata; 
      t4kadsrdata  adsrdata; 
      t4keventdata eventdata; 
      t4krealtimedata realtimedata; 
#ifdef TRACKER   
      t4koscil     oscil[0xF+1]; 
#endif   
     } t4ksynthdata;
     #undef p4ksynthdata
     typedef struct t4ksynthdata *p4ksynthdata; 

#define samplerate 44100  
      #define sampleratefactor 440 / samplerate  
      #define portamentofactor sampleratefactor / 16  
      #define div8 1 / 8  
      #define div12 1 / 12  
      #define div64 1 / 64  
      #define div127 1 / 127  
      #define div255 1 / 255  
      #define div256 1 / 256  
      #define div65536 1 / 65536  
      #define cutofflowpassstartvalue 255 * div256  
      #define buffersize 4096  

twaveformatex waveformat  = {3,2,samplerate,
                                samplerate * 8,8,
                                32,0}; 

longword     waveouthandle; 
    twavehdr     wavehandler[4]; 
    longword     buffercounter; 
    integer      i; 
    longword     whitenoiseseed; 
    single       buffers[4][buffersize+1][2]; 
    t4ksynthdata synthdata; 


single       f_power(single       number,
                     single       exponent)
{ 
} 


single       whitenoiserandom(void)
{ longword     whitenoisevalue; 

 whitenoiseseed = (whitenoiseseed * 0x524281) + 0x3133731; 
 whitenoisevalue = (whitenoiseseed & 0x7FFFFF) | 0x40000000; 
 result = single(*pointer(&whitenoisevalue)) - 3; 
} 


void         synthreinit(t4ksynthdata * synthdata)
{ integer      channel; 

 for (channel = 0; channel <= max4kchannels - 1; channel++) { 
  if (synthdata->filedata.eventoffset[channel] > 0) { 
   synthdata->realtimedata.eventoffset[channel] = pointer(longword(synthdata) + longword(synthdata->filedata.eventoffset[channel])); 
   synthdata->realtimedata.noteoffset[channel] = pointer(longword(synthdata) + longword(synthdata->filedata.noteoffset[channel])); 
   synthdata->realtimedata.volumeoffset[channel] = pointer(longword(synthdata) + longword(synthdata->filedata.volumeoffset[channel])); 
   synthdata->realtimedata.tickcounter[channel] = 0; 
  } 
 } 
} 


void         synthrecalcfilter(t4kfilter *  filter)
{ 
 { void *with1 = filter; 
  with1->fblp = with1->rlp + with1->rlp / (1 - with1->clp); 
  with1->fbhp = with1->rhp + with1->rhp / (1 - with1->clp); 
    } 
 
} 


void         synthinit(t4ksynthdata * synthdata)
{ integer      channel; 

 synthreinit(synthdata); 
 for (channel = 0; channel <= max4kchannels - 1; channel++) { 
  synthdata->realtimedata.filter[channel].clp = cutofflowpassstartvalue; 
  synthrecalcfilter(&synthdata->realtimedata.filter[channel]); 
 } 
} 


/* P2C: S.PAS(160): Warning: Nested function, tok=synthfillbuffer */

void         synthfillbuffer(t4ksynthdata * synthdata,
                             psingle      buffer,
                             integer      buffersize)#ifdef FPC   { 
/* P2C: S.PAS(160): Error: Section header expected (psection), tok=[ */
#endif   
integer      position, channel, count, waveform; 
    single       phase, left, right, panningvalue, oscvalue, value; 
    longword     *phasecasted = &(phase); 
    byte         note, volume; 

 for (position = 0; position <= buffersize - 1; position++) { 
  count = max4kchannels; 
  left = 0; 
  right = 0; 
  FillChar(&synthdata->realtimedata.linkfirst,16,'\x01'); 
  for (channel = 0; channel <= max4kchannels - 1; channel++) { 
   if (synthdata->realtimedata.currentbpmsamples == 0) { 
    while (assigned(synthdata->realtimedata.eventoffset[channel]) && (synthdata->realtimedata.tickcounter[channel] >= *synthdata->realtimedata.eventoffset[channel])) { 
     synthdata->realtimedata.tickcounter[channel] = 0; 
     note = *synthdata->realtimedata.noteoffset[channel]; 
     volume = *synthdata->realtimedata.volumeoffset[channel]; 
     inc(synthdata->realtimedata.eventoffset[channel]); 
     inc(synthdata->realtimedata.noteoffset[channel]); 
     inc(synthdata->realtimedata.volumeoffset[channel]); 
     if ((note != 0) && (note <= 0x81)) { 
      if (note < 0x80) { 
       synthdata->realtimedata.lastleft = synthdata->realtimedata.lastleft + synthdata->realtimedata.channellastleft[channel]; 
       synthdata->realtimedata.lastright = synthdata->realtimedata.lastright + synthdata->realtimedata.channellastright[channel]; 
       synthdata->realtimedata.channellastleft[channel] = 0; 
       synthdata->realtimedata.channellastright[channel] = 0; 
       synthcalcnote(synthdata,channel,note); 
       synthdata->realtimedata.phasefactor[channel] = synthdata->filedata.startphasefactor[channel]; 
       synthdata->realtimedata.volume[channel] = synthdata->filedata.startvolume[channel]; 
       synthdata->realtimedata.volumefactor[channel] = synthdata->filedata.startvolumefactor[channel]; 
       synthdata->realtimedata.adsrmode[channel] = 1; 
       synthdata->realtimedata.adsrvalue[channel] = 0; 
      } 
      else if (note == 0x80) { 
       synthdata->realtimedata.adsrmode[channel] = 4; 
      } 
      if (volume <= 64) { 
       synthdata->realtimedata.volumevalue[channel] = volume * div64; 
      } 
     } 
     else { 
      value = volume * div256; 
      switch (note) {
       
       case 0x82:   synthdata->realtimedata.bpmsamples = (samplerate * 5 * 128) / (volume << 8); 
       break; 
       
       case 0x83:   synthdata->realtimedata.eventoffset[channel] = nil; 
       break; 
       
       case 0x84:   
       case 0x85:   { 
        oscvalue = volume * portamentofactor; 
        if (note == 0x84) oscvalue = -oscvalue; 
        synthdata->realtimedata.phaseincrement[channel] = synthdata->realtimedata.phaseincrement[channel] * (1 + oscvalue); 
       } 
       break; 
       
       case 0x86:   synthdata->filedata.panning[channel] = volume; 
       break; 
       
       case 0x87:   { 
        synthdata->realtimedata.filter[channel].clp = value; 
        synthrecalcfilter(&synthdata->realtimedata.filter[channel]); 
       } 
       break; 
       
       case 0x88:   { 
        synthdata->realtimedata.filter[channel].chp = value; 
        synthrecalcfilter(&synthdata->realtimedata.filter[channel]); 
       } 
       break; 
       
       case 0x89:   { 
        synthdata->realtimedata.filter[channel].rlp = value; 
        synthrecalcfilter(&synthdata->realtimedata.filter[channel]); 
       } 
       break; 
       
       case 0x90:   { 
        synthdata->realtimedata.filter[channel].rhp = value; 
        synthrecalcfilter(&synthdata->realtimedata.filter[channel]); 
       } 
       break; 
       
       case 0x91:   synthdata->realtimedata.phase[channel] = value * 2 * pi; 
       break; 
       
       case 0x92:   synthcalcnote(synthdata,channel,volume); 
      break; 
      } 
     } 
    } 
    if (!assigned(synthdata->realtimedata.eventoffset[channel])) dec(count); 
    inc(synthdata->realtimedata.tickcounter[channel]); 
   } 
   phase = frac(synthdata->realtimedata.phase[channel] + synthdata->realtimedata.linkvalues[channel]); 
   waveform = synthdata->filedata.waveform[channel]; 
   switch (waveform) {
    
    case 0:   oscvalue = sin(phase * 2 * pi);   /*  Sinus */ 
    break; 
    
    case 1:   oscvalue = abs((phase - 0.5) * 4) - 1;   /*  Triangle */ 
    break; 
    
    case 2:   {   /*  Square */ 
    phase = phase - 0.5; 
     oscvalue = longword((*phasecasted >> 31) << 1); 
     oscvalue = 1 - oscvalue; 
    } 
    break; 
    
    case 3:   
    case 4:   oscvalue = ((phase - 0.5) * 2) * integer(1 - ((waveform - 3) * 2));   /*  Sawtooth Up/Down */ 
    break; 
    
    case 5:   oscvalue = whitenoiserandom();   /*  White Noise */ 
    break; 
    
    default: oscvalue = 0;   /*  Nothing ;-) */ 
    } 
   oscvalue = oscvalue * synthdata->realtimedata.volume[channel] * synthdata->realtimedata.volumevalue[channel] * synthdata->realtimedata.adsrvalue[channel]; 
   { void *with1 = &synthdata->realtimedata.filter[channel]; 
    with1->fd1 = with1->fd1 + with1->clp * (oscvalue - with1->fd1 + with1->fblp * (with1->fd1 - with1->fd2)); 
    with1->fd2 = with1->fd2 + with1->clp * (with1->fd1 - with1->fd2); 
    with1->fd3 = with1->fd3 + with1->chp * (with1->fd2 - with1->fd3 + with1->fbhp * (with1->fd3 - with1->fd4)); 
    with1->fd4 = with1->fd4 + with1->chp * (with1->fd3 - with1->fd4); 
    oscvalue = with1->fd2 - with1->fd4; 
      } 
   
   switch (synthdata->realtimedata.adsrmode[channel]) {
    
    case 0:   { 
    } 
    break; 
    
    case 1:   { 
     if (synthdata->realtimedata.adsrvalue[channel] < 1) { 
      synthdata->realtimedata.adsrvalue[channel] = synthdata->realtimedata.adsrvalue[channel] + synthdata->adsrdata.attackstep[channel]; 
     } 
     else { 
      synthdata->realtimedata.adsrvalue[channel] = 1; 
      synthdata->realtimedata.adsrmode[channel] = 2; 
     } 
    } 
    break; 
    
    case 2:   { 
     if (synthdata->realtimedata.adsrvalue[channel] > synthdata->adsrdata.destdecay[channel]) { 
      synthdata->realtimedata.adsrvalue[channel] = synthdata->realtimedata.adsrvalue[channel] + synthdata->adsrdata.decaystep[channel]; 
     } 
     else { 
      synthdata->realtimedata.adsrvalue[channel] = synthdata->adsrdata.destdecay[channel]; 
      if (synthdata->adsrdata.sustain[channel]) { 
       synthdata->realtimedata.adsrmode[channel] = 3; 
      } 
      else { 
       synthdata->realtimedata.adsrmode[channel] = 4; 
      } 
     } 
    } 
    break; 
    
    case 3:   { 
    } 
    break; 
    
    case 4:   { 
     if (synthdata->realtimedata.adsrvalue[channel] > 0) { 
      synthdata->realtimedata.adsrvalue[channel] = synthdata->realtimedata.adsrvalue[channel] + synthdata->adsrdata.releasestep[channel]; 
     } 
     else { 
      synthdata->realtimedata.adsrmode[channel] = 0; 
     } 
    } 
   break; 
   } 
   if (synthdata->realtimedata.adsrvalue[channel] < 0) synthdata->realtimedata.adsrvalue[channel] = 0; 
   if (synthdata->realtimedata.adsrvalue[channel] > 1) synthdata->realtimedata.adsrvalue[channel] = 1; 
   if ((synthdata->filedata.link[channel] & 0x7F) < max4kchannels) { 
    if (synthdata->realtimedata.linkfirst[synthdata->filedata.link[channel] & 0x7F]) { 
     synthdata->realtimedata.linkvalues[synthdata->filedata.link[channel] & 0x7F] = 0; 
     synthdata->realtimedata.linkfirst[synthdata->filedata.link[channel] & 0x7F] = false; 
    } 
    synthdata->realtimedata.linkvalues[synthdata->filedata.link[channel] & 0x7F] = synthdata->realtimedata.linkvalues[synthdata->filedata.link[channel] & 0x7F] + (oscvalue * synthdata->filedata.linkfactor[channel]); 
   } 
   if ((synthdata->filedata.link[channel] & 0x80) != 0) { 
    value = oscvalue * synthdata->filedata.outfactor[channel]; 
    panningvalue = synthdata->filedata.panning[channel] * div255; 
#ifdef TRACKER   
    synthdata->oscil[channel][position] = value; 
#endif   
    oscvalue = value * panningvalue; 
    synthdata->realtimedata.channellastleft[channel] = oscvalue; 
    left = left + oscvalue; 
    oscvalue = value * (1 - panningvalue); 
    synthdata->realtimedata.channellastright[channel] = oscvalue; 
    right = right + oscvalue; 
#ifdef TRACKER   
   } 
   else { 
    synthdata->oscil[channel][position] = 0; 
#endif   
   } 
   synthdata->realtimedata.phase[channel] = frac(synthdata->realtimedata.phase[channel] + synthdata->realtimedata.phaseincrement[channel]); 
   synthdata->realtimedata.phaseincrement[channel] = synthdata->realtimedata.phaseincrement[channel] * synthdata->realtimedata.phasefactor[channel]; 
   synthdata->realtimedata.volume[channel] = synthdata->realtimedata.volume[channel] * synthdata->realtimedata.volumefactor[channel]; 
  } 
  if (synthdata->realtimedata.currentbpmsamples == 0) { 
   if (count == 0) synthreinit(synthdata); 
   synthdata->realtimedata.currentbpmsamples = synthdata->realtimedata.bpmsamples; 
  } 
  dec(synthdata->realtimedata.currentbpmsamples); 
  left = left + synthdata->realtimedata.lastleft; 
  synthdata->realtimedata.lastleft = synthdata->realtimedata.lastleft * 0.9; 
  right = right + synthdata->realtimedata.lastright; 
  synthdata->realtimedata.lastright = synthdata->realtimedata.lastright * 0.9; 
  *buffer = left * div8; 
  inc(buffer); 
  *buffer = right * div8; 
  inc(buffer); 
 } 
} 


/* P2C: S.PAS(334): Warning: Nested function, tok=synthload */

void         synthload(t4ksynthdata * synthdata)
{ 
 FillChar(synthdata,sizeof(t4ksynthdata),'\x00'); 
 Move(&trackdata,synthdata,tracksize); 
 synthinit(synthdata); 
} 


void         synthcalcnote(t4ksynthdata * synthdata,
                           integer      channel,
                           integer      note)#ifdef FPC   { 
/* P2C: S.PAS(155): Error: Section header expected (psection), tok=[ */
#endif   
{ 
 synthdata->realtimedata.phaseincrement[channel] = f_power(2,(note - 45) * div12) * sampleratefactor; 
} 


   /* Nested function: synthfillbuffer */ 

   /* Nested function: synthload */ 

 synthload(synthdata); 

 whitenoiseseed = 0x12345678; 

 waveoutopen(&waveouthandle,wave_mapper,&waveformat,0,0,0); 

 for (i = 0; i <= 3; i++) { 
  wavehandler[i].dwflags = whdr_done; 
  wavehandler[i].lpdata = &buffers[i]; 
  wavehandler[i].dwbufferlength = buffersize * 8; 
 } 

 buffercounter = 0; 
 while (true) { 
  if ((wavehandler[buffercounter].dwflags & whdr_done) != 0) { 
   if (waveoutunprepareheader(waveouthandle,&wavehandler[buffercounter],sizeof(twavehdr)) != waverr_stillplaying) { 
    wavehandler[buffercounter].dwflags = wavehandler[buffercounter].dwflags && !whdr_done; 
    synthfillbuffer(synthdata,wavehandler[buffercounter].lpdata,buffersize); 
    waveoutprepareheader(waveouthandle,&wavehandler[buffercounter],sizeof(twavehdr)); 
    waveoutwrite(waveouthandle,&wavehandler[buffercounter],sizeof(twavehdr)); 
    buffercounter = (buffercounter + 1) % 4; 
   } 
  } 
  else { 
   sleep(25); 
  } 
 } 

#ifdef CLEAN   
 for (i = 0; i <= 3; i++) { 
  while (waveoutunprepareheader(waveouthandle,&wavehandler[i],sizeof(twavehdr)) == waverr_stillplaying) { 
   sleep(25); 
  } 
 } 
 waveoutreset(waveouthandle); 
 waveoutclose(waveouthandle); 
#endif   
} 



