C++读取Wav文件

C++的新手,自从搞了算法和kaldi开始着手C++,所以有很多坑没有趟过。最近需要把手头的matlab程序转化成C++,其中涉及到读取wav音频文件的部分,着实头疼,所以上网搜了一下,并且自己进行了尝试和改写,写了自己的一个版本,在这里主要记录一下其中遇到的教训和经验理解。

首先在做这个问题之前,确保你自己知道,你的wav文件的采样率和位数,我这里以最普遍的16k和16bit的wav文件来说明。有很大一部分人在想:我直接用二进制流暴力的读取不行吗,怎么那么多说道。同学这个思想是好的,不过有偏差。不知道你玩没玩过auditon,即使没玩过也应该听过cool edit,两款音频编辑软件。你往里面扔wav,mp3等格式的文件的时候,他什么都不会问你,自己就知道采样率和位数声道数等。而如果你扔进去pcm格式的音频的时候,他会问这问那,下面是Adobe audition的截图:

那么你会想为什么呢?同样的两种文件为什么一个他啥都知道,一个他啥都不知道呢?仔细想不难想出:wav(mp3)等文件里面有某种标识的部分,并且已经成为了某种标准,所以按照某种解码去解读就能获取相关内容。而pcm什么都没有。那么很明显了,wav里面含有标识位,在没有把标识位找出来的请路况下直接暴力读取很明显是错误的。顺着这个思路我们上网上搜一下关于wav标识位的内容,找到如下图:

C++读取Wav文件_第1张图片

这里的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<

结果可以考证,希望帮得到大家。

你可能感兴趣的:(C++)