1. 程式人生 > >轉wave 文件解析

轉wave 文件解析

chan col logs add gin mem lock fprintf rsa

轉 1

WAVE 文件格式分析

WAVE 文件作為多媒體中使用的聲音波形文件格式之一,它是以RIFF(Resource Interchange File Format)格式為標準的。每個WAVE文件的頭四個字節便是“RIFF”。WAVE 文件由文件頭和數據體兩大部分組成。其中文件頭又分為 RIFF/WAV 文件標識段和聲音數據格式說明段兩部分。WAVE文件各部分內容及格式見後文。

常見的聲音文件主要有兩種,分別對應於單聲道(11.025KHz 采樣率、8Bit 的采樣值)和雙聲道(44.1KHz 采樣率、16Bit 的采樣值)。采樣率是指:聲音信號在“模→數”轉換過程中單位時間內采樣的次數。采樣值是指每一次采樣周期
內聲音模擬信號的積分值。

對於單聲道聲音文件,采樣數據為八位的短整數(short int 00H-FFH);而對於雙聲道立體聲聲音文件,每次采樣數據為一個16位的整數(int),高八位和低八位分別代表左右兩個聲道。

WAVE 文件數據塊包含以脈沖編碼調制(PCM)格式表示的樣本。WAVE 文件是由樣本組織而成的。在單聲道 WAVE 文件中,聲道0代表左聲道,聲道1代表右聲道。在多聲道WAVE文件中,樣本是交替出現的。

WAVE 文件除了前面一小段文件頭對數據組織進行說明之外,Data 塊就是聲音的原始采樣數據,WAVE 文件雖然可以壓縮,但一般都使用不壓縮的格式。44.1KHz 采樣率、16Bit的分辨率、雙聲道,所以WAVE可以保存音質要求非常高的聲音文件,CD 采用的也是這種格式,聲音方面的專家或是音樂發燒友們應該非常熟悉。但這種文件的體積也非常大,以 44.1KHz 16bit 雙聲道的數據為例,一分鐘的聲音數據量為:4100*2byte*2channel*60s/1024/1024=10.09M 。所以不合適在網上傳送。


下面我們具體地分析 WAVE 文件的格式

endian

field name

Size

big ChunkID 4 文件頭標識,一般就是" RIFF" 四個字母
little ChunkSize 4 整個數據文件的大小,不包括上面ID和Size本身
big Format 4 一般就是" WAVE" 四個字母
big SubChunk1ID 4 格式說明塊,本字段一般就是"fmt "
little SubChunk1Size 4 本數據塊的大小,不包括ID和Size字段本身
little AudioFormat 2 音頻的格式說明
little NumChannels 2 聲道數
little SampleRate 4 采樣率
little ByteRate 4 比特率,每秒所需要的字節數
little BlockAlign 2 數據塊對齊單元
little BitsPerSample 2 采樣時模數轉換的分辨率
big SubChunk2ID 4 真正的聲音數據塊,本字段一般是"data"
little SubChunk2Size 4 本數據塊的大小,不包括ID和Size字段本身
little Data N 音頻的采樣數據

以下是對各個字段的詳細解說:

ChunkID 4bytes ASCII 碼表示的“RIFF”。(0x52494646)
ChunkSize 4bytes 36+SubChunk2Size,或是
4 + ( 8 + SubChunk1Size ) + ( 8 + SubChunk2Size ),
這是整個數據塊的大小(不包括ChunkID和ChunkSize的大小)
Format 4bytes ASCII 碼表示的“WAVE”。(0x57415645)
SubChunk1ID 新的數據塊(格式信息說明塊)
ASCII 碼表示的“fmt ”——最後是一個空格。(0x666d7420)
SubChunk1Size 4bytes 本塊數據的大小(對於PCM,值為16)。
AudioFormat 2bytes PCM = 1 (比如,線性采樣),如果是其它值的話,則可能是一些壓縮形式
NumChannels 2bytes 1 => 單聲道 | 2 => 雙聲道
SampleRate 4bytes 采樣率,如 8000,44100 等值
ByteRate 4bytes 等於: SampleRate * numChannels * BitsPerSample / 8
BlockAlign 2bytes 等於:NumChannels * BitsPerSample / 8
BitsPerSample 2bytes 采樣分辨率,也就是每個樣本用幾位來表示,一般是 8bits 或是 16bits
SubChunk2ID 4bytes 新數據塊,真正的聲音數據
ASCII 碼表示的“data ”——最後是一個空格。(0x64617461)
SubChunk2Size 4bytes 數據大小,即,其後跟著的采樣數據的大小。
Data N bytes 真正的聲音數據

對於Data塊,根據聲道數和采樣率的不同情況,布局如下(每列代表8bits):

1. 8 Bit 單聲道:

采樣1 采樣2
數據1 數據2

2. 8 Bit 雙聲道

采樣1 采樣2
聲道1數據1 聲道2數據1 聲道1數據2 聲道2數據2

1. 16 Bit 單聲道:

采樣1 采樣2
數據1低字節 數據1高字節 數據1低字節 數據1高字節

2. 16 Bit 雙聲道

采樣1
聲道1數據1低字節 聲道1數據1高字節 聲道2數據1低字節 聲道2數據1高字節
采樣2
聲道1數據2低字節 聲道1數據2高字節 聲道2數據2低字節 聲道2數據2高字節

下面我們看一個具體的例子,聲音文件如下:

52 49 46 46 24 08 00 00 57 41 56 45 
66 6d 74 20 10 00 00 00 01 00 02 00 
22 56 00 00 88 58 01 00 04 00 10 00 
64 61 74 61 00 08 00 00 00 00 00 00 
24 17 1e f3 3c 13 3c 14 16 f9 18 f9 
34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d 

對應的分析如下圖所示:

技術分享

本文參考了:

  • http://www.diybl.com/course/3_program/game/200798/70450.html
  • https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

轉2

1.PCM Wave格式詳解

WAVE文件格式是微軟RIFF(Resource Interchange File Format,資源交換文件標準)的一種,是針對於多媒體文件存儲的一種文件格式和標準。 一般而言,RIFF文件由文件頭和數據兩部分組成,一個WAVE文件由一個“WAVE”數據塊組成,這個“WAVE”塊又由一個”fmt”子數據塊和一個“data”子 數據塊組成,也稱這種格式為“Canonical form”(權威/牧師格式),如下圖所示:

技術分享

每個字段的涵義如下: ChunkID: 占4個字節,內容為“RIFF”的ASCII碼(0x52494646),以大端(big endian)存儲。
ChunkSize: 4字節,存儲整個文件的字節數(不包含ChunkID和ChunkSize這8個字節),以小端(little endian)方式存儲。
Format: 4字節,內容為“WAVE”的ASCII碼(0x57415645),以大端存儲。

其中bigendian 主要有一個特征,在內存中對操作數的存儲方式和從高字節到低字節。例如:0x1234,這樣一個數,存儲為:
0x4000: 0x12
0x4001: 0x34
而小尾端littleendian是:
0x4000: 0x34
0x4001: 0x12
用程序在區別的話,可以考慮:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
       union w
      {
       short int a;
       char b;
      }c;
      c.a=1;
      if( c.b==1 )  printf("little endian\n");
      else printf("big endian\n");
      system("PAUSE"); 
      return 0;
}

“WAVE”格式由兩個子數據塊構成:“fmt”塊和“data”塊,其中“fmt”塊的詳細解釋如下: Subchunk1ID: 占4個字節,內容為“fmt ”的ASCII碼(0x666d7420),以大端存儲。
Subchunk1Size: 占4個字節,存儲該子塊的字節數(不含前面的Subchunk1ID和Subchunk1Size這8個字節),以小端方式存儲。
AudioFormat:占2個字節,以小端方式存儲,存儲音頻文件的編碼格式,例如若為PCM則其存儲值為1,若為其他非PCM格式的則有一定的壓縮。
NumChannels: 占2個字節,以小端方式存儲,通道數,單通道(Mono)值為1,雙通道(Stereo)值為2,等等。
SampleRate: 占4個字節,以小端方式存儲,采樣率,如8k,44.1k等。
ByteRate: 占4個字節,以小端方式存儲,每秒存儲的bit數,其值=SampleRate * NumChannels * BitsPerSample/8
BlockAlign: 占2個字節,以小端方式存儲,塊對齊大小,其值=NumChannels * BitsPerSample/8
BitsPerSample: 占2個字節,以小端方式存儲,每個采樣點的bit數,一般為8,16,32等。
接下來是兩個可選的擴展參數:
ExtraParamSize: 占2個字節,表示擴展段的大小。
ExtraParams: 擴展段其他自定義的一些參數的具體內容,大小由前一個字段給定。

其中,對於每個采樣點的bit數,不同的bit數讀取數據的方式不同:

1
2
3
4
5
6
7
8
9
10
// data 為讀取到的采樣點的值,speech為原始數據流,
//對應於下面的"WAVE"格式文件的第二個子數據塊“data”塊的“Data”部分。
for(i=0;i<NumSample;i++){
  if(BitsPerSample==8)
      data[i] = (int)*((char*)speech+i);
  else if(BitsPerSample==16)
      data[i] = (int)*((short*)speech+i);
  else if(BitsPerSample==32)
      data[i] = (int)*((int*)speech+i);
}

“WAVE”格式文件的第二個子數據塊是“data”,其個字段的詳細解釋如下:
Subchunk2ID: 占4個字節,內容為“data”的ASCII碼(0x64617461),以大端存儲。
Subchunk2Size: 占4個字節,內容為接下來的正式的數據部分的字節數,其值=NumSamples * NumChannels * BitsPerSample/8
Data: 真正的語音數據部分。

一個Wave文件頭的實例

設一個wave文件的前72個字節的十六進制內容如下(可以使用Ultra Edit等工具查看wave文件頭):

1
2
3
52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00 
22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00 
24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d
則其個字段的解析如下圖:
技術分享

C語言實現wave文件的讀取

這裏給出一個用基本的C語言文件操作庫函數實現的Wave文件讀取的實例代碼,可以跨Windows和Linux平臺。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// define Wave format structure
typedef struct tWAVEFORMATEX
{
    short wFormatTag;         /* format type */
    short nChannels;          /* number of channels (i.e. mono, stereo...) */
    unsigned int nSamplesPerSec;     /* sample rate */
    unsigned int nAvgBytesPerSec;    /* for buffer estimation */
    short nBlockAlign;        /* block size of data */
    short wBitsPerSample;     /* number of bits per sample of mono data */
    short cbSize;             /* the count in bytes of the size of */
                                    /* extra information (after cbSize) */
} WAVEFORMATEX, *PWAVEFORMATEX;

char* wavread(char *fname, WAVEFORMATEX *wf);

int main(){
  char fname[] = "test.wav";
  char *speech;
  WAVEFORMATEX wf;
  
  speech = wavread(fname, &wf);
  // afterward processing...
  
  return 0;
}

// read wave file
char* wavread(char *fname, WAVEFORMATEX *wf){
  FILE* fp;
  char str[32];
  char *speech;
  unsigned int subchunk1size; // head size
  unsigned int subchunk2size; // speech data size

  // check format type
  fp = fopen(fname,"r");
  if(!fp){
      fprintf(stderr,"Can not open the wave file: %s.\n",fname);
      return NULL;
  }
  fseek(fp, 8, SEEK_SET);
  fread(str, sizeof(char), 7, fp);
  str[7] = ‘\0‘;
  if(strcmp(str,"WAVEfmt")){
      fprintf(stderr,"The file is not in WAVE format!\n");
      return NULL;
  }
  
  // read format header
  fseek(fp, 16, SEEK_SET);
  fread((unsigned int*)(&subchunk1size),4,1,fp);
  fseek(fp, 20, SEEK_SET);
  fread(wf, subchunk1size, 1, fp);
  
  // read wave data
  fseek(fp, 20+subchunk1size, SEEK_SET);
  fread(str, 1, 4, fp);
  str[4] = ‘\0‘;
  if(strcmp(str,"data")){
      fprintf(stderr,"Locating data start point failed!\n");
      return NULL;
  }
  fseek(fp, 20+subchunk1size+4, SEEK_SET);
  fread((unsigned int*)(&subchunk2size), 4, 1, fp);
  speech = (char*)malloc(sizeof(char)*subchunk2size);
  if(!speech){
      fprintf(stderr, "Memory alloc failed!\n");
      return NULL;
  }
  fseek(fp, 20+subchunk1size+8, SEEK_SET);
  fread(speech, 1, subchunk2size, fp);

  fclose(fp);
  return speech;
}

參考

[1]WAVE PCM soundfile format: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
[2]Resource Interchange File Format: http://en.wikipedia.org/wiki/Resource_Interchange_File_Format
[3]基於Visual C++6.0的聲音文件操作: http://www.yesky.com/20030414/1663116_1.shtml

Original Link: http://ibillxia.github.io/blog/2013/07/20/details-of-wave-format-and-reading-wave-files-in-C-language/
Attribution - NON-Commercial - ShareAlike - Copyright ? Bill Xia

轉wave 文件解析