2013-04-08 5 views
2

내가해야할 것은 마이크 입력의 주파수를 계산하는 것입니다. 나는 이것을 IWaveProviderRead()으로 구현했습니다. 버퍼는 항상 8820 요소의 크기를 가지며 뭔가 바이트 배열에서 float 배열로의 변환도 잘못 될 수 있습니다 (FloatBuffer 속성 부분). DataAvailable 이벤트 핸들러가 다음 실행이라고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(); 
} 

:

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() 인 것을 확인하면 완전히 0입니다. 모든 요소.

호기심에서 벗어난 이유는 무엇입니까? Read()에는 버퍼 매개 변수가 있지만 실제로 메서드에서 전혀 사용되지 않습니다 (기사에서 해당 코드를 얻었습니다)?

이 문제를 해결할 수있는 도움이 있으면 대단히 감사하겠습니다. 나는 이미 이것에 대해 꽤 오래 있었지만 아무런 의미가 없다.

감사합니다, 알랭

+0

처럼 사용할 수 있을까? – Jodrell

+0

마크 히스 (Mark Heath) - NAudio의 기사 중 하나입니다. – Alain

답변

0

당신이 언급하는 내가이 라이브러리에 익숙하지 않은 누구인지 기사 명확하지 않다. 그러나 Read 방법은 '시계열'/ 또는 다른 데이터를 분명히 읽는 것입니다. 이로부터 말하는 매개 변수 buffer은 데이터 세트의 양쪽 끝에 배치 할 패딩 길이가 될 가능성이 큽니다.

이 패딩은 '제로 패딩'으로 알려져 있으며 녹음 된 신호를 0으로 채 웁니다 (신호의 양쪽 끝에 n 개의 0을 입력합니다. 여기서 n은 사용 된 기수에 따라 설정 됨). 이것은 더 긴 FFT를 사용하게하여 더 긴 FFT 결과 벡터를 생성합니다.

더 긴 FFT 결과에는 주파수가보다 근접한 더 많은 주파수 빈이 있습니다. 그러나 원래의 데이터의 0이 아닌 패딩 된 짧은 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>();