为pcm音频文件增加wav头(C语音实现)

1.WAV

Waveform Audio File Format(WAVE,又或者是因为扩展名而被大众所知的WAV),是微软与IBM公司所开发在个人电脑存储音频流的编码格式,在Windows平台的应用软件受到广泛的支持,地位上类似于麦金塔电脑里的AIFF[2] 此格式属于资源交换文件格式(RIFF)的应用之一,通常会将采用脉冲编码调制的音频资存储在区块中。也是其音乐发烧友中常用的指定规格之一。由于此音频格式未经过压缩,所以在音质方面不会出现失真的情况,但文件的体积因而在众多音频格式中较为大。

2.wav的格式

WAV文件遵守资源交换文件格式之规则,在文件的前44(或46)字节放置标头(header),使播放器或编辑器能够简单掌握文件的基本信息,其内容以区块(chunk)为最小单位,每一区块长度为4字节,而区块之上则由子区块包裹,每一子区块长度不拘,但须在前头先宣告标签及长度(字节)。标头的前3个区块记录文件格式及长度;接着第一个子区块包含8个区块,记录声道数量、采样率等信息;接着第二个子区块才是真正的音频数据,长度则视音频长度而定。内容如下表所示。须注意的是,每个区块的端序不尽相同,而音频内容本身则是采用小端序。

对于WAV等未压缩的情况音频码率=采样率*位深*声道数目

typedef struct {
    char            riffType[4];    //4byte,资源交换文件标志:RIFF   
    unsigned int    riffSize;       //4byte,从下个地址到文件结尾的总字节数  
    char            wavType[4]; //4byte,wav文件标志:WAVE    
    char            formatType[4];  //4byte,波形文件标志:FMT(最后一位空格符)    
    unsigned int    formatSize;     //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
    unsigned short  compressionCode;//2byte,格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
    unsigned short  numChannels;    //2byte,通道数
    unsigned int    sampleRate;     //4byte,采样率
    unsigned int    bytesPerSecond; //4byte,传输速率
    unsigned short  blockAlign;     //2byte,数据块的对齐,即DATA数据块长度
    unsigned short  bitsPerSample;  //2byte,采样精度-PCM位宽
    char            dataType[4];    //4byte,数据标志:data
    unsigned int    dataSize;       //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
} head_data_t;

 

3.代码实现

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
    char            riffType[4];    //4byte,资源交换文件标志:RIFF   
    unsigned int    riffSize;       //4byte,从下个地址到文件结尾的总字节数  
    char            wavType[4]; //4byte,wav文件标志:WAVE    
    char            formatType[4];  //4byte,波形文件标志:FMT(最后一位空格符)    
    unsigned int    formatSize;     //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
    unsigned short  compressionCode;//2byte,格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
    unsigned short  numChannels;    //2byte,通道数
    unsigned int    sampleRate;     //4byte,采样率
    unsigned int    bytesPerSecond; //4byte,传输速率
    unsigned short  blockAlign;     //2byte,数据块的对齐,即DATA数据块长度
    unsigned short  bitsPerSample;  //2byte,采样精度-PCM位宽
    char            dataType[4];    //4byte,数据标志:data
    unsigned int    dataSize;       //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
} head_data_t;


/************************************************************ 
Function : usageHelp() 
Description: 
************************************************************/
void usageHelp(char *exe){
{
    printf("**********************************************************************"
           "**********************************************************************\n"
            "Usage  :\n"
            "%s xxx.pcm xxx.wav channel bits sample_rate\n"
           "**********************************************************************"
           "**********************************************************************\n",
    exe);
}

}
/************************************************************ 
Function : pcmAddWavHeader() 
Description: 
    pcm to wav Calls : 
    Called By : 
    Input : char *dst_file int channels int bits int sample_rate int len Output  
************************************************************/
int pcmAddWavHeader(FILE *fp, int channels, int bits, int sample_rate, int len) {
    head_data_t pcm2wavHEAD;
    if (NULL == fp) {
        printf("Input file ptr is null.\n"); 
        return -1; 
    }   
    memcpy(pcm2wavHEAD.riffType, "RIFF", strlen("RIFF"));
    memcpy(pcm2wavHEAD.wavType, "WAVE", strlen("WAVE"));
    pcm2wavHEAD.riffSize = 36 + len;
    pcm2wavHEAD.sampleRate = sample_rate;
    pcm2wavHEAD.bitsPerSample = bits;
    memcpy(pcm2wavHEAD.formatType, "fmt ", strlen("fmt "));
    pcm2wavHEAD.formatSize = 16;
    pcm2wavHEAD.numChannels = channels;
    pcm2wavHEAD.blockAlign = channels * bits / 8;
    pcm2wavHEAD.compressionCode = 1;
    pcm2wavHEAD.bytesPerSecond = pcm2wavHEAD.sampleRate * pcm2wavHEAD.blockAlign;
    memcpy(pcm2wavHEAD.dataType, "data", strlen("data"));
    pcm2wavHEAD.dataSize = len;
    fseek(fp, 0, SEEK_SET);
    fwrite(&pcm2wavHEAD, 44, 1, fp);
    return 0;
}

int main(int argc, char **argv){
    if(argc < 5){
        usageHelp(argv[0]);
        return -1;
    }
    int total_data = 0;
    FILE *orifp = fopen(argv[1],"rb");
    if(NULL == orifp){
        printf("OPEN FILE FAIL\n");
        return -1;
    }
    FILE *tarfp = fopen(argv[2],"wb");
    if(NULL == tarfp){
        printf("OPEN FILE FAIL\n");
        return -1;
    }
    int channel = atoi(argv[3]);
    int bit = atoi(argv[4]);
    int sample_rate = atoi(argv[5]);
    fseek(orifp, 0,SEEK_END);
    total_data = ftell(orifp);
    char *mempcm;
    mempcm = (char *)malloc(total_data);
    rewind(orifp);
    int lenn = fread(mempcm,sizeof(char),total_data,orifp);
    pcmAddWavHeader(tarfp, channel, bit, sample_rate, total_data);
    fseek(tarfp,44,SEEK_SET);
    fwrite(mempcm,total_data,1,tarfp);
    free(mempcm);
    mempcm = NULL;
    fclose(orifp);
    fclose(tarfp);
    orifp = NULL;
    tarfp = NULL;
}

具体思路:

根据pcm原始音频知道采样率,位深(采样精度),通道数,生成对应的wav头信息,加到原始pcm数据最前面

posted @ 2020-07-13 14:47  钰蛋  阅读(1588)  评论(0编辑  收藏  举报