[sdiy] Dealing with velocity sensitivity / scaling on envelopes
rsdio at audiobanshee.com
rsdio at audiobanshee.com
Thu Aug 31 22:40:00 CEST 2017
I think it helps to consider what's happening in the analog module.
First of all, I think that your existing implementation is overly complex. You talk about scale and offset when none of that is happening in the circuit. Perhaps it's just the terminology you're using, and the code is not as complicated as you make it sound.
I would expect the code to have one state variable representing the Voltage in a capacitor, with various resistance values simulated in the math for charging and discharging. I guess you could refer to the Voltage as offset and the charge/discharge resistances as scaling factors for the accumulator code.
An analog ADSR module has a single capacitor, with three difference variable resistances to control the rate of charge and discharge. The reason that Release always starts from the current value is because the single capacitor always has a particular Voltage at any given moment in time, and switching the resistances merely changes the rate of charging or discharging. Full level, Sustain level, and Zero/Off level are the only Voltages ever connected. Attack, Decay, and Release are different resistances that affect the RC time constant (rate of charge or discharge). Gate On controls the transition from Release to Attack, and Gate Off controls the transition from Sustain to Release. The only catch is that the transition from Attack to Decay is not controlled by the Gate, but controlled by reaching "Full" level, but since an RC circuit approaches the final Voltage on an asymptotic curve, i.e., it never really reaches Full. For this reason, the typical ADSR has a threshold level below Full that automatically triggers the transition from Attack to Decay.
I've not studied analog synths with velocity, but it would seem very difficult to scale the ADSR itself based on Velocity. Instead, I expect that the CV output of the ADSR would be scaled by the Velocity. A simple multiplier - maybe a VCA on the ADSR CV output - would be a separate module internally. That way, the ADSR works exactly the same whether it's Velocity enabled or not. The whole Envelope would be scaled in a single operation by the Velocity level.
Of course, there are many other possibilities such as Velocity control of Attack, or Velocity control of Release. Those would affect the ADSR internally, and could not be achieved by simple scaling of a non-Velocity ADSR output. In these cases, I would still model a single capacitor with a single Voltage at any one time. Any variation of Attack or Release time constants would still work from the current value in the virtual capacitor.
Brian
On Aug 31, 2017, at 11:16 AM, Tom Wiltshire <tom at electricdruid.net> wrote:
> I’m writing some code for a velocity-sensitive envelope generator. This throws up a few issues I haven’t had to deal with before.
>
> Usually, I’d store what level the envelope is outputting when the Gate goes high or low. This information can then be used to scale and offset the Attack stage so that it starts from the last output value rather than dropping abruptly to zero in order to start a new attack. This is how the CEM/SSM analog envelope generator chips worked, so I copied the existing behaviour. Same with the Release stage. Perhaps the Gate goes low during a long Decay, or even during a long Attack - we want the Release stage to be scaled so it drops to zero from there, not to always start at the Sustain level. It’s a simple question of making sure that the output is a nice continuous line with no abrupt jumps in it (unless you set up a 1msec attack!).
>
> However…this doesn’t work so nicely when you start including velocity scaling. Imagine the following scenario:
>
> I play a loud note with Sustain at maximum and a very long Release. Then I let go of the note (Gate goes low, long release starts) and play another very softly. The last output level is very close to maximum amplitude, since the Release time is long and it hasn’t dropped much yet. But the new note is very quiet and even the maximum Attack level could well be far less than the current output.
>
> So what should I do? Attacking downwards seems completely wrong. Jumping abruptly to zero and then attacking up to a much quieter note completely chops off the long release of the previous note. Are there other options?
>
> Has anyone else come up against this? What did you decide? How do modern monosynths that include velocity sensitivity deal with it? What does Moog do, for example?
>
More information about the Synth-diy
mailing list