Skip to content

Commit 62e6de8

Browse files
committed
synthio: Factor out synth_note_into_buffer, start adding filter buffer
1 parent 9d8dcf7 commit 62e6de8

File tree

2 files changed

+141
-132
lines changed

2 files changed

+141
-132
lines changed

shared-module/synthio/__init__.c

Lines changed: 139 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -171,160 +171,167 @@ int16_t mix_down_sample(int32_t sample) {
171171
return sample;
172172
}
173173

174-
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
174+
static void synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *out_buffer32, int16_t dur) {
175+
mp_obj_t note_obj = synth->span.note_obj[chan];
175176

176-
if (channel == synth->other_channel) {
177-
*buffer_length = synth->last_buffer_length;
178-
*bufptr = (uint8_t *)(synth->buffers[synth->other_buffer_index] + channel);
177+
if (note_obj == SYNTHIO_SILENCE) {
178+
synth->accum[chan] = 0;
179179
return;
180180
}
181181

182-
synth->buffer_index = !synth->buffer_index;
183-
synth->other_channel = 1 - channel;
184-
synth->other_buffer_index = synth->buffer_index;
185-
186-
uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur);
187-
synth->span.dur -= dur;
182+
if (synth->envelope_state[chan].level == 0) {
183+
// note is truly finished, but we only just noticed
184+
synth->span.note_obj[chan] = SYNTHIO_SILENCE;
185+
return;
186+
}
188187

189188
int32_t sample_rate = synth->sample_rate;
190-
int32_t out_buffer32[dur * synth->channel_count];
191-
192-
memset(out_buffer32, 0, sizeof(out_buffer32));
193-
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
194-
mp_obj_t note_obj = synth->span.note_obj[chan];
195-
if (note_obj == SYNTHIO_SILENCE) {
196-
synth->accum[chan] = 0;
197-
continue;
198-
}
199189

200-
if (synth->envelope_state[chan].level == 0) {
201-
// note is truly finished, but we only just noticed
202-
synth->span.note_obj[chan] = SYNTHIO_SILENCE;
203-
continue;
190+
// adjust loudness by envelope
191+
uint16_t loudness[2] = {synth->envelope_state[chan].level,synth->envelope_state[chan].level};
192+
193+
uint32_t dds_rate;
194+
const int16_t *waveform = synth->waveform_bufinfo.buf;
195+
uint32_t waveform_length = synth->waveform_bufinfo.len / 2;
196+
197+
uint32_t ring_dds_rate = 0;
198+
const int16_t *ring_waveform = NULL;
199+
uint32_t ring_waveform_length = 0;
200+
201+
if (mp_obj_is_small_int(note_obj)) {
202+
uint8_t note = mp_obj_get_int(note_obj);
203+
uint8_t octave = note / 12;
204+
uint16_t base_freq = notes[note % 12];
205+
// rate = base_freq * waveform_length
206+
// den = sample_rate * 2 ^ (10 - octave)
207+
// den = sample_rate * 2 ^ 10 / 2^octave
208+
// dds_rate = 2^SHIFT * rate / den
209+
// dds_rate = 2^(SHIFT-10+octave) * base_freq * waveform_length / sample_rate
210+
dds_rate = (sample_rate / 2 + ((uint64_t)(base_freq * waveform_length) << (SYNTHIO_FREQUENCY_SHIFT - 10 + octave))) / sample_rate;
211+
} else {
212+
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
213+
int32_t frequency_scaled = synthio_note_step(note, sample_rate, dur, loudness);
214+
if (note->waveform_buf.buf) {
215+
waveform = note->waveform_buf.buf;
216+
waveform_length = note->waveform_buf.len / 2;
204217
}
205-
206-
// adjust loudness by envelope
207-
uint16_t loudness[2] = {synth->envelope_state[chan].level,synth->envelope_state[chan].level};
208-
209-
uint32_t dds_rate;
210-
const int16_t *waveform = synth->waveform;
211-
uint32_t waveform_length = synth->waveform_length;
212-
213-
uint32_t ring_dds_rate = 0;
214-
const int16_t *ring_waveform = NULL;
215-
uint32_t ring_waveform_length = 0;
216-
217-
if (mp_obj_is_small_int(note_obj)) {
218-
uint8_t note = mp_obj_get_int(note_obj);
219-
uint8_t octave = note / 12;
220-
uint16_t base_freq = notes[note % 12];
221-
// rate = base_freq * waveform_length
222-
// den = sample_rate * 2 ^ (10 - octave)
223-
// den = sample_rate * 2 ^ 10 / 2^octave
224-
// dds_rate = 2^SHIFT * rate / den
225-
// dds_rate = 2^(SHIFT-10+octave) * base_freq * waveform_length / sample_rate
226-
dds_rate = (sample_rate / 2 + ((uint64_t)(base_freq * waveform_length) << (SYNTHIO_FREQUENCY_SHIFT - 10 + octave))) / sample_rate;
227-
} else {
228-
synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj);
229-
int32_t frequency_scaled = synthio_note_step(note, sample_rate, dur, loudness);
230-
if (note->waveform_buf.buf) {
231-
waveform = note->waveform_buf.buf;
232-
waveform_length = note->waveform_buf.len / 2;
233-
}
234-
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * waveform_length, sample_rate);
235-
if (note->ring_frequency_scaled != 0 && note->ring_waveform_buf.buf) {
236-
ring_waveform = note->ring_waveform_buf.buf;
237-
ring_waveform_length = note->ring_waveform_buf.len / 2;
238-
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_scaled * ring_waveform_length, sample_rate);
239-
uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
240-
if (ring_dds_rate > lim / 2) {
241-
ring_dds_rate = 0; // can't ring at that frequency
242-
}
218+
dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)frequency_scaled * waveform_length, sample_rate);
219+
if (note->ring_frequency_scaled != 0 && note->ring_waveform_buf.buf) {
220+
ring_waveform = note->ring_waveform_buf.buf;
221+
ring_waveform_length = note->ring_waveform_buf.len / 2;
222+
ring_dds_rate = synthio_frequency_convert_scaled_to_dds((uint64_t)note->ring_frequency_scaled * ring_waveform_length, sample_rate);
223+
uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
224+
if (ring_dds_rate > lim / 2) {
225+
ring_dds_rate = 0; // can't ring at that frequency
243226
}
244227
}
228+
}
245229

246-
int synth_chan = synth->channel_count;
247-
if (ring_dds_rate) {
248-
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
249-
uint32_t accum = synth->accum[chan];
230+
int synth_chan = synth->channel_count;
231+
if (ring_dds_rate) {
232+
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
233+
uint32_t accum = synth->accum[chan];
250234

251-
if (dds_rate > lim / 2) {
252-
// beyond nyquist, can't play note
253-
continue;
254-
}
235+
if (dds_rate > lim / 2) {
236+
// beyond nyquist, can't play note
237+
return;
238+
}
255239

256-
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
240+
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
241+
if (accum > lim) {
242+
accum %= lim;
243+
}
244+
245+
int32_t ring_buffer[dur];
246+
// first, fill with waveform
247+
for (uint16_t i = 0; i < dur; i++) {
248+
accum += dds_rate;
249+
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
257250
if (accum > lim) {
258-
accum %= lim;
251+
accum -= lim;
259252
}
253+
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
254+
ring_buffer[i] = waveform[idx];
255+
}
256+
synth->accum[chan] = accum;
260257

261-
int32_t ring_buffer[dur];
262-
// first, fill with waveform
263-
for (uint16_t i = 0; i < dur; i++) {
264-
accum += dds_rate;
265-
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
266-
if (accum > lim) {
267-
accum -= lim;
268-
}
269-
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
270-
ring_buffer[i] = waveform[idx];
271-
}
272-
synth->accum[chan] = accum;
258+
// now modulate by ring and accumulate
259+
accum = synth->ring_accum[chan];
260+
lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
273261

274-
// now modulate by ring and accumulate
275-
accum = synth->ring_accum[chan];
276-
lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT;
262+
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
263+
if (accum > lim) {
264+
accum %= lim;
265+
}
277266

278-
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
267+
for (uint16_t i = 0, j = 0; i < dur; i++) {
268+
accum += ring_dds_rate;
269+
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
279270
if (accum > lim) {
280-
accum %= lim;
271+
accum -= lim;
281272
}
282-
283-
for (uint16_t i = 0, j = 0; i < dur; i++) {
284-
accum += ring_dds_rate;
285-
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
286-
if (accum > lim) {
287-
accum -= lim;
288-
}
289-
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
290-
int16_t wi = (ring_waveform[idx] * ring_buffer[i]) / 32768;
291-
for (int c = 0; c < synth_chan; c++) {
292-
out_buffer32[j] += (wi * loudness[c]) / 32768;
293-
j++;
294-
}
273+
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
274+
int16_t wi = (ring_waveform[idx] * ring_buffer[i]) / 32768;
275+
for (int c = 0; c < synth_chan; c++) {
276+
out_buffer32[j] += (wi * loudness[c]) / 32768;
277+
j++;
295278
}
296-
synth->ring_accum[chan] = accum;
297-
} else {
298-
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
299-
uint32_t accum = synth->accum[chan];
279+
}
280+
synth->ring_accum[chan] = accum;
281+
} else {
282+
uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT;
283+
uint32_t accum = synth->accum[chan];
300284

301-
if (dds_rate > lim / 2) {
302-
// beyond nyquist, can't play note
303-
continue;
304-
}
285+
if (dds_rate > lim / 2) {
286+
// beyond nyquist, can't play note
287+
return;
288+
}
305289

306-
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
290+
// can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
291+
if (accum > lim) {
292+
accum %= lim;
293+
}
294+
295+
for (uint16_t i = 0, j = 0; i < dur; i++) {
296+
accum += dds_rate;
297+
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
307298
if (accum > lim) {
308-
accum %= lim;
299+
accum -= lim;
309300
}
310-
311-
for (uint16_t i = 0, j = 0; i < dur; i++) {
312-
accum += dds_rate;
313-
// because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
314-
if (accum > lim) {
315-
accum -= lim;
316-
}
317-
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
318-
int16_t wi = waveform[idx];
319-
for (int c = 0; c < synth_chan; c++) {
320-
out_buffer32[j] += (wi * loudness[c]) / 65536;
321-
j++;
322-
}
301+
int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT;
302+
int16_t wi = waveform[idx];
303+
for (int c = 0; c < synth_chan; c++) {
304+
out_buffer32[j] += (wi * loudness[c]) / 65536;
305+
j++;
323306
}
324-
synth->accum[chan] = accum;
325307
}
308+
synth->accum[chan] = accum;
309+
}
310+
}
311+
312+
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
313+
314+
if (channel == synth->other_channel) {
315+
*buffer_length = synth->last_buffer_length;
316+
*bufptr = (uint8_t *)(synth->buffers[synth->other_buffer_index] + channel);
317+
return;
326318
}
327319

320+
synth->buffer_index = !synth->buffer_index;
321+
synth->other_channel = 1 - channel;
322+
synth->other_buffer_index = synth->buffer_index;
323+
324+
uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur);
325+
synth->span.dur -= dur;
326+
327+
int32_t out_buffer32[dur * synth->channel_count];
328+
329+
memset(out_buffer32, 0, sizeof(out_buffer32));
330+
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
331+
synth_note_into_buffer(synth, chan, out_buffer32, dur);
332+
}
333+
334+
328335
int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index];
329336

330337
// mix down audio
@@ -358,8 +365,7 @@ bool synthio_synth_deinited(synthio_synth_t *synth) {
358365
}
359366

360367
void synthio_synth_deinit(synthio_synth_t *synth) {
361-
m_del(uint8_t, synth->buffers[0], synth->buffer_length);
362-
m_del(uint8_t, synth->buffers[1], synth->buffer_length);
368+
synth->filter_buffer = NULL;
363369
synth->buffers[0] = NULL;
364370
synth->buffers[1] = NULL;
365371
}
@@ -374,15 +380,19 @@ mp_obj_t synthio_synth_envelope_get(synthio_synth_t *synth) {
374380
}
375381

376382
void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t filter_obj, mp_obj_t envelope_obj) {
383+
synthio_synth_parse_waveform(&synth->waveform_bufinfo, waveform_obj);
384+
synthio_synth_parse_filter(&synth->filter_bufinfo, filter_obj);
377385
mp_arg_validate_int_range(channel_count, 1, 2, MP_QSTR_channel_count);
378386
synth->buffer_length = SYNTHIO_MAX_DUR * SYNTHIO_BYTES_PER_SAMPLE * channel_count;
379387
synth->buffers[0] = m_malloc(synth->buffer_length, false);
380388
synth->buffers[1] = m_malloc(synth->buffer_length, false);
389+
if (synth->filter_bufinfo.len) {
390+
synth->filter_buffer_length = (synth->filter_bufinfo.len + SYNTHIO_MAX_DUR) * channel_count * sizeof(int32_t);
391+
synth->filter_buffer = m_malloc(synth->filter_buffer_length, false);
392+
}
381393
synth->channel_count = channel_count;
382394
synth->other_channel = -1;
383395
synth->waveform_obj = waveform_obj;
384-
synthio_synth_parse_waveform(&synth->waveform_bufinfo, waveform_obj);
385-
synthio_synth_parse_filter(&synth->filter_bufinfo, filter_obj);
386396
synth->sample_rate = sample_rate;
387397
synthio_synth_envelope_set(synth, envelope_obj);
388398

shared-module/synthio/__init__.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,11 @@ typedef struct synthio_synth {
6464
uint32_t sample_rate;
6565
uint32_t total_envelope;
6666
int16_t *buffers[2];
67-
const int16_t *waveform;
67+
int32_t *filter_buffer;
6868
uint8_t channel_count;
69-
uint16_t buffer_length;
69+
uint16_t buffer_length, filter_buffer_length;
7070
uint16_t last_buffer_length;
7171
uint8_t other_channel, buffer_index, other_buffer_index;
72-
uint16_t waveform_length;
7372
mp_buffer_info_t waveform_bufinfo, filter_bufinfo;
7473
synthio_envelope_definition_t global_envelope_definition;
7574
mp_obj_t waveform_obj, filter_obj, envelope_obj;

0 commit comments

Comments
 (0)