S3C2416裸機開發(fā)系列十九_Fatfs下播放錄音wav音頻文件
標簽:wavfatfs音頻播放s3c2416sd驅(qū)動
2014-06-11 09:551938人閱讀評論(0)收藏舉報
分類:
s3c2416裸機開發(fā)(24)
版權聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
目錄(?)[+]
S3C2416裸機開發(fā)系列十九Fatfs下播放錄音wav音頻文件象棋小子 1048272975
對于多媒體資源,一般都是以文件的形式存儲在固化存儲器中。Fatfs所支持的fat32為windows支持的文件系統(tǒng),因此在嵌入式系統(tǒng)中采用Fatfs文件系統(tǒng)可極大地擴展系統(tǒng)的應用。例如,把計算機上圖片,音頻,視頻,文本等資源直接拷貝到嵌入式系統(tǒng)中的固化存儲器中,在系統(tǒng)中即可直接應用這些資源。把嵌入式系統(tǒng)中錄制的音頻、視頻直接保存成一定的格式,在計算機上可直接播放處理,把傳感器采集的數(shù)據(jù)保存成txt或dat文件,在計算機上通過處理生成數(shù)據(jù)曲線分析等。筆者此處就wav音頻文件的播放與錄音進行簡單的介紹。
1. wav音頻格式Wave是錄音時用的標準windows文件格式,文件擴展名為”.wav”,數(shù)據(jù)本身的格式為PCM或壓縮型,它是由微軟與IBM聯(lián)合開發(fā)的用于音頻數(shù)字存儲的標準,采用RIFF文件格式結構。
RIFF全稱資源互換文件格式,是windows下大部分多媒體文件遵循的一種文件結構,除了本文所說的波形格式數(shù)據(jù)(.wav),采用RIFF格式結構的文件還有音頻視頻交錯格式(.avi)、位圖格式(.rdi)、MIDI格式(.rmi)、調(diào)色板格式(.pal)、多媒體電影(.rmn)、動畫光標(.ani)。
RIFF結構的基本單元為chunk,它的結構如下:
struct chunk {
unsignedint id; /* 塊標志 */
unsignedint size; /* 塊大小 */
unsigned chardata[size]; /* 塊內(nèi)容 */
}
Id為4個ascii字符組成,用來識別塊中所包含的數(shù)據(jù),如”RIFF”、”WAV ”、”data”、”fmt ”等;size是存儲在data域中數(shù)據(jù)的長度,不包括id與size域的大??;data[size]為該塊保存的數(shù)據(jù),以字為單位排列。
wav音頻文件作為RIFF結構,其由若干個chunk組成,按照在文件中的位置包括:RIFF chunk,fmt chunk,fact chunk(可選),data chunk。所有RIFF結構文件均會首先包含RIFF chunk,并指明RIFF類型,此處為”WAVE”。對于wav文件,在fmt chunk中指明音頻文件的信息,例如采樣位數(shù)、采樣頻率、聲道數(shù)、編碼方式等。對于壓縮型wav音頻,還會有一個fact chunk,用以指明解壓后音頻數(shù)據(jù)的大小,對于PCM非壓縮wav文件,并沒有該chunk。音頻數(shù)據(jù)保存在data chunk中,根據(jù)fmt chunk中指明的聲道數(shù)以及采樣位數(shù),wav音頻數(shù)據(jù)存放形式有不同的方式。
一個PCM格式的wav結構定義Wav.h如下:
#ifndef __WAV_H__
#define __WAV_H__
#ifdef __cplusplus
extern "C" {
#endif
//資源互換文件格式RIFF,樹狀結構,基本單位是chunk,整個文件由chunk構成
typedef struct RIFF_HEADER {
char Riff_ID[4];
unsigned int Riff_Size;//記錄整個RIFF文件的大小,除ID和Size這兩個變量
char Riff_Format[4];
} RIFF_HEADER;
typedef struct WAVE_FORMAT {
unsigned short FormatTag; //聲音的格式代號
unsigned short Channels; //聲音通道
unsigned int SamplesPerSec; //采樣率
unsigned int AvgBytesPerSec; //=采樣率*區(qū)塊對其單位
unsigned short BlockAlign; //區(qū)塊對其單位=每個取樣所需位數(shù)*聲音通道/8
unsigned short BitsPerSample; //每個取樣所需位數(shù)
} WAVE_FORMAT;
typedef struct FMT_CHUNK {
char Fmt_ID[4];
unsigned int Fmt_Size;//記錄fmt的大小
WAVE_FORMAT WaveFormat;
} FMT_CHUNK;
typedef struct DATA_CHUNK {
char Data_ID[4];
unsigned int Data_Size;//記錄data區(qū)的大小
} DATA_CHUNK;
typedef struct WAVE_HEADER {
RIFF_HEADER RiffHeader;
FMT_CHUNK FmtChunk;
DATA_CHUNK DataChunk;
} WAVE_HEADER;
#ifdef __cplusplus
}
#endif
#endif /*__WAV_H__*/
根據(jù)以上的wav結構定義,一個錄音文件的wav文件頭可如下定義:
static WAVE_HEADER RecorderWaveHeader = {
'R', 'I', 'F', 'F',
sizeof(WAVE_HEADER) - 8,//整個wave文件大小,初始化值
'W', 'A', 'V', 'E',
'f', 'm', 't', ' ',
sizeof(FMT_CHUNK) - 8,
1,//編碼方式,線性PCM編碼
1,//單聲道
10000,//采樣率為10k
20000,//每個采樣2個字節(jié)
2,//每個采樣2個字節(jié)
16,//每個采樣需16位
'd', 'a', 't', 'a',
0, //data長度初始化為0
};
2. wav音頻文件的播放或錄音sd卡由于其可插拔、靈活性好,通常應用于設備的擴展存儲應用。計算機上wav音頻等文件可輕易地拷貝到fat32格式的sd卡上,在嵌入式系統(tǒng)中要使用sd卡,首先需實現(xiàn)sd卡驅(qū)動,這在前面的章節(jié)有詳細的介紹,此處不再詳述。fat32文件的讀寫還需要相應文件系統(tǒng)的接口支持,此處選用Fatfs,對于不同的嵌入式系統(tǒng),這是需要移植的部分,關于s3c2416下Fatfs文件系統(tǒng)的移植在前面章節(jié)有詳細的介紹,此處不再詳述。從wav文件讀出音頻數(shù)據(jù)后(播放),還需要把音頻數(shù)據(jù)傳輸給聲卡,聲卡還原出聲音模擬信號,即可聽到聲音。音頻數(shù)據(jù)的處理需要用到音頻編解碼器,數(shù)據(jù)的傳輸也有一定的音頻總線要求,因此還需要音頻驅(qū)動的實現(xiàn),這部分在前面的章節(jié)有詳細的介紹,此處不再詳述。
3. 應用實例工程中利用串口對耳機音量進行加大、調(diào)小,對Mic錄音進行靈敏度的調(diào)節(jié),通過串口輸入進行播放wav音頻或開始錄音。播放時實時顯示播放進度并可按下’s’后停止播放,錄音時實時顯示錄音wav文件的大小并可按下’s’后停止錄音。
main.c的內(nèi)容如下:
#include"s3c2416.h"
#include"UART0.h"
#include"ff.h"
#include"diskio.h"
#include "RTC.h"
#include"Wav.h"
#include"IIS.h"
#include"IIC.h"
#include"WM8960.h"
staticWAVE_HEADER RecorderWaveHeader = {
'R', 'I', 'F', 'F',
sizeof(WAVE_HEADER) - 8,//整個wave文件大小
'W', 'A', 'V', 'E',
'f', 'm', 't', ' ',
sizeof(FMT_CHUNK) - 8,
1,//編碼方式,線性PCM編碼
1,//單聲道
10000,//采樣率為10k
20000,//每個采樣2個字節(jié)
2,//每個采樣2個字節(jié)
16,//每個采樣需16位
'd', 'a', 't', 'a',
0, //data長度初始化為0
};
// 音頻數(shù)據(jù)緩存20KB
unsigned charAudioBuffer[20*1024];
int main()
{
FATFS fs;
FIL file;
FRESULT Res;
unsigned int i;
unsigned int BufferLen;
unsigned char *pData;
WAVE_HEADER WaveHeader;
int ByteWrite, ByteRead;
unsigned char State;
unsigned char VolumeLevel;
unsigned short Command;
const char Path1[] = "test.wav";
const char Path2[] = "1.wav";
char FilePath[256];
unsigned int Size = 0;
unsigned int AudioSize = 0;
unsigned int TotalSize = 0;
RTC_Time Time = {
2014, 5, 22, 23, 00, 0, 5
};
RTC_Init(&Time); // RTC初始化
Uart0_Init(); // 串口初始化
IIC_Init(); //IIC初始化,音頻芯片控制
IIS_Init(); // IIS音頻接口初始化
WM8960_Init(); // 音頻編解碼器初始化
RTC_GetTime(&Time); // 顯示RTC時間
Uart0_Printf("Time: %4d/%02d/%02d%02d:%02d:%02drn", Time.Year,
Time.Month, Time.Day, Time.Hour,Time.Min, Time.Sec);
f_mount(&fs, "" , 0);
ByteRead = 0;
pData = (unsigned char *)0;
for (i=0; i FilePath[i] = Path1[i]; } State = 1; // 進入播放test.wav狀態(tài) while(1) { switch (State) { case 0: // 操作選擇 WM8960_HeadphoneStop(); WM8960_RecorderStop(); IIS_TxPause(); IIS_RxPause(); Uart0_SendString("rnSelect:rn" "0: Play test.wavrn"