synthio: support audio outputs that need double buffering

closes #7837

tested on rp2040 pico w on pico dv shield
This commit is contained in:
Jeff Epler 2023-04-05 11:55:54 -05:00
parent 9679aaa0be
commit 04f4092e11
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
4 changed files with 43 additions and 16 deletions

View File

@ -156,7 +156,7 @@ uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *
void synthio_miditrack_reset_buffer(synthio_miditrack_obj_t *self,
bool single_channel_output, uint8_t channel) {
synthio_synth_reset_buffer(&self->synth, single_channel_output, channel);
self->synth.span.dur = 0;
self->next_span = 0;
}
@ -172,7 +172,7 @@ audioio_get_buffer_result_t synthio_miditrack_get_buffer(synthio_miditrack_obj_t
self->synth.span = self->track[self->next_span++];
}
synthio_synth_synthesize(&self->synth, buffer, buffer_length);
synthio_synth_synthesize(&self->synth, buffer, buffer_length, single_channel_output ? 0 : channel);
return (self->synth.span.dur == 0 && self->next_span >= self->total_spans) ?
GET_BUFFER_DONE : GET_BUFFER_MORE_DATA;

View File

@ -58,12 +58,13 @@ uint8_t common_hal_synthio_synthesizer_get_channel_count(synthio_synthesizer_obj
void synthio_synthesizer_reset_buffer(synthio_synthesizer_obj_t *self,
bool single_channel_output, uint8_t channel) {
synthio_synth_reset_buffer(&self->synth, single_channel_output, channel);
}
audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_obj_t *self,
bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) {
self->synth.span.dur = SYNTHIO_MAX_DUR;
synthio_synth_synthesize(&self->synth, buffer, buffer_length);
synthio_synth_synthesize(&self->synth, buffer, buffer_length, single_channel_output ? channel : 0);
return GET_BUFFER_MORE_DATA;
}

View File

@ -44,16 +44,27 @@ int synthio_span_count_active_channels(synthio_midi_span_t *span) {
}
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length) {
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
if (channel == synth->other_channel) {
*buffer_length = synth->last_buffer_length;
*bufptr = (uint8_t *)(synth->buffers[synth->other_buffer_index] + channel);
return;
}
synth->buffer_index = !synth->buffer_index;
synth->other_channel = 1 - channel;
synth->other_buffer_index = synth->buffer_index;
int16_t *out_buffer = (int16_t *)(void *)synth->buffers[synth->buffer_index];
uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur);
synth->span.dur -= dur;
memset(synth->buffer, 0, synth->buffer_length);
memset(out_buffer, 0, synth->buffer_length);
int32_t sample_rate = synth->sample_rate;
int active_channels = synthio_span_count_active_channels(&synth->span);
const int16_t *waveform = synth->waveform;
uint32_t waveform_length = synth->waveform_length;
int16_t *out_buffer = synth->buffer;
if (active_channels) {
int16_t loudness = 0x3fff / (1 + active_channels);
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
@ -84,27 +95,38 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t
}
}
*buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE;
*buffer = (uint8_t *)synth->buffer;
*buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE;
*bufptr = (uint8_t *)out_buffer;
}
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel) {
if (single_channel_output && channel == 1) {
return;
}
synth->other_channel = -1;
}
bool synthio_synth_deinited(synthio_synth_t *synth) {
return synth->buffer == NULL;
return synth->buffers[0] == NULL;
}
void synthio_synth_deinit(synthio_synth_t *synth) {
m_del(uint8_t, synth->buffer, synth->buffer_length);
synth->buffer = NULL;
m_del(uint8_t, synth->buffers[0], synth->buffer_length);
m_del(uint8_t, synth->buffers[1], synth->buffer_length);
synth->buffers[0] = NULL;
synth->buffers[1] = NULL;
}
void synthio_synth_init(synthio_synth_t *synth, uint16_t max_dur) {
synth->buffer_length = MIN(SYNTHIO_MAX_DUR, max_dur) * SYNTHIO_BYTES_PER_SAMPLE;
synth->buffer = m_malloc(synth->buffer_length, false);
synth->buffers[0] = m_malloc(synth->buffer_length, false);
synth->buffers[1] = m_malloc(synth->buffer_length, false);
synth->other_channel = -1;
}
void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output,
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) {
*single_buffer = true;
*single_buffer = false;
*samples_signed = true;
*max_buffer_length = synth->buffer_length;
*spacing = 1;

View File

@ -28,7 +28,7 @@
#define SYNTHIO_BITS_PER_SAMPLE (16)
#define SYNTHIO_BYTES_PER_SAMPLE (SYNTHIO_BITS_PER_SAMPLE / 8)
#define SYNTHIO_MAX_DUR (512)
#define SYNTHIO_MAX_DUR (256)
#define SYNTHIO_SILENCE (0x80)
#include "shared-module/audiocore/__init__.h"
@ -40,21 +40,25 @@ typedef struct {
typedef struct {
uint32_t sample_rate;
int16_t *buffer;
int16_t *buffers[2];
const int16_t *waveform;
uint16_t buffer_length;
uint16_t last_buffer_length;
uint8_t other_channel, buffer_index, other_buffer_index;
uint16_t waveform_length;
synthio_midi_span_t span;
uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS];
} synthio_synth_t;
void synthio_span_init(synthio_midi_span_t *span);
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length);
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length, uint8_t channel);
void synthio_synth_deinit(synthio_synth_t *synth);
bool synthio_synth_deinited(synthio_synth_t *synth);
void synthio_synth_init(synthio_synth_t *synth, uint16_t max_dur);
void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output,
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing);
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel);
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj);
bool synthio_span_change_note(synthio_midi_span_t *span, uint8_t old_note, uint8_t new_note);
int synthio_span_count_active_channels(synthio_midi_span_t *span);