Skip to content

Commit 7d8e41f

Browse files
authored
Merge pull request #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)