From: Paul K. <pau...@ma...> - 2002-11-15 14:15:44
|
Steve Harris <S.W...@ec...> wrote: > > Benno and I were discussing envelope generation last night, I think that > the right way to generate an exponential envelope (I checked some synths > outputs too and it looks like this is that way its done) is to feed a > constant value into a LP filter with different parameters for each stage. Yes, so the envelope level tends exponentially to a target level. Where this gets complicated is the attack, which should have a target level maybe 1.5 times it's end level, otherwise you spend a long time at nearly full volume waiting for the decay to start. DLS specifies the attack should be linear not exponental, and I tend to agree with that - for short attacks it doesn't sound any different, but for long attacks an exponential curve gets too loud too soon. Some softsynths now have much more complicated envelopes, with a time, target level and curve (variable between exp/lin/log) for each stage, but it's important to let the user set up a simple ADSR if that is all that's needed. > I suspect that, in general you need to calculate the amplitude of the > envelope for each sample, to avoid stairstepping (zipper noise). Yes, or use short linear segments, and update the envelope every 32 samples for example (64 samples is too long, and people will complain about the resolution). > Example code: > > env = env_input * ai + env * a; May be faster with one multiplication: env += ai * (env_input - env); If you allow real-time control of envelope times/rates, counting down the time to the next stage can get complicated, so it might be better to trigger the next stage when you reach a certain level. Here is some nasty code that does it that way, so env_rate could be modulated in real-time (but to be able to modulate the sustain_level, you would have to make env_target a pointer). //initialize: env = 0.0f; env_rate = ATTACK_RATE; env_thresh = 1.0f; env_target = 1.5f; //else we will never reach threshold //per sample: env += env_rate * (env_target - env); if(env > env_thresh) //end of attack { env_rate = DECAY_RATE; env_thresh = env; //move threshold out of the way env_target = SUSTAIN_LEVEL; //could set a flag so this block is skipped in future } //note off: env_rate = RELEASE_RATE; env_target = 0.0f; //kill the voice before this de-normals! Paul. _____________________________ m a x i m | digital audio http://mda-vst.com _____________________________ |