Skip to content

Commit 02154ca

Browse files
committed
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.
1 parent e6fd513 commit 02154ca

File tree

3 files changed

+61
-18
lines changed

3 files changed

+61
-18
lines changed

shared-bindings/audiomp3/MP3File.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,37 @@ STATIC mp_obj_t audiomp3_mp3file_obj___exit__(size_t n_args, const mp_obj_t *arg
129129
}
130130
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomp3_mp3file___exit___obj, 4, 4, audiomp3_mp3file_obj___exit__);
131131

132+
//| .. attribute:: file
133+
//|
134+
//| File to play back.
135+
//|
136+
STATIC mp_obj_t audiomp3_mp3file_obj_get_file(mp_obj_t self_in) {
137+
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
138+
check_for_deinit(self);
139+
return self->file;
140+
}
141+
MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_file_obj, audiomp3_mp3file_obj_get_file);
142+
143+
STATIC mp_obj_t audiomp3_mp3file_obj_set_file(mp_obj_t self_in, mp_obj_t file) {
144+
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
145+
check_for_deinit(self);
146+
if (!MP_OBJ_IS_TYPE(file, &mp_type_fileio)) {
147+
mp_raise_TypeError(translate("file must be a file opened in byte mode"));
148+
}
149+
common_hal_audiomp3_mp3file_set_file(self, file);
150+
return mp_const_none;
151+
}
152+
MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_file_obj, audiomp3_mp3file_obj_set_file);
153+
154+
const mp_obj_property_t audiomp3_mp3file_file_obj = {
155+
.base.type = &mp_type_property,
156+
.proxy = {(mp_obj_t)&audiomp3_mp3file_get_file_obj,
157+
(mp_obj_t)&audiomp3_mp3file_set_file_obj,
158+
(mp_obj_t)&mp_const_none_obj},
159+
};
160+
161+
162+
132163
//| .. attribute:: sample_rate
133164
//|
134165
//| 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[] = {
201232
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) },
202233

203234
// Properties
235+
{ MP_ROM_QSTR(MP_QSTR_file), MP_ROM_PTR(&audiomp3_mp3file_file_obj) },
204236
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomp3_mp3file_sample_rate_obj) },
205237
{ MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiomp3_mp3file_bits_per_sample_obj) },
206238
{ MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiomp3_mp3file_channel_count_obj) },

shared-bindings/audiomp3/MP3File.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern const mp_obj_type_t audiomp3_mp3file_type;
3838
void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
3939
pyb_file_obj_t* file, uint8_t *buffer, size_t buffer_size);
4040

41+
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file);
4142
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self);
4243
bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t* self);
4344
uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t* self);

shared-module/audiomp3/MP3File.c

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "supervisor/shared/translate.h"
3838
#include "lib/mp3/src/mp3common.h"
3939

40+
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
41+
4042
/** Fill the input buffer if it is less than half full.
4143
*
4244
* 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,
165167
// than the two 4kB output buffers, except that the alignment allows to
166168
// never allocate that extra frame buffer.
167169

168-
self->file = file;
169170
self->inbuf_length = 2048;
170171
self->inbuf_offset = self->inbuf_length;
171172
self->inbuf = m_malloc(self->inbuf_length, false);
@@ -181,40 +182,49 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
181182
translate("Couldn't allocate decoder"));
182183
}
183184

184-
mp3file_find_sync_word(self);
185-
MP3FrameInfo fi;
186-
if(!mp3file_get_next_frame_info(self, &fi)) {
187-
mp_raise_msg(&mp_type_RuntimeError,
188-
translate("Failed to parse MP3 file"));
189-
}
190-
191-
self->sample_rate = fi.samprate;
192-
self->channel_count = fi.nChans;
193-
self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
194-
195185
if ((intptr_t)buffer & 1) {
196186
buffer += 1; buffer_size -= 1;
197187
}
198-
if (buffer_size >= 2 * self->frame_buffer_size) {
199-
self->len = buffer_size / 2 / self->frame_buffer_size * self->frame_buffer_size;
188+
if (buffer_size >= 2 * MAX_BUFFER_LEN) {
200189
self->buffers[0] = (int16_t*)(void*)buffer;
201-
self->buffers[1] = (int16_t*)(void*)buffer + self->len;
190+
self->buffers[1] = (int16_t*)(void*)(buffer + MAX_BUFFER_LEN);
202191
} else {
203-
self->len = 2 * self->frame_buffer_size;
204-
self->buffers[0] = m_malloc(self->len, false);
192+
self->buffers[0] = m_malloc(MAX_BUFFER_LEN, false);
205193
if (self->buffers[0] == NULL) {
206194
common_hal_audiomp3_mp3file_deinit(self);
207195
mp_raise_msg(&mp_type_MemoryError,
208196
translate("Couldn't allocate first buffer"));
209197
}
210198

211-
self->buffers[1] = m_malloc(self->len, false);
199+
self->buffers[1] = m_malloc(MAX_BUFFER_LEN, false);
212200
if (self->buffers[1] == NULL) {
213201
common_hal_audiomp3_mp3file_deinit(self);
214202
mp_raise_msg(&mp_type_MemoryError,
215203
translate("Couldn't allocate second buffer"));
216204
}
217205
}
206+
207+
common_hal_audiomp3_mp3file_set_file(self, file);
208+
}
209+
210+
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
211+
self->file = file;
212+
f_lseek(&self->file->fp, 0);
213+
self->inbuf_offset = self->inbuf_length;
214+
self->eof = 0;
215+
self->other_channel = -1;
216+
mp3file_update_inbuf(self);
217+
mp3file_find_sync_word(self);
218+
MP3FrameInfo fi;
219+
if(!mp3file_get_next_frame_info(self, &fi)) {
220+
mp_raise_msg(&mp_type_RuntimeError,
221+
translate("Failed to parse MP3 file"));
222+
}
223+
224+
self->sample_rate = fi.samprate;
225+
self->channel_count = fi.nChans;
226+
self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
227+
self->len = 2 * self->frame_buffer_size;
218228
}
219229

220230
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self) {

0 commit comments

Comments
 (0)