ホーム < ゲームつくろー! < Ogg Vorbis入門編

その8 音が終わったことを通知する


 Ogg Vorbisを扱うクラスをここまで作成してきて、再生や停止が可能になりました。ところで、ループせずに1回きりの再生をした場合、現在の実装だと無音が返り続けています。これは多重再生をしている間も裏で再生スレッドが回り続けているためです。スレッド自体はSleepが入っているため負荷はとても軽いのですが、再生中であるためセカンダリバッファに対して意味の無いメモリコピーが発生しています。これは大きな無駄です。また、音を鳴らしている側からすると「音が終わったら知らせて欲しい」はずです。

 そこで、この章ではループ再生で無い場合に音が鳴り終わったら再生をやめて停止状態にし、再生終了を知らせるフラグを立てるようにクラスを拡張します。



@ IDirectSoundNotify8で通知したいのですが・・・

 DirectSoundには「IDirectSoundNotify8」というインターフェイスが用意されています。このインターフェイスはセカンダリバッファのある位置を指定し、その位置に音が来た時に通知をしてくれます。通知はWindows APIのイベントハンドルで知らせてくれます。

 これは非常にありがたい機能なのですが、実はストリーム再生の終了を知らせるために使う時にはちょっと面倒があります。それはイベントハンドルをIDirectSoundNotify8に設定する条件として「再生していない時」である必要があるためです。しかしストリーム再生中はセカンダリバッファを使いまわしており、指定位置に何度も音がやってきます。その度に通知フラグが立ってしまうんです。

 もう1つの問題。それは「音のサイズ」です。Ogg Vorbisは音をデコードしながらストリーム再生します。そのため終了位置までのサイズがわからないんです。これがわからないと終了位置を特定できません。Oggのストリーム再生とIDirectSoundNotify8との相性は良くないようです。

 そこで、正確ではありませんが終了通知を自前で実装する事にします。



A ストリームの最後のメモリコピー

 前章まで作ってきたPCMDecoderクラスのgetSegmentメソッドにはストリームの最後のメモリコピーを通知する仕組みがあります。第4引数にbool型の変数を渡すと、最後のメモリコピーだった場合にtrueが返ってきます(そう実装しました)。これが起こる状況というのは次のような場合です:

現在再生中のバッファに対してその反対側のバッファに最後の音がコピーされます。再生中でも現在の再生位置は取得でき、終了時のバッファコピーサイズもgetSegmentの第3引数から得ることが可能(そう実装しておいて良かった(^-^;)なので、この時点で終了位置は完全に把握できます。ですから、再生ヘッドが終了位置を通過した状態を感知して「終了宣言」とする事が可能です。



 非ループ時に停止処理に遷移するように改良したOgg Vorbisクラスを使ったサンプルプログラムはこちらです。今回はソースが無いというちょっと珍しい章になりました(^-^;。