# What's going on with curve in AdEnv

Hello! I’ve created a number of percussion sounds using AdEnv with noise, oscillators etc. I’m trying to use the Curve setting, and it’s not clear what’s going on with different values.

I know it says in the doc that only linear is implemented, but on decay, it definitely sounds like varying from exponential at -100 to linear at 0. Above 0, it’s less clear, and up around 90 or so it just gets very loud for no apparent reason.

However, on the attack segment, it’s very confusing. It does not sound exponential at all, and changing values actually seems to change the envelope time. it’s basically unpredictable and unusable.

Can anyone tell me what’s actually implemented in the AdEnv code, and is it possible to fix what’s going on? Also, I haven’t experimented much with ADSR, so I’m not sure if it behaves similarly.

I guess I can answer my own question, in part, by looking at the code. The key section is here:

``````    {
curve_x_ += (curve_scalar_ / time_samps);
val = beg + inc * (1.0f - EXPF(curve_x_));
if(val != val)
val = 0.0f; // NaN check
}
``````

Where `EXPF` is a function that basically computes x^10:

``````inline float expf_fast(float x)
{
x = 1.0f + x / 1024.0f;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
return x;
}
``````

…but I don’t really know why it does that, or why it behaves as strangely as it does. I watched a video on envelopes (found the link in an earlier discussion here) and while I can follow the math and the code in general, I’m not quite sure what’s going on in this case. Anyone have a clearer explanation, or a suggestion to improve AdEnv?

Well, I just went ahead and implemented my own, using repeated multiplication as a “fast exp” function. For whatever reason, this behaves more or less like I expect, where AdEnv doesn’t. Mine just assumes a range of 0-1, where AdEnv allows different ranges. Here’s the process function:

``````float AhdEnv2::Process() {

while (stage < STAGE_COUNT && counter >= stageTimes[stage]) {
stage++;
counter = 0;
}

switch (stage) {
case STAGE_ATTACK:
signal = (float)counter / (float)stageTimes[0];
break;
case STAGE_HOLD:
signal = 1;
break;
case STAGE_DECAY:
signal = 1 - (float)counter / (float)stageTimes[2];
break;
default:
signal = 0;
}

counter++;

if (curve > 0) {
for (u8 i = 0; i < curve; i++) {
signal *= signal;
}
}

return signal;
}
``````