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:
Jeff Epler 2023-05-16 10:26:56 -05:00
parent e6c5e83a45
commit 0b926f8fd4
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
2 changed files with 55 additions and 18 deletions

View File

@ -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) },

View File

@ -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;