CaptureSound Managed その5

真ん中の画面について、  どうも、48KHzでのサンプリングも、可能らしい...

DirectX9.0 sample CaptureSoundでは、

このサンプリング周波数で、実際に、captureBufferを、わざわざ作って、判定しているのですから.....

1. Notifyを調べる

「オーディオをキャプチャする場合、読み込みカーソルがバッファ内のあるポイントに到達したときや、

バッファが停止したときに、アプリケーションに通知したいことがある。Notify.SetNotificationPositions メソッドを使うと、

イベントのシグナルを送信するポイントをバッファ内にいくつでも設定できる。ただし、バッファがキャプチャを行っている間は、

イベント ポイントの設定を行うことはできない。」 Japan MSDN

このNotifyは、実は、オーディオを再生する secondaryBufferにも、設定できます。

前節で調べた、AutoResetEventを、Notifyに登録し、CaptureBufferに、Notifyを関連させておいて

読み込みカーソルがバッファ内のあるポイントに到達したときや、

バッファが停止したときに、アプリケーションに通知」。

別スレッドで、NotificationEvent.WaitOne(Timeout.Infinite, true)を使って、waitさせたスレッドに、通知するのです。

2. 具体的に、Notifyさせる

「通知を設定するには、次のステップを実行する。

  1. それぞれの通知位置に対して AutoResetEvent を作成する。
  2. Notify コンストラクタに CaptureBuffer オブジェクトを渡して、Notify オブジェクトを取得する。
  3. それぞれの通知位置に 1 つずつ、BufferPositionNotify 構造体の配列を作成する。Offset メンバに、通知を発生させる場所のバイト オフセットを設定する。EventNotifyHandle メンバに、ステップ 1 で作成したいずれかのイベントの AutoResetEvent.Handle を設定する。
  4. Notify.SetNotificationPositions を呼び出して、BufferPositionNotify 構造体の配列を渡す。

 

以上を行えば、別のスレッドでバッファを開始し、WaitHandle.WaitAny を使って通知を待機することができる。」Japan MSDN

これを、忠実に、実行しましょう。

void InitNotifications()

    {

    if (null == captureBuffer)

    throw new NullReferenceException();

    //Notificationsを待つ、スレッドを作成する。

    NotifyThread=new Thread(new ThreadStart(WaitThread));

    NotifyThread.Start();

    //通知を設定するには、次のステップを実行する。

    //1.それぞれの通知位置に対してAutoResetEvent を作成する。

        NotificationEvent=new AutoResetEvent(false);

        //2.Notify コンストラクタにCaptureBuffer オブジェクトを渡して、Notify オブジェクトを取得する。

        applicationNotify=new Notify(captureBuffer);

    //3.それぞれの通知位置に1 つずつ、BufferPositionNotify 構造体の配列を作成する。

    // Offset メンバに、通知を発生させる場所のバイトオフセットを設定する。

    //4.EventNotifyHandle メンバに、ステップ1 で作成したいずれかのイベントの

    // AutoResetEvent.Handle を設定する。

        for(int i=0;i< NumberRecordNotifications;i++)

        {

            PositionNotify[i].Offset=NotifySize*(i+1)-1;     // -1しなくて、よいのか?しないと、SetNotificationPosition()できない.....

            PositionNotify[i].EventNotifyHandle=NotificationEvent.Handle;

        }

    //5.Notify.SetNotificationPositions を呼び出して、BufferPositionNotify 構造体の配列を渡す。

        applicationNotify.SetNotificationPositions(PositionNotify,NumberRecordNotifications);

    }

}

青色の部分なんですが、マイナス1しないと、

        applicationNotify.SetNotificationPositions(PositionNotify,NumberRecordNotifications);

の部分で、exceptionが発生するのです。

Notifyの最後の位置、つまり、bufferの終端は、Notify不可能なのです。(らしい...)

従って、これの値を、マイナス1しておきます。(だから、後で、プラス1しないと、いかん....Notifyだけを使うなら。)

一方、sampleのCaptureSoundのプログラムでは、Notifyしているにも拘わらず、GetCurrentPositionメソッドを使っているのです。

Notifyすれば、capturebufferから読み込む位置は、明らかに、決定されているのに

何故、GetCurrentPositionメソッドを使っているのか、調べてみたのです。

よく解らんけど、恐らく、

    Notifyを使わないで、残りの部分を、recordingする時(つまり、ボタンで停止させた時)にも、このメソッド void RecordCapturedData()

を使っていますので、兼用したためと、思われます。リアルタイム性は、要求されませんので。

私は、Notifyを使ってrecordingする時と、そうでなくて、ボタンで停止させて、残りの部分をrecordingする時と、

分けて作ってみようと、思います。

このsample、 CaptureSoundを、お書きになった先輩は、大いに尊敬し、感謝いたしておりますが(教育的配慮が、たっぷりです、御礼。)

やはり、丸写しでは、失礼にあたるし、私も、さっぱり、楽しくありませぬ故。

H.18.7.4