ストリーミング再生を考える

DXRubyではサポートしていないが、DirectSoundにはストリーミング再生というものがある。
サウンドバッファをループバッファとして確保し、再生しながら再生し終わった部分をロック、書き換えという荒業を行う機能だ。
ゲームで使いそうな効果音でDXRubyがサポートしていない機能の1つに、レースゲームのエンジン音がある。
そのときの速度によって周波数を動的に変動する必要がある。
これは、たとえばwavファイルの音をループさせて、再生速度を変えるなどで対応することができるが、DXRubyではそれすらもできないから、現時点では不可能である。
まあ、やるならどっちでもいいのだが、今回はストリーミング再生を考える、ということで、そっちの可能性を検討してみよう。


リアルタイムでSoundEffectオブジェクトを生成し、stop、playを乱発したらできるんじゃないか、とか思ってためしてみたところ、音の再生と停止のタイミングでノイズがのって、音が鳴るどころではなかった。
1フレーム(16.6ms)だけ音を再生、というのはかなり無理のある操作のようだ。
これをストリーミング再生で実現しようとすると、現在再生しているバッファのカーソル位置から、直後をロックして書き換える必要がある。
ロックして書き換え中にその位置が再生に突入してしまうと大変なことになるから、ある程度先の時間にしないといけないだろうが、再生速度とバッファの書き換え時間に依存してしまい、再生速度は一定なのに書き換え速度はPCの速度によるから、ギリギリの設定は無理がある。
基本的には1フレーム分だけ先のデータを書き換える、って感じで、割と安全なのではないかという気がする。
書き換え量については、DXRubyの処理落ち対策は描画のみで、Rubyのロジックは1/60秒単位で動くから、これもやっぱり1フレーム分だけ書き換えるようにすればいい。
もしRubyの処理だけでも1フレーム内に終わらないようでは、そもそもゲームはまともに動かないレベルだからだ。
ただ、GCが動いた場合とか、別のプロセスのせいで重くなったりとか、そういう場合にどうなるのかというと、ちょっと怪しい。書き換え量を2フレーム分に増やせばいいかと言うと、単純にそういう話でもなさそうだ。
やはり、こういうのはライブラリでサポートするとはいえ、Rubyから基本的に制御しようとする時点で、リアルタイムに制御するのは難があるのだろう。
つってもRuby用拡張ライブラリだから、Rubyから制御じゃなくても実行タイミングはRubyの実行に依存してしまうわけで、もうちょっとよく考えて設計しないとあかんかもしれない。
DirectXのヘルプでストリーミング再生の仕組みを見たときに、これは何かできるかもしれない!って思ったが、Rubyが絡むとやっぱりこれも簡単ではない。