解析wav文件时我做错了什么?

时间:2016-12-07 03:13:28

标签: c# wav

我试图解析一个wav文件。我不确定wav文件中是否有多个数据块,但我最初假设只有1个,因为我阅读的wav文件格式描述只提到有1个。

但我注意到,当解析的wav文件大小为36MB且采样率为44100时,subchunk2size非常小(如26)。

所以我尝试解析它假设有多个块,但在第一个块之后,没有找到subchunk2id。

要按块进行块,我使用下面的代码

int chunkSize = System.BitConverter.ToInt32(strm, 40);
int widx = 44; //wav data starts at the 44th byte
//strm is a byte array of the wav file
while(widx < strm.Length)
{
    widx += chunkSize;
    if(widx < 1000)
    {
        //log "data" or "100 97 116 97" for the subchunkid
        //This is only getting printed the 1st time though. All prints after that are garbage
        Debug.Log( strm[widx] + " " + strm[widx+1] + " " + strm[widx+2] + " " + strm[widx+3]);
    }
    if(widx + 8 < strm.Length)
    {
        widx += 4;
        chunkSize = System.BitConverter.ToInt32(strm, widx);
        widx += 4;
    }else
    {
        widx += 8;
    }
}

2 个答案:

答案 0 :(得分:1)

.wav-File有3个块: 每个块的大小为4 Byte

第一个块是&#34; RIFF&#34; -chunk。它包括8字节文件大小(4字节)和格式名称(4字节,通常&#34; WAVE&#34;)。

下一个块是&#34; fmt&#34; -chunk(块名称中的空格很重要)。它包括音频格式(2字节),通道数(2字节),采样率(4字节),字节速率(4字节),块对齐(2字节)和每采样位数(2字节)

第三个和最后一个块是数据块。以下是样本的实际数据和幅度。它包括4个数据字节的字节,这是数据的字节数。

您可以找到.wav文件here的属性的进一步说明。

根据这些知识,我已经创建了以下课程:

public sealed class WaveFile
{
    //privates
    private int fileSize;
    private string format;
    private int fmtChunkSize;
    private int audioFormat;
    private int numChannels;
    private int sampleRate;
    private int byteRate;
    private int blockAlign;
    private int bitsPerSample;
    private int dataSize;
    private int[][] data;//One array per channel

    //publics
    public int FileSize => fileSize;
    public string Format => format;
    public int FmtChunkSize => fmtChunkSize;
    public int AudioFormat => audioFormat;
    public int NumChannels => numChannels;
    public int SampleRate => sampleRate;
    public int ByteRate => byteRate;
    public int BitsPerSample => bitsPerSample;
    public int DataSize => dataSize;
    public int[][] Data => data;

    public WaveFile(string path)
    {
        FileStream fs = File.OpenRead(path);
        LoadChunk(fs); //read RIFF Chunk
        LoadChunk(fs); //read fmt Chunk
        LoadChunk(fs); //read data Chunk
        fs.Close();
    }

    private void LoadChunk(FileStream fs)
    {
        ASCIIEncoding Encoder = new ASCIIEncoding();
        byte[] bChunkID = new byte[4];

        fs.Read(bChunkID, 0, 4);
        string sChunkID = Encoder.GetString(bChunkID);

        byte[] ChunkSize = new byte[4];

        fs.Read(ChunkSize, 0, 4);

        if (sChunkID.Equals("RIFF"))
        {
            fileSize = BitConverter.ToInt32(ChunkSize, 0);

            byte[] Format = new byte[4];
            fs.Read(Format, 0, 4);
            this.format = Encoder.GetString(Format);
        }

        if (sChunkID.Equals("fmt "))
        {
            fmtChunkSize = BitConverter.ToInt32(ChunkSize, 0);
            byte[] audioFormat = new byte[2];
            fs.Read(audioFormat, 0, 2);
            this.audioFormat = BitConverter.ToInt16(audioFormat, 0);
            byte[] numChannels = new byte[2];
            fs.Read(numChannels, 0, 2);
            this.numChannels = BitConverter.ToInt16(numChannels, 0);
            byte[] sampleRate = new byte[4];
            fs.Read(sampleRate, 0, 4);
            this.sampleRate = BitConverter.ToInt32(sampleRate, 0);
            byte[] byteRate = new byte[4];
            fs.Read(byteRate, 0, 4);
            this.byteRate = BitConverter.ToInt32(byteRate, 0);
            byte[] blockAlign = new byte[2];
            fs.Read(blockAlign, 0, 2);
            this.blockAlign = BitConverter.ToInt16(blockAlign, 0);
            byte[] bitsPerSample = new byte[2];
            fs.Read(bitsPerSample, 0, 2);
            this.bitsPerSample = BitConverter.ToInt16(bitsPerSample, 0);
        }

        if (sChunkID.Equals("data"))
        {
            dataSize = BitConverter.ToInt32(ChunkSize, 0);
            data = new int[this.numChannels][];

            byte[] temp = new byte[dataSize];

            for (int i = 0; i < this.numChannels; i++)
            {
                data[i] = new int[this.dataSize / (numChannels * bitsPerSample / 8)];
            }

            for (int i = 0; i < data[0].Length; i++)
            {
                for (int j = 0; j < numChannels; j++)
                {
                    if (fs.Read(temp, 0, blockAlign / numChannels) > 0)
                    {
                        if (blockAlign / numChannels == 2)
                        { data[j][i] = BitConverter.ToInt32(temp, 0); }
                        else
                        { data[j][i] = BitConverter.ToInt16(temp, 0); }

                    }
                }
            }
        }
    }
}

需要使用指令:

using System;
using System.IO;
using System.Text;

此类读取每个字节的所有块字节并设置属性。您只需初始化此类,它将返回所选波形文件的所有属性。

答案 1 :(得分:0)

在您添加的参考文献中,我没有看到任何提及每个数据块重复的块大小...

尝试这样的事情:

int chunkSize = System.BitConverter.ToInt32(strm, 40);
int widx = 44; //wav data starts at the 44th byte
//strm is a byte array of the wav file
while(widx < strm.Length)
{
    if(widx < 1000)
    {
        //log "data" or "100 97 116 97" for the subchunkid
        //This is only getting printed the 1st time though. All prints after that are garbage
        Debug.Log( strm[widx] + " " + strm[widx+1] + " " + strm[widx+2] + " " + strm[widx+3]);
    }    
    widx += chunkSize;
}
相关问题