synthio: more fir-filter removal; fix biquad logic errors

This commit is contained in:
Jeff Epler 2023-05-30 09:24:06 -05:00
parent 1d58b550b5
commit 3151656f4b
9 changed files with 17 additions and 27 deletions

View File

@ -53,7 +53,6 @@
//| channel_count: int = 1, //| channel_count: int = 1,
//| waveform: Optional[ReadableBuffer] = None, //| waveform: Optional[ReadableBuffer] = None,
//| envelope: Optional[Envelope] = None, //| envelope: Optional[Envelope] = None,
//| filter: Optional[ReadableBuffer] = None,
//| ) -> None: //| ) -> None:
//| """Create a synthesizer object. //| """Create a synthesizer object.
//| //|
@ -66,17 +65,15 @@
//| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory //| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory
//| :param int channel_count: The number of output channels (1=mono, 2=stereo) //| :param int channel_count: The number of output channels (1=mono, 2=stereo)
//| :param ReadableBuffer waveform: A single-cycle waveform. Default is a 50% duty cycle square wave. If specified, must be a ReadableBuffer of type 'h' (signed 16 bit) //| :param ReadableBuffer waveform: A single-cycle waveform. Default is a 50% duty cycle square wave. If specified, must be a ReadableBuffer of type 'h' (signed 16 bit)
//| :param ReadableBuffer filter: Coefficients of an FIR filter to apply to notes with ``filter=True``. If specified, must be a ReadableBuffer of type 'h' (signed 16 bit)
//| :param Optional[Envelope] envelope: An object that defines the loudness of a note over time. The default envelope, `None` provides no ramping, voices turn instantly on and off. //| :param Optional[Envelope] envelope: An object that defines the loudness of a note over time. The default envelope, `None` provides no ramping, voices turn instantly on and off.
//| """ //| """
STATIC mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { STATIC mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_sample_rate, ARG_channel_count, ARG_waveform, ARG_envelope, ARG_filter }; enum { ARG_sample_rate, ARG_channel_count, ARG_waveform, ARG_envelope };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
{ MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, { MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
{ MP_QSTR_envelope, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } }, { MP_QSTR_envelope, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
{ MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -88,7 +85,6 @@ STATIC mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n
args[ARG_sample_rate].u_int, args[ARG_sample_rate].u_int,
args[ARG_channel_count].u_int, args[ARG_channel_count].u_int,
args[ARG_waveform].u_obj, args[ARG_waveform].u_obj,
args[ARG_filter].u_obj,
args[ARG_envelope].u_obj); args[ARG_envelope].u_obj);
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);

View File

@ -32,7 +32,7 @@
extern const mp_obj_type_t synthio_synthesizer_type; extern const mp_obj_type_t synthio_synthesizer_type;
void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self, void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self,
uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t filter_obj, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj,
mp_obj_t envelope_obj); mp_obj_t envelope_obj);
void common_hal_synthio_synthesizer_deinit(synthio_synthesizer_obj_t *self); void common_hal_synthio_synthesizer_deinit(synthio_synthesizer_obj_t *self);
bool common_hal_synthio_synthesizer_deinited(synthio_synthesizer_obj_t *self); bool common_hal_synthio_synthesizer_deinited(synthio_synthesizer_obj_t *self);

View File

@ -94,7 +94,7 @@ mp_obj_t common_hal_synthio_new_bpf(mp_float_t w0, mp_float_t Q) {
return namedtuple_make_new((const mp_obj_type_t *)&synthio_biquad_type_obj, MP_ARRAY_SIZE(out_args), 0, out_args); return namedtuple_make_new((const mp_obj_type_t *)&synthio_biquad_type_obj, MP_ARRAY_SIZE(out_args), 0, out_args);
} }
#define BIQUAD_SHIFT (16) #define BIQUAD_SHIFT (19)
STATIC int32_t biquad_scale_arg_obj(mp_obj_t arg) { STATIC int32_t biquad_scale_arg_obj(mp_obj_t arg) {
return (int32_t)MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(ldexp)(mp_obj_get_float(arg), BIQUAD_SHIFT)); return (int32_t)MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(ldexp)(mp_obj_get_float(arg), BIQUAD_SHIFT));
} }
@ -110,6 +110,10 @@ void synthio_biquad_filter_assign(biquad_filter_state *st, mp_obj_t biquad_obj)
} }
} }
void synthio_biquad_filter_reset(biquad_filter_state *st) {
memset(&st->x, 0, 8 * sizeof(int16_t));
}
void synthio_biquad_filter_samples(biquad_filter_state *st, int32_t *out0, const int32_t *in0, size_t n0, size_t n_channels) { void synthio_biquad_filter_samples(biquad_filter_state *st, int32_t *out0, const int32_t *in0, size_t n0, size_t n_channels) {
int32_t a1 = st->a1; int32_t a1 = st->a1;
int32_t a2 = st->a2; int32_t a2 = st->a2;
@ -134,7 +138,7 @@ void synthio_biquad_filter_samples(biquad_filter_state *st, int32_t *out0, const
x0 = input; x0 = input;
y1 = y0; y1 = y0;
y0 = output; y0 = output;
*out = output; *out += output;
} }
st->x[i][0] = x0; st->x[i][0] = x0;
st->x[i][1] = x1; st->x[i][1] = x1;

View File

@ -34,4 +34,5 @@ typedef struct {
} biquad_filter_state; } biquad_filter_state;
void synthio_biquad_filter_assign(biquad_filter_state *st, mp_obj_t biquad_obj); void synthio_biquad_filter_assign(biquad_filter_state *st, mp_obj_t biquad_obj);
void synthio_biquad_filter_reset(biquad_filter_state *st);
void synthio_biquad_filter_samples(biquad_filter_state *st, int32_t *out, const int32_t *in, size_t n_samples, size_t n_channels); void synthio_biquad_filter_samples(biquad_filter_state *st, int32_t *out, const int32_t *in, size_t n_samples, size_t n_channels);

View File

@ -122,7 +122,7 @@ void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
self->track.buf = (void *)buffer; self->track.buf = (void *)buffer;
self->track.len = len; self->track.len = len;
synthio_synth_init(&self->synth, sample_rate, 1, waveform_obj, mp_const_none, envelope_obj); synthio_synth_init(&self->synth, sample_rate, 1, waveform_obj, envelope_obj);
start_parse(self); start_parse(self);
} }

View File

@ -148,6 +148,7 @@ void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate) {
void synthio_note_start(synthio_note_obj_t *self, int32_t sample_rate) { void synthio_note_start(synthio_note_obj_t *self, int32_t sample_rate) {
synthio_note_recalculate(self, sample_rate); synthio_note_recalculate(self, sample_rate);
synthio_biquad_filter_reset(&self->filter_state);
} }
// Perform a pitch bend operation // Perform a pitch bend operation

View File

@ -33,10 +33,10 @@
void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self, void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self,
uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t filter_obj, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj,
mp_obj_t envelope_obj) { mp_obj_t envelope_obj) {
synthio_synth_init(&self->synth, sample_rate, channel_count, waveform_obj, filter_obj, envelope_obj); synthio_synth_init(&self->synth, sample_rate, channel_count, waveform_obj, envelope_obj);
self->blocks = mp_obj_new_list(0, NULL); self->blocks = mp_obj_new_list(0, NULL);
} }

View File

@ -389,7 +389,6 @@ bool synthio_synth_deinited(synthio_synth_t *synth) {
} }
void synthio_synth_deinit(synthio_synth_t *synth) { void synthio_synth_deinit(synthio_synth_t *synth) {
synth->filter_buffer = NULL;
synth->buffers[0] = NULL; synth->buffers[0] = NULL;
synth->buffers[1] = NULL; synth->buffers[1] = NULL;
} }
@ -403,17 +402,12 @@ mp_obj_t synthio_synth_envelope_get(synthio_synth_t *synth) {
return synth->envelope_obj; return synth->envelope_obj;
} }
void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t filter_obj, mp_obj_t envelope_obj) { void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t envelope_obj) {
synthio_synth_parse_waveform(&synth->waveform_bufinfo, waveform_obj); synthio_synth_parse_waveform(&synth->waveform_bufinfo, waveform_obj);
synthio_synth_parse_filter(&synth->filter_bufinfo, filter_obj);
mp_arg_validate_int_range(channel_count, 1, 2, MP_QSTR_channel_count); mp_arg_validate_int_range(channel_count, 1, 2, MP_QSTR_channel_count);
synth->buffer_length = SYNTHIO_MAX_DUR * SYNTHIO_BYTES_PER_SAMPLE * channel_count; synth->buffer_length = SYNTHIO_MAX_DUR * SYNTHIO_BYTES_PER_SAMPLE * channel_count;
synth->buffers[0] = m_malloc(synth->buffer_length, false); synth->buffers[0] = m_malloc(synth->buffer_length, false);
synth->buffers[1] = m_malloc(synth->buffer_length, false); synth->buffers[1] = m_malloc(synth->buffer_length, false);
if (synth->filter_bufinfo.len) {
synth->filter_buffer_length = (synth->filter_bufinfo.len + SYNTHIO_MAX_DUR) * channel_count * sizeof(int32_t);
synth->filter_buffer = m_malloc(synth->filter_buffer_length, false);
}
synth->channel_count = channel_count; synth->channel_count = channel_count;
synth->other_channel = -1; synth->other_channel = -1;
synth->waveform_obj = waveform_obj; synth->waveform_obj = waveform_obj;
@ -453,11 +447,6 @@ void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t w
parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, 16384); parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, 16384);
} }
void synthio_synth_parse_filter(mp_buffer_info_t *bufinfo_filter, mp_obj_t filter_obj) {
*bufinfo_filter = ((mp_buffer_info_t) { .buf = NULL, .len = 0 });
parse_common(bufinfo_filter, filter_obj, MP_QSTR_filter, 128);
}
STATIC int find_channel_with_note(synthio_synth_t *synth, mp_obj_t note) { STATIC int find_channel_with_note(synthio_synth_t *synth, mp_obj_t note) {
for (int i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) { for (int i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) {
if (synth->span.note_obj[i] == note) { if (synth->span.note_obj[i] == note) {

View File

@ -64,12 +64,11 @@ typedef struct synthio_synth {
uint32_t sample_rate; uint32_t sample_rate;
uint32_t total_envelope; uint32_t total_envelope;
int16_t *buffers[2]; int16_t *buffers[2];
int32_t *filter_buffer;
uint8_t channel_count; uint8_t channel_count;
uint16_t buffer_length, filter_buffer_length; uint16_t buffer_length;
uint16_t last_buffer_length; uint16_t last_buffer_length;
uint8_t other_channel, buffer_index, other_buffer_index; uint8_t other_channel, buffer_index, other_buffer_index;
mp_buffer_info_t waveform_bufinfo, filter_bufinfo; mp_buffer_info_t waveform_bufinfo;
synthio_envelope_definition_t global_envelope_definition; synthio_envelope_definition_t global_envelope_definition;
mp_obj_t waveform_obj, filter_obj, envelope_obj; mp_obj_t waveform_obj, filter_obj, envelope_obj;
synthio_midi_span_t span; synthio_midi_span_t span;
@ -91,7 +90,7 @@ typedef struct {
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length, uint8_t channel); void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length, uint8_t channel);
void synthio_synth_deinit(synthio_synth_t *synth); void synthio_synth_deinit(synthio_synth_t *synth);
bool synthio_synth_deinited(synthio_synth_t *synth); bool synthio_synth_deinited(synthio_synth_t *synth);
void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t filter_obj, mp_obj_t envelope); void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t envelope);
void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output, void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output,
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing); bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing);
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel); void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel);