Main Archive Specials Wiki | FAQ Links Submit Forum


Fast LFO in Delphi...

References : Posted by Dambrin Didier ( gol [AT] e-officedirect [DOT] com )
Linked file : LFOGenerator.zip

Notes :
[from Didier's mail...]
[see attached zip file too!]

I was working on a flanger, & needed an LFO for it. I first used a Sin(), but it was too slow, then tried a big wavetable, but it wasn't accurate enough.

I then checked the alternate sine generators from your web site, & while they're good, they all can drift, so you're also wasting too much CPU in branching for the drift checks.

So I made a quick & easy linear LFO, then a sine-like version of it. Can be useful for LFO's, not to output as sound.
If has no branching & is rather simple. 2 Abs() but apparently they're fast. In all cases faster than a Sin()


It's in delphi, but if you understand it you can translate it if you want.
It uses a 32bit integer counter that overflows, & a power for the sine output.
If you don't know delphi, $ is for hex (h at the end in c++?), Single is 32bit float, integer is 32bit integer (signed, normally).


Code :
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls;

type
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Bevel1: TBevel;
procedure PaintBox1Paint(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.PaintBox1Paint(Sender: TObject);
var n,Pos,Speed:Integer;
Output,Scale,HalfScale,PosMul:Single;
OurSpeed,OurScale:Single;
begin
OurSpeed:=100; // 100 samples per cycle
OurScale:=100; // output in -100..100

Pos:=0; // position in our linear LFO
Speed:=Round($100000000/OurSpeed);


// --- triangle LFO ---
Scale:=OurScale*2;
PosMul:=Scale/$80000000;

// loop
for n:=0 to 299 do
Begin
// inc our 32bit integer LFO pos & let it overflow. It will be seen as signed when read by the math unit
Pos:=Pos+Speed;

Output:=Abs(Pos*PosMul)-OurScale;

// visual
Paintbox1.Canvas.Pixels[n,Round(100+Output)]:=clRed;
End;


// --- sine-like LFO ---
Scale:=Sqrt(OurScale*4);
PosMul:=Scale/$80000000;
HalfScale:=Scale/2;

// loop
for n:=0 to 299 do
Begin
// inc our 32bit integer LFO pos & let it overflow. It will be seen as signed when read by the math unit
Pos:=Pos+Speed;

Output:=Abs(Pos*PosMul)-HalfScale;
Output:=Output*(Scale-Abs(Output));

// visual
Paintbox1.Canvas.Pixels[n,Round(100+Output)]:=clBlue;
End;
end;

end.



Comments


Added on : 29/04/04 by Christian[ AT ]savioursofsoul[ DOT ]de
Comment :
LFO Class...

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls;

type
  TLFOType = (lfoTriangle,lfoSine);
  TLFO = class(TObject)
  private
    iSpeed     : Integer;
    fSpeed     : Single;
    fMax, fMin : Single;
    fValue     : Single;
    fPos       : Integer;
    fType      : TLFOType;
    fScale     : Single;
    fPosMul    : Single;
    fHalfScale : Single;
    function GetValue:Single;
    procedure SetType(tt: TLFOType);
    procedure SetMin(v:Single);
    procedure SetMax(v:Single);
  public
    { Public declarations }
    constructor Create;
  published
    property Value:Single read GetValue;
    property Speed:Single read FSpeed Write FSpeed;
    property Min:Single read FMin write SetMin;
    property Max:Single read FMax Write SetMax;
    property LFO:TLFOType read fType Write SetType;
  end;

  TForm1 = class(TForm)
    Bevel1: TBevel;
    PaintBox1: TPaintBox;
    procedure PaintBox1Paint(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

constructor TLFO.Create;
begin
fSpeed:=100;
fMax:=1;
fMin:=0;
fValue:=0;
fPos:=0;
iSpeed:=Round($100000000/fSpeed);
fType:=lfoTriangle;
fScale:=fMax-((fMin+fMax)/2);
end;

procedure TLFO.SetType(tt: TLFOType);
begin
fType:=tt;
if fType = lfoSine then
  begin
   fPosMul:=(Sqrt(fScale*2))/$80000000;
   fHalfScale:=(Sqrt(fScale*2))/2;
  end
else
  begin
   fPosMul:=fScale/$80000000;
  end;
end;

procedure TLFO.SetMin(v: Single);
begin
fMin:=v;
fScale:=fMax-((fMin+fMax)/2);
end;

procedure TLFO.SetMax(v: Single);
begin
fMax:=v;
fScale:=fMax-((fMin+fMax)/2);
end;

function TLFO.GetValue:Single;
begin
if fType = lfoSine then
  begin
   Result:=Abs(fPos*fPosMul)-fHalfScale;
   Result:=Result*(fHalfScale*2-Abs(Result))*2;
   Result:=Result+((fMin+fMax)/2);
  end
else
  begin
    Result:=Abs(fPos*(2*fPosMul))+fMin;
  end;
fPos:=fPos+iSpeed;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
var n    : Integer;
    LFO1 : TLFO;
begin

LFO1:=TLFO.Create;
LFO1.Min:=-100;
LFO1.Max:=100;
LFO1.Speed:=100;
LFO1.LFO:=lfoTriangle;

// --- triangle LFO ---
for n:=0 to 299 do Paintbox1.Canvas.Pixels[n,Round(100+LFO1.Value)]:=clRed;


LFO1.LFO:=lfoSine;
// --- sine-like LFO ---
for n:=0 to 299 do Paintbox1.Canvas.Pixels[n,Round(100+LFO1.Value)]:=clBlue;
end;

end.            




Added on : 01/06/05 by Christian[ AT ]savioursofsoul[ DOT ]de
Comment :
Ups, i forgot something:

  TLFO = class(TObject)
  private
    ...
    procedure SetSpeed(v:Single);
  public
    ...
  published
    ...
    property Speed:Single read FSpeed Write SetSpeed;
    ...
  end;

...

constructor TLFO.Create;
begin
...
Speed:=100;
...
end;

procedure TLFO.SetSpeed(v:Single);
begin
fSpeed:=v;
iSpeed:=Round($100000000/fSpeed);
end;

...




Add your own comment
Comments are displayed in fixed width, no HTML code allowed!
Email:

Comment:

Are you human?



Site created and maintained by Bram
Graphic design by line.out | Server sponsered by fxpansion