Managing Audio with Pd
Let's put these components together and try to do something useful with them; let's make a simple reverb filter, using the above techniques and one new one, the delay line. If you already have experience with designing sound effects, you probably know what a delay line is; if not, think of it as a buffer for sound. Sound that goes into a delay line inlet is stored for a fixed period of time before it comes out again. All sorts of complicated technologies have been used to implement delay lines in the analog realm, some involving special springs and loops of tape. Fortunately for us, we are dealing with digital signals where a delay line can be implemented with nothing more than a FIFO (first in, first out) buffer.
Reverb is a natural phenomenon caused when a sound reflects off surfaces in its environment. Due to increased distance, these reflections arrive slightly after the initial sound is heard. These reflected sounds also are reflected themselves. Most environments have some degree of reverb, and indeed a carefully controlled level of reverb is a sought-after feature in concert halls. A room without reverb is discomforting, because every sound you make seems like it's been snatched out of thin air.
The heart of this filter is the delay line. Figure 13 shows a delay line adding a one second (1,000msec) delay to the sound input. Delay lines in Pd are named, meaning that to use one you need two separate objects, a writer and a reader. The writer, delwrite~, takes two arguments: the first is the delay line's name, and the second is the maximum delay you want to use in msec. You can have only one writer per delay line. The second half is the reader, delread~, which also takes two arguments: the name of the delay line and amount of delay you want. Unlike the writer half, you can have as many readers as you want, with any delay time you want. An additional type of reader, the variable delay object (vd~), can change its delay in response to an audio signal, but that's beyond the scope of this article.
To recap, a reverb filter needs one straight signal path, the main signal, and one or more delayed signal paths, the reverberations. The reverberations are recursive, so some form of feedback needs to be in the system. Finally, although our inputs and outputs are stereo, in the interest of space we simply implement a mono reverb filter. For this, the incoming left and right need to be mixed together and split at the other end. Figure 14 shows such a filter. If we follow the signal patch from the inputs, the first thing you should notice is the *~ 1 object. This object is included to make the patch a bit cleaner. It multiplies the signal by one, which is useless in itself, but it also gives us an inlet to connect both the left and right channels and mix them into one. You can see a similar structure at the bottom of the patch. The reverb signal then is sent to another multiplier to attenuate the reverberation before it goes through another reverb cycle. The delwrite~ and delread~ form a loop of reverberation. Finally, the outlet of the multiplier is sent back to the dac~.
Make sure the MIDI device you want to use, preferably a control device such as the Evolution UC-16, currently is working. An easy way to verify that MIDI events are being received by Pd is to go to the Test Audio and MIDI menu item in the Help menu on the upper-right corner of any window. Open them and generate some MIDI events. If your controller is working and sending out control messages, as opposed to note events, you should see the numbers under the ctlin (control in) object at the bottom of the window change. You may need to play with the -midi command-line argument to Pd to get this working; also, make sure you read the debug messages displayed as Pd starts up by using the verbose option.
If all of this works, try out the patch shown in Figure 15. It's identical to the reverb patch in Figure 14, except the reverb and delay now are controlled from MIDI rather than from the GUI. This switch is achieved with the ctlin object, which takes one argument in this example, the controller number of the control you want to use. The output is the raw value from the controller. Assuming you are using a UC-16 or similar controller, this is a value from 0 to 127. The other objects need to do a little math on this value to get it into the desired range. In the case of reverb, the range we want is from 0 to 1,000, so we divide by 127 to get a value from 0 to 1 and then multiply by 1,000 to get our final value. For decay, a value of 0 to 1 is good, so we need only to divide. Providing visual feedback on the values to which your effects are set is good practice, so this patch sends a copy of both reverb and decay to number boxes marked as such.
There you have it—a fully computerized, MIDI-controlled sound effect made from only a few Pd objects connected together. This is only the beginning of what's possible. Got a MIDI keyboard? You can use it as a control device and make a patch that actually synthesizes the notes. Or, make a patch control the MIDI keyboard. You even could make an entire reprogrammable effects box. Furthermore, you don't have to be content with the existing objects in Pd; you can write your own in C or even in Pd itself. With Linux and Pd, the only limits are your skills and the speed of your CPU.
All of the examples from this article are available from the Linux Journal FTP site at ftp.linuxjournal.com/pub/lj/listings/issue116/7062.tgz.
Peter Todd has been using Linux since he was 14. He has a part-time job as the head techie of a small Linux-based sound studio. When he's not working he attends Wexford Collegiate, where he currently is studying ceramics and graphic design.
- High-Availability Storage with HA-LVM
- DNSMasq, the Pint-Sized Super Dæmon!
- Localhost DNS Cache
- Real-Time Rogue Wireless Access Point Detection with the Raspberry Pi
- Days Between Dates: the Counting
- Linux for Astronomers
- You're the Boss with UBOS
- The Usability of GNOME
- Multitenant Sites
- PostgreSQL, the NoSQL Database