Gen~ adsr with curved stages

J Mangel's icon

J Mangel

5月 29 2024 | 12:19 午前

ive managed to get the first stage to curve as expected, but cannot do so with the dec and rel stage. Any ideas?

Wil's icon

Wil

5月 29 2024 | 2:56 午前

you should zip your patch and include bpatchers

Graham Wakefield's icon

Graham Wakefield

5月 29 2024 | 2:28 午後

Aside from all the missing bpatcher files,

Generally when posting a question, it would be better to reduce the patch to only contain the specific thing you have a question about (rather than sending a huge patch), and frame the question with some context, e.g. how to operate the patch, describing the behaviour you want to see, what the patch is doing that you didn't expect, etc. Some guidance would help!

J Mangel's icon

J Mangel

5月 30 2024 | 2:55 午前

apologies yall. i saved that incorrectly. this should have only included the following. Graham, hello, this is still me working thru GO (tangentially). Hopefully this is whittled down enough now. Im posting this then checking it from the link. Zipped and unzipped.

essentially, i cant figure out why the decay phase of the envelope is behaving so strangely. Ive tried several variations on y=mx^2+b. when plotting on a graphing calc., that form seems to work for attack, but not for decay. Ive always believed that squaring/rooting any phase of an adsr that falls between 0.-1. will give you a positive or negative curve.

Thanks yall.

J Mangel's icon

J Mangel

5月 30 2024 | 4:17 午前

I ran the calcs a different way. its the 1/pow that creates an asymptotic decay... i cant see a way to fix that.

Graham Wakefield's icon

Graham Wakefield

5月 30 2024 | 2:16 午後

A 1/x type of function is likely to give an inverse exponential shape.

I tried looking at the patcher but it still is missing many bpatchers and has way too much going on. Just make a simple patch -- no bpatchers, just the single gen~ that you are trying to solve, and post that.

If it is just trying to shape a ramp, there's lots of options. A pow(x,a) where a < 1 will give a log-like response. So e.g. a=2 during attack, a=0.25 during decay:


Or you can look at different shaping functions -- the go unit shapers have a few that can be good for envelopes, and most take some parametric control, e.g. go.unit.arc.

Graham Wakefield's icon

Graham Wakefield

5月 30 2024 | 2:20 午後

Another nice and simple shaper is (pow(a,x) - 1) / (a - 1), where x is the triangular envelope input. Using 0<a<1 gives you a log-type shape, whereas a > 1 gives you an exp-like shape.

J Mangel's icon

J Mangel

5月 31 2024 | 1:19 午前

I really confused now. i went back and reopened my last post and all i had was one gen~ and no bpatchers. just to be safe, i deleted all the other patches.

so, i have been using the pow(x,a) on individual stages since i went down this path, but i keep getting bad results.

but now i think i know why. I was applying the function to individual stages, which are not normalized, so attack stage (0-1) works, decay (1-arbitrary#>0), does not, and terminates at some other value from the point where the sustain stage is to begin, causing a disjoint (you should see that behavior here).

DecProbPost.maxpat
Max Patch

So now i have to come up with a method of normalizing each stage. Thanks for looking into it. Hopefully this patch shows correctly.

Graham Wakefield's icon

Graham Wakefield

5月 31 2024 | 2:58 午後

A strategy I have found useful is to model every stage as always a rise from 0 to 1, then apply a shaping function to this 0..1 ramp, and then finally scale to the desired start & end values using a [scale] operator.

A 0..1 ramp can be modeled using an accum -> clip 0 1. The input to the accum is the rise per sample. Given a stage duration in milliseconds, you would do dur -> mstosamps -> / samplerate to get this value. The 2nd inlet to the accum is how you (re)trigger the ramp.

You can get a gate when the ramp is done using >= 1. That can be used to start the next stage.

The shaping function can be any unit shaper.

The shaped ramp then goes into a scale operator, where the 4th and 5th inlets determine the 'from' and 'to' values of the ramp.

If you want the next stage to continue from where the last stage ended, use a history from the output of scale back to a latch that is triggered by the end-of-stage, and use that as the 'from' value to scale the ramp.

(The core of this, the accum, clip 0 1, scale, and history/latch, is how we create something like a line~ object for gen~. It's also in the GO book at the end of the filter chapter.)

Roman Thilenius's icon

Roman Thilenius

5月 31 2024 | 3:02 午後

A strategy I have found useful is to model every stage as always a rise from 0 to 1

this.

J Mangel's icon

J Mangel

6月 01 2024 | 5:00 午前

right on. Thank yall. Ill be working thru the suggestions.

"You can get a gate when the ramp is done using >= 1. That can be used to start the next stage."

wow. i messed with a solution to that for days and ended up with something way more complicated.