Merge pull request #8629 from dcooperdalrymple/synthio-note-loop
Add loop_start and loop_end properties to synthio.Note for waveshaping and sampling capabilities.
This commit is contained in:
commit
383f79718a
|
@ -40,11 +40,15 @@ static const mp_arg_t note_properties[] = {
|
||||||
{ MP_QSTR_amplitude, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1) } },
|
{ MP_QSTR_amplitude, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1) } },
|
||||||
{ MP_QSTR_bend, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0) } },
|
{ MP_QSTR_bend, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0) } },
|
||||||
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
||||||
|
{ MP_QSTR_waveform_loop_start, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||||
|
{ MP_QSTR_waveform_loop_end, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) } },
|
||||||
{ MP_QSTR_envelope, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
{ MP_QSTR_envelope, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
||||||
{ MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
{ MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
||||||
{ MP_QSTR_ring_frequency, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
{ 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_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_ring_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
|
||||||
|
{ MP_QSTR_ring_waveform_loop_start, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
|
||||||
|
{ MP_QSTR_ring_waveform_loop_end, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) } },
|
||||||
};
|
};
|
||||||
//| class Note:
|
//| class Note:
|
||||||
//| def __init__(
|
//| def __init__(
|
||||||
|
@ -53,6 +57,8 @@ static const mp_arg_t note_properties[] = {
|
||||||
//| frequency: float,
|
//| frequency: float,
|
||||||
//| panning: BlockInput = 0.0,
|
//| panning: BlockInput = 0.0,
|
||||||
//| waveform: Optional[ReadableBuffer] = None,
|
//| waveform: Optional[ReadableBuffer] = None,
|
||||||
|
//| waveform_loop_start: int = 0,
|
||||||
|
//| waveform_loop_end: int = waveform_max_length,
|
||||||
//| envelope: Optional[Envelope] = None,
|
//| envelope: Optional[Envelope] = None,
|
||||||
//| amplitude: BlockInput = 0.0,
|
//| amplitude: BlockInput = 0.0,
|
||||||
//| bend: BlockInput = 0.0,
|
//| bend: BlockInput = 0.0,
|
||||||
|
@ -60,6 +66,8 @@ static const mp_arg_t note_properties[] = {
|
||||||
//| ring_frequency: float = 0.0,
|
//| ring_frequency: float = 0.0,
|
||||||
//| ring_bend: float = 0.0,
|
//| ring_bend: float = 0.0,
|
||||||
//| ring_waveform: Optional[ReadableBuffer] = 0.0,
|
//| ring_waveform: Optional[ReadableBuffer] = 0.0,
|
||||||
|
//| ring_waveform_loop_start: int = 0,
|
||||||
|
//| ring_waveform_loop_end: int = waveform_max_length,
|
||||||
//| ) -> None:
|
//| ) -> None:
|
||||||
//| """Construct a Note object, with a frequency in Hz, and optional panning, waveform, envelope, tremolo (volume change) and bend (frequency change).
|
//| """Construct a Note object, with a frequency in Hz, and optional panning, waveform, envelope, tremolo (volume change) and bend (frequency change).
|
||||||
//|
|
//|
|
||||||
|
@ -210,6 +218,53 @@ MP_PROPERTY_GETSET(synthio_note_waveform_obj,
|
||||||
(mp_obj_t)&synthio_note_get_waveform_obj,
|
(mp_obj_t)&synthio_note_get_waveform_obj,
|
||||||
(mp_obj_t)&synthio_note_set_waveform_obj);
|
(mp_obj_t)&synthio_note_set_waveform_obj);
|
||||||
|
|
||||||
|
//| waveform_loop_start: int
|
||||||
|
//| """The sample index of where to begin looping waveform data.
|
||||||
|
//|
|
||||||
|
//| Values outside the range ``0`` to ``waveform_max_length-1`` (inclusive) are rejected with a `ValueError`.
|
||||||
|
//|
|
||||||
|
//| Values greater than or equal to the actual waveform length are treated as 0."""
|
||||||
|
STATIC mp_obj_t synthio_note_get_waveform_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_waveform_loop_start(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_waveform_loop_start_obj, synthio_note_get_waveform_loop_start);
|
||||||
|
|
||||||
|
STATIC mp_obj_t synthio_note_set_waveform_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_waveform_loop_start(self, mp_obj_get_int(arg));
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_waveform_loop_start_obj, synthio_note_set_waveform_loop_start);
|
||||||
|
MP_PROPERTY_GETSET(synthio_note_waveform_loop_start_obj,
|
||||||
|
(mp_obj_t)&synthio_note_get_waveform_loop_start_obj,
|
||||||
|
(mp_obj_t)&synthio_note_set_waveform_loop_start_obj);
|
||||||
|
|
||||||
|
//| waveform_loop_end: int
|
||||||
|
//| """The sample index of where to end looping waveform data.
|
||||||
|
//|
|
||||||
|
//| Values outside the range ``1`` to ``waveform_max_length`` (inclusive) are rejected with a `ValueError`.
|
||||||
|
//|
|
||||||
|
//| If the value is greater than the actual waveform length, or less than or equal to the loop start, the loop will occur at the end of the waveform.
|
||||||
|
//|
|
||||||
|
//| Use the `synthio.waveform_max_length` constant to set the loop point at the end of the wave form, no matter its length."""
|
||||||
|
//|
|
||||||
|
STATIC mp_obj_t synthio_note_get_waveform_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_waveform_loop_end(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_waveform_loop_end_obj, synthio_note_get_waveform_loop_end);
|
||||||
|
|
||||||
|
STATIC mp_obj_t synthio_note_set_waveform_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_waveform_loop_end(self, mp_obj_get_int(arg));
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_waveform_loop_end_obj, synthio_note_set_waveform_loop_end);
|
||||||
|
MP_PROPERTY_GETSET(synthio_note_waveform_loop_end_obj,
|
||||||
|
(mp_obj_t)&synthio_note_get_waveform_loop_end_obj,
|
||||||
|
(mp_obj_t)&synthio_note_set_waveform_loop_end_obj);
|
||||||
|
|
||||||
|
|
||||||
//| envelope: Envelope
|
//| envelope: Envelope
|
||||||
//| """The envelope of this note"""
|
//| """The envelope of this note"""
|
||||||
|
@ -296,6 +351,53 @@ MP_PROPERTY_GETSET(synthio_note_ring_waveform_obj,
|
||||||
(mp_obj_t)&synthio_note_get_ring_waveform_obj,
|
(mp_obj_t)&synthio_note_get_ring_waveform_obj,
|
||||||
(mp_obj_t)&synthio_note_set_ring_waveform_obj);
|
(mp_obj_t)&synthio_note_set_ring_waveform_obj);
|
||||||
|
|
||||||
|
//| ring_waveform_loop_start: int
|
||||||
|
//| """The sample index of where to begin looping waveform data.
|
||||||
|
//|
|
||||||
|
//| Values outside the range ``0`` to ``waveform_max_length-1`` (inclusive) are rejected with a `ValueError`.
|
||||||
|
//|
|
||||||
|
//| Values greater than or equal to the actual waveform length are treated as 0."""
|
||||||
|
STATIC mp_obj_t synthio_note_get_ring_waveform_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_ring_waveform_loop_start(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_ring_waveform_loop_start_obj, synthio_note_get_ring_waveform_loop_start);
|
||||||
|
|
||||||
|
STATIC mp_obj_t synthio_note_set_ring_waveform_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_ring_waveform_loop_start(self, mp_obj_get_int(arg));
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_ring_waveform_loop_start_obj, synthio_note_set_ring_waveform_loop_start);
|
||||||
|
MP_PROPERTY_GETSET(synthio_note_ring_waveform_loop_start_obj,
|
||||||
|
(mp_obj_t)&synthio_note_get_ring_waveform_loop_start_obj,
|
||||||
|
(mp_obj_t)&synthio_note_set_ring_waveform_loop_start_obj);
|
||||||
|
|
||||||
|
//| ring_waveform_loop_end: int
|
||||||
|
//| """The sample index of where to end looping waveform data.
|
||||||
|
//|
|
||||||
|
//| Values outside the range ``1`` to ``waveform_max_length`` (inclusive) are rejected with a `ValueError`.
|
||||||
|
//|
|
||||||
|
//| If the value is greater than the actual waveform length, or less than or equal to the loop start, the loop will occur at the end of the waveform.
|
||||||
|
//|
|
||||||
|
//| Use the `synthio.waveform_max_length` constant to set the loop point at the end of the wave form, no matter its length."""
|
||||||
|
//|
|
||||||
|
STATIC mp_obj_t synthio_note_get_ring_waveform_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_ring_waveform_loop_end(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_ring_waveform_loop_end_obj, synthio_note_get_ring_waveform_loop_end);
|
||||||
|
|
||||||
|
STATIC mp_obj_t synthio_note_set_ring_waveform_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_ring_waveform_loop_end(self, mp_obj_get_int(arg));
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_ring_waveform_loop_end_obj, synthio_note_set_ring_waveform_loop_end);
|
||||||
|
MP_PROPERTY_GETSET(synthio_note_ring_waveform_loop_end_obj,
|
||||||
|
(mp_obj_t)&synthio_note_get_ring_waveform_loop_end_obj,
|
||||||
|
(mp_obj_t)&synthio_note_set_ring_waveform_loop_end_obj);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void note_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
static void note_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
|
@ -308,12 +410,16 @@ STATIC const mp_rom_map_elem_t synthio_note_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&synthio_note_filter_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&synthio_note_filter_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_panning), MP_ROM_PTR(&synthio_note_panning_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_panning), MP_ROM_PTR(&synthio_note_panning_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_waveform), MP_ROM_PTR(&synthio_note_waveform_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_waveform), MP_ROM_PTR(&synthio_note_waveform_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_waveform_loop_start), MP_ROM_PTR(&synthio_note_waveform_loop_start_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_waveform_loop_end), MP_ROM_PTR(&synthio_note_waveform_loop_end_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_envelope), MP_ROM_PTR(&synthio_note_envelope_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_envelope), MP_ROM_PTR(&synthio_note_envelope_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_amplitude), MP_ROM_PTR(&synthio_note_amplitude_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_amplitude), MP_ROM_PTR(&synthio_note_amplitude_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_bend), MP_ROM_PTR(&synthio_note_bend_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_bend), MP_ROM_PTR(&synthio_note_bend_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ring_frequency), MP_ROM_PTR(&synthio_note_ring_frequency_obj) },
|
{ 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_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_ring_waveform), MP_ROM_PTR(&synthio_note_ring_waveform_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_ring_waveform_loop_start), MP_ROM_PTR(&synthio_note_ring_waveform_loop_start_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_ring_waveform_loop_end), MP_ROM_PTR(&synthio_note_ring_waveform_loop_end_obj) },
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(synthio_note_locals_dict, synthio_note_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(synthio_note_locals_dict, synthio_note_locals_dict_table);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,12 @@ void common_hal_synthio_note_set_bend(synthio_note_obj_t *self, mp_obj_t value);
|
||||||
mp_obj_t common_hal_synthio_note_get_waveform_obj(synthio_note_obj_t *self);
|
mp_obj_t common_hal_synthio_note_get_waveform_obj(synthio_note_obj_t *self);
|
||||||
void common_hal_synthio_note_set_waveform(synthio_note_obj_t *self, mp_obj_t value);
|
void common_hal_synthio_note_set_waveform(synthio_note_obj_t *self, mp_obj_t value);
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_waveform_loop_start(synthio_note_obj_t *self);
|
||||||
|
void common_hal_synthio_note_set_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in);
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_waveform_loop_end(synthio_note_obj_t *self);
|
||||||
|
void common_hal_synthio_note_set_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in);
|
||||||
|
|
||||||
mp_float_t common_hal_synthio_note_get_ring_frequency(synthio_note_obj_t *self);
|
mp_float_t common_hal_synthio_note_get_ring_frequency(synthio_note_obj_t *self);
|
||||||
void common_hal_synthio_note_set_ring_frequency(synthio_note_obj_t *self, mp_float_t value);
|
void common_hal_synthio_note_set_ring_frequency(synthio_note_obj_t *self, mp_float_t value);
|
||||||
|
|
||||||
|
@ -33,5 +39,11 @@ void common_hal_synthio_note_set_ring_bend(synthio_note_obj_t *self, mp_obj_t va
|
||||||
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self);
|
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self);
|
||||||
void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_t value);
|
void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_t value);
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_start(synthio_note_obj_t *self);
|
||||||
|
void common_hal_synthio_note_set_ring_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in);
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_end(synthio_note_obj_t *self);
|
||||||
|
void common_hal_synthio_note_set_ring_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in);
|
||||||
|
|
||||||
mp_obj_t common_hal_synthio_note_get_envelope_obj(synthio_note_obj_t *self);
|
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);
|
void common_hal_synthio_note_set_envelope(synthio_note_obj_t *self, mp_obj_t value);
|
||||||
|
|
|
@ -304,6 +304,11 @@ STATIC mp_obj_t voct_to_hz(mp_obj_t arg) {
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_voct_to_hz_obj, voct_to_hz);
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_voct_to_hz_obj, voct_to_hz);
|
||||||
|
|
||||||
|
//|
|
||||||
|
//| waveform_max_length: int
|
||||||
|
//| """The maximum number of samples permitted in a waveform"""
|
||||||
|
//|
|
||||||
|
|
||||||
#if CIRCUITPY_AUDIOCORE_DEBUG
|
#if CIRCUITPY_AUDIOCORE_DEBUG
|
||||||
STATIC mp_obj_t synthio_lfo_tick(size_t n, const mp_obj_t *args) {
|
STATIC mp_obj_t synthio_lfo_tick(size_t n, const mp_obj_t *args) {
|
||||||
shared_bindings_synthio_lfo_tick(48000);
|
shared_bindings_synthio_lfo_tick(48000);
|
||||||
|
@ -333,6 +338,7 @@ STATIC const mp_rom_map_elem_t synthio_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_Envelope), MP_ROM_PTR(&synthio_envelope_type_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_Envelope), MP_ROM_PTR(&synthio_envelope_type_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_midi_to_hz), MP_ROM_PTR(&synthio_midi_to_hz_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_midi_to_hz), MP_ROM_PTR(&synthio_midi_to_hz_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_voct_to_hz), MP_ROM_PTR(&synthio_voct_to_hz_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_voct_to_hz), MP_ROM_PTR(&synthio_voct_to_hz_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_waveform_max_length), MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) },
|
||||||
#if CIRCUITPY_AUDIOCORE_DEBUG
|
#if CIRCUITPY_AUDIOCORE_DEBUG
|
||||||
{ MP_ROM_QSTR(MP_QSTR_lfo_tick), MP_ROM_PTR(&synthio_lfo_tick_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_lfo_tick), MP_ROM_PTR(&synthio_lfo_tick_obj) },
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "py/objnamedtuple.h"
|
#include "py/objnamedtuple.h"
|
||||||
#include "py/enum.h"
|
#include "py/enum.h"
|
||||||
|
|
||||||
|
#define SYNTHIO_WAVEFORM_SIZE 16384
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SYNTHIO_ENVELOPE_STATE_ATTACK, SYNTHIO_ENVELOPE_STATE_DECAY,
|
SYNTHIO_ENVELOPE_STATE_ATTACK, SYNTHIO_ENVELOPE_STATE_DECAY,
|
||||||
SYNTHIO_ENVELOPE_STATE_SUSTAIN, SYNTHIO_ENVELOPE_STATE_RELEASE
|
SYNTHIO_ENVELOPE_STATE_SUSTAIN, SYNTHIO_ENVELOPE_STATE_RELEASE
|
||||||
|
|
|
@ -120,6 +120,24 @@ void common_hal_synthio_note_set_waveform(synthio_note_obj_t *self, mp_obj_t wav
|
||||||
self->waveform_obj = waveform_in;
|
self->waveform_obj = waveform_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_waveform_loop_start(synthio_note_obj_t *self) {
|
||||||
|
return self->waveform_loop_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_hal_synthio_note_set_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||||
|
mp_int_t val = mp_arg_validate_int_range(value_in, 0, SYNTHIO_WAVEFORM_SIZE - 1, MP_QSTR_waveform_loop_start);
|
||||||
|
self->waveform_loop_start = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_waveform_loop_end(synthio_note_obj_t *self) {
|
||||||
|
return self->waveform_loop_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_hal_synthio_note_set_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||||
|
mp_int_t val = mp_arg_validate_int_range(value_in, 1, SYNTHIO_WAVEFORM_SIZE, MP_QSTR_waveform_loop_end);
|
||||||
|
self->waveform_loop_end = val;
|
||||||
|
}
|
||||||
|
|
||||||
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self) {
|
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self) {
|
||||||
return self->ring_waveform_obj;
|
return self->ring_waveform_obj;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +153,24 @@ void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_
|
||||||
self->ring_waveform_obj = ring_waveform_in;
|
self->ring_waveform_obj = ring_waveform_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_start(synthio_note_obj_t *self) {
|
||||||
|
return self->ring_waveform_loop_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_hal_synthio_note_set_ring_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||||
|
mp_int_t val = mp_arg_validate_int_range(value_in, 0, SYNTHIO_WAVEFORM_SIZE - 1, MP_QSTR_ring_waveform_loop_start);
|
||||||
|
self->ring_waveform_loop_start = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_end(synthio_note_obj_t *self) {
|
||||||
|
return self->ring_waveform_loop_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_hal_synthio_note_set_ring_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in) {
|
||||||
|
mp_int_t val = mp_arg_validate_int_range(value_in, 1, SYNTHIO_WAVEFORM_SIZE, MP_QSTR_ring_waveform_loop_end);
|
||||||
|
self->ring_waveform_loop_end = val;
|
||||||
|
}
|
||||||
|
|
||||||
void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate) {
|
void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate) {
|
||||||
if (sample_rate == self->sample_rate) {
|
if (sample_rate == self->sample_rate) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -48,7 +48,9 @@ typedef struct synthio_note_obj {
|
||||||
int32_t ring_frequency_scaled, ring_frequency_bent;
|
int32_t ring_frequency_scaled, ring_frequency_bent;
|
||||||
|
|
||||||
mp_buffer_info_t waveform_buf;
|
mp_buffer_info_t waveform_buf;
|
||||||
|
uint32_t waveform_loop_start, waveform_loop_end;
|
||||||
mp_buffer_info_t ring_waveform_buf;
|
mp_buffer_info_t ring_waveform_buf;
|
||||||
|
uint32_t ring_waveform_loop_start, ring_waveform_loop_end;
|
||||||
synthio_envelope_definition_t envelope_def;
|
synthio_envelope_definition_t envelope_def;
|
||||||
} synthio_note_obj_t;
|
} synthio_note_obj_t;
|
||||||
|
|
||||||
|
|
|
@ -180,10 +180,12 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
||||||
|
|
||||||
uint32_t dds_rate;
|
uint32_t dds_rate;
|
||||||
const int16_t *waveform = synth->waveform_bufinfo.buf;
|
const int16_t *waveform = synth->waveform_bufinfo.buf;
|
||||||
|
uint32_t waveform_start = 0;
|
||||||
uint32_t waveform_length = synth->waveform_bufinfo.len;
|
uint32_t waveform_length = synth->waveform_bufinfo.len;
|
||||||
|
|
||||||
uint32_t ring_dds_rate = 0;
|
uint32_t ring_dds_rate = 0;
|
||||||
const int16_t *ring_waveform = NULL;
|
const int16_t *ring_waveform = NULL;
|
||||||
|
uint32_t ring_waveform_start = 0;
|
||||||
uint32_t ring_waveform_length = 0;
|
uint32_t ring_waveform_length = 0;
|
||||||
|
|
||||||
if (mp_obj_is_small_int(note_obj)) {
|
if (mp_obj_is_small_int(note_obj)) {
|
||||||
|
@ -202,12 +204,24 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
||||||
if (note->waveform_buf.buf) {
|
if (note->waveform_buf.buf) {
|
||||||
waveform = note->waveform_buf.buf;
|
waveform = note->waveform_buf.buf;
|
||||||
waveform_length = note->waveform_buf.len;
|
waveform_length = note->waveform_buf.len;
|
||||||
|
if (note->waveform_loop_start > 0 && note->waveform_loop_start < waveform_length) {
|
||||||
|
waveform_start = note->waveform_loop_start;
|
||||||
}
|
}
|
||||||
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * waveform_length, sample_rate);
|
if (note->waveform_loop_end > waveform_start && note->waveform_loop_end < waveform_length) {
|
||||||
|
waveform_length = note->waveform_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) {
|
if (note->ring_frequency_scaled != 0 && note->ring_waveform_buf.buf) {
|
||||||
ring_waveform = note->ring_waveform_buf.buf;
|
ring_waveform = note->ring_waveform_buf.buf;
|
||||||
ring_waveform_length = note->ring_waveform_buf.len;
|
ring_waveform_length = note->ring_waveform_buf.len;
|
||||||
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_bent * ring_waveform_length, sample_rate);
|
if (note->ring_waveform_loop_start > 0 && note->ring_waveform_loop_start < ring_waveform_length) {
|
||||||
|
ring_waveform_start = note->waveform_loop_start;
|
||||||
|
}
|
||||||
|
if (note->ring_waveform_loop_end > ring_waveform_start && note->ring_waveform_loop_end < ring_waveform_length) {
|
||||||
|
ring_waveform_length = note->ring_waveform_loop_end;
|
||||||
|
}
|
||||||
|
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_bent * (ring_waveform_length - ring_waveform_start), sample_rate);
|
||||||
uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
||||||
if (ring_dds_rate > lim / sizeof(int16_t)) {
|
if (ring_dds_rate > lim / sizeof(int16_t)) {
|
||||||
ring_dds_rate = 0; // can't ring at that frequency
|
ring_dds_rate = 0; // can't ring at that frequency
|
||||||
|
@ -215,6 +229,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 lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
||||||
uint32_t accum = synth->accum[chan];
|
uint32_t accum = synth->accum[chan];
|
||||||
|
|
||||||
|
@ -225,7 +240,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
|
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
|
||||||
if (accum > lim) {
|
if (accum > lim) {
|
||||||
accum %= lim;
|
accum = accum % lim + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, fill with waveform
|
// first, fill with waveform
|
||||||
|
@ -233,7 +248,7 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
||||||
accum += dds_rate;
|
accum += dds_rate;
|
||||||
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
|
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
|
||||||
if (accum > lim) {
|
if (accum > lim) {
|
||||||
accum -= lim;
|
accum = accum - lim + offset;
|
||||||
}
|
}
|
||||||
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
||||||
out_buffer32[i] = waveform[idx];
|
out_buffer32[i] = waveform[idx];
|
||||||
|
@ -249,18 +264,19 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
|
||||||
|
|
||||||
// now modulate by ring and accumulate
|
// now modulate by ring and accumulate
|
||||||
accum = synth->ring_accum[chan];
|
accum = synth->ring_accum[chan];
|
||||||
|
offset = ring_waveform_start << SYNTHIO_FREQUENCY_SHIFT;
|
||||||
lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
|
||||||
|
|
||||||
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
|
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
|
||||||
if (accum > lim) {
|
if (accum > lim) {
|
||||||
accum %= lim;
|
accum = accum % lim + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint16_t i = 0; i < dur; i++) {
|
for (uint16_t i = 0; i < dur; i++) {
|
||||||
accum += ring_dds_rate;
|
accum += ring_dds_rate;
|
||||||
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
|
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
|
||||||
if (accum > lim) {
|
if (accum > lim) {
|
||||||
accum -= lim;
|
accum = accum - lim + offset;
|
||||||
}
|
}
|
||||||
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
|
||||||
int16_t wi = (ring_waveform[idx] * out_buffer32[i]) / 32768;
|
int16_t wi = (ring_waveform[idx] * out_buffer32[i]) / 32768;
|
||||||
|
@ -434,7 +450,7 @@ STATIC void parse_common(mp_buffer_info_t *bufinfo, mp_obj_t o, int16_t what, mp
|
||||||
|
|
||||||
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj) {
|
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj) {
|
||||||
*bufinfo_waveform = ((mp_buffer_info_t) { .buf = (void *)square_wave, .len = 2 });
|
*bufinfo_waveform = ((mp_buffer_info_t) { .buf = (void *)square_wave, .len = 2 });
|
||||||
parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, 16384);
|
parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, SYNTHIO_WAVEFORM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
Loading…
Reference in New Issue