MP3File: Add a settable ".file" property

This enables jeplayer to allocate just one MP3File at startup, rather
than have to make repeated large allocations while the application is
running.

The buffers have to be allocated their theoretical maximum, but that
doesn't matter much as all the real-life MP3 files I checked needed
that much allocation anyway.
This commit is contained in:
Jeff Epler 2019-12-23 09:36:46 -06:00
parent e6fd513cfa
commit 02154caf24
3 changed files with 68 additions and 25 deletions

View File

@ -129,6 +129,37 @@ STATIC mp_obj_t audiomp3_mp3file_obj___exit__(size_t n_args, const mp_obj_t *arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomp3_mp3file___exit___obj, 4, 4, audiomp3_mp3file_obj___exit__);
//| .. attribute:: file
//|
//| File to play back.
//|
STATIC mp_obj_t audiomp3_mp3file_obj_get_file(mp_obj_t self_in) {
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return self->file;
}
MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_file_obj, audiomp3_mp3file_obj_get_file);
STATIC mp_obj_t audiomp3_mp3file_obj_set_file(mp_obj_t self_in, mp_obj_t file) {
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
if (!MP_OBJ_IS_TYPE(file, &mp_type_fileio)) {
mp_raise_TypeError(translate("file must be a file opened in byte mode"));
}
common_hal_audiomp3_mp3file_set_file(self, file);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_file_obj, audiomp3_mp3file_obj_set_file);
const mp_obj_property_t audiomp3_mp3file_file_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&audiomp3_mp3file_get_file_obj,
(mp_obj_t)&audiomp3_mp3file_set_file_obj,
(mp_obj_t)&mp_const_none_obj},
};
//| .. attribute:: sample_rate
//|
//| 32 bit value that dictates how quickly samples are loaded into the DAC
@ -201,6 +232,7 @@ STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) },
// Properties
{ MP_ROM_QSTR(MP_QSTR_file), MP_ROM_PTR(&audiomp3_mp3file_file_obj) },
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomp3_mp3file_sample_rate_obj) },
{ 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) },

View File

@ -38,6 +38,7 @@ extern const mp_obj_type_t audiomp3_mp3file_type;
void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
pyb_file_obj_t* file, uint8_t *buffer, size_t buffer_size);
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file);
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self);
bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t* self);
uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t* self);

View File

@ -37,6 +37,8 @@
#include "supervisor/shared/translate.h"
#include "lib/mp3/src/mp3common.h"
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
/** Fill the input buffer if it is less than half full.
*
* Returns true if the input buffer contains any useful data,
@ -165,7 +167,6 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
// than the two 4kB output buffers, except that the alignment allows to
// never allocate that extra frame buffer.
self->file = file;
self->inbuf_length = 2048;
self->inbuf_offset = self->inbuf_length;
self->inbuf = m_malloc(self->inbuf_length, false);
@ -181,6 +182,38 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
translate("Couldn't allocate decoder"));
}
if ((intptr_t)buffer & 1) {
buffer += 1; buffer_size -= 1;
}
if (buffer_size >= 2 * MAX_BUFFER_LEN) {
self->buffers[0] = (int16_t*)(void*)buffer;
self->buffers[1] = (int16_t*)(void*)(buffer + MAX_BUFFER_LEN);
} else {
self->buffers[0] = m_malloc(MAX_BUFFER_LEN, false);
if (self->buffers[0] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate first buffer"));
}
self->buffers[1] = m_malloc(MAX_BUFFER_LEN, false);
if (self->buffers[1] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate second buffer"));
}
}
common_hal_audiomp3_mp3file_set_file(self, file);
}
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
self->file = file;
f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length;
self->eof = 0;
self->other_channel = -1;
mp3file_update_inbuf(self);
mp3file_find_sync_word(self);
MP3FrameInfo fi;
if(!mp3file_get_next_frame_info(self, &fi)) {
@ -191,30 +224,7 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
self->sample_rate = fi.samprate;
self->channel_count = fi.nChans;
self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
if ((intptr_t)buffer & 1) {
buffer += 1; buffer_size -= 1;
}
if (buffer_size >= 2 * self->frame_buffer_size) {
self->len = buffer_size / 2 / self->frame_buffer_size * self->frame_buffer_size;
self->buffers[0] = (int16_t*)(void*)buffer;
self->buffers[1] = (int16_t*)(void*)buffer + self->len;
} else {
self->len = 2 * self->frame_buffer_size;
self->buffers[0] = m_malloc(self->len, false);
if (self->buffers[0] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate first buffer"));
}
self->buffers[1] = m_malloc(self->len, false);
if (self->buffers[1] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate second buffer"));
}
}
self->len = 2 * self->frame_buffer_size;
}
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self) {