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 |