From 98b0029a292cf51826275cbacbaae1800698d7ed Mon Sep 17 00:00:00 2001 From: Ben Combee Date: Sat, 1 Jan 2022 23:28:43 -0600 Subject: [PATCH] audiomp3: add decoded_samples property In my testing, there is no way to accurately know how far into a MP3 file you're currently playing. You can use monotonic time, but that can have drift versus the audio playback system, which may not be running at exactly the expected sample rate. To allow syncing animation with timestamps in a MP3 file, this presents a new property, decoded_samples, that records the number of audio samples sent out of the decoder. While this may not be a completely accurate time, due to mixer delays, it's much better position that the monotonic clock difference. Implementation is keeping track of this value in the mp3file structure and adding to it whenever data is sent out of the decoder. The property implementation was a copy/paste from current properties in the audiomp3 files. --- shared-bindings/audiomp3/MP3Decoder.c | 17 +++++++++++++++++ shared-bindings/audiomp3/MP3Decoder.h | 1 + shared-module/audiomp3/MP3Decoder.c | 8 ++++++++ shared-module/audiomp3/MP3Decoder.h | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index 227cb6dec1..4761feacd8 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -232,6 +232,22 @@ const mp_obj_property_t audiomp3_mp3file_rms_level_obj = { MP_ROM_NONE}, }; +//| samples_decoded: int +//| """The number of audio samples decoded from the current file. (read only)""" +//| +STATIC mp_obj_t audiomp3_mp3file_obj_get_samples_decoded(mp_obj_t self_in) { + audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_samples_decoded(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_samples_decoded_obj, audiomp3_mp3file_obj_get_samples_decoded); + +const mp_obj_property_t audiomp3_mp3file_samples_decoded_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomp3_mp3file_get_samples_decoded_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = { // Methods @@ -245,6 +261,7 @@ STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiomp3_mp3file_bits_per_sample_obj) }, { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiomp3_mp3file_channel_count_obj) }, { MP_ROM_QSTR(MP_QSTR_rms_level), MP_ROM_PTR(&audiomp3_mp3file_rms_level_obj) }, + { MP_ROM_QSTR(MP_QSTR_samples_decoded), MP_ROM_PTR(&audiomp3_mp3file_samples_decoded_obj) }, }; STATIC MP_DEFINE_CONST_DICT(audiomp3_mp3file_locals_dict, audiomp3_mp3file_locals_dict_table); diff --git a/shared-bindings/audiomp3/MP3Decoder.h b/shared-bindings/audiomp3/MP3Decoder.h index 2428cedf16..e1f4fcff4a 100644 --- a/shared-bindings/audiomp3/MP3Decoder.h +++ b/shared-bindings/audiomp3/MP3Decoder.h @@ -46,5 +46,6 @@ void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t *self, u uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t *self); uint8_t common_hal_audiomp3_mp3file_get_channel_count(audiomp3_mp3file_obj_t *self); float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self); +uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MP3FILE_H diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index 5e1bce5924..4687e01e43 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -258,6 +258,7 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file self->channel_count = fi.nChans; self->frame_buffer_size = fi.outputSamps * sizeof(int16_t); self->len = 2 * self->frame_buffer_size; + self->samples_decoded = 0; } void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) { @@ -267,6 +268,7 @@ void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) { self->buffers[0] = NULL; self->buffers[1] = NULL; self->file = NULL; + self->samples_decoded = 0; } bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t *self) { @@ -327,6 +329,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * if (channel == self->other_channel) { *bufptr = (uint8_t *)(self->buffers[self->other_buffer_index] + channel); self->other_channel = -1; + self->samples_decoded += *buffer_length / sizeof(int16_t); return GET_BUFFER_MORE_DATA; } @@ -359,6 +362,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * self); } + self->samples_decoded += *buffer_length / sizeof(int16_t); return GET_BUFFER_MORE_DATA; } @@ -384,3 +388,7 @@ float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self) { } return sqrtf(sumsq) / (self->frame_buffer_size / sizeof(int16_t)); } + +uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self) { + return self->samples_decoded; +} diff --git a/shared-module/audiomp3/MP3Decoder.h b/shared-module/audiomp3/MP3Decoder.h index 0f2256a417..17616d4a28 100644 --- a/shared-module/audiomp3/MP3Decoder.h +++ b/shared-module/audiomp3/MP3Decoder.h @@ -54,6 +54,8 @@ typedef struct { int8_t other_channel; int8_t other_buffer_index; + + uint32_t samples_decoded; } audiomp3_mp3file_obj_t; // These are not available from Python because it may be called in an interrupt. @@ -71,4 +73,6 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t *self, bool si float audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self); +uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self); + #endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H