First     Previous     Next

Processing data

The main task of an audio plugin is of course to work with audio data. Depending on the type of plugin, this is done in either Eff_Render (for effects), in Gen_Render (for full generators) or in Voice_Render (for hybrid generators). For both types of generators you'll also want to check out Working with voices so you'll actually have something to generate sound from.

Common to all processing
First of all, samples in Fruity plugins are floating point values (single in Delphi, float in C++). They range from -1.0 to +1.0.

Audio data in Fruity plugins is always stereo. So there's always a left and a right channel. The samples are interlaced. When you get an audio buffer from FL Studio (of type PWAV32FS), the first sample is on the left channel, the second sample is for the right channel, the third is on the left channel again, and so on. So a buffer contains double the amount of samples that the Length parameter (see below) specifies. The PWAV32FS type makes it easy to work with buffers sent by FL Studio.


Eff_Render
An effect always receives a source and a destination buffer in Eff_Render. The source buffer (SourceBuffer parameter) shouldn't be altered. Instead, samples are to be read from the source buffer and saved in the destination buffer (DestBuffer) after being processed.

The Length parameter specifies how many samples the buffers contain for each channel. For example, when Length is 1024, the buffers contain 1024 samples on the left channel and 1024 samples on the right channel, making 2048 samples in total.

SourceBuffer and DestBuffer can be the same (that means they could point to the same memory block). It's worth to check for this, as it could save you the trouble (and cpu) of copying data from one buffer to the other. One way of going about this could be the following: check if the pointers are the same. If they are not, copy the data from SourceBuffer to SestBuffer. Now you can continue processing on DestBuffer only, which you can also do if SourceBuffer and DestBuffer are the same. You have to think this through however and find out if this method works for your particular plugin.

Gen_Render
A generator only has one buffer parameter in Gen_Render: the destination buffer (DestBuffer). This is of course because a generator does not apply an effect to already existing samples, but instead creates entirely new samples.

The Length parameter in Gen_Render serves a somewhat different purpose than in Eff_Render. It still specifies how many samples are in the buffers for each channel, just like in Eff_Render. But this value is a maximum in Gen_Render. The generator may choose to generate less samples than Length specifies. In this case, Length has to be set to the actual amount of samples that were generated before the function returns. For this reason, Length in Gen_Render can be altered by the function (it is a var parameter in Delphi and a reference (&) in C++).

Gen_Render needs to render all currently active voices. It's probably a good idea to keep those in a list and run through that. It also needs to take care of stuff like envelopes itself, unlike Voice_Render. You can take a look at Osc3 for an example of what Gen_Render has to do.

Take care to always check the levels of a voice before rendering, as FL Studio can change those at any time (for example: when the user chooses to slide a note up or down).


Voice_Render
This function is called for a hybrid generator when a voice slice needs to be rendered. It works in the same way as Gen_Render, with one big difference: you only have to render one voice each time. The function has an extra parameter (Handle) that identifies the voice to be rendered. This handle is the same value you returned when TriggerVoice was called (see Working with voices). Voice_Render also doesn't return a result, unlike Gen_Render.