我的第一条建议是使用某种库来帮助你。大多数声音解决方案似乎都过于复杂,因此一个简单的库(如在你的问题评论中推荐的libsndfile)就可以解决问题。
如果你只是想知道如何读取WAV文件,以便自己编写代码(因为你的学校可能会不赞成你像其他普通人一样使用库),那么快速搜索谷歌将为你提供所有所需信息以及一些已经编写了许多有关读取.wav格式的教程的人。
如果你还不明白,这里有一些我自己的代码,我读取了WAV/RIFF数据文件的头部和所有其他块,直到我到达数据块。它完全基于WAV格式规范。提取实际的声音数据并不难:你可以直接读取并使用原始数据,或者将其转换为你在内部更舒适的格式(32位PCM无压缩数据或其他格式)。
查看下面的代码时,请用相应的fread
调用替换reader.Read...( ... )
,以获取指定类型的整数值和字节大小。 WavChunks
是一个枚举类型,它是WAV文件块内部ID的小端值,而format
变量则是WAV文件格式中可能包含的Wav格式类型之一:
enum class WavChunks {
RiffHeader = 0x46464952,
WavRiff = 0x54651475,
Format = 0x020746d66,
LabeledText = 0x478747C6,
Instrumentation = 0x478747C6,
Sample = 0x6C706D73,
Fact = 0x47361666,
Data = 0x61746164,
Junk = 0x4b4e554a,
};
enum class WavFormat {
PulseCodeModulation = 0x01,
IEEEFloatingPoint = 0x03,
ALaw = 0x06,
MuLaw = 0x07,
IMAADPCM = 0x11,
YamahaITUG723ADPCM = 0x16,
GSM610 = 0x31,
ITUG721ADPCM = 0x40,
MPEG = 0x50,
Extensible = 0xFFFE
};
int32 chunkid = 0;
bool datachunk = false;
while ( !datachunk ) {
chunkid = reader.ReadInt32( );
switch ( (WavChunks)chunkid ) {
case WavChunks::Format:
formatsize = reader.ReadInt32( );
format = (WavFormat)reader.ReadInt16( );
channels = (Channels)reader.ReadInt16( );
channelcount = (int)channels;
samplerate = reader.ReadInt32( );
bitspersecond = reader.ReadInt32( );
formatblockalign = reader.ReadInt16( );
bitdepth = reader.ReadInt16( );
if ( formatsize == 18 ) {
int32 extradata = reader.ReadInt16( );
reader.Seek( extradata, SeekOrigin::Current );
}
break;
case WavChunks::RiffHeader:
headerid = chunkid;
memsize = reader.ReadInt32( );
riffstyle = reader.ReadInt32( );
break;
case WavChunks::Data:
datachunk = true;
datasize = reader.ReadInt32( );
break;
default:
int32 skipsize = reader.ReadInt32( );
reader.Seek( skipsize, SeekOrigin::Current );
break;
}
}