synthio: improve release/press/change
Semi-incompatible name change: The method `release_then_press` is now `change`. For now a compatibility alias is supported. Everywhere a `NoteSequence` was accepted, a single note is now accepted. So for instance, `synth.press(30)` can be written instead of requiring ``synth.press((30,))`. The same goes for `change.retrigger`, which will accept a single LFO or a sequence.
This commit is contained in:
parent
e6c5e83a45
commit
0b926f8fd4
|
@ -38,7 +38,11 @@
|
|||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
//| NoteSequence = Sequence[Union[int, Note]]
|
||||
//| """A sequence of notes, which can each be integer MIDI notes or `Note` objects"""
|
||||
//| """A sequence of notes, which can each be integer MIDI note numbers or `Note` objects"""
|
||||
//| NoteOrNoteSequence = Union[int, Note, NoteSequence]
|
||||
//| """A note or sequence of notes"""
|
||||
//| LFOOrLFOSequence = Union["LFO", Sequence["LFO"]]
|
||||
//| """An LFO or a sequence of LFOs"""
|
||||
//|
|
||||
//| class Synthesizer:
|
||||
//| def __init__(
|
||||
|
@ -94,12 +98,12 @@ STATIC void check_for_deinit(synthio_synthesizer_obj_t *self) {
|
|||
}
|
||||
}
|
||||
|
||||
//| def press(self, /, press: NoteSequence = ()) -> None:
|
||||
//| def press(self, /, press: NoteOrNoteSequence = ()) -> None:
|
||||
//| """Turn some notes on.
|
||||
//|
|
||||
//| Pressing a note that was already pressed has no effect.
|
||||
//|
|
||||
//| :param NoteSequence press: Any sequence of notes."""
|
||||
//| :param NoteOrNoteSequence press: Any sequence of notes."""
|
||||
STATIC mp_obj_t synthio_synthesizer_press(mp_obj_t self_in, mp_obj_t press) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
|
@ -107,12 +111,12 @@ STATIC mp_obj_t synthio_synthesizer_press(mp_obj_t self_in, mp_obj_t press) {
|
|||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(synthio_synthesizer_press_obj, synthio_synthesizer_press);
|
||||
//| def release(self, /, release: NoteSequence = ()) -> None:
|
||||
//| def release(self, /, release: NoteOrNoteSequence = ()) -> None:
|
||||
//| """Turn some notes off.
|
||||
//|
|
||||
//| Releasing a note that was already released has no effect.
|
||||
//|
|
||||
//| :param NoteSequence release: Any sequence of notes."""
|
||||
//| :param NoteOrNoteSequence release: Any sequence of notes."""
|
||||
STATIC mp_obj_t synthio_synthesizer_release(mp_obj_t self_in, mp_obj_t release) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
|
@ -121,10 +125,15 @@ 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 = (), retrigger=LFOSequence
|
||||
//| def change(
|
||||
//| self,
|
||||
//| release: NoteOrNoteSequence = (),
|
||||
//| press: NoteOrNoteSequence = (),
|
||||
//| retrigger=LFOOrLFOSequence,
|
||||
//| ) -> None:
|
||||
//| """Turn some notes on and/or off.
|
||||
//| """Start notes, stop them, and/or re-trigger some LFOs.
|
||||
//|
|
||||
//| The changes all happen atomically with respect to output generation.
|
||||
//|
|
||||
//| It is OK to release note that was not actually turned on.
|
||||
//|
|
||||
|
@ -135,10 +144,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(synthio_synthesizer_release_obj, synthio_synthe
|
|||
//|
|
||||
//| 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 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) {
|
||||
//| :param NoteOrNoteSequence release: Any sequence of notes.
|
||||
//| :param NoteOrNoteSequence press: Any sequence of notes.
|
||||
//| :param LFOOrLFOSequence retrigger: Any sequence of LFOs.
|
||||
//|
|
||||
//| Note: for compatibility, ``release_then_press`` may be used as an alias
|
||||
//| for this function. This compatibility name will be removed in 9.0."""
|
||||
STATIC mp_obj_t synthio_synthesizer_change(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
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 } },
|
||||
|
@ -156,16 +168,16 @@ STATIC mp_obj_t synthio_synthesizer_release_then_press(mp_uint_t n_args, const m
|
|||
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);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(synthio_synthesizer_change_obj, 1, synthio_synthesizer_change);
|
||||
|
||||
//
|
||||
//| def release_all_then_press(self, /, press: NoteSequence) -> None:
|
||||
//| def release_all_then_press(self, /, press: NoteOrNoteSequence) -> None:
|
||||
//| """Turn any currently-playing notes off, then turn on the given notes
|
||||
//|
|
||||
//| 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.
|
||||
//| Releasing a note and immediately pressing it again returns it to the
|
||||
//| attack phase with an initial amplitude of 0.
|
||||
//|
|
||||
//| :param NoteSequence press: Any sequence of notes."""
|
||||
//| :param NoteOrNoteSequence press: Any sequence of notes."""
|
||||
STATIC mp_obj_t synthio_synthesizer_release_all_then_press(mp_obj_t self_in, mp_obj_t press) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
|
@ -284,7 +296,8 @@ STATIC const mp_rom_map_elem_t synthio_synthesizer_locals_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_press), MP_ROM_PTR(&synthio_synthesizer_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&synthio_synthesizer_release_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_all), MP_ROM_PTR(&synthio_synthesizer_release_all_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_then_press), MP_ROM_PTR(&synthio_synthesizer_release_then_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_change), MP_ROM_PTR(&synthio_synthesizer_change_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_then_press), MP_ROM_PTR(&synthio_synthesizer_change_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_all_then_press), MP_ROM_PTR(&synthio_synthesizer_release_all_then_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&synthio_synthesizer_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||
|
|
|
@ -99,6 +99,10 @@ void common_hal_synthio_synthesizer_release_all(synthio_synthesizer_obj_t *self)
|
|||
}
|
||||
}
|
||||
|
||||
STATIC bool is_note(mp_obj_t note_in) {
|
||||
return mp_obj_is_small_int(note_in) || mp_obj_is_type(note_in, &synthio_note_type);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t validate_note(mp_obj_t note_in) {
|
||||
if (mp_obj_is_small_int(note_in)) {
|
||||
mp_arg_validate_int_range(mp_obj_get_int(note_in), 0, 127, MP_QSTR_note);
|
||||
|
@ -112,6 +116,11 @@ STATIC mp_obj_t validate_note(mp_obj_t note_in) {
|
|||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_release(synthio_synthesizer_obj_t *self, mp_obj_t to_release) {
|
||||
if (is_note(to_release)) {
|
||||
synthio_span_change_note(&self->synth, validate_note(to_release), SYNTHIO_SILENCE);
|
||||
return;
|
||||
}
|
||||
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_release, &iter_buf);
|
||||
mp_obj_t item;
|
||||
|
@ -121,6 +130,15 @@ void common_hal_synthio_synthesizer_release(synthio_synthesizer_obj_t *self, mp_
|
|||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_obj_t to_press) {
|
||||
if (is_note(to_press)) {
|
||||
if (!mp_obj_is_small_int(to_press)) {
|
||||
synthio_note_obj_t *note = MP_OBJ_TO_PTR(to_press);
|
||||
synthio_note_start(note, self->synth.sample_rate);
|
||||
}
|
||||
synthio_span_change_note(&self->synth, SYNTHIO_SILENCE, validate_note(to_press));
|
||||
return;
|
||||
}
|
||||
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_press, &iter_buf);
|
||||
mp_obj_t note_obj;
|
||||
|
@ -135,6 +153,12 @@ 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) {
|
||||
if (mp_obj_is_type(to_retrigger, &synthio_lfo_type)) {
|
||||
synthio_lfo_obj_t *lfo = MP_OBJ_TO_PTR(mp_arg_validate_type(to_retrigger, &synthio_lfo_type, MP_QSTR_retrigger));
|
||||
common_hal_synthio_lfo_retrigger(lfo);
|
||||
return;
|
||||
}
|
||||
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_retrigger, &iter_buf);
|
||||
mp_obj_t lfo_obj;
|
||||
|
|
Loading…
Reference in New Issue