[Fpga-synth] Envelope - linear attack & expo decay/release?

Magnus Danielson magnus at rubidium.dyndns.org
Sun Apr 5 00:39:22 CEST 2009


Scott Gravenhorst skrev:
> "The making of synthesizers in FPGAs." wrote:
>> Scott Gravenhorst skrev:
>>> Eric B. wrote:
>>>> Here's a philosophical question:
>>>>
>>>> Last weekend I built an ADSR for my ARM/FPGA synth and it seems to work 
>>>> fine. The thing that's bugging me is that I used linear calculations for 
>>>> the gain, so when doing a long release that last little tail seems to 
>>>> cut off rather abruptly.
>>>>
>>>> The obvious solution is to use exponential decay for the release. I know 
>>>> how I'd implement that in hardware (scale the difference between where 
>>>> you are and where you're going by some constant related to the rate & 
>>>> add to current state). Question is, is the exponential curve also 
>>>> appropriate for the attack & decay phases?
>>>>
>>>> The ultimate envelope would seem to be one with the option for 
>>>> log/lin/expo curve on each segment, along with variable rate & target. 
>>>> You'd need three parameters to define every segment. Probably too 
>>>> complex, but certainly flexible.
>>>>
>>>> Thoughts? What have you tried in the past?
>>>>
>>>> Eric
>>> I went back to my GateMan synths and they are linear only ADSRs.  They have the same
>>> "problem" that Eric describes.
>>>
>>> My question is: What envelope shapes are most useful?
>>>
>>> How much does it matter that A and D are expo?
>>>
>>> Would the most useful modification to an ADSR be simply selectable lin/expo for R?
>> For quick A, D and R it is not so important, but if you reach for longer 
>>  stretches, the end-result needs to be more expo at least.
> 
> Agreed, because linear is a fairly close approximation of fast expo transitions anyway.
> 
>> Rolling back to the 80thies, the highly digital SID-chip was fairly easy 
>> to design except for the ADSR for this particular reason. It took some 
>> engineering time to get the envelopes right.
>>
>> An exponential decay is not too hard to cook up correctly if one pulls 
>> in a multiplier block or performs multiplications using a shift-add 
>> approach, which can easilly be used for the full calculations with some 
>> additional thought put into it. If you think about it, it should not be 
>> too hard to achieve lin/exp as needed.
>>
>> I think I would need to spend some quality time with paper and pen to 
>> bring it all together, but I am confident that it will not be all that 
>> complex in the end.
> 
> Ah, paper and pen...  I'm more of a dabbler, y'know, fartin' around and hear what happens sorta
> guy.  I know I should probably learn to use paper and pen more, but I have to figure out which end
> of the pen is the business end.  (you're supposed to laugh)...  

Hahaha... (in an obvious theatrical manor)

For me it is a way to concentrate on key aspects, dabble around on the 
paper, and then when I have a good solution I move to implementation.
I also work with witeboards at work. If I had one at home I would work 
with it here too. But I need a large one... don't get far on a square 
centimeter one... or whatever babysizes comes in... I need square 
meters... several. I also likes colours... on the whiteboard I have only 
4 colours on the pens... usually only 3 when I work on papers...

> I figured that I could use a modified single pole IIR lowpass.  Pre-initialize the Z^-1 memory with
> the sustain value (or wherever it was when the key was released) and present a constant zero as
> input (which eliminates the a0 term).  That might be the same thing Eric said...  Regardless, only
> one multiplier is needed.

This is indeed all it takes more or less...

As I see it, the core should be an exponential...

First, the input potential I depends on the phase

I <= MAX when state = A else
      SUSTAIN when state = DS else
      0 when state = R;

Default state would be release of course, gate goes high and the shift 
to attack state and when as the integrator goes beyond the peak we shift 
to the Decay/Sustain state and stay there until the Gate goes low (key 
depressed).

Now, the pull potential should be the difference between the input and 
the output for exponential or just the input for linear resonse. Those,

P <= I - O when resp = exp else
      I when resp = lin;

The resp signal can be muxed for the Attack, Decay and Release phase 
such that they can be individually controlled. The timeconstants needs 
to be muxed similarly:

T <= ATTACK when state = A else
      DECAY when state = DS else
      RELEASE when state = R;

The integrator is a straight flip-flop with feedback for the scaled pull 
, like this

O <= O + P * T;

We need to monitor the output for peak-detection, which takes a 
comparation, effectively done though a subtract and look at the output 
carry.

PD <= O - PEAK;

If the MSB of PD is 1, the output value is below the peak, if it is 0 it 
is at or above the peak. The peak-value needs to be slightly less than 
the maximum value of the integer... since it needs to handle the maximum 
step-size from one sample to another such that the attack goes beyond 
the peak value but remains below the max value for the attack time, 
which for a simple approximation needs to handle the quickest time. If 
one has peak at max value to the same value the exponential case would 
never end. If the peak value is at the top of the integer range, then it 
will wrap as it is range-limited.

With that done, all there is to actually design the state-machine, but 
it should be a trivial exercise.

Using a straight 18x18 multiplier block should be straightforward.

Anyway, that is what I would try out...

> So I'll probably see what happens if I just modify the ADSR to allow selectable linear or expo
> release and leave A and D linear for now.  It's a matter of whether there's a significant
> difference or not and with long release times I think it is.  Long decay times are usually coupled
> with long release and really amount to more of an AR than an ADSR envelope (for something like a
> bell).  In this case though the decay phase can still be linear I think.

You'd still want some decay there...

Cheers,
Magnus


More information about the Fpga-synth mailing list