Creating Audio Plugins, Part 4

  • Tutorial
All posts in the series:
Part 1. Introduction and configuration
Part 2. Learning the code
Part 3. VST and AU
Part 4. Digital distortion
Part 5. Presets and GUI
Part 6. Signal synthesis
Part 7. Receiving MIDI messages
Part 8. Virtual keyboard
Part 9 Envelopes
Part 10. Refinement of the GUI
Part 11. Filter
Part 12. Low-frequency oscillator
Part 13. Redesign
Part 14. Polyphony 1
Part 15. Polyphony 2
Part 16. Antialiasing



It's time to start writing our first plugin. It will be a dirty digital distortion. More specifically, the plugin will simply trim the peaks in the amplitude of the audio signal.

Digital distortion



We will limit the signal values ​​that exceed a certain threshold so that they do not go beyond it:



By saying “exceeding” I mean “exceeding a certain positive threshold or falling below a certain negative threshold”.

Using the good old script, duplicateyou can copy any project, giving it a new name. And we do not have to make all the changes that I described earlier for each new project.
Open the terminal, in it go to the IPlugExamples directory and enter this:

./duplicate.py MyFirstPlugin/ DigitalDistortion YourName

If you have not read the previous posts, the results from them can be downloaded from here . If you are doing this on a Mac, make sure that no other projects are open in Xcode. In the freshly created DigitalDistortion folderlies the DigitalDistortion.xcodeproj file . Open it, check that the APP target assembly starts without errors. Edit the schemas as I described earlier so that REAPER runs for VST and AU. Do not forget that Arguments Passed On Launch should point to the desired .rpp file.

Now, when starting REAPER, it does not load MyFirstPlugin , but DigitalDistortion . Wonders. This is because project files in REAPER are simply structured text files in which the script duplicatereplaced all “MyFirstPlugin” with “DigitalDistortion”.

Let's first rename the parameter mGainto mThreshold. Open DigitalDistortion.h and renameprivate variable:

private:
  double mThreshold;


Now, in DigitalDistortion.cpp, replace (Cmd + Alt + F) all that you find Gainwith Threshold. When assembling, no errors should pop up. In the constructor, in the parameter initialization line, specify 0.01both the minimum value and the 100.0default value:

GetParam(kThreshold)->InitDouble("Threshold", 100.0, 0.01, 100.0, 0.01, "%");


Now let's write the digital signal processing directly:

void DigitalDistortion::ProcessDoubleReplacing(
    double** inputs,
    double** outputs,
    int nFrames)
{
  // Mutex is already locked for us.
  int const channelCount = 2;
  for (int i = 0; i < channelCount; i++) {
    double* input = inputs[i];
    double* output = outputs[i];
    for (int s = 0; s < nFrames; ++s, ++input, ++output) {
      if(*input >= 0) {
        // Make sure positive values can't go above the threshold:
        *output = fmin(*input, mThreshold);
      } else {
        // Make sure negative values can't go below the threshold:
        *output = fmax(*input, -mThreshold);
      }
    }
  }
}


If the error gets out about what is fminand fmaxis not identified, try to rename them simply minand max. If this doesn’t help, add the following to the DigitalDistortion.cpp header :

#include 


If this does not solve the problem, add this instead of the previous line:

#include 


And replace fminwith std::min, and fmaxwith std::max.

Despite the fact that the value is channelCounthard-coded, we removed some redundancy by using an external loop forto iterate over the channels. That is, first the plugin processes several samples from one channel, and then does the same with the samples of the second.
An interesting point with the conditional operator if. For positive values ​​of the amplitude, we choose the smaller of the two: either the input value or the threshold. For negative ones, on the contrary, we choose the larger one: either *input, or a negative threshold value. In short, we always choose the value that is closer to zero.
Launch the plugin in REAPER and drive it to the test sound. When the knob is turned all the way to the right, a clear sound will be heard. The more the knob is turned counterclockwise, the more distorted the signal becomes.
As the distortion increases, the signal becomes quieter - this is because we lower the threshold value closer and closer to zero, and, accordingly, cut off the amplitude to increasingly quieter values. To compensate for this, we divide the input value by a threshold:

if(*input >= 0) {
  *output = fmin(*input, mThreshold);
} else {
  *output = fmax(*input, -mThreshold);
}
*output /= mThreshold;


A little higher, we set the minimum value for the parameter equal 0.01. Thus, we will never divide by zero, even if we turn the knob all the way to the left.
Now, if you run the plugin again, the amplitude will remain at the same level. But the volume will seem higher: the cutoff of the amplitude brings our sine wave closer in shape closer to the meander , which has a larger rms value .

So far, I intentionally try not to get into the jungle of digital signal processing. In my opinion, a good plugin is not just signal processing algorithms. This is a mixture that includes

  • reliable host compatibility (settings, stable operation)
  • good sound (here is pure digital processing)
  • intuitive user interface
  • beautiful appearance


So before diving into the sound processing algorithms in the next posts we add presets and a more pleasant interface.

Original article:
martin-finke.de/blog/articles/audio-plugins-005-digital-distortion

Also popular now: