1. 程式人生 > >【音訊】wave格式解析

【音訊】wave格式解析

本文目的:

1、瞭解wave格式組成,瞭解wave頭各個部分組成


wav 格式,是微軟開發的一種檔案格式規範,整個檔案分為兩部分,第一部分是“檔案頭”,記錄重要的引數資訊,對於音訊而言,就包括:取樣率、通道數、位寬等等;第二部分是“資料塊”,即一幀一幀的二進位制資料,對於音訊而言,就是原始的 PCM 資料。

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



Offset Size Name Description
0 4 ChunkID ASCII碼”0x52494646”對應字母”RIFF”
4 4 ChunkSize 塊大小是指除去ChunkID與ChunkSize的剩餘部分有多少位元組資料。注意:小尾位元組序數。Value=36+SubChunk2SizeValue=36+SubChunk2Size 或者Value=4+(8+SubChunk1Size)+(8+SubChunk2Size)Value=4+(8+SubChunk1Size)+(8+SubChunk2Size)。
8 4 Format ASCII碼”0x57415645”對應字母”WAVE”。該塊由兩個子快組成,一個“fmt”chunk用於詳細說明資料格式,一個“data”chunk包含實際的樣本資料。
12 4 Subchunk1ID ASCII碼”0x666d7420”對應字母”fmt “。
16 4 Subchunk1Size 如果檔案採用PCM編碼,則該子塊剩餘位元組數為16。
20 2 AudioFormat 如果檔案採用PCM編碼(線性量化),則AudioFormat=1。AudioFormat代表不同的壓縮方式。
22 2 NumChannels 聲道數,單聲道(Mono)為1, 雙聲道(Stereo)為 2。
24 4 SampleRate 取樣率,例:44.1kHz,48kHz。
28 4 ByteRate 傳輸速率,單位:Byte/s。Value==SampleRateNumChannelsBitsPerSample/8Value==SampleRate∗NumChannels∗BitsPerSample/8
32 2 BlockAlign 一個樣點(包含所有聲道)的位元組數。Value==NumChannelsBitsPerSample/8Value==NumChannels∗BitsPerSample/8
34 2 BitsPerSample 每個樣點對應的位數。
  2 ExtraParamSize 如果採用PCM編碼,該值不存在。
  X ExtraParams 用於儲存其他引數。如果採用PCM編碼,該值不存在。
36 4 Subchunk2ID ASCII碼”0x64617461”對應字母”data”。
40 4 Subchunk2Size 實際樣本資料的大小(單位:位元組)。Value==NumSamplesNumChannelsBitsPerSample/8Value==NumSamples∗NumChannels∗BitsPerSample/8
44 * Data 實際的音訊資料 。

簡單地分析一下這個 wav 格式頭,它主要分為三個部分:


第一部分,屬於最“頂層”的資訊塊,通過“ChunkID”來表示這是一個 “RIFF”格式的檔案,“ChunkSize”則記錄了整個 wav 檔案的位元組數,"Format"包含了“WAVE”標識這是一個 wav 檔案。

第二部分,屬於“fmt”資訊塊,主要記錄了本 wav 音訊檔案的詳細音訊引數資訊,例如:通道數、取樣率、位寬等等(含義請參考我的第一篇文章

第三部分,屬於“data”資訊塊,由“Subchunk2Size”這個欄位來記錄後面儲存的二進位制原始音訊資料的長度。




現在的wave支援哪些格式:

AudioFormat Description
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/