synthio: add Synthesizer.lfo, retrigger option
This commit is contained in:
parent
f83212314e
commit
b2c6f9b1a4
@ -33,6 +33,7 @@
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
#include "shared-bindings/synthio/LFO.h"
|
||||
#include "shared-bindings/synthio/__init__.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
@ -120,23 +121,29 @@ STATIC mp_obj_t synthio_synthesizer_release(mp_obj_t self_in, mp_obj_t release)
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(synthio_synthesizer_release_obj, synthio_synthesizer_release);
|
||||
|
||||
//| def release_then_press(self, release: NoteSequence = (), press: NoteSequence = ()) -> None:
|
||||
//| def release_then_press(
|
||||
//| self, release: NoteSequence = (), press: NoteSequence = (), retrigger=LFOSequence
|
||||
//| ) -> None:
|
||||
//| """Turn some notes on and/or off.
|
||||
//|
|
||||
//| It is OK to release note that was not actually turned on.
|
||||
//|
|
||||
//| Pressing a note that was already pressed has no effect.
|
||||
//| Pressing a note that was already pressed returns it to the attack phase
|
||||
//| but without resetting its amplitude. Releasing a note and immediately
|
||||
//| pressing it again returns it to the attack phase with an initial
|
||||
//| amplitude of 0.
|
||||
//|
|
||||
//| Releasing and pressing the note again has little effect, but does reset the phase
|
||||
//| of the note, which may be perceptible as a small glitch.
|
||||
//| At the same time, the passed LFOs (if any) are retriggered.
|
||||
//|
|
||||
//| :param NoteSequence release: Any sequence of notes.
|
||||
//| :param NoteSequence press: Any sequence of notes."""
|
||||
//| :param NoteSequence press: Any sequence of notes.
|
||||
//| :param LFOSequence retrigger: Any sequence of LFOs."""
|
||||
STATIC mp_obj_t synthio_synthesizer_release_then_press(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_release, ARG_press };
|
||||
enum { ARG_release, ARG_press, ARG_retrigger };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_release, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple } },
|
||||
{ MP_QSTR_press, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple } },
|
||||
{ MP_QSTR_retrigger, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
@ -146,6 +153,7 @@ STATIC mp_obj_t synthio_synthesizer_release_then_press(mp_uint_t n_args, const m
|
||||
check_for_deinit(self);
|
||||
common_hal_synthio_synthesizer_release(self, args[ARG_release].u_obj);
|
||||
common_hal_synthio_synthesizer_press(self, args[ARG_press].u_obj);
|
||||
common_hal_synthio_synthesizer_retrigger(self, args[ARG_retrigger].u_obj);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(synthio_synthesizer_release_then_press_obj, 1, synthio_synthesizer_release_then_press);
|
||||
@ -250,6 +258,23 @@ MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_get_pressed_obj, synthio_synthesiz
|
||||
MP_PROPERTY_GETTER(synthio_synthesizer_pressed_obj,
|
||||
(mp_obj_t)&synthio_synthesizer_get_pressed_obj);
|
||||
|
||||
//| lfos: List[LFO]
|
||||
//| """A list of LFOs to advance whether or not they are associated with a playing note.
|
||||
//|
|
||||
//| This can be used to implement 'free-running' LFOs. LFOs associated with playing notes are advanced whether or not they are in this list.
|
||||
//|
|
||||
//| This attribute is read-only but its contents may be modified by e.g., calling append() or remove(). It is initially an empty list."""
|
||||
//|
|
||||
STATIC mp_obj_t synthio_synthesizer_obj_get_lfos(mp_obj_t self_in) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
return common_hal_synthio_synthesizer_get_lfos(self);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_get_lfos_obj, synthio_synthesizer_obj_get_lfos);
|
||||
|
||||
MP_PROPERTY_GETTER(synthio_synthesizer_lfos_obj,
|
||||
(mp_obj_t)&synthio_synthesizer_get_lfos_obj);
|
||||
|
||||
//| max_polyphony: int
|
||||
//| """Maximum polyphony of the synthesizer (read-only class property)"""
|
||||
//|
|
||||
@ -270,6 +295,7 @@ STATIC const mp_rom_map_elem_t synthio_synthesizer_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&synthio_synthesizer_sample_rate_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_max_polyphony), MP_ROM_INT(CIRCUITPY_SYNTHIO_MAX_CHANNELS) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&synthio_synthesizer_pressed_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_lfos), MP_ROM_PTR(&synthio_synthesizer_lfos_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(synthio_synthesizer_locals_dict, synthio_synthesizer_locals_dict_table);
|
||||
|
||||
|
@ -41,5 +41,7 @@ uint8_t common_hal_synthio_synthesizer_get_bits_per_sample(synthio_synthesizer_o
|
||||
uint8_t common_hal_synthio_synthesizer_get_channel_count(synthio_synthesizer_obj_t *self);
|
||||
void common_hal_synthio_synthesizer_release(synthio_synthesizer_obj_t *self, mp_obj_t to_release);
|
||||
void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_obj_t to_press);
|
||||
void common_hal_synthio_synthesizer_retrigger(synthio_synthesizer_obj_t *self, mp_obj_t to_retrigger);
|
||||
void common_hal_synthio_synthesizer_release_all(synthio_synthesizer_obj_t *self);
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_pressed_notes(synthio_synthesizer_obj_t *self);
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_lfos(synthio_synthesizer_obj_t *self);
|
||||
|
@ -25,8 +25,9 @@
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
#include "shared-bindings/synthio/LFO.h"
|
||||
#include "shared-bindings/synthio/Note.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
#include "shared-module/synthio/Note.h"
|
||||
|
||||
|
||||
@ -36,6 +37,7 @@ void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self,
|
||||
mp_obj_t envelope_obj) {
|
||||
|
||||
synthio_synth_init(&self->synth, sample_rate, channel_count, waveform_obj, filter_obj, envelope_obj);
|
||||
self->lfos = mp_obj_new_list(0, NULL);
|
||||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_deinit(synthio_synthesizer_obj_t *self) {
|
||||
@ -67,7 +69,20 @@ audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_o
|
||||
return GET_BUFFER_ERROR;
|
||||
}
|
||||
self->synth.span.dur = SYNTHIO_MAX_DUR;
|
||||
|
||||
|
||||
synthio_synth_synthesize(&self->synth, buffer, buffer_length, single_channel_output ? channel : 0);
|
||||
|
||||
// free-running LFOs
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(self->lfos, &iter_buf);
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
synthio_lfo_slot_t slot = { .obj = item };
|
||||
// does not error for invalid type, so it's OK that we don't police
|
||||
// list contents
|
||||
(void)synthio_lfo_obj_tick(&slot);
|
||||
}
|
||||
return GET_BUFFER_MORE_DATA;
|
||||
}
|
||||
|
||||
@ -119,6 +134,16 @@ void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_ob
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_retrigger(synthio_synthesizer_obj_t *self, mp_obj_t to_retrigger) {
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_retrigger, &iter_buf);
|
||||
mp_obj_t lfo_obj;
|
||||
while ((lfo_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
synthio_lfo_obj_t *lfo = MP_OBJ_TO_PTR(mp_arg_validate_type(lfo_obj, &synthio_lfo_type, MP_QSTR_retrigger));
|
||||
common_hal_synthio_lfo_retrigger(lfo);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_pressed_notes(synthio_synthesizer_obj_t *self) {
|
||||
int count = 0;
|
||||
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
|
||||
@ -134,3 +159,7 @@ mp_obj_t common_hal_synthio_synthesizer_get_pressed_notes(synthio_synthesizer_ob
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(result);
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_lfos(synthio_synthesizer_obj_t *self) {
|
||||
return self->lfos;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
synthio_synth_t synth;
|
||||
mp_obj_t lfos;
|
||||
} synthio_synthesizer_obj_t;
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user