Skip to content

Commit d2aca7e

Browse files
committed
synthio: fix per-note envelope & envelope modification
.. and simplify the envelope advance logic by handling 'instant' values more intelligently.
1 parent eebd4a7 commit d2aca7e

File tree

4 files changed

+39
-48
lines changed

4 files changed

+39
-48
lines changed

shared-module/synthio/Note.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ mp_obj_t common_hal_synthio_note_get_envelope_obj(synthio_note_obj_t *self) {
105105
void common_hal_synthio_note_set_envelope(synthio_note_obj_t *self, mp_obj_t envelope_in) {
106106
if (envelope_in != mp_const_none) {
107107
mp_arg_validate_type(envelope_in, (mp_obj_type_t *)&synthio_envelope_type_obj, MP_QSTR_envelope);
108+
if (self->sample_rate != 0) {
109+
synthio_envelope_definition_set(&self->envelope_def, envelope_in, self->sample_rate);
110+
}
108111
}
109112
self->envelope_obj = envelope_in;
110113
}

shared-module/synthio/Synthesizer.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,11 @@ void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_ob
110110
mp_obj_t iterable = mp_getiter(to_press, &iter_buf);
111111
mp_obj_t note_obj;
112112
while ((note_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
113-
if (synthio_span_change_note(&self->synth, SYNTHIO_SILENCE, validate_note(note_obj))) {
114-
if (!mp_obj_is_small_int(note_obj)) {
115-
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
116-
synthio_note_start(note, self->synth.sample_rate);
117-
}
113+
if (!mp_obj_is_small_int(note_obj)) {
114+
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
115+
synthio_note_start(note, self->synth.sample_rate);
118116
}
117+
synthio_span_change_note(&self->synth, SYNTHIO_SILENCE, validate_note(note_obj));
119118
}
120119
}
121120

shared-module/synthio/__init__.c

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ STATIC const int16_t square_wave[] = {-32768, 32767};
3737
STATIC const uint16_t notes[] = {8372, 8870, 9397, 9956, 10548, 11175, 11840,
3838
12544, 13290, 14080, 14917, 15804}; // 9th octave
3939

40-
static int32_t round_float_to_int(mp_float_t f) {
40+
STATIC int32_t round_float_to_int(mp_float_t f) {
4141
return (int32_t)(f + MICROPY_FLOAT_CONST(0.5));
4242
}
4343

44-
static int64_t round_float_to_int64(mp_float_t f) {
44+
STATIC int64_t round_float_to_int64(mp_float_t f) {
4545
return (int64_t)(f + MICROPY_FLOAT_CONST(0.5));
4646
}
4747

@@ -55,7 +55,7 @@ STATIC int16_t convert_time_to_rate(uint32_t sample_rate, mp_obj_t time_in, int1
5555
mp_float_t time = mp_obj_get_float(time_in);
5656
int num_samples = (int)MICROPY_FLOAT_C_FUN(round)(time * sample_rate);
5757
if (num_samples == 0) {
58-
return 0;
58+
return 32767;
5959
}
6060
int16_t result = MIN(32767, MAX(1, abs(difference * SYNTHIO_MAX_DUR) / num_samples));
6161
return (difference < 0) ? -result : result;
@@ -102,34 +102,19 @@ STATIC void synthio_envelope_state_step(synthio_envelope_state_t *state, synthio
102102
case SYNTHIO_ENVELOPE_STATE_SUSTAIN:
103103
break;
104104
case SYNTHIO_ENVELOPE_STATE_ATTACK:
105-
if (def->attack_step != 0) {
106-
state->level = MIN(state->level + def->attack_step, def->attack_level);
107-
if (state->level == def->attack_level) {
108-
state->state = SYNTHIO_ENVELOPE_STATE_DECAY;
109-
}
110-
break;
105+
state->level = MIN(state->level + def->attack_step, def->attack_level);
106+
if (state->level == def->attack_level) {
107+
state->state = SYNTHIO_ENVELOPE_STATE_DECAY;
111108
}
112-
state->state = SYNTHIO_ENVELOPE_STATE_DECAY;
113-
MP_FALLTHROUGH;
109+
break;
114110
case SYNTHIO_ENVELOPE_STATE_DECAY:
115-
if (def->decay_step != 0) {
116-
state->level = MAX(state->level + def->decay_step, def->sustain_level);
117-
assert(state->level >= 0);
118-
if (state->level == def->sustain_level) {
119-
state->state = SYNTHIO_ENVELOPE_STATE_SUSTAIN;
120-
}
121-
break;
122-
}
123-
state->state = SYNTHIO_ENVELOPE_STATE_RELEASE;
124-
MP_FALLTHROUGH;
125-
case SYNTHIO_ENVELOPE_STATE_RELEASE:
126-
if (def->release_step != 0) {
127-
int delta = def->release_step;
128-
state->level = MAX(state->level + delta, 0);
129-
} else {
130-
state->level = 0;
111+
state->level = MAX(state->level + def->decay_step, def->sustain_level);
112+
if (state->level == def->sustain_level) {
113+
state->state = SYNTHIO_ENVELOPE_STATE_SUSTAIN;
131114
}
132115
break;
116+
case SYNTHIO_ENVELOPE_STATE_RELEASE:
117+
state->level = MAX(state->level + def->release_step, 0);
133118
}
134119
}
135120
}
@@ -146,23 +131,34 @@ STATIC void synthio_envelope_state_release(synthio_envelope_state_t *state, synt
146131
state->state = SYNTHIO_ENVELOPE_STATE_RELEASE;
147132
}
148133

134+
STATIC synthio_envelope_definition_t *synthio_synth_get_note_envelope(synthio_synth_t *synth, mp_obj_t note_obj) {
135+
synthio_envelope_definition_t *def = &synth->global_envelope_definition;
136+
if (!mp_obj_is_small_int(note_obj)) {
137+
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
138+
if (note->envelope_obj != mp_const_none) {
139+
def = &note->envelope_def;
140+
}
141+
}
142+
return def;
143+
}
144+
149145

150146
STATIC uint32_t synthio_synth_sum_envelope(synthio_synth_t *synth) {
151147
uint32_t result = 0;
152148
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
153-
if (synth->span.note_obj[chan] != SYNTHIO_SILENCE) {
149+
mp_obj_t note_obj = synth->span.note_obj[chan];
150+
if (note_obj != SYNTHIO_SILENCE) {
154151
synthio_envelope_state_t *state = &synth->envelope_state[chan];
155152
if (state->state == SYNTHIO_ENVELOPE_STATE_ATTACK) {
156153
result += state->level;
157154
} else {
158-
result += synth->envelope_definition.attack_level;
155+
result += synthio_synth_get_note_envelope(synth, note_obj)->attack_level;
159156
}
160157
}
161158
}
162159
return result;
163160
}
164161

165-
166162
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
167163

168164
if (channel == synth->other_channel) {
@@ -265,14 +261,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
265261
if (note_obj == SYNTHIO_SILENCE) {
266262
continue;
267263
}
268-
synthio_envelope_definition_t *def = &synth->envelope_definition;
269-
if (!mp_obj_is_small_int(note_obj)) {
270-
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
271-
if (note->envelope_obj != mp_const_none) {
272-
def = &note->envelope_def;
273-
}
274-
}
275-
synthio_envelope_state_step(&synth->envelope_state[chan], def, dur);
264+
synthio_envelope_state_step(&synth->envelope_state[chan], synthio_synth_get_note_envelope(synth, note_obj), dur);
276265
}
277266

278267
*buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE;
@@ -298,7 +287,7 @@ void synthio_synth_deinit(synthio_synth_t *synth) {
298287
}
299288

300289
void synthio_synth_envelope_set(synthio_synth_t *synth, mp_obj_t envelope_obj) {
301-
synthio_envelope_definition_set(&synth->envelope_definition, envelope_obj, synth->sample_rate);
290+
synthio_envelope_definition_set(&synth->global_envelope_definition, envelope_obj, synth->sample_rate);
302291
synth->envelope_obj = envelope_obj;
303292
}
304293

@@ -329,7 +318,7 @@ void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_chan
329318
*spacing = 1;
330319
}
331320

332-
static bool parse_common(mp_buffer_info_t *bufinfo, mp_obj_t o, int16_t what) {
321+
STATIC bool parse_common(mp_buffer_info_t *bufinfo, mp_obj_t o, int16_t what) {
333322
if (o != mp_const_none) {
334323
mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ);
335324
if (bufinfo->typecode != 'h') {
@@ -379,10 +368,10 @@ bool synthio_span_change_note(synthio_synth_t *synth, mp_obj_t old_note, mp_obj_
379368
channel = find_channel_with_note(synth, old_note);
380369
if (channel != -1) {
381370
if (new_note == SYNTHIO_SILENCE) {
382-
synthio_envelope_state_release(&synth->envelope_state[channel], &synth->envelope_definition);
371+
synthio_envelope_state_release(&synth->envelope_state[channel], synthio_synth_get_note_envelope(synth, old_note));
383372
} else {
384373
synth->span.note_obj[channel] = new_note;
385-
synthio_envelope_state_init(&synth->envelope_state[channel], &synth->envelope_definition);
374+
synthio_envelope_state_init(&synth->envelope_state[channel], synthio_synth_get_note_envelope(synth, new_note));
386375
synth->accum[channel] = 0;
387376
}
388377
return true;

shared-module/synthio/__init__.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ typedef struct synthio_synth {
6969
uint16_t last_buffer_length;
7070
uint8_t other_channel, buffer_index, other_buffer_index;
7171
uint16_t waveform_length;
72-
synthio_envelope_definition_t envelope_definition;
72+
synthio_envelope_definition_t global_envelope_definition;
7373
mp_obj_t envelope_obj;
7474
synthio_midi_span_t span;
7575
uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS];

0 commit comments

Comments
 (0)