ASPiK SDK
|
As the projects become more complex, we will typically create C++ objects to do the signal processing. This is good practice on many different levels. For example, suppose you created three really interesting and marketable plugins that did compression, EQ, and reverb and you later decided to consolidate them into one multi-function plugin. If the majority of your signal processing code were implemented in C++ objects, you would only need to aggregate these objects and chain their processing functions together. If you did not use C++ objects and instead had code scattered all over the frame processing function and various PluginCore functions, then consolidation would be difficult.
In our volume plugin here it does not make sense to create C++ objects to implement volume and mute, but we will use the C++ object paradigm as much as possible other example plugin projects. And you will find that the included fxobjects.h and fxobjects.cpp files are full of useful C++ audio processing objects that we will use throughout the book and you may use in any other C++ based signal processing system.
We can take advantage of the fact that we know that there must be a left channel present for any of our supported channel I/O combinations and simplify the code a bit and of course you are free to refactor the code however you like to make it more efficient or more readable. Looking at the volume plugin block diagram we see that the user adjusts the volume in dB. We need to convert the dB value of the GUI control to a raw multiplier for the audio signal processing using the following equation:
This introduces an important concept: the GUI control delivered a value that we could not immediately use. We needed to manipulate this value to arrive at something we can use directly in the signal processing routine. The data delivered from the GUI control is sometimes called raw data. We then take that data and cook it to create our final volume multiplier coefficient. This produces cooked data and the dB equation above can be thought of as the cooking equation. Very often the cooking process is complex, in which case we will create a separate cooking function to handle this chore. We will use the terms raw and cooked throughout the SDK when referring to these values. Referring to the block diagram again, we see that we need to not only calculate a volume multiplier value, but we also need to take into account the mute and channel settings. Rather than dwell on each line of code, let's examine a simple and perhaps naïve approach, disregarding the parameter smoothing or VST3 sample accurate automation options. Here we will create left and right channel volume multiplier values which will take on either the cooked volume value, or 0.0 if the channel selection does not include it, or if the mute switch is engaged. In this case, we may fill in the signal processing with this code:
With our left and right channel volume multiplier values calculated we can then do the actual signal processing. Notice how the VU meter value is formed; since the PluginParameter will automatically rectify the signal as part of the meter ballistics operation, we only need to feed it the ordinary audio signal value of interest that is the output value here. Also, note how the mono-in-stereo-out logic simply copies the left output to both the left and right channels, which is appropriate for this plugin.
If you compile and test the plugin, you will see that it behaves as designed, though perhaps a bit underwhelming since it is just a volume control. Now let's step back and think about our CPU intensive calculation part: the only really complicated math involves cooking the raw dB value into a volume coefficient. But do we really need to run this equation on every function call to processAudioFrame? This is going to depend on whether the volume parameter has undergone smoothing (either automatic, or via the VST3 sample accurate process).