為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數據最前面


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM