Skip to content

Commit 383f797

Browse files
authored
Merge pull request #8629 from dcooperdalrymple/synthio-note-loop
Add loop_start and loop_end properties to synthio.Note for waveshaping and sampling capabilities.
2 parents 8c1a365 + 0fe7502 commit 383f797

File tree

7 files changed

+187
-7
lines changed

7 files changed

+187
-7
lines changed

shared-bindings/synthio/Note.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ static const mp_arg_t note_properties[] = {
4040
{ MP_QSTR_amplitude, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1) } },
4141
{ MP_QSTR_bend, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0) } },
4242
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
43+
{ MP_QSTR_waveform_loop_start, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
44+
{ MP_QSTR_waveform_loop_end, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) } },
4345
{ MP_QSTR_envelope, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
4446
{ MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
4547
{ MP_QSTR_ring_frequency, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
4648
{ MP_QSTR_ring_bend, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
4749
{ MP_QSTR_ring_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } },
50+
{ MP_QSTR_ring_waveform_loop_start, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(0) } },
51+
{ MP_QSTR_ring_waveform_loop_end, MP_ARG_OBJ, {.u_obj = MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) } },
4852
};
4953
//| class Note:
5054
//| def __init__(
@@ -53,13 +57,17 @@ static const mp_arg_t note_properties[] = {
5357
//| frequency: float,
5458
//| panning: BlockInput = 0.0,
5559
//| waveform: Optional[ReadableBuffer] = None,
60+
//| waveform_loop_start: int = 0,
61+
//| waveform_loop_end: int = waveform_max_length,
5662
//| envelope: Optional[Envelope] = None,
5763
//| amplitude: BlockInput = 0.0,
5864
//| bend: BlockInput = 0.0,
5965
//| filter: Optional[Biquad] = None,
6066
//| ring_frequency: float = 0.0,
6167
//| ring_bend: float = 0.0,
6268
//| ring_waveform: Optional[ReadableBuffer] = 0.0,
69+
//| ring_waveform_loop_start: int = 0,
70+
//| ring_waveform_loop_end: int = waveform_max_length,
6371
//| ) -> None:
6472
//| """Construct a Note object, with a frequency in Hz, and optional panning, waveform, envelope, tremolo (volume change) and bend (frequency change).
6573
//|
@@ -210,6 +218,53 @@ MP_PROPERTY_GETSET(synthio_note_waveform_obj,
210218
(mp_obj_t)&synthio_note_get_waveform_obj,
211219
(mp_obj_t)&synthio_note_set_waveform_obj);
212220

221+
//| waveform_loop_start: int
222+
//| """The sample index of where to begin looping waveform data.
223+
//|
224+
//| Values outside the range ``0`` to ``waveform_max_length-1`` (inclusive) are rejected with a `ValueError`.
225+
//|
226+
//| Values greater than or equal to the actual waveform length are treated as 0."""
227+
STATIC mp_obj_t synthio_note_get_waveform_loop_start(mp_obj_t self_in) {
228+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
229+
return mp_obj_new_int(common_hal_synthio_note_get_waveform_loop_start(self));
230+
}
231+
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_waveform_loop_start_obj, synthio_note_get_waveform_loop_start);
232+
233+
STATIC mp_obj_t synthio_note_set_waveform_loop_start(mp_obj_t self_in, mp_obj_t arg) {
234+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
235+
common_hal_synthio_note_set_waveform_loop_start(self, mp_obj_get_int(arg));
236+
return mp_const_none;
237+
}
238+
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_waveform_loop_start_obj, synthio_note_set_waveform_loop_start);
239+
MP_PROPERTY_GETSET(synthio_note_waveform_loop_start_obj,
240+
(mp_obj_t)&synthio_note_get_waveform_loop_start_obj,
241+
(mp_obj_t)&synthio_note_set_waveform_loop_start_obj);
242+
243+
//| waveform_loop_end: int
244+
//| """The sample index of where to end looping waveform data.
245+
//|
246+
//| Values outside the range ``1`` to ``waveform_max_length`` (inclusive) are rejected with a `ValueError`.
247+
//|
248+
//| If the value is greater than the actual waveform length, or less than or equal to the loop start, the loop will occur at the end of the waveform.
249+
//|
250+
//| Use the `synthio.waveform_max_length` constant to set the loop point at the end of the wave form, no matter its length."""
251+
//|
252+
STATIC mp_obj_t synthio_note_get_waveform_loop_end(mp_obj_t self_in) {
253+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
254+
return mp_obj_new_int(common_hal_synthio_note_get_waveform_loop_end(self));
255+
}
256+
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_waveform_loop_end_obj, synthio_note_get_waveform_loop_end);
257+
258+
STATIC mp_obj_t synthio_note_set_waveform_loop_end(mp_obj_t self_in, mp_obj_t arg) {
259+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
260+
common_hal_synthio_note_set_waveform_loop_end(self, mp_obj_get_int(arg));
261+
return mp_const_none;
262+
}
263+
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_waveform_loop_end_obj, synthio_note_set_waveform_loop_end);
264+
MP_PROPERTY_GETSET(synthio_note_waveform_loop_end_obj,
265+
(mp_obj_t)&synthio_note_get_waveform_loop_end_obj,
266+
(mp_obj_t)&synthio_note_set_waveform_loop_end_obj);
267+
213268

214269
//| envelope: Envelope
215270
//| """The envelope of this note"""
@@ -296,6 +351,53 @@ MP_PROPERTY_GETSET(synthio_note_ring_waveform_obj,
296351
(mp_obj_t)&synthio_note_get_ring_waveform_obj,
297352
(mp_obj_t)&synthio_note_set_ring_waveform_obj);
298353

354+
//| ring_waveform_loop_start: int
355+
//| """The sample index of where to begin looping waveform data.
356+
//|
357+
//| Values outside the range ``0`` to ``waveform_max_length-1`` (inclusive) are rejected with a `ValueError`.
358+
//|
359+
//| Values greater than or equal to the actual waveform length are treated as 0."""
360+
STATIC mp_obj_t synthio_note_get_ring_waveform_loop_start(mp_obj_t self_in) {
361+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
362+
return mp_obj_new_int(common_hal_synthio_note_get_ring_waveform_loop_start(self));
363+
}
364+
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_ring_waveform_loop_start_obj, synthio_note_get_ring_waveform_loop_start);
365+
366+
STATIC mp_obj_t synthio_note_set_ring_waveform_loop_start(mp_obj_t self_in, mp_obj_t arg) {
367+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
368+
common_hal_synthio_note_set_ring_waveform_loop_start(self, mp_obj_get_int(arg));
369+
return mp_const_none;
370+
}
371+
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_ring_waveform_loop_start_obj, synthio_note_set_ring_waveform_loop_start);
372+
MP_PROPERTY_GETSET(synthio_note_ring_waveform_loop_start_obj,
373+
(mp_obj_t)&synthio_note_get_ring_waveform_loop_start_obj,
374+
(mp_obj_t)&synthio_note_set_ring_waveform_loop_start_obj);
375+
376+
//| ring_waveform_loop_end: int
377+
//| """The sample index of where to end looping waveform data.
378+
//|
379+
//| Values outside the range ``1`` to ``waveform_max_length`` (inclusive) are rejected with a `ValueError`.
380+
//|
381+
//| If the value is greater than the actual waveform length, or less than or equal to the loop start, the loop will occur at the end of the waveform.
382+
//|
383+
//| Use the `synthio.waveform_max_length` constant to set the loop point at the end of the wave form, no matter its length."""
384+
//|
385+
STATIC mp_obj_t synthio_note_get_ring_waveform_loop_end(mp_obj_t self_in) {
386+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
387+
return mp_obj_new_int(common_hal_synthio_note_get_ring_waveform_loop_end(self));
388+
}
389+
MP_DEFINE_CONST_FUN_OBJ_1(synthio_note_get_ring_waveform_loop_end_obj, synthio_note_get_ring_waveform_loop_end);
390+
391+
STATIC mp_obj_t synthio_note_set_ring_waveform_loop_end(mp_obj_t self_in, mp_obj_t arg) {
392+
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
393+
common_hal_synthio_note_set_ring_waveform_loop_end(self, mp_obj_get_int(arg));
394+
return mp_const_none;
395+
}
396+
MP_DEFINE_CONST_FUN_OBJ_2(synthio_note_set_ring_waveform_loop_end_obj, synthio_note_set_ring_waveform_loop_end);
397+
MP_PROPERTY_GETSET(synthio_note_ring_waveform_loop_end_obj,
398+
(mp_obj_t)&synthio_note_get_ring_waveform_loop_end_obj,
399+
(mp_obj_t)&synthio_note_set_ring_waveform_loop_end_obj);
400+
299401

300402

301403
static void note_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -308,12 +410,16 @@ STATIC const mp_rom_map_elem_t synthio_note_locals_dict_table[] = {
308410
{ MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&synthio_note_filter_obj) },
309411
{ MP_ROM_QSTR(MP_QSTR_panning), MP_ROM_PTR(&synthio_note_panning_obj) },
310412
{ MP_ROM_QSTR(MP_QSTR_waveform), MP_ROM_PTR(&synthio_note_waveform_obj) },
413+
{ MP_ROM_QSTR(MP_QSTR_waveform_loop_start), MP_ROM_PTR(&synthio_note_waveform_loop_start_obj) },
414+
{ MP_ROM_QSTR(MP_QSTR_waveform_loop_end), MP_ROM_PTR(&synthio_note_waveform_loop_end_obj) },
311415
{ MP_ROM_QSTR(MP_QSTR_envelope), MP_ROM_PTR(&synthio_note_envelope_obj) },
312416
{ MP_ROM_QSTR(MP_QSTR_amplitude), MP_ROM_PTR(&synthio_note_amplitude_obj) },
313417
{ MP_ROM_QSTR(MP_QSTR_bend), MP_ROM_PTR(&synthio_note_bend_obj) },
314418
{ MP_ROM_QSTR(MP_QSTR_ring_frequency), MP_ROM_PTR(&synthio_note_ring_frequency_obj) },
315419
{ MP_ROM_QSTR(MP_QSTR_ring_bend), MP_ROM_PTR(&synthio_note_ring_bend_obj) },
316420
{ MP_ROM_QSTR(MP_QSTR_ring_waveform), MP_ROM_PTR(&synthio_note_ring_waveform_obj) },
421+
{ MP_ROM_QSTR(MP_QSTR_ring_waveform_loop_start), MP_ROM_PTR(&synthio_note_ring_waveform_loop_start_obj) },
422+
{ MP_ROM_QSTR(MP_QSTR_ring_waveform_loop_end), MP_ROM_PTR(&synthio_note_ring_waveform_loop_end_obj) },
317423
};
318424
STATIC MP_DEFINE_CONST_DICT(synthio_note_locals_dict, synthio_note_locals_dict_table);
319425

shared-bindings/synthio/Note.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ void common_hal_synthio_note_set_bend(synthio_note_obj_t *self, mp_obj_t value);
2424
mp_obj_t common_hal_synthio_note_get_waveform_obj(synthio_note_obj_t *self);
2525
void common_hal_synthio_note_set_waveform(synthio_note_obj_t *self, mp_obj_t value);
2626

27+
mp_int_t common_hal_synthio_note_get_waveform_loop_start(synthio_note_obj_t *self);
28+
void common_hal_synthio_note_set_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in);
29+
30+
mp_int_t common_hal_synthio_note_get_waveform_loop_end(synthio_note_obj_t *self);
31+
void common_hal_synthio_note_set_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in);
32+
2733
mp_float_t common_hal_synthio_note_get_ring_frequency(synthio_note_obj_t *self);
2834
void common_hal_synthio_note_set_ring_frequency(synthio_note_obj_t *self, mp_float_t value);
2935

@@ -33,5 +39,11 @@ void common_hal_synthio_note_set_ring_bend(synthio_note_obj_t *self, mp_obj_t va
3339
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self);
3440
void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_t value);
3541

42+
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_start(synthio_note_obj_t *self);
43+
void common_hal_synthio_note_set_ring_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in);
44+
45+
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_end(synthio_note_obj_t *self);
46+
void common_hal_synthio_note_set_ring_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in);
47+
3648
mp_obj_t common_hal_synthio_note_get_envelope_obj(synthio_note_obj_t *self);
3749
void common_hal_synthio_note_set_envelope(synthio_note_obj_t *self, mp_obj_t value);

shared-bindings/synthio/__init__.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ STATIC mp_obj_t voct_to_hz(mp_obj_t arg) {
304304
}
305305
MP_DEFINE_CONST_FUN_OBJ_1(synthio_voct_to_hz_obj, voct_to_hz);
306306

307+
//|
308+
//| waveform_max_length: int
309+
//| """The maximum number of samples permitted in a waveform"""
310+
//|
311+
307312
#if CIRCUITPY_AUDIOCORE_DEBUG
308313
STATIC mp_obj_t synthio_lfo_tick(size_t n, const mp_obj_t *args) {
309314
shared_bindings_synthio_lfo_tick(48000);
@@ -333,6 +338,7 @@ STATIC const mp_rom_map_elem_t synthio_module_globals_table[] = {
333338
{ MP_ROM_QSTR(MP_QSTR_Envelope), MP_ROM_PTR(&synthio_envelope_type_obj) },
334339
{ MP_ROM_QSTR(MP_QSTR_midi_to_hz), MP_ROM_PTR(&synthio_midi_to_hz_obj) },
335340
{ MP_ROM_QSTR(MP_QSTR_voct_to_hz), MP_ROM_PTR(&synthio_voct_to_hz_obj) },
341+
{ MP_ROM_QSTR(MP_QSTR_waveform_max_length), MP_ROM_INT(SYNTHIO_WAVEFORM_SIZE) },
336342
#if CIRCUITPY_AUDIOCORE_DEBUG
337343
{ MP_ROM_QSTR(MP_QSTR_lfo_tick), MP_ROM_PTR(&synthio_lfo_tick_obj) },
338344
#endif

shared-bindings/synthio/__init__.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "py/objnamedtuple.h"
3030
#include "py/enum.h"
3131

32+
#define SYNTHIO_WAVEFORM_SIZE 16384
33+
3234
typedef enum {
3335
SYNTHIO_ENVELOPE_STATE_ATTACK, SYNTHIO_ENVELOPE_STATE_DECAY,
3436
SYNTHIO_ENVELOPE_STATE_SUSTAIN, SYNTHIO_ENVELOPE_STATE_RELEASE

shared-module/synthio/Note.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,24 @@ void common_hal_synthio_note_set_waveform(synthio_note_obj_t *self, mp_obj_t wav
120120
self->waveform_obj = waveform_in;
121121
}
122122

123+
mp_int_t common_hal_synthio_note_get_waveform_loop_start(synthio_note_obj_t *self) {
124+
return self->waveform_loop_start;
125+
}
126+
127+
void common_hal_synthio_note_set_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in) {
128+
mp_int_t val = mp_arg_validate_int_range(value_in, 0, SYNTHIO_WAVEFORM_SIZE - 1, MP_QSTR_waveform_loop_start);
129+
self->waveform_loop_start = val;
130+
}
131+
132+
mp_int_t common_hal_synthio_note_get_waveform_loop_end(synthio_note_obj_t *self) {
133+
return self->waveform_loop_end;
134+
}
135+
136+
void common_hal_synthio_note_set_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in) {
137+
mp_int_t val = mp_arg_validate_int_range(value_in, 1, SYNTHIO_WAVEFORM_SIZE, MP_QSTR_waveform_loop_end);
138+
self->waveform_loop_end = val;
139+
}
140+
123141
mp_obj_t common_hal_synthio_note_get_ring_waveform_obj(synthio_note_obj_t *self) {
124142
return self->ring_waveform_obj;
125143
}
@@ -135,6 +153,24 @@ void common_hal_synthio_note_set_ring_waveform(synthio_note_obj_t *self, mp_obj_
135153
self->ring_waveform_obj = ring_waveform_in;
136154
}
137155

156+
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_start(synthio_note_obj_t *self) {
157+
return self->ring_waveform_loop_start;
158+
}
159+
160+
void common_hal_synthio_note_set_ring_waveform_loop_start(synthio_note_obj_t *self, mp_int_t value_in) {
161+
mp_int_t val = mp_arg_validate_int_range(value_in, 0, SYNTHIO_WAVEFORM_SIZE - 1, MP_QSTR_ring_waveform_loop_start);
162+
self->ring_waveform_loop_start = val;
163+
}
164+
165+
mp_int_t common_hal_synthio_note_get_ring_waveform_loop_end(synthio_note_obj_t *self) {
166+
return self->ring_waveform_loop_end;
167+
}
168+
169+
void common_hal_synthio_note_set_ring_waveform_loop_end(synthio_note_obj_t *self, mp_int_t value_in) {
170+
mp_int_t val = mp_arg_validate_int_range(value_in, 1, SYNTHIO_WAVEFORM_SIZE, MP_QSTR_ring_waveform_loop_end);
171+
self->ring_waveform_loop_end = val;
172+
}
173+
138174
void synthio_note_recalculate(synthio_note_obj_t *self, int32_t sample_rate) {
139175
if (sample_rate == self->sample_rate) {
140176
return;

shared-module/synthio/Note.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ typedef struct synthio_note_obj {
4848
int32_t ring_frequency_scaled, ring_frequency_bent;
4949

5050
mp_buffer_info_t waveform_buf;
51+
uint32_t waveform_loop_start, waveform_loop_end;
5152
mp_buffer_info_t ring_waveform_buf;
53+
uint32_t ring_waveform_loop_start, ring_waveform_loop_end;
5254
synthio_envelope_definition_t envelope_def;
5355
} synthio_note_obj_t;
5456

shared-module/synthio/__init__.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,12 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
180180

181181
uint32_t dds_rate;
182182
const int16_t *waveform = synth->waveform_bufinfo.buf;
183+
uint32_t waveform_start = 0;
183184
uint32_t waveform_length = synth->waveform_bufinfo.len;
184185

185186
uint32_t ring_dds_rate = 0;
186187
const int16_t *ring_waveform = NULL;
188+
uint32_t ring_waveform_start = 0;
187189
uint32_t ring_waveform_length = 0;
188190

189191
if (mp_obj_is_small_int(note_obj)) {
@@ -202,19 +204,32 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
202204
if (note->waveform_buf.buf) {
203205
waveform = note->waveform_buf.buf;
204206
waveform_length = note->waveform_buf.len;
207+
if (note->waveform_loop_start > 0 && note->waveform_loop_start < waveform_length) {
208+
waveform_start = note->waveform_loop_start;
209+
}
210+
if (note->waveform_loop_end > waveform_start && note->waveform_loop_end < waveform_length) {
211+
waveform_length = note->waveform_loop_end;
212+
}
205213
}
206-
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * waveform_length, sample_rate);
214+
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * (waveform_length - waveform_start), sample_rate);
207215
if (note->ring_frequency_scaled != 0 && note->ring_waveform_buf.buf) {
208216
ring_waveform = note->ring_waveform_buf.buf;
209217
ring_waveform_length = note->ring_waveform_buf.len;
210-
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_bent * ring_waveform_length, sample_rate);
218+
if (note->ring_waveform_loop_start > 0 && note->ring_waveform_loop_start < ring_waveform_length) {
219+
ring_waveform_start = note->waveform_loop_start;
220+
}
221+
if (note->ring_waveform_loop_end > ring_waveform_start && note->ring_waveform_loop_end < ring_waveform_length) {
222+
ring_waveform_length = note->ring_waveform_loop_end;
223+
}
224+
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_bent * (ring_waveform_length - ring_waveform_start), sample_rate);
211225
uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
212226
if (ring_dds_rate > lim / sizeof(int16_t)) {
213227
ring_dds_rate = 0; // can't ring at that frequency
214228
}
215229
}
216230
}
217231

232+
uint32_t offset = waveform_start << SYNTHIO_FREQUENCY_SHIFT;
218233
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
219234
uint32_t accum = synth->accum[chan];
220235

@@ -225,15 +240,15 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
225240

226241
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
227242
if (accum > lim) {
228-
accum %= lim;
243+
accum = accum % lim + offset;
229244
}
230245

231246
// first, fill with waveform
232247
for (uint16_t i = 0; i < dur; i++) {
233248
accum += dds_rate;
234249
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
235250
if (accum > lim) {
236-
accum -= lim;
251+
accum = accum - lim + offset;
237252
}
238253
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
239254
out_buffer32[i] = waveform[idx];
@@ -249,18 +264,19 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou
249264

250265
// now modulate by ring and accumulate
251266
accum = synth->ring_accum[chan];
267+
offset = ring_waveform_start << SYNTHIO_FREQUENCY_SHIFT;
252268
lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
253269

254270
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
255271
if (accum > lim) {
256-
accum %= lim;
272+
accum = accum % lim + offset;
257273
}
258274

259275
for (uint16_t i = 0; i < dur; i++) {
260276
accum += ring_dds_rate;
261277
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
262278
if (accum > lim) {
263-
accum -= lim;
279+
accum = accum - lim + offset;
264280
}
265281
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
266282
int16_t wi = (ring_waveform[idx] * out_buffer32[i]) / 32768;
@@ -434,7 +450,7 @@ STATIC void parse_common(mp_buffer_info_t *bufinfo, mp_obj_t o, int16_t what, mp
434450

435451
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj) {
436452
*bufinfo_waveform = ((mp_buffer_info_t) { .buf = (void *)square_wave, .len = 2 });
437-
parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, 16384);
453+
parse_common(bufinfo_waveform, waveform_obj, MP_QSTR_waveform, SYNTHIO_WAVEFORM_SIZE);
438454
}
439455

440456
STATIC int find_channel_with_note(synthio_synth_t *synth, mp_obj_t note) {

0 commit comments

Comments
 (0)