From: Steve H. <S.W...@ec...> - 2002-11-14 12:28:09
|
Hi all, 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. I suspect that, in general you need to calculate the amplitude of the envelope for each sample, to avoid stairstepping (zipper noise). I expect Paul Kellett knows the right approach, so should be able to say if we're barking up the wrong tree. Example code: #include <math.h> #include <stdio.h> #define EVENTS 5 #define ENV_NONE 0 #define ENV_ATTACK 1 #define ENV_DECAY 2 #define ENV_SUSTAIN 3 #define ENV_RELEASE 4 void lp_set_par(double time, double *a, double *ai) { *a = exp(-5.0 / time); // The 5.0 is a fudge factor *ai = 1.0 - *a; } int main() { unsigned int event_time[EVENTS] = {0, 100, 200, 400, 900}; unsigned int event_action[EVENTS]= {ENV_ATTACK, ENV_DECAY, ENV_SUSTAIN, ENV_RELEASE, ENV_NONE}; unsigned int i, event = 0; float env_input = 0.0f; double env = 0.0f; double a, ai; float attack_level = 1.0f; float sustain_level = 0.5f; float release_level = 0.0f; for (i=0; i<1000; i++) { if (i == event_time[event]) { switch (event_action[event]) { case ENV_ATTACK: env_input = attack_level; break; case ENV_DECAY: env_input = sustain_level; break; case ENV_SUSTAIN: env_input = sustain_level; break; case ENV_RELEASE: env_input = release_level; break; } lp_set_par((double)(event_time[event+1] - event_time[event]), &a, &ai); event++; } env = env_input * ai + env * a; printf("%g\n", env); } return 0; } |