こんな目にあっても続けることができる…
vector
推定3時間ほどかかって見つかった原因はこれ。
void DSound::playBGM(const std::vector<BYTE> &src) { // いろいろ shared_ptr<IDirectSoundBuffer8> pBuffer(ptmp8, iunknown_deleter()); // バッファへの書き込みなど DSoundError::check(pBuffer->Play(0, 0, DSBPLAY_LOOPING)); }
わからない?C++の「}」の力を侮るな。
pBuffer->Play();
// ここでpBufferがデストラクト
}
もっと書き下してしまえばこう。
pBuffer->Play(); pBuffer->Release(); }
再生を始めた直後に即解放っ…!そこまでの関数呼び出しは全部S_OK(成功)返してるしPlay()の後でGetStatusしてもPLAYING返ってくるし。どんな検証コードを書いてもそのあとに来る「}」が停止させてしまう…!スマートポインタとデストラクタ、恐ろしや。
DSoundError::check(pBuffer->Play(0, 0, DSBPLAY_LOOPING)); m_pbgmbuf = pBuffer; }
メンバ変数に代入したら全て解決しました。よく覚えてないけど推定3時間。
追記:ということで、バッファを半分に区切って再生カーソルが後半部分に入ったら前半部分に次のデータを書き込む的なストリーミングが完成しました。バッファサイズを小さくしすぎるとウィンドウをがちゃがちゃ動かしたりして毎フレのチェックが甘くなった時に同じ部分を繰り返したりしておかしくなるみたい。ただ、大きくしすぎると一度に行うデコード量が増えて一定周期で重くなるという現象に見舞われるでしょう。適当に要調整。
ウィンドウを非アクティブにすると音声がストップするので気になって(なんというかBGM鳴りっぱなしのソフトが多いような…)調べたところ、IDirectSound8::CreateSoundBufferするときの設定、DSBUFFERDESC構造体のdwFlagsメンバにDSBCAPS_GLOBALFOCUSを設定するといいみたい。ついでにIDirectSoundBuffer8::GetCurrentPositionで次のデータの書き込みタイミングを制御してるのでDSBCAPS_GETCURRENTPOSITION2も入れておく。「エミュレートされたサウンドカード」に対してのみ効果があるらしいけどヘルプを読む限り一応。SE*1の方のバッファはいいや。
生のPCM*2のバイト列を素手で触りながら書いたプログラムで再生する不思議の国のアリスは格別だぜ……。ウィンドウをバックグラウンドにしても聞こえるようにしたし。BGMなんか非圧縮じゃあ大きすぎるしもっと高レベルなAPIにシフトしていくくさい。XNAかなんか的な意味で(多分)。過激派が暴れだしてもしょうがないからどっちとは言わないけどDirectSoundはDirectXの中でも最もDirectな気がするなあ。