Math help for ADSR curved Decay and Relase segments

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Hi guys,
my math knowledge is really modest, i'm trying to solve a thing a about an ADSR with variable curved segments.

The following link is what i did with Desmos an online graph calculator.

https://www.desmos.com/calculator/2p237rbfrn

Everything works for the Attack segment because the y range is 0..1.
But when the range is 1..S for the Decay segment and S..0 for the Release segment i can't get a formula to let pass a curve with an arbitrary exponent value (as in my Attack formula) on two given points on x,y plane.

I guess i could try to calculate the curve in the 0..1 range and then do some kind of translation and stretch/compression to fit the curve on the given points.

Any help, book, tutorial, hints?
I can't find anything really useful for this on the net.

Many thanks!
a.

Post

Everything works for the Attack segment because the y range is 0..1.
So you have:
x = f(y, exp)
which works
But when the range is 1..S for the Decay segment and S..0 for the Release segment i can't get a formula to let pass a curve with an arbitrary exponent value (as in my Attack formula) on two given points on x,y plane.
Why not simply extending the math from a above with a range and offset?
Like:
x = (f(y, exp) * (range - offset)) + offset
On decay range=S and offset=1 (you might need to adapt the sign, depending if you look at range being negative, because decay decreases, or if you want to work positive range values)
On release range=S and offset=0

Post

Hi lalo

Maybe it isn't what you want in curved lines, but have you looked at hermite interpolation?

You could search "hermite" on this page-- http://www.musicdsp.org/archive.php?classid=5#93

That kind of hermite basically tries to automatically draw smooth curves which always pass thru the control points. So the exact curve chosen would be determined by the equation, calculating whatever is necessary to smoothly connect the control points.

However if you want "user adjustable" curves of different shapes, on the same set of control points-- Maybe splines? Drawing of curves in such as adobe illustrator, twiddling the curve by dragging control points, are typically splines.

Post

Many thanks guys!
Thanks to PurpleSunray suggestions i came up with this.
I think is a good starting point for my Reaktor Core envelope project, and eventually i can do Max external or a full VST incorporating these elements i'm workin' on.

https://www.desmos.com/calculator/9ikgovu8zt

Thanks JCJR for your suggestions, i'll look into it when i'll need more complex control curves.

best!
a.

Post


Post

Thanks again!
And how to do the same thing with a true exponential curve like

y = a^x

?

:?:

Post

The simple format for this is like so:

lerp(start, end, f(x))

Where f(x) is your "curve".
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

thanks aciddose.
is "lerp" linear interpolation?
how to do computationally a lerp of a curve?
thanks
a.

Post

I just told you that.

lerp(x,y,z) = x + (y - x) * z
psh(min, max, z) = min * exp(log(max / min) * z)

lerp(0, 1, x) = straight line
lerp(0, 1, 1 - psh(0.01, 1, 1 - x) = log attack with 101% asymptote
lerp(0, 1, 2 - psh(0.5, 1, 1 - x) * 2) = log attack with 200% asymptote
lerp(1, 0.5, 1 - ps(0.01, 1, 1 - x)) = decay to 50.5% (to 1/100th)

Although this requires only a few muls and a call to exp() or approximation it is incredibly expensive compared to computing a lossy-integrator. The flexibility of parametrization of the curve is not free.

There are also a lot of complexities introduced as you attempt to model the functionality of a typical lossy-integrator based envelope (tracks sustain parameter at decay rate) and the slight benefit of exact timing is countered by the fact you must introduce direct discontinuities into the resulting waveform.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Hi aciddose,
my math is still not at an advanced level and my electronic knowledge has still not touched a lossy integrator.
What's "psh"? and what's "ps"?
many thanks!

Post

ps is a typo, it's psh. And psh is defined in the post.

Post

Here is another wrapper that simplifies usage of psh() for envelopes (it has other uses.)

esh(a, x) = 1 - (psh(a, 1, 1 - x) - a) * (1 / (1 - a))

This allows you to use:

lerp(start, end, esh(1 - 1/asymptote, x))
or:
lerp(start, end, esh(threshold, x))

For example in a decay you'd likely want to set the threshold based upon some value in decibels. For example -40 dB = 0.01

Your timing is a simple linear 0 -> 1, d = 1 / T

The "decay time" however which is printed should likely be computed based upon some section of the curve. Generally 90% to 10% is used although -20 dB (1/10) and others are also common.

The "linear" length of that section of the envelope will then be different from the timing value you print.

You should find that if you use low "threshold" values the timing will seem much too long with a very sharp logarithmic attack/decay. If you use high values the discontinuity will become too large at the end of the segment. The only solution available is to apply different values for each. Select the discontinuity you are comfortable with, then adjust the timing value displayed using one of the common systems.

"psh" is just a quick function name, you can rename the function whatever you like as I'm not aware of any similar "standard" function. The name is an abbreviation of "power shape".
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Here's another approach if want super fast performance:

Code: Select all

y=x^n
dy = x^(n-1) dx = n y dx / x
So you can compute the next point based on the previous point and the derivative. However you need a division, but you can apply the same principle:

Code: Select all

z=1/x
dz = -1/(x^2) dx = -z*z dx.
and compute the next point based on the previous one without the division.

If I remember correctly, I had stability problems with x=0 so I had to offset everything by a small constant, and offset it back.

Post

At which point you're just computing a lossy-integrator. You can't input a random variable for x as in psh(..., x).

This is problematic if you want bi-directional loops or random jumping capability.

Using an approximation for exp (via float exponent) is actually very fast, significantly faster than integrating from the start point to some mid-point selected during a random jump.

It is possible to pre-compute fixed points (points known where jumps will occur) and use these to correct the cumulative error from integration. This is the method my envelopes in Xhip use. Integration is used to within 0.01 (1e-2 or -40 dB) immediately followed by a correction. The exception is during decay/release where the sustain stage is not entered (sustain = 0) the threshold is then 1e-4 or -80 dB.

Since we're dealing with integration a second-order impulse can be used to anti-alias the edges of the envelope (ala "minblamp") and any sharp edges can be anti-aliased with the first-order impulse ("minblep"). This can allow state change to occur between samples which can slightly increase the accuracy of a very short envelope segment (<100 us) although I don't bother with this.

In a parameterized envelope it may make sense especially where it may be used at audio rate as a generic modulator (replacing LFOs and envelopes.)
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post


Post Reply

Return to “DSP and Plugin Development”