gen~: The Garden of Earthly Delays

    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.
    application/zip 23.25 KB
    Download the patches used in this tutorial
    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.
    1. 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.
    2. 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.
    3. 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.
    4. 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.

    Ring Tones

    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).

    Doubling Down

    Often, you don’t really need to do anything really difficult to get good results. Our second patch drive-by1b.maxpat builds on that with a few simple extensions. Since one damped ringing delay line sounded pretty wonderful, let’s add another one for each channel (and an MSP line~ object in the patch to smooth things out a little on input), and let’s also add another of those mixer-history-feedback modules to the overall output to add some ringing to the combined signals. I’ll wager that the resulting howling and humming will get you thinking about the same thing as I did – I started using mathematically related input values for the number of samples to delay to get tuned or harmonic effects. Please feel free to live with the harshly soothing sound of this patch for a while.

    Pitching Practice

    drive-by1c.maxpat, the third iteration of our patch, does its work outside of the gen~ object itself – it adds a simple little subpatcher named that lets us tune the ringing delay lines by using a keyboard – I’m sure it’s occurred to you that this would be handy to do (although I found tuning the delay lines by hand to be a pleasant and restful activity). Here’s the inside of the subpatcher for your study and edification.
    I’m sure that some of you may already be thinking about just intervals (musical intervals that can be expressed as simple whole-number frequency ratios) rather than living with the equally tempered intervals that the Max mtof object produces. Feel free to make those changes for yourself (they sound pretty wonderful, trust me).

    It's the Network, Silly....

    drive-by1d.maxpat, the fourth iteration of our drive-by tutorial patch, adds a final minor variation that manages a modestly impressive major transformation of the proceedings.
    All we've added is a gate operator, which functions in much the same way as its Max and MSP cousins - an incoming message relayed by way of the param operator named feeder is used to send the delayed signal for reinjection into the delay line to one of the four delay lines we've set up. That means you can route your signal back to itself (as we've done all along), to the second tuned delay line on the same audio channel, or to the first or second delay lines on the opposite channel. The result of this reassignment is that the ringing delays become quite complex - the interplay of damping and pitch and the routing of the delayed signals result in some really interesting sounds.
    Of course, there are always other possibilities. More ringing delay lines? Sure. More complex routing? You betcha. More subtle approaches to amplitude control? Why not? This is a shameless attempt (as is the omission of the wet/dry mixer logic in the last couple of examples, to be honest) to encourage you to play around with the patch. Good luck and happy patching!

    by Gregory Taylor on
    Nov 7, 2011 5:40 PM

    • Lume
      Nov 07 2011 | 11:46 pm
      ha! nice one. looking forward to how this is used for visuals.
    • Steve's icon
      Steve's icon
      Nov 08 2011 | 3:56 am
      Fantastic stuff.
    • AudioLemon's icon
      AudioLemon's icon
      Nov 10 2011 | 5:43 pm
      I was hoping for a Gen~ tutorial but the patches are a real bonus - thanks!
    • Gregory Taylor's icon
      Gregory Taylor's icon
      Gregory Taylor
      Nov 11 2011 | 8:38 am
      There is a gen~ tutorial in the works. Tutorials take a lot longer to do than my having a nice time and trying to briefly explain the whys and wherefores. It is definitely in the works, and we appreciate your patience, as ever.
    • Julien Bayle's icon
      Julien Bayle's icon
      Julien Bayle
      Nov 15 2011 | 11:17 am
      gen~ is a really huge world itself. I cannot wait for grabbing output source code :p
    • hz37's icon
      hz37's icon
      Nov 29 2011 | 5:50 am
      Thanks for sharing this, truly wonderful. PS: In the fourth patch, the gate outlet 4 ("other side") goes to the same inlet twice for the last gate.
    • AudioMatt's icon
      AudioMatt's icon
      Mar 07 2012 | 1:01 pm
      Gregory your writing has always been amazing.
    • TConnors's icon
      TConnors's icon
      Jul 24 2012 | 10:18 pm
      Humm. When I open the patches downloaded for this tutorial they do not look anything like the ones given in the above example.
    • TConnors's icon
      TConnors's icon
      Jul 25 2012 | 4:14 pm
      Ah! Never mind that last message. I’m new to MaxMspJitterGen world and I’m still stumbling around.
    • Mutorsound's icon
      Mutorsound's icon
      Nov 23 2012 | 6:49 pm
      Within a few minutes I was making big nasty phasor patches that sounded awesome. Loving it!
    • JeffD's icon
      JeffD's icon
      Mar 08 2013 | 9:50 pm
      I've tried downloading these patches a couple times now and they don't seem to open for me. Even if Max is already running, when I try to open the patches, Max just shuts down. Is there a way to fix this?
    • Max Gardener's icon
      Max Gardener's icon
      Max Gardener
      Mar 09 2013 | 12:38 pm
      Platform? OS version? Max Version? I just downloaded the package and everything runs perfectly well on a 10.7.5 Mac running Version 6.1.0 (ee85fad) at 32-bit. Everything in the patch is vanilla gen~ So I can't reproduce your difficulties. What's your system like?
    • Mattebass's icon
      Mattebass's icon
      May 20 2013 | 6:54 am
      simple question: why connecting the feedback directly from mix causes delay explosion (like as having feedback=1), I can't understand the difference with the choice of connecting from the history operator. thanks
    • Stephane Morisse's icon
      Stephane Morisse's icon
      Stephane Morisse
      Aug 13 2013 | 4:04 am
      This is explained : gen works in a synchronous way, that's why you have to use history.p
    • kgoold's icon
      kgoold's icon
      Feb 05 2014 | 4:55 am
      When you say "lowpass filter", are you talking in terms of EQ? If so, I don't get it. If not, what are you talking about?
    • woyteg's icon
      woyteg's icon
      Feb 05 2014 | 1:27 pm
      When you say “lowpass filter”, are you talking in terms of EQ? If so, I don’t get it. If not, what are you talking about?
      Yes he is. I mean what does "in terms of EQ" mean? It's just a lowpass filter, feed audio throught it and you'll see. It is, to be more specific a simple IIR onepole lowpass of the form y[n]=x[n]*a + y[n-1]*b where a=1-b and b= the param weighted_average
    • kgoold's icon
      kgoold's icon
      Feb 09 2014 | 5:31 am
      I'll take your word for it. The math is beyond me. I did try the example on this page and I did hear the result. So I got that going for me.
    • woyteg's icon
      woyteg's icon
      Feb 09 2014 | 12:19 pm
      no, common, the math is not beyond you, sorry for stating this a bit short. take the simplest FIR filter, a moving average: take the input sample, the last input sample, add them, multiply by 0.5. moving average right? that would be: y[n]=(x[n]+x[n-1])*0.5 This is exactly the same, but kind of infinite :)
    • vichug's icon
      vichug's icon
      Feb 09 2014 | 3:06 pm
      hm. fir is frequency impulse response right ? so what's the link with a moving average ?
    • woyteg's icon
      woyteg's icon
      Feb 09 2014 | 10:57 pm
      no, a fir filter is a Finite imulse response filter, so a filter whose response to a finite signal is always finite. == no feedback.
      I'm not entirely sure about the definition and don't want to talk too sophisticated blabla but I think this is mostly correct: (discrete) FIR filter has a finite response to the unit impulse function (=[click~]) always, A IIR Filter(infinite impulse response) can have an infinte response given the coefficients are set that way. there is feedback. Analog filters are always IIRs, digital filters can be FIRs. A fir filter would for example be the above. Also buffir~ is a FIR filter. A FIRs impulse response is always equal to it's coefficients, if you look that up, that's pretty logical.
      IIRs in max are for example the [biquad], [onepole], [slide] etc..
      edit: wanted to be correct here..
    • Tosh Molloy's icon
      Tosh Molloy's icon
      Tosh Molloy
      Feb 14 2018 | 11:36 pm
      Gregory, thank you so much for this lesson. I made a piece for cymbals & electronics based on this idea: https://soundcloud.com/toshmolloy/perpetua-4th-raga?in=toshmolloy/sets/perpetua-4-ragas All the best! Tosh
    • johan englund's icon
      johan englund's icon
      johan englund
      May 07 2021 | 10:45 am
      Soz, I know this is an old thread but I'm just curios about the history operator – as it defaults to 0, why are you setting the initial value to 0? Best
    • 👽It W∆s ∆lienz👽's icon
      👽It W∆s ∆lienz👽's icon
      👽It W∆s ∆lienz👽
      May 07 2021 | 3:56 pm
      why are you setting the initial value to 0?
      0 is silence. Most of the time, you'd want to initialize history ops with 0s, that way you avoid any unwanted clicks/pops/etc. right when audio is first turned on.