[sdiy] Integer exponential envelope generation

Richie Burnett rburnett at richieburnett.co.uk
Tue Nov 22 22:11:34 CET 2011


This topic seems to come up quite frequently.  The two equations Scott 
posted are equivalent provided your processor can handle signed arithmetic:

y = a0 * input + b1 * y        (where b1 = 1.0 - a0)
y = y + b1 * (input - y)        (where b1 is the "time constant")

On a DSP which is geared up to multiplying and accumulating I implement the 
calculation like this:

y = y + (b1 * input) - (b1 * output)

In programming terms it reduces to two operations:  Multiply the current 
output value by b1 and subtract from the running total, then multiply the 
current input value by b1 and add to the running total.

...of course we still need to work out what the magic b1 value needs to be 
in order to achieve a specific attack or decay time constant.  To be 
precise:

b1 = 1 - exp (-Ts / Tc)

where Tc is the required time-constant in seconds, and Ts is your sampling 
time also in seconds.  If your required minimum Tc is always much greater 
than the sampling time Ts, you can use the approximation:

b1 = Ts / Tc

This is pretty accurate if your sampling frequency is something like 48kHz 
and the minimum attack and decay times are 1ms or more.  It also gets around 
having to perform an exp() function or a table lookup to calculate the 
required b1 coefficient.  However if you calculate new updated envelope 
values at a lower control rate like 2kHz, this formula will become 
increasingly innacurate for short time constants that approach the sampling 
time.

The only thing to watch out for with this 1-pole IIR envelope generator is 
making sure you store the current running total "y" to sufficient bits of 
resolution!  Take the case where the required envelope time-constant is 1000 
times the sampling time.  In this case the constant b1 is going to be 
something around 1/1000.  You need to make sure that when the current output 
value is multiplied by b1 it doesn't get rounded down to zero.  If this 
product were to get rounded down to zero then the decaying envelope will get 
stuck at a low level without falling away smoothly to zero.

As a rough rule of thumb you need to keep track of the current "y" value to 
the number of bits of precision you want in the answer plus an extra bit for 
every factor of 2 that the envelope time-constant is greater than the 
sampling time.  So if your sampling time is 1ms, and you want a maximum time 
constant of 1 second, thats a factor of 1000.  Or roughly 2 to the power of 
10.  Therefore if you want your envelope to be accurate to 8 bits, you need 
to keep track of "y" to at least 18 bits of precision.

Hopefully this summary of digital envelopes will help.  Although you put 
"Integer" in the title it really helps to think of this more like fixed 
point arithmetic rather than Integer, because the coefficient b1 must always 
be fractional.  All you are really doing with integer arithmetic is shifting 
all of the fractional numbers left by a fixed number of bits and thinking of 
them as integers.  "Fractional" or "Integer"?  It's all just a matter of 
where you imagine that the binary point is placed.

-Richie, 




More information about the Synth-diy mailing list