为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数据最前面
----保持谦虚保持清醒