考察1 - 入力のズレ

 「黎明」の章で述べた通り、音ズレには「サウンドのズレ」「入力のズレ」「描画のズレ」があり、そしてさらに「音ズレの原則」があります。

 ここでは、「入力のズレ」について DTXMania で行ってきたことを振り返りたいと思います。

1 スレッドモデルにおける入力

 初期のDTXMania では、音ゲーの3大処理である「サウンド」「入力」「描画」を、すべて1つのスレッドで行っていました。これを1スレッドモデルと呼んでいます。勝手に。

 DTXMania の VSync オプションを ON にすると、描画の処理に約 16.6㎳ かかると同時に入力の精度も約 16.6㎳ になってしまう、ということはすでにお話しした通りです。

 この問題は現在も進行中ですが、過去には他にも問題がありました。

MIDI入力のズレ

 DTXMania が MIDI入力を処理する方法は、実は Windows 95 の時代から全然変わっていません。同じマルチメディア(死語)ライブラリをずっと使い続けています。

 DTXMania が MIDI機器(電子ドラムなど)からメッセージを受け取れば、それがDTXManiaに事前登録されたドラムの入力かどうかを判定した上で、チップとのヒット判定を行います。

 しかし、この時受け取る MIDIメッセージには、タイムスタンプ(入力が発生した時刻の情報)がありません。

 MIDIは演奏のための通信規格ですから、もちろん楽器の同期用にタイマーの仕様もあります。しかも 2 つも持っています。MIDI クロックと、MIDI タイムコードです。しかし、MIDIクロックの精度は 4 分音符 1 つあたり 24 回、つまり BPM によって精度が相対的に変化します。MIDIタイムコードは絶対時刻をやり取りするのですが、MIDI メッセージがその精度についていけないという痛烈なオチのため、非常に面倒臭い処理が必要になります。よってMIDIのタイマーは使い物になりません

 ということで、DTXMania では、システムタイマーやサウンドタイマーから取得した現在時刻(MIDI コールバック関数が呼び出された時点の時刻)を、タイムスタンプとして MIDI メッセージに後付けするようにしています。なので、これは入力が発生した正確な時刻ではないわけです。DTXMania のコールバックが呼び出されるまでのレイテンシも不明ですので、これを自動修正することもかないません。

 マルチメディア(死語)ライブラリを使う限りにおいては、今のところこれ以上どうしようもありません。

SlimDX.DirectInput のバグ

 DTXMania では、DirectX を扱うために SlimDX というライブラリを使用していました。(※現在は SharpDX に乗り換えています。)

 しかしそこにあったのは、タイムスタンプが取得されないという SlimDX.DirectInput のバグ。

 DirectInput は、MIDI とは違い、入力に対してタイムスタンプ(システムタイマー;timeGetTimeの値)をちゃんと付与して渡してくれます(精度は怪しいですが)。しかし、SlimDX.DirectInput を使うと、その情報だけが抜け落ちてしまうのです。

 問題の箇所も特定でき、つたない英語で SlimDX 公式フォーラムにも投稿しました。
 が、一向に修正される様子もなく。

DTXMania 070 (2008/09/16)
・SlimDXのバグが直るまで、ジョイスティックのみリアルタイムチェック入力に変更。(60fpsくらいだと、最悪16ms以上押下し続けていないと入力漏れを起こす可能性有り。FPSが大きいほど問題にならなくなる。)

 結局、業を煮やして、SlimDX のソースを全部持ってきて、自分で修正することで対応しました(※ SlimDX は MIT Licence を持つオープンソースなので、自由に改変して配布することが許されています)。少し前の DTXMania のソースコードに SlimDXc_Jun2010 という名前のプロジェクトが含まれていたのは、そのためです。

 なお、SharpDX にはこのバグは存在しないようですが、結局はタイムスタンプがシステムタイマーであることを嫌って、サウンドタイマーをタイムスタンプとした上で SlimDX 時代と同じ方式で実装していたりします。

 DTXMania 087(2011/01/15)では、このズレを調節できる InputAdjust オプションも搭載されました。(最新版では廃止されています。)

Direct でなくなった DirectInput

 DirectInput は、XInput が登場した今でも、Windows でゲームパッドやジョイスティックをダイレクトに扱うための機能としてまだ採用されています。(XInput は XBOX用のゲームパッドを対象にしているため、DirectInput とはまた違った仕様になっています。そして、その煽りを受けて、DirectInput と XInput を物理スイッチで切り替える機能を持たざるを得ないゲームパッドも多々登場し、混乱を極めています。ひどいね。)

 しかし、最近の DirectInput は、もっとダイレクトRawInput を使って実装されているということが判明しました[要出典]。いつの間にか、DirectInput も Direct ではなくなっていたようです。

 RawInput を使うと、入力装置(HID; Human Interface Device)の生の入力を取得することができます。しかし、その情報は、API で取得するのではなくウィンドウメッセージとして流れてきます。しかも、DirectInput にはタイムスタンプがありますが、RawInput にはタイムスタンプがありません。

 RawInput にタイムスタンプがない以上、それはウィンドウメッセージの処理タイミングに依存する(メッセージを受信したらすぐにアプリ側でタイムスタンプを後付けする)ことになります。すると、最悪、DirectInput の Buffered モードですら、バッファリングされた入力データがすべて同じタイムスタンプを持つことになるかも知れません(編注:なりました)。アプリが VSync でブロックしているなら、16.6ms ごとの飛び飛びの値になる可能性もあります(編注:なりました)。

 次の「考察2」でも述べますが、最近の Windows では、とにかくウィンドウメッセージの処理を止めてはいけないようです。

ランダムに変わる判定

 DTXMania では、チップ位置から ±34ms の範囲で叩けば、Perfect 判定が出ます。しかし、先述したMIDI入力のズレと Direct ではなくなった DirectInput のために、判定の範囲がランダムで変化するようになりました。

 1スレッドモデルでは、60Hz の垂直帰線同期で VSync が ON のとき、入力のタイムスタンプは約 16.6 ms 単位(フレーム単位)でとびとびになります。これは、0より大きく16.6ms以下の入力がすべて 16.6ms に丸められる(未来に繰り上げられる)ことを意味しています。VSync と MIDI入力 / DirectInput の影響により、入力には常に 0~16.5ms のランダムな遅延が生じてしまったのです。

 よって、もしチップの位置がきっちり VSync のタイミング(この位置を0msとする)に置かれていた場合、チップの前方3フレーム、後方2フレームが Perfect 判定の範囲となります。これは、チップに対して -49.8~33.2ms の範囲が Perfect と判定されることを意味しています。

 さらに、チップが VSync に対して -8ms に置かれていた場合を考えてみましょう。この場合、チップの前方3フレーム(チップの存在するフレームを含む)、後方2フレーム(同)が Perfect 判定の範囲となります。これは、チップに対して -41.8~24.6ms の範囲が Perfect と判定されることを意味しています。(チップがたまたまVSyncぴったりに現れることはまずないと思うので、こちらのケースが大半だと思います。)

 このように、現在の MIDI / DirectInput で Vsync ON だと、チップの判定範囲はすべてのチップでランダムに変化します。そして、チップは早めに叩く方が有利、早めに叩く分には本来 Great の範囲でも Perfect になることさえあるということです。

 これは Perfect~Great 間の話でしたが、Great~Good、Good~Ok、Ok~Miss の間でも同様のことが発生します。つまり、コンボが切れるか否かという非常にセンシティブな問題にも直結します。ランダムで

 DTXMania2 の中盤以降は、次の「考察2」で述べるように、ウィンドウメッセージを遅滞なくフル回転させることで、VSync が ON でも MIDI / DirectInput のタイムスタンプが丸められないようになりました(正しくは、丸められる単位を1~2ms まで縮めました)。

意図的な入力ズレ(推定)

 昔(1st とか 2nd のころ)のドラムマニアでは、連打を行った際に、最初の1つを外してしまうと残りも全部外れてしまうという「なだれ現象命名・私 が、人々にひどいストレスを生みました。

 その真相は不明ですが、この現象は間違いなく存在していたと確信しています。

 これ以上はツッコみません。

 ええ。過去のことですから。