unit PALFO; // // purpose: LUT based LFO // author: © 2004, Thaddy de Koning // Remarks: Translated from c++ sources by Remy Mueller, www.musicdsp.org // Since it is based on a lookup table you can easily add any waveform // you like. interface uses {$IFDEF KOL} Windows, Kol,KolMath; {$ELSE} Windows, math; {$ENDIF} const k1Div24lowerBits = 1/(1 shl 24); WFStrings:array[0..4] of string = ('triangle','sinus', 'sawtooth', 'square', 'exponent'); type Twaveform = (triangle, sinus, sawtooth, square, exponent); {$IFDEF KOL} PPaLfo = ^TPALfo; TPaLfo = object(TObj) {$ELSE} TPaLfo = class {$ENDIF} private FTable:array[0..256] of Single;// 1 more for linear interpolation FPhase, FInc:dword; FRate: Single; FSampleRate: Single; FWaveForm: TWaveForm; procedure SetRate(const Value: Single); procedure SetSampleRate(const Value: Single); procedure SetWaveForm(const Value: TWaveForm); public {$IFNDEF KOL} constructor create(SampleRate:Single);virtual; {$ENDIF} // increments the phase and outputs the new LFO value. // return the new LFO value between [-1;+1] function WaveformName:String; function Tick:Single; // The rate in Hz property Rate:Single read FRate write SetRate; // The Samplerate property SampleRate:Single read FSampleRate write SetSampleRate; property WaveForm:TWaveForm read FWaveForm write SetWaveForm; end; {$IFDEF KOL} function NewPaLfo(aSamplerate:Single):PPaLfo; {$ENDIF} implementation { TPaLfo } {$IFDEF KOL} function NewPaLfo(aSamplerate:Single):PPaLfo; begin New(Result,Create); with Result^ do begin FPhase:=0; FSamplerate:=aSamplerate; SetWaveform(sinus); Rate:=1; end; end; {$ELSE} constructor TPaLfo.create(SampleRate: Single); begin inherited create; FPhase:=0; FSamplerate:=aSamplerate; SetWaveform(sinus); FRate:=1; end; {$ENDIF} procedure TPaLfo.SetRate(const Value: Single); begin FRate := Value; // the rate in Hz is converted to a phase increment with the following formula // f[ inc = (256*rate/samplerate) * 2^24] Finc := round((256 * Frate / Fsamplerate) * (1 shl 24)); end; procedure TPaLfo.SetSampleRate(const Value: Single); begin FSampleRate := Value; end; procedure TPaLfo.SetWaveForm(const Value: TWaveForm); var i:integer; begin FWaveForm := Value; Case Fwaveform of sinus: for i:=0 to 256 do FTable[i] := sin(2*pi*(i/256)); triangle: begin for i:=0 to 63 do begin FTable[i] := i / 64; FTable[i+64] :=(64-i) / 64; FTable[i+128] := - i / 64; FTable[i+192] := - (64-i) / 64; end; FTable[256] := 0; end; sawtooth: begin for i:=0 to 255 do FTable[i] := 2*(i/255) - 1; FTable[256] := -1; end; square: begin for i:=0 to 127 do begin FTable[i] := 1; FTable[i+128] := -1; end; FTable[256] := 1; end; exponent: begin // symetric exponent similar to triangle for i:=0 to 127 do begin FTable[i] := 2 * ((exp(i/128) - 1) / (exp(1) - 1)) - 1 ; FTable[i+128] := 2 * ((exp((128-i)/128) - 1) / (exp(1) - 1)) - 1 ; end; FTable[256] := -1; end; end; end; function TPaLfo.WaveformName:String; begin result:=WFStrings[Ord(Fwaveform)]; end; function TPaLfo.Tick: Single; var i:integer; frac:Single; begin // the 8 MSB are the index in the table in the range 0-255 i := Fphase shr 24; // and the 24 LSB are the fractionnal part frac := (Fphase and $00FFFFFF) * k1Div24lowerBits; // increment the phase for the next tick Fphase :=FPhase + Finc; // the phase overflows itself Result:= Ftable[i]*(1-frac) + Ftable[i+1]* frac; // linear interpolation end; end.