@@ -61,7 +61,7 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
6161 synthio_block_assign_slot (decay , & self -> decay , MP_QSTR_decay );
6262
6363 if (delay_ms == MP_OBJ_NULL ) {
64- delay_ms = mp_obj_new_float (0.05 );
64+ delay_ms = mp_obj_new_float (500.0 );
6565 }
6666 synthio_block_assign_slot (delay_ms , & self -> delay_ms , MP_QSTR_delay_ms );
6767
@@ -74,9 +74,9 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
7474 // A maximum length buffer was created and then the current echo length can be dynamically changes
7575 // without having to reallocate a large chunk of memory.
7676
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
7878 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
8080 self -> echo_buffer = m_malloc (self -> max_echo_buffer_len );
8181 if (self -> echo_buffer == NULL ) {
8282 common_hal_audiodelays_echo_deinit (self );
@@ -86,11 +86,11 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
8686
8787 // calculate current echo buffer size we use for the given delay
8888 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 ));
9090
9191 // read is where we store the incoming sample + previous echo
9292 // 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 );
9494 self -> echo_buffer_write_pos = 0 ;
9595}
9696
@@ -164,6 +164,9 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self,
164164 bool single_channel_output ,
165165 uint8_t channel ) {
166166
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 );
167170}
168171
169172bool 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
201204
202205 // Track remaining sample length in terms of bytes per sample
203206 self -> sample_buffer_length /= (self -> bits_per_sample / 8 );
207+ // Store if we have more data in the sample to retrieve
204208 self -> more_data = result == GET_BUFFER_MORE_DATA ;
205209
206210 return ;
@@ -213,10 +217,10 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
213217 return ;
214218}
215219
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
220224
221225// dynamic range compression via a downward compressor with hard knee
222226//
@@ -231,10 +235,10 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
231235// https://en.wikipedia.org/wiki/Dynamic_range_compression
232236static
233237int16_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 ;
238242 }
239243 return sample ;
240244}
@@ -249,20 +253,18 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
249253 // Switch our buffers to the other buffer
250254 self -> last_buf_idx = !self -> last_buf_idx ;
251255
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
253257 int16_t * word_buffer = (int16_t * )self -> buffer [self -> last_buf_idx ];
254258 int8_t * hword_buffer = self -> buffer [self -> last_buf_idx ];
255259 uint32_t length = self -> buffer_len / (self -> bits_per_sample / 8 );
256260
257261 // The echo buffer is always stored as a 16-bit value internally
258262 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 );
261264
262265 // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample
263266 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
266268 if (self -> sample_buffer_length == 0 ) {
267269 if (!self -> more_data ) { // The sample has indicated it has no more data to play
268270 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 *
286288 if (self -> samples_signed ) {
287289 memset (word_buffer , 0 , length * (self -> bits_per_sample / 8 ));
288290 } 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+ }
290297 }
291298 } 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
293300 for (uint32_t i = 0 ; i < length ; i ++ ) {
294301 int16_t echo = echo_buffer [self -> echo_buffer_read_pos ++ ] * decay ;
295302 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 *
319326 length = 0 ;
320327 } else {
321328 // we have a sample to play and echo
322-
323329 // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining
324330 uint32_t n = MIN (self -> sample_buffer_length , length );
325331
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
328334
329335 if (mix <= 0.01 ) { // if mix is zero pure sample only
330336 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 *
343349 if (self -> samples_signed ) {
344350 sample_word = sample_hsrc [i ];
345351 } 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
350353 sample_word = (int8_t )(((uint8_t )sample_hsrc [i ]) ^ 0x80 );
351354 }
352355 }
353356
354357 int32_t echo = echo_buffer [self -> echo_buffer_read_pos ++ ] * decay ;
355358 int32_t word = echo + sample_word ;
359+
356360 if (MP_LIKELY (self -> bits_per_sample == 16 )) {
357361 word = mix_down_sample (word );
358362 echo_buffer [self -> echo_buffer_write_pos ++ ] = (int16_t )word ;
359363 } else {
364+ // Do not have mix_down for 8 bit so just hard cap samples into 1 byte
360365 if (word > 127 ) {
361366 word = 127 ;
362367 } else if (word < -128 ) {
@@ -372,7 +377,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
372377 }
373378 } else {
374379 int8_t mixed = (sample_word * (1.0 - mix )) + (word * mix );
375- ;
376380 if (self -> samples_signed ) {
377381 hword_buffer [i ] = mixed ;
378382 } else {
@@ -389,6 +393,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
389393 }
390394 }
391395
396+ // Update the remaining length and the buffer positions based on how much we wrote into our buffer
392397 length -= n ;
393398 word_buffer += n ;
394399 hword_buffer += n ;
@@ -397,14 +402,19 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
397402 }
398403 }
399404
405+ // Finally pass our buffer and length to the calling audio function
400406 * buffer = (uint8_t * )self -> buffer [self -> last_buf_idx ];
401407 * 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)
402410 return GET_BUFFER_MORE_DATA ;
403411}
404412
405413void audiodelays_echo_get_buffer_structure (audiodelays_echo_obj_t * self , bool single_channel_output ,
406414 bool * single_buffer , bool * samples_signed , uint32_t * max_buffer_length , uint8_t * spacing ) {
407415
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
408418 * single_buffer = false;
409419 * samples_signed = self -> samples_signed ;
410420 * max_buffer_length = self -> buffer_len ;
0 commit comments