c语言合并多个wav文件

1.wav头部解析

wav头部解析
链接: wav头部解析图片来源

00~03 4字节(“RIFF” 资源交换文件标志)
header[0] ='R';           (header[0] = 5252的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值