@@ -78,7 +78,7 @@ void AudioEffectChorus::update(void) | |||
// do passthru | |||
// It stores the unmodified data in the delay line so that | |||
// it isn't as likely to click | |||
if(num_chorus < 1) { | |||
if(num_chorus <= 1) { | |||
// Just passthrough | |||
block = receiveWritable(0); | |||
if(block) { | |||
@@ -93,6 +93,7 @@ void AudioEffectChorus::update(void) | |||
transmit(block,0); | |||
release(block); | |||
} | |||
return; | |||
} | |||
// L E F T C H A N N E L | |||
@@ -100,6 +101,7 @@ void AudioEffectChorus::update(void) | |||
block = receiveWritable(0); | |||
if(block) { | |||
bp = block->data; | |||
uint32_t tmp = delay_length/(num_chorus - 1) - 1; | |||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | |||
l_circ_idx++; | |||
if(l_circ_idx >= delay_length) { | |||
@@ -110,7 +112,7 @@ void AudioEffectChorus::update(void) | |||
c_idx = l_circ_idx; | |||
for(int k = 0; k < num_chorus; k++) { | |||
sum += l_delayline[c_idx]; | |||
if(num_chorus > 1)c_idx -= delay_length/(num_chorus - 1) - 1; | |||
if(num_chorus > 1)c_idx -= tmp; | |||
if(c_idx < 0) { | |||
c_idx += delay_length; | |||
} |
@@ -157,6 +157,15 @@ static int16_t testmem[8000]; // testing only | |||
#define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0) | |||
// While 20 MHz (Teensy actually uses 16 MHz in most cases) and even 24 MHz | |||
// have worked well in testing at room temperature with 3.3V power, to fully | |||
// meet all the worst case timing specs, the SPI clock low time would need | |||
// to be 40ns (12.5 MHz clock) for the single chip case and 51ns (9.8 MHz | |||
// clock) for the 6-chip memoryboard with 74LCX126 buffers. | |||
// | |||
// Timing analysis and info is here: | |||
// https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library?p=97506&viewfull=1#post97506 | |||
void AudioEffectDelayExternal::read(uint32_t offset, uint32_t count, int16_t *data) | |||
{ | |||
uint32_t addr = memory_begin + offset; |
@@ -77,7 +77,7 @@ if(0) { | |||
// initial index | |||
l_delay_rate_index = 0; | |||
l_circ_idx = 0; | |||
delay_rate_incr = delay_rate/44100.*2147483648.; | |||
delay_rate_incr = delay_rate / (2147483648.0 * AUDIO_SAMPLE_RATE_EXACT); | |||
//Serial.println(delay_rate_incr,HEX); | |||
delay_offset_idx = delay_offset; | |||
@@ -100,7 +100,7 @@ boolean AudioEffectFlange::voices(int delay_offset,int d_depth,float delay_rate) | |||
delay_depth = d_depth; | |||
delay_rate_incr = delay_rate/44100.*2147483648.; | |||
delay_rate_incr = delay_rate / (2147483648.0 * AUDIO_SAMPLE_RATE_EXACT); | |||
delay_offset_idx = delay_offset; | |||
// Allow the passthru code to go through |
@@ -1053,6 +1053,13 @@ span.mainfunction {color: #993300; font-weight: bolder} | |||
Disabling the audio library interrupt for too long may cause audible | |||
dropouts or glitches. | |||
</p> | |||
<p>An experimental SD library optimization exists, which can remove these | |||
SD library restrictions. It also allows reliable playback of more | |||
files at the same time. To enable this special code, find and edit | |||
the SD_t3.h file within your Arduino folder. See the comments within | |||
that file for details. | |||
</p> | |||
</script> | |||
<script type="text/x-red" data-template-name="AudioPlaySdWav"> | |||
<div class="form-row"> |
@@ -32,20 +32,17 @@ | |||
// compute (a - b) / c | |||
// handling 32 bit interger overflow at every step | |||
// without resorting to slow 64 bit math | |||
#if 0 | |||
// TODO: write this in assembly.... | |||
static inline int32_t substract_32_then_divide(int32_t a, int32_t b, int32_t c) __attribute__((always_inline, unused)); | |||
static inline int32_t substract_32_then_divide(int32_t a, int32_t b, int32_t c) | |||
#if defined(KINETISK) | |||
static inline int32_t substract_int32_then_divide_int32(int32_t a, int32_t b, int32_t c) __attribute__((always_inline, unused)); | |||
static inline int32_t substract_int32_then_divide_int32(int32_t a, int32_t b, int32_t c) | |||
{ | |||
int32_t diff = substract_32_saturate(a, b); | |||
// if only C language provided a way to test Q status bit.... | |||
if (diff != 0x7FFFFFFF && diff != 0x80000000) { | |||
return diff / c; | |||
} else { | |||
diff = substract_32_saturate(a/2, b/2); | |||
if (c == 1 || c == -1) c *= 2; // <-- horrible, incorrect hack | |||
return (diff / c) * 2; | |||
} | |||
int r; | |||
r = substract_32_saturate(a,b); | |||
if ( !get_q_psr() ) return (r/c); | |||
clr_q_psr(); | |||
if ( c==0 ) r=0; | |||
if (__builtin_abs(c)<=1) return r; | |||
return (a/c)-(b/c); | |||
} | |||
#else | |||
// compute (a - b) / c ... handling 32 bit interger overflow without slow 64 bit math |
@@ -34,7 +34,7 @@ | |||
boolean AudioSynthToneSweep::play(float t_amp,int t_lo,int t_hi,float t_time) | |||
{ | |||
double tone_tmp; | |||
float tone_tmp; | |||
if(0) { | |||
Serial.print("AudioSynthToneSweep.begin(tone_amp = "); | |||
@@ -52,8 +52,8 @@ if(0) { | |||
if(t_amp > 1)return false; | |||
if(t_lo < 1)return false; | |||
if(t_hi < 1)return false; | |||
if(t_hi >= 44100/2)return false; | |||
if(t_lo >= 44100/2)return false; | |||
if(t_hi >= (int) AUDIO_SAMPLE_RATE_EXACT / 2)return false; | |||
if(t_lo >= (int) AUDIO_SAMPLE_RATE_EXACT / 2)return false; | |||
if(t_time < 0)return false; | |||
tone_lo = t_lo; | |||
tone_hi = t_hi; | |||
@@ -69,7 +69,7 @@ if(0) { | |||
tone_sign = -1; | |||
tone_tmp = tone_lo - tone_hi; | |||
} | |||
tone_tmp = tone_tmp/t_time/44100.; | |||
tone_tmp = tone_tmp / t_time / AUDIO_SAMPLE_RATE_EXACT; | |||
tone_incr = (tone_tmp * 0x100000000LL); | |||
sweep_busy = 1; | |||
return(true); | |||
@@ -95,22 +95,23 @@ void AudioSynthToneSweep::update(void) | |||
block = allocate(); | |||
if(block) { | |||
bp = block->data; | |||
uint32_t tmp = tone_freq >> 32; | |||
uint64_t tone_tmp = (0x400000000000LL * (int)(tmp&0x7fffffff)) / (int) AUDIO_SAMPLE_RATE_EXACT; | |||
// Generate the sweep | |||
for(i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | |||
*bp++ = (short)(( (short)(arm_sin_q31((uint32_t)((tone_phase >> 15)&0x7fffffff))>>16) *tone_amp) >> 16); | |||
uint64_t tone_tmp = (0x400000000000LL * (int)((tone_freq >> 32)&0x7fffffff))/44100; | |||
tone_phase += tone_tmp; | |||
if(tone_phase & 0x800000000000LL)tone_phase &= 0x7fffffffffffLL; | |||
if(tone_sign > 0) { | |||
if((tone_freq >> 32) > tone_hi) { | |||
if(tmp > tone_hi) { | |||
sweep_busy = 0; | |||
break; | |||
} | |||
tone_freq += tone_incr; | |||
} else { | |||
if((tone_freq >> 32) < tone_hi) { | |||
if(tmp < tone_hi) { | |||
sweep_busy = 0; | |||
break; | |||
@@ -121,8 +122,7 @@ void AudioSynthToneSweep::update(void) | |||
while(i < AUDIO_BLOCK_SAMPLES) { | |||
*bp++ = 0; | |||
i++; | |||
} | |||
//b_count++; | |||
} | |||
// send the samples to the left channel | |||
transmit(block,0); | |||
release(block); |
@@ -338,7 +338,7 @@ static inline uint32_t get_q_psr(void) __attribute__((always_inline, unused)); | |||
static inline uint32_t get_q_psr(void) | |||
{ | |||
uint32_t out; | |||
asm volatile("mrs %0, APSR" : "=r" (out)); | |||
asm ("mrs %0, APSR" : "=r" (out)); | |||
return (out & 0x8000000)>>27; | |||
} | |||
@@ -347,9 +347,8 @@ static inline void clr_q_psr(void) __attribute__((always_inline, unused)); | |||
static inline void clr_q_psr(void) | |||
{ | |||
uint32_t t; | |||
asm volatile("mrs %0,APSR " : "=r" (t)); | |||
asm volatile("bfc %0, #27, #1" : "=r" (t)); | |||
asm volatile("msr APSR_nzcvq,%0" : "=r" (t)); | |||
asm ("mov %[t],#0\n" | |||
"msr APSR_nzcvq,%0\n" : [t] "=&r" (t)::"cc"); | |||
} | |||
#endif |