synthio: more fir-filter removal; fix biquad logic errors
This commit is contained in:
parent
1d58b550b5
commit
3151656f4b
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue