1.wav头部解析
链接: wav头部解析图片来源
00~03 4字节(“RIFF” 资源交换文件标志)
header[0] ='R'; (header[0] = 52, 52的ASCII码为R)
header[1] ='I';
header[2] ='F';
header[3] ='F';
04~07字节
(从下08开始到末尾的长度,实际window下查看的文件大小,需要在这个大小的基础加上8字节
存储RIFF的四字节和存储文件大小的四字节)
小端存储 44 2C 00 00 = 0x2C44
08~11字节“wave” wav文件标志
header[8] ='W';
header[9] ='A';
header[10] ='V';
header[11] ='E';
12~15 4字节“fmt” 波形格式标志,最后一位空格
header[12] ='f';
header[13] ='m';
header[14] ='t';
header[15] =' ';
16~19 4字节过滤字节(一般为00000010H)
header[16] =16;
header[17] =0;
header[18] =0;
header[19] =0;
20~21 2字节格式种类(值为1时,表示数据为线性pcm编码)
header[20] =1;
header[21] =0;
22~23 2字节通道数,单声道为1,双声道为2
header[22] = (char) channel;
header[23] =0;
24~27 4字节采样率
header[24] = (char) (sample_rate &0xff);
header[25] = (char) ((sample_rate >>8) & 0xff);
header[26] = (char) ((sample_rate >>16) & 0xff);
header[27] = (char) ((sample_rate >>24) & 0xff);
28~31 4字节比特率(Byte率=采样频率*音频通道数*每次采样得到的样本位数/8)
header[28] = (char) (bit_rate &0xff);
header[29] = (char) ((bit_rate >>8) & 0xff);
header[30] = (char) ((bit_rate >>16) & 0xff);
header[31] = (char) ((bit_rate >>24) & 0xff);
32~33 2字节数据块长度(每个样本的字节数=通道数*每次采样得到的样本位数/8)
header[32] = (char) (channel* sample_bit / 8);
header[33] =0;
34~35 2字节每个采样点的位数
header[34] = (char) sample_bit;
header[35] =0;
wav格式含有LIST数据块
struct list {
uint32_t list_size; // List 大小
uint32_t list_type; // List 类型
uint8_t list_data[list_size]; // List 数据
};
Note: list_data 是该 LIST 的数据内容,由 CHUNK 和 SUB_LIST 组成,它们的个数和组成次序可以是不确定.
LIST数据块后是data数据
4字节 “data”数据标志符
header[36] ='d';
header[37] ='a';
header[38] ='t';
header[39] ='a';
4字节 pcm音频数据大小
header[40] = (char) (data_size &0xff);
header[41] = (char) ((data_size >>8) & 0xff);
header[42] = (char) ((data_size >>16) & 0xff);
header[43] = (char) ((data_size >>24) & 0xff);
Note:存在LIST数据块的data字节数不固定。
合并多个wav音频文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HI_SUCCESS 0
#define HI_FAILURE (-1)
typedef struct
{
unsigned short u16Channel;
unsigned int u32SampleRate;
unsigned int u32DataLength;
}WAV_TRACK_HEADER;
/*****************************************************************************
* Function: BigToLittleArray32
* Description: 大端转小端
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
unsigned char* BigToLittleArray32(unsigned int x,unsigned char array[4])
{
array[0] = (x<<24) >> 24;
array[1] = ((x<<8) & 0x00ff0000) >> 16;
array[2] = (((x>>8) & 0x0000ff00)) >> 8;
array[3] = (x>>24);
return array;
}
/*****************************************************************************
* Function: LittleToint32
* Description: 小端转int32
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
unsigned int LittleToint32(unsigned char *array)
{
return array[0] | (array[1]<<8) | (array[2]<<16) | (array[3]<<24);
}
/*****************************************************************************
* Function: LittleToint16
* Description: 小端转int16
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
short LittleToint16(unsigned char *array)
{
return array[0] | (array[1] << 8);
}
/*****************************************************************************
* Function: Wav_GetTrackHeader
* Description: 解析wav音频头部
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
WAV_TRACK_HEADER* GetTrackHeader(FILE *track)
{
char szTemp[4] = {};
WAV_TRACK_HEADER *header = NULL;
/* RIFF Check*/
fread(szTemp,1, 4, track);
if(!strstr(szTemp, "RIFF"))
{
printf("missing riff \n");
return NULL;
}
/* ignore wav ,fmt */
fseek(track, 18, SEEK_CUR);
/* Number of channels (1 = mono,2 = stereo)*/
header = (WAV_TRACK_HEADER*) malloc(sizeof(WAV_TRACK_HEADER));
if(header == NULL)
{
printf("malloc fail\n");
return NULL;
}
fread(szTemp,1, 2, track);
header->u16Channel = LittleToint16(szTemp);
/* Sample Rate (Hz)*/
fread(szTemp,1, 4, track);
header->u32SampleRate = LittleToint32(szTemp);
/* data check*/
while(1)
{
fread(szTemp,1, 2, track);
if(strstr(szTemp, "da"))
{
/* some wav files list info, find the date header one by one*/
fread(szTemp,1, 2, track);
break;
}
}
/* length of datas*/
fread(szTemp,1, 4, track);
header->u32DataLength = LittleToint32(szTemp);
return header;
}
/*****************************************************************************
* Function: ModifySize
* Description: 修改文件大小
* Input: track:目标的文件流, 添加音频的长度
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
void ModifySize(FILE *track, unsigned int u32SrcDataLength)
{
char szLength[4] = {};
int u32Length = 0;
//Locate file length
fseek(track, 0, SEEK_SET);
fseek(track, 4, SEEK_CUR);
fread(szLength,1, 4, track);
u32Length = LittleToint32(szLength);
u32Length += u32SrcDataLength;
fseek(track, -4, SEEK_CUR);
memset(szLength, 0, sizeof(szLength));
BigToLittleArray32(u32Length,szLength);
fwrite(szLength, 1, 4, track);
return;
}
/*****************************************************************************
* Function: Wav_TrackCompare
* Description: 比较wav音频参数是否一致
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
int TrackCompare(WAV_TRACK_HEADER *header1,WAV_TRACK_HEADER *header2)
{
if(header1->u16Channel != header2->u16Channel) return HI_FAILURE;
if(header1->u32SampleRate != header2->u32SampleRate) return HI_FAILURE;
return HI_SUCCESS;
}
/*****************************************************************************
* Function: Wav_AudioMerge
* Description: wav音频合并
* Input: 无
* Output: 无
* Return: 无
* Others: 无
*****************************************************************************/
int AudioMerge(char * szSrcFileName, char * szDestFileName)
{
#define ETC_BLANK_AUDIO_PATH "/customer/audio/aud_blank.wav"
FILE *destfp = NULL, *srcfp = NULL;
unsigned char szLength[4] = {};
unsigned char szData[128] = {};
WAV_TRACK_HEADER *stDestHeader = NULL;
WAV_TRACK_HEADER *stSrcHeader = NULL;
unsigned int u32DataLength = 0;
int s32Size = 0;
destfp = fopen(szDestFileName,"rb+");
if (destfp == NULL)
{
printf("open file(%s) fail\n", szDestFileName);
goto end;
}
srcfp = fopen(szSrcFileName,"rb");
if (srcfp == NULL)
{
printf("open file(%s) fail\n", szSrcFileName);
goto end;
}
stDestHeader = GetTrackHeader(destfp);
if(stDestHeader == NULL)
{
goto end;
}
stSrcHeader = GetTrackHeader(srcfp);
if(stSrcHeader == NULL)
{
goto end;
}
if(TrackCompare(stDestHeader, stSrcHeader) == HI_FAILURE)
{
printf("channel or samplerate mismatch\n");
goto end;
}
/* data length addition */
fseek(destfp, -4, SEEK_CUR);
u32DataLength = stDestHeader->u32DataLength + stSrcHeader->u32DataLength;
BigToLittleArray32(u32DataLength,szLength);
fwrite(szLength, 1, 4,destfp);
fseek(destfp, 0, SEEK_END);
while(1)
{
s32Size = fread(szData,1, sizeof(szData), srcfp);
if(s32Size <= 0)
{
break;
}
fwrite(szData, 1, s32Size,destfp);
}
ModifySize(destfp, stSrcHeader->u32DataLength);
end:
if (srcfp != NULL)
{
fclose(srcfp);
}
if (destfp != NULL)
{
fclose(destfp);
}
if (stDestHeader != NULL)
{
free(stDestHeader);
}
if (stSrcHeader != NULL)
{
free(stSrcHeader);
}
return HI_SUCCESS;
}
int main()
{
AudioMerge("aud_SEVEN.wav","aud_THREE.wav");
return 0;
}