Skip to content

Commit a10cd85

Browse files
authored
Merge pull request #2445 from jepler/mp3-jeplayer-fixes
Fixes for JEplayer
2 parents 28c1e4f + dd6010a commit a10cd85

File tree

7 files changed

+119
-38
lines changed

7 files changed

+119
-38
lines changed

ports/atmel-samd/peripherals

py/circuitpy_defns.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ SRC_SHARED_MODULE_ALL = \
323323
audiomixer/Mixer.c \
324324
audiomixer/MixerVoice.c \
325325
audiomp3/__init__.c \
326-
audiomp3/MP3File.c \
326+
audiomp3/MP3Decoder.c \
327327
bitbangio/I2C.c \
328328
bitbangio/OneWire.c \
329329
bitbangio/SPI.c \

shared-bindings/audiomp3/MP3File.c renamed to shared-bindings/audiomp3/MP3Decoder.c

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,16 @@
3030
#include "lib/utils/context_manager_helpers.h"
3131
#include "py/objproperty.h"
3232
#include "py/runtime.h"
33-
#include "shared-bindings/audiomp3/MP3File.h"
33+
#include "shared-bindings/audiomp3/MP3Decoder.h"
3434
#include "shared-bindings/util.h"
3535
#include "supervisor/shared/translate.h"
3636

3737
//| .. currentmodule:: audiomp3
3838
//|
39-
//| :class:`MP3` -- Load a mp3 file for audio playback
40-
//| ========================================================
39+
//| :class:`MP3Decoder` -- Load a mp3 file for audio playback
40+
//| =========================================================
4141
//|
42-
//| A .mp3 file prepped for audio playback. Only mono and stereo files are supported. Samples must
43-
//| be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating
44-
//| an internal buffer.
42+
//| An object that decodes MP3 files for playback on an audio device.
4543
//|
4644
//| .. class:: MP3(file[, buffer])
4745
//|
@@ -63,7 +61,7 @@
6361
//| speaker_enable.switch_to_output(value=True)
6462
//|
6563
//| data = open("cplay-16bit-16khz-64kbps.mp3", "rb")
66-
//| mp3 = audiomp3.MP3File(data)
64+
//| mp3 = audiomp3.MP3Decoder(data)
6765
//| a = audioio.AudioOut(board.A0)
6866
//|
6967
//| print("playing")
@@ -129,6 +127,37 @@ STATIC mp_obj_t audiomp3_mp3file_obj___exit__(size_t n_args, const mp_obj_t *arg
129127
}
130128
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomp3_mp3file___exit___obj, 4, 4, audiomp3_mp3file_obj___exit__);
131129

130+
//| .. attribute:: file
131+
//|
132+
//| File to play back.
133+
//|
134+
STATIC mp_obj_t audiomp3_mp3file_obj_get_file(mp_obj_t self_in) {
135+
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
136+
check_for_deinit(self);
137+
return self->file;
138+
}
139+
MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_file_obj, audiomp3_mp3file_obj_get_file);
140+
141+
STATIC mp_obj_t audiomp3_mp3file_obj_set_file(mp_obj_t self_in, mp_obj_t file) {
142+
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
143+
check_for_deinit(self);
144+
if (!MP_OBJ_IS_TYPE(file, &mp_type_fileio)) {
145+
mp_raise_TypeError(translate("file must be a file opened in byte mode"));
146+
}
147+
common_hal_audiomp3_mp3file_set_file(self, file);
148+
return mp_const_none;
149+
}
150+
MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_file_obj, audiomp3_mp3file_obj_set_file);
151+
152+
const mp_obj_property_t audiomp3_mp3file_file_obj = {
153+
.base.type = &mp_type_property,
154+
.proxy = {(mp_obj_t)&audiomp3_mp3file_get_file_obj,
155+
(mp_obj_t)&audiomp3_mp3file_set_file_obj,
156+
(mp_obj_t)&mp_const_none_obj},
157+
};
158+
159+
160+
132161
//| .. attribute:: sample_rate
133162
//|
134163
//| 32 bit value that dictates how quickly samples are loaded into the DAC
@@ -193,6 +222,24 @@ const mp_obj_property_t audiomp3_mp3file_channel_count_obj = {
193222
(mp_obj_t)&mp_const_none_obj},
194223
};
195224

225+
//| .. attribute:: rms_level
226+
//|
227+
//| The RMS audio level of a recently played moment of audio. (read only)
228+
//|
229+
STATIC mp_obj_t audiomp3_mp3file_obj_get_rms_level(mp_obj_t self_in) {
230+
audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
231+
check_for_deinit(self);
232+
return mp_obj_new_float(common_hal_audiomp3_mp3file_get_rms_level(self));
233+
}
234+
MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_rms_level_obj, audiomp3_mp3file_obj_get_rms_level);
235+
236+
const mp_obj_property_t audiomp3_mp3file_rms_level_obj = {
237+
.base.type = &mp_type_property,
238+
.proxy = {(mp_obj_t)&audiomp3_mp3file_get_rms_level_obj,
239+
(mp_obj_t)&mp_const_none_obj,
240+
(mp_obj_t)&mp_const_none_obj},
241+
};
242+
196243

197244
STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = {
198245
// Methods
@@ -201,9 +248,11 @@ STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = {
201248
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) },
202249

203250
// Properties
251+
{ MP_ROM_QSTR(MP_QSTR_file), MP_ROM_PTR(&audiomp3_mp3file_file_obj) },
204252
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomp3_mp3file_sample_rate_obj) },
205253
{ MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiomp3_mp3file_bits_per_sample_obj) },
206254
{ MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiomp3_mp3file_channel_count_obj) },
255+
{ MP_ROM_QSTR(MP_QSTR_rms_level), MP_ROM_PTR(&audiomp3_mp3file_rms_level_obj) },
207256
};
208257
STATIC MP_DEFINE_CONST_DICT(audiomp3_mp3file_locals_dict, audiomp3_mp3file_locals_dict_table);
209258

@@ -219,7 +268,7 @@ STATIC const audiosample_p_t audiomp3_mp3file_proto = {
219268

220269
const mp_obj_type_t audiomp3_mp3file_type = {
221270
{ &mp_type_type },
222-
.name = MP_QSTR_MP3File,
271+
.name = MP_QSTR_MP3Decoder,
223272
.make_new = audiomp3_mp3file_make_new,
224273
.locals_dict = (mp_obj_dict_t*)&audiomp3_mp3file_locals_dict,
225274
.protocol = &audiomp3_mp3file_proto,

shared-bindings/audiomp3/MP3File.h renamed to shared-bindings/audiomp3/MP3Decoder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,20 @@
3131
#include "py/obj.h"
3232
#include "extmod/vfs_fat.h"
3333

34-
#include "shared-module/audiomp3/MP3File.h"
34+
#include "shared-module/audiomp3/MP3Decoder.h"
3535

3636
extern const mp_obj_type_t audiomp3_mp3file_type;
3737

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);
4445
void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t* self, uint32_t sample_rate);
4546
uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t* self);
4647
uint8_t common_hal_audiomp3_mp3file_get_channel_count(audiomp3_mp3file_obj_t* self);
48+
float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self);
4749

4850
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MP3FILE_H

shared-bindings/audiomp3/__init__.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include "py/obj.h"
3030
#include "py/runtime.h"
3131

32-
#include "shared-bindings/audiomp3/MP3File.h"
32+
#include "shared-bindings/audiomp3/MP3Decoder.h"
3333

3434
//| :mod:`audiomp3` --- Support for MP3-compressed audio files
3535
//| ==========================================================
@@ -44,12 +44,12 @@
4444
//| .. toctree::
4545
//| :maxdepth: 3
4646
//|
47-
//| MP3File
47+
//| MP3Decoder
4848
//|
4949

5050
STATIC const mp_rom_map_elem_t audiomp3_module_globals_table[] = {
5151
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiomp3) },
52-
{ MP_ROM_QSTR(MP_QSTR_MP3File), MP_ROM_PTR(&audiomp3_mp3file_type) },
52+
{ MP_ROM_QSTR(MP_QSTR_MP3Decoder), MP_ROM_PTR(&audiomp3_mp3file_type) },
5353
};
5454

5555
STATIC MP_DEFINE_CONST_DICT(audiomp3_module_globals, audiomp3_module_globals_table);

shared-module/audiomp3/MP3File.c renamed to shared-module/audiomp3/MP3Decoder.c

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@
2525
* THE SOFTWARE.
2626
*/
2727

28-
#include "shared-bindings/audiomp3/MP3File.h"
28+
#include "shared-bindings/audiomp3/MP3Decoder.h"
2929

3030
#include <stdint.h>
3131
#include <string.h>
32+
#include <math.h>
3233

3334
#include "py/mperrno.h"
3435
#include "py/runtime.h"
3536

36-
#include "shared-module/audiomp3/MP3File.h"
37+
#include "shared-module/audiomp3/MP3Decoder.h"
3738
#include "supervisor/shared/translate.h"
3839
#include "lib/mp3/src/mp3common.h"
3940

41+
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
42+
4043
/** Fill the input buffer if it is less than half full.
4144
*
4245
* Returns true if the input buffer contains any useful data,
@@ -143,7 +146,7 @@ STATIC bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t* self, MP3FrameIn
143146
do {
144147
err = MP3GetNextFrameInfo(self->decoder, fi, READ_PTR(self));
145148
if (err == ERR_MP3_NONE) {
146-
break;
149+
break;
147150
}
148151
CONSUME(self, 1);
149152
mp3file_find_sync_word(self);
@@ -165,7 +168,6 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
165168
// than the two 4kB output buffers, except that the alignment allows to
166169
// never allocate that extra frame buffer.
167170

168-
self->file = file;
169171
self->inbuf_length = 2048;
170172
self->inbuf_offset = self->inbuf_length;
171173
self->inbuf = m_malloc(self->inbuf_length, false);
@@ -181,40 +183,56 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
181183
translate("Couldn't allocate decoder"));
182184
}
183185

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-
195186
if ((intptr_t)buffer & 1) {
196187
buffer += 1; buffer_size -= 1;
197188
}
198-
if (buffer_size >= 2 * self->frame_buffer_size) {
199-
self->len = buffer_size / 2 / self->frame_buffer_size * self->frame_buffer_size;
189+
if (buffer_size >= 2 * MAX_BUFFER_LEN) {
200190
self->buffers[0] = (int16_t*)(void*)buffer;
201-
self->buffers[1] = (int16_t*)(void*)buffer + self->len;
191+
self->buffers[1] = (int16_t*)(void*)(buffer + MAX_BUFFER_LEN);
202192
} else {
203-
self->len = 2 * self->frame_buffer_size;
204-
self->buffers[0] = m_malloc(self->len, false);
193+
self->buffers[0] = m_malloc(MAX_BUFFER_LEN, false);
205194
if (self->buffers[0] == NULL) {
206195
common_hal_audiomp3_mp3file_deinit(self);
207196
mp_raise_msg(&mp_type_MemoryError,
208197
translate("Couldn't allocate first buffer"));
209198
}
210199

211-
self->buffers[1] = m_malloc(self->len, false);
200+
self->buffers[1] = m_malloc(MAX_BUFFER_LEN, false);
212201
if (self->buffers[1] == NULL) {
213202
common_hal_audiomp3_mp3file_deinit(self);
214203
mp_raise_msg(&mp_type_MemoryError,
215204
translate("Couldn't allocate second buffer"));
216205
}
217206
}
207+
208+
common_hal_audiomp3_mp3file_set_file(self, file);
209+
}
210+
211+
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
212+
self->file = file;
213+
f_lseek(&self->file->fp, 0);
214+
self->inbuf_offset = self->inbuf_length;
215+
self->eof = 0;
216+
self->other_channel = -1;
217+
mp3file_update_inbuf(self);
218+
mp3file_find_sync_word(self);
219+
// It **SHOULD** not be necessary to do this; the buffer should be filled
220+
// with fresh content before it is returned by get_buffer(). The fact that
221+
// this is necessary to avoid a glitch at the start of playback of a second
222+
// track using the same decoder object means there's still a bug in
223+
// get_buffer() that I didn't understand.
224+
memset(self->buffers[0], 0, MAX_BUFFER_LEN);
225+
memset(self->buffers[1], 0, MAX_BUFFER_LEN);
226+
MP3FrameInfo fi;
227+
if(!mp3file_get_next_frame_info(self, &fi)) {
228+
mp_raise_msg(&mp_type_RuntimeError,
229+
translate("Failed to parse MP3 file"));
230+
}
231+
232+
self->sample_rate = fi.samprate;
233+
self->channel_count = fi.nChans;
234+
self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
235+
self->len = 2 * self->frame_buffer_size;
218236
}
219237

220238
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self) {
@@ -280,7 +298,6 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
280298
channel = 0;
281299
}
282300

283-
*bufptr = (uint8_t*)(self->buffers[self->buffer_index] + channel);
284301
*buffer_length = self->frame_buffer_size;
285302

286303
if (channel == self->other_channel) {
@@ -289,11 +306,12 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
289306
return GET_BUFFER_MORE_DATA;
290307
}
291308

292-
self->other_channel = 1-channel;
293-
self->other_buffer_index = self->buffer_index;
294309

295310
self->buffer_index = !self->buffer_index;
311+
self->other_channel = 1-channel;
312+
self->other_buffer_index = self->buffer_index;
296313
int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
314+
*bufptr = (uint8_t*)buffer;
297315

298316
mp3file_skip_id3v2(self);
299317
if (!mp3file_find_sync_word(self)) {
@@ -322,3 +340,13 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool si
322340
*spacing = 1;
323341
}
324342
}
343+
344+
float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self) {
345+
float sumsq = 0.f;
346+
// Assumes no DC component to the audio. Is that a safe assumption?
347+
int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
348+
for(size_t i=0; i<self->frame_buffer_size / sizeof(int16_t); i++) {
349+
sumsq += (float)buffer[i] * buffer[i];
350+
}
351+
return sqrtf(sumsq) / (self->frame_buffer_size / sizeof(int16_t));
352+
}

shared-module/audiomp3/MP3File.h renamed to shared-module/audiomp3/MP3Decoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool si
6767
bool* single_buffer, bool* samples_signed,
6868
uint32_t* max_buffer_length, uint8_t* spacing);
6969

70+
float audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self);
71+
7072
#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy