Skip to content

Commit 7d8e41f

Browse files
authored
Merge pull request adafruit#10252 from relic-se/audiodelays_stereo
Fix handling of stereo audio within `audiodelays.Delay` when `freq_shift=True`
2 parents 376e3ba + 7d0e72e commit 7d8e41f

File tree

2 files changed

+66
-65
lines changed

2 files changed

+66
-65
lines changed

shared-module/audiodelays/Echo.c

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,10 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
9898

9999
// read is where we read previous echo from delay_ms ago to play back now
100100
// write is where the store the latest playing sample to echo back later
101-
self->echo_buffer_read_pos = self->buffer_len / sizeof(uint16_t);
102-
self->echo_buffer_write_pos = 0;
101+
self->echo_buffer_left_pos = 0;
103102

104-
// where we read the previous echo from delay_ms ago to play back now (for freq shift)
105-
self->echo_buffer_left_pos = self->echo_buffer_right_pos = 0;
103+
// use a separate buffer position for the right channel
104+
self->echo_buffer_right_pos = 0;
106105
}
107106

108107
void common_hal_audiodelays_echo_deinit(audiodelays_echo_obj_t *self) {
@@ -128,30 +127,32 @@ void recalculate_delay(audiodelays_echo_obj_t *self, mp_float_t f_delay_ms) {
128127
// Require that delay is at least 1 sample long
129128
f_delay_ms = MAX(f_delay_ms, self->sample_ms);
130129

130+
// Calculate the maximum buffer size per channel in bytes
131+
uint32_t max_echo_buffer_len = self->max_echo_buffer_len >> (self->base.channel_count - 1);
132+
131133
if (self->freq_shift) {
132134
// Calculate the rate of iteration over the echo buffer with 8 sub-bits
133135
self->echo_buffer_rate = (uint32_t)MAX(self->max_delay_ms / f_delay_ms * MICROPY_FLOAT_CONST(256.0), MICROPY_FLOAT_CONST(1.0));
134-
self->echo_buffer_len = self->max_echo_buffer_len;
136+
// Only use half of the buffer per channel if stereo
137+
self->echo_buffer_len = max_echo_buffer_len;
135138
} else {
136139
// Calculate the current echo buffer length in bytes
137-
uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * (self->base.channel_count * sizeof(uint16_t));
138-
139-
// Check if our new echo is too long for our maximum buffer
140-
if (new_echo_buffer_len > self->max_echo_buffer_len) {
141-
return;
142-
} else if (new_echo_buffer_len < 0.0) { // or too short!
143-
return;
144-
}
145-
146-
// If the echo buffer is larger then our audio buffer weird things happen
147-
if (new_echo_buffer_len < self->buffer_len) {
148-
return;
140+
uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * sizeof(uint16_t);
141+
142+
// Limit to valid range
143+
if (new_echo_buffer_len > max_echo_buffer_len) {
144+
new_echo_buffer_len = max_echo_buffer_len;
145+
} else if (new_echo_buffer_len < self->buffer_len) {
146+
// If the echo buffer is smaller than our audio buffer, weird things happen
147+
new_echo_buffer_len = self->buffer_len;
149148
}
150149

151150
self->echo_buffer_len = new_echo_buffer_len;
152151

153152
// Clear the now unused part of the buffer or some weird artifacts appear
154-
memset(self->echo_buffer + self->echo_buffer_len, 0, self->max_echo_buffer_len - self->echo_buffer_len);
153+
for (uint32_t i = 0; i < self->base.channel_count; i++) {
154+
memset(self->echo_buffer + (i * max_echo_buffer_len) + self->echo_buffer_len, 0, max_echo_buffer_len - self->echo_buffer_len);
155+
}
155156
}
156157

157158
self->current_delay_ms = f_delay_ms;
@@ -178,6 +179,12 @@ bool common_hal_audiodelays_echo_get_freq_shift(audiodelays_echo_obj_t *self) {
178179
}
179180

180181
void common_hal_audiodelays_echo_set_freq_shift(audiodelays_echo_obj_t *self, bool freq_shift) {
182+
// Clear the echo buffer and reset buffer position if changing freq_shift modes
183+
if (self->freq_shift != freq_shift) {
184+
memset(self->echo_buffer, 0, self->max_echo_buffer_len);
185+
self->echo_buffer_left_pos = 0;
186+
self->echo_buffer_right_pos = 0;
187+
}
181188
self->freq_shift = freq_shift;
182189
uint32_t delay_ms = (uint32_t)synthio_block_slot_get(&self->delay_ms);
183190
recalculate_delay(self, delay_ms);
@@ -277,15 +284,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
277284
}
278285

279286
uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t);
280-
281-
// Set our echo buffer position accounting for stereo
282-
uint32_t echo_buffer_pos = 0;
283-
if (self->freq_shift) {
284-
echo_buffer_pos = self->echo_buffer_left_pos;
285-
if (channel == 1) {
286-
echo_buffer_pos = self->echo_buffer_right_pos;
287-
}
288-
}
287+
uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t);
289288

290289
// If we have no sample keep the echo echoing
291290
if (self->sample == NULL) {
@@ -309,18 +308,22 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
309308
int16_t echo, word = 0;
310309
uint32_t next_buffer_pos = 0;
311310

311+
// Get our echo buffer position and offset depending on current channel
312+
uint32_t echo_buffer_offset = max_echo_buf_len * ((single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1));
313+
uint32_t echo_buffer_pos = echo_buffer_offset ? self->echo_buffer_right_pos : self->echo_buffer_left_pos;
314+
312315
if (self->freq_shift) {
313-
echo = echo_buffer[echo_buffer_pos >> 8];
316+
echo = echo_buffer[(echo_buffer_pos >> 8) + echo_buffer_offset];
314317
next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate;
315318

316319
for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) {
317-
word = (int16_t)(echo_buffer[j % echo_buf_len] * decay);
318-
echo_buffer[j % echo_buf_len] = word;
320+
word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay);
321+
echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = word;
319322
}
320323
} else {
321-
echo = echo_buffer[self->echo_buffer_read_pos++];
324+
echo = echo_buffer[echo_buffer_pos + echo_buffer_offset];
322325
word = (int16_t)(echo * decay);
323-
echo_buffer[self->echo_buffer_write_pos++] = word;
326+
echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = word;
324327
}
325328

326329
word = (int16_t)(echo * mix);
@@ -339,13 +342,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
339342

340343
if (self->freq_shift) {
341344
echo_buffer_pos = next_buffer_pos % (echo_buf_len << 8);
345+
} else if (!self->freq_shift && echo_buffer_pos >= echo_buf_len) {
346+
echo_buffer_pos = 0;
347+
}
348+
349+
// Update buffer position
350+
if (echo_buffer_offset) {
351+
self->echo_buffer_right_pos = echo_buffer_pos;
342352
} else {
343-
if (self->echo_buffer_read_pos >= echo_buf_len) {
344-
self->echo_buffer_read_pos = 0;
345-
}
346-
if (self->echo_buffer_write_pos >= echo_buf_len) {
347-
self->echo_buffer_write_pos = 0;
348-
}
353+
self->echo_buffer_left_pos = echo_buffer_pos;
349354
}
350355
}
351356
}
@@ -380,37 +385,42 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
380385

381386
int32_t echo, word = 0;
382387
uint32_t next_buffer_pos = 0;
388+
389+
// Get our echo buffer position and offset depending on current channel
390+
uint32_t echo_buffer_offset = max_echo_buf_len * ((single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1));
391+
uint32_t echo_buffer_pos = echo_buffer_offset ? self->echo_buffer_right_pos : self->echo_buffer_left_pos;
392+
383393
if (self->freq_shift) {
384-
echo = echo_buffer[echo_buffer_pos >> 8];
394+
echo = echo_buffer[(echo_buffer_pos >> 8) + echo_buffer_offset];
385395
next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate;
386396
} else {
387-
echo = echo_buffer[self->echo_buffer_read_pos++];
397+
echo = echo_buffer[echo_buffer_pos + echo_buffer_offset];
388398
word = (int32_t)(echo * decay + sample_word);
389399
}
390400

391401
if (MP_LIKELY(self->base.bits_per_sample == 16)) {
392402
if (self->freq_shift) {
393403
for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) {
394-
word = (int32_t)(echo_buffer[j % echo_buf_len] * decay + sample_word);
404+
word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word);
395405
word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2));
396-
echo_buffer[j % echo_buf_len] = (int16_t)word;
406+
echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)word;
397407
}
398408
} else {
399409
word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2));
400-
echo_buffer[self->echo_buffer_write_pos++] = (int16_t)word;
410+
echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)word;
401411
}
402412
} else {
403413
if (self->freq_shift) {
404414
for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) {
405-
word = (int32_t)(echo_buffer[j % echo_buf_len] * decay + sample_word);
415+
word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word);
406416
// Do not have mix_down for 8 bit so just hard cap samples into 1 byte
407417
word = MIN(MAX(word, -128), 127);
408-
echo_buffer[j % echo_buf_len] = (int8_t)word;
418+
echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)word;
409419
}
410420
} else {
411421
// Do not have mix_down for 8 bit so just hard cap samples into 1 byte
412422
word = MIN(MAX(word, -128), 127);
413-
echo_buffer[self->echo_buffer_write_pos++] = (int8_t)word;
423+
echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)word;
414424
}
415425
}
416426

@@ -433,13 +443,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
433443

434444
if (self->freq_shift) {
435445
echo_buffer_pos = next_buffer_pos % (echo_buf_len << 8);
446+
} else if (!self->freq_shift && echo_buffer_pos >= echo_buf_len) {
447+
echo_buffer_pos = 0;
448+
}
449+
450+
// Update buffer position
451+
if (echo_buffer_offset) {
452+
self->echo_buffer_right_pos = echo_buffer_pos;
436453
} else {
437-
if (self->echo_buffer_read_pos >= echo_buf_len) {
438-
self->echo_buffer_read_pos = 0;
439-
}
440-
if (self->echo_buffer_write_pos >= echo_buf_len) {
441-
self->echo_buffer_write_pos = 0;
442-
}
454+
self->echo_buffer_left_pos = echo_buffer_pos;
443455
}
444456
}
445457
}
@@ -451,14 +463,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
451463
self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8));
452464
self->sample_buffer_length -= n;
453465
}
454-
455-
if (self->freq_shift) {
456-
if (channel == 0) {
457-
self->echo_buffer_left_pos = echo_buffer_pos;
458-
} else if (channel == 1) {
459-
self->echo_buffer_right_pos = echo_buffer_pos;
460-
}
461-
}
462466
}
463467

464468
// Finally pass our buffer and length to the calling audio function

shared-module/audiodelays/Echo.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,9 @@ typedef struct {
3737
uint32_t echo_buffer_len; // bytes
3838
uint32_t max_echo_buffer_len; // bytes
3939

40-
uint32_t echo_buffer_read_pos; // words
41-
uint32_t echo_buffer_write_pos; // words
42-
40+
uint32_t echo_buffer_left_pos; // words (<< 8 when freq_shift=True)
41+
uint32_t echo_buffer_right_pos; // words (<< 8 when freq_shift=True)
4342
uint32_t echo_buffer_rate; // words << 8
44-
uint32_t echo_buffer_left_pos; // words << 8
45-
uint32_t echo_buffer_right_pos; // words << 8
4643

4744
mp_obj_t sample;
4845
} audiodelays_echo_obj_t;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy