2016-12-07 80 views
0

我想解析一个wav文件。我不确定在wav文件中是否可以有多个数据块,但是我原本以为只有1个,因为我读的wav文件格式说明只提到了1个。解析wav文件时我做了什么错误?

但我注意到subchunk2size是非常小的(如26),当分析的wav文件是像大约36MB和采样率是44100.

所以我试图解析它假设有多个块,但在第一个块后,没有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; 
    } 
} 
+0

它非常含糊地提及它没有运行/没有工作。请提及您的例外情况,如有任何或任何有关错误的细节。 –

+0

我确实提到过这些东西。我没有看到第一个缓冲区中的“数据”,我的subchunk2size太小了。 – Thundercleez

+0

你能解释你如何期待数据被格式化吗?从代码它看起来像︰ 标题(40):chunksize(4):(数据块大小):(:(4个字节的东西?):(新的块大小):(数据块大小):等... 是否正确? – meganaut

回答

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; 
} 
+0

是的,我知道它只提到1,但我不确定是否可以有其他的块。它看起来并不像它,因为我也试图搜索整个数据阵列中的另一个“数据”块标识符,并找不到一个。但是我不明白为什么当文件为36MB时subchunk2size只有26。它应该比这大得多。我想知道是否有错误的wav文件,因为第一块大小也是假的(我得到0xffffffff)。我使用ffmpeg来制作wav文件,所以我可能会错过一个选项或其他东西? – Thundercleez

+0

@Thundercleez这听起来像文件可能已损坏。尝试拔出ChunkSize(字节4 - 8)。它应该等于36 + SubChunk2Size。 – meganaut

+0

它确实在该文档的底部说过,WAV文件通常使用较旧的格式。遗憾的是旧格式的链接被打破。我认为你应该看看数据中的文件,并确保一切都在你期望的位置。如果不是,可能会更好地搜索“数据”字(预期为36-40),然后从那里开始工作。 – meganaut

1

一个.wav-文件有3个大块: 每个块的大小4字节的

第一块是“RIFF” - 大块。它包括8字节的文件大小(4字节)和格式名称(4字节,通常是“WAVE”)。

下一个块是“fmt”-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指令:

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

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