Amplitude envelope from mathematically-defined curve

    Jun 25 2013 | 3:01 am
    I want to use mathematical functions to generate amplitude envelopes. I am a relative newcomer to Max and am not sure of the best way to achieve this. The approach I have been working with thus far is demonstrated in the attached patch.
    I am using uzi + expr to generate a number of coordinates and storing them in a buffer~. I then use a metro + counter to output the y-values from the buffer~ and use these to scale the gain of an oscillator. The resulting sound is close to my goal, but includes some unwanted noise.
    Looking for suggestions about a better way to do this. Should the envelope coordinates be stored in a table instead of a buffer~? Is there a better way to extract the coordinates from the buffer~ using index~ or something similar? I tried a few different implementations without much success. Is there a canonical way to generate envelopes like this?

    • Jun 25 2013 | 10:33 am
      with [sadam.envelopeGenerator], you could do something like this:
      [sadam.envelopeGenerator] is part of The sadam Library, freely downloadable from .
      HTH, Ádám
    • Jun 25 2013 | 11:18 am
      i am not sure why you connect a [peek~] to the [*~], this does nothing. is that a typo? this is the place where normally a [play~] would belong – then all is fine.
    • Jun 25 2013 | 11:58 am
      i am not sure why you connect a [peek~] to the [*~], this does nothing.
      In fact, it does. If there is no signal arriving to second inlet of [*~], a simple float would do the job.
      (Not that I say that this should be the way to go. In fact, it's not...)
      HTH, Ádám
    • Jun 25 2013 | 7:04 pm
      Thank you for the suggestions. The [sadam.envelopeGenerator] object is useful, although in this case I want an implementation that does not rely on any additional externals. The example gave me the information I needed to get a smooth amplitude envelope. Instead of using [buffer~] to store the envelope coordinates, I am now using [function] and [line~] which results in cleaner audio.
      If anyone is interested, I have attached an example using this approach.
      In the interest of learning, can anyone explain why it is better to use [line~] rather than looping over a set of points (using [metro], for example) and adjusting the gain with [*~] directly with those points? The latter results in audio with clicks (as you can hear in the patch from the original post). Are those clicks simply due to abrupt changes in gain? I didn't expect those changes to be a problem if there were a sufficient number of points (i.e. the changes shouldn't be very abrupt), but I hear those clicks/pops even using a large number of points.
    • Jun 25 2013 | 9:09 pm
      using your original patch, this is how i would do it to be sample-specific:
      (also take a look at slide~ and rampsmooth~ objects if you ever do want to go from control-rate to audio-rate)
    • Jun 25 2013 | 11:32 pm
      @Drohnee Max runs on two threads: the event thread and the audio thread (although with Overdrive enabled, the scheduled events run on a separate, high-priority thread). Signal processing runs on the audio thread, which executes in real-time. On the other hand, the low-priority thread running the non-audio events runs slower: for example, a metro object won't send a new bang until the processing of the last one finished. This might seem awkward at first glance, but in fact, it's not.
      So, if you set the gain with a non-signal event, it will surely cause clicks in the sound, since there are dozens of samples per each non-audio event. It simply can not be smooth.
      A more detailed (and, BTW, great) summary about threading and priorities in Max can be found here:
      Hope that help, Ádám
    • Jun 25 2013 | 11:50 pm
      @karaokaze: Thanks for showing me how to modify my original patch to get this working with sample accuracy. Very helpful.
      @sadam: Appreciate the description of the two threads and the link to that informative post. The clicking in my original patch makes more sense to me now.