2929#define background_callback_add (buf , fn , arg ) ((fn)((arg)))
3030#endif
3131
32+ STATIC bool stream_readable (void * stream ) {
33+ int errcode = 0 ;
34+ mp_obj_base_t * o = MP_OBJ_TO_PTR (stream );
35+ const mp_stream_p_t * stream_p = MP_OBJ_TYPE_GET_SLOT (o -> type , protocol );
36+ if (!stream_p -> ioctl ) {
37+ return true;
38+ }
39+
40+ mp_int_t ret = stream_p -> ioctl (stream , MP_STREAM_POLL , MP_STREAM_POLL_RD | MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP , & errcode );
41+ return ret != 0 ;
42+ }
43+
3244// (near copy of mp_stream_posix_read, but with changes)
3345// (circuitpy doesn't enable posix stream routines anyway)
3446STATIC ssize_t stream_read (void * stream , void * buf , size_t len ) {
@@ -46,27 +58,6 @@ STATIC ssize_t stream_read(void *stream, void *buf, size_t len) {
4658 }
4759}
4860
49- // (near copy of mp_stream_posix_read, but with changes)
50- // (circuitpy doesn't enable posix stream routines anyway)
51- // (and the return value semantic is different)
52- STATIC ssize_t stream_read_all (void * stream , uint8_t * buf , size_t len ) {
53- ssize_t total_read = 0 ;
54- while (len ) {
55- ssize_t r = stream_read (stream , buf , len );
56- if (r <= 0 ) {
57- if (total_read ) {
58- break ;
59- }
60- return r ;
61- }
62- total_read += r ;
63- buf += r ;
64- len -= r ;
65- }
66- return total_read ;
67- }
68-
69-
7061// (near copy of mp_stream_posix_lseek, but with changes)
7162// (circuitpy doesn't enable posix stream routines anyway)
7263STATIC off_t stream_lseek (void * stream , off_t offset , int whence ) {
@@ -86,6 +77,12 @@ STATIC off_t stream_lseek(void *stream, off_t offset, int whence) {
8677 return seek_s .offset ;
8778}
8879
80+ #define INPUT_BUFFER_AVAILABLE (i ) ((i).write_off - (i).read_off)
81+ #define INPUT_BUFFER_SPACE (i ) ((i).size - INPUT_BUFFER_AVAILABLE(i))
82+ #define INPUT_BUFFER_READ_PTR (i ) ((i).buf + (i).read_off)
83+ #define INPUT_BUFFER_CONSUME (i , n ) ((i).read_off += (n))
84+ #define INPUT_BUFFER_CLEAR (i ) ((i).read_off = (i).write_off = 0)
85+
8986/** Fill the input buffer unconditionally.
9087 *
9188 * Returns true if the input buffer contains any useful data,
@@ -97,46 +94,61 @@ STATIC off_t stream_lseek(void *stream, off_t offset, int whence) {
9794 * Sets self->eof if any read of the file returns 0 bytes
9895 */
9996static bool mp3file_update_inbuf_always (audiomp3_mp3file_obj_t * self ) {
100- // If we didn't previously reach the end of file, we can try reading now
101- if (!self -> eof && self -> inbuf_offset != 0 ) {
102-
103- // Move the unconsumed portion of the buffer to the start
104- uint8_t * end_of_buffer = self -> inbuf + self -> inbuf_length ;
105- uint8_t * new_end_of_data = self -> inbuf + self -> inbuf_length - self -> inbuf_offset ;
106- memmove (self -> inbuf , self -> inbuf + self -> inbuf_offset ,
107- self -> inbuf_length - self -> inbuf_offset );
108- self -> inbuf_offset = 0 ;
109-
110- ssize_t to_read = end_of_buffer - new_end_of_data ;
111- memset (new_end_of_data , 0 , to_read );
112- ssize_t r = stream_read_all (self -> stream , new_end_of_data , to_read );
113- if (r < 0 ) {
114- self -> eof = true;
115- mp_raise_OSError (- r );
116- }
97+ if (self -> eof || INPUT_BUFFER_SPACE (self -> inbuf ) == 0 ) {
98+ return INPUT_BUFFER_AVAILABLE (self -> inbuf ) > 0 ;
99+ }
100+
101+ // We didn't previously reach EOF and we have input buffer space available
117102
118- if (r == 0 ) {
103+ // Move the unconsumed portion of the buffer to the start
104+ if (self -> inbuf .read_off ) {
105+ memmove (self -> inbuf .buf , INPUT_BUFFER_READ_PTR (self -> inbuf ), INPUT_BUFFER_AVAILABLE (self -> inbuf ));
106+ self -> inbuf .write_off -= self -> inbuf .read_off ;
107+ self -> inbuf .read_off = 0 ;
108+ }
109+
110+ for (size_t to_read ; !self -> eof && (to_read = INPUT_BUFFER_SPACE (self -> inbuf )) > 0 ;) {
111+ uint8_t * write_ptr = self -> inbuf .buf + self -> inbuf .write_off ;
112+ ssize_t n_read = stream_read (self -> stream , write_ptr , to_read );
113+
114+ if (n_read < 0 ) {
115+ int errcode = - n_read ;
116+ if (mp_is_nonblocking_error (errcode ) || errcode == MP_ETIMEDOUT ) {
117+ break ;
118+ }
119119 self -> eof = true;
120+ mp_raise_OSError (errcode );
120121 }
121122
122- if (to_read != r ) {
123- new_end_of_data += r ;
124- memset (new_end_of_data , 0 , end_of_buffer - new_end_of_data );
123+ if (n_read == 0 ) {
124+ self -> eof = true;
125125 }
126126
127+ self -> inbuf .write_off += n_read ;
127128 }
128129
129130 // Return true iff there are at least some useful bytes in the buffer
130- return self -> inbuf_offset < self -> inbuf_length ;
131+ return INPUT_BUFFER_AVAILABLE ( self -> inbuf ) > 0 ;
131132}
132133
133134/** Update the inbuf from a background callback.
134135 *
135- * This variant is introduced so that at the site of the
136- * add_background_callback_core call, the prototype matches.
136+ * Re-queue if there's still buffer space available to read stream data
137137 */
138- static void mp3file_update_inbuf_cb (void * self ) {
139- mp3file_update_inbuf_always (self );
138+ static void mp3file_update_inbuf_cb (void * self_in ) {
139+ audiomp3_mp3file_obj_t * self = self_in ;
140+ if (!self -> eof && stream_readable (self -> stream )) {
141+ mp3file_update_inbuf_always (self );
142+ }
143+
144+ #if !defined(MICROPY_UNIX_COVERAGE )
145+ if (!self -> eof && INPUT_BUFFER_SPACE (self -> inbuf ) > 512 ) {
146+ background_callback_add (
147+ & self -> inbuf_fill_cb ,
148+ mp3file_update_inbuf_cb ,
149+ self );
150+ }
151+ #endif
140152}
141153
142154/** Fill the input buffer if it is less than half full.
@@ -145,18 +157,17 @@ static void mp3file_update_inbuf_cb(void *self) {
145157 */
146158static bool mp3file_update_inbuf_half (audiomp3_mp3file_obj_t * self ) {
147159 // If buffer is over half full, do nothing
148- if (self -> inbuf_offset < self -> inbuf_length / 2 ) {
160+ if (INPUT_BUFFER_SPACE ( self -> inbuf ) < self -> inbuf . size / 2 ) {
149161 return true;
150162 }
151163
152164 return mp3file_update_inbuf_always (self );
153165}
154166
155- #define READ_PTR (self ) (self->inbuf + self->inbuf_offset )
156- #define BYTES_LEFT (self ) (self->inbuf_length - self->inbuf_offset )
157- #define CONSUME (self , n ) (self->inbuf_offset += n )
167+ #define READ_PTR (self ) (INPUT_BUFFER_READ_PTR( self->inbuf) )
168+ #define BYTES_LEFT (self ) (INPUT_BUFFER_AVAILABLE( self->inbuf) )
169+ #define CONSUME (self , n ) (INPUT_BUFFER_CONSUME( self->inbuf, n) )
158170
159- // http://id3.org/d3v2.3.0
160171// http://id3.org/id3v2.3.0
161172static void mp3file_skip_id3v2 (audiomp3_mp3file_obj_t * self ) {
162173 mp3file_update_inbuf_half (self );
@@ -228,54 +239,65 @@ static bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t *self, MP3FrameIn
228239 return err == ERR_MP3_NONE ;
229240}
230241
242+ #define DEFAULT_INPUT_BUFFER_SIZE (2048)
243+ #define MIN_USER_BUFFER_SIZE (DEFAULT_INPUT_BUFFER_SIZE + 2 * MAX_BUFFER_LEN)
244+
231245void common_hal_audiomp3_mp3file_construct (audiomp3_mp3file_obj_t * self ,
232246 mp_obj_t stream ,
233247 uint8_t * buffer ,
234248 size_t buffer_size ) {
235- // XXX Adafruit_MP3 uses a 2kB input buffer and two 4kB output buffers .
236- // for a whopping total of 10kB buffers (+mp3 decoder state and frame buffer)
249+ // XXX Adafruit_MP3 uses a 2kB input buffer and two 4kB output pcm_buffer .
250+ // for a whopping total of 10kB pcm_buffer (+mp3 decoder state and frame buffer)
237251 // At 44kHz, that's 23ms of output audio data.
238252 //
239253 // We will choose a slightly different allocation strategy for the output:
240- // Make sure the buffers are sized exactly to match (a multiple of) the
254+ // Make sure the pcm_buffer are sized exactly to match (a multiple of) the
241255 // frame size; this is typically 2304 * 2 bytes, so a little bit bigger
242- // than the two 4kB output buffers , except that the alignment allows to
256+ // than the two 4kB output pcm_buffer , except that the alignment allows to
243257 // never allocate that extra frame buffer.
244258
245- self -> inbuf_length = 2048 ;
246- self -> inbuf_offset = self -> inbuf_length ;
247- self -> inbuf = m_malloc (self -> inbuf_length );
248- if (self -> inbuf == NULL ) {
249- common_hal_audiomp3_mp3file_deinit (self );
250- m_malloc_fail (self -> inbuf_length );
251- }
252- self -> decoder = MP3InitDecoder ();
253- if (self -> decoder == NULL ) {
254- common_hal_audiomp3_mp3file_deinit (self );
255- mp_raise_msg (& mp_type_MemoryError ,
256- MP_ERROR_TEXT ("Couldn't allocate decoder" ));
257- }
258-
259259 if ((intptr_t )buffer & 1 ) {
260260 buffer += 1 ;
261261 buffer_size -= 1 ;
262262 }
263- if (buffer_size >= 2 * MAX_BUFFER_LEN ) {
264- self -> buffers [0 ] = (int16_t * )(void * )buffer ;
265- self -> buffers [1 ] = (int16_t * )(void * )(buffer + MAX_BUFFER_LEN );
263+ if (buffer && buffer_size > MIN_USER_BUFFER_SIZE ) {
264+ self -> pcm_buffer [0 ] = (int16_t * )(void * )buffer ;
265+ self -> pcm_buffer [1 ] = (int16_t * )(void * )(buffer + MAX_BUFFER_LEN );
266+ self -> inbuf .buf = buffer + 2 * MAX_BUFFER_LEN ;
267+ self -> inbuf .size = buffer_size - 2 * MAX_BUFFER_LEN ;
266268 } else {
267- self -> buffers [0 ] = m_malloc (MAX_BUFFER_LEN );
268- if (self -> buffers [0 ] == NULL ) {
269+ self -> inbuf .size = DEFAULT_INPUT_BUFFER_SIZE ;
270+ self -> inbuf .buf = m_malloc (DEFAULT_INPUT_BUFFER_SIZE );
271+ if (self -> inbuf .buf == NULL ) {
269272 common_hal_audiomp3_mp3file_deinit (self );
270- m_malloc_fail (MAX_BUFFER_LEN );
273+ m_malloc_fail (DEFAULT_INPUT_BUFFER_SIZE );
271274 }
272275
273- self -> buffers [1 ] = m_malloc (MAX_BUFFER_LEN );
274- if (self -> buffers [1 ] == NULL ) {
275- common_hal_audiomp3_mp3file_deinit (self );
276- m_malloc_fail (MAX_BUFFER_LEN );
276+ if (buffer_size >= 2 * MAX_BUFFER_LEN ) {
277+ self -> pcm_buffer [0 ] = (int16_t * )(void * )buffer ;
278+ self -> pcm_buffer [1 ] = (int16_t * )(void * )(buffer + MAX_BUFFER_LEN );
279+ } else {
280+ self -> pcm_buffer [0 ] = m_malloc (MAX_BUFFER_LEN );
281+ if (self -> pcm_buffer [0 ] == NULL ) {
282+ common_hal_audiomp3_mp3file_deinit (self );
283+ m_malloc_fail (MAX_BUFFER_LEN );
284+ }
285+
286+ self -> pcm_buffer [1 ] = m_malloc (MAX_BUFFER_LEN );
287+ if (self -> pcm_buffer [1 ] == NULL ) {
288+ common_hal_audiomp3_mp3file_deinit (self );
289+ m_malloc_fail (MAX_BUFFER_LEN );
290+ }
277291 }
278292 }
293+ self -> inbuf .read_off = self -> inbuf .write_off = 0 ;
294+
295+ self -> decoder = MP3InitDecoder ();
296+ if (self -> decoder == NULL ) {
297+ common_hal_audiomp3_mp3file_deinit (self );
298+ mp_raise_msg (& mp_type_MemoryError ,
299+ MP_ERROR_TEXT ("Couldn't allocate decoder" ));
300+ }
279301
280302 common_hal_audiomp3_mp3file_set_file (self , stream );
281303}
@@ -288,7 +310,7 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
288310 // Seek the beginning of the stream if possible, but ignore any errors
289311 (void )stream_lseek (self -> stream , SEEK_SET , 0 );
290312
291- self -> inbuf_offset = self -> inbuf_length ;
313+ INPUT_BUFFER_CLEAR ( self -> inbuf ) ;
292314 self -> eof = 0 ;
293315 self -> other_channel = -1 ;
294316 mp3file_update_inbuf_half (self );
@@ -298,8 +320,8 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
298320 // this is necessary to avoid a glitch at the start of playback of a second
299321 // track using the same decoder object means there's still a bug in
300322 // get_buffer() that I didn't understand.
301- memset (self -> buffers [0 ], 0 , MAX_BUFFER_LEN );
302- memset (self -> buffers [1 ], 0 , MAX_BUFFER_LEN );
323+ memset (self -> pcm_buffer [0 ], 0 , MAX_BUFFER_LEN );
324+ memset (self -> pcm_buffer [1 ], 0 , MAX_BUFFER_LEN );
303325 MP3FrameInfo fi ;
304326 bool result = mp3file_get_next_frame_info (self , & fi );
305327 background_callback_allow ();
@@ -318,15 +340,15 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
318340void common_hal_audiomp3_mp3file_deinit (audiomp3_mp3file_obj_t * self ) {
319341 MP3FreeDecoder (self -> decoder );
320342 self -> decoder = NULL ;
321- self -> inbuf = NULL ;
322- self -> buffers [0 ] = NULL ;
323- self -> buffers [1 ] = NULL ;
343+ self -> inbuf . buf = NULL ;
344+ self -> pcm_buffer [0 ] = NULL ;
345+ self -> pcm_buffer [1 ] = NULL ;
324346 self -> stream = mp_const_none ;
325347 self -> samples_decoded = 0 ;
326348}
327349
328350bool common_hal_audiomp3_mp3file_deinited (audiomp3_mp3file_obj_t * self ) {
329- return self -> buffers [0 ] == NULL ;
351+ return self -> pcm_buffer [0 ] == NULL ;
330352}
331353
332354uint32_t common_hal_audiomp3_mp3file_get_sample_rate (audiomp3_mp3file_obj_t * self ) {
@@ -356,11 +378,10 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
356378 // loads
357379 background_callback_prevent ();
358380 if (stream_lseek (self -> stream , SEEK_SET , 0 ) == 0 ) {
359- self -> inbuf_offset = self -> inbuf_length ;
381+ INPUT_BUFFER_CLEAR ( self -> inbuf ) ;
360382 self -> eof = 0 ;
361383 self -> samples_decoded = 0 ;
362384 self -> other_channel = -1 ;
363- mp3file_update_inbuf_half (self );
364385 mp3file_skip_id3v2 (self );
365386 mp3file_find_sync_word (self );
366387 }
@@ -372,7 +393,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
372393 uint8_t channel ,
373394 uint8_t * * bufptr ,
374395 uint32_t * buffer_length ) {
375- if (!self -> inbuf ) {
396+ if (!self -> inbuf . buf ) {
376397 * buffer_length = 0 ;
377398 return GET_BUFFER_ERROR ;
378399 }
@@ -383,7 +404,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
383404 * buffer_length = self -> frame_buffer_size ;
384405
385406 if (channel == self -> other_channel ) {
386- * bufptr = (uint8_t * )(self -> buffers [self -> other_buffer_index ] + channel );
407+ * bufptr = (uint8_t * )(self -> pcm_buffer [self -> other_buffer_index ] + channel );
387408 self -> other_channel = -1 ;
388409 self -> samples_decoded += * buffer_length / sizeof (int16_t );
389410 return GET_BUFFER_MORE_DATA ;
@@ -393,7 +414,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
393414 self -> buffer_index = !self -> buffer_index ;
394415 self -> other_channel = 1 - channel ;
395416 self -> other_buffer_index = self -> buffer_index ;
396- int16_t * buffer = (int16_t * )(void * )self -> buffers [self -> buffer_index ];
417+ int16_t * buffer = (int16_t * )(void * )self -> pcm_buffer [self -> buffer_index ];
397418 * bufptr = (uint8_t * )buffer ;
398419
399420 mp3file_skip_id3v2 (self );
@@ -416,7 +437,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
416437 mp3file_skip_id3v2 (self );
417438 int result = mp3file_find_sync_word (self ) ? GET_BUFFER_MORE_DATA : GET_BUFFER_DONE ;
418439
419- if (self -> inbuf_offset >= 512 ) {
440+ if (INPUT_BUFFER_SPACE ( self -> inbuf ) > 512 ) {
420441 background_callback_add (
421442 & self -> inbuf_fill_cb ,
422443 mp3file_update_inbuf_cb ,
@@ -442,7 +463,7 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t *self, bool si
442463float common_hal_audiomp3_mp3file_get_rms_level (audiomp3_mp3file_obj_t * self ) {
443464 float sumsq = 0.f ;
444465 // Assumes no DC component to the audio. Is that a safe assumption?
445- int16_t * buffer = (int16_t * )(void * )self -> buffers [self -> buffer_index ];
466+ int16_t * buffer = (int16_t * )(void * )self -> pcm_buffer [self -> buffer_index ];
446467 for (size_t i = 0 ; i < self -> frame_buffer_size / sizeof (int16_t ); i ++ ) {
447468 sumsq += (float )buffer [i ] * buffer [i ];
448469 }
0 commit comments