UNIT synth;
{-$APPTYPE CONSOLE}
{$IFDEF FPC}
{$MODE DELPHI}
{$HINTS OFF}
{$ENDIF}
{$UNDEF CLEAN}
{$O+}

INTERFACE

TYPE PSINGLE=^SINGLE;
     PBYTE=^BYTE;

CONST SampleRate=44100;
      DelayLen=$20000;
      SampleRateFactor=440/SampleRate;
      PortamentoFactor=SampleRateFactor/16;
      Div8=1/8;
      Div12=1/12;
      Div16=1/16;
      Div64=1/64;
      Div127=1/127;
      Div255=1/255;
      Div256=1/256;
      Div65536=1/65536;
      CutOffLowPassStartValue=255*Div256;

      BufferSize=2048;
      MaxSynthChannels=16;
      AddDenormalNoise=1.0E-24;

      ENVINC=64;

TYPE TSynthCallBackHook=PROCEDURE(Channel,Parameter:INTEGER);

     TSynthFileData=PACKED RECORD
      WaveForm:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      Link:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      LinkFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      OutFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      StartVolume:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      StartVolumeFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      StartPhaseFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      Panning:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      EventOffset:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      NoteOffset:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      VolumeOffset:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
     END;

     TSynthFilter=PACKED RECORD
      FD1,FD2,FD3,FD4:SINGLE;
      FBLP,FBHP:SINGLE;
      CLP,CHP:SINGLE;
      RLP,RHP:SINGLE;
     END;

     TSynthADSRData=PACKED RECORD
      AttackStep:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      DecayStep:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      DestDecay:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      Sustain:ARRAY[0..MaxSynthChannels-1] OF BOOLEAN;
      ReleaseStep:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
     END;

     TSynthVowelFilterMemory=ARRAY[0..4,0..9] OF DOUBLE;

     TSynthTB303Data=PACKED RECORD
      SampleRate:DOUBLE;
      CurrentCounter:INTEGER;
      MaxCounterValue:INTEGER;
      Mode:INTEGER;
      EnvPos:INTEGER;
      Waveform:INTEGER;
      IncValue:SINGLE;
      IncSrc:SINGLE;
      InternalCounter:SINGLE;
      CutOff:SINGLE;
      EnvMod:SINGLE;
      EnvDecayInfo:SINGLE;
      EnvDecay:SINGLE;
      Resonance:SINGLE;
      ResonanceCoeff:SINGLE;
      GlideSpeed:SINGLE;
      AccAmt:SINGLE;
      Attack:SINGLE;
      Decay:SINGLE;
      A0:SINGLE;
      A1:SINGLE;
      A2:SINGLE;
      B1:SINGLE;
      C0:SINGLE;
      E0:SINGLE;
      E1:SINGLE;
      D1:SINGLE;
      D2:SINGLE;
      Acc:BOOLEAN;
      Glide:BOOLEAN;
      NoteOff:BOOLEAN;
     END;
     TSynthTB303Datas=ARRAY[0..MaxSynthChannels-1] OF TSynthTB303Data;

     TSynthDelay=PACKED RECORD
      Active:BOOLEAN;
      InputIndex:INTEGER;
      OutputIndex:INTEGER;
      Time:INTEGER;
      FeedBack:SINGLE;
      Buffer:ARRAY[0..DelayLen-1] OF SINGLE;
     END;

     TSynthDelays=ARRAY[0..MaxSynthChannels-1] OF TSynthDelay;

     TSynthRealTimeData=PACKED RECORD
      TB303Data:TSynthTB303Datas;
      Delay:TSynthDelays;
      Distortion:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      Clipping:ARRAY[0..MaxSynthChannels-1] OF BOOLEAN;
      WaveForm:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      VowelFilter:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      VowelFilterMemory:ARRAY[0..MaxSynthChannels-1] OF TSynthVowelFilterMemory;
      FineTune:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      Harmony:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      ChorusDelayFactor:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      Note:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      LinkFirst:ARRAY[0..MaxSynthChannels-1] OF BYTE;
      LinkValues:ARRAY[0..7,0..MaxSynthChannels-1] OF SINGLE;
      FeedBackValue:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      FeedBackFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      Volume:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      VolumeValue:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      VolumeFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      ChannelLastLeft:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      ChannelLastRight:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      ADSRMode:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      ADSRValue:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      Phase:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      PhaseIncrement:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      PhaseFactor:ARRAY[0..MaxSynthChannels-1] OF SINGLE;
      Filter:ARRAY[0..MaxSynthChannels-1] OF TSynthFilter;
      LastLeft:SINGLE;
      LastRight:SINGLE;
      TickCounter:ARRAY[0..MaxSynthChannels-1] OF LONGINT;
      EventOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      NoteOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      VolumeOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartEventOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartNoteOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartVolumeOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      BPMSamples:LONGWORD;
      CurrentBPMSamples:LONGWORD;
      ShouldExit:BOOLEAN;
     END;

     TSynthEventData=ARRAY[0..$1FFFFF] OF BYTE;

{$IFDEF tracker}
     TSynthOscil=ARRAY[0..$FFFF] OF SINGLE;
{$ENDIF}

{$IFDEF seeking}
     TSynthRestartPoint=PACKED RECORD
      RestartEventOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartNoteOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartVolumeOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
      RestartTick:ARRAY[0..MaxSynthChannels-1] OF INTEGER;
      CurrentBPMSamples:INTEGER;
      BPMSamples:INTEGER;
      Samples:INT64;
     END;
{$ENDIF}

     PSynthData=^TSynthData;
     TSynthData=PACKED RECORD
      FileData:TSynthFileData;
      ADSRData:TSynthADSRData;
      InfoData:LONGWORD;
      EventData:TSynthEventData;
      RealtimeData:TSynthRealtimeData;
{$IFDEF tracker}
      Oscil:ARRAY[0..$F] OF TSynthOscil;
{$ENDIF}
{$IFDEF player}
{$IFDEF seeking}
      Samples:INT64;
      MaxSamples:INT64;
      Restart:BOOLEAN;
      RestartPoints:ARRAY[0..100] OF TSynthRestartPoint;
{$ENDIF}
      ActiveState:BOOLEAN;
      DestActiveState:BOOLEAN;
{$ENDIF}
      CallBackHook:TSynthCallBackHook;
     END;

     PSynthInfoData=^TSynthInfoData;
     TSynthInfoData=PACKED RECORD
      NameLength:LONGWORD;
      AuthorLength:LONGWORD;
      MessageLength:LONGWORD;
     END;

{$IFDEF tracker}
PROCEDURE SynthSetNoteEx(VAR SynthData:TSynthData;Channel,Note,SampleRate:INTEGER);
PROCEDURE SynthSetNote(VAR SynthData:TSynthData;Channel,Note,SampleRate:INTEGER);
PROCEDURE SynthSetHz(VAR SynthData:TSynthData;Channel,Volume:INTEGER);
PROCEDURE SynthSetVolume(VAR SynthData:TSynthData;Channel,Volume:INTEGER);
PROCEDURE SynthSetFeedBackFactor(VAR SynthData:TSynthData;Channel,FeedBackFactor:INTEGER);
PROCEDURE SynthSetFineTune(VAR SynthData:TSynthData;Channel,FineTune:INTEGER);
PROCEDURE SynthSetHarmony(VAR SynthData:TSynthData;Channel,Harmony:INTEGER);
PROCEDURE SynthSetVowelFilter(VAR SynthData:TSynthData;Channel,Vowel:INTEGER);
PROCEDURE SynthSetWaveForm(VAR SynthData:TSynthData;Channel,WaveForm:INTEGER);
PROCEDURE SynthSetDistortion(VAR SynthData:TSynthData;Channel,Distortion:INTEGER);
PROCEDURE SynthSetClipping(VAR SynthData:TSynthData;Channel,Clipping:INTEGER);
PROCEDURE SynthSetDelayActive(VAR SynthData:TSynthData;Channel,DelayActive:INTEGER);
PROCEDURE SynthSetDelayFeedBack(VAR SynthData:TSynthData;Channel,DelayFeedBack:INTEGER);
PROCEDURE SynthSetDelayTime(VAR SynthData:TSynthData;Channel,DelayTime:INTEGER);
PROCEDURE SynthSetDelayTimeDiv(VAR SynthData:TSynthData;Channel,DelayTimeDiv:INTEGER);
PROCEDURE SynthSetTB303WaveForm(VAR SynthData:TSynthData;Channel,WaveForm:INTEGER);
PROCEDURE SynthSetTB303CutOff(VAR SynthData:TSynthData;Channel,CutOff:INTEGER);
PROCEDURE SynthSetTB303Resonance(VAR SynthData:TSynthData;Channel,Resonance:INTEGER);
PROCEDURE SynthSetTB303EnvMod(VAR SynthData:TSynthData;Channel,EnvMod:INTEGER);
PROCEDURE SynthSetTB303EnvDecay(VAR SynthData:TSynthData;Channel,EnvDecay:INTEGER);
PROCEDURE SynthSetTB303GlideSpeed(VAR SynthData:TSynthData;Channel,GlideSpeed:INTEGER);
PROCEDURE SynthSetTB303Acc(VAR SynthData:TSynthData;Channel,Acc:INTEGER);
PROCEDURE SynthSetTB303Glide(VAR SynthData:TSynthData;Channel,Glide:INTEGER);
PROCEDURE SynthSetTB303AccAmt(VAR SynthData:TSynthData;Channel,AccAmt:INTEGER);
PROCEDURE SynthSetTB303NoteOff(VAR SynthData:TSynthData;Channel,NoteOff:INTEGER);
{$ENDIF}
PROCEDURE SynthInitData(VAR SynthData:TSynthData); STDCALL; {$IFDEF FPC}[public, alias : 'SynthInitData'];{$ENDIF}
PROCEDURE SynthRecalcFilter(VAR Filter:TSynthFilter); STDCALL; {$IFDEF FPC}[public, alias : 'SynthRecalcFilter'];{$ENDIF}
PROCEDURE SynthCopyInstrument(VAR SynthData:TSynthData;Dest,Src:INTEGER);
PROCEDURE SynthFillBuffer(VAR SynthData:TSynthData;DestBuffer:PSINGLE;StartPosition,BufferSize:INTEGER); STDCALL;
{$IFDEF player}
PROCEDURE SynthLoad(VAR SynthData:TSynthData;TrackData:POINTER;TrackSize:INTEGER); STDCALL; {$IFDEF FPC}[public, alias : 'SynthLoad'];{$ENDIF}
PROCEDURE SynthInit(VAR SynthData:TSynthData;TrackData:POINTER;TrackSize:INTEGER;CallBackHook:TSynthCallBackHook=NIL); STDCALL;
FUNCTION SynthPoll(VAR SynthData:TSynthData):BOOLEAN; STDCALL;
PROCEDURE SynthDone(VAR SynthData:TSynthData); STDCALL;
{$IFNDEF smallplayer}
FUNCTION SynthGetName(VAR Data):STRING; STDCALL;
FUNCTION SynthGetAuthor(VAR Data):STRING; STDCALL;
FUNCTION SynthGetMessage(VAR Data):STRING; STDCALL;
{$ENDIF}
{$IFDEF seeking}
PROCEDURE SynthSeeking(VAR SynthData:TSynthData;Percent:INTEGER);
{$ENDIF}
{$ELSE}
PROCEDURE SynthInit; STDCALL;
{$ENDIF}
FUNCTION TRUNCINT(X:SINGLE):INTEGER; STDCALL;

IMPLEMENTATION

{$IFDEF player}
USES Windows,MMSYSTEM;

CONST WaveFormat:TWaveFormatEx=(wFormatTag:3;nChannels:2;nSamplesPerSec:SampleRate;
                                nAvgBytesPerSec:SampleRate*8;nBlockAlign:8;
                                wBitsPerSample:32;cbSize:0);

VAR WaveOutHandle:LONGWORD;
    WaveHandler:ARRAY[0..3] OF TWAVEHDR;
    BufferCounter:LONGWORD;
    Buffers:ARRAY[0..3,0..BufferSize,0..1] OF SINGLE;
{$ENDIF}
VAR WhiteNoiseSeed:LONGWORD;

CONST VowelFilterCoefficients:ARRAY[0..4,0..10] OF DOUBLE=((8.11044e-06,8.943665402,-36.83889529,92.01697887,-154.337906,181.6233289,-151.8651235,89.09614114,-35.10298511,8.388101016,-0.923313471),
                                                           (4.36215e-06,8.90438318,-36.55179099,91.05750846,-152.422234,179.1170248,-149.6496211,87.78352223,-34.60687431,8.282228154,-0.914150747),
                                                           (3.33819e-06,8.893102966,-36.49532826,90.96543286,-152.4545478,179.4835618,-150.315433,88.43409371,-34.98612086,8.407803364,-0.932568035),
                                                           (1.13572e-06,8.994734087,-37.2084849,93.22900521,-156.6929844,184.596544,-154.3755513,90.49663749,-35.58964535,8.478996281,-0.929252233),
                                                           (4.09431e-07,8.997322763,-37.20218544,93.11385476,-156.2530937,183.7080141,-153.2631681,89.59539726,-35.12454591,8.338655623,-0.910251753));

FUNCTION F_POWER(Number,Exponent:SINGLE):SINGLE; ASSEMBLER; STDCALL;
ASM
 FLD Exponent
 FLD Number
 FYL2X
 FLD1
 FLD ST(1)
 FPREM
 F2XM1
 FADDP ST(1),ST
 FSCALE
 FSTP ST(1)
END;

FUNCTION WhiteNoiseRandom:SINGLE; STDCALL;
VAR WhiteNoiseValue:LONGWORD;
BEGIN
 WhiteNoiseSeed:=(WhiteNoiseSeed*$524281)+$3133731;
 WhiteNoiseValue:=(WhiteNoiseSeed AND $7FFFFF) OR $40000000;
 RESULT:=SINGLE(POINTER(@WhiteNoiseValue)^)-3;
END;

FUNCTION TRUNCINT(X:SINGLE):INTEGER; STDCALL;
BEGIN
 ASM
  FLD DWORD PTR X
  FRNDINT
  FISTP DWORD PTR RESULT
 END;
END;

FUNCTION FRAC(X:SINGLE):SINGLE; STDCALL;
VAR Y:SINGLE;
BEGIN
 Y:=X;
 ASM
  FLD DWORD PTR Y
  FRNDINT
  FSTP DWORD PTR Y
 END;
 RESULT:=X-Y;
END;

PROCEDURE SynthTB303ResetValues(VAR TB303Data:TSynthTB303Data);
BEGIN
 WITH TB303Data DO BEGIN
  E1:=EXP(6.109+1.5876*EnvMod+2.1553*CutOff-1.2*(1.0-Resonance));
  E0:=EXP(5.613-0.8*EnvMod+2.1553*CutOff-0.7696*(1.0-Resonance));
  E0:=E0*PI/SampleRate;
  E1:=E1*PI/SampleRate;
  E1:=E1-E0;
  EnvPos:=ENVINC;
 END;
END;

PROCEDURE SynthTB303SetCutOff(VAR TB303Data:TSynthTB303Data;ACutOff:SINGLE);
BEGIN
 TB303Data.CutOff:=ACutOff;
 SynthTB303ResetValues(TB303Data);
END;

PROCEDURE SynthTB303SetResonance(VAR TB303Data:TSynthTB303Data;AResonance:SINGLE);
BEGIN
 WITH TB303Data DO BEGIN
  Resonance:=AResonance;
  ResonanceCoeff:=EXP(-1.20+3.455*Resonance);
 END;
 SynthTB303ResetValues(TB303Data);
END;

PROCEDURE SynthTB303SetEnvMod(VAR TB303Data:TSynthTB303Data;AEnvMod:SINGLE);
BEGIN
 TB303Data.EnvMod:=AEnvMod;
 SynthTB303ResetValues(TB303Data);
END;

PROCEDURE SynthTB303SetEnvDecay(VAR TB303Data:TSynthTB303Data;AEnvDecay:SINGLE);
BEGIN
 WITH TB303Data DO BEGIN
  EnvDecay:=AEnvDecay;
  EnvDecayInfo:=(0.2+(2.3*EnvDecay))*SampleRate;
  IF EnvDecayInfo<1 THEN EnvDecayInfo:=1;
  EnvDecayInfo:=F_POWER(0.1,1/EnvDecayInfo*ENVINC);
 END;
END;

FUNCTION SynthTB303Process(VAR TB303Data:TSynthTB303Data;IncDest,AdditionalDest:SINGLE):SINGLE;
VAR W,K,X:SINGLE;
    XCasted:LONGWORD ABSOLUTE X;
BEGIN
 WITH TB303Data DO BEGIN
  IF EnvPos>=ENVINC THEN BEGIN
   W:=E0+C0;
   K:=EXP(-W/ResonanceCoeff);
   C0:=C0*EnvDecayInfo;
   A1:=2*COS(2*W)*K;
   B1:=-K*K;
   C0:=1-A1-B1;
   EnvPos:=0;
  END;
  IF AdditionalDest<>0 THEN BEGIN
   X:=InternalCounter+AdditionalDest;
   WHILE X>0.5 DO X:=X-1;
  END ELSE BEGIN
   X:=InternalCounter;
  END;
  CASE Waveform OF
   1:BEGIN
    X:=LONGWORD((XCasted SHR 31) SHL 1);
    X:=((1-X)*0.5);
   END;
   2:X:=SIN(X*4*PI)*0.5;
   3:X:=(ABS(((X*2)-0.5)*4)-1)*0.5;
   4,5:X:=((((X*2)-0.5)*2)*INTEGER(1-((WaveForm-4)*2)))*0.5;
  END;
  RESULT:=A1*D1+B1*D2+C0*X*A2;
  D2:=D1;
  EnvPos:=EnvPos+1;
  D1:=RESULT;

  INC(CurrentCounter);
  W:=CurrentCounter/MaxCounterValue;
  IF W<1 THEN BEGIN
   K:=IncSrc*(1-W)+W*IncDest;
  END ELSE BEGIN
   IncValue:=IncDest;
   K:=IncValue;
  END;

  InternalCounter:=InternalCounter+K;
  IF InternalCounter>0.5 THEN InternalCounter:=InternalCounter-1;

  CASE Mode OF
   0:A2:=A2+(A0-A2)*Attack;
   1:BEGIN
    A2:=A2*Decay;
    IF A2<(1/65536) THEN BEGIN
     A2:=0;
     Mode:=2;
    END;
   END;
   ELSE BEGIN
   END;
  END;
 END;
END;

PROCEDURE SynthTB303NoteOn(VAR TB303Data:TSynthTB303Data);
BEGIN
 WITH TB303Data DO BEGIN
  IncSrc:=IncValue;
  MaxCounterValue:=TRUNCINT(SampleRate*GlideSpeed);
  IF MaxCounterValue=0 THEN MaxCounterValue:=1;
  IF Glide THEN BEGIN
   CurrentCounter:=0;
  END ELSE BEGIN
   CurrentCounter:=MaxCounterValue-1;
  END;
  Mode:=0;
  C0:=E1;
  EnvPos:=ENVINC;
  A0:=0.5;
  IF Acc THEN A0:=A0+AccAmt*0.5;
 END;
END;

PROCEDURE SynthTB303NoteOff(VAR TB303Data:TSynthTB303Data);
BEGIN
 WITH TB303Data DO BEGIN
  IF NoteOff THEN BEGIN
   A2:=0;
   Mode:=2;
  END;
 END;
END;

PROCEDURE SynthTB303Create(VAR TB303Data:TSynthTB303Data;ASampleRate:DOUBLE);
BEGIN
 WITH TB303Data DO BEGIN
  SampleRate:=ASampleRate;
  IncValue:=SampleRateFactor;
  Waveform:=0;
  InternalCounter:=0;
  CutOff:=0;
  EnvMod:=0;
  Resonance:=0;
  EnvDecayInfo:=0;
  EnvPos:=ENVINC;
  A0:=0.5;
  A1:=0;
  A2:=0;
  B1:=0;
  C0:=0;
  D1:=0;
  D2:=0;
  E0:=0;
  E1:=0;
  Mode:=2;
  ResonanceCoeff:=1;
  Attack:=1-0.94406088;
  Decay:=0.99897516;
  AccAmt:=0.5;
  GlideSpeed:=0.1;
  SynthTB303SetCutOff(TB303Data,0.9);
  SynthTB303SetResonance(TB303Data,0.1);
  SynthTB303SetEnvMod(TB303Data,1);
  SynthTB303SetEnvDecay(TB303Data,0.1);
  MaxCounterValue:=1;
 END;
END;

PROCEDURE SynthReinit(VAR SynthData:TSynthData); STDCALL; {$IFDEF FPC}[public, alias : 'SynthReinit'];{$ENDIF}
VAR Channel:INTEGER;
BEGIN
 FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
  SynthData.RealtimeData.EventOffset[Channel]:=SynthData.RealtimeData.RestartEventOffset[Channel];
  SynthData.RealtimeData.NoteOffset[Channel]:=SynthData.RealtimeData.RestartNoteOffset[Channel];
  SynthData.RealtimeData.VolumeOffset[Channel]:=SynthData.RealtimeData.RestartVolumeOffset[Channel];
  SynthData.RealtimeData.TickCounter[Channel]:=0;
 END;
 SynthData.RealtimeData.ShouldExit:=TRUE;
END;

PROCEDURE SynthRecalcFilter(VAR Filter:TSynthFilter); STDCALL; {$IFDEF FPC}[public, alias : 'SynthRecalcFilter'];{$ENDIF}
BEGIN
 WITH Filter DO BEGIN
  FBLP:=(RLP+RLP/(1-CLP))+AddDenormalNoise;
  FBHP:=(RHP+RHP/(1-CLP))+AddDenormalNoise;
 END;
END;

PROCEDURE SynthInitData(VAR SynthData:TSynthData); STDCALL; {$IFDEF FPC}[public, alias : 'SynthInitData'];{$ENDIF}
VAR Channel:INTEGER;
BEGIN
 FILLCHAR(SynthData.RealtimeData,SIZEOF(TSynthRealtimeData),#0);
 FILLCHAR(SynthData.RealtimeData.Note,16,#$FF);
 FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
  SynthTB303Create(SynthData.RealtimeData.TB303Data[Channel],SampleRate);
  SynthData.RealtimeData.LinkValues[1,Channel]:=1;
  SynthData.RealtimeData.LinkValues[2,Channel]:=1;
  SynthData.RealtimeData.WaveForm[Channel]:=SynthData.FileData.WaveForm[Channel];
 END;
 FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
  IF SynthData.FileData.EventOffset[Channel]>0 THEN BEGIN
   SynthData.RealtimeData.RestartEventOffset[Channel]:=POINTER(LONGWORD(@SynthData)+LONGWORD(SynthData.FileData.EventOffset[Channel]));
   SynthData.RealtimeData.RestartNoteOffset[Channel]:=POINTER(LONGWORD(@SynthData)+LONGWORD(SynthData.FileData.NoteOffset[Channel]));
   SynthData.RealtimeData.RestartVolumeOffset[Channel]:=POINTER(LONGWORD(@SynthData)+LONGWORD(SynthData.FileData.VolumeOffset[Channel]));
  END;
  SynthData.RealtimeData.Filter[Channel].CLP:=CutOffLowPassStartValue;
  SynthRecalcFilter(SynthData.RealtimeData.Filter[Channel]);
 END;
 SynthReinit(SynthData);
 SynthData.RealtimeData.ShouldExit:=FALSE;
END;

PROCEDURE SynthCalcNote(VAR SynthData:TSynthData;Channel,Note:INTEGER); STDCALL; {$IFDEF FPC}[public, alias : 'SynthCalcNote'];{$ENDIF}
BEGIN
 SynthData.RealtimeData.Note[Channel]:=Note;
 IF SynthData.RealtimeData.Harmony[Channel]<>0 THEN BEGIN
  SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128)+(1/SynthData.RealtimeData.Harmony[Channel]))/12)*SampleRateFactor;
 END ELSE BEGIN
  SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128))/12)*SampleRateFactor;
 END;
 SynthTB303NoteOn(SynthData.RealtimeData.TB303Data[Channel]);
END;

PROCEDURE SynthSetNoteEx(VAR SynthData:TSynthData;Channel,Note,SampleRate:INTEGER);
BEGIN
 IF Note<$80 THEN BEGIN
  SynthData.RealtimeData.Note[Channel]:=Note;
  IF SynthData.RealtimeData.Harmony[Channel]<>0 THEN BEGIN
   SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128)+(1/SynthData.RealtimeData.Harmony[Channel]))/12)*SampleRateFactor;
  END ELSE BEGIN
   SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128))/12)*SampleRateFactor;
  END;
  SynthTB303NoteOn(SynthData.RealtimeData.TB303Data[Channel]);
 END;
END;

PROCEDURE SynthSetNote(VAR SynthData:TSynthData;Channel,Note,SampleRate:INTEGER);
BEGIN
 IF Note<$80 THEN BEGIN
  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;
  SynthData.RealtimeData.Note[Channel]:=Note;
  IF SynthData.RealtimeData.Harmony[Channel]<>0 THEN BEGIN
   SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128)+(1/SynthData.RealtimeData.Harmony[Channel]))/12)*SampleRateFactor;
  END ELSE BEGIN
   SynthData.RealtimeData.PhaseIncrement[Channel]:=F_POWER(2,((Note-45)+(SynthData.RealtimeData.FineTune[Channel]/128))/12)*SampleRateFactor;
  END;
  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;
  IF SynthData.ADSRData.AttackStep[Channel]=0 THEN BEGIN
   SynthData.RealtimeData.ADSRValue[Channel]:=1;
  END ELSE BEGIN
   SynthData.RealtimeData.ADSRValue[Channel]:=0;
  END;
  SynthTB303NoteOn(SynthData.RealtimeData.TB303Data[Channel]);
 END ELSE IF Note=$80 THEN BEGIN
  SynthData.RealtimeData.ADSRMode[Channel]:=4;
  SynthTB303NoteOff(SynthData.RealtimeData.TB303Data[Channel]);
 END;
END;

PROCEDURE SynthSetHz(VAR SynthData:TSynthData;Channel,Volume:INTEGER);
BEGIN
 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;
 SynthData.RealtimeData.Note[Channel]:=0;
 SynthData.RealtimeData.PhaseIncrement[Channel]:=SampleRate/(Volume+1);
 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;
 IF SynthData.ADSRData.AttackStep[Channel]=0 THEN BEGIN
  SynthData.RealtimeData.ADSRValue[Channel]:=1;
 END ELSE BEGIN
  SynthData.RealtimeData.ADSRValue[Channel]:=0;
 END;
 SynthTB303NoteOn(SynthData.RealtimeData.TB303Data[Channel]);
END;

PROCEDURE SynthSetVolume(VAR SynthData:TSynthData;Channel,Volume:INTEGER);
BEGIN
 SynthData.RealtimeData.VolumeValue[Channel]:=Volume/64;
END;

PROCEDURE SynthSetFeedBackFactor(VAR SynthData:TSynthData;Channel,FeedBackFactor:INTEGER);
BEGIN
 SynthData.RealtimeData.FeedBackFactor[Channel]:=FeedBackFactor/$FF;
END;

PROCEDURE SynthSetVowelFilter(VAR SynthData:TSynthData;Channel,Vowel:INTEGER);
BEGIN
 CASE Vowel OF
  0..5:SynthData.RealtimeData.VowelFilter[Channel]:=Vowel;
 END;
END;

PROCEDURE SynthSetWaveForm(VAR SynthData:TSynthData;Channel,WaveForm:INTEGER);
BEGIN
 SynthData.RealtimeData.WaveForm[Channel]:=WaveForm;
END;

PROCEDURE SynthSetDistortion(VAR SynthData:TSynthData;Channel,Distortion:INTEGER);
BEGIN
 SynthData.RealtimeData.Distortion[Channel]:=Distortion;
END;

PROCEDURE SynthSetClipping(VAR SynthData:TSynthData;Channel,Clipping:INTEGER);
BEGIN
 CASE Clipping OF
  0..1:SynthData.RealtimeData.Clipping[Channel]:=Clipping<>0;
 END;
END;

PROCEDURE SynthSetDelayActive(VAR SynthData:TSynthData;Channel,DelayActive:INTEGER);
BEGIN
 CASE DelayActive OF
  0..1:SynthData.RealtimeData.Delay[Channel].Active:=DelayActive<>0;
  2:FILLCHAR(SynthData.RealtimeData.Delay[Channel].Buffer,SIZEOF(SynthData.RealtimeData.Delay[Channel].Buffer),#0);
 END;
END;

PROCEDURE SynthSetDelayFeedBack(VAR SynthData:TSynthData;Channel,DelayFeedBack:INTEGER);
BEGIN
 SynthData.RealtimeData.Delay[Channel].FeedBack:=DelayFeedBack/$FF;
END;

PROCEDURE SynthSetDelayTime(VAR SynthData:TSynthData;Channel,DelayTime:INTEGER);
BEGIN
 SynthData.RealtimeData.Delay[Channel].Time:=INTEGER(SynthData.RealtimeData.BPMSamples)*DelayTime;
END;

PROCEDURE SynthSetDelayTimeDiv(VAR SynthData:TSynthData;Channel,DelayTimeDiv:INTEGER);
BEGIN
 SynthData.RealtimeData.Delay[Channel].Time:=SynthData.RealtimeData.Delay[Channel].Time DIV (DelayTimeDiv+1);
END;

PROCEDURE SynthSetTB303WaveForm(VAR SynthData:TSynthData;Channel,WaveForm:INTEGER);
BEGIN
 SynthData.RealtimeData.TB303Data[Channel].WaveForm:=WaveForm;
END;

PROCEDURE SynthSetTB303CutOff(VAR SynthData:TSynthData;Channel,CutOff:INTEGER);
BEGIN
 SynthTB303SetCutOff(SynthData.RealtimeData.TB303Data[Channel],CutOff/$FF);
END;

PROCEDURE SynthSetTB303Resonance(VAR SynthData:TSynthData;Channel,Resonance:INTEGER);
BEGIN
 SynthTB303SetResonance(SynthData.RealtimeData.TB303Data[Channel],Resonance/$FF);
END;

PROCEDURE SynthSetTB303EnvMod(VAR SynthData:TSynthData;Channel,EnvMod:INTEGER);
BEGIN
 SynthTB303SetEnvMod(SynthData.RealtimeData.TB303Data[Channel],EnvMod/$FF);
END;

PROCEDURE SynthSetTB303EnvDecay(VAR SynthData:TSynthData;Channel,EnvDecay:INTEGER);
BEGIN
 SynthTB303SetEnvDecay(SynthData.RealtimeData.TB303Data[Channel],EnvDecay/$FF);
END;

PROCEDURE SynthSetTB303GlideSpeed(VAR SynthData:TSynthData;Channel,GlideSpeed:INTEGER);
BEGIN
 SynthData.RealtimeData.TB303Data[Channel].GlideSpeed:=GlideSpeed/$FF;
END;

PROCEDURE SynthSetTB303Acc(VAR SynthData:TSynthData;Channel,Acc:INTEGER);
BEGIN
 CASE Acc OF
  0..1:SynthData.RealtimeData.TB303Data[Channel].Acc:=Acc<>0;
 END;
END;

PROCEDURE SynthSetTB303Glide(VAR SynthData:TSynthData;Channel,Glide:INTEGER);
BEGIN
 CASE Glide OF
  0..1:SynthData.RealtimeData.TB303Data[Channel].Glide:=Glide<>0;
 END;
END;

PROCEDURE SynthSetTB303AccAmt(VAR SynthData:TSynthData;Channel,AccAmt:INTEGER);
BEGIN
 SynthData.RealtimeData.TB303Data[Channel].AccAmt:=AccAmt/$FF;
END;

PROCEDURE SynthSetTB303NoteOff(VAR SynthData:TSynthData;Channel,NoteOff:INTEGER);
BEGIN
 CASE NoteOff OF
  0..1:SynthData.RealtimeData.TB303Data[Channel].NoteOff:=NoteOff<>0;
 END;
END;

PROCEDURE SynthSetFineTune(VAR SynthData:TSynthData;Channel,FineTune:INTEGER);
BEGIN
 SynthData.RealTimeData.FineTune[Channel]:=FineTune-128;
 SynthCalcNote(SynthData,Channel,SynthData.RealtimeData.Note[Channel]);
END;

PROCEDURE SynthSetHarmony(VAR SynthData:TSynthData;Channel,Harmony:INTEGER);
BEGIN
 SynthData.RealTimeData.Harmony[Channel]:=Harmony-128;
 SynthCalcNote(SynthData,Channel,SynthData.RealtimeData.Note[Channel]);
END;

PROCEDURE SynthCopyInstrument(VAR SynthData:TSynthData;Dest,Src:INTEGER);
BEGIN
 SynthData.RealtimeData.WaveForm[Dest]:=SynthData.RealtimeData.WaveForm[Src];
 SynthData.FileData.WaveForm[Dest]:=SynthData.FileData.WaveForm[Src];
 SynthData.FileData.StartVolume[Dest]:=SynthData.FileData.StartVolume[Src];
 SynthData.FileData.StartVolumeFactor[Dest]:=SynthData.FileData.StartVolumeFactor[Src];
 SynthData.FileData.StartPhaseFactor[Dest]:=SynthData.FileData.StartPhaseFactor[Src];
 SynthData.FileData.OutFactor[Dest]:=SynthData.FileData.OutFactor[Src];
 SynthData.FileData.LinkFactor[Dest]:=SynthData.FileData.LinkFactor[Src];
 SynthData.ADSRData.AttackStep[Dest]:=SynthData.ADSRData.AttackStep[Src];
 SynthData.ADSRData.DecayStep[Dest]:=SynthData.ADSRData.DecayStep[Src];
 SynthData.ADSRData.DestDecay[Dest]:=SynthData.ADSRData.DestDecay[Src];
 SynthData.ADSRData.ReleaseStep[Dest]:=SynthData.ADSRData.ReleaseStep[Src];
 SynthData.ADSRData.Sustain[Dest]:=SynthData.ADSRData.Sustain[Src];
 SynthData.FileData.Link[Dest]:=SynthData.FileData.Link[Src];
 SynthData.RealtimeData.Filter[Dest]:=SynthData.RealtimeData.Filter[Src];
 SynthRecalcFilter(SynthData.RealtimeData.Filter[Dest]);
 SynthData.RealtimeData.VowelFilter[Dest]:=SynthData.RealtimeData.VowelFilter[Src];
 SynthData.RealtimeData.FineTune[Dest]:=SynthData.RealtimeData.FineTune[Src];
 SynthData.RealtimeData.Harmony[Dest]:=SynthData.RealtimeData.Harmony[Src];
 IF SynthData.RealtimeData.Note[Dest]<$80 THEN BEGIN
  SynthCalcNote(SynthData,Dest,SynthData.RealtimeData.Note[Dest]);
 END;
END;

PROCEDURE SynthDoEffects(VAR SynthData:TSynthData;CONST Channel:INTEGER;VAR OscValue:SINGLE); REGISTER;
VAR VowelFilter,RealTime:INTEGER;
BEGIN
 VowelFilter:=SynthData.RealtimeData.VowelFilter[Channel];
 IF VowelFilter<>0 THEN BEGIN
  DEC(VowelFilter);
  OscValue:=(VowelFilterCoefficients[VowelFilter,0]*OscValue+
             VowelFilterCoefficients[VowelFilter,1]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,0]+
             VowelFilterCoefficients[VowelFilter,2]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,1]+
             VowelFilterCoefficients[VowelFilter,3]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,2]+
             VowelFilterCoefficients[VowelFilter,4]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,3]+
             VowelFilterCoefficients[VowelFilter,5]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,4]+
             VowelFilterCoefficients[VowelFilter,6]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,5]+
             VowelFilterCoefficients[VowelFilter,7]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,6]+
             VowelFilterCoefficients[VowelFilter,8]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,7]+
             VowelFilterCoefficients[VowelFilter,9]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,8]+
             VowelFilterCoefficients[VowelFilter,10]*SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,9])+AddDenormalNoise;
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,9]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,8];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,8]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,7];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,7]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,6];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,6]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,5];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,5]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,4];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,4]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,3];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,3]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,2];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,2]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,1];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,1]:=SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,0];
  SynthData.RealtimeData.VowelFilterMemory[Channel,VowelFilter,0]:=OscValue;
 END;
 IF SynthData.RealtimeData.Distortion[Channel]<>0 THEN BEGIN
  OscValue:=OscValue*(1+(SynthData.RealtimeData.Distortion[Channel]*0.5));
 END;
 IF SynthData.RealtimeData.Clipping[Channel] THEN BEGIN
  IF OscValue<-1 THEN OscValue:=-1;
  IF OscValue>1 THEN OscValue:=1;
 END;
 WITH SynthData.RealtimeData.Delay[Channel] DO BEGIN
  IF Active THEN BEGIN
   OutputIndex:=(OutputIndex+1) AND (DelayLen-1);
   RealTime:=Time;
   IF SynthData.RealtimeData.LinkValues[5,Channel]<>0 THEN BEGIN
    INC(RealTime,TRUNCINT((1+SynthData.RealtimeData.LinkValues[5,Channel])*(64*(SynthData.RealtimeData.ChorusDelayFactor[Channel]+1))));
   END;
   InputIndex:=(OutputIndex+RealTime) AND (DelayLen-1);
   OscValue:=OscValue+(Buffer[OutputIndex]*FeedBack);
   Buffer[InputIndex]:=OscValue;
  END;
 END;
END;

PROCEDURE SynthFillBuffer(VAR SynthData:TSynthData;DestBuffer:PSINGLE;StartPosition,BufferSize:INTEGER); STDCALL; {$IFDEF FPC}[public, alias : 'SynthFillBuffer'];{$ENDIF}
VAR Position,Channel,Count,WaveForm:INTEGER;
    Phase,AdditionalPhase,Left,Right,PanningValue,OscValue,Value:SINGLE;
{$IFDEF player}
    AmpiferFactor,AmpiferStep:SINGLE;
{$ENDIF}
    PhaseCasted:LONGWORD ABSOLUTE Phase;
    Note,Volume,LinkChannel,LinkType:BYTE;
    Buffer:PSINGLE;
BEGIN
 Buffer:=DestBuffer;
{$IFDEF tracker}
 FOR Position:=0 TO BufferSize-1 DO BEGIN
{$ELSE}
 FOR Position:=1 TO BufferSize DO BEGIN
{$ENDIF}
  Count:=MaxSynthChannels;
  Left:=0;
  Right:=0;
  FILLCHAR(SynthData.RealtimeData.LinkFirst,16,#0);
  FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
   IF SynthData.RealtimeData.CurrentBPMSamples=0 THEN BEGIN
    WHILE ASSIGNED(SynthData.RealtimeData.EventOffset[Channel]) AND (SynthData.RealtimeData.TickCounter[Channel]>=SynthData.RealtimeData.EventOffset[Channel]^) DO BEGIN
     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<=$81 THEN BEGIN
      IF Note<$80 THEN BEGIN
       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;
       IF SynthData.ADSRData.AttackStep[Channel]=0 THEN BEGIN
        SynthData.RealtimeData.ADSRValue[Channel]:=1;
       END ELSE BEGIN
        SynthData.RealtimeData.ADSRValue[Channel]:=0;
       END;
      END ELSE IF Note=$80 THEN BEGIN
       SynthData.RealtimeData.ADSRMode[Channel]:=4;
       SynthTB303NoteOff(SynthData.RealtimeData.TB303Data[Channel]);
      END;
      IF Volume<=64 THEN BEGIN
       SynthData.RealtimeData.VolumeValue[Channel]:=Volume/64;
      END;
     END ELSE BEGIN
      Value:=Volume/256;
      CASE Note OF
       $82:SynthData.RealtimeData.BPMSamples:=(SampleRate*5*128) DIV (Volume SHL 8);
       $83:SynthData.RealtimeData.EventOffset[Channel]:=NIL;
       $84:BEGIN
        OscValue:=Volume*PortamentoFactor;
        SynthData.RealtimeData.PhaseIncrement[Channel]:=SynthData.RealtimeData.PhaseIncrement[Channel]*(1-OscValue);
       END;
       $85:BEGIN
        OscValue:=Volume*PortamentoFactor;
        SynthData.RealtimeData.PhaseIncrement[Channel]:=SynthData.RealtimeData.PhaseIncrement[Channel]*(1+OscValue);
       END;
       $86:SynthData.FileData.Panning[Channel]:=Volume;
       $87:BEGIN
        SynthData.RealtimeData.Filter[Channel].CLP:=Value;
        SynthRecalcFilter(SynthData.RealtimeData.Filter[Channel]);
       END;
       $88:BEGIN
        SynthData.RealtimeData.Filter[Channel].CHP:=Value;
        SynthRecalcFilter(SynthData.RealtimeData.Filter[Channel]);
       END;
       $89:BEGIN
        SynthData.RealtimeData.Filter[Channel].RLP:=Value;
        SynthRecalcFilter(SynthData.RealtimeData.Filter[Channel]);
       END;
       $90:BEGIN
        SynthData.RealtimeData.Filter[Channel].RHP:=Value;
        SynthRecalcFilter(SynthData.RealtimeData.Filter[Channel]);
       END;
       $91:SynthData.RealTimeData.Phase[Channel]:=Value*2*PI;
       $92:SynthCalcNote(SynthData,Channel,Volume);
       $93:BEGIN
        SynthData.RealtimeData.RestartEventOffset[Channel]:=SynthData.RealtimeData.EventOffset[Channel];
        SynthData.RealtimeData.RestartNoteOffset[Channel]:=SynthData.RealtimeData.NoteOffset[Channel];
        SynthData.RealtimeData.RestartVolumeOffset[Channel]:=SynthData.RealtimeData.VolumeOffset[Channel];
       END;
       $94:SynthSetFeedBackFactor(SynthData,Channel,Volume);
       $95:SynthSetFineTune(SynthData,Channel,Volume);
       $96:SynthSetHarmony(SynthData,Channel,Volume);
       $97:SynthSetVowelFilter(SynthData,Channel,Volume);
       $98:SynthSetWaveForm(SynthData,Channel,Volume);
       $99:SynthCopyInstrument(SynthData,Channel,Volume AND $F);
       $9A:SynthSetTB303WaveForm(SynthData,Channel,Volume);
       $9B:SynthSetTB303CutOff(SynthData,Channel,Volume);
       $9C:SynthSetTB303Resonance(SynthData,Channel,Volume);
       $9D:SynthSetTB303EnvMod(SynthData,Channel,Volume);
       $9E:SynthSetTB303EnvDecay(SynthData,Channel,Volume);
       $9F:SynthSetTB303GlideSpeed(SynthData,Channel,Volume);
       $A0:SynthSetTB303Acc(SynthData,Channel,Volume);
       $A1:SynthSetTB303Glide(SynthData,Channel,Volume);
       $A2:SynthSetTB303AccAmt(SynthData,Channel,Volume);
       $A3:SynthSetDistortion(SynthData,Channel,Volume);
       $A4:SynthSetClipping(SynthData,Channel,Volume);
       $A5:SynthSetDelayActive(SynthData,Channel,Volume);
       $A6:SynthSetDelayFeedBack(SynthData,Channel,Volume);
       $A7:SynthSetDelayTime(SynthData,Channel,Volume);                                                                             
       $A8:SynthSetDelayTimeDiv(SynthData,Channel,Volume);
       $A9:SynthSetTB303NoteOff(SynthData,Channel,Volume);
       $AA:SynthData.RealtimeData.ChorusDelayFactor[Channel]:=Volume;
       $AB:SynthSetHz(SynthData,Channel,Volume);
       $AC:BEGIN
        IF ASSIGNED(SynthData.CallBackHook) THEN BEGIN
         SynthData.CallBackHook(Channel,Volume);
        END;
       END;
      END;
     END;
    END;
    IF NOT ASSIGNED(SynthData.RealtimeData.EventOffset[Channel]) THEN DEC(Count);
    INC(SynthData.RealtimeData.TickCounter[Channel]);
   END;
   AdditionalPhase:=SynthData.RealtimeData.LinkValues[0,Channel]+(SynthData.RealtimeData.FeedBackValue[Channel]*SynthData.RealtimeData.FeedBackFactor[Channel]);
   Phase:=FRAC(SynthData.RealtimeData.Phase[Channel]+AdditionalPhase);
   WaveForm:=SynthData.RealtimeData.WaveForm[Channel];
   CASE WaveForm OF
    0:OscValue:=SIN(Phase*2*PI); // Sinus
    1:OscValue:=ABS((Phase-0.5)*4)-1; // Triangle
    2:BEGIN // Square
     Phase:=Phase-0.5;
     OscValue:=LONGWORD((PhaseCasted SHR 31) SHL 1);
     OscValue:=1-OscValue;
    END;
    3,4:OscValue:=((Phase-0.5)*2)*INTEGER(1-((WaveForm-3)*2)); // Sawtooth Up/Down
    5:OscValue:=WhiteNoiseRandom; // White Noise
    6:OscValue:=SynthTB303Process(SynthData.RealtimeData.TB303Data[Channel],SynthData.RealtimeData.PhaseIncrement[Channel],AdditionalPhase); // TB303 emulation
    ELSE OscValue:=0; // Nothing ;-)
   END;
   OscValue:=OscValue+SynthData.RealtimeData.LinkValues[3,Channel]-ABS(SynthData.RealtimeData.LinkValues[4,Channel]);
   OscValue:=(OscValue*SynthData.RealtimeData.Volume[Channel]*SynthData.RealtimeData.VolumeValue[Channel]*SynthData.RealtimeData.ADSRValue[Channel])+AddDenormalNoise;
   OscValue:=OscValue*SynthData.RealtimeData.LinkValues[1,Channel]*ABS(SynthData.RealtimeData.LinkValues[2,Channel]);
   WITH SynthData.RealtimeData.Filter[Channel] DO BEGIN
    FD1:=(FD1+CLP*(OscValue-FD1+FBLP*(FD1-FD2)))+AddDenormalNoise;
    FD2:=(FD2+CLP*(FD1-FD2))+AddDenormalNoise;
    FD3:=(FD3+CHP*(FD2-FD3+FBHP*(FD3-FD4)))+AddDenormalNoise;
    FD4:=(FD4+CHP*(FD3-FD4))+AddDenormalNoise;
    OscValue:=FD2-FD4;
   END;
   SynthData.RealtimeData.FeedBackValue[Channel]:=OscValue;
   SynthDoEffects(SynthData,Channel,OscValue);
   CASE SynthData.RealtimeData.ADSRMode[Channel] OF
    0:BEGIN
    END;
    1:BEGIN
     IF SynthData.RealtimeData.ADSRValue[Channel]<1 THEN BEGIN
      SynthData.RealtimeData.ADSRValue[Channel]:=SynthData.RealtimeData.ADSRValue[Channel]+SynthData.ADSRData.AttackStep[Channel];
     END ELSE BEGIN
      SynthData.RealtimeData.ADSRValue[Channel]:=1;
      SynthData.RealtimeData.ADSRMode[Channel]:=2;
     END;
    END;
    2:BEGIN
     IF SynthData.RealtimeData.ADSRValue[Channel]>SynthData.ADSRData.DestDecay[Channel] THEN BEGIN
      SynthData.RealtimeData.ADSRValue[Channel]:=SynthData.RealtimeData.ADSRValue[Channel]+SynthData.ADSRData.DecayStep[Channel];
     END ELSE BEGIN
      SynthData.RealtimeData.ADSRValue[Channel]:=SynthData.ADSRData.DestDecay[Channel];
      IF SynthData.ADSRData.Sustain[Channel] THEN BEGIN
       SynthData.RealtimeData.ADSRMode[Channel]:=3;
      END ELSE BEGIN
       SynthData.RealtimeData.ADSRMode[Channel]:=4;
      END;
     END;
    END;
    3:BEGIN
    END;
    4:BEGIN
     IF SynthData.RealtimeData.ADSRValue[Channel]>0 THEN BEGIN
      SynthData.RealtimeData.ADSRValue[Channel]:=SynthData.RealtimeData.ADSRValue[Channel]+SynthData.ADSRData.ReleaseStep[Channel];
     END ELSE BEGIN
      SynthData.RealtimeData.ADSRMode[Channel]:=0;
     END;
    END;
   END;
   SynthData.RealtimeData.ADSRValue[Channel]:=SynthData.RealtimeData.ADSRValue[Channel]+AddDenormalNoise;
   IF SynthData.RealtimeData.ADSRValue[Channel]<0 THEN SynthData.RealtimeData.ADSRValue[Channel]:=0;
   IF SynthData.RealtimeData.ADSRValue[Channel]>1 THEN SynthData.RealtimeData.ADSRValue[Channel]:=1;
   IF SynthData.FileData.Link[Channel]<>$FF THEN BEGIN
    LinkChannel:=SynthData.FileData.Link[Channel] AND $F;
    LinkType:=(SynthData.FileData.Link[Channel] AND $7F) SHR 4;
    IF (SynthData.RealtimeData.LinkFirst[LinkChannel] AND (1 SHL LinkType))=0 THEN BEGIN
     SynthData.RealtimeData.LinkValues[LinkType,LinkChannel]:=0;
     SynthData.RealtimeData.LinkFirst[LinkChannel]:=SynthData.RealtimeData.LinkFirst[LinkChannel] OR (1 SHL LinkType);
    END;
    SynthData.RealtimeData.LinkValues[LinkType,LinkChannel]:=SynthData.RealtimeData.LinkValues[LinkType,LinkChannel]+(OscValue*SynthData.FileData.LinkFactor[Channel]);
   END;
   IF (SynthData.FileData.Link[Channel] AND $80)<>0 THEN BEGIN
    Value:=OscValue*SynthData.FileData.OutFactor[Channel];
    PanningValue:=(SynthData.FileData.Panning[Channel]*Div255)+AddDenormalNoise;;
{$IFDEF tracker}
    SynthData.Oscil[Channel,StartPosition+Position]:=Value;
{$ENDIF}
    OscValue:=Value*PanningValue;
    SynthData.RealtimeData.ChannelLastLeft[Channel]:=OscValue+AddDenormalNoise;
    Left:=Left+OscValue;
    OscValue:=Value*(1-PanningValue);
    SynthData.RealtimeData.ChannelLastRight[Channel]:=OscValue+AddDenormalNoise;
    Right:=Right+OscValue;
{$IFDEF tracker}
   END ELSE BEGIN
    SynthData.Oscil[Channel,StartPosition+Position]:=0;
{$ENDIF}
   END;
   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])+AddDenormalNoise;
   SynthData.RealtimeData.Volume[Channel]:=(SynthData.RealtimeData.Volume[Channel]*SynthData.RealtimeData.VolumeFactor[Channel])+AddDenormalNoise;
  END;
  IF SynthData.RealtimeData.CurrentBPMSamples=0 THEN BEGIN
   IF Count=0 THEN SynthReinit(SynthData);
   SynthData.RealtimeData.CurrentBPMSamples:=SynthData.RealtimeData.BPMSamples;
  END;
  DEC(SynthData.RealtimeData.CurrentBPMSamples);
  Left:=Left+SynthData.RealtimeData.LastLeft;
  SynthData.RealtimeData.LastLeft:=(SynthData.RealtimeData.LastLeft*0.9)+AddDenormalNoise;
  Right:=Right+SynthData.RealtimeData.LastRight;
  SynthData.RealtimeData.LastRight:=(SynthData.RealtimeData.LastRight*0.9)+AddDenormalNoise;
  Buffer^:=Left*Div8;
  INC(Buffer);
  Buffer^:=Right*Div8;
  INC(Buffer);
{$IFDEF seeking}
  INC(SynthData.Samples);
{$ENDIF}
 END;
{$IFDEF player}
 IF SynthData.ActiveState<>SynthData.DestActiveState THEN BEGIN
  Buffer:=DestBuffer;
  AmpiferStep:=(1/BufferSize)+AddDenormalNoise;
  IF SynthData.DestActiveState THEN BEGIN
   AmpiferFactor:=0;
  END ELSE BEGIN
   AmpiferFactor:=1;
   AmpiferStep:=-AmpiferStep;
  END;
  FOR Position:=1 TO BufferSize DO BEGIN
   Buffer^:=(Buffer^*AmpiferFactor)+AddDenormalNoise;
   INC(Buffer);
   Buffer^:=(Buffer^*AmpiferFactor)+AddDenormalNoise;
   INC(Buffer);
   AmpiferFactor:=AmpiferFactor+AmpiferStep;
  END;
  SynthData.ActiveState:=SynthData.DestActiveState;
 END;
{$ENDIF}
END;

{$IFDEF player}
{$IFDEF seeking}
PROCEDURE SynthScan(VAR SynthData:TSynthData); STDCALL; {$IFDEF FPC}[public, alias : 'SynthScan'];{$ENDIF}
 PROCEDURE DoPass(PassNr:INTEGER);
 VAR Channel,Count,BPMSamples:INTEGER;
     ShouldExit:BOOLEAN;
     TickCounter:ARRAY[0..MaxSynthChannels-1] OF LONGINT;
     EventOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
     NoteOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
     VolumeOffset:ARRAY[0..MaxSynthChannels-1] OF PBYTE;
     LastPercent:INT64;
     Percent:INT64;
     Samples:INT64;
     Note,Volume:BYTE;
 BEGIN
  ShouldExit:=FALSE;
  FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
   EventOffset[Channel]:=SynthData.RealtimeData.RestartEventOffset[Channel];
   NoteOffset[Channel]:=SynthData.RealtimeData.RestartNoteOffset[Channel];
   VolumeOffset[Channel]:=SynthData.RealtimeData.RestartVolumeOffset[Channel];
   TickCounter[Channel]:=0;
  END;
  BPMSamples:=0;
  LastPercent:=-1;
  Samples:=0;
  WHILE NOT ShouldExit DO BEGIN
   Count:=MaxSynthChannels;
   FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
    WHILE ASSIGNED(EventOffset[Channel]) AND (TickCounter[Channel]>=EventOffset[Channel]^) DO BEGIN
     TickCounter[Channel]:=0;
     Note:=NoteOffset[Channel]^;
     Volume:=VolumeOffset[Channel]^;
     INC(EventOffset[Channel]);
     INC(NoteOffset[Channel]);
     INC(VolumeOffset[Channel]);
     CASE Note OF
      $82:BPMSamples:=(SampleRate*5*128) DIV (Volume SHL 8);
      $83:EventOffset[Channel]:=NIL;
     END;
    END;
    IF NOT ASSIGNED(EventOffset[Channel]) THEN DEC(Count);
    INC(TickCounter[Channel]);
   END;
   IF PassNr=2 THEN BEGIN
    IF SynthData.MaxSamples=0 THEN BEGIN
     Percent:=0;
    END ELSE BEGIN
     Percent:=(Samples*100) DIV SynthData.MaxSamples;
    END;
    IF Percent<0 THEN Percent:=0;
    IF Percent>100 THEN Percent:=100;
    IF LastPercent<>Percent THEN BEGIN
     FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
      SynthData.RestartPoints[Percent].RestartEventOffset[Channel]:=EventOffset[Channel];
      SynthData.RestartPoints[Percent].RestartNoteOffset[Channel]:=NoteOffset[Channel];
      SynthData.RestartPoints[Percent].RestartVolumeOffset[Channel]:=VolumeOffset[Channel];
      SynthData.RestartPoints[Percent].RestartTick[Channel]:=TickCounter[Channel];
     END;
     SynthData.RestartPoints[Percent].Samples:=Samples;
     SynthData.RestartPoints[Percent].CurrentBPMSamples:=0;
     SynthData.RestartPoints[Percent].BPMSamples:=BPMSamples;
     LastPercent:=Percent;
    END;
   END;
   INC(Samples,BPMSamples);
   IF Count=0 THEN ShouldExit:=TRUE;
  END;
  IF PassNr=2 THEN BEGIN
   IF SynthData.MaxSamples=0 THEN BEGIN
    Percent:=0;
   END ELSE BEGIN
    Percent:=(Samples*100) DIV SynthData.MaxSamples;
   END;
   IF Percent<0 THEN Percent:=0;
   IF Percent>100 THEN Percent:=100;
   IF LastPercent<>Percent THEN BEGIN
    FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
     SynthData.RestartPoints[Percent].RestartEventOffset[Channel]:=EventOffset[Channel];
     SynthData.RestartPoints[Percent].RestartNoteOffset[Channel]:=NoteOffset[Channel];
     SynthData.RestartPoints[Percent].RestartVolumeOffset[Channel]:=VolumeOffset[Channel];
     SynthData.RestartPoints[Percent].RestartTick[Channel]:=TickCounter[Channel];
    END;
    SynthData.RestartPoints[Percent].Samples:=Samples;
   END;
  END;
  IF PassNr=1 THEN SynthData.MaxSamples:=Samples;
 END;
VAR Pass:INTEGER;
BEGIN
 FOR Pass:=1 TO 2 DO DoPass(Pass);
END;
{$ENDIF}

PROCEDURE SynthLoad(VAR SynthData:TSynthData;TrackData:POINTER;TrackSize:INTEGER); STDCALL; {$IFDEF FPC}[public, alias : 'SynthLoad'];{$ENDIF}
BEGIN
 FILLCHAR(SynthData,SIZEOF(TSynthData),#0);
 MOVE(TrackData^,SynthData,TrackSize);
 SynthInitData(SynthData);
{$IFDEF seeking}
 SynthScan(SynthData);
 SynthData.Samples:=0;
 SynthData.Restart:=FALSE;
{$ENDIF}
 SynthData.ActiveState:=FALSE;
 SynthData.DestActiveState:=FALSE;
END;

PROCEDURE SynthInit(VAR SynthData:TSynthData;TrackData:POINTER;TrackSize:INTEGER;CallBackHook:TSynthCallBackHook=NIL); STDCALL; {$IFDEF FPC}[public, alias : 'SynthInit'];{$ENDIF}
CONST cwChop:WORD=$F7B;
VAR I:INTEGER;
BEGIN
 ASM
  FLDCW cwChop
 END;
 SynthLoad(SynthData,TrackData,TrackSize);

 WhiteNoiseSeed:=$12345678;

 waveOutOpen(@WaveOutHandle,WAVE_MAPPER,@WaveFormat,0,0,0);

 FOR I:=0 TO 3 DO BEGIN
  WaveHandler[I].dwFlags:=WHDR_DONE;
  WaveHandler[I].lpData:=@Buffers[I];
  WaveHandler[I].dwBufferLength:=BufferSize*8;
 END;

 SynthData.CallBackHook:=CallBackHook;

 BufferCounter:=0;
END;

FUNCTION SynthPoll(VAR SynthData:TSynthData):BOOLEAN; STDCALL; {$IFDEF FPC}[public, alias : 'SynthPoll'];{$ENDIF}
BEGIN
 RESULT:=FALSE;
 IF SynthData.ActiveState OR SynthData.DestActiveState THEN BEGIN
  IF (WaveHandler[BufferCounter].dwFlags AND WHDR_DONE)<>0 THEN BEGIN
   IF waveOutUnprepareHeader(WaveOutHandle,@WaveHandler[BufferCounter],SIZEOF(TWAVEHDR))<>WAVERR_STILLPLAYING THEN BEGIN
    WaveHandler[BufferCounter].dwFlags:=WaveHandler[BufferCounter].dwFlags AND NOT WHDR_DONE;
    SynthFillBuffer(SynthData,@WaveHandler[BufferCounter].lpData^,0,BufferSize);
    waveOutPrepareHeader(WaveOutHandle,@WaveHandler[BufferCounter],SIZEOF(TWAVEHDR));
    waveOutWrite(WaveOutHandle,@WaveHandler[BufferCounter],SIZEOF(TWAVEHDR));
    BufferCounter:=(BufferCounter+1) MOD 4;
    RESULT:=TRUE;
   END;
  END;
 END ELSE BEGIN
  RESULT:=TRUE;
 END;
END;

PROCEDURE SynthDone(VAR SynthData:TSynthData); STDCALL; {$IFDEF FPC}[public, alias : 'SynthDone'];{$ENDIF}
{$IFDEF clean}
VAR I:INTEGER;
{$ENDIF}
BEGIN
{$IFDEF clean}
 FOR I:=0 TO 3 DO BEGIN
  WHILE waveOutUnprepareHeader(WaveOutHandle,@WaveHandler[I],SIZEOF(TWAVEHDR))=WAVERR_STILLPLAYING DO BEGIN
  END;
 END;
 waveOutReset(WaveOutHandle);
 waveOutClose(WaveOutHandle);
{$ENDIF}
END;

{$IFDEF seeking}
PROCEDURE SynthSeeking(VAR SynthData:TSynthData;Percent:INTEGER);
VAR Channel:INTEGER;
BEGIN
 IF Percent<0 THEN Percent:=0;
 IF Percent>100 THEN Percent:=100;
 FOR Channel:=0 TO MaxSynthChannels-1 DO BEGIN
  SynthData.RealtimeData.VolumeFactor[Channel]:=0.9;
  SynthData.RealtimeData.PhaseIncrement[Channel]:=0;
  SynthData.RealtimeData.EventOffset[Channel]:=SynthData.RestartPoints[Percent].RestartEventOffset[Channel];
  SynthData.RealtimeData.NoteOffset[Channel]:=SynthData.RestartPoints[Percent].RestartNoteOffset[Channel];
  SynthData.RealtimeData.VolumeOffset[Channel]:=SynthData.RestartPoints[Percent].RestartVolumeOffset[Channel];
  SynthData.RealtimeData.TickCounter[Channel]:=SynthData.RestartPoints[Percent].RestartTick[Channel];
 END;
 SynthData.Samples:=SynthData.RestartPoints[Percent].Samples;
 SynthData.RealtimeData.CurrentBPMSamples:=SynthData.RestartPoints[Percent].CurrentBPMSamples;
 SynthData.RealtimeData.BPMSamples:=SynthData.RestartPoints[Percent].BPMSamples;
END;
{$ENDIF}

{$IFNDEF smallplayer}
FUNCTION SynthGetName(VAR Data):STRING; STDCALL; {$IFDEF FPC}[public, alias : 'SynthGetName'];{$ENDIF}
VAR SynthData:PSynthData;
    InfoData:PSynthInfoData;
    B:PBYTE;
BEGIN
 SynthData:=@Data;
 InfoData:=POINTER(LONGWORD(LONGWORD(@Data)+SynthData^.InfoData));
 IF InfoData^.NameLength>0 THEN BEGIN
  B:=POINTER(LONGWORD(LONGWORD(InfoData)+SIZEOF(TSynthInfoData)));
  SETLENGTH(RESULT,InfoData^.NameLength);
  MOVE(B^,RESULT[1],InfoData^.NameLength);
 END ELSE BEGIN
  RESULT:='';
 END;
END;

FUNCTION SynthGetAuthor(VAR Data):STRING; STDCALL; {$IFDEF FPC}[public, alias : 'SynthGetAuthor'];{$ENDIF}
VAR SynthData:PSynthData;
    InfoData:PSynthInfoData;
    B:PBYTE;
BEGIN
 SynthData:=@Data;
 InfoData:=POINTER(LONGWORD(LONGWORD(@Data)+SynthData^.InfoData));
 IF InfoData^.AuthorLength>0 THEN BEGIN
  B:=POINTER(LONGWORD(LONGWORD(InfoData)+SIZEOF(TSynthInfoData))+InfoData^.NameLength);
  SETLENGTH(RESULT,InfoData^.AuthorLength);
  MOVE(B^,RESULT[1],InfoData^.AuthorLength);
 END ELSE BEGIN
  RESULT:='';
 END;
END;

FUNCTION SynthGetMessage(VAR Data):STRING; STDCALL; {$IFDEF FPC}[public, alias : 'SynthGetMessage'];{$ENDIF}
VAR SynthData:PSynthData;
    InfoData:PSynthInfoData;
    B:PBYTE;
BEGIN
 SynthData:=@Data;
 InfoData:=POINTER(LONGWORD(LONGWORD(@Data)+SynthData^.InfoData));
 IF InfoData^.MessageLength>0 THEN BEGIN
  B:=POINTER(LONGWORD(LONGWORD(InfoData)+SIZEOF(TSynthInfoData))+InfoData^.NameLength+InfoData^.AuthorLength);
  SETLENGTH(RESULT,InfoData^.MessageLength);
  MOVE(B^,RESULT[1],InfoData^.MessageLength);
 END ELSE BEGIN
  RESULT:='';
 END;
END;
{$ENDIF}

{$ELSE}
PROCEDURE SynthInit; STDCALL; {$IFDEF FPC}[public, alias : 'SynthInit'];{$ENDIF}
CONST cwChop:WORD=$F7B;
BEGIN
 ASM
  FLDCW cwChop
 END;

 WhiteNoiseSeed:=$12345678;
END;
{$ENDIF}

END.
