首頁 > 評(píng)測(cè) > 基于靈動(dòng)MM32F5270開發(fā)板播放MP3和WAV音頻文件

基于靈動(dòng)MM32F5270開發(fā)板播放MP3和WAV音頻文件

  
  • 作者:
  • 來源:
  • [導(dǎo)讀]
  • 本帖最后由 春嬌霹靂娃 于 2023-6-16 14:47 編輯 #申請(qǐng)?jiān)瓌?chuàng)# @21小跑堂 一、I2S簡(jiǎn)介 I2S(Inter-IC Sound)總線為集成在芯片內(nèi)的音頻總線,是飛利浦公司為數(shù)字音頻設(shè)備之間的音頻數(shù)據(jù)傳輸而制定的一種總

本帖最后由 春嬌霹靂娃 于 2023-6-16 14:47 編輯

#申請(qǐng)?jiān)瓌?chuàng)# @21小跑堂

一、I2S簡(jiǎn)介
I2S(Inter-IC Sound)總線為集成在芯片內(nèi)的音頻總線,是飛利浦公司為數(shù)字音頻設(shè)備之間的音頻數(shù)據(jù)傳輸而制定的一種總線標(biāo)準(zhǔn)。

MM32F5270系列MCU最多支持3個(gè)I2S接口,支持半雙工通信和全雙工通信,數(shù)據(jù)幀格式可配置為 16 位、24 位或 32 位。數(shù)據(jù)傳輸方向始終是MSB優(yōu)先,且每個(gè)I2S接口都支持DMA傳輸方式。MM32F5270系列的I2S支持飛利浦標(biāo)準(zhǔn)、MSB向左對(duì)齊標(biāo)準(zhǔn)、LSB向右對(duì)齊標(biāo)準(zhǔn)和PCM標(biāo)準(zhǔn)四種。

MM32F5270 是一款搭載了安謀科技 Arm China STAR-MC1 內(nèi)核的 MCU 產(chǎn)品,其工作頻率可達(dá) 120MHz,內(nèi)置多達(dá) 256KB Flash 和 192KB RAM。MM32F5270 相較于現(xiàn)有產(chǎn)品全面提升了性能、存儲(chǔ)容量、總線架構(gòu)和外設(shè)配置,旨在覆蓋更廣泛的工業(yè)、汽車和 IoT 應(yīng)用。

二、本文實(shí)現(xiàn)音頻播放的設(shè)計(jì)框架
本實(shí)驗(yàn)搭載在 PLUS-F5270 開發(fā)板,通過 SDSPI 組件實(shí)現(xiàn) FatFs 移植讀取音頻文件,分為 WAV 格式音頻文件解碼和 MP3 格式音頻文件通過 libmad 解碼。組件包含SDSPI、FatFS 和 Libmad 三部分組成,整個(gè)設(shè)計(jì)框圖如下圖:



三、實(shí)驗(yàn)環(huán)境


1.硬件環(huán)境:MM32F5277E9P開發(fā)板,SD卡及讀卡器



I2S 部分電路原理圖:


2.軟件環(huán)境:KEIL軟件,Tera Term 終端軟件,酷狗音樂

本實(shí)驗(yàn)整個(gè)設(shè)計(jì)思路為:
1.通過 SDSPI 接口操作 SD 卡,移植 FatFs 文件系統(tǒng)對(duì)音頻文件進(jìn)行識(shí)別,對(duì)音頻文件數(shù)據(jù)進(jìn)行讀取操作;
2.通過 DMA 搬運(yùn)的方式,將存儲(chǔ)在 SD 卡中的音頻文件(WAV 格式 / MP3 格式)通過 I2S 總線,將音頻數(shù)據(jù)發(fā)送給 CS4344 音頻數(shù)模轉(zhuǎn)換芯片,從而播放出音樂;
3.開啟 DMA 傳輸完成中斷和半傳輸完成中斷;
4.使用雙緩沖區(qū),實(shí)現(xiàn)流暢的音頻文件播放效果。

四、FatFS簡(jiǎn)介
1.FatFs official website: http://elm-chan.org/fsw/ff/00index_e.html
FatFS 負(fù)責(zé)管理和存儲(chǔ)文件信息的軟件機(jī)構(gòu),是一種在磁盤上組織文件的方法。其優(yōu)點(diǎn)有:
  • C 語言編寫,支持 FAT12, FAT16 和 FAT32
  • 支持多種存儲(chǔ)媒介,有獨(dú)立的緩沖區(qū),可對(duì)多個(gè)文件進(jìn)行讀寫
  • 可裁剪的文件系統(tǒng)
  • 免費(fèi)開源,專門為小型嵌入式系統(tǒng)設(shè)計(jì)

2.移植FatFS
適配ffconf.h和diskio.c文件,使編譯通過。


FatFS常用的API如下圖:


五、WAV格式音頻文件
1.WAV是 Waveform 的簡(jiǎn)寫,也叫波形文件,是一種可以存儲(chǔ)聲音波形的數(shù)字音頻格式。其具有真實(shí)記錄聲音波形的特點(diǎn),基本無數(shù)據(jù)壓縮,數(shù)據(jù)體量相對(duì)較大。典型的WAV文件格式如下圖:

WAV 文件采用的是 RIFF 格式結(jié)構(gòu),至少由 RIFF 塊、fmt 塊和 data 塊組成。每個(gè) RIFF 文件由若干個(gè)塊 (chunk) 組成,每個(gè)塊由塊標(biāo)識(shí)、塊長(zhǎng)度以及數(shù)據(jù)這三部分組成。塊標(biāo)識(shí)由 4 個(gè) ASCII 碼字符組成的,如果不滿 4 個(gè)字符則在右邊以空格來補(bǔ)齊。塊長(zhǎng)度由 4 個(gè)字節(jié)存儲(chǔ)空間,保存的是當(dāng)前塊數(shù)據(jù)的長(zhǎng)度,但不包含塊標(biāo)識(shí)和塊長(zhǎng)度字段,所以一個(gè)塊的實(shí)際長(zhǎng)度就是塊長(zhǎng)度字段的數(shù)值再加上 8 字節(jié)。

WAV文件格式實(shí)例解析如下:


2.WAV文件解碼

 

  • 結(jié)構(gòu)體定義:wav_decode.h
  • 結(jié)構(gòu)解析:
  • bool wav_decode_open(wav_decode_obj_t * obj, char * file_name, uint8_t * buf, uint32_t buf_size)
  • bool wav_decode_read(wav_decode_obj_t * obj, uint16_t * buf, uint32_t buf_len)
  • void wav_decode_close(wav_decode_obj_t * obj)
  • 播放實(shí)現(xiàn):void app_wav_play(void)


wav_decode_open 打開FatFS 中音頻文件:

  1. <font face="Arial"><span style="background-color: black;"><font color="#fffacd">/* open fatfs file. */
  2. bool wav_decode_open(wav_decode_obj_t * obj,char * file_name, uint8_t * buf, uint32_t buf_size){
  3.      UINT fatfs_br = 0u;
  4.      uint8_t offset = 0u;
  5.      if (FR_OK != f_open(&(obj->fatfs_file), file_name, FA_READ) ){
  6.          return false;}
  7.      obj->fatfs_buf = buf;
  8.      obj->fatfs_buf_size = buf_size;
  9.      if (FR_OK != f_read(&(obj->fatfs_file), obj->fatfs_buf, WAV_DECODE_HEAD_BUFFER_SIZE, &fatfs_br)){
  10.          return false;}
  11.     chunk_riff_def_t *chunk_riff;
  12.     chunk_fmt_def_t  *chunk_fmt;
  13.     chunk_fact_def_t *chunk_fact;
  14.     chunk_data_def_t *chunk_data;
  15.  
  16.     chunk_riff = (chunk_riff_def_t *)(obj->fatfs_buf);
  17.     chunk_fmt  = (chunk_fmt_def_t  *)(obj->fatfs_buf + 12);
  18.     chunk_fact = (chunk_fact_def_t *)(obj->fatfs_buf + 12 + 8 + chunk_fmt->sub_chunk1_size);
  19.  
  20.     if((chunk_fact->chunk_id == 0x74636166) || (chunk_fact->chunk_id == 0x5453494C)){
  21.         chunk_data = (chunk_data_def_t *)(obj->fatfs_buf + 12 + 8 + chunk_fmt->sub_chunk1_size + 8 + chunk_fact->chunk_size);
  22.         offset = 12 + 8 + chunk_fmt->sub_chunk1_size + 8 + chunk_fact->chunk_size;}
  23.     else{
  24.         chunk_data = (chunk_data_def_t *)(obj->fatfs_buf + 12 + 8 + chunk_fmt->sub_chunk1_size);
  25.         offset = 12 + 8 + chunk_fmt->sub_chunk1_size;}
  26.  
  27.     if(chunk_riff->format == 0x45564157 && chunk_data->sub_chunk2_id == 0x61746164){
  28.          obj->audio_format    = chunk_fmt->audio_format;
  29.          obj->channel         = chunk_fmt->num_of_channels;
  30.          obj->sample_rate     = chunk_fmt->sample_rate;
  31.          obj->bits_per_sample = chunk_fmt->bits_per_sample;
  32.          obj->bit_rate        = chunk_fmt->byte_rate * 8;
  33.          obj->block_align     = chunk_fmt->block_align;
  34.  
  35.          obj->data_size  = chunk_data->sub_chunk2_size;
  36.          obj->data_start_offset = offset;
  37.          obj->total_second = obj->data_size;
  38.     }else{
  39.         return false;}
  40.      return true;
  41. }</font></span></font>
復(fù)制代碼

wav_decode_read 讀取音頻文件數(shù)據(jù):

  1. <font face="Arial">/* read fatfs file. */
  2. bool wav_decode_read(wav_decode_obj_t * obj,uint16_t * buf,uint32_t buf_len){
  3.      UINT fat_br = 0u;
  4.      if (FR_OK != f_read(&(obj->fatfs_file), buf, buf_len,&fat_br) ){
  5.          return false;}
  6.      obj->current_second+=fat_br;
  7.  
  8.      if((fat_br <= 0) || (fat_br < buf_len)){
  9.      return false;}
  10.      return true;
  11. }</font>
復(fù)制代碼

wav_decode_close 解碼數(shù)據(jù)結(jié)束:

  1. <font face="Arial">/* close fatfs file. */
  2. void wav_decode_close(wav_decode_obj_t * obj){
  3.     f_close(&(obj->fatfs_file) );}
  4. </font>
復(fù)制代碼

app_wav_play 播放 WAV:

  1. <font face="Arial">/* play wave audio. */
  2. void app_wav_play(void){
  3.     if( wav_decode_open(&wav_obj, file_path, file_buf, 10240) ){
  4.         if( (wav_obj.bits_per_sample == 16) &&
  5.             (wav_obj.channel == 2) &&
  6.             (wav_obj.sample_rate > 44000) &&
  7.             (wav_obj.sample_rate < 48100)){
  8.             Audio_ClearStatus(AUDIO_STATUS_XFER_HALF | AUDIO_STATUS_XFER_DONE);
  9.             wav_decode_read(&wav_obj, audio_buf[0], 5120);
  10.  
  11.             Audio_SetConf(44100, (uint16_t *)audio_buf[0], 2560);
  12.             Audio_Enable(true);}}
  13.     else{
  14.         return;}
  15.  
  16.     uint8_t next_index = 1;
  17.  
  18.     while(1){
  19.         while((Audio_GetStatus() & AUDIO_STATUS_XFER_HALF) != AUDIO_STATUS_XFER_HALF);
  20.         Audio_ClearStatus(AUDIO_STATUS_XFER_HALF);
  21.         if(next_index == 0){
  22.             if(!wav_decode_read(&wav_obj,audio_buf[0], 5120)){
  23.                 break;}}
  24.         else{
  25.             if(!wav_decode_read(&wav_obj,audio_buf[1], 5120)){
  26.                 break;}}
  27.  
  28.         while((Audio_GetStatus() & AUDIO_STATUS_XFER_DONE) != AUDIO_STATUS_XFER_DONE);
  29.         Audio_ClearStatus(AUDIO_STATUS_XFER_DONE);
  30.  
  31.         if(next_index == 0){
  32.             Audio_SetConf(44100, (uint16_t *)audio_buf[0], 2560);
  33.             next_index = 1;}
  34.         else{
  35.             Audio_SetConf(44100, (uint16_t *)audio_buf[1], 2560);
  36.             next_index = 0;}
  37.         Audio_Enable(true);}
  38.  
  39.     Audio_Enable(false);
  40.     wav_decode_close(&wav_obj);}</font>
復(fù)制代碼


六、MP3音頻文件解碼

1.MP3 格式音樂文件 (Moving Picture Experts Group Audio Layer III (MPEG Audio Layer 3) ),經(jīng)過壓縮后的 MP3 文件數(shù)據(jù)由多個(gè)幀 (frame) 組成。幀是 MP3 文件的最小組成單位,每個(gè)幀由幀頭 、附加信息和聲音數(shù)據(jù)組成,幀的長(zhǎng)度由不同的 MP3 文件而不同,每個(gè)幀包含一段音頻的壓縮數(shù)據(jù),通過解碼庫(kù)解碼即可得到對(duì)應(yīng) PCM 音頻數(shù)據(jù)。

2.MP3解碼庫(kù)

適合在小型嵌入式控制器移植的有兩個(gè)開源 MP3 解碼庫(kù),libmad 解碼庫(kù)和 helix 解碼庫(kù),這兩個(gè)解碼庫(kù)都是以一幀為解碼單位,一次解碼一幀,其區(qū)別見下表:

Libmad Helix
  • 高精度的MPEG音頻解碼庫(kù)
  • 支持MPEG-1、MPEG-2、MPEG-2.5標(biāo)準(zhǔn)
  • 提供24 bit PCM輸出
  • 用定點(diǎn)運(yùn)算模擬浮點(diǎn)運(yùn)算,不需要處理器有浮點(diǎn)運(yùn)算功能
  • 對(duì)MP3解碼中關(guān)鍵部分采用優(yōu)化算法
  • 軟件庫(kù)結(jié)構(gòu)清晰,易于開發(fā)和使用
。。。
  • 支持MPEG-1、MPEG-2、MPEG-2.5標(biāo)準(zhǔn)
  • 支持定點(diǎn)和浮點(diǎn)運(yùn)算
  • 支持可變位恒率、恒定位速率及立體聲、單聲道音頻格式
。。。


3.libmad軟件解碼庫(kù)
本實(shí)驗(yàn)使用Libmad解碼庫(kù)進(jìn)行MP3解碼。
libmad 是一個(gè)開源 MP3 解碼庫(kù),其對(duì) MP3 解碼算法做了很多優(yōu)化,性能較好,很多播放器如 mplayer、xmms 等都是使用這個(gè)開源庫(kù)進(jìn)行解碼的。Download from : https://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz

“mad.h” 頭文件定義了 libmad 的數(shù)據(jù)結(jié)構(gòu)及 API 函數(shù),libmad 中的主要數(shù)據(jù)結(jié)構(gòu)體如下表所示:



4.移植libmad
將 libmad-0.15.1b 文件夾復(fù)制到工程目錄,將所有的 .c 文件加入工程,設(shè)置好包含路徑。



若編譯出現(xiàn) “FPM not select” 警告,在 KEIL 進(jìn)行宏定義配置,如下圖:


libmad 代碼中使用 DEBUG 預(yù)編譯作為調(diào)試開關(guān),需將其屏蔽


libmad 解碼出的數(shù)據(jù)為 24-bit PCM 數(shù)據(jù),需進(jìn)行 24-bit 至 16-bit 的轉(zhuǎn)換,使用 uint16_t scale(mad_fixed_t sample) 函數(shù)。

解碼用到三個(gè)數(shù)據(jù)結(jié)構(gòu),需將其定義為全局變量,防止?臻g不夠:
  • struct mad_frame Frame;
  • struct mad_synth Synth;
  • struct mad_stream Stream;

解碼的緩沖區(qū) audio buffer 要設(shè)置為全局變量,注意字節(jié)對(duì)齊的問題。

Libmad音頻解碼MP3也分為三個(gè)API完成:
  1. bool mp3_decode_open(mp3_decode_obj_t * obj, char * file_name, uint8_t * buf, uint32_t buf_size);
  2. bool mp3_decode_read(mp3_decode_obj_t * obj, uint16_t * buf, uint32_t buf_len);
  3. void mp3_decode_close(mp3_decode_obj_t * obj);
復(fù)制代碼
最終主函數(shù)實(shí)現(xiàn)WAV和MP3的播放
  1. #include "board_init.h"
  2.  
  3. #include "ff.h"
  4. #include "mp3_decode.h"
  5. #include "audio_port.h"
  6. #include "wav_decode.h"
  7.  
  8. FATFS   fs;
  9. DIR     dir;
  10. char file_path[BOARD_FILE_PATH_MAX_LEN];
  11. const char str_dir_path[] = BOARD_AUDIO_DIR_PATH;
  12.  
  13. /* audio buffer. */
  14. __attribute__((aligned(4))) uint16_t audio_buf[2][5120];
  15. __attribute__((aligned(4))) uint16_t out_buf[2][5120];
  16.  
  17. /* file buffer. */
  18. __attribute__((aligned(4))) uint8_t file_buf[10240];
  19.  
  20. __attribute__((aligned(4))) mp3_decode_obj_t mp3_obj;
  21. __attribute__((aligned(4))) wav_decode_obj_t wav_obj;
  22.  
  23. bool app_fatfs_init(void);
  24. void app_get_next_audio(void);
  25. void app_mp3_play(void);
  26. void app_wav_play(void);
  27.  
  28. int main(void){
  29.     BOARD_Init();
  30.     printf("audio player.\r\n");
  31.  
  32.     app_fatfs_init();
  33.     while (1){
  34.         app_get_next_audio();
  35.  
  36.         /* play mp3 audio. */
  37.         if (strstr(file_path, ".mp3") != NULL || strstr(file_path, ".MP3")) /* mp3 file. */{
  38.             app_mp3_play();
  39.             printf("done.\r\n");}
  40.  
  41.  
復(fù)制代碼
最后播放音樂的視頻



酷狗音樂下載網(wǎng)址

https://www.kugou.com/yy/html/rank.html

附件
軟件工程源代碼:
plus-f5270_audio_player_20239615.zip (7.87 MB)

MM32F5270原理圖:
PLUS-F5270 原理圖 V1.2.1.4.pdf (521.64 KB)

 

  • 本文系21ic原創(chuàng),未經(jīng)許可禁止轉(zhuǎn)載!

網(wǎng)友評(píng)論

  • 聯(lián)系人:巧克力娃娃
  • 郵箱:board@21ic.com
  • 我要投稿
  • 歡迎入駐,開放投稿

熱門標(biāo)簽
項(xiàng)目外包 more+