2017-06-02 349 views
0

我想從.wav文件中分離出低頻,中頻和高頻。因爲我已經使用FFT將數據從時域轉換到頻域。如何從音頻文件(.wav)中分離頻率

閱讀文件和應用與n音訊的幫助下快速傅立葉變換的代碼是這樣

OpenFileDialog file = new OpenFileDialog(); 
     file.ShowDialog(); 
     WaveFileReader reader = new WaveFileReader(file.FileName); 
     int samepleRate = reader.WaveFormat.SampleRate; 
     double ts = 1.0/samepleRate; 
     int _fftLength = 4096; 
     double time = reader.TotalTime.TotalSeconds; 
     int channels = reader.WaveFormat.Channels; 
     int _m = (int)Math.Log(_fftLength, 2.0); 
     float fileSize = (float)reader.Length/1048576; 
     if (fileSize < 2) 
      window = 8; 
     else if (fileSize > 2 && fileSize < 4) 
      window = 16; 
     else if (fileSize > 4 && fileSize < 8) 
      window = 32; 
     else if (fileSize > 8 && fileSize < 12) 
      window = 128; 
     else if (fileSize > 12 && fileSize < 20) 
      window = 256; 
     else if (fileSize > 20 && fileSize < 30) 
      window = 512; 
     else 
      window = 2048; 


     byte[] readBuffer = new byte[reader.Length]; 

     reader.Read(readBuffer,0,readBuffer.Length); 
     float[] data = ConvertByteToFloat(readBuffer,readBuffer.Length);    

     Complex[] fftBuffer= new Complex[_fftLength]; 
     int fftPos = 0; 
     for (int i = 0; i < _fftLength; i++) 
     { 
      fftBuffer[fftPos].X = (float)(data[i] * NAudio.Dsp.FastFourierTransform.HammingWindow(i,_fftLength)); 
      fftBuffer[fftPos].Y = 0; 
      fftPos++; 
     } 
     NAudio.Dsp.FastFourierTransform.FFT(true, _m, fftBuffer); 

private float[] ConvertByteToFloat(byte[] array, int length) 
    { 
     int samplesNeeded = length/4; 
     float[] floatArr = new float[samplesNeeded]; 

     for (int i = 0; i < samplesNeeded; i++) 
     { 
      floatArr[i] = (float)BitConverter.ToInt32(array, i * 4); 
     } 

     return floatArr; 
    } 

//ZedGraph code 
     GraphPane myPane = zedGraphControl1.GraphPane; 
     myPane.Title.Text = "Frequency domain output"; 
     PointPairList list1 = new PointPairList(); 
     PointPairList list2 = new PointPairList(); 
     for (int i = 0; i < fftBuffer.Length; i++) 
     { 
      list1.Add(i, fftBuffer[i].Y); 
     } 
     list2.Add(0, 0); 
     //list2.Add(time, 0);uncomment this and remove below to plot time domain graph 
     var maxIndex = -1; 
     var maxValue = 0f; 
     for (var j = 0; j < _fftLength/2; j++) 
     { 
      var value = fftBuffer[j].X * fftBuffer[j].X 
       + fftBuffer[j].Y * fftBuffer[j].Y; 

      if (value > maxValue) 
      { 
       maxIndex = j; 
       maxValue = value; 
      } 
      var freq = maxIndex == -1 ? 0 
      : (ushort)Math.Round((_fftLength - maxIndex)/(_fftLength * ts)); 
      list2.Add(freq, 0); 
     } 
     if (myCurve1 != null && myCurve2 != null) 
     { 
      myCurve1.Clear(); 
      myCurve2.Clear(); 
     } 

     myCurve1 = myPane.AddCurve(null, list1, Color.Blue, SymbolType.None); 
     myCurve1.IsX2Axis = true; 
     myCurve2 = myPane.AddCurve(null, list2, Color.Black, SymbolType.None); 
     myPane.XAxis.Scale.MaxAuto = true; 
     myPane.XAxis.Scale.MinAuto = true; 
     myPane.YAxis.Title.Text = "Amplitude"; 
     myPane.XAxis.Title.Text = "Frequency"; 
     zedGraphControl1.AxisChange(); 
     zedGraphControl1.Invalidate(); 

現在,我得到的頻域數據,我已經與幅度繪製它ZedGraph在Y軸和頻率對X -軸。 FFT output on ZedGraph

現在我有複雜的數據作爲FFT與我一起,但如何從給定的數據中分離出以下列出的頻率以及如何生成或播放該特定頻率的文件。

  1. 低 - 20Hz到500Hz的
  2. 半山 - 500Hz的4kHz的
  3. 高爲4KHz至20KHz

任何建議或指導,將不勝感激.. !!

回答

0

如果您只是想過濾一個音頻流,那麼您正在採用計算成本較高的方法。 FFT對識別光譜特徵非常有用。但是,如果你想把時間花在頻率和時間上,那就是很多數字處理(你很可能不喜歡你所聽到的)。如果保持當前規定的路徑,則需要在頻域中執行某種形式的掩碼,然後再轉換爲時間。當你回到時間(一個真實的產品)時,它會聽起來很「髒」(你需要實現某種形式的想象到真正的合併)。在你的代碼中,你可以形成一個幅度平方以回到實時系列(注意 - 這會給你一個修正的信號 - 這應該聽起來很嘶啞)。

如果你想隔離一個特定的頻帶,從某種形式的FIR帶通濾波器開始。如果您想在開發過程中聽到結果,請查看如何使用Android AudioTrack類的示例。

+0

我的目的是將這些頻率分開以用於調音臺應用程序(用於執行dj混音)。我已經在c#中嘗試了一些低通和高通濾波器函數,但不知道我在這個濾波器函數後得到的數據是否有效,我也試圖從過濾的數據創建.wav文件,但創建的文件是頭少,不能播放與任何音頻播放器。保存.wav和播放音頻不是我的目標,但需要驗證數據是否有效。我只需要帶有播放位置(基本上是時間域)的過濾數據陣列,這樣我就可以混合兩首歌曲,其中低=>低,中=>中和高=>高。 – Nitin