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
4548microbit_audio_frame_obj_t * microbit_audio_frame_make_new (void );
4649
4750void 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+
5366STATIC 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
97111STATIC 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) {
101115STATIC MP_DEFINE_CONST_FUN_OBJ_1 (audio_data_fetcher_wrapper_obj , audio_data_fetcher_wrapper );
102116
103117void 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
113132static 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
121138void 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
175192MP_DEFINE_CONST_FUN_OBJ_KW (microbit_audio_play_obj , 0 , play );
176193
177194bool microbit_audio_is_playing (void ) {
178- return running ;
195+ return audio_running ;
179196}
180197
181198mp_obj_t is_playing (void ) {
182- return mp_obj_new_bool (running );
199+ return mp_obj_new_bool (audio_running );
183200}
184201MP_DEFINE_CONST_FUN_OBJ_0 (microbit_audio_is_playing_obj , is_playing );
185202
0 commit comments