Building an AD envelope with curve~ and retrigger

exitdevice's icon

Hi all, I am implementing a monosynth using a simple attack-decay envelope that utilizes curve~ (in hindsight, I see I could have just used live.adsr~, but I think this is a good exercise for me regardless).

I am attempting to use poly~ with two voices to limit the amount of "clicking". I would like to implement some sort of retrigger functionality (like what adsr~ offers), where the level moves to zero in a specified amount of time if asked to trigger before the envelope finishes. I'm a bit at a loss as to how to implement this and would appreciate any pointers or input. Am I correct in thinking this can all be handled at the envelope level? Or do I need to make changes inside at the voice level?

Thanks for reading!

EDIT: I originally posted AR envelope, which was a mistake.

Max Patch
Copy patch and select New From Clipboard in Max.

Source Audio's icon

get voice status.

if on and needs to retrigger, fade out in retrigger time, then fire curve message.

by the way, your curve message does not work with short notes

and also takes no notice about note off message (velocity 0).

what is that good for ?

exitdevice's icon

get voice status.

if on and needs to retrigger, fade out in retrigger time, then fire curve message.

Thank you for the reply! I knew it was something simple. I will chew on that.

by the way, your curve message does not work with short notes

and also takes no notice about note off message (velocity 0).

what is that good for ?

My goal was to make an envelope with attack and release only -- so when a note on event is received, the envelope beings. A note off message isn't necessary in this paradigm, unless I am missing something. I am an ultra-beginner though so happy to receive any and all feedback.

Source Audio's icon

release would be note release = note off.

Your envelope has only start.

means all notes can be only as long as your envelope , no matter how long you hold them.

but if note off arrives before your curve ends, you mute ??? the voice

and send that "signal env trigger" to muted voice ?

exitdevice's icon

You are correct - I was very much using the wrong words. I am attempting to make an AD envelope! That is why I am ignoring note off. I appreciate your suggestions for the retrigger part -- I will try to implement this.

I edited the title of this post and my original post to avoid further confusion!

Source Audio's icon

maybe you want to have a look at function object in curve mode,

which also offers to put a point into sustain mode, then continue when

note gets released.

this is one example for poly instance:

Max Patch
Copy patch and select New From Clipboard in Max.

exitdevice's icon

I am still struggling with the re-trigger portion. Assuming I have voice status, how do I route the flow accordingly? In procedural programming, this would be something like:

if (voice_status == 1):
    curve(0, 10)
curve(atk, decay)

In other words, if the envelope is triggered when the voice is active, use curve~ to go to zero in 10 ms. Then fire the normal envelope.

I don't understand how to implement this is Max. I think I'm struggling with a basic "philosophy" of the language.

Roman Thilenius's icon

yup, AD, thought so.

the retriggering itself just works out of the box for line~ and curve~.

as for the clicking issue itself you could do the following: add interpolation, but only at the very beginning of the envelope using a gate~ object.

hopefully you are aware that this either needs lookup time / latency or the perceived transients of your music signal will be delayed. (and if it is really required for a synthesizer is also a discussion which would fill books.)

proposal for a basic principle (no idea if it actually works, test it with very long time values to check, but then you need to use a buffer or counter instead of click):

exitdevice's icon

I don't see how retriggering works out of the box for curve~. It appears to return to zero immediately, which is causing popping/clicking. Ideally I could control the retrigger time.


Roman Thilenius's icon

well that is intented and how most synthesizer oscillators work.

there are always three options: 1.) let it click, 2.) use interpolation as shown above, or 3.) use the current amplitude value to start a possible new attack phase from.

the latter is only possible by scaling the attack phase after the curve~ object, and not by changing the messages for its input.


Source Audio's icon

no matter what you use to retrigger sounding voice,

you need to fade it down before retriggering.

for that you need a switch detecting signal state,

and if it is > 0, then send curve down first.

here is very simple example, using 50 ms retrigger time

Max Patch
Copy patch and select New From Clipboard in Max.

Roman Thilenius's icon

it is actually not so easy. because when the attack phase is shorter than the interpolation, the interpolation time has to be shortened likewise or your next event will come late and never reaches its max amplitude.

for things like that it can be a good idea to build the envelope around line~ and do a custom curve distortion at the end, i.e. after interpolations, loops, scalings are done.

if you want realtime modulation of envelope parameters in addition there is no way around a custom signal-only solution. ;)

exitdevice's icon

Very interesting discussion. I am comparing a lot of the behavior of my monosynth to Ableton's Operator set to one voice with similar envelopes. Although Operator clicks, it is a much less abrasive one. I wonder what secret sauce they are putting in..

This is the case even when using live.adsr~ instead of my goofy halfbaked AD envelope.

Roman Thilenius's icon

simple method example for custom curved envelope.

all this nonsense is required because there is no expr~ object ... you might want to use gen~ instead


to trigger an envelope using signals you can also use count~ instead of line~ (or actually phasor~).

it´ll get more and more inaccurate for very small time values, but for envelopes that is usually no problem. (but don´t use fig. 2 for tuned oscillators.)