ESP32那些事儿(八):功能开发之音乐播放功能

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/alpha_harrison/article/details/80693978
    本篇对于在线音乐播放不做讨论,如果整个系统只有在线音乐播放的功能,系统资源应该是没有问题的。同时也可以支持多种音频的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();
}

展开阅读全文

没有更多推荐了,返回首页