https://forum.pjrc.com/threads/27806-Clicking-envelope-with-Audio-Librarydds
#define STATE_DECAY 4 | #define STATE_DECAY 4 | ||||
#define STATE_SUSTAIN 5 | #define STATE_SUSTAIN 5 | ||||
#define STATE_RELEASE 6 | #define STATE_RELEASE 6 | ||||
#define STATE_FORCED 7 | |||||
void AudioEffectEnvelope::noteOn(void) | void AudioEffectEnvelope::noteOn(void) | ||||
{ | { | ||||
__disable_irq(); | __disable_irq(); | ||||
mult_hires = 0; | |||||
count = delay_count; | |||||
if (count > 0) { | |||||
state = STATE_DELAY; | |||||
inc_hires = 0; | |||||
} else { | |||||
state = STATE_ATTACK; | |||||
count = attack_count; | |||||
inc_hires = 0x40000000 / (int32_t)count; | |||||
if (state == STATE_IDLE || state == STATE_DELAY || release_forced_count == 0) { | |||||
mult_hires = 0; | |||||
count = delay_count; | |||||
if (count > 0) { | |||||
state = STATE_DELAY; | |||||
inc_hires = 0; | |||||
} else { | |||||
state = STATE_ATTACK; | |||||
count = attack_count; | |||||
inc_hires = 0x40000000 / (int32_t)count; | |||||
} | |||||
} else if (state != STATE_FORCED) { | |||||
state = STATE_FORCED; | |||||
count = release_forced_count; | |||||
inc_hires = (-mult_hires) / (int32_t)count; | |||||
} | } | ||||
__enable_irq(); | __enable_irq(); | ||||
} | } | ||||
void AudioEffectEnvelope::noteOff(void) | void AudioEffectEnvelope::noteOff(void) | ||||
{ | { | ||||
__disable_irq(); | __disable_irq(); | ||||
if (state != STATE_IDLE) { | |||||
if (state != STATE_IDLE && state != STATE_FORCED) { | |||||
state = STATE_RELEASE; | state = STATE_RELEASE; | ||||
count = release_count; | count = release_count; | ||||
inc_hires = (-mult_hires) / (int32_t)count; | inc_hires = (-mult_hires) / (int32_t)count; | ||||
*p++ = 0; | *p++ = 0; | ||||
} | } | ||||
break; | break; | ||||
} else if (state == STATE_FORCED) { | |||||
mult_hires = 0; | |||||
count = delay_count; | |||||
if (count > 0) { | |||||
state = STATE_DELAY; | |||||
inc_hires = 0; | |||||
} else { | |||||
state = STATE_ATTACK; | |||||
count = attack_count; | |||||
inc_hires = 0x40000000 / (int32_t)count; | |||||
} | |||||
} else if (state == STATE_DELAY) { | } else if (state == STATE_DELAY) { | ||||
state = STATE_ATTACK; | state = STATE_ATTACK; | ||||
count = attack_count; | count = attack_count; |
public: | public: | ||||
AudioEffectEnvelope() : AudioStream(1, inputQueueArray) { | AudioEffectEnvelope() : AudioStream(1, inputQueueArray) { | ||||
state = 0; | state = 0; | ||||
delay(0.0); // default values... | |||||
attack(1.5); | |||||
hold(0.5); | |||||
decay(15.0); | |||||
sustain(0.667); | |||||
release(30.0); | |||||
delay(0.0f); // default values... | |||||
attack(10.5f); | |||||
hold(2.5f); | |||||
decay(35.0f); | |||||
sustain(0.5f); | |||||
release(300.0f); | |||||
releaseNoteOn(5.0f); | |||||
} | } | ||||
void noteOn(); | void noteOn(); | ||||
void noteOff(); | void noteOff(); | ||||
release_count = milliseconds2count(milliseconds); | release_count = milliseconds2count(milliseconds); | ||||
if (release_count == 0) release_count = 1; | if (release_count == 0) release_count = 1; | ||||
} | } | ||||
void releaseNoteOn(float milliseconds) { | |||||
release_forced_count = milliseconds2count(milliseconds); | |||||
if (release_count == 0) release_count = 1; | |||||
} | |||||
using AudioStream::release; | using AudioStream::release; | ||||
virtual void update(void); | virtual void update(void); | ||||
private: | private: | ||||
} | } | ||||
audio_block_t *inputQueueArray[1]; | audio_block_t *inputQueueArray[1]; | ||||
// state | // state | ||||
uint8_t state; // idle, delay, attack, hold, decay, sustain, release | |||||
uint8_t state; // idle, delay, attack, hold, decay, sustain, release, forced | |||||
uint16_t count; // how much time remains in this state, in 8 sample units | uint16_t count; // how much time remains in this state, in 8 sample units | ||||
int32_t mult_hires; // attenuation, 0=off, 0x40000000=unity gain | int32_t mult_hires; // attenuation, 0=off, 0x40000000=unity gain | ||||
int32_t inc_hires; // amount to change mult_hires every 8 samples | int32_t inc_hires; // amount to change mult_hires every 8 samples | ||||
uint16_t decay_count; | uint16_t decay_count; | ||||
int32_t sustain_mult; | int32_t sustain_mult; | ||||
uint16_t release_count; | uint16_t release_count; | ||||
uint16_t release_forced_count; | |||||
}; | }; | ||||
default is zero, for no delay. | default is zero, for no delay. | ||||
</p> | </p> | ||||
<p class=func><span class=keyword>attack</span>(milliseconds);</p> | <p class=func><span class=keyword>attack</span>(milliseconds);</p> | ||||
<p class=desc>Set the attack time. The default is 1.5 milliseconds. | |||||
<p class=desc>Set the attack time. The default is 10.5 milliseconds. | |||||
</p> | </p> | ||||
<p class=func><span class=keyword>hold</span>(milliseconds);</p> | <p class=func><span class=keyword>hold</span>(milliseconds);</p> | ||||
<p class=desc>Set the hold time. The default is 0.5 milliseconds. | |||||
<p class=desc>Set the hold time. The default is 2.5 milliseconds. | |||||
</p> | </p> | ||||
<p class=func><span class=keyword>decay</span>(milliseconds);</p> | <p class=func><span class=keyword>decay</span>(milliseconds);</p> | ||||
<p class=desc>Set the decay time. The default is 15 milliseconds. | |||||
<p class=desc>Set the decay time. The default is 35 milliseconds. | |||||
</p> | </p> | ||||
<p class=func><span class=keyword>sustain</span>(level);</p> | <p class=func><span class=keyword>sustain</span>(level);</p> | ||||
<p class=desc>Set the sustain level. The range is 0 to 1.0. The | <p class=desc>Set the sustain level. The range is 0 to 1.0. The | ||||
until noteOff() is called. | until noteOff() is called. | ||||
</p> | </p> | ||||
<p class=func><span class=keyword>release</span>(milliseconds);</p> | <p class=func><span class=keyword>release</span>(milliseconds);</p> | ||||
<p class=desc>Set the release time. The default is 30 millisecond. | |||||
<p class=desc>Set the release time. The default is 300 millisecond. | |||||
</p> | |||||
<p class=func><span class=keyword>releaseNoteOn</span>(milliseconds);</p> | |||||
<p class=desc>Set a quick release time to be used when a new note is | |||||
started while the envelop is in any state passing the signal. | |||||
This will add latency before your new attack phase begins, so | |||||
short times are recommended. Zero may be used to completely | |||||
disable this feature (never extra latency). Longer times help | |||||
reduce clicks or pops. The default is 5 millisecond. | |||||
</p> | </p> | ||||
<h3>Examples</h3> | <h3>Examples</h3> | ||||
<p class=exam>File > Examples > Audio > Synthesis > PlaySynthMusic | <p class=exam>File > Examples > Audio > Synthesis > PlaySynthMusic |
decay KEYWORD2 | decay KEYWORD2 | ||||
sustain KEYWORD2 | sustain KEYWORD2 | ||||
release KEYWORD2 | release KEYWORD2 | ||||
releaseNoteOn KEYWORD2 | |||||
inputLevel KEYWORD2 | inputLevel KEYWORD2 | ||||
inputSelect KEYWORD2 | inputSelect KEYWORD2 | ||||
muteHeadphone KEYWORD2 | muteHeadphone KEYWORD2 |