Skip to content

Commit 01a220a

Browse files
committed
Started simplifying getbuffer
1 parent 4774807 commit 01a220a

File tree

1 file changed

+69
-60
lines changed
  • shared-module/audiodelays

1 file changed

+69
-60
lines changed

shared-module/audiodelays/Echo.c

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
4343
}
4444
synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix);
4545

46-
// calculate buffer size for the set delay
47-
mp_float_t f_delay_ms = synthio_block_slot_get(&self->delay_ms);
48-
self->echo_buffer_len = self->sample_rate / 1000.0f * f_delay_ms * (self->channel_count * (self->bits_per_sample / 8));
49-
5046
// Set the echo buffer for the max possible delay
5147
self->max_delay_ms = max_delay_ms;
5248
self->max_echo_buffer_len = self->sample_rate / 1000.0f * max_delay_ms * (self->channel_count * (self->bits_per_sample / 8));
@@ -57,9 +53,13 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
5753
}
5854
memset(self->echo_buffer, 0, self->max_echo_buffer_len);
5955

56+
// calculate current echo buffer size for the set delay
57+
mp_float_t f_delay_ms = synthio_block_slot_get(&self->delay_ms);
58+
self->echo_buffer_len = self->sample_rate / 1000.0f * f_delay_ms * (self->channel_count * (self->bits_per_sample / 8));
59+
6060
// read is where we store the incoming sample
6161
// write is what we send to the outgoing buffer
62-
self->echo_buffer_read_pos = self->buffer_len / sizeof(uint32_t);
62+
self->echo_buffer_read_pos = self->buffer_len / sizeof(uint16_t);
6363
self->echo_buffer_write_pos = 0;
6464

6565
self->sample = NULL;
@@ -168,7 +168,7 @@ void common_hal_audiodelays_echo_play(audiodelays_echo_obj_t *self, mp_obj_t sam
168168
audiosample_reset_buffer(self->sample, false, 0);
169169
audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length);
170170
// Track length in terms of words.
171-
self->sample_buffer_length /= sizeof(uint32_t);
171+
self->sample_buffer_length /= sizeof(uint16_t);
172172
self->more_data = result == GET_BUFFER_MORE_DATA;
173173

174174
return;
@@ -179,35 +179,48 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
179179
return;
180180
}
181181

182+
#define RANGE_LOW (-28000)
183+
#define RANGE_HIGH (28000)
184+
#define RANGE_SHIFT (16)
185+
#define RANGE_SCALE (0xfffffff / (32768 * 2 - RANGE_HIGH))
186+
187+
// dynamic range compression via a downward compressor with hard knee
188+
//
189+
// When the output value is within the range +-28000 (about 85% of full scale),
190+
// it is unchanged. Otherwise, it undergoes a gain reduction so that the
191+
// largest possible values, (+32768,-32767) * 2 (2 for echo and sample),
192+
// still fit within the output range
193+
//
194+
// This produces a much louder overall volume with multiple voices, without
195+
// much additional processing.
196+
//
197+
// https://en.wikipedia.org/wiki/Dynamic_range_compression
198+
static
199+
int16_t mix_down_sample(int32_t sample) {
200+
if (sample < RANGE_LOW) {
201+
sample = (((sample - RANGE_LOW) * RANGE_SCALE) >> RANGE_SHIFT) + RANGE_LOW;
202+
} else if (sample > RANGE_HIGH) {
203+
sample = (((sample - RANGE_HIGH) * RANGE_SCALE) >> RANGE_SHIFT) + RANGE_HIGH;
204+
}
205+
return sample;
206+
}
207+
182208
audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *self, bool single_channel_output, uint8_t channel,
183209
uint8_t **buffer, uint32_t *buffer_length) {
184210

185-
uint32_t *word_buffer = (uint32_t *)self->buffer;
186-
uint32_t length = self->buffer_len / sizeof(uint32_t);
187-
uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint32_t);
188-
mp_float_t f_mix = synthio_block_slot_get(&self->mix);
189-
if (f_mix > 1.0) {
190-
f_mix = 1.0;
191-
} else if (f_mix < 0.0) {
192-
f_mix = 0.0;
193-
}
194-
uint16_t mix = (uint16_t)(f_mix * (1 << 15));
211+
mp_float_t mix = MIN(1.0, MAX(synthio_block_slot_get(&self->mix), 0.0));
212+
mp_float_t decay = MIN(1.0, MAX(synthio_block_slot_get(&self->decay), 0.0));
195213

196-
mp_float_t f_decay = synthio_block_slot_get(&self->decay);
197-
if (f_decay > 1.0) {
198-
f_decay = 1.0;
199-
} else if (f_decay < 0.0) {
200-
f_decay = 0.0;
201-
}
202-
uint16_t decay = (uint16_t)(f_decay * (1 << 15));
214+
int16_t *word_buffer = (int16_t *)self->buffer;
215+
uint32_t length = self->buffer_len / sizeof(uint16_t);
216+
int16_t *echo_buffer = (int16_t *)self->echo_buffer;
217+
uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t);
203218

204219
while (length != 0) {
205220
if (self->sample_buffer_length == 0) {
206221
if (!self->more_data) {
207-
if (self->loop) {
208-
if (self->sample) {
209-
audiosample_reset_buffer(self->sample, false, 0);
210-
}
222+
if (self->loop && self->sample) {
223+
audiosample_reset_buffer(self->sample, false, 0);
211224
} else {
212225
self->sample = NULL;
213226
}
@@ -216,26 +229,24 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
216229
// Load another buffer
217230
audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length);
218231
// Track length in terms of words.
219-
self->sample_buffer_length /= sizeof(uint32_t);
232+
self->sample_buffer_length /= sizeof(uint16_t); // assuming 16 bit samples
220233
self->more_data = result == GET_BUFFER_MORE_DATA;
221234
}
222235
}
223236

224237
// If we have no sample keep the echo echoing
225238
if (self->sample == NULL) {
226239
if (MP_LIKELY(self->bits_per_sample == 16)) {
227-
if (mix == 0) { // no effect and no sample sound
228-
for (uint32_t i = 0; i < length; i++) {
229-
word_buffer[i] = 0;
230-
}
240+
if (mix <= 0.01) { // no sample sound and with no mix, no echo
241+
memset(word_buffer, 0, length * sizeof(uint16_t));
231242
} else {
232243
// sample signed/unsigned won't matter as we have no sample
233244
for (uint32_t i = 0; i < length; i++) {
234-
uint32_t echo = self->echo_buffer[self->echo_buffer_read_pos++];
235-
word_buffer[i] = mult16signed(echo, decay);
236-
self->echo_buffer[self->echo_buffer_write_pos++] = word_buffer[i];
245+
word_buffer[i] = echo_buffer[self->echo_buffer_read_pos++] * decay;
237246

238-
word_buffer[i] = mult16signed(word_buffer[i], mix);
247+
echo_buffer[self->echo_buffer_write_pos++] = word_buffer[i];
248+
249+
word_buffer[i] = word_buffer[i] * mix;
239250

240251
if (self->echo_buffer_read_pos >= echo_buf_len) {
241252
self->echo_buffer_read_pos = 0;
@@ -251,7 +262,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
251262
uint16_t *echo_hsrc = (uint16_t *)self->echo_buffer;
252263
for (uint32_t i = 0; i < length * 2; i++) {
253264
uint32_t echo_word = unpack8(echo_hsrc[i]);
254-
echo_word = mult16signed(echo_word, decay);
265+
echo_word = echo_word * decay;
255266
hword_buffer[i] = pack8(echo_word);
256267

257268
echo_hsrc[self->echo_buffer_write_pos++] = hword_buffer[i];
@@ -263,34 +274,37 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
263274
}
264275
}
265276
}
277+
266278
length = 0;
267279
} else { // we have a sample
268280
uint32_t n = MIN(self->sample_buffer_length, length);
269-
uint32_t *sample_src = self->sample_remaining_buffer;
281+
int16_t *sample_src = (int16_t *)self->sample_remaining_buffer;
270282

271283
if (MP_LIKELY(self->bits_per_sample == 16)) {
272-
if (mix == 0) { // sample only
284+
if (mix <= 0.01) { // sample only
273285
for (uint32_t i = 0; i < n; i++) {
274286
word_buffer[i] = sample_src[i];
275287
}
276288
} else {
277289
for (uint32_t i = 0; i < n; i++) {
278-
uint32_t sample_word = sample_src[i];
279-
if (MP_LIKELY(!self->samples_signed)) {
290+
int32_t sample_word = sample_src[i];
291+
if (!self->samples_signed) {
280292
sample_word = tosigned16(sample_word);
281293
}
282-
uint32_t echo = self->echo_buffer[self->echo_buffer_read_pos++];
283-
word_buffer[i] = add16signed(mult16signed(echo, decay), sample_word);
284-
self->echo_buffer[self->echo_buffer_write_pos++] = word_buffer[i];
285294

286-
word_buffer[i] = add16signed(mult16signed(sample_word, 32768 - mix), mult16signed(word_buffer[i], mix));
295+
int32_t word = (echo_buffer[self->echo_buffer_read_pos++] * decay) + sample_word;
296+
word_buffer[i] = mix_down_sample(word);
297+
298+
echo_buffer[self->echo_buffer_write_pos++] = word_buffer[i];
287299

288300
if (self->echo_buffer_read_pos >= echo_buf_len) {
289301
self->echo_buffer_read_pos = 0;
290302
}
291303
if (self->echo_buffer_write_pos >= echo_buf_len) {
292304
self->echo_buffer_write_pos = 0;
293305
}
306+
307+
word_buffer[i] = (sample_word * (1.0 - mix)) + (word_buffer[i] * mix);
294308
}
295309
}
296310
} else { // bits per sample is 8
@@ -303,11 +317,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
303317
if (MP_LIKELY(!self->samples_signed)) {
304318
sample_word = tosigned16(sample_word);
305319
}
306-
echo_word = mult16signed(echo_word, decay);
307-
sample_word = add16signed(sample_word, echo_word);
320+
echo_word = echo_word * decay;
321+
sample_word = sample_word + echo_word;
308322
hword_buffer[i] = pack8(sample_word);
309323

310-
echo_hsrc[self->echo_buffer_write_pos++] = pack8(add16signed(sample_word, unpack8(hword_buffer[i])));
324+
echo_hsrc[self->echo_buffer_write_pos++] = pack8(sample_word + unpack8(hword_buffer[i]));
311325
if (self->echo_buffer_read_pos >= echo_buf_len) {
312326
self->echo_buffer_read_pos = 0;
313327
}
@@ -323,6 +337,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
323337
self->sample_buffer_length -= n;
324338
}
325339
}
340+
326341
*buffer = (uint8_t *)self->buffer;
327342
*buffer_length = self->buffer_len;
328343
return GET_BUFFER_MORE_DATA;
@@ -331,18 +346,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
331346
void audiodelays_echo_get_buffer_structure(audiodelays_echo_obj_t *self, bool single_channel_output,
332347
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) {
333348

334-
if (self->sample != NULL) {
335-
audiosample_get_buffer_structure(self->sample, single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing);
336-
*single_buffer = false;
337-
*max_buffer_length = self->buffer_len;
349+
*single_buffer = true;
350+
*samples_signed = true;
351+
*max_buffer_length = self->buffer_len;
352+
if (single_channel_output) {
353+
*spacing = self->channel_count;
338354
} else {
339-
*single_buffer = true;
340-
*samples_signed = true;
341-
*max_buffer_length = self->buffer_len;
342-
if (single_channel_output) {
343-
*spacing = self->channel_count;
344-
} else {
345-
*spacing = 1;
346-
}
355+
*spacing = 1;
347356
}
348357
}

0 commit comments

Comments
 (0)