I have tried to find samples of using LADSPA in Lazarus; but I cannot find any, probably me just googling for the wrong keywords.
I had a look at the LADSPA for FreePascal unit. Finally got it working, but its a complex solution. First up, there are 6 callback functions which need to be made stdcall. Otherwise it wont work.
To create a TLADSPAPlugin class, you use:
uses LADSPA, dynlibs;
TLibHandle FLib := LoadLibrary(ProgramDirectory + 'plugin.dll');
FPlugin := TLADSPAPlugin.Create(FLib, 0);
FPlugin.Instantiate(44100, 1);
At that point, you should be able to get some information about the plugin. eg: PortCount, Port Names, Author, Copyright, etc.
But, thats where is starts getting hairy. LADSPA uses ports for both input/output samples, and for effect parameters. Its a neat trick, but can be hard to visualize. You setup a port array, which contains samples and parameters for the effect. (VST has separate parameters and sample processing buffers)
FPorts: array of array of TLADSPA_Data;
The array should be initilized to default values, and then the plugin needs to be activated:
SetLength(FPorts, FPlugin.PortCount, 1);
for LIndex := 0 to FPlugin.PortCount - 1 do begin
FPorts[LIndex][0] := 0.5;
end;
FPorts[6][0] := 1.2;
FPlugin.Activate;
The effect im testing is the 12 band EQ I posted, converted to LADSPA using Geep Jeez. The port description is this:
0 INPUT
1 INPUT
2 OUTPUT
3 OUTPUT
4 HPF
5 Low Shelf
6 80 Hz
7 150 Hz
8 250 Hz
9 400 Hz
10 630 Hz
11 800 Hz
12 1.6 kHz
13 3 kHz
14 5 kHz
15 7 kHz
16 10 kHz
17 12 kHz
18 LPF
19 Output Gain
Here is the hairy part. With Bass, you need to ensure you create streams with the flag BASS_SAMPLE_FLOAT. So, all the samples will be singles. If you setup a DSP callback, you will receive a buffer, and byte length. The samples are interleaved. ie: LRLRLRLRLR
Problem is, LADSPA wants all the left channel as port 0, and all the right channel as port 1. And, depending on the byte length given by BASS, you need to resize the input/output ports, and reconnect them before calling the LADSPA plugin.
Anyway, long story short, this is what you would be looking at having todo.
procedure TMyEffect.Process(const ABuffer: Pointer; const ALength: DWORD);
var
LPtr: PSingle;
LP0, LP1: PSingle;
LIndex, LSampleCount, LPortSize: Integer;
begin
LSampleCount := (ALength div SizeOf(Single)) div 2;
for LIndex := 0 to FPlugin.PortCount - 1 do begin
if FPlugin.IsInput(LIndex) or FPlugin.IsOutput(LIndex) then begin
LPortSize := LSampleCount;
end else begin
LPortSize := 1;
end;
if Length(FPorts[LIndex]) <> LPortSize then begin
SetLength(FPorts[LIndex], LPortSize);
FPlugin.ConnectPort(0, LIndex, @FPorts[LIndex][0]);
end;
end;
LP0 := @FPorts[0][0];
LP1 := @FPorts[1][0];
LPtr := ABuffer;
for LIndex := 0 to LSampleCount - 1 do begin
LP0[LIndex] := LPtr[0];
LP1[LIndex] := LPtr[1];
Inc(LPtr, 2);
end;
FPlugin.Run(LSampleCount);
LP0 := @FPorts[2][0];
LP1 := @FPorts[3][0];
LPtr := ABuffer;
for LIndex := 0 to LSampleCount - 1 do begin
LPtr[0] := LP0[LIndex];
LPtr[1] := LP1[LIndex];
Inc(LPtr, 2);
end;
end;
That code isn't releasable. It assumes the DSP callback will be stereo and it assumes the effect is stereo and input ports are 0 & 1, and output ports are 2 & 3.
But, by using FPorts[6][0] := 1.2 I was able to increase the bass (80hz) of a MP3. ie: 6 is the port number for 80hz.
I guess, see what you think. Its a lot of fun getting it working, but, I can see a lot of work to be done to make it a solid solution. ie: support for any LADSPA effect, and autogenerating TForm's with sliders.
Hope that helps.