Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions shared-module/synthio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,15 @@ static int find_channel_with_note(synthio_synth_t *synth, mp_obj_t note) {
bool synthio_span_change_note(synthio_synth_t *synth, mp_obj_t old_note, mp_obj_t new_note) {
int channel;
if (new_note != SYNTHIO_SILENCE && (channel = find_channel_with_note(synth, new_note)) != -1) {
// note already playing, re-enter attack phase
synth->envelope_state[channel].state = SYNTHIO_ENVELOPE_STATE_ATTACK;
if (synth->envelope_state[channel].level == 0) {
// released and already decayed to silence, but not yet reaped:
// treat this like a fresh press, not a swell from 0
synthio_envelope_state_init(&synth->envelope_state[channel], synthio_synth_get_note_envelope(synth, new_note));
synth->accum[channel] = 0;
} else {
// note already playing, re-enter attack phase
synth->envelope_state[channel].state = SYNTHIO_ENVELOPE_STATE_ATTACK;
}
return true;
}
channel = find_channel_with_note(synth, old_note);
Expand Down
24 changes: 24 additions & 0 deletions tests/circuitpython/synthio_note_repress_after_decay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# A note whose envelope has decayed to 0 but whose slot hasn't been reaped
# yet should re-press like a fresh note, not silently vanish.
from synthio import Synthesizer, Note, Envelope
from audiocore import get_buffer

# release_time=0 collapses the envelope to level 0 in a single step, while
# the note object still holds its channel.
quick = Envelope(release_time=0)
synth = Synthesizer()
note = Note(440, envelope=quick)

synth.press(note)
get_buffer(synth)
synth.release(note)
get_buffer(synth)
print("pressed after decay:", len(synth.pressed))

synth.press(note)
print("pressed right after re-press:", len(synth.pressed))
get_buffer(synth)
print("pressed after one more render:", len(synth.pressed))
for _ in range(3):
print("{} {:.2f}".format(*synth.note_info(note)))
get_buffer(synth)
6 changes: 6 additions & 0 deletions tests/circuitpython/synthio_note_repress_after_decay.py.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pressed after decay: 0
pressed right after re-press: 1
pressed after one more render: 1
synthio.EnvelopeState.ATTACK 0.46
synthio.EnvelopeState.ATTACK 0.70
synthio.EnvelopeState.ATTACK 0.93
Loading