C++的新手,自从搞了算法和kaldi开始着手C++,所以有很多坑没有趟过。最近需要把手头的matlab程序转化成C++,其中涉及到读取wav音频文件的部分,着实头疼,所以上网搜了一下,并且自己进行了尝试和改写,写了自己的一个版本,在这里主要记录一下其中遇到的教训和经验理解。
首先在做这个问题之前,确保你自己知道,你的wav文件的采样率和位数,我这里以最普遍的16k和16bit的wav文件来说明。有很大一部分人在想:我直接用二进制流暴力的读取不行吗,怎么那么多说道。同学这个思想是好的,不过有偏差。不知道你玩没玩过auditon,即使没玩过也应该听过cool edit,两款音频编辑软件。你往里面扔wav,mp3等格式的文件的时候,他什么都不会问你,自己就知道采样率和位数声道数等。而如果你扔进去pcm格式的音频的时候,他会问这问那,下面是Adobe audition的截图:
那么你会想为什么呢?同样的两种文件为什么一个他啥都知道,一个他啥都不知道呢?仔细想不难想出:wav(mp3)等文件里面有某种标识的部分,并且已经成为了某种标准,所以按照某种解码去解读就能获取相关内容。而pcm什么都没有。那么很明显了,wav里面含有标识位,在没有把标识位找出来的请路况下直接暴力读取很明显是错误的。顺着这个思路我们上网上搜一下关于wav标识位的内容,找到如下图:
这里的position都是字节,一定要注意。那么我们看到了每个字节都有标识什么内容,接下来我们开始设计我们的程序。用一个struct标识这个结构,由于是16位的,所以对于整数类型的我们按照两个字节一个来读取,所以我是用int16_t来表示一个最小读取单位(char除外)。那么下面给出程序:
#include
#include
#include
#include
using namespace std;
struct WavData{
public:
int16_t* data;
long size;
WavData(){
data=NULL;
size=0;
}
};
void loadWavFile(const char* fname,WavData *ret){
FILE* fp=fopen(fname,"rb");
if(fp){
char id[5];
int32_t size;
int16_t format_tag,channels,block_align,bits_per_sample;
int32_t format_length,sample_rate,avg_bytes_sec,data_size;
fread(id,sizeof(char),4,fp);
id[4]='\0';
if(!strcmp(id,"RIFF")){
fread(&size,sizeof(int16_t),2,fp);
fread(id,sizeof(char),4,fp);
id[4]='\0';
if(!strcmp(id,"WAVE")){
fread(id,sizeof(char),4,fp);
fread(&format_length,sizeof(int16_t),2,fp);
fread(&format_tag,sizeof(int16_t),1,fp);
fread(&channels,sizeof(int16_t),1,fp);
fread(&sample_rate,sizeof(int16_t),2,fp);
fread(&avg_bytes_sec,sizeof(int16_t),2,fp);
fread(&block_align,sizeof(int16_t),1,fp);
fread(&bits_per_sample,sizeof(int16_t),2,fp);
fread(id,sizeof(char),4,fp);
fread(&data_size,sizeof(int16_t),2,fp);
ret->size=data_size/sizeof(int16_t);
// 动态分配了空间,记得要释放
ret->data=(int16_t*)malloc(data_size);
fread(ret->data,sizeof(int16_t),ret->size,fp);
}
else{
cout<<"Error: RIFF File but not a wave file\n";
}
}
else{
cout<<"ERROR: not a RIFF file\n";
}
}
fclose(fp);
}
void freeSource(WavData* data){
free(data->data);
}
int main(){
WavData song;
ofstream out("city_16k.txt");
const char* fname="city_16k.wav";
loadWavFile(fname,&song);
cout<
结果可以考证,希望帮得到大家。