Skip to content

Commit adbff26

Browse files
authored
Add SDCardPlayMP3 example, helix_mp3_drv and update AmebaFatFSFile (Ameba-AIoT#277)
* Add SDCardPlayMP3 example, helix_mp3_drv and update AmebaFatFSFile Feature: - Add Example SDCardPlayMP3 - Add audio.mp3 API Updates: - Update AmebaFatFSFile.cpp and Update AmebaFatFSFile.h - Add helix_mp3_drv.c and Update helix_mp3_drv.h * Update platform.txt Update platform.txt for new include path. * Update Ameba-AIoT#277 commit Features -change play MP3 example guide to multimedia/example folder. -change helix_mp3_drv.c and .h to multimedia/src folder. -update platform.txt. * Deleted helix_mp3_drv.c and .h Feature Deleted helix_mp3_drv.c and .h from core folder * update Ameba-AIoT#277 -Change file location for sample mp3 to Ameba_misc\Example_Samples folder. -update docs links in SDCardPlayMP3.ino and UVCDObjectDetectionLoop.ino.
1 parent 1215550 commit adbff26

File tree

8 files changed

+280
-6
lines changed

8 files changed

+280
-6
lines changed
3.65 MB
Binary file not shown.

Arduino_package/hardware/libraries/FileSystem/src/AmebaFatFSFile.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#include "Arduino.h"
22
#include "AmebaFatFSFile.h"
33

4+
#ifdef __cplusplus
5+
extern "C" {
6+
#include "helix_mp3_drv.h"
7+
}
8+
#endif
49
File::File(void)
510
{
611
_file = NULL;
@@ -15,15 +20,20 @@ File::File(const char *filename)
1520
bool File::open(const char *filename)
1621
{
1722
FRESULT res = FR_OK;
18-
23+
const char *extension = strrchr(filename, '.');
1924
_file = (FIL *)malloc(sizeof(FIL));
2025
if (_file == NULL) {
2126
res = FR_INT_ERR;
2227
printf("\r\n[ERROR] open file (%s) malloc fail.\n", filename);
2328
return false;
2429
}
2530

26-
res = f_open(_file, filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
31+
if (strcmp(extension, ".mp3") == 0) {
32+
res = f_open(_file, filename, FA_OPEN_EXISTING | FA_READ);
33+
convertMp3ToArray();
34+
} else {
35+
res = f_open(_file, filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
36+
}
2737

2838
if (res != FR_OK) {
2939
printf("\r\n[ERROR] open file (%s) fail. (res=%d)\n", filename, res);
@@ -189,3 +199,55 @@ const char *File::name(void)
189199
}
190200
return NULL;
191201
}
202+
203+
void File::convertMp3ToArray(void)
204+
{
205+
uint32_t mp3_size = 0;
206+
unsigned char *mp3_data = NULL;
207+
208+
if (_file != NULL) {
209+
// Read ID3 header
210+
unsigned char id3_header[10];
211+
f_lseek(_file, 0); // Move to the beginning
212+
UINT bytesRead;
213+
FRESULT res = f_read(_file, id3_header, 10, &bytesRead);
214+
215+
if (res != FR_OK || bytesRead != 10) {
216+
printf("\r\n[ERROR] Failed to read ID3v2 header. (res=%d)\n", res);
217+
return;
218+
}
219+
220+
// Check for ID3v2
221+
if (id3_header[0] == 'I' && id3_header[1] == 'D' && id3_header[2] == '3') {
222+
uint32_t id3v2_size = ((id3_header[6] & 0x7F) << 21) | ((id3_header[7] & 0x7F) << 14) | ((id3_header[8] & 0x7F) << 7) | (id3_header[9] & 0x7F);
223+
f_lseek(_file, id3v2_size + 10); // Move past ID3v2
224+
} else {
225+
f_lseek(_file, 0);
226+
}
227+
228+
// Calculate MP3 size
229+
mp3_size = f_size(_file) - f_tell(_file);
230+
231+
232+
// Allocate memory for MP3 data
233+
mp3_data = (unsigned char *)malloc(mp3_size);
234+
if (mp3_data == NULL) {
235+
printf("\r\n[ERROR] Memory allocation failed for MP3 data.\n");
236+
return;
237+
}
238+
239+
// Read MP3 data
240+
res = f_read(_file, mp3_data, mp3_size, &bytesRead);
241+
242+
if (res != FR_OK || bytesRead != mp3_size) {
243+
printf("\r\n[ERROR] Failed to read MP3 data. (res=%d, bytesRead=%lu)\n", res, bytesRead);
244+
free(mp3_data);
245+
return;
246+
}
247+
audio_play_binary_array(mp3_data, mp3_size);
248+
free(mp3_data);
249+
mp3_data = NULL;
250+
} else {
251+
printf("\r\n[ERROR] No file opened to convert.\n");
252+
}
253+
}

Arduino_package/hardware/libraries/FileSystem/src/AmebaFatFSFile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class File: public Stream {
3535
bool isOpen(void);
3636
const char *name(void);
3737

38+
void convertMp3ToArray(void);
39+
3840
friend class AmebaFatFS;
3941

4042
private:
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* This example decodes an MP3 file from an SD card
2+
and plays audio through a TRRS 3.5mm audio jack module.
3+
4+
Example guide: https://ameba-doc-arduino-sdk.readthedocs-hosted.com/en/latest/amebapro2/Example_Guides/Multimedia/Play%20MP3%20with%20SD%20card.html
5+
6+
*/
7+
#include "AmebaFatFS.h"
8+
9+
#define FILENAME "Audio_test"
10+
#define INTERVAL 1000
11+
12+
AmebaFatFS fs;
13+
14+
void setup()
15+
{
16+
Serial.begin(115200);
17+
18+
fs.begin();
19+
20+
File file = fs.open(String(fs.getRootPath()) + String(FILENAME) + String(".mp3"));
21+
22+
file.close();
23+
}
24+
25+
void loop()
26+
{
27+
delay(INTERVAL);
28+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "mp3dec.h"
2+
#include "audio_api.h"
3+
#include "helix_mp3_drv.h"
4+
#define MP3_MAX_FRAME_SIZE (1600)
5+
#define BUFFER_SIZE (1500)
6+
#define AUDIO_DMA_PAGE_SIZE (2304)
7+
#define I2S_DMA_PAGE_SIZE 2304
8+
#define MP3_DATA_CACHE_SIZE (BUFFER_SIZE + 2 * MP3_MAX_FRAME_SIZE)
9+
#define TX_PAGE_SIZE AUDIO_DMA_PAGE_SIZE // 64*N bytes, max: 4095. 128, 4032
10+
#define TX_PAGE_NUM AUDIO_DMA_PAGE_NUM
11+
#define RX_PAGE_SIZE AUDIO_DMA_PAGE_SIZE // 64*N bytes, max: 4095. 128, 4032
12+
#define RX_PAGE_NUM AUDIO_DMA_PAGE_NUM
13+
#define AUDIO_DMA_PAGE_NUM 4
14+
#define AUDIO_PKT_QUEUE_LENGTH (50)
15+
#define AUDIO_TX_PCM_QUEUE_LENGTH (10)
16+
static uint32_t audio_tx_pcm_cache_len = 0;
17+
static int16_t audio_tx_pcm_cache[AUDIO_DMA_PAGE_SIZE * 3 / 4];
18+
19+
#ifndef SDRAM_BSS_SECTION
20+
#define SDRAM_BSS_SECTION
21+
SECTION(".sdram.bss")
22+
#endif
23+
static xQueueHandle audio_tx_pcm_queue = NULL;
24+
SDRAM_BSS_SECTION static uint8_t decodebuf[8192];
25+
static audio_t g_taudio;
26+
static uint8_t dma_txdata[TX_PAGE_SIZE * TX_PAGE_NUM] __attribute__((aligned(0x20)));
27+
static uint8_t dma_rxdata[RX_PAGE_SIZE * RX_PAGE_NUM] __attribute__((aligned(0x20)));
28+
29+
30+
void audio_play_binary_array(uint8_t *srcbuf, uint32_t len)
31+
{
32+
uint8_t *inbuf;
33+
int bytesLeft;
34+
35+
int ret;
36+
HMP3Decoder hMP3Decoder;
37+
MP3FrameInfo frameInfo;
38+
39+
uint8_t first_frame = 1;
40+
int ch_sel = 0;
41+
short *wTemp;
42+
audio_tx_pcm_queue = xQueueCreate(AUDIO_TX_PCM_QUEUE_LENGTH, AUDIO_DMA_PAGE_SIZE);
43+
hMP3Decoder = MP3InitDecoder();
44+
MP3DecodeSetChannel(ch_sel);
45+
46+
inbuf = srcbuf;
47+
bytesLeft = len;
48+
while (bytesLeft > 0) {
49+
if (bytesLeft > 6) {
50+
ret = MP3Decode(hMP3Decoder, &inbuf, &bytesLeft, (short *)decodebuf, 0);
51+
wTemp = (short *)decodebuf;
52+
} else {
53+
ret = ERR_MP3_INDATA_UNDERFLOW;
54+
}
55+
if (!ret) {
56+
MP3GetLastFrameInfo(hMP3Decoder, &frameInfo);
57+
wTemp = (short *)decodebuf;
58+
if (frameInfo.nChans == 2) {
59+
for (int i = 0; i < 2048; i++) {
60+
wTemp[i] = wTemp[2 * i + ch_sel % 2];
61+
}
62+
frameInfo.outputSamps /= 2;
63+
}
64+
65+
if (first_frame) {
66+
initialize_audio(frameInfo.samprate);
67+
first_frame = 0;
68+
}
69+
audio_play_pcm((int16_t *)decodebuf, frameInfo.outputSamps);
70+
} else {
71+
if (ret != ERR_MP3_INDATA_UNDERFLOW) {
72+
printf("[ERROR] %d\r\n", ret);
73+
}
74+
break;
75+
}
76+
}
77+
78+
printf("decoding finished\r\n");
79+
}
80+
81+
void initialize_audio(int sample_rate)
82+
{
83+
uint8_t smpl_rate_idx = ASR_16KHZ;
84+
// audio_sr smpl_rate_idx = ASR_16KHZ;
85+
86+
switch (sample_rate) {
87+
case 8000:
88+
smpl_rate_idx = ASR_8KHZ;
89+
break;
90+
case 16000:
91+
smpl_rate_idx = ASR_16KHZ;
92+
break;
93+
case 32000:
94+
smpl_rate_idx = ASR_32KHZ;
95+
break;
96+
case 44100:
97+
smpl_rate_idx = ASR_44p1KHZ;
98+
break;
99+
case 48000:
100+
smpl_rate_idx = ASR_48KHZ;
101+
break;
102+
case 88200:
103+
smpl_rate_idx = ASR_88p2KHZ;
104+
break;
105+
case 96000:
106+
smpl_rate_idx = ASR_96KHZ;
107+
break;
108+
default:
109+
break;
110+
}
111+
112+
audio_init(&g_taudio, OUTPUT_SINGLE_EDNED, MIC_SINGLE_EDNED, AUDIO_CODEC_2p8V);
113+
audio_dac_digital_vol(&g_taudio, 0xAF / 2);
114+
115+
// Init TX dma
116+
117+
audio_set_dma_buffer(&g_taudio, dma_txdata, dma_rxdata, AUDIO_DMA_PAGE_SIZE, AUDIO_DMA_PAGE_NUM);
118+
119+
120+
audio_rx_irq_handler(&g_taudio, (audio_irq_handler)audio_rx_complete, (uint32_t *)&g_taudio);
121+
122+
// Init TX dma
123+
audio_tx_irq_handler(&g_taudio, (audio_irq_handler)audio_tx_complete, (uint32_t *)&g_taudio);
124+
125+
audio_set_param(&g_taudio, smpl_rate_idx, WL_16BIT); // ASR_8KHZ, ASR_16KHZ //ASR_48KHZ
126+
// audio_mic_analog_gain(&g_taudio, 1, AUDIO_MIC_40DB); // default 0DB
127+
128+
129+
/* Use (DMA page count -1) because occur RX interrupt in first */
130+
for (int i = 0; i < (AUDIO_DMA_PAGE_NUM - 1); i++) {
131+
uint8_t *ptx_buf = audio_get_tx_page_adr(&g_taudio);
132+
if (ptx_buf) {
133+
memset(ptx_buf, 0x0, AUDIO_DMA_PAGE_SIZE);
134+
audio_set_tx_page(&g_taudio, ptx_buf);
135+
}
136+
audio_set_rx_page(&g_taudio);
137+
}
138+
139+
140+
audio_trx_start(&g_taudio);
141+
}
142+
143+
void audio_tx_complete(uint32_t arg, uint8_t *pbuf)
144+
{
145+
uint8_t *ptx_buf;
146+
147+
ptx_buf = (uint8_t *)audio_get_tx_page_adr(&g_taudio);
148+
if (xQueueReceiveFromISR(audio_tx_pcm_queue, ptx_buf, NULL) != pdPASS) {
149+
memset(ptx_buf, 0, AUDIO_DMA_PAGE_SIZE);
150+
}
151+
audio_set_tx_page(&g_taudio, (uint8_t *)ptx_buf);
152+
}
153+
154+
void audio_rx_complete(uint32_t arg, uint8_t *pbuf)
155+
{
156+
audio_t *obj = (audio_t *)arg;
157+
audio_set_rx_page(obj);
158+
}
159+
160+
void audio_play_pcm(int16_t *buf, uint32_t len)
161+
{
162+
for (int i = 0; i < len; i++) {
163+
audio_tx_pcm_cache[audio_tx_pcm_cache_len++] = buf[i];
164+
if (audio_tx_pcm_cache_len == AUDIO_DMA_PAGE_SIZE / 2) {
165+
xQueueSend(audio_tx_pcm_queue, audio_tx_pcm_cache, portMAX_DELAY);
166+
audio_tx_pcm_cache_len = 0;
167+
}
168+
}
169+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef HELIX_MP3_DRV_H
2+
#define HELIX_MP3_DRV_H
3+
#include <stdint.h>
4+
#include <string.h>
5+
#include <stdio.h>
6+
void audio_play_binary_array(uint8_t *srcbuf, uint32_t len);
7+
8+
void initialize_audio(int sample_rate);
9+
void audio_play_pcm(int16_t *buf, uint32_t len);
10+
void audio_rx_complete(uint32_t arg, uint8_t *pbuf);
11+
void audio_tx_complete(uint32_t arg, uint8_t *pbuf);
12+
13+
#endif

Arduino_package/hardware/libraries/NeuralNetwork/examples/UVCDObjectDetectionLoop/UVCDObjectDetectionLoop.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Connect to PC and use the device as a USB camera.
55
Perform objects prediction when the device is connect to PC and PotPlayer.
66
7-
Example guide: TBD
7+
Example guide: https://ameba-doc-arduino-sdk.readthedocs-hosted.com/en/latest/amebapro2/Example_Guides/Neural%20Network/UVCD%20Object%20Detection.html
88
99
1010
NN Model Selection

0 commit comments

Comments
 (0)