/* 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; |