我们先随便找一个wav文件,查看其属性,就能得到下面的结果。
上面主要注意文件大小,声音长度与比特率。
文件占用空间就不用关心了,如果有人想知道为什么文件占用空间比文件大小要大,我在这里也解释一下。这和文件在硬盘中的组织方式有关系,这里的硬盘分区是以最小4096Byte为单位的,我文件的大小是1325044Byte,那么1325044/4096=323.49,为了能把文件对齐的放到硬盘中,所以占用的空间就要是324*4096=1327104Byte了,所以占用的空间就是这么多了。你也可以建立一个只写一个字母的txt文件试试,文件大小虽然为1Byte,不过占用空间也为4096Byte。
上面说的当然和wav文件没什么关系,下面就正式说wav文件的问题。
用ultraedit打开就是下面这个样子:
用表格说明一下文件的格式:
起始地址 | 占用空间 | 本地址数字的含义 |
00H | 4byte | RIFF,资源交换文件标志。 |
04H | 4byte | 从下一个地址开始到文件尾的总字节数。高位字节在后面,这里就是001437ECH,换成十进制是1325036byte,算上这之前的8byte就正好1325044byte了。 |
08H | 4byte | WAVE,代表wav文件格式。 |
0CH | 4byte | FMT ,波形格式标志 |
10H | 4byte | 00000010H,16PCM,我的理解是用16bit的数据表示一个量化结果。 |
14H | 2byte | 为1时表示线性PCM编码,大于1时表示有压缩的编码。这里是0001H。 |
16H | 2byte | 1为单声道,2为双声道,这里是0001H。 |
18H | 4byte | 采样频率,这里是00002B11H,也就是11025Hz。 |
1CH | 4byte | Byte率=采样频率*音频通道数*每次采样得到的样本位数/8,00005622H,也就是22050Byte/s=11025*1*16/2。 |
20H | 2byte | 块对齐=通道数*每次采样得到的样本位数/8,0002H,也就是2=1*16/8。 |
22H | 2byte | 样本数据位数,0010H即16,一个量化样本占2byte。 |
24H | 4byte | data,一个标志而已。 |
28H | 4byte | Wav文件实际音频数据所占的大小,这里是001437C8H即1325000,再加上2CH就正好是1325044,整个文件的大小。 |
2CH | 不定 | 量化数据。 |
注意属性中的比特率是176kbps,而1CH中为22050Byte/s,换算一下就会发现22050*8/1024并不等于176,而是等于172,这里我想可能是通信中的1K并不等于1024而是等于1000的原因(通信原理书中好像有),如果按22050*8/1000这样算,就正好等于176了。其实比特率也可以这样算,总字节除以时长得到每秒字节率,再乘以8除以1000就得到比特率了,即(1325000/60)*8/1000=176kbps。
最后是量化数据的表示。
看数据结尾的表示吧,我这音频最初那一段都是0,不好解释。
Ultraedit中的表示:
Matlab中的表示:
上面的matlab是662500个数,正好也是11325000的一半。可以看出数据是有正有负的浮点数,为正负双向PCM量化编码,得到的十六进制位的最高位是一个符号位,为0表示正数,为1表示负数,正好表示-32768~32767。而且十六进制的数据正数要除以32767,负数要除以32768才能得到结果,如果是单向PCM就要除以65535了。
比如最后一位十六进制为2710H,在Matlab中为0.3052,而2710H的十进制10000除以32767正好近似为0.3052。
再比如matlab中662472这个数为-0.0206,考虑到44位的偏差,在ultraedit中为1437BAH位上的FD5DH,表示为十进制-675除以32768正好近似为-0.0206。
当然,上面只是针对matlab和ultraedit中的数据进行具体的分析,真正编程处理时还是要根据情况有所不同的。量化位数的不同,32bit或是8bit处理又不同了。符号的表示也可能不同,原码补码反码等等的知识可能也要用到。
这里我只把基本的数据提取出来了,没有进行下一步处理,数据提取出来,后面怎么应用就看具体情况了。
#include <iostream> #include <fstream> using namespace std; struct wav_struct { unsigned long file_size; //文件大小 unsigned short channel; //通道数 unsigned long frequency; //采样频率 unsigned long Bps; //Byte率 unsigned short sample_num_bit; //一个样本的位数 unsigned long data_size; //数据大小 unsigned char *data; //音频数据 ,这里要定义什么就看样本位数了,我这里只是单纯的复制数据 }; int main(int argc,char **argv) { fstream fs; wav_struct WAV; fs.open("B:\\output.wav",ios::binary|ios::in); // fs.seekg(0x04); //从文件数据中获取文件大小 // fs.read((char*)&WAV.file_size,sizeof(WAV.file_size)); // WAV.file_size+=8; fs.seekg(0,ios::end); //用c++常用方法获得文件大小 WAV.file_size=fs.tellg(); fs.seekg(0x14); fs.read((char*)&WAV.channel,sizeof(WAV.channel)); fs.seekg(0x18); fs.read((char*)&WAV.frequency,sizeof(WAV.frequency)); fs.seekg(0x1c); fs.read((char*)&WAV.Bps,sizeof(WAV.Bps)); fs.seekg(0x22); fs.read((char*)&WAV.sample_num_bit,sizeof(WAV.sample_num_bit)); fs.seekg(0x28); fs.read((char*)&WAV.data_size,sizeof(WAV.data_size)); WAV.data=new unsigned char[WAV.data_size]; fs.seekg(0x2c); fs.read((char *)WAV.data,sizeof(char)*WAV.data_size); cout<<"文件大小为 :"<<WAV.file_size<<endl; cout<<"音频通道数 :"<<WAV.channel<<endl; cout<<"采样频率 :"<<WAV.frequency<<endl; cout<<"Byte率 :"<<WAV.Bps<<endl; cout<<"样本位数 :"<<WAV.sample_num_bit<<endl; cout<<"音频数据大小:"<<WAV.data_size<<endl; cout<<"最后20个数据:"<<endl; for (unsigned long i=WAV.data_size-20;i<WAV.data_size;i++) { printf("%x ",WAV.data[i]); } fs.close(); delete[] WAV.data; system("pause"); }
运行结果: