2012-11-15 2 views
4

저는 C# 4.0/WPF 실시간 스펙트럼 분석기 (다른 프로젝트의 기본)로 작업 중입니다. 저는 사운드 카드에서 실시간 오디오 출력을 얻으려면 NAudio 마지막 버전을 사용하고, 스펙트럼 분석기 WPF 컨트롤에서는 WPFSoundVisualizationLib (http://wpfsvl.codeplex.com/)을 사용합니다. 이 놀라운 도구를 사용하면 작업이 거의 끝나지만 제대로 작동하지 않습니다 .-(NAudio & WPFSoundVisualizationLib가있는 스펙트럼 분석기

기능 스펙트럼이 있지만 정보가 권리가 아니며 문제의 출처를 이해할 수 없습니다. . 이것은 내 메인 클래스

이다 (나는 Equalify, 스포티 파이의 스펙트럼/이퀄라이저 내 스펙트럼을 비교, 그리고 나도 같은 행동을하지 않음) :

using System; 
using System.Windows; 
using WPFSoundVisualizationLib; 

namespace MySpectrumAnalyser 
{ 
    public partial class MainWindow : Window 
    { 
     private RealTimePlayback _playback; 
     private bool _record; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      this.Topmost = true; 
      this.Closing += MainWindow_Closing; 
      this.spectrum.FFTComplexity = FFTDataSize.FFT2048; 
      this.spectrum.RefreshInterval = 60; 
     } 

     private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
     { 
      if (this._record) 
      { 
       this._playback.Stop(); 
      } 
     } 

     private void Button_Click_1(object sender, RoutedEventArgs e) 
     { 
      if (this._playback == null) 
      { 
       this._playback = new RealTimePlayback(); 
       this.spectrum.RegisterSoundPlayer(this._playback); 
      } 

      if (!this._record) 
      { 
       this._playback.Start(); 
       this.Dispatcher.Invoke(new Action(delegate 
       { 
        this.btnRecord.Content = "Stop"; 
       })); 
      } 
      else 
      { 
       this._playback.Stop(); 
       this.Dispatcher.Invoke(new Action(delegate 
       { 
        this.btnRecord.Content = "Start"; 
       })); 
      } 

      this._record = !this._record; 
     } 
    } 
} 

그리고 내 루프백 분석기는 (이 WPFSoundVisualizationLib Spectrum 컨트롤과 함께 사용하기 위해 ISpectrumPlayer를 구현합니다.)

LoopbackCapture는 NAudio.CoreAudioApi.WasapiCapture를 상속받습니다. WASAPI에서

수신 된 데이터는 (32 비트 PCM, 44.1kHz의 2 개 채널, 샘플 당 32 비트)

using NAudio.Dsp; 
using NAudio.Wave; 
using System; 
using WPFSoundVisualizationLib; 

namespace MySpectrumAnalyser 
{ 
    public class RealTimePlayback : ISpectrumPlayer 
    { 
     private LoopbackCapture _capture; 
     private object _lock; 
     private int _fftPos; 
     private int _fftLength; 
     private Complex[] _fftBuffer; 
     private float[] _lastFftBuffer; 
     private bool _fftBufferAvailable; 
     private int _m; 

     public RealTimePlayback() 
     { 
      this._lock = new object(); 

      this._capture = new LoopbackCapture(); 
      this._capture.DataAvailable += this.DataAvailable; 

      this._m = (int)Math.Log(this._fftLength, 2.0); 
      this._fftLength = 2048; // 44.1kHz. 
      this._fftBuffer = new Complex[this._fftLength]; 
      this._lastFftBuffer = new float[this._fftLength]; 
     } 

     public WaveFormat Format 
     { 
      get 
      { 
       return this._capture.WaveFormat; 
      } 
     } 

     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] = BitConverter.ToSingle(array, i * 4); 
      } 

      return floatArr; 
     } 

     private void DataAvailable(object sender, WaveInEventArgs e) 
     { 
      // Convert byte[] to float[]. 
      float[] data = ConvertByteToFloat(e.Buffer, e.BytesRecorded); 

      // For all data. Skip right channel on stereo (i += this.Format.Channels). 
      for (int i = 0; i < data.Length; i += this.Format.Channels) 
      { 
       this._fftBuffer[_fftPos].X = (float)(data[i] * FastFourierTransform.HannWindow(_fftPos, _fftLength)); 
       this._fftBuffer[_fftPos].Y = 0; 
       this._fftPos++; 

       if (this._fftPos >= this._fftLength) 
       { 
        this._fftPos = 0; 

        // NAudio FFT implementation. 
        FastFourierTransform.FFT(true, this._m, this._fftBuffer); 

        // Copy to buffer. 
        lock (this._lock) 
        { 
         for (int c = 0; c < this._fftLength; c++) 
         { 
          this._lastFftBuffer[c] = this._fftBuffer[c].X; 
         } 

         this._fftBufferAvailable = true; 
        } 
       } 
      } 
     } 

     public void Start() 
     { 
      this._capture.StartRecording(); 
     } 

     public void Stop() 
     { 
      this._capture.StopRecording(); 
     } 

     public bool GetFFTData(float[] fftDataBuffer) 
     { 
      lock (this._lock) 
      { 
       // Use last available buffer. 
       if (this._fftBufferAvailable) 
       { 
        this._lastFftBuffer.CopyTo(fftDataBuffer, 0); 
        this._fftBufferAvailable = false; 
        return true; 
       } 
       else 
       { 
        return false; 
       } 
      } 
     } 

     public int GetFFTFrequencyIndex(int frequency) 
     { 
      int index = (int)(frequency/(this.Format.SampleRate/this._fftLength/this.Format.Channels)); 
      return index; 
     } 

     public bool IsPlaying 
     { 
      get { return true; } 
     } 

     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 
    } 
} 

GetFFTData은 WPF에 의해 호출되는 스펙트럼을 갱신마다 60ms 제어 바이트 배열이다.

+0

무엇이 작동하지 않습니까? 오류 메시지가 있습니까? 그렇다면 어디서 발생합니까? 오류를 자세히 설명해야합니다. –

+0

당신은 실제로 당신이 얻었거나 당신이 도울 수있을 것이라고 예상했던 것을 말할 필요가 있습니다. –

+0

'float'로 변환하기 전에 데이터의 유형을 알고 계십니까? 이미 'float'이 아닌 경우 변환 기능이 작동하는지 모르겠습니다. –

답변

0

은 들어오는 웨이브 형식입니다. IEEE float입니까? 32 비트 정수라면 어떨까요?

나는 이것이 내가 (플로트에 캐스트)를 INT32 배열 내 바이트 배열로 변환하려고했습니다 MSDN Here

설명되지 않지만, 결과는 최악입니다 ... 그것이 IEEE 부동 소수점 같아요 :

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; 
} 
0

another question에 코드를 사용하여 작동하는 스펙트럼 분석기가 있습니다. 매우 원유 버전이지만 사소한 수정으로 사용할 수 있습니다.

실제로 코드에 어떤 문제가 있는지 알 수 없지만 최소한 제공된 코드는 저에게 효과적입니다. 문제는 여전히 스펙트럼을 잘못 사용하는 경우 다른 곳에서 발생합니다.

2

나는이 답변에 조금 늦을 지 모르지만 여기 있습니다.

거의 다 왔어. FFT가 X 값 대신에 리턴하는 복소수의 진폭을 제공하면됩니다.

그래서 for 루프에서, 대신의 :

this._lastFftBuffer[c] = this._fftBuffer[c].X; 

이 작업을 수행 :

float amplitude = (float)Math.Sqrt(this._fftBuffer[c].X * this._fftBuffer[c].X + this._fftBuffer[c].Y * this._fftBuffer[c].Y); 
this._lastFftBuffer[c] = amplitude; 

건배!