您的位置:首页 > 编程语言

网上找的一个读取wave文件的代码片段

2013-05-04 10:49 295 查看
struct RIFF_HEADER
{
char szRiffID[4];   // 'R','I','F','F'
DWORD dwRiffSize;
char szRiffFormat[4]; // 'W','A','V','E'
};

struct WAVE_FORMAT
{
WORD wFormatTag;
WORD wChannels;
DWORD dwSamplesPerSec;
DWORD dwAvgBytesPerSec;
WORD wBlockAlign;
WORD wBitsPerSample;
};
struct waveHead
{
RIFF_HEADER riff;
char   szFmtID[4]; // 'f','m','t',' '
DWORD   dwFmtSize;
WAVE_FORMAT wavFormat;
};

struct FACT_BLOCK
{
char   szFactID[4]; // 'f','a','c','t'
DWORD   dwFactSize;
};

struct DATA_BLOCK
{
char szDataID[4]; // 'd','a','t','a'
DWORD dwDataSize;
};

#define WAVE_FORMAT_PCM 0x0001
#define WAVE_FORMAT_ADPCM 0x0002

else if (m_iSoundType == wavesound)
{
waveHead aHeader;
fseek(m_soundf, 0, SEEK_SET);
fread(&aHeader, 1, sizeof(waveHead), m_soundf);
if (aHeader.wavFormat.wFormatTag != WAVE_FORMAT_PCM)
{
PGELOG(LOG_ERROR, "不支持的Wave格式:%s", caFile);
fclose(m_soundf);
m_soundf = 0;
return -1;
}
memcpy(&m_wformat, &(aHeader.wavFormat), sizeof(WAVE_FORMAT));
m_wformat.cbSize = 0;
//if (aHeader.dwFmtSize == 18)
//fread(&(m_wformat.cbSize), 1, sizeof(WORD), m_soundf);
fseek(m_soundf, aHeader.dwFmtSize-16, SEEK_CUR);
FACT_BLOCK fact;
DATA_BLOCK data;
fread(&fact, 1, sizeof(FACT_BLOCK), m_soundf);
if (*((DWORD*)fact.szFactID) == *((DWORD*)"fact"))
{
fseek(m_soundf, fact.dwFactSize, SEEK_CUR);
fread(&data, 1, sizeof(DATA_BLOCK), m_soundf);
}
else if (*((DWORD*)fact.szFactID) == *((DWORD*)"data"))
memcpy(&data, &fact, sizeof(DATA_BLOCK));
m_iDataStart = ftell(m_soundf);
m_iDataSize = data.dwDataSize;
fread(m_pWaveData, 1, m_iDataSize, m_soundf);
}


附上wave文件格式:

下面我们具体地分析 WAVE 文件的格式

endian

field name

Size

bigChunkID4文件头标识,一般就是" RIFF" 四个字母
littleChunkSize4整个数据文件的大小,不包括上面ID和Size本身
bigFormat4一般就是" WAVE" 四个字母
bigSubChunk1ID4格式说明块,本字段一般就是"fmt "
littleSubChunk1Size4本数据块的大小,不包括ID和Size字段本身
littleAudioFormat2音频的格式说明
littleNumChannels2声道数
littleSampleRate4采样率
littleByteRate4比特率,每秒所需要的字节数
littleBlockAlign2数据块对齐单元
littleBitsPerSample2采样时模数转换的分辨率
bigSubChunk2ID4真正的声音数据块,本字段一般是"data"
littleSubChunk2Size4本数据块的大小,不包括ID和Size字段本身
littleDataN音频的采样数据

以下是对各个字段的详细解说:

ChunkID4bytesASCII 码表示的“RIFF”。(0x52494646)
ChunkSize4bytes36+SubChunk2Size,或是
4 + ( 8 + SubChunk1Size ) + ( 8 + SubChunk2Size ),
这是整个数据块的大小(不包括ChunkID和ChunkSize的大小)
Format4bytesASCII 码表示的“WAVE”。(0x57415645)
SubChunk1ID新的数据块(格式信息说明块)
ASCII 码表示的“fmt ”——最后是一个空格。(0x666d7420)
SubChunk1Size4bytes本块数据的大小(对于PCM,值为16)。
AudioFormat2bytesPCM = 1 (比如,线性采样),如果是其它值的话,则可能是一些压缩形式
NumChannels2bytes1 => 单声道 | 2 => 双声道
SampleRate4bytes采样率,如 8000,44100 等值
ByteRate4bytes等于: SampleRate * numChannels * BitsPerSample / 8
BlockAlign2bytes等于:NumChannels * BitsPerSample / 8
BitsPerSample2bytes采样分辨率,也就是每个样本用几位来表示,一般是 8bits 或是 16bits
SubChunk2ID4bytes新数据块,真正的声音数据
ASCII 码表示的“data ”——最后是一个空格。(0x64617461)
SubChunk2Size4bytes数据大小,即,其后跟着的采样数据的大小。
DataN bytes真正的声音数据
对于Data块,根据声道数和采样率的不同情况,布局如下(每列代表8bits):

1. 8 Bit 单声道:

采样1采样2
数据1数据2
2. 8 Bit 双声道

采样1采样2
声道1数据1声道2数据1声道1数据2声道2数据2
1. 16 Bit 单声道:

采样1采样2
数据1低字节数据1高字节数据1低字节数据1高字节
2. 16 Bit 双声道

采样1
声道1数据1低字节声道1数据1高字节声道2数据1低字节声道2数据1高字节
采样2
声道1数据2低字节声道1数据2高字节声道2数据2低字节声道2数据2高字节
下面我们看一个具体的例子,声音文件如下:

52 49 46 46 24 08 00 00 57 41 56 45
66 6d 74 20 10 00 00 00 01 00 02 00
22 56 00 00 88 58 01 00 04 00 10 00
64 61 74 61 00 08 00 00 00 00 00 00
24 17 1e f3 3c 13 3c 14 16 f9 18 f9
34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d

对应的分析如下图所示:





自己测试了下暂时还没有弄通。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: