7
7
8
8
#include <stdint.h>
9
9
#include "py/runtime.h"
10
+ #include <math.h>
10
11
11
12
void common_hal_audiodelays_echo_construct (audiodelays_echo_obj_t * self , uint32_t max_delay_ms ,
12
13
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_
57
58
58
59
// If we did not receive a BlockInput we need to create a default float value
59
60
if (decay == MP_OBJ_NULL ) {
60
- decay = mp_obj_new_float (0.7 );
61
+ decay = mp_obj_new_float (MICROPY_FLOAT_CONST ( 0.7 ) );
61
62
}
62
63
synthio_block_assign_slot (decay , & self -> decay , MP_QSTR_decay );
63
64
64
65
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 ) );
66
67
}
67
68
synthio_block_assign_slot (delay_ms , & self -> delay_ms , MP_QSTR_delay_ms );
68
69
69
70
if (mix == MP_OBJ_NULL ) {
70
- mix = mp_obj_new_float (0.5 );
71
+ mix = mp_obj_new_float (MICROPY_FLOAT_CONST ( 0.5 ) );
71
72
}
72
73
synthio_block_assign_slot (mix , & self -> mix , MP_QSTR_mix );
73
74
@@ -77,14 +78,17 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_
77
78
78
79
// Allocate the echo buffer for the max possible delay, echo is always 16-bit
79
80
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
81
82
self -> echo_buffer = m_malloc (self -> max_echo_buffer_len );
82
83
if (self -> echo_buffer == NULL ) {
83
84
common_hal_audiodelays_echo_deinit (self );
84
85
m_malloc_fail (self -> max_echo_buffer_len );
85
86
}
86
87
memset (self -> echo_buffer , 0 , self -> max_echo_buffer_len );
87
88
89
+ // calculate the length of a single sample in milliseconds
90
+ self -> sample_ms = MICROPY_FLOAT_CONST (1000.0 ) / self -> sample_rate ;
91
+
88
92
// calculate everything needed for the current delay
89
93
mp_float_t f_delay_ms = synthio_block_slot_get (& self -> delay_ms );
90
94
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
127
131
}
128
132
129
133
void 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
+
130
137
if (self -> freq_shift ) {
131
138
// Calculate the rate of iteration over the echo buffer with 8 sub-bits
132
139
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) {
153
160
memset (self -> echo_buffer + self -> echo_buffer_len , 0 , self -> max_echo_buffer_len - self -> echo_buffer_len );
154
161
}
155
162
156
- self -> current_delay_ms = ( uint32_t ) f_delay_ms ;
163
+ self -> current_delay_ms = f_delay_ms ;
157
164
}
158
165
159
166
mp_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) {
251
258
return ;
252
259
}
253
260
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
-
280
261
audioio_get_buffer_result_t audiodelays_echo_get_buffer (audiodelays_echo_obj_t * self , bool single_channel_output , uint8_t channel ,
281
262
uint8_t * * buffer , uint32_t * buffer_length ) {
282
263
283
264
if (!single_channel_output ) {
284
265
channel = 0 ;
285
266
}
286
267
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
-
296
268
// Switch our buffers to the other buffer
297
269
self -> last_buf_idx = !self -> last_buf_idx ;
298
270
@@ -303,16 +275,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
303
275
304
276
// The echo buffer is always stored as a 16-bit value internally
305
277
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
- }
316
278
317
279
// Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample
318
280
while (length != 0 ) {
@@ -334,9 +296,38 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
334
296
}
335
297
}
336
298
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
+
337
328
// If we have no sample keep the echo echoing
338
329
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
340
331
if (self -> samples_signed ) {
341
332
memset (word_buffer , 0 , length * (self -> bits_per_sample / 8 ));
342
333
} else {
@@ -400,13 +391,10 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
400
391
length = 0 ;
401
392
} else {
402
393
// 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
-
406
394
int16_t * sample_src = (int16_t * )self -> sample_remaining_buffer ; // for 16-bit samples
407
395
int8_t * sample_hsrc = (int8_t * )self -> sample_remaining_buffer ; // for 8-bit samples
408
396
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
410
398
for (uint32_t i = 0 ; i < n ; i ++ ) {
411
399
if (MP_LIKELY (self -> bits_per_sample == 16 )) {
412
400
word_buffer [i ] = sample_src [i ];
@@ -440,7 +428,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
440
428
}
441
429
442
430
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 ) );
444
432
if (self -> freq_shift ) {
445
433
for (uint32_t j = echo_buffer_pos >> 8 ; j < next_buffer_pos >> 8 ; j ++ ) {
446
434
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 *
465
453
}
466
454
467
455
word = echo + sample_word ;
456
+ word = synthio_mix_down_sample (word , SYNTHIO_MIX_DOWN_SCALE (2 ));
468
457
469
458
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 ));
471
460
if (!self -> samples_signed ) {
472
461
word_buffer [i ] ^= 0x8000 ;
473
462
}
474
463
} 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 ));
476
465
if (self -> samples_signed ) {
477
466
hword_buffer [i ] = mixed ;
478
467
} else {
@@ -500,13 +489,13 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *
500
489
self -> sample_remaining_buffer += (n * (self -> bits_per_sample / 8 ));
501
490
self -> sample_buffer_length -= n ;
502
491
}
503
- }
504
492
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
+ }
510
499
}
511
500
}
512
501
0 commit comments