【音频】wave格式解析

本文目的:

1、了解wave格式组成,了解wave头各个部分组成


wav 格式,是微软开发的一种文件格式规范,整个文件分为两部分,第一部分是“文件头”,记录重要的参数信息,对于音频而言,就包括:采样率、通道数、位宽等等;第二部分是“数据块”,即一帧一帧的二进制数据,对于音频而言,就是原始的 PCM 数据。

所以wav格式 = Header(44 bytes) + data



OffsetSizeNameDescription
04ChunkIDASCII码”0x52494646”对应字母”RIFF”
44ChunkSize块大小是指除去ChunkID与ChunkSize的剩余部分有多少字节数据。注意:小尾字节序数。Value=36+SubChunk2SizeValue=36+SubChunk2Size 或者Value=4+(8+SubChunk1Size)+(8+SubChunk2Size)Value=4+(8+SubChunk1Size)+(8+SubChunk2Size)。
84FormatASCII码”0x57415645”对应字母”WAVE”。该块由两个子快组成,一个“fmt”chunk用于详细说明数据格式,一个“data”chunk包含实际的样本数据。
124Subchunk1IDASCII码”0x666d7420”对应字母”fmt “。
164Subchunk1Size如果文件采用PCM编码,则该子块剩余字节数为16。
202AudioFormat如果文件采用PCM编码(线性量化),则AudioFormat=1。AudioFormat代表不同的压缩方式。
222NumChannels声道数,单声道(Mono)为1, 双声道(Stereo)为 2。
244SampleRate取样率,例:44.1kHz,48kHz。
284ByteRate传输速率,单位:Byte/s。Value==SampleRateNumChannelsBitsPerSample/8Value==SampleRate∗NumChannels∗BitsPerSample/8
322BlockAlign一个样点(包含所有声道)的字节数。Value==NumChannelsBitsPerSample/8Value==NumChannels∗BitsPerSample/8
342BitsPerSample每个样点对应的位数。
 2ExtraParamSize如果采用PCM编码,该值不存在。
 XExtraParams用于存储其他参数。如果采用PCM编码,该值不存在。
364Subchunk2IDASCII码”0x64617461”对应字母”data”。
404Subchunk2Size实际样本数据的大小(单位:字节)。Value==NumSamplesNumChannelsBitsPerSample/8Value==NumSamples∗NumChannels∗BitsPerSample/8
44*Data实际的音频数据 。

简单地分析一下这个 wav 格式头,它主要分为三个部分:


第一部分,属于最“顶层”的信息块,通过“ChunkID”来表示这是一个 “RIFF”格式的文件,“ChunkSize”则记录了整个 wav 文件的字节数,"Format"包含了“WAVE”标识这是一个 wav 文件。

第二部分,属于“fmt”信息块,主要记录了本 wav 音频文件的详细音频参数信息,例如:通道数、采样率、位宽等等(含义请参考我的第一篇文章

第三部分,属于“data”信息块,由“Subchunk2Size”这个字段来记录后面存储的二进制原始音频数据的长度。




现在的wave支持哪些格式:

AudioFormatDescription
0 (0x0000)Unknown
1 (0x0001)PCM/uncompressed
2 (0x0002)Microsoft ADPCM
6 (0x0006)ITU G.711 a-law
7 (0x0007)ITU G.711 µ-law
17 (0x0011)IMA ADPCM
20 (0x0016)ITU G.723 ADPCM (Yamaha)
49 (0x0031)ITU G.721 ADPCM
80 (0x0050)MPEG
65,536 (0xFFFF)Experimental

将PCM文件转换为WAVE格式(其实就是在PCM前面加上了44个字节的头):

int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
 
	typedef struct WAVE_HEADER{  
		char         fccID[4];        
		unsigned   long    dwSize;            
		char         fccType[4];    
	}WAVE_HEADER;  
 
	typedef struct WAVE_FMT{  
		char         fccID[4];        
		unsigned   long       dwSize;            
		unsigned   short     wFormatTag;    
		unsigned   short     wChannels;  
		unsigned   long       dwSamplesPerSec;  
		unsigned   long       dwAvgBytesPerSec;  
		unsigned   short     wBlockAlign;  
		unsigned   short     uiBitsPerSample;  
	}WAVE_FMT;  
 
	typedef struct WAVE_DATA{  
		char       fccID[4];          
		unsigned long dwSize;              
	}WAVE_DATA;  
 
 
	if(channels==0||sample_rate==0){
    channels = 2;
    sample_rate = 44100;
	}
	int bits = 16;
 
    WAVE_HEADER   pcmHEADER;  
    WAVE_FMT   pcmFMT;  
    WAVE_DATA   pcmDATA;  
 
    unsigned   short   m_pcmData;
    FILE   *fp,*fpout;  
 
	fp=fopen(pcmpath, "rb");
    if(fp == NULL) {  
        printf("open pcm file error\n");
        return -1;  
    }
	fpout=fopen(wavepath,   "wb+");
    if(fpout == NULL) {    
        printf("create wav file error\n");  
        return -1; 
    }        
	//WAVE_HEADER
    memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));                    
    memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));  
    fseek(fpout,sizeof(WAVE_HEADER),1); 
	//WAVE_FMT
    pcmFMT.dwSamplesPerSec=sample_rate;  
    pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*sizeof(m_pcmData);  
    pcmFMT.uiBitsPerSample=bits;
    memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));  
    pcmFMT.dwSize=16;  
    pcmFMT.wBlockAlign=2;  
    pcmFMT.wChannels=channels;  
    pcmFMT.wFormatTag=1;  
 
    fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout); 
 
    //WAVE_DATA;
    memcpy(pcmDATA.fccID,"data",strlen("data"));  
    pcmDATA.dwSize=0;
    fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
 
    fread(&m_pcmData,sizeof(unsigned short),1,fp);
    while(!feof(fp)){  
        pcmDATA.dwSize+=2;
        fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
        fread(&m_pcmData,sizeof(unsigned short),1,fp);
    }  
 
    pcmHEADER.dwSize=44+pcmDATA.dwSize;
 
    rewind(fpout);
    fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
    fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
    fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
	
	fclose(fp);
    fclose(fpout);
 
    return 0;
}

调用方法:

simplest_pcm16le_to_wave("NocturneNo2inEflat_44.1k_s16le.pcm",2,44100,"output_nocturne.wav");


参考:

http://soundfile.sapp.org/doc/WaveFormat/

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值