WAVE是录音时用的标准的WINDOWS文件格式,文件的扩展名为“WAV”,数据本身的格式为PCM或压缩型,属于无损音乐格式的一种。
WAV文件的文件头:
偏移地址
|
大小
字节
|
数据块
类型
|
内容
|
00H~03H
|
4
|
4字符
|
资源交换文件标志(RIFF)
|
04H~07H
|
4
|
长整数
|
从下个地址开始到文件尾的总字节数
|
08H~0BH
|
4
|
4字符
|
WAV文件标志(WAVE)
|
0CH~0FH
|
4
|
4字符
|
波形格式标志(fmt ),最后一位空格。
|
10H~13H
|
4
|
整数
|
过滤字节(一般为00000010H)
|
14H~15H
|
2
|
整数
|
格式种类(值为1时,表示数据为线性PCM编码)
|
16H~17H
|
2
|
整数
|
通道数,单声道为1,双声道为2
|
18H~1BH
|
4
|
长整数
|
采样频率
|
1CH~1FH
|
4
|
长整数
|
波形数据传输速率(每秒平均字节数)
|
20H~21H
|
2
|
整数
| DATA数据块长度,字节。 |
22H~23H
|
2
|
整数
|
PCM位宽
|
24H~27H | 4 | 4字符 |
“fact”,该部分一下是可选部分,即可能有,可能没有,一般到WAV文件由某些软件转换而成时,包含这部分。
|
28H~2BH | 4 |
长整数
| size,数值为4 |
WAV声音文件的数据块
偏移地址
|
字节数
|
类型
|
内容
|
24H~27H
|
4
|
4字符
|
数据标志符(data)
|
28H~2BH
|
4
|
长整型
|
DATA总数据长度字节
|
2CH...
|
...
|
DATA数据块
|
source code:
#include <memory.h>
#include <stdio.h>
struct RIFF_HEADER
{
char szRiffID[4]; // 'R','I','F','F'
unsigned int dwRiffSize;
char szRiffFormat[4]; // 'W','A','V','E'
};
struct WAVE_FORMAT
{
unsigned short wFormatTag;
unsigned short wChannels;
unsigned int dwSamplesPerSec;
unsigned int dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
};
struct FMT_BLOCK
{
char szFmtID[4]; // 'f','m','t',' '
unsigned int dwFmtSize;
struct WAVE_FORMAT wavFormat;
};
union DWORD_CHAR
{
int nValue;
char charBuf[4];
};
int writeFile2Int(FILE *fp, int nWhere, int nValue)
{
if (fp == NULL )
{
return -1;
}
fseek(fp, nWhere, SEEK_SET);
union DWORD_CHAR dc;
dc.nValue = nValue;
fwrite(dc.charBuf, 1, 4, fp);
return 0;
}
void writeWaveHead(FILE *fp)
{
if (fp)
{
//写WAV文件头
struct RIFF_HEADER rh;
memset(&rh, 0, sizeof(rh));
strncpy(rh.szRiffFormat, "WAVE", 4);
strncpy(rh.szRiffID, "RIFF", 4);
fwrite(&rh, 1, sizeof(rh), fp);
struct FMT_BLOCK fb;
strncpy(fb.szFmtID, "fmt ", 4);
fb.dwFmtSize = 16;
fb.wavFormat.wFormatTag = 1;
fb.wavFormat.wChannels = 1;
fb.wavFormat.wBitsPerSample = 16;
fb.wavFormat.dwSamplesPerSec = 44100;
fb.wavFormat.wBlockAlign = fb.wavFormat.wChannels * fb.wavFormat.wBitsPerSample / 8; //4;
fb.wavFormat.dwAvgBytesPerSec = fb.wavFormat.dwSamplesPerSec * fb.wavFormat.wBlockAlign;
fwrite(&fb, 1, sizeof(fb), fp);
char buf[] = { "data" };
fwrite(buf, 1, sizeof(buf), fp);
}
}
void writeWaveBody(FILE *fp, long filelength)
{
//更新WAV文件dwRiffSize字段中的值
int nWhere = 4;
writeFile2Int(fp, nWhere, filelength + 40);
//更新WAV文件DataChunk中Size字段的值
nWhere = sizeof(struct RIFF_HEADER) + sizeof(struct FMT_BLOCK) + 4;
writeFile2Int(fp, nWhere, filelength);
}
void main()
{
FILE *fpS;
FILE *fpD;
const char *wsPCMFileName = "record.pcm";
const char *wsWAVEFileName = "Oput.wav";
fpS = fopen(wsPCMFileName, "rb");
fpD = fopen(wsWAVEFileName, "wb+");
if (fpS == NULL || fpD == NULL )
{
printf("[CIrrReplay::createScene]PCM转WAVE失败!\n");
return;
}
fseek(fpS, 0, SEEK_END);
long filelength = ftell(fpS);
printf("filelength:%ld\n", filelength);
writeWaveHead(fpD);
writeWaveBody(fpD, filelength);
fseek(fpS, 0, SEEK_SET);
char buf[4];
while (4 == fread(buf, 1, 4, fpS))
{
fwrite(buf, 1, 4, fpD);
}
fclose(fpS);
fclose(fpD);
}