本篇对于在线音乐播放不做讨论,如果整个系统只有在线音乐播放的功能,系统资源应该是没有问题的。同时也可以支持多种音频的CODEC。
对于本地音频文件播放,由于ESP32芯片系统通常存储和内存资源有限,如果不外挂SRAM,片内只有512KB可用内存,例如我们的项目只有512KB的内存,和4MB的Flash,对于这样的项目,如果要求有音频播放的需求,则要就要考虑:
文件如何存储?内存是否够用?很明显压缩后的音频文件体积会变小,但是Codec解码的时候会需要更多的内存,则系统内存是否可以满足需求。本项目刚开始是保存的mp3格式的文件,由于开启了蓝牙功能,蓝牙消耗内存比较多,系统可用内存所剩无几,但是mp3解码的时候所用的解码器需要消耗大概十几K的内存,内存比较紧张,后来由于我们的音频资源 比较少,就用空间换内存,就采用wav格式的文件,音频没有压缩,直接读文件写入I2S.
1、mp3播放
用mad解码器。在网上可以找到很多播放mp3的例子,在此就不列举代码了。
2、Raw wav文件播放
/* read 4 bytes of data from wav file */
int read4bytes(uint8_t *pos, uint32_t *chunkId){
memcpy((uint8_t *)chunkId, pos, sizeof(uint32_t));
return sizeof(uint32_t);
}
/* these are function to process wav file */
int readRiff(uint8_t *pos, wavRiff_t *wavRiff){
memcpy((uint8_t *)wavRiff, pos, sizeof(wavRiff_t));
return sizeof(wavRiff_t);
}
int readProps(uint8_t *pos, wavProperties_t *wavProps){
memcpy((uint8_t *)wavProps, pos, sizeof(wavProperties_t));
return sizeof(wavProperties_t);
}
void play_wav_files(uint8_t *fstart, uint8_t *fend)
{
//uint8_t *pos = fstart;
//renderer_start();
uint8_t *pos = fstart;
//renderer_zero_dma_buffer();
/*int n = 0;
headerState_t state = HEADER_RIFF;
wavProperties_t wavProps;
while (pos < fend) {
switch(state){
case HEADER_RIFF: {
wavRiff_t wavRiff;
n = readRiff(pos, &wavRiff);
if(n == sizeof(wavRiff_t)){
if(wavRiff.chunkID == CCCC('R', 'I', 'F', 'F') && wavRiff.format == CCCC('W', 'A', 'V', 'E')){
state = HEADER_FMT;
ESP_LOGI(TAG, "HEADER_RIFF");
}
}
pos += n;
break;
}
case HEADER_FMT:
n = readProps(pos, &wavProps);
if(n == sizeof(wavProperties_t)){
state = HEADER_DATA;
}
pos += n;
break;
case HEADER_DATA:{
uint32_t chunkId, chunkSize;
n = read4bytes(pos, &chunkId);
if(n == 4){
if(chunkId == CCCC('d', 'a', 't', 'a')){
ESP_LOGI(TAG, "HEADER_DATA");
}
}
pos += n;
n = read4bytes(pos, &chunkSize);
if(n == 4){
ESP_LOGI(TAG, "prepare data");
state = DATA;
}
pos += n;
wav_buffer_fmt.sample_rate = wavProps.sampleRate;
wav_buffer_fmt.num_channels = wavProps.numChannels;
break;*/
/* after processing wav file, it is time to process music data */
}
case DATA:{
char data[2];
memcpy(data, pos , 2);
pos += 2;
render_samples(data, 2, &wav_buffer_fmt);
if(fend - pos < 2 ) {
ESP_LOGE(TAG, "<<<<<<<<<<<<<<<< Invalid file len <<<<<<<<<<<<<<<");
pos = fend;
}
break;
}
}
}
renderer_zero_dma_buffer();
}