@@ -61,7 +61,7 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
61
61
synthio_block_assign_slot (decay , & self -> decay , MP_QSTR_decay );
62
62
63
63
if (delay_ms == MP_OBJ_NULL ) {
64
- delay_ms = mp_obj_new_float (0.05 );
64
+ delay_ms = mp_obj_new_float (500.0 );
65
65
}
66
66
synthio_block_assign_slot (delay_ms , & self -> delay_ms , MP_QSTR_delay_ms );
67
67
@@ -74,9 +74,9 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
74
74
// A maximum length buffer was created and then the current echo length can be dynamically changes
75
75
// without having to reallocate a large chunk of memory.
76
76
77
- // Allocate the echo buffer for the max possible delay
77
+ // Allocate the echo buffer for the max possible delay, echo is always 16-bit
78
78
self -> max_delay_ms = max_delay_ms ;
79
- self -> max_echo_buffer_len = self -> sample_rate / 1000.0f * max_delay_ms * (self -> channel_count * 2 ); // (self->bits_per_sample / 8 )); // bytes
79
+ self -> max_echo_buffer_len = self -> sample_rate / 1000.0f * max_delay_ms * (self -> channel_count * sizeof ( uint16_t )); // bytes
80
80
self -> echo_buffer = m_malloc (self -> max_echo_buffer_len );
81
81
if (self -> echo_buffer == NULL ) {
82
82
common_hal_audiodelays_echo_deinit (self );
@@ -86,11 +86,11 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
86
86
87
87
// calculate current echo buffer size we use for the given delay
88
88
mp_float_t f_delay_ms = synthio_block_slot_get (& self -> delay_ms );
89
- self -> echo_buffer_len = self -> sample_rate / 1000.0f * f_delay_ms * (self -> channel_count * 2 ); // (self->bits_per_sample / 8 ));
89
+ self -> echo_buffer_len = self -> sample_rate / 1000.0f * f_delay_ms * (self -> channel_count * sizeof ( uint16_t ));
90
90
91
91
// read is where we store the incoming sample + previous echo
92
92
// write is what we send to the outgoing buffer
93
- self -> echo_buffer_read_pos = self -> buffer_len / 2 ; // (self->bits_per_sample / 8 );
93
+ self -> echo_buffer_read_pos = self -> buffer_len / sizeof ( uint16_t );
94
94
self -> echo_buffer_write_pos = 0 ;
95
95
}
96
96
@@ -164,6 +164,9 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self,
164
164
bool single_channel_output ,
165
165
uint8_t channel ) {
166
166
167
+ memset (self -> buffer [0 ], 0 , self -> buffer_len );
168
+ memset (self -> buffer [1 ], 0 , self -> buffer_len );
169
+ memset (self -> echo_buffer , 0 , self -> max_echo_buffer_len );
167
170
}
168
171
169
172
bool common_hal_audiodelays_echo_get_playing (audiodelays_echo_obj_t * self ) {
@@ -201,6 +204,7 @@ void common_hal_audiodelays_echo_play(audiodelays_echo_obj_t *self, mp_obj_t sam
201
204
202
205
// Track remaining sample length in terms of bytes per sample
203
206
self -> sample_buffer_length /= (self -> bits_per_sample / 8 );
207
+ // Store if we have more data in the sample to retrieve
204
208
self -> more_data = result == GET_BUFFER_MORE_DATA ;
205
209
206
210
return ;
@@ -213,10 +217,10 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
213
217
return ;
214
218
}
215
219
216
- #define RANGE_LOW (-28000)
217
- #define RANGE_HIGH (28000)
218
- #define RANGE_SHIFT (16)
219
- #define RANGE_SCALE (0xfffffff / (32768 * 4 - RANGE_HIGH))
220
+ #define RANGE_LOW_16 (-28000)
221
+ #define RANGE_HIGH_16 (28000)
222
+ #define RANGE_SHIFT_16 (16)
223
+ #define RANGE_SCALE_16 (0xfffffff / (32768 * 2 - RANGE_HIGH_16)) // 2 for echo+sample
220
224
221
225
// dynamic range compression via a downward compressor with hard knee
222
226
//
@@ -231,10 +235,10 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
231
235
// https://en.wikipedia.org/wiki/Dynamic_range_compression
232
236
static
233
237
int16_t mix_down_sample (int32_t sample ) {
234
- if (sample < RANGE_LOW ) {
235
- sample = (((sample - RANGE_LOW ) * RANGE_SCALE ) >> RANGE_SHIFT ) + RANGE_LOW ;
236
- } else if (sample > RANGE_HIGH ) {
237
- sample = (((sample - RANGE_HIGH ) * RANGE_SCALE ) >> RANGE_SHIFT ) + RANGE_HIGH ;
238
+ if (sample < RANGE_LOW_16 ) {
239
+ sample = (((sample - RANGE_LOW_16 ) * RANGE_SCALE_16 ) >> RANGE_SHIFT_16 ) + RANGE_LOW_16 ;
240
+ } else if (sample > RANGE_HIGH_16 ) {
241
+ sample = (((sample - RANGE_HIGH_16 ) * RANGE_SCALE_16 ) >> RANGE_SHIFT_16 ) + RANGE_HIGH_16 ;
238
242
}
239
243
return sample ;
240
244
}
@@ -249,20 +253,18 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
249
253
// Switch our buffers to the other buffer
250
254
self -> last_buf_idx = !self -> last_buf_idx ;
251
255
252
- // If we are using 16 bit samples we need a 16 bit pointer
256
+ // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer
253
257
int16_t * word_buffer = (int16_t * )self -> buffer [self -> last_buf_idx ];
254
258
int8_t * hword_buffer = self -> buffer [self -> last_buf_idx ];
255
259
uint32_t length = self -> buffer_len / (self -> bits_per_sample / 8 );
256
260
257
261
// The echo buffer is always stored as a 16-bit value internally
258
262
int16_t * echo_buffer = (int16_t * )self -> echo_buffer ;
259
- uint32_t echo_buf_len = self -> echo_buffer_len / 2 ;// (self->bits_per_sample / 8);
260
-
263
+ uint32_t echo_buf_len = self -> echo_buffer_len / sizeof (uint16_t );
261
264
262
265
// Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample
263
266
while (length != 0 ) {
264
-
265
- // Check if there is no more sample to play
267
+ // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample
266
268
if (self -> sample_buffer_length == 0 ) {
267
269
if (!self -> more_data ) { // The sample has indicated it has no more data to play
268
270
if (self -> loop && self -> sample ) { // If we are supposed to loop reset the sample to the start
@@ -286,10 +288,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
286
288
if (self -> samples_signed ) {
287
289
memset (word_buffer , 0 , length * (self -> bits_per_sample / 8 ));
288
290
} else {
289
- memset (hword_buffer , 128 , length * (self -> bits_per_sample / 8 ));
291
+ // For unsigned samples set to the middle which is "quiet"
292
+ if (MP_LIKELY (self -> bits_per_sample == 16 )) {
293
+ memset (word_buffer , 32768 , length * (self -> bits_per_sample / 8 ));
294
+ } else {
295
+ memset (hword_buffer , 128 , length * (self -> bits_per_sample / 8 ));
296
+ }
290
297
}
291
298
} else {
292
- // Since we have no sample we can just iterate over the our entire remaining buffer
299
+ // Since we have no sample we can just iterate over the our entire remaining buffer and finish
293
300
for (uint32_t i = 0 ; i < length ; i ++ ) {
294
301
int16_t echo = echo_buffer [self -> echo_buffer_read_pos ++ ] * decay ;
295
302
echo_buffer [self -> echo_buffer_write_pos ++ ] = echo ;
@@ -319,12 +326,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
319
326
length = 0 ;
320
327
} else {
321
328
// we have a sample to play and echo
322
-
323
329
// Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining
324
330
uint32_t n = MIN (self -> sample_buffer_length , length );
325
331
326
- int16_t * sample_src = (int16_t * )self -> sample_remaining_buffer ;
327
- int8_t * sample_hsrc = (int8_t * )self -> sample_remaining_buffer ;
332
+ int16_t * sample_src = (int16_t * )self -> sample_remaining_buffer ; // for 16-bit samples
333
+ int8_t * sample_hsrc = (int8_t * )self -> sample_remaining_buffer ; // for 8-bit samples
328
334
329
335
if (mix <= 0.01 ) { // if mix is zero pure sample only
330
336
for (uint32_t i = 0 ; i < n ; i ++ ) {
@@ -343,20 +349,19 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
343
349
if (self -> samples_signed ) {
344
350
sample_word = sample_hsrc [i ];
345
351
} else {
346
- // uint8_t s1 = sample_hsrc[i];
347
- // int8_t s2 = s1^0x80;
348
- // sample_word = s2;
349
-
352
+ // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed
350
353
sample_word = (int8_t )(((uint8_t )sample_hsrc [i ]) ^ 0x80 );
351
354
}
352
355
}
353
356
354
357
int32_t echo = echo_buffer [self -> echo_buffer_read_pos ++ ] * decay ;
355
358
int32_t word = echo + sample_word ;
359
+
356
360
if (MP_LIKELY (self -> bits_per_sample == 16 )) {
357
361
word = mix_down_sample (word );
358
362
echo_buffer [self -> echo_buffer_write_pos ++ ] = (int16_t )word ;
359
363
} else {
364
+ // Do not have mix_down for 8 bit so just hard cap samples into 1 byte
360
365
if (word > 127 ) {
361
366
word = 127 ;
362
367
} else if (word < -128 ) {
@@ -372,7 +377,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
372
377
}
373
378
} else {
374
379
int8_t mixed = (sample_word * (1.0 - mix )) + (word * mix );
375
- ;
376
380
if (self -> samples_signed ) {
377
381
hword_buffer [i ] = mixed ;
378
382
} else {
@@ -389,6 +393,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
389
393
}
390
394
}
391
395
396
+ // Update the remaining length and the buffer positions based on how much we wrote into our buffer
392
397
length -= n ;
393
398
word_buffer += n ;
394
399
hword_buffer += n ;
@@ -397,14 +402,19 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
397
402
}
398
403
}
399
404
405
+ // Finally pass our buffer and length to the calling audio function
400
406
* buffer = (uint8_t * )self -> buffer [self -> last_buf_idx ];
401
407
* buffer_length = self -> buffer_len ;
408
+
409
+ // Echo always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h)
402
410
return GET_BUFFER_MORE_DATA ;
403
411
}
404
412
405
413
void audiodelays_echo_get_buffer_structure (audiodelays_echo_obj_t * self , bool single_channel_output ,
406
414
bool * single_buffer , bool * samples_signed , uint32_t * max_buffer_length , uint8_t * spacing ) {
407
415
416
+ // Return information about the effect's buffer (not the sample's)
417
+ // These are used by calling audio objects to determine how to handle the effect's buffer
408
418
* single_buffer = false;
409
419
* samples_signed = self -> samples_signed ;
410
420
* max_buffer_length = self -> buffer_len ;
0 commit comments