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