gen~ attack decay logarithmic envelope

Uasmi Nasser's icon

Hey fellas,

I have a hard time finding any examples with envelopes in gen~ (besides famous Peter McCulloch adsr), so what would be your take on making Attack/Decay logarithmic curve envelope? Or maybe ASR?

So, essentially, I want an envelope triggered by incoming click~, which goes from 1 to 0 as a logarithmic curve (slowly moves toward 0 first, then rapidly decreases)

I tried building it by using two click~ objects with a delay into the counter object and then feeding it to the slide object, but maybe there's a more elegant solution.

Roman Thilenius's icon

log exists for gen~, not sure about exp, but in case not, you can roll your own using pow.

your click~, if that is really a precondition, can be converted to phase accumulators / line segments to run them through such functions.

the rest is scaling and cutting/gate.

yes, the signal scaling can become difficult and is cpu intensive.

lysdexic's icon

Take a look at Help > Examples > Gen > gen~.slide

:)

Ess M's icon

Something like this, in a codebox:

ar(trig, attack, release) {
    History env(0), stage(0),
        atk_rate(0), atk_coeff(0), atk_offset(0),
        rel_rate(0), rel_coeff(0), rel_offset(0);
        
    if (trig) {
        // rate in seconds
        atk_rate = samplerate * attack;
        rel_rate = samplerate * release;
        
        // slope 0 = linear, slope -n = log/exp
        atk_slope = exp(-1.5);
        rel_slope = exp(-8);
        
        // calculate coefficients
        atk_coeff = exp(-log((1 + atk_slope) / atk_slope) / atk_rate);
        atk_offset = (1 + atk_slope) * (1 - atk_coeff);
        
        rel_coeff = exp(-log((1 + rel_slope) / rel_slope) / rel_rate);
        rel_offset = -rel_slope * (1 - rel_coeff);
        
        // reset & trigger envelope
        env = 0;
        stage = 1;
    }

    // stage 0 = idle, 1 = attack, 2 = decay
    if (stage == 0) {
        env = 0;
    } else if (stage == 1) {
        env = atk_offset + env * atk_coeff;
        
        if (env >= 1 || attack <= 0) {
            env = 1;
            stage = 2;
        }
    } else if (stage == 2) {
        env = rel_offset + env * rel_coeff;
        
        if (env <= 0 || release <= 0) {
            env = 0;
            stage = 0;
        }
    } 
    return env;
}