29
29
#define background_callback_add (buf , fn , arg ) ((fn)((arg)))
30
30
#endif
31
31
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
+
32
44
// (near copy of mp_stream_posix_read, but with changes)
33
45
// (circuitpy doesn't enable posix stream routines anyway)
34
46
STATIC 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) {
46
58
}
47
59
}
48
60
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
-
70
61
// (near copy of mp_stream_posix_lseek, but with changes)
71
62
// (circuitpy doesn't enable posix stream routines anyway)
72
63
STATIC 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) {
86
77
return seek_s .offset ;
87
78
}
88
79
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
+
89
86
/** Fill the input buffer unconditionally.
90
87
*
91
88
* 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) {
97
94
* Sets self->eof if any read of the file returns 0 bytes
98
95
*/
99
96
static 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
117
102
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
+ }
119
119
self -> eof = true;
120
+ mp_raise_OSError (errcode );
120
121
}
121
122
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;
125
125
}
126
126
127
+ self -> inbuf .write_off += n_read ;
127
128
}
128
129
129
130
// 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 ;
131
132
}
132
133
133
134
/** Update the inbuf from a background callback.
134
135
*
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
137
137
*/
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
140
152
}
141
153
142
154
/** Fill the input buffer if it is less than half full.
@@ -145,18 +157,17 @@ static void mp3file_update_inbuf_cb(void *self) {
145
157
*/
146
158
static bool mp3file_update_inbuf_half (audiomp3_mp3file_obj_t * self ) {
147
159
// 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 ) {
149
161
return true;
150
162
}
151
163
152
164
return mp3file_update_inbuf_always (self );
153
165
}
154
166
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) )
158
170
159
- // http://id3.org/d3v2.3.0
160
171
// http://id3.org/id3v2.3.0
161
172
static void mp3file_skip_id3v2 (audiomp3_mp3file_obj_t * self ) {
162
173
mp3file_update_inbuf_half (self );
@@ -228,54 +239,65 @@ static bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t *self, MP3FrameIn
228
239
return err == ERR_MP3_NONE ;
229
240
}
230
241
242
+ #define DEFAULT_INPUT_BUFFER_SIZE (2048)
243
+ #define MIN_USER_BUFFER_SIZE (DEFAULT_INPUT_BUFFER_SIZE + 2 * MAX_BUFFER_LEN)
244
+
231
245
void common_hal_audiomp3_mp3file_construct (audiomp3_mp3file_obj_t * self ,
232
246
mp_obj_t stream ,
233
247
uint8_t * buffer ,
234
248
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)
237
251
// At 44kHz, that's 23ms of output audio data.
238
252
//
239
253
// 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
241
255
// 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
243
257
// never allocate that extra frame buffer.
244
258
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
-
259
259
if ((intptr_t )buffer & 1 ) {
260
260
buffer += 1 ;
261
261
buffer_size -= 1 ;
262
262
}
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 ;
266
268
} 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 ) {
269
272
common_hal_audiomp3_mp3file_deinit (self );
270
- m_malloc_fail (MAX_BUFFER_LEN );
273
+ m_malloc_fail (DEFAULT_INPUT_BUFFER_SIZE );
271
274
}
272
275
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
+ }
277
291
}
278
292
}
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
+ }
279
301
280
302
common_hal_audiomp3_mp3file_set_file (self , stream );
281
303
}
@@ -288,7 +310,7 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
288
310
// Seek the beginning of the stream if possible, but ignore any errors
289
311
(void )stream_lseek (self -> stream , SEEK_SET , 0 );
290
312
291
- self -> inbuf_offset = self -> inbuf_length ;
313
+ INPUT_BUFFER_CLEAR ( self -> inbuf ) ;
292
314
self -> eof = 0 ;
293
315
self -> other_channel = -1 ;
294
316
mp3file_update_inbuf_half (self );
@@ -298,8 +320,8 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
298
320
// this is necessary to avoid a glitch at the start of playback of a second
299
321
// track using the same decoder object means there's still a bug in
300
322
// 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 );
303
325
MP3FrameInfo fi ;
304
326
bool result = mp3file_get_next_frame_info (self , & fi );
305
327
background_callback_allow ();
@@ -318,15 +340,15 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
318
340
void common_hal_audiomp3_mp3file_deinit (audiomp3_mp3file_obj_t * self ) {
319
341
MP3FreeDecoder (self -> decoder );
320
342
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 ;
324
346
self -> stream = mp_const_none ;
325
347
self -> samples_decoded = 0 ;
326
348
}
327
349
328
350
bool common_hal_audiomp3_mp3file_deinited (audiomp3_mp3file_obj_t * self ) {
329
- return self -> buffers [0 ] == NULL ;
351
+ return self -> pcm_buffer [0 ] == NULL ;
330
352
}
331
353
332
354
uint32_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,
356
378
// loads
357
379
background_callback_prevent ();
358
380
if (stream_lseek (self -> stream , SEEK_SET , 0 ) == 0 ) {
359
- self -> inbuf_offset = self -> inbuf_length ;
381
+ INPUT_BUFFER_CLEAR ( self -> inbuf ) ;
360
382
self -> eof = 0 ;
361
383
self -> samples_decoded = 0 ;
362
384
self -> other_channel = -1 ;
363
- mp3file_update_inbuf_half (self );
364
385
mp3file_skip_id3v2 (self );
365
386
mp3file_find_sync_word (self );
366
387
}
@@ -372,7 +393,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
372
393
uint8_t channel ,
373
394
uint8_t * * bufptr ,
374
395
uint32_t * buffer_length ) {
375
- if (!self -> inbuf ) {
396
+ if (!self -> inbuf . buf ) {
376
397
* buffer_length = 0 ;
377
398
return GET_BUFFER_ERROR ;
378
399
}
@@ -383,7 +404,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
383
404
* buffer_length = self -> frame_buffer_size ;
384
405
385
406
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 );
387
408
self -> other_channel = -1 ;
388
409
self -> samples_decoded += * buffer_length / sizeof (int16_t );
389
410
return GET_BUFFER_MORE_DATA ;
@@ -393,7 +414,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
393
414
self -> buffer_index = !self -> buffer_index ;
394
415
self -> other_channel = 1 - channel ;
395
416
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 ];
397
418
* bufptr = (uint8_t * )buffer ;
398
419
399
420
mp3file_skip_id3v2 (self );
@@ -416,7 +437,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *
416
437
mp3file_skip_id3v2 (self );
417
438
int result = mp3file_find_sync_word (self ) ? GET_BUFFER_MORE_DATA : GET_BUFFER_DONE ;
418
439
419
- if (self -> inbuf_offset >= 512 ) {
440
+ if (INPUT_BUFFER_SPACE ( self -> inbuf ) > 512 ) {
420
441
background_callback_add (
421
442
& self -> inbuf_fill_cb ,
422
443
mp3file_update_inbuf_cb ,
@@ -442,7 +463,7 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t *self, bool si
442
463
float common_hal_audiomp3_mp3file_get_rms_level (audiomp3_mp3file_obj_t * self ) {
443
464
float sumsq = 0.f ;
444
465
// 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 ];
446
467
for (size_t i = 0 ; i < self -> frame_buffer_size / sizeof (int16_t ); i ++ ) {
447
468
sumsq += (float )buffer [i ] * buffer [i ];
448
469
}
0 commit comments