|
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;
}
|