| /* Audio Library for Teensy 3.X | /* Audio Library for Teensy 3.X | ||||
| * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com | |||||
| * Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com | |||||
| * | * | ||||
| * Development of this audio library was funded by PJRC.COM, LLC by sales of | * Development of this audio library was funded by PJRC.COM, LLC by sales of | ||||
| * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | ||||
| void AudioEffectEnvelope::noteOn(void) | void AudioEffectEnvelope::noteOn(void) | ||||
| { | { | ||||
| __disable_irq(); | __disable_irq(); | ||||
| mult = 0; | |||||
| mult_hires = 0; | |||||
| count = delay_count; | count = delay_count; | ||||
| if (count > 0) { | if (count > 0) { | ||||
| state = STATE_DELAY; | state = STATE_DELAY; | ||||
| inc = 0; | |||||
| inc_hires = 0; | |||||
| } else { | } else { | ||||
| state = STATE_ATTACK; | state = STATE_ATTACK; | ||||
| count = attack_count; | count = attack_count; | ||||
| inc = (0x10000 / count) >> 3; | |||||
| inc_hires = 0x40000000 / (int32_t)count; | |||||
| } | } | ||||
| __enable_irq(); | __enable_irq(); | ||||
| } | } | ||||
| void AudioEffectEnvelope::noteOff(void) | void AudioEffectEnvelope::noteOff(void) | ||||
| { | { | ||||
| __disable_irq(); | __disable_irq(); | ||||
| state = STATE_RELEASE; | |||||
| count = release_count; | |||||
| mult = sustain_mult; | |||||
| inc = (-mult / ((int32_t)count << 3)); | |||||
| if (state != STATE_IDLE) { | |||||
| state = STATE_RELEASE; | |||||
| count = release_count; | |||||
| inc_hires = (-mult_hires) / (int32_t)count; | |||||
| } | |||||
| __enable_irq(); | __enable_irq(); | ||||
| } | } | ||||
| count = hold_count; | count = hold_count; | ||||
| if (count > 0) { | if (count > 0) { | ||||
| state = STATE_HOLD; | state = STATE_HOLD; | ||||
| mult = 0x10000; | |||||
| inc = 0; | |||||
| mult_hires = 0x40000000; | |||||
| inc_hires = 0; | |||||
| } else { | } else { | ||||
| count = decay_count; | |||||
| state = STATE_DECAY; | state = STATE_DECAY; | ||||
| inc = ((sustain_mult - 0x10000) / ((int32_t)count << 3)); | |||||
| count = decay_count; | |||||
| inc_hires = (sustain_mult - 0x40000000) / (int32_t)count; | |||||
| } | } | ||||
| continue; | continue; | ||||
| } else if (state == STATE_HOLD) { | } else if (state == STATE_HOLD) { | ||||
| state = STATE_DECAY; | state = STATE_DECAY; | ||||
| count = decay_count; | count = decay_count; | ||||
| inc = ((sustain_mult - 0x10000) / (int32_t)count) >> 3; | |||||
| inc_hires = (sustain_mult - 0x40000000) / (int32_t)count; | |||||
| continue; | continue; | ||||
| } else if (state == STATE_DECAY) { | } else if (state == STATE_DECAY) { | ||||
| state = STATE_SUSTAIN; | state = STATE_SUSTAIN; | ||||
| count = 0xFFFF; | count = 0xFFFF; | ||||
| mult = sustain_mult; | |||||
| inc = 0; | |||||
| mult_hires = sustain_mult; | |||||
| inc_hires = 0; | |||||
| } else if (state == STATE_SUSTAIN) { | } else if (state == STATE_SUSTAIN) { | ||||
| count = 0xFFFF; | count = 0xFFFF; | ||||
| } else if (state == STATE_RELEASE) { | } else if (state == STATE_RELEASE) { | ||||
| } else if (state == STATE_DELAY) { | } else if (state == STATE_DELAY) { | ||||
| state = STATE_ATTACK; | state = STATE_ATTACK; | ||||
| count = attack_count; | count = attack_count; | ||||
| inc = (0x10000 / count) >> 3; | |||||
| inc_hires = 0x40000000 / count; | |||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| // process 8 samples, using only mult and inc | |||||
| int32_t mult = mult_hires >> 14; | |||||
| int32_t inc = inc_hires >> 17; | |||||
| // process 8 samples, using only mult and inc (16 bit resolution) | |||||
| sample12 = *p++; | sample12 = *p++; | ||||
| sample34 = *p++; | sample34 = *p++; | ||||
| sample56 = *p++; | sample56 = *p++; | ||||
| *p++ = sample34; | *p++ = sample34; | ||||
| *p++ = sample56; | *p++ = sample56; | ||||
| *p++ = sample78; | *p++ = sample78; | ||||
| // adjust the long-term gain using 30 bit resolution (fix #102) | |||||
| // https://github.com/PaulStoffregen/Audio/issues/102 | |||||
| mult_hires += inc_hires; | |||||
| count--; | count--; | ||||
| } | } | ||||
| transmit(block); | transmit(block); |
| /* Audio Library for Teensy 3.X | /* Audio Library for Teensy 3.X | ||||
| * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com | |||||
| * Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com | |||||
| * | * | ||||
| * Development of this audio library was funded by PJRC.COM, LLC by sales of | * Development of this audio library was funded by PJRC.COM, LLC by sales of | ||||
| * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | ||||
| } | } | ||||
| void attack(float milliseconds) { | void attack(float milliseconds) { | ||||
| attack_count = milliseconds2count(milliseconds); | attack_count = milliseconds2count(milliseconds); | ||||
| if (attack_count == 0) attack_count = 1; | |||||
| } | } | ||||
| void hold(float milliseconds) { | void hold(float milliseconds) { | ||||
| hold_count = milliseconds2count(milliseconds); | hold_count = milliseconds2count(milliseconds); | ||||
| } | } | ||||
| void decay(float milliseconds) { | void decay(float milliseconds) { | ||||
| decay_count = milliseconds2count(milliseconds); | decay_count = milliseconds2count(milliseconds); | ||||
| if (decay_count == 0) decay_count = 1; | |||||
| } | } | ||||
| void sustain(float level) { | void sustain(float level) { | ||||
| if (level < 0.0) level = 0; | if (level < 0.0) level = 0; | ||||
| else if (level > 1.0) level = 1.0; | else if (level > 1.0) level = 1.0; | ||||
| sustain_mult = level * 65536.0; | |||||
| sustain_mult = level * 1073741824.0; | |||||
| } | } | ||||
| void release(float milliseconds) { | void release(float milliseconds) { | ||||
| release_count = milliseconds2count(milliseconds); | release_count = milliseconds2count(milliseconds); | ||||
| if (release_count == 0) release_count = 1; | |||||
| } | } | ||||
| using AudioStream::release; | using AudioStream::release; | ||||
| virtual void update(void); | virtual void update(void); | ||||
| uint16_t milliseconds2count(float milliseconds) { | uint16_t milliseconds2count(float milliseconds) { | ||||
| if (milliseconds < 0.0) milliseconds = 0.0; | if (milliseconds < 0.0) milliseconds = 0.0; | ||||
| uint32_t c = ((uint32_t)(milliseconds*SAMPLES_PER_MSEC)+7)>>3; | uint32_t c = ((uint32_t)(milliseconds*SAMPLES_PER_MSEC)+7)>>3; | ||||
| if (c > 1103) return 1103; // allow up to 200 ms | |||||
| if (c > 65535) c = 65535; // allow up to 11.88 seconds | |||||
| return c; | return c; | ||||
| } | } | ||||
| audio_block_t *inputQueueArray[1]; | audio_block_t *inputQueueArray[1]; | ||||
| // state | // state | ||||
| uint8_t state; // idle, delay, attack, hold, decay, sustain, release | |||||
| uint16_t count; // how much time remains in this state, in 8 sample units | |||||
| int32_t mult; // attenuation, 0=off, 0x10000=unity gain | |||||
| int32_t inc; // amount to change mult on each sample | |||||
| uint8_t state; // idle, delay, attack, hold, decay, sustain, release | |||||
| 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 inc_hires; // amount to change mult_hires every 8 samples | |||||
| // settings | // settings | ||||
| uint16_t delay_count; | uint16_t delay_count; | ||||
| uint16_t attack_count; | uint16_t attack_count; |