2016-12-07 81 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; 

該類讀取每個字節的所有字節塊,並設置屬性。你只需要初始化這個類,它將返回你選擇的波形文件的所有屬性。