ref: 32b90cfcbaa02028922bc30afb0ad99db5a0cdfe
parent: 1bea5d76d5b4ad8ec19112d07008fc5f0e46509c
author: spiricom <jeff@snyderphonics.com>
date: Wed May 20 17:14:37 EDT 2020
updated ADSR
binary files a/.DS_Store b/.DS_Store differ
binary files a/LEAF/.DS_Store b/LEAF/.DS_Store differ
--- a/LEAF/Inc/leaf-envelopes.h
+++ b/LEAF/Inc/leaf-envelopes.h
@@ -105,47 +105,144 @@
};
/* ADSR */
- typedef struct _tADSR
- {
- float sampleRateInMs;
- int state;
- float output;
- float attackRate;
- float decayRate;
- float releaseRate;
- float attackCoef;
- float decayCoef;
- float releaseCoef;
- float sustainLevel;
- float targetRatioA;
- float targetRatioDR;
- float attackBase;
- float decayBase;
- float releaseBase;
- float leakFactor;
- float gain;
+ typedef struct _tADSR
+ {
+ const float *exp_buff;
+ const float *inc_buff;
+ uint32_t buff_size;
- } _tADSR;
+ float next;
+
+ float attackInc, decayInc, releaseInc, rampInc;
+
+ oBool inAttack, inDecay, inSustain, inRelease, inRamp;
+
+ float sustain, gain, rampPeak, releasePeak;
+
+ float attackPhase, decayPhase, releasePhase, rampPhase;
+
+ float leakFactor;
+
+
+ } _tADSR;
+
+ typedef _tADSR* tADSR;
+
+ void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
+ void tADSR_free (tADSR* const);
+ void tADSR_initToPool (tADSR* const, float attack, float decay, float sustain, float release, tMempool* const);
+ void tADSR_freeFromPool (tADSR* const, tMempool* const);
+
+ float tADSR_tick (tADSR* const);
+ void tADSR_setAttack (tADSR* const, float attack);
+ void tADSR_setDecay (tADSR* const, float decay);
+ void tADSR_setSustain (tADSR* const, float sustain);
+ void tADSR_setRelease (tADSR* const, float release);
+ void tADSR_setLeakFactor (tADSR* const, float leakFactor);
+ void tADSR_on (tADSR* const, float velocity);
+ void tADSR_off (tADSR* const);
+
+
- typedef _tADSR* tADSR;
- void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
- void tADSR_free (tADSR* const);
- void tADSR_initToPool (tADSR* const, float attack, float decay, float sustain, float release, tMempool* const);
- void tADSR_freeFromPool (tADSR* const, tMempool* const);
-
- float tADSR_tick (tADSR* const);
- void tADSR_setAttack (tADSR* const, float attack);
- void tADSR_setDecay (tADSR* const, float decay);
- void tADSR_setSustain (tADSR* const, float sustain);
- void tADSR_setRelease (tADSR* const, float release);
- void tADSR_setLeakFactor (tADSR* const, float leakFactor);
- void tADSR_on (tADSR* const, float velocity);
- void tADSR_off (tADSR* const);
-
-
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+
+ /* ADSR2 */
+ typedef struct _tADSR2
+ {
+ float sampleRateInMs;
+ float attack;
+ float decay;
+ float release;
+ float attackLambda;
+ float decayLambda;
+ float releaseLambda;
+ float sustain;
+ float leakGain;
+ float leakFactor;
+ float targetGainSquared;
+ float factor;
+ float oneMinusFactor;
+ float gain;
+ uint8_t attacking;
+ uint8_t gate;
+ float env;
+ float envTarget;
+ } _tADSR2;
+
+ typedef _tADSR2* tADSR2;
+
+ void tADSR2_init (tADSR2* const, float attack, float decay, float sustain, float release);
+ void tADSR2_free (tADSR2* const);
+ void tADSR2_initToPool (tADSR2* const, float attack, float decay, float sustain, float release, tMempool* const);
+ void tADSR2_freeFromPool (tADSR2* const, tMempool* const);
+
+ float tADSR2_tick (tADSR2* const);
+ void tADSR2_setAttack (tADSR2* const, float attack);
+ void tADSR2_setDecay (tADSR2* const, float decay);
+ void tADSR2_setSustain (tADSR2* const, float sustain);
+ void tADSR2_setRelease (tADSR2* const, float release);
+ void tADSR2_setLeakFactor (tADSR2* const, float leakFactor);
+ void tADSR2_on (tADSR2* const, float velocity);
+ void tADSR2_off (tADSR2* const);
+
+
+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+ enum envState {
+ env_idle = 0,
+ env_attack,
+ env_decay,
+ env_sustain,
+ env_release
+ };
+
+ /* ADSR3 */
+ typedef struct _tADSR3
+ {
+ float sampleRateInMs;
+ int state;
+ float output;
+ float attackRate;
+ float decayRate;
+ float releaseRate;
+ float attackCoef;
+ float decayCoef;
+ float releaseCoef;
+ float sustainLevel;
+ float targetRatioA;
+ float targetRatioDR;
+ float attackBase;
+ float decayBase;
+ float releaseBase;
+ float leakFactor;
+ float targetGainSquared;
+ float factor;
+ float oneMinusFactor;
+ float gain;
+
+ } _tADSR3;
+
+ typedef _tADSR3* tADSR3;
+
+ void tADSR3_init (tADSR3* const, float attack, float decay, float sustain, float release);
+ void tADSR3_free (tADSR3* const);
+ void tADSR3_initToPool (tADSR3* const, float attack, float decay, float sustain, float release, tMempool* const);
+ void tADSR3_freeFromPool (tADSR3* const, tMempool* const);
+
+ float tADSR3_tick (tADSR3* const);
+ void tADSR3_setAttack (tADSR3* const, float attack);
+ void tADSR3_setDecay (tADSR3* const, float decay);
+ void tADSR3_setSustain (tADSR3* const, float sustain);
+ void tADSR3_setRelease (tADSR3* const, float release);
+ void tADSR3_setLeakFactor (tADSR3* const, float leakFactor);
+ void tADSR3_on (tADSR3* const, float velocity);
+ void tADSR3_off (tADSR3* const);
+
+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
/* Ramp */
--- a/LEAF/Src/leaf-envelopes.c
+++ b/LEAF/Src/leaf-envelopes.c
@@ -254,46 +254,480 @@
}
+
/* ADSR */
-//replaced our older ADSR that relied on a large lookup table with this one by Nigel Redmon from his blog. Thanks, Nigel!
+void tADSR_init(tADSR* const adsrenv, float attack, float decay, float sustain, float release)
+{
+ tADSR_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
+}
+
+void tADSR_free(tADSR* const adsrenv)
+{
+ tADSR_freeFromPool(adsrenv, &leaf.mempool);
+}
+
+void tADSR_initToPool (tADSR* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tADSR* adsr = *adsrenv = (_tADSR*) mpool_alloc(sizeof(_tADSR), m);
+
+ adsr->exp_buff = __leaf_table_exp_decay;
+ adsr->inc_buff = __leaf_table_attack_decay_inc;
+ adsr->buff_size = sizeof(__leaf_table_exp_decay);
+
+ if (attack > 8192.0f)
+ attack = 8192.0f;
+ if (attack < 0.0f)
+ attack = 0.0f;
+
+ if (decay > 8192.0f)
+ decay = 8192.0f;
+ if (decay < 0.0f)
+ decay = 0.0f;
+
+ if (sustain > 1.0f)
+ sustain = 1.0f;
+ if (sustain < 0.0f)
+ sustain = 0.0f;
+
+ if (release > 8192.0f)
+ release = 8192.0f;
+ if (release < 0.0f)
+ release = 0.0f;
+
+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
+ int16_t releaseIndex = ((int16_t)(release * 8.0f))-1;
+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
+
+ if (attackIndex < 0)
+ attackIndex = 0;
+ if (decayIndex < 0)
+ decayIndex = 0;
+ if (releaseIndex < 0)
+ releaseIndex = 0;
+ if (rampIndex < 0)
+ rampIndex = 0;
+
+ adsr->next = 0.0f;
+
+ adsr->inRamp = OFALSE;
+ adsr->inAttack = OFALSE;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OFALSE;
+
+ adsr->sustain = sustain;
+
+ adsr->attackInc = adsr->inc_buff[attackIndex];
+ adsr->decayInc = adsr->inc_buff[decayIndex];
+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
+ adsr->rampInc = adsr->inc_buff[rampIndex];
+
+ adsr->leakFactor = 1.0f;
+}
+
+void tADSR_freeFromPool (tADSR* const adsrenv, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tADSR* adsr = *adsrenv;
+ mpool_free(adsr, m);
+}
+
+void tADSR_setAttack(tADSR* const adsrenv, float attack)
+{
+ _tADSR* adsr = *adsrenv;
+
+ int32_t attackIndex;
+
+ if (attack < 0.0f) {
+ attackIndex = 0.0f;
+ } else if (attack < 8192.0f) {
+ attackIndex = ((int32_t)(attack * 8.0f))-1;
+ } else {
+ attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
+ }
+
+ adsr->attackInc = adsr->inc_buff[attackIndex];
+}
+
+void tADSR_setDecay(tADSR* const adsrenv, float decay)
+{
+ _tADSR* adsr = *adsrenv;
+
+ int32_t decayIndex;
+
+ if (decay < 0.0f) {
+ decayIndex = 0.0f;
+ } else if (decay < 8192.0f) {
+ decayIndex = ((int32_t)(decay * 8.0f)) - 1;
+ } else {
+ decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
+ }
+
+ adsr->decayInc = adsr->inc_buff[decayIndex];
+}
+
+void tADSR_setSustain(tADSR* const adsrenv, float sustain)
+{
+ _tADSR* adsr = *adsrenv;
+
+ if (sustain > 1.0f) adsr->sustain = 1.0f;
+ else if (sustain < 0.0f) adsr->sustain = 0.0f;
+ else adsr->sustain = sustain;
+}
+
+void tADSR_setRelease(tADSR* const adsrenv, float release)
+{
+ _tADSR* adsr = *adsrenv;
+
+ int32_t releaseIndex;
+
+ if (release < 0.0f) {
+ releaseIndex = 0.0f;
+ } else if (release < 8192.0f) {
+ releaseIndex = ((int32_t)(release * 8.0f)) - 1;
+ } else {
+ releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
+ }
+
+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
+}
+
+// 0.999999 is slow leak, 0.9 is fast leak
+void tADSR_setLeakFactor(tADSR* const adsrenv, float leakFactor)
+{
+ _tADSR* adsr = *adsrenv;
+
+
+ adsr->leakFactor = leakFactor;
+}
+
+void tADSR_on(tADSR* const adsrenv, float velocity)
+{
+ _tADSR* adsr = *adsrenv;
+
+ if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
+ {
+ adsr->rampPhase = 0;
+ adsr->inRamp = OTRUE;
+ adsr->rampPeak = adsr->next;
+ }
+ else // Normal start.
+ {
+ adsr->inAttack = OTRUE;
+ }
+
+ adsr->attackPhase = 0;
+ adsr->decayPhase = 0;
+ adsr->releasePhase = 0;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OFALSE;
+ adsr->gain = velocity;
+}
+
+void tADSR_off(tADSR* const adsrenv)
+{
+ _tADSR* adsr = *adsrenv;
+
+ if (adsr->inRelease) return;
+
+ adsr->inAttack = OFALSE;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OTRUE;
+
+ adsr->releasePeak = adsr->next;
+}
+
+float tADSR_tick(tADSR* const adsrenv)
+{
+ _tADSR* adsr = *adsrenv;
+
+
+ if (adsr->inRamp)
+ {
+ if (adsr->rampPhase > UINT16_MAX)
+ {
+ adsr->inRamp = OFALSE;
+ adsr->inAttack = OTRUE;
+ adsr->next = 0.0f;
+ }
+ else
+ {
+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
+ }
+
+ adsr->rampPhase += adsr->rampInc;
+ }
+
+ if (adsr->inAttack)
+ {
+
+ // If attack done, time to turn around.
+ if (adsr->attackPhase > UINT16_MAX)
+ {
+ adsr->inDecay = OTRUE;
+ adsr->inAttack = OFALSE;
+ adsr->next = adsr->gain * 1.0f;
+ }
+ else
+ {
+ // do interpolation !
+ adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
+ }
+
+ // Increment ADSR attack.
+ adsr->attackPhase += adsr->attackInc;
+
+ }
+
+ if (adsr->inDecay)
+ {
+
+ // If decay done, sustain.
+ if (adsr->decayPhase >= UINT16_MAX)
+ {
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OTRUE;
+ adsr->next = adsr->gain * adsr->sustain;
+ }
+
+ else
+ {
+ adsr->next = adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1 - adsr->sustain))); // do interpolation !
+ }
+
+ // Increment ADSR decay.
+ adsr->decayPhase += adsr->decayInc;
+ }
+
+ if (adsr->inSustain)
+ {
+ adsr->next = adsr->next * adsr->leakFactor;
+ }
+
+ if (adsr->inRelease)
+ {
+ // If release done, finish.
+ if (adsr->releasePhase >= UINT16_MAX)
+ {
+ adsr->inRelease = OFALSE;
+ adsr->next = 0.0f;
+ }
+ else {
+
+ adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation !
+ }
+
+ // Increment envelope release;
+ adsr->releasePhase += adsr->releaseInc;
+ }
+
+
+ return adsr->next;
+}
+
+
+
+
+/* ADSR 2*/
+//This one is adapted from the VCV Rack code
//-JS
-float calcADSRCoef(double rate, double targetRatio)
+const float ADSR2_MIN_TIME = 1e-3f;
+const float ADSR2_INV_MIN_TIME = 1000.0f;
+const float ADSR2_MAX_TIME = 10.f;
+const float ADSR2_LAMBDA_BASE = 10000.0f;
+
+
+void tADSR2_init(tADSR2* const adsrenv, float attack, float decay, float sustain, float release)
{
+ tADSR2_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
+}
+
+void tADSR2_free(tADSR2* const adsrenv)
+{
+ tADSR2_freeFromPool(adsrenv, &leaf.mempool);
+}
+
+void tADSR2_initToPool (tADSR2* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tADSR2* adsr = *adsrenv = (_tADSR2*) mpool_alloc(sizeof(_tADSR2), m);
+ adsr->sampleRateInMs = leaf.sampleRate * 0.001f;
+ adsr->attack = LEAF_clip(0.0f, attack * 0.001f, 1.0f);
+ adsr->attackLambda = powf(ADSR2_LAMBDA_BASE, -adsr->attack) * ADSR2_INV_MIN_TIME;
+
+
+ adsr->decay = LEAF_clip(0.0f, decay * 0.001f, 1.0f);
+ adsr->decayLambda = powf(ADSR2_LAMBDA_BASE, -adsr->decay) * ADSR2_INV_MIN_TIME;
+
+
+ adsr->sustain= sustain;
+
+
+ adsr->release = LEAF_clip(0.0f, release * 0.001f, 1.0f);
+ adsr->releaseLambda = powf(ADSR2_LAMBDA_BASE, -adsr->release) * ADSR2_INV_MIN_TIME;
+
+ adsr->attacking = 0;
+ adsr->gate = 0;
+ adsr->gain = 1.0f;
+ adsr->targetGainSquared = 1.0f;
+ adsr->factor = 0.01f;
+ adsr->oneMinusFactor = 0.99f;
+ adsr->env = 0.0f;
+ adsr->leakFactor = 1.0f;
+}
+
+void tADSR2_freeFromPool (tADSR2* const adsrenv, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tADSR2* adsr = *adsrenv;
+ mpool_free(adsr, m);
+}
+
+void tADSR2_setAttack(tADSR2* const adsrenv, float attack)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->attack = LEAF_clip(0.0f, attack * 0.001f, 1.0f);
+ adsr->attackLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->attack) * ADSR2_INV_MIN_TIME;
+
+}
+
+void tADSR2_setDecay(tADSR2* const adsrenv, float decay)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->decay = LEAF_clip(0.0f, decay * 0.001f, 1.0f);
+ adsr->decayLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->decay) * ADSR2_INV_MIN_TIME;
+
+}
+
+void tADSR2_setSustain(tADSR2* const adsrenv, float sustain)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->sustain = sustain;
+
+ if (adsr->gate)
+ {
+ if (adsr->attacking == 0)
+ {
+ adsr->envTarget = sustain;
+ }
+ }
+}
+
+void tADSR2_setRelease(tADSR2* const adsrenv, float release)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->release = LEAF_clip(0.0f, release * 0.001f, 1.0f);
+ adsr->releaseLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->release) * ADSR2_INV_MIN_TIME;
+}
+
+// 0.999999 is slow leak, 0.9 is fast leak
+void tADSR2_setLeakFactor(tADSR2* const adsrenv, float leakFactor)
+{
+ _tADSR2* adsr = *adsrenv;
+
+ adsr->leakFactor = leakFactor;
+}
+
+void tADSR2_on(tADSR2* const adsrenv, float velocity)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->targetGainSquared = velocity * velocity;
+ adsr->envTarget = 1.2f;
+ adsr->leakGain = 1.0f;
+ adsr->gate = 1;
+ adsr->attacking = 1;
+}
+
+void tADSR2_off(tADSR2* const adsrenv)
+{
+ _tADSR2* adsr = *adsrenv;
+ adsr->gate = 0;
+ adsr->envTarget = 0.0f;
+}
+
+float tADSR2_tick(tADSR2* const adsrenv)
+{
+ _tADSR2* adsr = *adsrenv;
+ float lambda;
+
+ if (adsr->gate)
+ {
+ if (adsr->attacking)
+ {
+ lambda = adsr->attackLambda;
+ }
+ else
+ {
+ lambda = adsr->decayLambda;
+ }
+ }
+ else
+ {
+ lambda = adsr->releaseLambda;
+ }
+
+
+ // Adjust env
+ adsr->env += (adsr->envTarget - adsr->env) * lambda * leaf.invSampleRate;
+
+ // Turn off attacking state if envelope is HIGH
+ if (adsr->env >= 1.0f)
+ {
+ adsr->attacking = 0;
+ adsr->envTarget = adsr->sustain;
+ }
+
+ //smooth the gain value -- this is not ideal, a retrigger while the envelope is still going with a new gain will cause a jump, although it will be smoothed quickly. Maybe doing the math so the range is computed based on the gain rather than 0.->1. is preferable? But that's harder to get the exponential curve right without a lookup.
+ adsr->gain = ((adsr->factor*adsr->targetGainSquared)+(adsr->oneMinusFactor*adsr->gain));
+ adsr->leakGain *= adsr->leakFactor;
+ return adsr->env * adsr->gain * adsr->leakGain;
+}
+
+/* ADSR 3*/
+//This one doesn't use any lookup table - by Nigel Redmon from his blog. Thanks, Nigel!
+//-JS
+
+float calcADSR3Coef(double rate, double targetRatio)
+{
return (rate <= 0.0f) ? 0.0f : exp(-log((1.0 + targetRatio) / targetRatio) / rate);
}
-void tADSR_init(tADSR* const adsrenv, float attack, float decay, float sustain, float release)
+void tADSR3_init(tADSR3* const adsrenv, float attack, float decay, float sustain, float release)
{
- tADSR_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
+ tADSR3_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
}
-void tADSR_free(tADSR* const adsrenv)
+void tADSR3_free(tADSR3* const adsrenv)
{
- tADSR_freeFromPool(adsrenv, &leaf.mempool);
+ tADSR3_freeFromPool(adsrenv, &leaf.mempool);
}
-void tADSR_initToPool (tADSR* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
+void tADSR3_initToPool (tADSR3* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
{
_tMempool* m = *mp;
- _tADSR* adsr = *adsrenv = (_tADSR*) mpool_alloc(sizeof(_tADSR), m);
+ _tADSR3* adsr = *adsrenv = (_tADSR3*) mpool_alloc(sizeof(_tADSR3), m);
adsr->sampleRateInMs = leaf.sampleRate * 0.001f;
adsr->targetRatioA = 0.3f;
adsr->targetRatioDR = 0.0001f;
adsr->attackRate = attack * adsr->sampleRateInMs;
- adsr->attackCoef = calcADSRCoef(attack * adsr->sampleRateInMs, adsr->targetRatioA);
+ adsr->attackCoef = calcADSR3Coef(attack * adsr->sampleRateInMs, adsr->targetRatioA);
adsr->attackBase = (1.0f + adsr->targetRatioA) * (1.0f - adsr->attackCoef);
-
+
adsr->decayRate = decay * adsr->sampleRateInMs;
adsr->decayCoef = calcADSRCoef(decay * adsr->sampleRateInMs,adsr-> targetRatioDR);
adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
-
+
adsr->sustainLevel = sustain;
adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
-
+
adsr->releaseRate = release * adsr->sampleRateInMs;
adsr->releaseCoef = calcADSRCoef(release * adsr->sampleRateInMs, adsr->targetRatioDR);
adsr->releaseBase = -adsr->targetRatioDR * (1.0f - adsr->releaseCoef);
@@ -300,70 +734,73 @@
adsr->state = env_idle;
adsr->gain = 1.0f;
+ adsr->targetGainSquared = 1.0f;
+ adsr->factor = 0.01f;
+ adsr->oneMinusFactor = 0.99f;
adsr->output = 0.0f;
adsr->leakFactor = 1.0f;
}
-void tADSR_freeFromPool (tADSR* const adsrenv, tMempool* const mp)
+void tADSR3_freeFromPool (tADSR3* const adsrenv, tMempool* const mp)
{
_tMempool* m = *mp;
- _tADSR* adsr = *adsrenv;
+ _tADSR3* adsr = *adsrenv;
mpool_free(adsr, m);
}
-void tADSR_setAttack(tADSR* const adsrenv, float attack)
+void tADSR3_setAttack(tADSR3* const adsrenv, float attack)
{
- _tADSR* adsr = *adsrenv;
+ _tADSR3* adsr = *adsrenv;
adsr->attackRate = attack * adsr->sampleRateInMs;
- adsr->attackCoef = calcADSRCoef(adsr->attackRate, adsr->targetRatioA);
+ adsr->attackCoef = calcADSR3Coef(adsr->attackRate, adsr->targetRatioA);
adsr->attackBase = (1.0f + adsr->targetRatioA) * (1.0f - adsr->attackCoef);
}
-void tADSR_setDecay(tADSR* const adsrenv, float decay)
+void tADSR3_setDecay(tADSR3* const adsrenv, float decay)
{
- _tADSR* adsr = *adsrenv;
-
+ _tADSR3* adsr = *adsrenv;
+
adsr->decayRate = decay * adsr->sampleRateInMs;
- adsr->decayCoef = calcADSRCoef(adsr->decayRate,adsr-> targetRatioDR);
+ adsr->decayCoef = calcADSR3Coef(adsr->decayRate,adsr-> targetRatioDR);
adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
}
-void tADSR_setSustain(tADSR* const adsrenv, float sustain)
+void tADSR3_setSustain(tADSR3* const adsrenv, float sustain)
{
- _tADSR* adsr = *adsrenv;
-
+ _tADSR3* adsr = *adsrenv;
+
adsr->sustainLevel = sustain;
adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
}
-void tADSR_setRelease(tADSR* const adsrenv, float release)
+void tADSR3_setRelease(tADSR3* const adsrenv, float release)
{
- _tADSR* adsr = *adsrenv;
-
+ _tADSR3* adsr = *adsrenv;
+
adsr->releaseRate = release * adsr->sampleRateInMs;
- adsr->releaseCoef = calcADSRCoef(adsr->releaseRate, adsr->targetRatioDR);
+ adsr->releaseCoef = calcADSR3Coef(adsr->releaseRate, adsr->targetRatioDR);
adsr->releaseBase = -adsr->targetRatioDR * (1.0f - adsr->releaseCoef);
}
// 0.999999 is slow leak, 0.9 is fast leak
-void tADSR_setLeakFactor(tADSR* const adsrenv, float leakFactor)
+void tADSR3_setLeakFactor(tADSR3* const adsrenv, float leakFactor)
{
- _tADSR* adsr = *adsrenv;
+ _tADSR3* adsr = *adsrenv;
adsr->leakFactor = leakFactor;
}
-void tADSR_on(tADSR* const adsrenv, float velocity)
+void tADSR3_on(tADSR3* const adsrenv, float velocity)
{
- _tADSR* adsr = *adsrenv;
+ _tADSR3* adsr = *adsrenv;
adsr->state = env_attack;
- adsr->gain = velocity;
+ adsr->targetGainSquared = velocity * velocity;
}
-void tADSR_off(tADSR* const adsrenv)
+void tADSR3_off(tADSR3* const adsrenv)
{
- _tADSR* adsr = *adsrenv;
+ _tADSR3* adsr = *adsrenv;
if (adsr->state != env_idle)
{
@@ -371,11 +808,11 @@
}
}
-float tADSR_tick(tADSR* const adsrenv)
+float tADSR3_tick(tADSR3* const adsrenv)
{
- _tADSR* adsr = *adsrenv;
-
+ _tADSR3* adsr = *adsrenv;
+
switch (adsr->state) {
case env_idle:
break;
@@ -403,11 +840,10 @@
adsr->state = env_idle;
}
}
+ //smooth the gain value -- this is not ideal, a retrigger while the envelope is still going with a new gain will cause a jump, although it will be smoothed quickly. Maybe doing the math so the range is computed based on the gain rather than 0.->1. is preferable? But that's harder to get the exponential curve right without a lookup.
+ adsr->gain = (adsr->factor*adsr->targetGainSquared)+(adsr->oneMinusFactor*adsr->gain);
return adsr->output * adsr->gain;
}
-
-
-