8000 Merge pull request #930 from dhalbert/sd_card_audio_play · sparkfun/circuitpython@720042f · GitHub
[go: up one dir, main page]

Skip to content

Commit 720042f

Browse files
authored
Merge pull request adafruit#930 from dhalbert/sd_card_audio_play
Fix playing audio from SD card
2 parents 618943d + fa814a3 commit 720042f

14 files changed

+153
-46
lines changed

extmod/vfs_fat_diskio.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,17 @@ DRESULT disk_read (
131131
} else {
132132
vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
133133
vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff);
134-
mp_call_method_n_kw(2, 0, vfs->readblocks);
135-
// TODO handle error return
134+
nlr_buf_t nlr;
135+
if (nlr_push(&nlr) == 0) {
136+
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->readblocks);
137+
nlr_pop();
138+
if (mp_obj_get_int(ret) != 0) {
139+
return RES_ERROR;
140+
}
141+
} else {
142+
// Exception thrown by readblocks or something it calls.
143+
return RES_ERROR;
144+
}
136145
}
137146

138147
return RES_OK;
@@ -167,8 +176,17 @@ DRESULT disk_write (
167176
} else {
168177
vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
169178
vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff);
170-
mp_call_method_n_kw(2, 0, vfs->writeblocks);
171-
// TODO handle error return
179+
nlr_buf_t nlr;
180+
if (nlr_push(&nlr) == 0) {
181+
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->writeblocks);
182+
nlr_pop();
183+
if (mp_obj_get_int(ret) != 0) {
184+
return RES_ERROR;
185+
}
186+
} else {
187+
// Exception thrown by writeblocks or something it calls.
188+
return RES_ERROR;
189+
}
172190
}
173191

174192
return RES_OK;

main.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ bool start_mp(safe_mode_t safe_mode) {
233233
}
234234
}
235235

236-
void run_boot_py(safe_mode_t safe_mode) {
236+
void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
237237
// If not in safe mode, run boot before initing USB and capture output in a
238238
// file.
239239
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
@@ -258,10 +258,12 @@ void run_boot_py(safe_mode_t safe_mode) {
258258
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
259259
// during the write, which may happen due to bobbling the power connector or weak power.
260260

261+
static const size_t NUM_CHARS_TO_COMPARE = 160;
261262
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
262-
char file_contents[512];
263+
264+
char file_contents[NUM_CHARS_TO_COMPARE];
263265
UINT chars_read = 0;
264-
f_read(boot_output_file, file_contents, 512, &chars_read);
266+
f_read(boot_output_file, file_contents, NUM_CHARS_TO_COMPARE, &chars_read);
265267
f_close(boot_output_file);
266268
skip_boot_output =
267269
// + 2 accounts for \r\n.

ports/atmel-samd/Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ endif
102102
ifeq ($(DEBUG), 1)
103103
# Turn on Python modules useful for debugging (e.g. uheap, ustack).
104104
CFLAGS += -ggdb
105-
## CFLAGS += -flto
106-
CFLAGS += -fno-inline -fno-ipa-sra
105+
# You may want to disable -flto if it interferes with debugging.
106+
CFLAGS += -flto
107+
# You may want to enable these flags to make setting breakpoints easier.
108+
## CFLAGS += -fno-inline -fno-ipa-sra
107109
ifeq ($(CHIP_FAMILY), samd21)
108110
CFLAGS += -DENABLE_MICRO_TRACE_BUFFER
109111
endif
@@ -112,7 +114,7 @@ else
112114
# -finline-limit=80 or so is similar to not having it on.
113115
# There is no simple default value, though.
114116
ifdef INTERNAL_FLASH_FILESYSTEM
115-
CFLAGS += -finline-limit=60
117+
CFLAGS += -finline-limit=55
116118
endif
117119
CFLAGS += -flto
118120
endif

ports/atmel-samd/audio_dma.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434

3535
#include "py/mpstate.h"
3636

37+
static audio_dma_t* audio_dma_state[AUDIO_DMA_CHANNEL_COUNT];
38+
39+
// This cannot be in audio_dma_state because it's volatile.
40+
static volatile bool audio_dma_pending[AUDIO_DMA_CHANNEL_COUNT];
41+
3742
uint32_t audiosample_sample_rate(mp_obj_t sample_obj) {
3843
if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
3944
audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
@@ -70,7 +75,7 @@ uint8_t audiosample_channel_count(mp_obj_t sample_obj) {
7075
return 1;
7176
}
7277

73-
void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) {
78+
static void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) {
7479
if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
7580
audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
7681
audioio_rawsample_reset_buffer(sample, single_channel, audio_channel);
@@ -81,7 +86,10 @@ void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t
8186
}
8287
}
8388

84-
bool audiosample_get_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t channel, uint8_t** buffer, uint32_t* buffer_length) {
89+
static audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj,
90+
bool single_channel,
91+
uint8_t channel,
92+
uint8_t** buffer, uint32_t* buffer_length) {
8593
if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
8694
audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
8795
return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length);
@@ -90,7 +98,7 @@ bool audiosample_get_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t ch
9098
audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
9199
return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length);
92100
}
93-
return true;
101+
return GET_BUFFER_DONE;
94102
}
95103

96104
static void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel,
@@ -117,7 +125,6 @@ uint8_t find_free_audio_dma_channel(void) {
117125
return channel;
118126
}
119127

120-
audio_dma_t* audio_dma_state[AUDIO_DMA_CHANNEL_COUNT];
121128
void audio_dma_convert_signed(audio_dma_t* dma, uint8_t* buffer, uint32_t buffer_length,
122129
uint8_t** output_buffer, uint32_t* output_buffer_length,
123130
uint8_t* output_spacing) {
@@ -163,15 +170,21 @@ void audio_dma_convert_signed(audio_dma_t* dma, uint8_t* buffer, uint32_t buffer
163170
void audio_dma_load_next_block(audio_dma_t* dma) {
164171
uint8_t* buffer;
165172
uint32_t buffer_length;
166-
bool last_buffer = audiosample_get_buffer(dma->sample, dma->single_channel, dma->audio_channel,
167-
&buffer, &buffer_length);
173+
audioio_get_buffer_result_t get_buffer_result =
174+
audiosample_get_buffer(dma->sample, dma->single_channel, dma->audio_channel,
175+
&buffer, &buffer_length);
168176

169177
DmacDescriptor* descriptor = dma->second_descriptor;
170178
if (dma->first_descriptor_free) {
171179
descriptor = dma_descriptor(dma->dma_channel);
172180
}
173181
dma->first_descriptor_free = !dma->first_descriptor_free;
174182

183+
if (get_buffer_result == GET_BUFFER_ERROR) {
184+
audio_dma_stop(dma);
185+
return;
186+
}
187+
175188
uint8_t* output_buffer;
176189
uint32_t output_buffer_length;
177190
uint8_t output_spacing;
@@ -180,7 +193,7 @@ void audio_dma_load_next_block(audio_dma_t* dma) {
180193

181194
descriptor->BTCNT.reg = output_buffer_length / dma->beat_size / output_spacing;
182195
descriptor->SRCADDR.reg = ((uint32_t) output_buffer) + output_buffer_length;
183-
if (last_buffer) {
196+
if (get_buffer_result == GET_BUFFER_DONE) {
184197
if (dma->loop) {
185198
audiosample_reset_buffer(dma->sample, dma->single_channel, dma->audio_channel);
186199
} else {
@@ -347,6 +360,7 @@ void audio_dma_init(audio_dma_t* dma) {
347360
void audio_dma_reset(void) {
348361
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
349362
audio_dma_state[i] = NULL;
363+
audio_dma_pending[i] = false;
350364
dma_disable_channel(i);
351365
dma_descriptor(i)->BTCTRL.bit.VALID = false;
352366
MP_STATE_PORT(playing_audio)[i] = NULL;
@@ -367,8 +381,12 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
367381

368382
// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
369383
// stack overflow.
384+
370385
void audio_dma_background(void) {
371386
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
387+
if (audio_dma_pending[i]) {
388+
continue;
389+
}
372390
audio_dma_t* dma = audio_dma_state[i];
373391
if (dma == NULL) {
374392
continue;
@@ -379,6 +397,10 @@ void audio_dma_background(void) {
379397
continue;
380398
}
381399

400+
// audio_dma_load_next_block() can call Python code, which can call audio_dma_background()
401+
// recursively at the next background processing time. So disallow recursive calls to here.
402+
audio_dma_pending[i] = true;
382403
audio_dma_load_next_block(dma);
404+
audio_dma_pending[i] = false;
383405
}
384406
}

shared-module/audioio/RawSample.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,18 @@ void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self,
6666
uint8_t channel) {
6767
}
6868

69-
bool audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self,
70-
bool single_channel,
71-
uint8_t channel,
72-
uint8_t** buffer,
73-
uint32_t* buffer_length) {
69+
audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self,
70+
bool single_channel,
71+
uint8_t channel,
72+
uint8_t** buffer,
73+
uint32_t* buffer_length) {
7474
*buffer_length = self->len;
7575
if (single_channel) {
7676
*buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8);
7777
} else {
7878
*buffer = self->buffer;
7979
}
80-
return true;
80+
return GET_BUFFER_DONE;
8181
}
8282

8383
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel,

shared-module/audioio/RawSample.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include "py/obj.h"
3131

32+
#include "shared-module/audioio/__init__.h"
33+
3234
typedef struct {
3335
mp_obj_base_t base;
3436
uint8_t* buffer;
@@ -45,11 +47,11 @@ typedef struct {
4547
void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self,
4648
bool single_channel,
4749
uint8_t channel);
48-
bool audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self,
49-
bool single_channel,
50-
uint8_t channel,
51-
uint8_t** buffer,
52-
uint32_t* buffer_length); // length in bytes
50+
audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self,
51+
bool single_channel,
52+
uint8_t channel,
53+
uint8_t** buffer,
54+
uint32_t* buffer_length); // length in bytes
5355
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel,
5456
bool* single_buffer, bool* samples_signed,
5557
uint32_t* max_buffer_length, uint8_t* spacing);

shared-module/audioio/WaveFile.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <stdint.h>
3030
#include <string.h>
3131

32+
#include "py/mperrno.h"
3233
#include "py/runtime.h"
3334

3435
#include "shared-module/audioio/WaveFile.h"
@@ -50,20 +51,26 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self,
5051
uint8_t chunk_header[16];
5152
f_rewind(&self->file->fp);
5253
UINT bytes_read;
53-
f_read(&self->file->fp, chunk_header, 16, &bytes_read);
54+
if (f_read(&self->file->fp, chunk_header, 16, &bytes_read) != FR_OK) {
55+
mp_raise_OSError(MP_EIO);
56+
}
5457
if (bytes_read != 16 ||
5558
memcmp(chunk_header, "RIFF", 4) != 0 ||
5659
memcmp(chunk_header + 8, "WAVEfmt ", 8) != 0) {
5760
mp_raise_ValueError("Invalid wave file");
5861
}
5962
uint32_t format_size;
60-
f_read(&self->file->fp, &format_size, 4, &bytes_read);
63+
if (f_read(&self->file->fp, &format_size, 4, &bytes_read) != FR_OK) {
64+
mp_raise_OSError(MP_EIO);
65+
}
6166
if (bytes_read != 4 ||
6267
format_size > sizeof(struct wave_format_chunk)) {
6368
mp_raise_ValueError("Invalid format chunk size");
6469
}
6570
struct wave_format_chunk format;
66-
f_read(&self->file->fp, &format, format_size, &bytes_read);
71+
if (f_read(&self->file->fp, &format, format_size, &bytes_read) != FR_OK) {
72+
mp_raise_OSError(MP_EIO);
73+
}
6774
if (bytes_read != format_size) {
6875
}
6976

@@ -83,14 +90,18 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self,
8390
// TODO(tannewt): Skip any extra chunks that occur before the data section.
8491

8592
uint8_t data_tag[4];
86-
f_read(&self->file->fp, &data_tag, 4, &bytes_read);
93+
if (f_read(&self->file->fp, &data_tag, 4, &bytes_read) != FR_OK) {
94+
mp_raise_OSError(MP_EIO);
95+
}
8796
if (bytes_read != 4 ||
8897
memcmp((uint8_t *) data_tag, "data", 4) != 0) {
8998
mp_raise_ValueError("Data chunk must follow fmt chunk");
9099
}
91100

92101
uint32_t data_length;
93-
f_read(&self->file->fp, &data_length, 4, &bytes_read);
102+
if (f_read(&self->file->fp, &data_length, 4, &bytes_read) != FR_OK) {
103+
mp_raise_OSError(MP_EIO);
104+
}
94105
if (bytes_read != 4) {
95106
mp_raise_ValueError("Invalid file");
96107
}
@@ -152,11 +163,11 @@ void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self,
152163
self->right_read_count = 0;
153164
}
154165

155-
bool audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
156-
bool single_channel,
157-
uint8_t channel,
158-
uint8_t** buffer,
159-
uint32_t* buffer_length) {
166+
audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
167+
bool single_channel,
168+
uint8_t channel,
169+
uint8_t** buffer,
170+
uint32_t* buffer_length) {
160171
if (!single_channel) {
161172
channel = 0;
162173
}
@@ -171,7 +182,7 @@ bool audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
171182
if (self->bytes_remaining == 0 && need_more_data) {
172183
*buffer = NULL;
173184
*buffer_length = 0;
174-
return true;
185+
return GET_BUFFER_DONE;
175186
}
176187

177188
if (need_more_data) {
@@ -185,7 +196,9 @@ bool audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
185196
} else {
186197
*buffer = self->buffer;
187198
}
188-
f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read);
199+
if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) {
200+
return GET_BUFFER_ERROR;
201+
}
189202
*buffer_length = length_read;
190203
if (self->buffer_index % 2 == 1) {
191204
self->second_buffer_length = length_read;
@@ -213,7 +226,7 @@ bool audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
213226
*buffer = *buffer + self->bits_per_sample / 8;
214227
}
215228

216-
return self->bytes_remaining == 0;
229+
return self->bytes_remaining == 0 ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA;
217230
}
218231

219232
void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel,

shared-module/audioio/WaveFile.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include "py/obj.h"
3131

32+
#include "shared-module/audioio/__init__.h"
33+
3234
typedef struct {
3335
mp_obj_base_t base;
3436
uint8_t* buffer;
@@ -56,11 +58,11 @@ typedef struct {
5658
void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self,
5759
bool single_channel,
5860
uint8_t channel);
59-
bool audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
60-
bool single_channel,
61-
uint8_t channel,
62-
uint8_t** buffer,
63-
uint32_t* buffer_length); // length in bytes
61+
audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self,
62+
bool single_channel,
63+
uint8_t channel,
64+
uint8_t** buffer,
65+
uint32_t* buffer_length); // length in bytes
6466
void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel,
6567
bool* single_buffer, bool* samples_signed,
6668
uint32_t* max_buffer_length, uint8_t* spacing);

0 commit comments

Comments
 (0)
0