77
88#include <stdint.h>
99#include "py/runtime.h"
10+ #include <math.h>
1011
1112void common_hal_audiodelays_echo_construct (audiodelays_echo_obj_t * self , uint32_t max_delay_ms ,
1213 mp_obj_t delay_ms , mp_obj_t decay , mp_obj_t mix ,
@@ -57,17 +58,17 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
5758
5859 // If we did not receive a BlockInput we need to create a default float value
5960 if (decay == MP_OBJ_NULL ) {
60- decay = mp_obj_new_float (0.7 );
61+ decay = mp_obj_new_float (MICROPY_FLOAT_CONST ( 0.7 ) );
6162 }
6263 synthio_block_assign_slot (decay , & self -> decay , MP_QSTR_decay );
6364
6465 if (delay_ms == MP_OBJ_NULL ) {
65- delay_ms = mp_obj_new_float (250.0 );
66+ delay_ms = mp_obj_new_float (MICROPY_FLOAT_CONST ( 250.0 ) );
6667 }
6768 synthio_block_assign_slot (delay_ms , & self -> delay_ms , MP_QSTR_delay_ms );
6869
6970 if (mix == MP_OBJ_NULL ) {
70- mix = mp_obj_new_float (0.5 );
71+ mix = mp_obj_new_float (MICROPY_FLOAT_CONST ( 0.5 ) );
7172 }
7273 synthio_block_assign_slot (mix , & self -> mix , MP_QSTR_mix );
7374
@@ -77,14 +78,17 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
7778
7879 // Allocate the echo buffer for the max possible delay, echo is always 16-bit
7980 self -> max_delay_ms = max_delay_ms ;
80- self -> max_echo_buffer_len = (uint32_t )(self -> sample_rate / 1000.0f * max_delay_ms ) * (self -> channel_count * sizeof (uint16_t )); // bytes
81+ self -> max_echo_buffer_len = (uint32_t )(self -> sample_rate / MICROPY_FLOAT_CONST ( 1000.0 ) * max_delay_ms ) * (self -> channel_count * sizeof (uint16_t )); // bytes
8182 self -> echo_buffer = m_malloc (self -> max_echo_buffer_len );
8283 if (self -> echo_buffer == NULL ) {
8384 common_hal_audiodelays_echo_deinit (self );
8485 m_malloc_fail (self -> max_echo_buffer_len );
8586 }
8687 memset (self -> echo_buffer , 0 , self -> max_echo_buffer_len );
8788
89+ // calculate the length of a single sample in milliseconds
90+ self -> sample_ms = MICROPY_FLOAT_CONST (1000.0 ) / self -> sample_rate ;
91+
8892 // calculate everything needed for the current delay
8993 mp_float_t f_delay_ms = synthio_block_slot_get (& self -> delay_ms );
9094 recalculate_delay (self , f_delay_ms );
@@ -127,6 +131,9 @@ void common_hal_audiodelays_echo_set_delay_ms(audiodelays_echo_obj_t *self, mp_o
127131}
128132
129133void recalculate_delay (audiodelays_echo_obj_t * self , mp_float_t f_delay_ms ) {
134+ // Require that delay is at least 1 sample long
135+ f_delay_ms = MAX (f_delay_ms , self -> sample_ms );
136+
130137 if (self -> freq_shift ) {
131138 // Calculate the rate of iteration over the echo buffer with 8 sub-bits
132139 self -> echo_buffer_rate = (uint32_t )MAX (self -> max_delay_ms / f_delay_ms * MICROPY_FLOAT_CONST (256.0 ), MICROPY_FLOAT_CONST (1.0 ));
@@ -153,7 +160,7 @@ void recalculate_delay(audiodelays_echo_obj_t *self, mp_float_t f_delay_ms) {
153160 memset (self -> echo_buffer + self -> echo_buffer_len , 0 , self -> max_echo_buffer_len - self -> echo_buffer_len );
154161 }
155162
156- self -> current_delay_ms = ( uint32_t ) f_delay_ms ;
163+ self -> current_delay_ms = f_delay_ms ;
157164}
158165
159166mp_obj_t common_hal_audiodelays_echo_get_decay (audiodelays_echo_obj_t * self ) {
@@ -251,48 +258,13 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) {
251258 return ;
252259}
253260
254- #define RANGE_LOW_16 (-28000)
255- #define RANGE_HIGH_16 (28000)
256- #define RANGE_SHIFT_16 (16)
257- #define RANGE_SCALE_16 (0xfffffff / (32768 * 2 - RANGE_HIGH_16)) // 2 for echo+sample
258-
259- // dynamic range compression via a downward compressor with hard knee
260- //
261- // When the output value is within the range +-28000 (about 85% of full scale),
262- // it is unchanged. Otherwise, it undergoes a gain reduction so that the
263- // largest possible values, (+32768,-32767) * 2 (2 for echo and sample),
264- // still fit within the output range
265- //
266- // This produces a much louder overall volume with multiple voices, without
267- // much additional processing.
268- //
269- // https://en.wikipedia.org/wiki/Dynamic_range_compression
270- static
271- int16_t mix_down_sample (int32_t sample ) {
272- if (sample < RANGE_LOW_16 ) {
273- sample = (((sample - RANGE_LOW_16 ) * RANGE_SCALE_16 ) >> RANGE_SHIFT_16 ) + RANGE_LOW_16 ;
274- } else if (sample > RANGE_HIGH_16 ) {
275- sample = (((sample - RANGE_HIGH_16 ) * RANGE_SCALE_16 ) >> RANGE_SHIFT_16 ) + RANGE_HIGH_16 ;
276- }
277- return sample ;
278- }
279-
280261audioio_get_buffer_result_t audiodelays_echo_get_buffer (audiodelays_echo_obj_t * self , bool single_channel_output , uint8_t channel ,
281262 uint8_t * * buffer , uint32_t * buffer_length ) {
282263
283264 if (!single_channel_output ) {
284265 channel = 0 ;
285266 }
286267
287- // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required
288- mp_float_t mix = MIN (1.0 , MAX (synthio_block_slot_get (& self -> mix ), 0.0 ));
289- mp_float_t decay = MIN (1.0 , MAX (synthio_block_slot_get (& self -> decay ), 0.0 ));
290-
291- uint32_t delay_ms = (uint32_t )synthio_block_slot_get (& self -> delay_ms );
292- if (self -> current_delay_ms != delay_ms ) {
293- recalculate_delay (self , delay_ms );
294- }
295-
296268 // Switch our buffers to the other buffer
297269 self -> last_buf_idx = !self -> last_buf_idx ;
298270
@@ -303,16 +275,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
303275
304276 // The echo buffer is always stored as a 16-bit value internally
305277 int16_t * echo_buffer = (int16_t * )self -> echo_buffer ;
306- uint32_t echo_buf_len = self -> echo_buffer_len / sizeof (uint16_t );
307-
308- // Set our echo buffer position accounting for stereo
309- uint32_t echo_buffer_pos = 0 ;
310- if (self -> freq_shift ) {
311- echo_buffer_pos = self -> echo_buffer_left_pos ;
312- if (channel == 1 ) {
313- echo_buffer_pos = self -> echo_buffer_right_pos ;
314- }
315- }
316278
317279 // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample
318280 while (length != 0 ) {
@@ -334,9 +296,38 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
334296 }
335297 }
336298
299+ // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining
300+ uint32_t n ;
301+ if (self -> sample == NULL ) {
302+ n = MIN (length , SYNTHIO_MAX_DUR * self -> channel_count );
303+ } else {
304+ n = MIN (MIN (self -> sample_buffer_length , length ), SYNTHIO_MAX_DUR * self -> channel_count );
305+ }
306+
307+ // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required
308+ shared_bindings_synthio_lfo_tick (self -> sample_rate , n / self -> channel_count );
309+ mp_float_t mix = synthio_block_slot_get_limited (& self -> mix , MICROPY_FLOAT_CONST (0.0 ), MICROPY_FLOAT_CONST (1.0 ));
310+ mp_float_t decay = synthio_block_slot_get_limited (& self -> decay , MICROPY_FLOAT_CONST (0.0 ), MICROPY_FLOAT_CONST (1.0 ));
311+
312+ mp_float_t f_delay_ms = synthio_block_slot_get (& self -> delay_ms );
313+ if (MICROPY_FLOAT_C_FUN (fabs )(self -> current_delay_ms - f_delay_ms ) >= self -> sample_ms ) {
314+ recalculate_delay (self , f_delay_ms );
315+ }
316+
317+ uint32_t echo_buf_len = self -> echo_buffer_len / sizeof (uint16_t );
318+
319+ // Set our echo buffer position accounting for stereo
320+ uint32_t echo_buffer_pos = 0 ;
321+ if (self -> freq_shift ) {
322+ echo_buffer_pos = self -> echo_buffer_left_pos ;
323+ if (channel == 1 ) {
324+ echo_buffer_pos = self -> echo_buffer_right_pos ;
325+ }
326+ }
327+
337328 // If we have no sample keep the echo echoing
338329 if (self -> sample == NULL ) {
339- if (mix <= 0.01 ) { // Mix of 0 is pure sample sound. We have no sample so no sound
330+ if (mix <= MICROPY_FLOAT_CONST ( 0.01 ) ) { // Mix of 0 is pure sample sound. We have no sample so no sound
340331 if (self -> samples_signed ) {
341332 memset (word_buffer , 0 , length * (self -> bits_per_sample / 8 ));
342333 } else {
@@ -400,13 +391,10 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
400391 length = 0 ;
401392 } else {
402393 // we have a sample to play and echo
403- // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining
404- uint32_t n = MIN (self -> sample_buffer_length , length );
405-
406394 int16_t * sample_src = (int16_t * )self -> sample_remaining_buffer ; // for 16-bit samples
407395 int8_t * sample_hsrc = (int8_t * )self -> sample_remaining_buffer ; // for 8-bit samples
408396
409- if (mix <= 0.01 ) { // if mix is zero pure sample only
397+ if (mix <= MICROPY_FLOAT_CONST ( 0.01 ) ) { // if mix is zero pure sample only
410398 for (uint32_t i = 0 ; i < n ; i ++ ) {
411399 if (MP_LIKELY (self -> bits_per_sample == 16 )) {
412400 word_buffer [i ] = sample_src [i ];
@@ -440,7 +428,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
440428 }
441429
442430 if (MP_LIKELY (self -> bits_per_sample == 16 )) {
443- word = mix_down_sample (word );
431+ word = synthio_mix_down_sample (word , SYNTHIO_MIX_DOWN_SCALE ( 2 ) );
444432 if (self -> freq_shift ) {
445433 for (uint32_t j = echo_buffer_pos >> 8 ; j < next_buffer_pos >> 8 ; j ++ ) {
446434 echo_buffer [j % echo_buf_len ] = (int16_t )word ;
@@ -465,14 +453,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
465453 }
466454
467455 word = echo + sample_word ;
456+ word = synthio_mix_down_sample (word , SYNTHIO_MIX_DOWN_SCALE (2 ));
468457
469458 if (MP_LIKELY (self -> bits_per_sample == 16 )) {
470- word_buffer [i ] = (int16_t )((sample_word * (1.0 - mix )) + (word * mix ));
459+ word_buffer [i ] = (int16_t )((sample_word * (MICROPY_FLOAT_CONST ( 1.0 ) - mix )) + (word * mix ));
471460 if (!self -> samples_signed ) {
472461 word_buffer [i ] ^= 0x8000 ;
473462 }
474463 } else {
475- int8_t mixed = (int16_t )((sample_word * (1.0 - mix )) + (word * mix ));
464+ int8_t mixed = (int16_t )((sample_word * (MICROPY_FLOAT_CONST ( 1.0 ) - mix )) + (word * mix ));
476465 if (self -> samples_signed ) {
477466 hword_buffer [i ] = mixed ;
478467 } else {
@@ -500,13 +489,13 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
500489 self -> sample_remaining_buffer += (n * (self -> bits_per_sample / 8 ));
501490 self -> sample_buffer_length -= n ;
502491 }
503- }
504492
505- if (self -> freq_shift ) {
506- if (channel == 0 ) {
507- self -> echo_buffer_left_pos = echo_buffer_pos ;
508- } else if (channel == 1 ) {
509- self -> echo_buffer_right_pos = echo_buffer_pos ;
493+ if (self -> freq_shift ) {
494+ if (channel == 0 ) {
495+ self -> echo_buffer_left_pos = echo_buffer_pos ;
496+ } else if (channel == 1 ) {
497+ self -> echo_buffer_right_pos = echo_buffer_pos ;
498+ }
510499 }
511500 }
512501
0 commit comments