After doing a quick tutorial at the Cycling â€™74 Expo, it became clear that lots of people out there were really surprised and happy to discover that they didnâ€™t need to be a supergenius to have fun with the gen~ object. While the new Gen stuff is as elegant and powerful as the day is long, you can also have quite a lot of enjoyment with a very few objects. So hereâ€™s a sequence of little patches that I hope will give you a window into having some audio fun without scaring the bejeepers out of you. These patches are not impossibly complicated, or efficient or elegant â€“ theyâ€™re the product of someone at play. I hope they encourage you to play, too. I even added some simple presets to spur your imagination.
- Download the patches used in this tutorial.
- Read the other tutorials in this series:
Gen need not be Rocket Surgery (although the Rocket Surgeons will find much to enjoy, Iâ€™m sure), but there are a few simple things that itâ€™ll help to know when looking at these patches.
- The flow of data inside the gen~ object is like MSP in that itâ€™s synchronous, but instead of thinking of performing some action on a block of samples, weâ€™re working with one sample at a time – which lets us do things with single-sample feedback that we could never do before.
- The flow of data inside the gen~ object is constant â€“ there isnâ€™t anything like a trigger, for example. It also means that gen~ operators are always sending something out â€“ a signal sample value, a parameter value, or the result of a test of some kind. We need something special that lets us control our patch with messages from the â€śoutside world.â€ť In the Gen world, we have the param (parameter) operator to do that. Youâ€™ll see it in use here.
- Since data is always synchronous, a feedback loop isnâ€™t really possible. Instead, we have an operator called history that acts like a single-sample delay that lets us create feedback loops for useful things like data smoothing andâ€¦ wellâ€¦ feedback.
- One difference you may notice between Gen objects and their Max cousins has to do with the relationship between arguments to a Gen operator and the number of inlets the operator has. Unlike Max object, using arguments to specify an initial value for a Gen operator changes the number of inlets an object has â€“ thatâ€™s because those initial values cannot be changed once specified. Hereâ€™s a simple example of that relationship using the mixer object, which weâ€™ll be making good use of in just a minute.
Okay. Letâ€™s get down to business!
This tutorial is going to be about manipulating delay lines. Since the gen~ object gives us access to audio on a per-sample basis â€“ and thus lets us set feedback loops that are tighter than the signal-vector variety that MSP provides, thereâ€™s a lot of room for creating new sounds.
The first patch drive-by1a.maxpat, demonstrates a few simple features of working with delays (using the delay operator):
Like the MSP tapin~ object, the delay operator at the heart of this patch takes an argument that specifies the length of the maximum delay possible (remember that since weâ€™re working with gen~, that amount is specified in samples). Although the delay operator can take a second argument to set multiple taps, weâ€™ll only need one delay line each for the left and right channels of our stereo gen~ patch. You might want to investigate that for yourself later on.
The other crucial piece of our patch is the mix operator. It not only lets us mix the wet and dry signals for output, but it introduces a way of smoothing data that gen~ aficionados use everywhere. The mix operator takes two input values in the first two inputs, and then outputs an interpolated value based on a value between 0. and 1.0 received in the right inlet. And of course, it works on one sample at a time.
Youâ€™ll see the mix operator used in two places â€“ to handle the wet/dry mix of the delayed and non-delayed signals (notice the clip -1 1 operator for waveform hygiene), and to create a mixable delay line. In both cases, weâ€™ve added a param operator that allows us to send messages to the gen~ object to set values by means of messages to our gen~ object. Of course, we could have adding another in operator or two and used the MSP sig~ object to control our patch – you might find that technique more to your liking, in fact.
The wet-dry mix should be pretty straight ahead, but I want to take a minute to consider this generalized example of using the mix operator for feedback and data smoothing. Here’s a generalized example of how to add feedback effects:
The feedback portion of the patch also uses the mix operator along with a param operator to control the balance of the current and previous signal values. Since the Gen environment is synchronous, we canâ€™t connect the output of the mix operator directly to one of its inputs to create a feedback loop. But donâ€™t worry â€“ the Gen history fb 0. operator functions as a single-sample delay line and will allow us to add the mixed signal back to itself (typing an argument into the history operator also lets us specify a starting value of zero for our feedback loop). If you have a specific kind of data smoothing in mind that doesn’t require modication of the amount of the previous signal being mixed in, you can add an argument to the mix object (e.g. mix 0.5) and skip the param object entirely. The clever trainspotter reading this tutorial is probably already thinking, “Hmm. Isn’t that a kind of lowpass filter?”
Yes, it is. And if you spend some quality time in the Gen examples folder, you’ll see some variation of it used quite often.
In the case of our example patch, we’re using this feedback loop twice in the patch – once for the left and right channels. In the case of our example patch, we send the averaged sample values on as output to the wet/dry mix, and also re-inject them into our delay operator. The result is the classic ringing delay line with a damping control. You can use this particular kind of patch for all kinds of useful tasks.
Note: the fold -1 1 operator makes sure that the feedback values never increase above a value of 1.0 or below a value of -1.0 â€“ if they do, theyâ€™ll be folded back for the next iteration. Itâ€™s a simple way of producing self-regulated output.
Try the patch with a variety of different kinds of input audio files â€“ some things will sound interesting, some wonâ€™t (thatâ€™s because an algorithm is never an automatic guarantee of interesting output unless youâ€™re a hard-core formalist).