-
Notifications
You must be signed in to change notification settings - Fork 1.4k
audio: apply mix and decay in fixed point, not floating point #11415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -298,6 +298,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * | |||||
| mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(2.0); | ||||||
| mp_float_t decay = synthio_block_slot_get_limited(&self->decay, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); | ||||||
|
|
||||||
| int32_t decay_scaled = (int32_t)(decay * MICROPY_FLOAT_CONST(32768.0)); | ||||||
| int32_t echo_scaled = (int32_t)(MIN(mix, MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(32768.0)); | ||||||
| int32_t sample_scaled = (int32_t)(MIN(MICROPY_FLOAT_CONST(2.0) - mix, | ||||||
| MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(32768.0)); | ||||||
|
|
||||||
| mp_float_t f_delay_ms = synthio_block_slot_get(&self->delay_ms); | ||||||
| if (MICROPY_FLOAT_C_FUN(fabs)(self->current_delay_ms - f_delay_ms) >= self->sample_ms) { | ||||||
| recalculate_delay(self, f_delay_ms); | ||||||
|
|
@@ -340,16 +345,16 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * | |||||
| next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate; | ||||||
|
|
||||||
| for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { | ||||||
| word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); | ||||||
| word = (int16_t)((echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay_scaled) >> 15); | ||||||
| echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); | ||||||
| } | ||||||
| } else { | ||||||
| echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; | ||||||
| word = (int16_t)(echo * decay); | ||||||
| word = (int16_t)((echo * decay_scaled) >> 15); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); | ||||||
| } | ||||||
|
|
||||||
| word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); | ||||||
| word = (int16_t)((echo * echo_scaled) >> 15); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
| word_buffer[i] = word; | ||||||
|
|
@@ -418,13 +423,13 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * | |||||
| next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate; | ||||||
| } else { | ||||||
| echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; | ||||||
| word = (int32_t)(echo * decay + sample_word); | ||||||
| word = ((echo * decay_scaled) >> 15) + sample_word; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
| if (self->freq_shift) { | ||||||
| for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { | ||||||
| word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); | ||||||
| word = ((echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay_scaled) >> 15) + sample_word; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
| echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); | ||||||
| } | ||||||
|
|
@@ -435,7 +440,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * | |||||
| } else { | ||||||
| if (self->freq_shift) { | ||||||
| for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { | ||||||
| word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); | ||||||
| word = ((echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay_scaled) >> 15) + sample_word; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| // Do not have mix_down for 8 bit so just hard cap samples into 1 byte | ||||||
| word = MIN(MAX(word, -128), 127); | ||||||
| echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); | ||||||
|
|
@@ -447,8 +452,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| word = (int32_t)((sample_word * MIN(MICROPY_FLOAT_CONST(2.0) - mix, MICROPY_FLOAT_CONST(1.0))) | ||||||
| + (echo * MIN(mix, MICROPY_FLOAT_CONST(1.0)))); | ||||||
| word = ((sample_word * sample_scaled) >> 15) + ((echo * echo_scaled) >> 15); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This version shifts and truncates each separately before adding. It could instead sum first and then shift to stay more precise.
Suggested change
This is the helper function that could be added to synthio/init.h so it can be used here and a few other places. |
||||||
| word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
|
|
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -374,6 +374,11 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m | |||||
| mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(2.0); | ||||||
| mp_float_t decay = synthio_block_slot_get_limited(&self->decay, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); | ||||||
|
|
||||||
| int32_t decay_scaled = (int32_t)(decay * MICROPY_FLOAT_CONST(32768.0)); | ||||||
| int32_t tap_scaled = (int32_t)(MIN(mix, MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(32768.0)); | ||||||
| int32_t sample_scaled = (int32_t)(MIN(MICROPY_FLOAT_CONST(2.0) - mix, | ||||||
| MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(32768.0)); | ||||||
|
|
||||||
| int16_t *sample_src = NULL; | ||||||
| int8_t *sample_hsrc = NULL; | ||||||
| if (self->sample != NULL) { | ||||||
|
|
@@ -424,7 +429,7 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m | |||||
| } | ||||||
|
|
||||||
| // Apply decay and add sample | ||||||
| delay_word = (int32_t)(delay_word * decay) + sample_word; | ||||||
| delay_word = ((delay_word * decay_scaled) >> 15) + sample_word; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should use
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
| delay_word = synthio_mix_down_sample(delay_word, SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
|
|
@@ -436,8 +441,7 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m | |||||
| } | ||||||
|
|
||||||
| // Mix sample with tap output | ||||||
| word = (int32_t)((sample_word * MIN(MICROPY_FLOAT_CONST(2.0) - mix, MICROPY_FLOAT_CONST(1.0))) | ||||||
| + (word * MIN(mix, MICROPY_FLOAT_CONST(1.0)))); | ||||||
| word = ((sample_word * sample_scaled) >> 15) + ((word * tap_scaled) >> 15); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
|
|
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -195,6 +195,9 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o | |||||
| shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); | ||||||
| mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); | ||||||
|
|
||||||
| int32_t wet_scaled = (int32_t)(mix * MICROPY_FLOAT_CONST(32768.0)); | ||||||
| int32_t dry_scaled = (int32_t)((MICROPY_FLOAT_CONST(1.0) - mix) * MICROPY_FLOAT_CONST(32768.0)); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Both wet and dry truncate toward zero. Could cause off by 1 error when they're summed. |
||||||
|
|
||||||
| if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter.states) { // if mix is zero pure sample only or no biquad filter objects are provided | ||||||
| for (uint32_t i = 0; i < n; i++) { | ||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
|
|
@@ -238,15 +241,15 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o | |||||
| bool buf_offset = (j % self->base.channel_count) == 1; | ||||||
| uint32_t k = j / self->base.channel_count; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section has different behavior rounding always down instead of toward zero. It should use the new helper function. Add here: |
||||||
| if (MP_LIKELY(self->base.bits_per_sample == 16)) { | ||||||
| word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
| word_buffer[i + j] = synthio_mix_down_sample(((sample_src[i + j] * dry_scaled) >> 15) + ((self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * wet_scaled) >> 15), SYNTHIO_MIX_DOWN_SCALE(2)); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| if (!self->base.samples_signed) { | ||||||
| word_buffer[i + j] ^= 0x8000; | ||||||
| } | ||||||
| } else { | ||||||
| if (self->base.samples_signed) { | ||||||
| hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)); | ||||||
| hword_buffer[i + j] = (int8_t)(((sample_hsrc[i + j] * dry_scaled) >> 15) + ((self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * wet_scaled) >> 15)); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } else { | ||||||
| hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)) ^ 0x80; | ||||||
| hword_buffer[i + j] = (uint8_t)((((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * dry_scaled) >> 15) + ((self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * wet_scaled) >> 15)) ^ 0x80; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.