Pure Data (PD) is a powerful open source visual-programming language that is well suited for rapidly prototyping procedural audio concepts. Although the vanilla version distributed by Miller Puckette is feature-rich enough to deal with most situations (and the one I will be using in this article), a variety of libraries and externals exist which can further extend the functionality of PD as needed.
- For a more thorough introduction to PD, I suggest Andy Farnell’s Designing sound; the PD chapter of which is available for free: http://aspress.co.uk/ds/pdf/pd_intro.pdf.
- If you’re more into videos, I recommend Dr Rafael Hernandez’s Youtube series: https://youtu.be/rtgGol-I4gA
- And, if you have a bit more time on your hands, you can even follow the lectures of Miller Puckette himself: https://podcast.ucsd.edu/podcasts/default.aspx?PodcastId=3157&l=2&v=1
The Analysis Phase
In order to showcase the kind of straight-forward approach one might take in devising a procedural system for a sound effect, I will walk through the process of creating a patch which generates the sound of an electric fan. This particular sound was chosen due to its clearly demonstrable design process from analysis to synthesis. To see a quick video overview I made of this patch, and to test it out, visit my blog post here: http://gu-on.com/2018/08/creating-an-electric-fan-in-pure-data-procedural-audio/
The above is a spectrogram of the source recording used for analysis. From this we can discern 3 prominent features of the sound.
- The first is the noisy spikes of energy near the very beginning and approximately ¾ of the way in. These are the flipping on and off of the mechanical switch of the fan.
- The second is the hazy energy which decreases in amplitude at higher-frequencies, which represents the sound of the fan moving air.
- The third is the more solid bars of energy which increase and decrease non-linearly after the switch has been flipped, which represents the sound of the fan’s motor. When the fan reaches its stable operation speed, these frequencies remain constant.
In order to generate this sound inside of PD we need to approximate these components.
The Switch – Sample Playback
For the switch click, the sound was simply extracted from the source file and played back in PD on a trigger. Different synthesis methods were tested for this component, but simple methods didn’t yield good results, and elaborate methods were needlessly complicated for what is a short and simple click. Often the best sounding procedural systems involve a hybridisation of traditional sample playback and nonlinear synthesis, however the best overall approach is ultimately dictated by the constraints of the specific project.
To achieve this in PD, a message box sends a read message to a soundfiler object, which points to a wav file in the project’s root directory (in this case FanClick.wav), and stores it as PCM data to an array called fanClick. A bang trigger button then sends the message
0, 6774 154
to a line~ object. This object is simply reading the values of the array from 0 to 6774, over a duration of 154 milliseconds, which corresponds to the length (in samples) and duration of the sampled audio. These values can be computationally derived from the audio itself, but have instead been hard coded for simplicity and demonstration purposes.
The Fan – Pink Noise
The steep roll off of the noisy portion of the waveform can be approximated as a kind of pink noise. Since the vanilla version of PD doesn’t have native support for this, I used a regular white noise generator, and applied some amplitude filtering. The bp~ (bandpass) object has arguments for frequency and Q, which I have centred on the fundamental of the motor component at 500Hz, and adjusted the Q to taste. This bandpass object will control the amplitude of the fan in response to the nonlinear curve that will be employed later. Next, two lop~ (lowpass) objects provide the steep high-frequency roll-off, with a cutoff frequency of 4500Hz. Since these are cheap 1-pole filters, they don’t have an adjustable slope curve, and thus two are used in series to increase the steepness.
The Motor – Wavetable Synthesis
The motor component shows a strong sinusoidal fundamental frequency with less pronounced harmonic overtones. There are many ways this could be approximated, such as with several osc~ components which can be manually set to match the apparent frequencies, but a much easier and cheaper way is with a sinesum function. This function accepts several arguments, and writes values to an array. The first argument after sinesum sets the size of the array (1024) which is ample resolution for this signal. The proceeding arguments then set the amplitudes of each of the partials (1 being max, and 0 being mute). These values were set by analysing the waveform, and adjusting further by ear.
The filled array then works like a wavetable, which can be read back from using a tabosc4~ object. This oscillator does 4-point interpolation, which allows for smooth transitioning between the non-linear frequency changes that will be employed later. In the example, messages with 1 and 0 are sent to a multiplier object (*500), which act as controls for the on and off state, effectively telling the oscillator to either generate at 500Hz or 0Hz.
The Curves – Creating non-linear control
There are various methods for creating control curves in PD. The method that I have chosen involves the use of a lowpass filter as a control signal. This effectively reads the values of the filter and outputs them as a data curve, where the cut-off frequency argument sets the transition time. The metro object acts as a timer, telling the snapshot~ object to output its value every 10ms. The sig~ object then coverts that control information into a signal which sets the frequency of the tabosc4~ oscillator. The snapshot~ object also outputs a second connection to a message box (with the message $1 10). The $1 acts as a placeholder variable that fills its value with whatever data is received by the input. When read into the line~ object, it transitions from whatever value it’s currently on, to the next value it receives, over a duration of 10ms. This 10ms is to ensure that the values interpolate smoothly, avoiding audible clicks resulting from discrete jumps in amplitude. This value is then scaled down by a factor of 500, since the non-linear curve is being set to transition from 0 to 500 to accommodate the frequency sweep, but I only want to scale the amplitude between 0 and 1. Finally the signal is scaled by this amplitude curve and output to the speakers.
Putting it all together – Interactive Controls
A primary strength of procedural audio lies in its potential for interactivity. Although the components previously outlined can be assembled to create a patch that is very light on memory consumption, a great deal more value can be extracted through parameterisation. The controls I have chosen are fairly arbitrary, and how this patch might be parametrised for practical contextual use – depends on the specifications of the project. I have created control for the on-off state, the operational speed/intensity of the fan, and amplitude controls for the fan and motor components. The controls in this instance serve to showcase how the model can seamlessly transition between states, and shows an interactive usability that is trickier to achieve using only traditional sampling.
The finished patch above illustrates the integration of the separate parts into one machine. Yellow shows the sample playback, red shows the filtered noise, teal shows the wavetable, green shows the non-linear control, and blue shows the parameterisation. A few extra features have been implemented for polish.
- Firstly, a spigot object has been used as a sort of logic gate to allow the operation speed to only work in real-time while the fan is activated. This means that if the fan is in its off state, it won’t magically turn on if the user decides to change the operation speed. However, the next time it turns on, it will be set to whatever the currently held value is.
- Noise~ has been abstracted so that there is only one instance of it actually generating a signal. It is then drawn from twice, once for the pink noise component of the fan, and again to add some irregularity to wavetable synthesis so that it doesn’t generate a perfectly flat sine wave. Using a generator in this way saves a bit on system resources.
- Finally a few more filters are used to shape and control the signal to the desired outcome. More time could be spent on optimising the loudness of the final signal to improve signal-to-noise, but everything has instead been scaled down to avoid clipping and simply get the overall idea across (facilitated by all of the *~ 0.5 objects).
The method presented is by no means perfect, but I hope that it helped to highlight the strengths of procedural audio, as well as the relative simplicity in getting started. I suggets playing around with the values to see what effect they have on the sound, and trying out different approaches to see what works best. Again, feel free to have a look at the blog post on my website with the interactive demo to play around with the final patch: http://gu-on.com/2018/08/creating-an-electric-fan-in-pure-data-procedural-audio/
Kevin Doran is a Technical Sound Designer and Procedural Audio Engineer.