PCM WAVEフォーマットの詳細解とC言語でwaveファイルの読み込みを実現します。

20965 ワード

回転:http://ibillxia.github.io/blog/2013/07/20/details-of-wave-format-and-reading-wave-files-in-C-language/
1.PCM Waveフォーマットの詳細
WAVEファイルフォーマットは、マイクロソフトRIFF(Resource Interchange File Format、リソース交換ファイル標準)の一種であり、マルチメディアファイルに格納されているファイルフォーマットと標準である。一般的に、RIFFファイルはファイルヘッドとデータの二つの部分から構成されています。一つのWAVEファイルは一つの「WAVE」データブロックから構成されています。この「WAVE」ブロックはもう一つの「fmt」サブデータブロックと一つの「data」サブデータブロックから構成されています。このフォーマットは「Canonical form」(権威/牧師フォーマット)ともいいます。
各フィールドの意味は以下の通りである。ChunkID:4バイトを占め、内容は「RIFF」のASCIIコード(0 x 524946)で、ビッグエンド(big endian)で記憶される。ChunkSize:4バイトは、ファイル全体のバイト数(ChunkIDとChunkSizeの8バイトを含まない)を格納し、リトルエンディアン方式で記憶する。Format:4バイトで、内容は「WAVE」のASCIIコード(0 x 57415645)で、大端に格納されています。
ここで、bigendianは主に1つの特徴があり、メモリにおける動作数の記憶方式と、高バイトから低バイトまでがある。例えば、0 x 1234、このような数は、0 x 4000:0 x 12 0 x 4001:0 x 34で、小さな端littleendianは、0 x 4000:0 x 34 0 x 4001:0 x 12で、プログラムを区別すると、考えられます。
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
");
else printf("big endian
");
system("PAUSE"); return 0; }
「WAVE」形式は、2つのサブデータブロックから構成される。「fmt」ブロックと「data」ブロックは、「fmt」ブロックの詳細な説明は、以下の通りである。Subchunk 1 ID:4バイトを占め、コンテンツは「fmt」のASCIIコード(0 x 666 d 7420)は、大端で格納される。Subchunk 1 Size:4バイトを占めて、このサブブロックのバイト数(前のSubchunk 1 IDとSubchunk 1 Sizeの8バイトを含まない)を端数的に記憶する。AudioFormat:2バイトを占め、オーディオファイルの符号化フォーマットを小端に記憶し、例えばPCMの場合はその保存値は1であり、他の非PCM形式の場合は圧縮がある。NumChanels:2バイトを占めて、チャネル数、シングルチャネル値は1、デュアルチャネル値は2、など。SampleRate:4バイトを占め、8 k、44.1 kなどのサンプリングレートをリトルに記憶する。ByteRate:4バイトを小端で記憶し、毎秒記憶するビット数、その値=SampleRate*NumChanels*BitsPerSample/8 BlockAlign:2バイトを小端で記憶し、ブロック配置の大きさ、その値=Numbit Chanels*BitsPerSample/8 BitsPerSample/8 BitsPerSample/8サンプルの小数、16点を小端とします。次は2つのオプションの拡張パラメータです。ExtraParameSize:2バイト分で、拡張子のサイズを表します。ExtraParaams:拡張セグメントの他のカスタムパラメータの特定の内容は、前のフィールドによって与えられたサイズです。
ここでは、各サンプリングポイントのビット数に対して、異なるビット数でデータを読み出す方式が異なります。
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」であり、そのフィールドの詳細な説明は以下の通りである。Subchunk 2 ID:4バイトを占め、コンテンツは「data」のASCIIコード(0 x 6464646417461)は、大端に格納される。Subchunk 2 Size:4バイトを占め、コンテンツは次の正式なデータ部分のバイト数であり、その値=NumSamples*NumChanels*Bits PerSample/8 Data:本当の音声データ部分である。
ファイルヘッダの例
waveファイルを設定する前72バイトの16進数は以下の通りです。
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.
",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!
");
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!
");
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!
");
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_インターチェンジFile_Format  [3]ビジュアル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-Copyright©  ビルXia