35
35
#define audio_source_frame MP_STATE_PORT(audio_source_frame_state)
36
36
#define audio_source_iter MP_STATE_PORT(audio_source_iter_state)
37
37
38
+ #ifndef AUDIO_OUTPUT_BUFFER_SIZE
38
39
#define AUDIO_OUTPUT_BUFFER_SIZE (32)
40
+ #endif
41
+
39
42
#define DEFAULT_AUDIO_FRAME_SIZE (32)
40
43
#define DEFAULT_SAMPLE_RATE (7812)
41
44
@@ -46,8 +49,9 @@ typedef enum {
46
49
} audio_output_state_t ;
47
50
48
51
static uint8_t audio_output_buffer [AUDIO_OUTPUT_BUFFER_SIZE ];
52
+ static size_t audio_output_buffer_offset ;
49
53
static volatile audio_output_state_t audio_output_state ;
50
- static size_t audio_raw_offset ;
54
+ static size_t audio_source_frame_offset ;
51
55
static uint32_t audio_current_sound_level ;
52
56
static mp_sched_node_t audio_data_fetcher_sched_node ;
53
57
@@ -56,27 +60,18 @@ static inline bool audio_is_running(void) {
56
60
}
57
61
58
62
void microbit_audio_stop (void ) {
63
+ audio_output_buffer_offset = 0 ;
59
64
audio_source_frame = NULL ;
60
65
audio_source_iter = NULL ;
61
- audio_raw_offset = 0 ;
66
+ audio_source_frame_offset = 0 ;
62
67
audio_current_sound_level = 0 ;
63
68
microbit_hal_audio_stop_expression ();
64
69
}
65
70
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 ) {
77
72
if (audio_source_frame != NULL ) {
78
73
// 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 ) {
80
75
// AudioFrame is exhausted.
81
76
audio_source_frame = NULL ;
82
77
}
@@ -118,30 +113,54 @@ static void audio_data_fetcher(mp_sched_node_t *node) {
118
113
119
114
// We have the next AudioFrame.
120
115
audio_source_frame = MP_OBJ_TO_PTR (frame_obj );
121
- audio_raw_offset = 0 ;
116
+ audio_source_frame_offset = 0 ;
122
117
microbit_hal_audio_raw_set_rate (audio_source_frame -> rate );
123
118
}
119
+ }
124
120
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 ];
131
124
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 ;
137
139
}
138
140
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 ;
143
147
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
+ }
145
164
}
146
165
147
166
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
178
197
sound_expr_data = microbit_soundeffect_get_sound_expr_data (src );
179
198
} else if (mp_obj_is_type (src , & microbit_audio_frame_type )) {
180
199
audio_source_frame = MP_OBJ_TO_PTR (src );
181
- audio_raw_offset = 0 ;
200
+ audio_source_frame_offset = 0 ;
182
201
microbit_hal_audio_raw_set_rate (audio_source_frame -> rate );
183
202
} else if (mp_obj_is_type (src , & mp_type_tuple ) || mp_obj_is_type (src , & mp_type_list )) {
184
203
// A tuple/list passed in. Need to check if it contains SoundEffect instances.
0 commit comments