2017-09-01 171 views
-3

我想獲取字節數組中音頻字節的音高(以Hz爲單位)。 現在這是我的代碼:從音頻字節中獲取音調或振幅等信息

 byte[] wav = File.ReadAllBytes("test.wav"); 
     for (int i = 44; i<wav.Length; i++) 
     { 
      // wav[i] is an audio byte, channel shifts every 2 bytes (I think) 
     } 

起初我以爲WAV文件是建立與數百或數千塊,每個塊包含一個採樣率,所以我試圖掃描另一個字節整個陣列序列表示作爲塊的一部分的單詞「WAVE」,但是採樣率僅在數組的開始處,並且在放置44之後,所有數組本身就是音頻數據本身。
音頻字節只是一個十六進制值,我不知道如何從該值獲取任何信息。

更新:我已經下載了具有FFT算法的Math.NET庫。 這是FFT的文檔:https://numerics.mathdotnet.com/api/MathNet.Numerics.IntegralTransforms/Fourier.htm 我已閱讀所有的方法,但我不知道什麼方法會做我想做的(給它的wav文件的幾個字節,並獲得他們的頻率)。

更新2: 現在我使用Accord庫進行FFT,我在YouTube上找到了一個教程。 這是我的聲音字節轉換爲雙陣列碼:

  for (int i = 44; i<wav.Length; i+=BufferSize) 
     { 
      float currentSec = (float) audioLength/wav.Length * i; 

      byte[] buffer = new byte[BufferSize]; 

      for (int j = 0; j < buffer.Length; j++) 
      { 
       if ((i + j + 1) < wav.Length) 
        buffer[j] = wav[i + j]; 
      } 

      int SAMPLE_RESOLUTION = 16; 
      int BYTES_PER_POINT = SAMPLE_RESOLUTION/8; 

      Int32[] vals = new Int32[buffer.Length/BYTES_PER_POINT]; 
      double[] Ys = new double[buffer.Length/BYTES_PER_POINT]; 
      double[] Ys2 = new double[buffer.Length/BYTES_PER_POINT]; 

      for (int k = 0; k < Ys.Length; k++) 
      { 
       byte hByte = buffer[k * 2 + 1]; 
       byte lByte = buffer[k * 2 + 0]; 

       vals[k] = (int)(short)((hByte << 8) | lByte); 
       Ys[k] = vals[k]; 
      } 
      Ys2 = FFT(Ys); 

      double avgFrq = AverageFromArray(Ys2); 

      if(lastSecond < (int) currentSec) 
       lastSecond = (int) currentSec; 

     } 

FFT功能:

 private double[] FFT(double[] data) 
    { 
     double[] fft = new double[data.Length]; 
     System.Numerics.Complex[] fftComplex = new System.Numerics.Complex[data.Length]; 
     for (int i = 0; i < data.Length; i++) 
     { 
      fftComplex[i] = new System.Numerics.Complex(data[i], 0); 
     } 

     Accord.Math.FourierTransform.FFT(fftComplex, Accord.Math.FourierTransform.Direction.Forward); 
     for (int i = 0; i < data.Length; i++) 
     { 
      fft[i] = fftComplex[i].Magnitude; 
     } 

     return fft; 
    } 

所以要檢查是否正常工作我做了一個wav文件,這只是在白噪聲5000Hz的頻率,但這些結果我從FFT獲得(2048個字節數組的值): https://pastebin.com/PUq5bQTn 整個音頻文件,具有5000Hz的頻率相同,但我的代碼給了我像值和605.80502914453746 4401.1090268930584

+3

你是什麼意思「音頻字節的音高」?該陣列是以特定的採樣速率對音頻流進行數字捕獲 - 每個字節代表採樣時刻的幅度 - 因爲該字節沒有音高。您需要對整個陣列(或其一部分)執行某種音頻分析以獲得該時間段的音調。 – PaulF

+0

您需要閱讀並分析標題。 – TaW

+0

@PaulF我可以分析並獲得它的音調的最短時間段是多少?我怎樣才能做到這一點? –

回答

4

WAV數據只是脈衝編碼調製(PCM)。這意味着每個值都代表音頻信號的實際點。

Wav文件有一個標題,你可以找到它的一些信息here。它描述了文件的結構。

如果通過「間距」樣品的基本頻率意味着,嘗試一個FFT

幅度是在某一個點的價值,但要注意,你需要考慮這些變量考慮在內:

  • 比特誤碼率樣品
  • 字節順序
  • 塊對準
  • 通道數
+0

請參閱@ JohanDonne的答案以更好地鏈接到標題結構:http://soundfile.sapp.org/doc/WaveFormat/ – Stefan

+0

分析數字音頻時 - 音調通常定義爲樣本的基本頻率(即最大振幅頻率) - _「音高是播放和原始採樣率的差異」_聽起來更像是音高轉換。 – PaulF

+0

我的意思是頻率分析,我只是不知道如何實現FFT –

6

恐怕你的代碼(和問題)太過於天真了。

  1. Wav文件不僅僅是音頻樣本的集合。查看(例如)http://soundfile.sapp.org/doc/WaveFormat/瞭解文件格式及其結構的描述。

  2. 如果你想讀取,處理,寫入音頻文件,那裏有不同的庫(例如,NAudio),這將有很大的幫助。

  3. 從audiostream中的1個樣本中,您永遠無法計算音高。要做到這一點,您需要一個(相對較大的)樣本數量,並使用FFT變換計算頻譜。

+0

尼斯鏈接,我正在尋找這樣的標題描述。 :-) – Stefan

+0

在發佈這個問題之前,我剛剛讀到這個數字,這個數字非常好,它幫助我理解了WAV文件的結構。 –

2
  1. 單個FFT幅度峯是衡量音調較差,經常不準確的方式,因爲間距是一個比較複雜的心理現象。

  2. 估計頻率存在時間頻率折衷,通常與sampleRate/blockLength成比例。因此,以44100的採樣率使用44個採樣塊,頻率估計誤差將在44100/44的數量級或大約+ 1000Hz(可能取決於平穩性和信噪比)。

+0

你可以定義'blockLength'嗎? –

+0

DFT的長度。 – hotpaw2