Add loop_start and loop_end properties to synthio.Note for waveshaping and sampling capabilities.
This commit is contained in:
parent
87163def73
commit
785ef5abd2
|
@ -45,6 +45,8 @@ static const mp_arg_t note_properties[] = {
|
|||
{ MP_QSTR_ring_frequency, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||
{ MP_QSTR_ring_bend, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||
{ MP_QSTR_ring_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_loop_start, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||
{ MP_QSTR_loop_end, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||
};
|
||||
//| class Note:
|
||||
//| def __init__(
|
||||
|
@ -60,6 +62,8 @@ static const mp_arg_t note_properties[] = {
|
|||
//| ring_frequency: float = 0.0,
|
||||
//| ring_bend: float = 0.0,
|
||||
//| ring_waveform: Optional[ReadableBuffer] = 0.0,
|
||||
//| loop_start: int = 0,
|
||||
//| loop_end: int = 0,
|
||||
//| ) -> None:
|
||||
//| """Construct a Note object, with a frequency in Hz, and optional panning, waveform, envelope, tremolo (volume change) and bend (frequency change).
|
||||
//|
|
||||
|
@ -296,6 +300,43 @@ MP_PROPERTY_GETSET(synthio_note_ring_waveform_obj,
|
|||
(mp_obj_t)&synthio_note_get_ring_waveform_obj,
|
||||
(mp_obj_t)&synthio_note_set_ring_waveform_obj);
|
||||
|
||||
//| loop_start: int
|
||||
//| """The index of where to begin looping waveform data. Must be greater than 0 and less than the total size of the waveform data."""
|
||||
STATIC mp_obj_t synthio_note_get_loop_start(mp_obj_t self_in) {
|
||||
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(common_hal_synthio_note_get_loop_start(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_loop_start_obj, synthio_note_get_loop_start);
|
||||
|
||||
STATIC mp_obj_t synthio_note_set_loop_start(mp_obj_t self_in, mp_obj_t arg) {
|
||||
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_synthio_note_set_loop_start(self, mp_obj_get_int(arg));
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_loop_start_obj, synthio_note_set_loop_start);
|
||||
MP_PROPERTY_GETSET(synthio_note_loop_start_obj,
|
||||
(mp_obj_t)&synthio_note_get_loop_start_obj,
|
||||
(mp_obj_t)&synthio_note_set_loop_start_obj);
|
||||
|
||||
//| loop_end: int
|
||||
//| """The index of where to end looping waveform data. Must be greater than 0 or ``loop_start`` and less than the total size of the waveform data."""
|
||||
//|
|
||||
STATIC mp_obj_t synthio_note_get_loop_end(mp_obj_t self_in) {
|
||||
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(common_hal_synthio_note_get_loop_end(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_loop_end_obj, synthio_note_get_loop_end);
|
||||
|
||||
STATIC mp_obj_t synthio_note_set_loop_end(mp_obj_t self_in, mp_obj_t arg) {
|
||||
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_synthio_note_set_loop_end(self, mp_obj_get_int(arg));
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_loop_end_obj, synthio_note_set_loop_end);
|
||||
MP_PROPERTY_GETSET(synthio_note_loop_end_obj,
|
||||
(mp_obj_t)&synthio_note_get_loop_end_obj,
|
||||
(mp_obj_t)&synthio_note_set_loop_end_obj);
|
||||
|
||||
|
||||
|
||||
static void note_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
|
@ -314,6 +355,8 @@ STATIC const mp_rom_map_elem_t synthio_note_locals_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_ring_frequency), MP_ROM_PTR(&synthio_note_ring_frequency_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ring_bend), MP_ROM_PTR(&synthio_note_ring_bend_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ring_waveform), MP_ROM_PTR(&synthio_note_ring_waveform_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_loop_start), MP_ROM_PTR(&synthio_note_loop_start_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_loop_end), MP_ROM_PTR(&synthio_note_loop_end_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(synthio_note_locals_dict, synthio_note_locals_dict_table);
|
||||
|
||||
|
|
|
@ -35,3 +35,9 @@ void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_
|
|||
|
||||
mp_obj_t common_hal_synthio_note_get_envelope_obj(synthio_note_obj_t *self);
|
||||
void common_hal_synthio_note_set_envelope(synthio_note_obj_t *self, mp_obj_t value);
|
||||
|
||||
mp_int_t common_hal_synthio_note_get_loop_start(synthio_note_obj_t *self);
|
||||
void common_hal_synthio_note_set_loop_start(synthio_note_obj_t *self, mp_int_t value_in);
|
||||
|
||||
mp_int_t common_hal_synthio_note_get_loop_end(synthio_note_obj_t *self);
|
||||
void common_hal_synthio_note_set_loop_end(synthio_note_obj_t *self, mp_int_t value_in);
|
||||
|
|
|
@ -135,6 +135,24 @@ void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_
|
|||
self->ring_waveform_obj = ring_waveform_in;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_synthio_note_get_loop_start(synthio_note_obj_t *self) {
|
||||
return self->loop_start;
|
||||
}
|
||||
|
||||
void common_hal_synthio_note_set_loop_start(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||
mp_int_t val = mp_arg_validate_int_range(value_in, 0, 32767, MP_QSTR_loop_start);
|
||||
self->loop_start = val;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_synthio_note_get_loop_end(synthio_note_obj_t *self) {
|
||||
return self->loop_end;
|
||||
}
|
||||
|
||||
void common_hal_synthio_note_set_loop_end(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||
mp_int_t val = mp_arg_validate_int_range(value_in, 0, 32767, MP_QSTR_loop_end);
|
||||
self->loop_end = val;
|
||||
}
|
||||
|
||||
void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate) {
|
||||
if (sample_rate == self->sample_rate) {
|
||||
return;
|
||||
|
|
|
@ -50,6 +50,8 @@ typedef struct synthio_note_obj {
|
|||
mp_buffer_info_t waveform_buf;
|
||||
mp_buffer_info_t ring_waveform_buf;
|
||||
synthio_envelope_definition_t envelope_def;
|
||||
|
||||
uint32_t loop_start, loop_end;
|
||||
} synthio_note_obj_t;
|
||||
|
||||
void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate);
|
||||
|
|
|
@ -180,6 +180,7 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
|||
|
||||
uint32_t dds_rate;
|
||||
const int16_t *waveform = synth->waveform_bufinfo.buf;
|
||||
uint32_t waveform_start = 0;
|
||||
uint32_t waveform_length = synth->waveform_bufinfo.len;
|
||||
|
||||
uint32_t ring_dds_rate = 0;
|
||||
|
@ -202,8 +203,14 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
|||
if (note->waveform_buf.buf) {
|
||||
waveform = note->waveform_buf.buf;
|
||||
waveform_length = note->waveform_buf.len;
|
||||
if (note->loop_start > 0 && note->loop_start < waveform_length) {
|
||||
waveform_start = note->loop_start;
|
||||
}
|
||||
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * waveform_length, sample_rate);
|
||||
if (note->loop_end > waveform_start && note->loop_end < waveform_length) {
|
||||
waveform_length = note->loop_end;
|
||||
}
|
||||
}
|
||||
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * (waveform_length - waveform_start), sample_rate);
|
||||
if (note->ring_frequency_scaled != 0 && note->ring_waveform_buf.buf) {
|
||||
ring_waveform = note->ring_waveform_buf.buf;
|
||||
ring_waveform_length = note->ring_waveform_buf.len;
|
||||
|
@ -215,6 +222,7 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t offset = waveform_start << SYNTHIO_FREQUENCY_SHIFT;
|
||||
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
||||
uint32_t accum = synth->accum[chan];
|
||||
|
||||
|
@ -225,7 +233,7 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
|||
|
||||
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
|
||||
if (accum > lim) {
|
||||
accum %= lim;
|
||||
accum = accum % lim + offset;
|
||||
}
|
||||
|
||||
// first, fill with waveform
|
||||
|
@ -233,7 +241,7 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
|||
accum += dds_rate;
|
||||
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
|
||||
if (accum > lim) {
|
||||
accum -= lim;
|
||||
accum = accum - lim + offset;
|
||||
}
|
||||
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
||||
out_buffer32[i] = waveform[idx];
|
||||
|
|
Loading…
Reference in New Issue