Previous | Next |
Home
In my experience, Process() and ProcessReplacing()
are the methods least understood by Delphi programmers who want to make VST
plugins. Why is this? I don't really know, but my guess is it has something
to do with pointers. These two methods work with the audio data provided by
the host. This data is sent to the plugin by a specific kind of parameter, which
is used regularly in C/C++, but not very often in ObjectPascal. I'll explain
this, but first an explanation of the difference between these two methods.
The Process method gets audio data, does something to it and then adds the result
to the original data. This is done like this :
resultsample := dosomethingwith(currentsample) + currentsample;
ProcessReplacing on the other hand doesn't care about the original sample data
once it's done its work.
resultsample := dosomethingwith(currentsample);
That's the difference between Process and ProcessReplacing. It's that simple.
ProcessReplacing only gets called when you called canProcessReplacing(TRUE) in
your constructor. In general, it's very easy to make a ProcessReplacing method,
so there's really no reason not to.
Now for the declaration of the two methods:
procedure process(inputs, outputs: PPSingle; sampleframes:
Longint);
procedure processReplacing(inputs, outputs: PPSingle;
sampleframes: Longint);
As you can see, they have the same parameters. Like I said, it's easy to create
a processReplacing method if you already have a Process method.
Samples can have any value between -1.0 and +1.0. A value of 0.0 means no sound.
-1.0 and +1.0 mean full sound.
Inputs : This is a pointer to the buffers with the original samples.
Outputs : This is a pointer to the buffers where you will store the result of
your processing.
SampleFrames : This is the easiest parameter. It tells you how many samples are
in the Inputs and Outputs buffers.
Like I said, a lot of people have difficulty with the Inputs and Outputs parameters.
Actually, it's quite simple. Inputs is a pointer to the input buffers. It points
to the area in memory where you can find the pointer to the first buffer. Look
at it as an array of pointers. I'll use a little drawing to make it clear.
Inputs --> inputbuffer1 --> samples for input1
inputbuffer2
--> samples for input2
So provided you defined two inputs in your constructor, Inputs points to two other
pointers. These last pointers point to the actual sample data.
Maybe the easiest way to look at it is like this : Inputs is an array of pointers.
It has as many elements as your plugin has inputs.
type
PDataBuffer = ^TDataBuffer;
TDataBuffer = array[0..NumSamples-1]
of Single;
TInputArray = array[0..NumInputs-1]
of PDataBuffer;
Enough for the theory, how do you get at these buffers? It's quite simple. Look
at this example (there are two inputs and two outputs in this example):
procedure Process(inputs, outputs: PPSingle; sampleframes:
longint)
var
input1, input2, output1, output2:
PSingle;
temp : Single;
i : integer;
begin
// here we get the actual sample
buffers
input1 := inputs^;
inc(inputs);
input2 := inputs^;
output1 := outputs^;
inc(outputs);
output2 := outputs^;
// sampleframes tells you how
many samples there are in the buffers
for i := 0 to sampleframes-1 do
begin
temp :=
dosomething(input1^); //
get the current sample on the first input and process it
output1^
:= temp + output1^; //
put the processed sample on the first output
temp :=
dosomething(input2^); //
get the current sample on the second input and process it
output2^
:= temp + output2^; //
put the processed sample on the second output
inc(input1);
// move on to the next sample
inc(input2);
inc(output1);
inc(output2);
end;
end;
And this is immediately an example of a complete Process method. You can also
take a look at the Process method in uExampleEffect.pas.