2016-05-02 27 views
0

私はピアノで演奏する音符を識別するプログラムを作成しようとしていますが、Goertzelフィルタはアルゴリズムを実装するのは簡単ですが使用方法はわかりません。ここで NAudioでC#を使用してピアノノートを検出する

コードです:コードが正しく動作していないが、どのように私はコンソールに書き込みに行う必要があります

using NAudio.Wave; 
using System.Windows; 
using System; 
using System.Collections.Generic; 

namespace WpfTest { 
    public partial class MainWindow : Window { 
     private BufferedWaveProvider buffer; 
     private WaveIn waveIn; 
     private WaveOut waveOut; 
     private const double TargetFreaquency = 261.626;//C4 note 
     private const int SampleRate = 44100; 

     public MainWindow() { 
      InitializeComponent(); 
      InitializeSound(); 
      waveIn.StartRecording(); 
      waveOut.Play(); 
     } 

     private void InitializeSound() { 
      waveIn = new WaveIn(); 
      waveOut = new WaveOut(); 
      buffer = new BufferedWaveProvider(waveIn.WaveFormat); 
      waveIn.DataAvailable += WaveInDataAvailable; 
      waveOut.Init(buffer); 
     } 

     private void WaveInDataAvailable(object sender, WaveInEventArgs e) { 
      buffer.AddSamples(e.Buffer, 0, e.BytesRecorded); 

      var floatBuffer = new List<float>(); 
      for (int index = 0; index < e.BytesRecorded; index += 2) { 
       short sample = (short)((e.Buffer[index + 1] << 8) | 
             e.Buffer[index + 0]); 
       float sample32 = sample/32768f; 
       floatBuffer.Add(sample32); 
      } 

      if (NotePlayed(floatBuffer.ToArray(), e.BytesRecorded)) { 
       Console.WriteLine("You have played C4"); 
      } 
     } 

     private bool NotePlayed(float[] buffer, int end) { 
      double power = GoertzelFilter(buffer, TargetFreaquency, buffer.Length); 
      if (power > 500) return true; 
      return false; 
     } 

     private double GoertzelFilter(float[] samples, double targetFreaquency, int end) { 
      double sPrev = 0.0; 
      double sPrev2 = 0.0; 
      int i; 
      double normalizedfreq = targetFreaquency/SampleRate; 
      double coeff = 2 * Math.Cos(2 * Math.PI * normalizedfreq); 
      for (i = 0; i < end; i++) { 
       double s = samples[i] + coeff * sPrev - sPrev2; 
       sPrev2 = sPrev; 
       sPrev = s; 
      } 
      double power = sPrev2 * sPrev2 + sPrev * sPrev - coeff * sPrev * sPrev2; 
      return power; 
     } 
    } 
} 

:私はマイクにC4のノートを演奏するたびに、「あなたはC4を果たしてきましたか」?

+1

ようこそ!私はあなたの質問は、あなたが実際に助けを必要としているかどうか少し不明であると思います。 You'rコードは_ "あなたはC4を演奏しました" _ので、何か問題があるか、またはこれらのメソッドを呼び出す方法について助けが必要なので、これらのメソッドの助けが必要ですか? – Binke

+0

こんにちは、ありがとう!どこかでエラーがあったので、私はこの方法の助けが必要でした。私はすでにこの質問に答えましたが、私は将来もっと明確にしようとします。 –

答えて

1

マイク入力が44100Hzの16ビットPCMサンプルであると仮定しているようです。それは必ずしもそうではありません。

private void InitializeSound() 
{ 
    waveIn = new WaveIn(); 

    // Add this here to see what the waveIn default format is. 
    // Step through this line in the debugger. If this isn't 
    // 44100Hz sampling rate, 16-bit PCM, 1-channel, then that's 
    // probably what's going wrong. 
    WaveFormat checkformat = waveIn.WaveFormat; 

    // Note that these are the default values if we used the 
    // parameterless WaveFormat constructor, but just expanding 
    // here to show that we're forcing the input to what you're 
    // expecting: 
    WaveFormat myformat = new WaveFormat(44100, 16, 2); 
    waveIn.WaveFormat = myformat; 
    SampleRate = myformat.SampleRate; 

    waveIn.DataAvailable += WaveInDataAvailable; 

    waveOut = new WaveOut(); 
    buffer = new BufferedWaveProvider(waveIn.WaveFormat); 
    waveOut.Init(buffer); 
} 

は、私はあなたがfloatshortを変換しているエンディアンにはわからない:次のように、「デフォルト」のマイク・フォーマットを確認し、だけでなく、あなたが期待しているものにそれを強制することができますあなたのイベントハンドラ(私は老いていて、もうどちらが終了するか覚えていません:))、それも問題になるかもしれません。あなたは、おそらくかなりシフト/あなたが今やっていることを追加するよりも、それを行うためにBitConverter.ToInt16を使用したほうが良いでしょう:

private void WaveInDataAvailable(object sender, WaveInEventArgs e) 
{ 
    buffer.AddSamples(e.Buffer, 0, e.BytesRecorded); 

    var floatBuffer = new List<float>(); 
    for (int index = 0; index < e.BytesRecorded; index += 2) 
    { 
     short sample = BitConvert.ToInt16(e.Buffer, index); 
     float sample32 = (float)sample; 
     sample32 /= (float)Int16.MaxValue; 
     floatBuffer.Add(sample32); 
    } 

    if (NotePlayed(floatBuffer.ToArray(), e.BytesRecorded)) 
    { 
     Console.WriteLine("You have played C4"); 
    } 
} 

またNotePlayedendパラメータのように見えることは、実際に良いである、未使用です! endパラメータの意味を推測すると、e.BytesRecordedはサンプルカウントではないため、正しい値ではありません。

+0

ご協力いただきありがとうございます!私はあなたが言ったように、それがうまくいきました。問題はデフォルトのサンプルレートが8000 Hzで、44100 Hzではないということでした。 私はC4ノートを演奏するたびに、「あなたはC4を演奏しました」という行をコンソールに書いていますが、私が演奏したノートはしばらく共鳴しているので、これは普通だと思います。 もう一度、迅速かつ完全な回答をいただき、ありがとうございます。 –

+0

私は助けてくれると嬉しかったです:)そうですね、文字列が何度か見えるでしょう。私は、メモが消える前に生成された 'DataAvailable'イベントごとに1回疑います。 –

関連する問題