Take a quick tour of a few of the Plug-Ins you will write through the course of the book. Some of them have Custom GUIs and some don’t though all of them can support having a Custom GUI. Watch in 720p.
The book is full of algorithms and the Projects use most of them to demonstrate the Plug-In coding. The book projects consist of (these follow the order in the book):
- Volume in dB
- Simple HPF
- Resonant LPF
- Digital Delay Line Module
- Stereo Delay with Feedback
- Direct Form Oscillator
- Wave Table Oscillator
- Modulated Delay Module
- Stereo Quad Flanger
- Stereo LCR Chorus
- Modulated Filter
- Envelope Follower
- Dynamics Processor
- Spectral Dynamics Processor
- Ring Modulator
- Wave Shaper
Unzip the projects into your RackAFX Projects folder; you can find the folder by using the Start menu and navigate to the RackAFX menu item and find the RackAFX Projects Folder. You can also find it in the RackAFX menu File->Open Projects Folder. These projects were updated 6.4.2012.
A few readers have been asking about a general purpose convolver; the convolver from my book and that is built-in to RackAFX uses the Analyzer Window as a user interface for selecting IR files. But there is another way – use the built-in CWaveData object. CWaveData is a C++ object I wrote that opens a WAV file and extracts its audio data into a floating point buffer. It supports a variety of file formats:
- 16-BIT Signed Integer PCM
- 24-BIT Signed Integer PCM 3-ByteAlign
- 24-BIT Signed Integer PCM 4-ByteAlign
- 32-BIT Signed Integer PCM
- 32-BIT Floating Point
- 64-BIT Floating Point
Regardless of input format, it always returns a buffer of floats – it extracts the entire contents of the file at once. You can use it by constructing it with a path to a wave file, or you can let the user select a file. Both methods are shown in the sample code; the first in the constructor and the second in the userInterfaceChange() function when Assignable Button A1 is pressed. I’m super busy right now so I didn’t do a whole lot of commenting but the code should be reasonably obvious – use the Forum if you have questions.
- MAKE SURE YOU COMPILE AND RUN IN RELEASE MODE – linear convolution is a CPU hog and debug mode has too much overhead; if you need to compile and debug in Debug mode, that’s fine for checking index values, buffers etc… but actual convolution will be glitchy unless you have a super-fast computer
- download and place the file lpf2sir.wav in your C:\ root directory if you want to match my code exactly (see the constructor for this path – you can change it (and the file name) here; you will get an error message if the file is not found)
- be careful with linear convolution – I’ve seen some IR files that are not normalized properly and will clip after the full accumulation (correctable by attenuating the input signal); I’ve also seen some files that had 1024 points of actual data, but in files that were 22050 samples (or more) in length – this will clog the processing function
- you can find the object declaration in pluginconstants.h and the implementation in pluginobjects.cpp
- the project is stock RackAFX, but you can use the Make VST Compatible feature to make a VST version; make sure you use the GUI editor to drag and drop an instance of the Assignable Button bank in a RackAFX GUI, and set the “Use Custom RackAFX GUI” button on the Edit Projects page. You need this button if you want to use the object’s initWithUserWAVFile() feature (if you are hard-coding your IRs, you don’t need it)
You can construct the CWaveData object two ways; first is with a path to the file:
CWaveData* pWaveData = new CWaveData(“C:\\LPF2sir.wav”);
The other is by calling the init() function:
CWaveData* pWaveData = new CWaveData(NULL); // construct with NULL pointer
pWaveData->initWithUserWAVFile(); // then, call init() function for user selection
The buffer of data is in
Multi-channel data is interleaved just as in the file; stereo is L/R/L/R/etc…
CWaveData Member Variables:
UINT m_uLoopStartIndex; // start index of FIRST loop
UINT m_uLoopEndIndex; // end index of FIRST loop
UINT m_uMIDINote; // MIDI Unity Note
UINT m_uMIDIPitchFraction; // Unity Note pitch fraction
bool m_bWaveLoaded; // true if succeeded loading file
// the WAV file converted to floats on range of -1.0 –> +1.0
This famous 4th Order LPF is found on classic Moog Synths. Stilson and Smith published a paper on a digital equivalent in 1996. You can get the paper here. Although there are some issues with the design (it can and will blow up and the frequency control is not perfectly linear) its simplicity and decoupling of the cutoff frequency and Q controls makes it easy to implement and very efficient on CPU cycles. You will also notice how the feedback path cancels out low frequencies thus reducing the LF gain as the Q is increased.
- Moog Synths have knobs that are labeled 0 to 10; this project reflects that by similarly labeling the controls. Check the calculateCoefficient() functions; there are two of them, one that uses the Moog 0->10 version and another that uses the standard fc in Hz and Q as a number from 0.707 on up.
- I set the Q range from 0.707 to 25 to map to the original design. At a Q of 25, the filter will self oscillate.
- I added bounding code to prevent the filter from blowing up. If you want to experience the blowing up, comment out the code below the comments that say // bounding
- The block diagram and difference equation for the single-pole filter stages G(z) are shown below.
The Chapter 6 Resonant LPF project does not specifically include the Massberg version; a reader discovered a typo in an equation on Page 203. The error is in the calculation of g1, gz, gp and the Q decision branch (on the square root of 0.5, not 5.0); click on the image to open in a new window and you can print it out for the book.
This project implements both the normal Bilinear Z-Transform (BZT) LPF and the Massberg version; the first button bank is used to select between them.
This Chorus unit is based on the Roland Dimension D® Chorus. Known for its subtle transparent sound, it features a shared but inverted LFO and an interesting output section where each output is a combination of three signals:
- Chorus Output
- Opposite Channel Chorus Output, inverted and high-pass filtered
The controls on the original unit consisted of four switches only; these were hardwired presets and changed:
- the LFO Rate (either 0.25Hz or 0.5Hz)
- the Depth
- for one preset, the Wet/Dry Mix ratios for the two channels (WL vs DL, WR vs DR)
Here I have added two more level controls for experimentation: WCL and WCR which are the filtered, inverted chorused signals from the opposite (crossed) channels. Experiment with various rate, depth and output mixture combinations as well as different HPF cutoff frequencies. This version can sound very subtle or very processed depending on the settings. The algorithm was put together using information from Mark Cole’s document.
This project was updated on January 7, 2015 to fix a bug with the Wet/Dry control which did not work properly. You are encouraged to lower the upper limit on the Rate variable to somewhere between 1Hz and 2.5Hz for a wider range of subtle control. If you like getting sea-sick, then increase the upper limit above 5Hz and set the Wet/Dry mix to 100%.
Here are alternate Bandpass and Bandstop filters that you can add to your filters on page 184 of the book. NOTE: there is a typo in the Butterworth BPF and BSF equations in the book: The “C” term in the coefficient calculations for the Butterworth BPF and BSF both have a typo in the tan() function; remove the fc term from the calculation. Thanks to Ernst Oosterveld for finding this!
The source is an excellent book full of algorithms called DAFX published by Wiley – check it out if you don’t already have it (note that the author prefers swapping the a and b coefficients as discussed in my book). These filters do not use the “toxic” tan(thetaC/2Q) which blows up when the argument is pi (there are many filter designs with this same issue). The tan() function is still there, but only evaluates to pi when the center frequency is Nyquist and is independent of Q. The project uses the built-in BiQuad object. Click on the equation graphic to get the full-sized version. NOTE: this project was updated 2.12.14