Gain plugin
We all need to adjust level sometimes. So here's a simple demo using processSample.
- // script name
- string name="gain (dB)";
- // Define our input parameters
- array<double> inputParameters(1); // how many params we need
- array<string> inputParametersNames={"Gain"};
- array<string> inputParametersUnits={"dB"};
- array<double> inputParametersMin={-20};
- array<double> inputParametersMax={20};
- array<double> inputParametersDefault={0};
- // variable to keep gain (0..1 to decrease, >1 to increase level)
- double gain = 0;
- // called for every sample
- // loop through available channels
- for(uint channel=0;channel<audioInputsCount;channel++) {
- ioSample[channel]*=gain;
- }
- }
- // called before every processSample call if input parameter changes
- // convert gainDb to gain (0..1+)
- gain = pow(10, inputParameters[0]/20);
- }
See the detailed tutorial in "Writing a simple script".
processBlock maybe?
We could rewrite it using processBlock instead.
- // script name
- string name="gain (dB)";
- // Define our input parameters
- array<double> inputParameters(1); // how many params we need
- array<string> inputParametersNames={"Gain"};
- array<string> inputParametersUnits={"dB"};
- array<double> inputParametersMin={-20};
- array<double> inputParametersMax={20};
- array<double> inputParametersDefault={0};
- // variable to keep gain (0..1 to decrease, >1 to increase level)
- double gain = 0;
- // main processing function
- // parse block of samples
- for(uint i = 0; i<data.samplesToProcess; i++) {
- // loop through all channels for current sample
- for(uint ch = 0; ch < audioOutputsCount; ch++) {
- data.samples[ch][i] *= gain;
- }
- }
- }
- // called before every processBlock call if input parameter changes
- // convert gainDb to gain (0..1+)
- gain = pow(10, inputParameters[0]/20);
- }
What's the difference?
When using processSample, the updateInputParameters is called for every sample, so we get our param smoothly recalculated.
When using processBlock, the updateInputParameters is called for every block, so we get rather abrupt changes.
But we often need to use processBlock, as it is much more powerful. So, let's try to do parameter interpolation manually.
processBlock + interpolation
We can get rid of updateInputParameters, because in processBlock we receive parameter values for the start and end of the current block. So we can calculate how much parameter changes during every sample in current block, and add this delta value step by step.
- // script name
- string name="gain (dB)";
- // Define our input parameters
- array<double> inputParameters(1); // how many params we need
- array<string> inputParametersNames={"Gain"};
- array<string> inputParametersUnits={"dB"};
- array<double> inputParametersMin={-20};
- array<double> inputParametersMax={20};
- array<double> inputParametersDefault={0};
- // process blocks of audio
- // get gain for the start and the end of the block, convert from dB
- double gain = pow(10, data.beginParamValues[0] / 20);
- double gain_end = pow(10, data.endParamValues[0] / 20);
- // calculate gain delta per-sample
- double gain_delta = (gain_end - gain) / data.samplesToProcess;
- // parse block of samples
- for(uint i = 0; i<data.samplesToProcess; i++) {
- // loop through all channels for current sample
- for(uint ch = 0; ch < audioOutputsCount; ch++) {
- data.samples[ch][i] *= gain;
- }
- // change gain smoothly
- gain += gain_delta;
- }
- }
Now we have it smooth.
We could try to save some CPU and make a check inside processBlock to see if input parameters have changed since the last call, and only then recalculate our gain variables. But for now, let's keep it simple.
Great, we're done!