beatmani IIDX
beatmania IIDXという音楽ゲーム(音ゲー)があります。通常はゲームセンターに置いてあるアーケード版で遊ぶことになりますが、それ以外にPC版(INFINITAS)やアプリ版(ULTIMATE MOBILE)が存在します。
当然ながらゲームセンター以外でゲームをプレイする場合は専用のコントローラーがないとキーボード操作やタッチ操作でプレイすることになりますが、これは本来のゲーム体験とは大部違ってしまうことになります。そこはKONAMIも認識していて専用のコントローラーをいくつか販売しています。
専用コントローラー
- beatmania IIDX 専用コントローラ エントリーモデル
- 16,280円(税込)
- USB/Bluetooth接続対応
- ラバーコンタクト(接点ゴム)PS2版と同様の静音タイプのスイッチを採用
- この部分はアーケードの感覚と違うし、ボタンが戻ってこない症状も発生するため厳しい
- beatmania IIDX 専用コントローラ プロフェッショナルモデル
- 80,080円(税込)
- USB接続対応
- アーケード版に準拠したマイクロスイッチ・バネを採用
これら二つが現行モデルということになるでしょう。両者ともに言えることですが、いつでも買えるわけではないのはなかなか難しい部分です(再販待ち・受注生産)。また、アプリ版は現時点ではBluetooh接続でしか使えないということになっているため、エントリーモデルの方でしかアプリ版は遊べません。下記のブログ記事のようにAndroid版ではUSB接続でコントローラが接続できそうですが、iOS/iPadOS版では動作しないような気がしています。(未確認なだけでUSB Type-Cが搭載されている端末では動くかもしれない)
おうちマニア
beatmani IIDXを家でプレイすることをさしておうちマニアと言ったりするようです。昨今の社会情勢もあり家でプレイできる環境は非常に魅力的です。前述の通り選択肢はPC版とアプリ版があるわけですが、正直初心者がプレイするのにPC版はあまり向いていません。楽曲の解放は上級者の方が楽にできる仕様になっているため楽曲パックを購入するなどしないと選択できる楽曲数が非常に少ないためです。加えてPC版には月額費用もかかってきます。アプリ版もプレイし放題にするには月額費用がかかりますが比べるとアプリ版の方が圧倒的に安いわけです。
- PC版(INFINITAS)
- 1,628円/月(税込)
- 楽曲はパックで購入するか、BITSをためて難易度ごとに解放
- アプリ版(ULTIMATE MOBILE)
- 480円/月(税込)
- 980円/月(税込)
- Hyper以上の譜面をプレイしたい場合
- 楽曲は全てプレイし放題
アプリ版をコントローラーで遊びたい
普通はエントリーモデルを購入・改造して満足のいく操作感にする人が多いようです。ところが、なぜか私はそういう発想にならずエントリーモデルのBluetoothの通信仕様さえわかれば任意のコントローラーでアプリ版をプレイできるのではないかという発想に至りました。前置きが長くなりましたが、この記事はその結果をまとめたものです。
たまたま同僚がエントリーモデルを所有していたため、お借りすることができました。これがなければこの記事はそもそも存在し得なかったでしょう。非常に感謝しています。
非公式コントローラーの選択肢
USB接続専用のプロフェッショナルモデルが2021夏頃に発売されるためその頃には公式でアプリ版もUSB接続に対応を謳うような気がしていますが、現時点で手軽にコントローラが手に入らないわけです。ところが、非公式のコントローラーというものが存在しており40,000円ほどでアーケードに近い操作感のコントローラーを購入することができます。
いろいろな種類がありますが、現在だとPHOENIXWANを購入するのが無難じゃないかなと思います。他には、PC版対応のコントローラーを選ぶとPC版でも使えるし、入力の形式が同じなので扱いやすいと思います。
通信形式
いくつかの方法で確認しました。Androidであれば開発者向けオプションからBluetooth HCIスヌープログ
が設定できるためこの状態でアプリとエントリーモデルを接続して普通にプレイします。それから、adb
でログを取得します。このログはwiresharkで確認できるのでそうしましょう。この通信を眺めるだけで大体のことはわかったのですが、リアルタイム性がないため実際のキー入力がどう表現されているがいまいち確信を持てませんでした。そのため、リアルタイムにBluetoothの通信を確認できるnRF Connect for Mobile
というアプリを活用しました。
結果
Bluetooth Low Energyのnotifyを使って秒間120回ほどデータを送信していることがわかりました。
+------------------------+
|Peripheral |
| Name: IIDX Entry model |
| +----------------------|
| |Primary Service |
| | UUID: 0xFF00 |
| | +--------------------|
| | |Characteristic |
| | | UUID: 0xFF01 |
| | | Properties: notify |
+------------------------+
notify部分では以下のようなデータを送信しています。
// 10 bytes
0xAA00BC0DEE
0xAA00BC0DFF
判例 | 備考 |
---|---|
AA | スクラッチ(時計回りが正) |
B | 次の値の和: B5(0x1), B6(0x2), B7(0x4) |
C | 次の値の和: B1(0x1), B2(0x2), B3(0x4), B4(0x8) |
D | 次の値の和: E1(0x1), E2(0x2) |
EE | 1から始まり、2ずつ加算 |
FF | 2から始まり、2ずつ加算 |
補足
0xFF00
, 0xFF01
という短い形式のUUIDは用途が事前に届出されていて、なおかつ受理されていないといけない気がしますが果たして……
https://www.bluetooth.com/ja-jp/specifications/assigned-numbers/
実装
動かすデバイスはUSB接続ができて、Bluetooth Low Energyが使えればなんでも良いのですが、ここではどこのご家庭にもありふれているRaspberry Piを活用することにしました。
+----------+ USB +------------+ BLE +------+
|Controller+----->Raspberry Pi+----->Mobile|
+----------+ +------------+ +------+
実際には以下のデバイスあたりで動作させることを想定しています。特にRaspberry Pi Zeroの無印には無線周りのモジュールが搭載されていないはずなので動きません。
- Raspberry Pi Zero W
- Raspberry Pi Zero WH
- Raspberry Pi 3B v1.2
- Raspberry Pi 3B+
- Raspberry Pi 4
Node(TypeScript)
程よく型付でライブラリが豊富ということでTypeScriptを使って最初の試作を行いました。blenoでBLEの通信を行いましたが、本家の開発が停止していて、フォーク先を使う必要があるということを除いて非常にスムーズに開発できました。
LinuxでDBus経由ではなく直接Bluezなどを使っていそうなのが特徴的ですね。
worker_threads
とAtomics
で複数スレッド処理もできそうなので実験しています(が動かせていない)。
https://github.com/watiko/beatble/pull/1/files
Rust
Nodeの方でも普通に動いたのですが、速度的な部分(複数スレッド処理や純粋に言語のパフォーマンスなど)が優位そうなRustでも実装して見ることにしました。BLEライブラリ周りで苦労が多くかなり時間を使いましたが、最終的にこちらでも動作させることができました。
gilrsが同期的な入力の取得しか提供しておらず可能な限り入力を受け付けようとするとそのスレッドのCPU使用率が100%に張り付いてしまうのですが何かいい方法がないか気になっています。もしかするとライブラリ使うのをやめて/dev/input/js*
を自前で読むようにした方がいいかもしれないですね。
またRaspberry Pi Zeroでビルドすると100分ほどかかってしまうので非常にキビシイです。動くことは確認できているのですが、大変なので手元では3Bでメインで検証していました。
結論
おうちマニア環境作った。(初心者なので腕前には期待しないでほしい) pic.twitter.com/py9pHuBQTR
— watiko (@watiko) December 8, 2020
Rustで作ったbeatbleの方は既にudevやsystemdと連携してコントローラーが接続されたらbeatbleを起動させるというところまで作ってあるため、実用上快適に使えるようになりました。
iPad Proに有線で認識させることができるかや、マイコンを使ってBLEを喋らせたりなども余裕があれば試したいなと思っています。