DirectSoundモード時のサウンド読み込み高速化
本件についてタレコミをいただきました。まずチケットだけ発行させて頂きます。
Clone()を止めた経緯についても、覚えている範囲でチケット詳細に記載いたしました。
ただ、私は今週の平日は対応時間が取れません。早くて週末からの調査着手となります。すみません。
多分、サウンドデータの実体を持っているかどうかで、dispose の仕方を少し変えないといけないけれど、そうなってない、といったとことかな、とは思います。
そして、そうしていないからdispose で例外が出て、それを避けるために管理リストに登録せず、その結果開放されずリークする、かな。
すみません。あとは後日。
あれ、意外と難しいぞ、これ。
まずメモリリークする原因は上述の通りでした。こんなつまらないバグを残しておくな(表面化しないように蓋をしておくな)よという感じではありますが、曲演奏終了時にサウンドデータを一斉廃棄するところ、廃棄してない。なぜ廃棄してないかというと、実体/参照問わずに破棄するロジックだったから、実体を先に破棄すると、参照の破棄のところで例外発生する。それを嫌って破棄をしない(ようにするために管理リストに登録してない)。
対策としては、参照の破棄時にバッファの実体を破棄しなければいいのだけど、とすると、実体だけ破棄して参照が残る状況の時にどうするか?実体を残しておかないといけないが、そのまま放っておくと参照が全部なくなっても実体が残り、結果としてメモリリークすることに変わりはない(このレベルのリークなら、GCが回収してくれそうではあるけど)。
んー、参照カウンタを導入するしかないかなぁ。
おつですー。
Vista のサポートも終わったことですし、DirectSoundへの対応も廃止してしまってもよいのでは?とか思ったり。
fromさん
お疲れ様です。出張から戻りました。
さて、DirectSound対応廃止の件、私もそうしたいところです。
代わりにWASAPI共有にちゃんと対応しようと思って、feature/wasapi_shared_win10 なるブランチを作りました。
うちの環境 (Roland DUO CAPTURE: USB Audioです悪しからず) の場合、バッファサイズが22msと、WASAPI排他時の32msより小さい値が出てくるんですが、実際の出音の反応はどうみても排他のほうが良いです。
やっぱし、オンマザーのRealtekのHD Audioでの動作確認から始めたほうがいいですかね。(DUO CAPTUREは小遅延のドライバサポートが入ってなさそうな気がするし・・・)
うちのRealtek HD Audio は、共有で10msですよ。
最新のWin10でのWASAPI共有モードは10ms保証だった……気がしましたが、違ったんですかね?
以下、ログから抜粋。おっしゃる通り、10msでいけると返ってくるんですよ。
しかし、それで BassWasapi.BASS_WASAPI_Init() すると、バッファを22ms分確保してやったぜ感謝しな、と返ってきて、実際に演奏させると体感でDirectSoundと同程度のバッファ量がある感じ。
まあ、BassNetのヘルプにも、共有モードではバッファ量を手動設定できないぜと確かに書いてあるのですが、ならば10msを使ってくれよと。
Win10のLow Latencyな設定を正しく叩いてあげないといけない予感がしています。その辺、Bassで制御できるのかどうか、何とも言えませんが。
ログ抜粋
WASAPIデバイス一覧: WASAPI Device #8: スピーカー (High Definition Audio デバイス): IsDefault=True, defPeriod=0.01s, minperiod=0.0026667s, mixchans=2, mixfreq=48000 : 使用デバイス: #8 : スピーカー (High Definition Audio デバイス), flags=BASS_DEVICE_ENABLED, BASS_DEVICE_DEFAULT BASS を初期化しました。(WASAPI共有モード, 48000Hz, 2ch, フォーマット:BASS_WASAPI_FORMAT_FLOAT, バッファ8448bytes [22ms(希望1ms)], 更新間隔2ms, イベント動作=True)
うわ
うちでも22msになってる……
BASSですか?BASSの仕様なのですか?
WASAPI Device #10: スピーカー (USB Audio DAC ): IsDefault=True, defPeriod=0.01s, minperiod=0.003s, mixchans=2, mixfreq=48000 使用デバイス: #10 : スピーカー (USB Audio DAC ), flags=BASS_DEVICE_ENABLED, BASS_DEVICE_DEFAULT BASS を初期化しました。(WASAPI共有モード, 48000Hz, 2ch, フォーマット:BASS_WASAPI_FORMAT_FLOAT, バッファ8448bytes [22ms(希望10ms)], 更新間隔3ms, イベント動作=True)
なお
USB Audio とありますがこれはただの DAC なので、ちゃんと10ms出ることをSSTで確認済みです。
Low Latency Audio (MSDN) - https://docs.microsoft.com/ja-jp/windows-hardware/drivers/audio/low-latency-audio
によると、
The above functionality is provided by a new interface, called IAudioClient3
とあるので、やっぱり低遅延に対応した新しいAPI (IAudioClient3) を使わないといけないようです。
BASSライブラリは(未だにVista対応を謳っているせいか)、まだ対応していないようですね。
SSTで使ってるCSCoreのソースを見てみたら、IAudioClient3 は使ってませんでした。
でもバッファサイズは共有モードで1056byte(2.75ms)でした。
うむ。わからん。
はい、そのようですね。また、BASSWASAPIのリリメモも確認しましたが、最終更新が2015年2月であり、Win10の発売がその後でしたから、Win10の新I/Fに対応しているはずがないです。(そろそろWin10の発売から2年が経ちますけどね・・・)
# でも、22msって返しておいて、体感が80~100msくらいなのは何とかならんのか…
・・・なお、元のメモリリークの対策については、サウンドファイル名の連想配列で参照カウントを作ることで対策しようと思います。
SSTで使ってるCSCoreのソースを見てみたら、IAudioClient3 は使ってませんでした。 でもバッファサイズは共有モードで1056byte(2.75ms)でした。
ちょっと待て
・・・もう少しいろいろと試してみます。はぁ・・
バッファサイズは共有モードで1056byte
すみませんうそかましてました
IAudioClient::GetBufferSize() の戻り値は byte じゃなくて frame でした。
よって、CSCore でもバッファサイズは 1056frame÷48000frame/sec = 0.022sec(22ms)ということになります。m(_ _)m
情報ありがとうございました。安心?しました。
では参照カウンタの実装に戻ります・・・が、現在なぜかこれを入れるとDirectSoundなSoundDeviceのDisposeに失敗するわ、メモリリークは相変わらず発生しているわで、一体何のために実装したんだか状態。あーもう。今日はもう寝るか・・
気づいてみれば、メモリリークの原因は、もんのすごいポカミスにありました。もうやだ。
さっそく修正して、pushして、108+と099の動作確認版を作りました。すみませんがお試しいただけますか。
https://osdn.net/users/yyagi/pf/DTXMania_TestBuilds/files/DTXMania/DTXManiaGR_Clone_fixmemleak_099e_diff.zip https://osdn.net/users/yyagi/pf/DTXMania_TestBuilds/files/DTXMania/DTXManiaGR_Clone_fixmemleak_108.zip
Rel109に搭載。本チケットはクローズします。
現在、DirectSoundを使用しているときは、サウンドファイルの読み込み時にClone()を使わず、都度Diskから読み込みを行っているため、読み込みが遅い。これを高速化したい。
ただし、単純にCDTX.csのL660~でコメントアウトしているClone()使用の実装を復活させるだけだと、メモリリークが発生するので注意。FDKのCSound.csのCSound: Clone()の実装の見直しが必要。
メモリリークの再現方法は、以下の通り。(#28914 の 2013-01-29 23:20 sf298yenの書き込みより)