2013-04-08 82 views
2

我需要做的是計算麥克風輸入的頻率。我正在使用IWaveProvider進行此操作,並已執行Read()。緩衝區總是有8820個元素的大小,而且從字節數組到float數組的轉換也是錯誤的(FloatBuffer屬性部分)。C#頻率檢索

下面是一些重要的位......

這是我開始我的錄音:

private void InitializeSoundRecording() 
{ 
    WaveIn waveIn = new WaveIn(); 
    waveIn.DeviceNumber = 0; 
    waveIn.DataAvailable += (s, e) => this.waveIn_DataAvailable(s, e); 
    waveIn.RecordingStopped += (s, e) => this.waveIn_RecordingStopped(s, e); 
    waveIn.WaveFormat = new WaveFormat(44100, 1); 
    waveIn.StartRecording(); 
} 

當DataAvailable事件處理程序被調用,執行以下操作:

private void waveIn_DataAvailable(object sender, WaveInEventArgs e) 
{ 
    WaveBuffer wb = new WaveBuffer(e.Buffer.Length); 

    IWaveProvider iWaveProvider = new PitchDetector(new WaveInProvider(sender as WaveIn), new WaveBuffer(e.Buffer)); 
    iWaveProvider.Read(wb, 0, e.Buffer.Length); 

    PitchDetector pd = iWaveProvider as PitchDetector; 

    this.ShowPitch(pd.Pitch); 
} 

最後,這是「實際」重要位:

private const int FLOAT_BUFFER_SIZE = 8820; 
private IWaveProvider source; 
private WaveBuffer waveBuffer; 
private int sampleRate; 
private float[] fftBuffer; 
private float[] prevBuffer; 
public float Pitch { get; private set; } 

public WaveFormat WaveFormat { get { return this.source.WaveFormat; } } 

internal PitchDetector(IWaveProvider waveProvider, WaveBuffer waveBuffer = null) 
{ 
    this.source = waveProvider; 
    this.sampleRate = waveProvider.WaveFormat.SampleRate; 
    this.waveBuffer = waveBuffer; 
} 

/// <summary> 
/// UNSAFE METHOD! 
/// </summary> 
/// <param name="input"></param> 
/// <returns></returns> 
private unsafe float[] ByteArrayToFloatArray(byte[] input) 
{ 
    float[] fb = new float[FLOAT_BUFFER_SIZE]; 
    unsafe 
    { 
     fixed (byte* ptrBuffer = input) 
     { 
      float* ptrFloatBuffer = (float*)ptrBuffer; 
      for (int i = 0; i < FLOAT_BUFFER_SIZE; i++) 
      { 
       fb[i] = *ptrFloatBuffer; 
       ptrFloatBuffer++; 
      } 
     } 
    } 
    return fb; 
} 

public int Read(byte[] buffer, int offset = 0, int count = 0) 
{ 
    if (this.waveBuffer == null || this.waveBuffer.MaxSize < count) 
     this.waveBuffer = new WaveBuffer(count); 

    int readBytes = this.source.Read(this.waveBuffer, 0, count); 

    if (readBytes > 0) readBytes = count; 

    int frames = readBytes/sizeof(float); 

    this.Pitch = this.DeterminePitch(this.waveBuffer.FloatBuffer, frames); 

    return frames * 4; 
} 

奇怪的是,當它進入構造函數時,waveBuffer包含一些數據(255,1,0等),但是當我檢查Read()的「buffer」參數時,它完全是0.每個元素。

出於好奇,爲什麼Read()有一個緩衝參數,但實際上並沒有在方法中使用(我從你的一篇文章中獲得了那段代碼)?

任何幫助解決這個問題將不勝感激!我已經在這方面已經有一段時間了,但是沒有任何意義。

感謝, 阿蘭

+0

,其文章的一個? – Jodrell 2013-04-08 08:02:52

+0

請原諒我,Mark Heath的一位 - 來自NAudio的文章。 – Alain 2013-04-08 08:13:54

回答

0

目前尚不清楚你是指什麼文章,我不熟悉這個庫。然而,Read方法顯然是讀取您的'時間序列'/或其他數據。因此,您所說的buffer參數可能是您希望放置在數據集兩端的填充長度。

該填充稱爲「零填充」,它用零填充記錄的信號(在信號的任一端放置n個零,其中n根據所用的基數設置)。這允許使用更長的FFT,這將產生更長的FFT結果向量。

較長的FFT結果具有更多頻率間隔更近的頻率點。但它們本質上會提供與原始數據的較短非零填充FFT的高質量Sinc插值相同的結果。

當沒有進一步插值繪圖時,這可能會導致看起來更平滑的光譜。

對於進一步形成看

https://dsp.stackexchange.com/questions/741/why-should-i-zero-pad-a-signal-before-taking-the-fourier-transform

我希望這有助於。

0

這不是真的回答你的問題,但我寫了safe泛型替代你的數組轉換函數。

using System; 
using System.Runtime.InteropServices; 

public static class Extensions 
{ 
    public staitc TDestination[] Transform<TSource, TDestination>(
     this TSource[] source) 
     where TSource : struct 
     where TDestination : struct 
    { 
     if (source.Length == 0) 
     { 
      return new TDestination[0]; 
     } 

     var sourceSize = Marshal.SizeOf(typeof(TSource)); 
     var destinationSize = Marshal.SizeOf(typeof(TDestination)); 

     var byteLength = source.Length * sourceSize; 

     int remainder; 
     var destinationLength = Math.DivRem(
      byteLength, 
      destinationSize, 
      out remainder); 
     if (remainder > 0) 
     { 
      destinationLength++; 
     } 

     var destination = new TDestination[destinationLength]; 
     Buffer.BlockCopy(source, 0, destination, 0, byteLength); 
     return destination; 
    } 
} 

這顯然,你可以使用像

var bytes = new byte[] { 1, 1, 2, 3, 5, 8, 13, 21 }; 
var floats = bytes.Transform<byte, float>();