在C/C++中读取和处理WAV文件数据

16
我正在进行一项非常重要的学校项目,需要用C/C++提取WAVE文件的信息并使用该信息获取语音信号的LPC。但是,为了做到这一点,我需要对信号进行一些预处理,例如进行零交叉和能量分析等操作。这意味着我需要符号和实际值。问题是我不知道如何获取有用的信息和正确的格式。我已经阅读了文件中的每个字段,但我不确定是否做得正确。请给些建议?
这是我目前读取文件的方法:
``` readI = fread(&bps, 1, 2, audio); printf("bits per sample = %d \n", bps); ```
提前感谢。

3
这两个库可能会帮助你处理 WAV 文件:http://www.mega-nerd.com/libsndfile/ 和 http://ccrma.stanford.edu/software/snd/sndlib/。 - Patashu
1个回答

20

我的第一条建议是使用某种库来帮助你。大多数声音解决方案似乎都过于复杂,因此一个简单的库(如在你的问题评论中推荐的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;
    }
}

3
为什么 RIFF 的十六进制表示是反过来的?我知道关于小/大端的问题,但我使用的所有十六进制编辑器都显示为 RIFF,而不是 FFIR,它们是在进行某种奇怪的转换,还是其他情况? - MarcusJ
我认为@MarcusJ是正确的,应该读作RIFF,这里有一个波形格式的描述http://soundfile.sapp.org/doc/WaveFormat/,所以我相信它应该是RiffHeader=0x52494646,因为格式说明它是big-endian字段。 - alexm
@MarcusJ 因为它是小端字节序...这甚至在答案本身中直接说明了。旧评论 - user202729

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接