2013-03-18 29 views
0

我剛剛從編程的角度開始編輯音樂,我瞭解了很多關於波形和這種性質的想法,但是我一直在關注如何從聲音文件中讀取單個樣本的問題作爲一個字節數組。如何從音樂文件中讀取樣本?

我正在使用Alvas.Audio庫(http://www.alvas.net/alvas.audio.aspx)和C#,如果這有助於回答問題。

據我所知,不同的文件格式有不同的存儲數據的方式,但我的主要問題圍繞如何以編程方式確定數據如何存儲以及一次遍歷文件一個樣本。我可能會將所有文件轉換爲.wav格式(使用Alvas庫),因此專門針對wav格式的答案就足夠了,但是我仍然對在文件處於立體聲時迭代樣本感到好奇。據我所知,具有立體聲數據的文件連續存儲並行採樣。

我的最終目標是能夠從歌曲的某個時間段(在歌曲中的某個位置幾秒鐘)獲取樣本,然後對它們執行一些數學或其他內容,但我只是不要確定我讀到的內容其實是正確的數據。

回答

0

假設您知道如何打開文件並從中讀取數據,則需要引用數據文件格式。對於WAV文件,請參閱here以獲取關於如何組織和訪問數據的說明。

enter image description here

Offset Size Name    Description 

The canonical WAVE format starts with the RIFF header: 

0   4 ChunkID   Contains the letters "RIFF" in ASCII form 
           (0x52494646 big-endian form). 
4   4 ChunkSize  36 + SubChunk2Size, or more precisely: 
           4 + (8 + SubChunk1Size) + (8 + SubChunk2Size) 
           This is the size of the rest of the chunk 
           following this number. This is the size of the 
           entire file in bytes minus 8 bytes for the 
           two fields not included in this count: 
           ChunkID and ChunkSize. 
8   4 Format   Contains the letters "WAVE" 
           (0x57415645 big-endian form). 

The "WAVE" format consists of two subchunks: "fmt " and "data": 
The "fmt " subchunk describes the sound data's format: 

12  4 Subchunk1ID  Contains the letters "fmt " 
           (0x666d7420 big-endian form). 
16  4 Subchunk1Size 16 for PCM. This is the size of the 
           rest of the Subchunk which follows this number. 
20  2 AudioFormat  PCM = 1 (i.e. Linear quantization) 
           Values other than 1 indicate some 
           form of compression. 
22  2 NumChannels  Mono = 1, Stereo = 2, etc. 
24  4 SampleRate  8000, 44100, etc. 
28  4 ByteRate   == SampleRate * NumChannels * BitsPerSample/8 
32  2 BlockAlign  == NumChannels * BitsPerSample/8 
           The number of bytes for one sample including 
           all channels. I wonder what happens when 
           this number isn't an integer? 
34  2 BitsPerSample 8 bits = 8, 16 bits = 16, etc. 
      2 ExtraParamSize if PCM, then doesn't exist 
      X ExtraParams  space for extra parameters 

The "data" subchunk contains the size of the data and the actual sound: 

36  4 Subchunk2ID  Contains the letters "data" 
           (0x64617461 big-endian form). 
40  4 Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 
           This is the number of bytes in the data. 
           You can also think of this as the size 
           of the read of the subchunk following this 
           number. 
44  * Data    The actual sound data. 

更新:添加的數據在線。

+0

該鏈接是史詩般的,謝謝:) – Tevis 2013-03-19 21:23:39

+0

該鏈接已死亡,一個很好的例子說明爲什麼只有鏈接的答案沒有幫助。 – miken32 2016-12-20 18:04:39

+0

以上第二個想法 – Fer 2017-07-25 21:07:21

1

「打包」音頻數據的最常見方式是PCM - 用於未壓縮的WAV文件。每個樣本都「打包」成短整型值(short),如果您有可以提供PCM的庫,則可以通過將它們視爲short值的數組來處理它們。

根據通道數量的不同,每個樣本的數量將爲short s。由於每個short是2 byte s,您通常每個樣本4個字節用於立體聲音頻。假設以44100(最常見的採樣率 - 來自CD)採樣音頻,則必須跳過44100 * 4字節,以便例如在1.0s位置訪問音頻數據到音頻文件。

3

參見What is a PCM format?

PCM(脈衝編碼調製)是未壓縮的音頻格式。我們得到Wav文件,它維護(保存)PCM數據。看怎麼做什麼是Wav文件?方法AudioCompressionManager.GetWaveFormat有助於調查音頻格式。

  • FormatTag = 1是PCM。
  • 通道=用於單通道(單聲道),雙通道(立體聲),8用於7.1環繞聲(左,右,中央,左環繞,右環繞,左後,右後方7.1系統也有1低頻效果通道(LFE)通常發送到超低音揚聲器)。
  • SamplesPerSec =每秒(或採樣)的數字化數量值。可以是任何東西,但是標準值:8000Hz,11025Hz,12000Hz,16000Hz,22050Hz,24000Hz,32000Hz,44100Hz,48000Hz。
  • BitsPerSample - 最常見的使用8位(1字節)和16位(2字節)。很少24位(3字節),32位(4字節)和64位(4字節)。如果我們認爲16位是基本的,那麼8位可以被認爲是壓縮格式。它的大小減少了兩倍,但是對於16位,值的變體可以只有28 = 256而不是216 = 65536。這就是爲什麼8位音質將明顯低於16位。
  • BlockAlign = Channels * BitsPerSample/8.其中8是每個字節的位數。
  • AvgBytesPerSec(比特率)=通道* SamplesPerSec * BitsPerSample/8.

可以使用下面的代碼來分析PCM音頻格式中更特別。

private void WhatIsPcmFormat(string fileName) 
    { 
     WaveReader wr = new WaveReader(File.OpenRead(fileName)); 
     IntPtr format = wr.ReadFormat(); 
     wr.Close(); 
     WaveFormat wf = AudioCompressionManager.GetWaveFormat(format); 
     if (wf.wFormatTag == AudioCompressionManager.PcmFormatTag) 
     { 
      int bitsPerByte = 8; 
      Console.WriteLine("Channels: {0}, SamplesPerSec: {1}, BitsPerSample: {2}, BlockAlignIsEqual: {3}, BytesPerSecIsEqual: {4}", 
      wf.nChannels, wf.nSamplesPerSec, wf.wBitsPerSample, 
      (wf.nChannels * wf.wBitsPerSample)/bitsPerByte == wf.nBlockAlign, 
      (int)(wf.nChannels * wf.nSamplesPerSec * wf.wBitsPerSample)/bitsPerByte == wf.nAvgBytesPerSec); 
     } 
    } 
相關問題