Skip to content

Commit 9679263

Browse files
committed
codal_port/modaudio: Improve buffering and flow control out to mixer.
Signed-off-by: Damien George <damien@micropython.org>
1 parent d60c75b commit 9679263

File tree

2 files changed

+41
-25
lines changed

2 files changed

+41
-25
lines changed

src/codal_port/modaudio.c

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,37 @@
3434
#include "modaudio.h"
3535
#include "modmicrobit.h"
3636

37-
#define audio_buffer_ptr MP_STATE_PORT(audio_buffer)
3837
#define audio_source_iter MP_STATE_PORT(audio_source)
3938

4039
#define DEFAULT_SAMPLE_RATE (7812)
41-
#define BUFFER_EXPANSION (16)
40+
#define BUFFER_EXPANSION (4) // smooth out the samples via linear interpolation
41+
#define OUT_CHUNK_SIZE (BUFFER_EXPANSION * AUDIO_CHUNK_SIZE)
4242

43-
static volatile bool running = false;
43+
static volatile bool audio_running = false;
44+
static uint8_t audio_output_buffer[OUT_CHUNK_SIZE];
45+
static volatile int audio_output_read;
46+
static volatile bool audio_fetecher_scheduled;
4447

4548
microbit_audio_frame_obj_t *microbit_audio_frame_make_new(void);
4649

4750
void microbit_audio_stop(void) {
4851
audio_source_iter = NULL;
49-
running = false;
52+
audio_running = false;
5053
microbit_pin_audio_free();
5154
}
5255

56+
STATIC void audio_buffer_ready(void) {
57+
uint32_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
58+
int x = audio_output_read;
59+
audio_output_read = 0;
60+
MICROPY_END_ATOMIC_SECTION(atomic_state);
61+
if (x == -2) {
62+
microbit_hal_audio_ready_callback();
63+
}
64+
}
65+
5366
STATIC void audio_data_fetcher(void) {
67+
audio_fetecher_scheduled = false;
5468
if (audio_source_iter == NULL) {
5569
microbit_audio_stop();
5670
return;
@@ -70,15 +84,15 @@ STATIC void audio_data_fetcher(void) {
7084
if (buffer_obj == MP_OBJ_STOP_ITERATION) {
7185
// End of audio iterator
7286
audio_source_iter = NULL;
73-
memset(audio_buffer_ptr, 0, BUFFER_EXPANSION * AUDIO_CHUNK_SIZE);
87+
microbit_audio_stop();
7488
} else if (mp_obj_get_type(buffer_obj) != &microbit_audio_frame_type) {
7589
// Audio iterator did not return an AudioFrame
7690
audio_source_iter = NULL;
77-
memset(audio_buffer_ptr, 0, BUFFER_EXPANSION * AUDIO_CHUNK_SIZE);
91+
microbit_audio_stop();
7892
MP_STATE_VM(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, "not an AudioFrame");
7993
} else {
8094
microbit_audio_frame_obj_t *buffer = (microbit_audio_frame_obj_t *)buffer_obj;
81-
uint8_t *dest = audio_buffer_ptr;
95+
uint8_t *dest = &audio_output_buffer[0];
8296
uint32_t last = dest[BUFFER_EXPANSION * AUDIO_CHUNK_SIZE - 1];
8397
for (int i = 0; i < AUDIO_CHUNK_SIZE; ++i) {
8498
uint32_t cur = buffer->data[i];
@@ -90,8 +104,8 @@ STATIC void audio_data_fetcher(void) {
90104
}
91105
last = cur;
92106
}
107+
audio_buffer_ready();
93108
}
94-
microbit_hal_audio_write_data(audio_buffer_ptr, BUFFER_EXPANSION * AUDIO_CHUNK_SIZE);
95109
}
96110

97111
STATIC mp_obj_t audio_data_fetcher_wrapper(mp_obj_t arg) {
@@ -101,25 +115,28 @@ STATIC mp_obj_t audio_data_fetcher_wrapper(mp_obj_t arg) {
101115
STATIC MP_DEFINE_CONST_FUN_OBJ_1(audio_data_fetcher_wrapper_obj, audio_data_fetcher_wrapper);
102116

103117
void microbit_hal_audio_ready_callback(void) {
104-
/*
105-
if (double_pin) {
106-
// Convert 0 to 255 to -256 to +254
107-
next_sample = next_sample*2-256;
118+
if (audio_output_read >= 0) {
119+
// there is data ready to send out to the audio pipeline, so send it
120+
microbit_hal_audio_write_data(&audio_output_buffer[0], OUT_CHUNK_SIZE);
121+
audio_output_read = -1;
122+
} else {
123+
// no data ready, need to call this function later when data is ready
124+
audio_output_read = -2;
125+
}
126+
if (!audio_fetecher_scheduled) {
127+
// schedule audio_data_fetcher to be executed to prepare the next buffer
128+
audio_fetecher_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&audio_data_fetcher_wrapper_obj), mp_const_none);
108129
}
109-
*/
110-
mp_sched_schedule(MP_OBJ_FROM_PTR(&audio_data_fetcher_wrapper_obj), mp_const_none);
111130
}
112131

113132
static void audio_init(uint32_t sample_rate) {
114-
if (audio_buffer_ptr == NULL) {
115-
audio_source_iter = NULL;
116-
audio_buffer_ptr = m_new(uint8_t, BUFFER_EXPANSION * AUDIO_CHUNK_SIZE);
117-
}
118-
microbit_hal_audio_init(BUFFER_EXPANSION / 4 * sample_rate);
133+
audio_fetecher_scheduled = false;
134+
audio_output_read = -2;
135+
microbit_hal_audio_init(BUFFER_EXPANSION * sample_rate);
119136
}
120137

121138
void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin_select, bool wait, uint32_t sample_rate) {
122-
if (running) {
139+
if (audio_running) {
123140
microbit_audio_stop();
124141
}
125142
audio_init(sample_rate);
@@ -136,11 +153,11 @@ void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin_select, bool wait, ui
136153

137154
audio_source_iter = mp_getiter(src, NULL);
138155
audio_data_fetcher();
139-
running = true;
156+
audio_running = true;
140157
if (!wait) {
141158
return;
142159
}
143-
while (running) {
160+
while (audio_running) {
144161
mp_handle_pending(true);
145162
microbit_hal_idle();
146163
}
@@ -175,11 +192,11 @@ STATIC mp_obj_t play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
175192
MP_DEFINE_CONST_FUN_OBJ_KW(microbit_audio_play_obj, 0, play);
176193

177194
bool microbit_audio_is_playing(void) {
178-
return running;
195+
return audio_running;
179196
}
180197

181198
mp_obj_t is_playing(void) {
182-
return mp_obj_new_bool(running);
199+
return mp_obj_new_bool(audio_running);
183200
}
184201
MP_DEFINE_CONST_FUN_OBJ_0(microbit_audio_is_playing_obj, is_playing);
185202

src/codal_port/mpconfigport.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ extern const struct _mp_obj_module_t utime_module;
130130
const char *readline_hist[8]; \
131131
void *display_data; \
132132
uint8_t *radio_buf; \
133-
void *audio_buffer; \
134133
void *audio_source; \
135134
void *speech_data; \
136135
struct _music_data_t *music_data; \

0 commit comments

Comments
 (0)