MP3Decoder: Make it possible to start in the middle of an MP3
You can now, e.g.,
```
with open("/whatever.mp3") as mp3_file:
mp3_file.seek(16000*30)
decoder.file = mp3_file
i2s.play(decoder)
```
to start about 30 seconds into a 128kbit/s CBR track.
If a track is looped, the loop will start at the beginning.
This also changes the behavior if the track is started & stopped: it will
continue from where it left off, except if it had prevously run to
completion. To get other behavior, you can seek the file and then re-assign
the file property.
This commit is contained in:
parent
6f6b680c18
commit
cb295c57d7
2 changed files with 13 additions and 8 deletions
|
|
@ -28,13 +28,13 @@
|
||||||
//| """Load a .mp3 file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
|
//| """Load a .mp3 file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
|
||||||
//|
|
//|
|
||||||
//| :param Union[str, typing.BinaryIO] file: The name of a mp3 file (preferred) or an already opened mp3 file
|
//| :param Union[str, typing.BinaryIO] file: The name of a mp3 file (preferred) or an already opened mp3 file
|
||||||
//| :param ~circuitpython_typing.WriteableBuffer buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two buffers are allocated internally. The specific buffer size required depends on the mp3 file.
|
//| :param ~circuitpython_typing.WriteableBuffer buffer: Optional pre-allocated buffer, that will be split and used for buffering the data. The buffer is split into two parts for decoded data and the remainder is used for pre-decoded data. When playing from a socket, a larger buffer can help reduce playback glitches at the expense of increased memory usage.
|
||||||
//|
|
//|
|
||||||
//| Playback of mp3 audio is CPU intensive, and the
|
//| Playback of mp3 audio is CPU intensive, and the
|
||||||
//| exact limit depends on many factors such as the particular
|
//| exact limit depends on many factors such as the particular
|
||||||
//| microcontroller, SD card or flash performance, and other
|
//| microcontroller, SD card or flash performance, network performance, and
|
||||||
//| code in use such as displayio. If playback is garbled,
|
//| other code in use such as displayio. If playback is garbled, skips, or plays as
|
||||||
//| skips, or plays as static, first try using a "simpler" mp3:
|
//| static, first try using a "simpler" mp3:
|
||||||
//|
|
//|
|
||||||
//| * Use constant bit rate (CBR) not VBR or ABR (variable or average bit rate) when encoding your mp3 file
|
//| * Use constant bit rate (CBR) not VBR or ABR (variable or average bit rate) when encoding your mp3 file
|
||||||
//| * Use a lower sample rate (e.g., 11.025kHz instead of 48kHz)
|
//| * Use a lower sample rate (e.g., 11.025kHz instead of 48kHz)
|
||||||
|
|
@ -64,6 +64,14 @@
|
||||||
//| while a.playing:
|
//| while a.playing:
|
||||||
//| pass
|
//| pass
|
||||||
//| print("stopped")
|
//| print("stopped")
|
||||||
|
//|
|
||||||
|
//| It is possible to seek within a file before playing it::
|
||||||
|
//|
|
||||||
|
//| with open("/test.mp3", "rb") as stream:
|
||||||
|
//| stream.seek(128000 * 30 // 8) # Seek about 30s into a 128kbit/s stream
|
||||||
|
//| decoder.file = stream
|
||||||
|
//|
|
||||||
|
//| If the stream is played with ``loop = True``, the loop will start at the beginning.
|
||||||
//| """
|
//| """
|
||||||
//| ...
|
//| ...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,9 +329,6 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
|
||||||
|
|
||||||
self->stream = stream;
|
self->stream = stream;
|
||||||
|
|
||||||
// Seek the beginning of the stream if possible, but ignore any errors
|
|
||||||
(void)stream_lseek(self->stream, SEEK_SET, 0);
|
|
||||||
|
|
||||||
INPUT_BUFFER_CLEAR(self->inbuf);
|
INPUT_BUFFER_CLEAR(self->inbuf);
|
||||||
self->eof = 0;
|
self->eof = 0;
|
||||||
self->other_channel = -1;
|
self->other_channel = -1;
|
||||||
|
|
@ -401,7 +398,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
|
||||||
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
|
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
|
||||||
// loads
|
// loads
|
||||||
background_callback_prevent();
|
background_callback_prevent();
|
||||||
if (stream_lseek(self->stream, SEEK_SET, 0) == 0) {
|
if (self->eof && stream_lseek(self->stream, SEEK_SET, 0) == 0) {
|
||||||
INPUT_BUFFER_CLEAR(self->inbuf);
|
INPUT_BUFFER_CLEAR(self->inbuf);
|
||||||
self->eof = 0;
|
self->eof = 0;
|
||||||
self->samples_decoded = 0;
|
self->samples_decoded = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue