Skip to content

Commit c7c7485

Browse files
committed
codal_port/modaudio: Allow output buffer to be larger than 32 bytes.
Signed-off-by: Damien George <[email protected]>
1 parent 42d56a2 commit c7c7485

File tree

1 file changed

+51
-32
lines changed

1 file changed

+51
-32
lines changed

src/codal_port/modaudio.c

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535
#define audio_source_frame MP_STATE_PORT(audio_source_frame_state)
3636
#define audio_source_iter MP_STATE_PORT(audio_source_iter_state)
3737

38+
#ifndef AUDIO_OUTPUT_BUFFER_SIZE
3839
#define AUDIO_OUTPUT_BUFFER_SIZE (32)
40+
#endif
41+
3942
#define DEFAULT_AUDIO_FRAME_SIZE (32)
4043
#define DEFAULT_SAMPLE_RATE (7812)
4144

@@ -46,8 +49,9 @@ typedef enum {
4649
} audio_output_state_t;
4750

4851
static uint8_t audio_output_buffer[AUDIO_OUTPUT_BUFFER_SIZE];
52+
static size_t audio_output_buffer_offset;
4953
static volatile audio_output_state_t audio_output_state;
50-
static size_t audio_raw_offset;
54+
static size_t audio_source_frame_offset;
5155
static uint32_t audio_current_sound_level;
5256
static mp_sched_node_t audio_data_fetcher_sched_node;
5357

@@ -56,27 +60,18 @@ static inline bool audio_is_running(void) {
5660
}
5761

5862
void microbit_audio_stop(void) {
63+
audio_output_buffer_offset = 0;
5964
audio_source_frame = NULL;
6065
audio_source_iter = NULL;
61-
audio_raw_offset = 0;
66+
audio_source_frame_offset = 0;
6267
audio_current_sound_level = 0;
6368
microbit_hal_audio_stop_expression();
6469
}
6570

66-
static void audio_buffer_ready(void) {
67-
uint32_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
68-
audio_output_state_t old_state = audio_output_state;
69-
audio_output_state = AUDIO_OUTPUT_STATE_DATA_READY;
70-
MICROPY_END_ATOMIC_SECTION(atomic_state);
71-
if (old_state == AUDIO_OUTPUT_STATE_IDLE) {
72-
microbit_hal_audio_raw_ready_callback();
73-
}
74-
}
75-
76-
static void audio_data_fetcher(mp_sched_node_t *node) {
71+
static void audio_data_pull_from_source(void) {
7772
if (audio_source_frame != NULL) {
7873
// An existing AudioFrame is being played, see if there's any data left.
79-
if (audio_raw_offset >= audio_source_frame->used_size) {
74+
if (audio_source_frame_offset >= audio_source_frame->used_size) {
8075
// AudioFrame is exhausted.
8176
audio_source_frame = NULL;
8277
}
@@ -118,30 +113,54 @@ static void audio_data_fetcher(mp_sched_node_t *node) {
118113

119114
// We have the next AudioFrame.
120115
audio_source_frame = MP_OBJ_TO_PTR(frame_obj);
121-
audio_raw_offset = 0;
116+
audio_source_frame_offset = 0;
122117
microbit_hal_audio_raw_set_rate(audio_source_frame->rate);
123118
}
119+
}
124120

125-
const uint8_t *src = &audio_source_frame->data[audio_raw_offset];
126-
size_t src_len = MIN(audio_source_frame->used_size - audio_raw_offset, AUDIO_OUTPUT_BUFFER_SIZE);
127-
audio_raw_offset += src_len;
128-
129-
uint8_t *dest = &audio_output_buffer[0];
130-
uint32_t sound_level = 0;
121+
static void audio_data_fetcher(mp_sched_node_t *node) {
122+
audio_data_pull_from_source();
123+
uint8_t *dest = &audio_output_buffer[audio_output_buffer_offset];
131124

132-
for (int i = 0; i < src_len; ++i) {
133-
// Copy sample to the buffer.
134-
*dest++ = src[i];
135-
// Compute the sound level.
136-
sound_level += (src[i] - 128) * (src[i] - 128);
125+
if (audio_source_frame == NULL) {
126+
// Audio source is exhausted.
127+
// Fill any remaining audio_output_buffer bytes with silence.
128+
memset(dest, 128, AUDIO_OUTPUT_BUFFER_SIZE - audio_output_buffer_offset);
129+
audio_output_buffer_offset = AUDIO_OUTPUT_BUFFER_SIZE;
130+
} else {
131+
// Copy samples to the buffer.
132+
const uint8_t *src = &audio_source_frame->data[audio_source_frame_offset];
133+
size_t src_len = MIN(audio_source_frame->used_size - audio_source_frame_offset, AUDIO_OUTPUT_BUFFER_SIZE - audio_output_buffer_offset);
134+
memcpy(dest, src, src_len);
135+
136+
// Update output and source offsets.
137+
audio_output_buffer_offset += src_len;
138+
audio_source_frame_offset += src_len;
137139
}
138140

139-
// Fill any remaining audio_output_buffer bytes with silence.
140-
memset(dest, 128, AUDIO_OUTPUT_BUFFER_SIZE - src_len);
141-
142-
audio_current_sound_level = sound_level / AUDIO_OUTPUT_BUFFER_SIZE;
141+
if (audio_output_buffer_offset < AUDIO_OUTPUT_BUFFER_SIZE) {
142+
// Output buffer not full yet, so attempt to pull more data from the source.
143+
mp_sched_schedule_node(&audio_data_fetcher_sched_node, audio_data_fetcher);
144+
} else {
145+
// Output buffer is full, process it and prepare for next buffer fill.
146+
audio_output_buffer_offset = 0;
143147

144-
audio_buffer_ready();
148+
// Compute the sound level.
149+
uint32_t sound_level = 0;
150+
for (int i = 0; i < AUDIO_OUTPUT_BUFFER_SIZE; ++i) {
151+
sound_level += (audio_output_buffer[i] - 128) * (audio_output_buffer[i] - 128);
152+
}
153+
audio_current_sound_level = sound_level / AUDIO_OUTPUT_BUFFER_SIZE;
154+
155+
// Send the data to the lower levels of the audio pipeline.
156+
uint32_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
157+
audio_output_state_t old_state = audio_output_state;
158+
audio_output_state = AUDIO_OUTPUT_STATE_DATA_READY;
159+
MICROPY_END_ATOMIC_SECTION(atomic_state);
160+
if (old_state == AUDIO_OUTPUT_STATE_IDLE) {
161+
microbit_hal_audio_raw_ready_callback();
162+
}
163+
}
145164
}
146165

147166
void microbit_hal_audio_raw_ready_callback(void) {
@@ -178,7 +197,7 @@ void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin_select, bool wait, ui
178197
sound_expr_data = microbit_soundeffect_get_sound_expr_data(src);
179198
} else if (mp_obj_is_type(src, &microbit_audio_frame_type)) {
180199
audio_source_frame = MP_OBJ_TO_PTR(src);
181-
audio_raw_offset = 0;
200+
audio_source_frame_offset = 0;
182201
microbit_hal_audio_raw_set_rate(audio_source_frame->rate);
183202
} else if (mp_obj_is_type(src, &mp_type_tuple) || mp_obj_is_type(src, &mp_type_list)) {
184203
// A tuple/list passed in. Need to check if it contains SoundEffect instances.

0 commit comments

Comments
 (0)