新型コロナウイルスの猛威が収まらず、仕事や生活面で色々と制約の多い日々を送っています。日々のストレスをどんな方法で解消されていますか?
私の場合、メガドライブ基板のYM2612を眺めながら、チップから出るサウンドを聴いている時、一番心が癒されます。
ここ数年、趣味でSGDKを使ったメガドライブプログラミングを楽しんでいます。SGDKにはC言語でゲームを作るための強力なライブラリが多数用意されていて、特にXGMサウンドドライバは、FM5ch+8bit14kHzのPCM4ch同時再生可能な、当時では考えられないようなハイクオリティなサウンドを再生できます。しかし、高性能ゆえの欠点もあります。追加してほしい機能として、「FMによる効果音」・「フェードアウト機能」・「複数の曲間でのPCMの共用」などがありますが、SGDKのサイトにはXGM2の仕様が…。期待大ですが待ちきれません!
そこで実際にゲームで使うためのPCM再生機能付きメガドライブ用サウンドドライバを設計し自作してみました。まずは仕様設計です。
<目標にした仕様>
・FMによる効果音再生、最大3ch再生(BGMと排他的再生)
・DCSGによる効果音再生
・PCMによる効果音再生
・PCMは同時に2ch再生
・PCMサンプリングレートは8kHz以上
・PCMサンプリングレートはYM2612のTimer-Aで管理
・フェードアウト機能
・曲の途中からでも再生可能
・なるべくZ80側で処理
<コマンド一覧>
サウンドデータのサイズを考慮すると、リアルタイムにデータを展開するカスタムトラッカーフォーマット+ドライバーが理想ですが、今回は処理速度と音質を重視し、XGMと同じレジスタベースにしました。(XGMを参考に必要なコマンドを追加した仕様になります)
同じポートへのデータををまとめることで圧縮し、PCMは異なる曲でも共有できる仕組みなので、VGMの半分以下のサイズになります。(それでも大容量ですが…)
<データフォーマット>
ヘッダーの16バイトは曲名、次の16バイトにExt3.ch3 modeやループアドレス、ジャンプアドレスなどを、voice data adress, voiceはFM音色データですが、現在は未実装です。
<VSYNC駆動ドライバの問題点>
メガドライブには垂直基線割り込み(V-INT)、水平基線割り込み(H-INT)以外に、割り込み機能がなく、YM2612にあるタイマー機能もポーリングしないと使えません。基本的にV-INT間隔(1/60秒)を音の長さの最小単位にしないと、テンポが一定にならずリズムがヨレてしまいます。
上図のように1/60秒を最小単位にした場合、音の長さは正確ですが、微妙に早くしたり遅くしたりすると、音の長さが短くなったり長くなったりして、気持ちの悪いノリになってしまいます。
そこで、1/60秒をさらに16分割し、ジャストのタイミングになるようにあえて、ウェイトデータを入れてタイミングを調節します。ウェイト時間が長いと次のV-INTまでに処理が終了しない可能性が出てくるので、Z80側のメモリにダブルバッファリング処理を行うことで解決しました。
なお、メガドラミニ2に収録予定の「ファンタジーゾーン」は似たようなフォーマットですが、PCM再生機能がなく、その代わり、VSYNC駆動ではなくTimer-Aで駆動しており、再生テンポは自由自在です
<Z80プログラミング>
Timer-Aを1019に設定すると約10653Hzのタイミングで、YM2612にフラグが立ちます。Z80は3579540Hzのクロックで動いているので、約335 (3579540/10653)サイクル以内にポーリングを開始しないといけません。処理に必要なサイクル数を全て計算し、処理を小さな単位に分割しました。
プログラムの流れはこんな感じですが、処理の合間にTimer-Aのフラグのチェックをし、2ch合成したPCMデータを書き込みます。シングルスレッドのように処理になるのでしょうか。Z80は3579540Hzで動作するので、1フレーム(1/60秒)で59659クロック、PROG_00からPROG_15までを、1フレームで11回ぐらい回すことになります。実際はDMA転送中はZ80を停止するので、DMA転送に時間がかかれば、PCMの再生品質が落ちてしまいます。
XGMドライバは、DMA転送をしていないタイミングにPCMデータをZ80側のメモリに溜め込んでおいて、DMA転送中は68000側のメモリ読みに行かない工夫をして、高音質なPCM再生を確保しているようです。すごいですね。
<DefleMaskによる打ち込み>
大好きな「SPACE HARRIER」の曲をDefleMaskで打ち込みました。いつまでも色褪せない名曲ですね。AC版はFM 3ch PSG 3ch PCM 16ch?の構成ですが、パーカッションのみPCMでベースなどはFMで鳴らしています。重厚なベースの音の再現がなかなかできず、耳コピ職人のWING☆さんに相談したところ、ベースの音色データを頂きました。元はNOZ MUSICさんが作られた音色とのことで、音圧のある素晴らしい音色でした。有難うございました。
<VGMファイルを独自フォーマットに変換>
打ち込みが終了したら、VGM形式で書き出し、上記のフォーマットに変換します。
<68000側のドライバ作成>
先ほどのフォーマットのデータを展開し、FMによる効果音の処理は68000側で処理します。YM2612に書き込む最終レジスタデータに整理し、Z80側に一気にデータを書き込みます。
68000のプログラムはC言語で書いていますが、8ビットのデータ処理はインラインアセンブルで書いた方が早かったので、部分的に使用しています。
<テストプログラム>
こんな感じで無事「PCM再生機能付きメガドライブ用サウンドドライバ」完成しました!ダブルバッファリングでウェイト処理を行っているので、62HzのようなVSYNCから少しずれたタイミングでもリズムがほぼ正確に演奏できます。FMの効果音は120Hzで再生しています。PCMのフェードアウト機能はないので、今後の課題です。
なんとか、目標のサウンドドライバは完成しましたが、SGDK標準のXGMドライバと比較すると、どうでしょうか。FMでの効果音再生、フェードウト機能は可能になりましたが、やはりZ80のみで動く、14kHzPCM4ch再生可能な「XGMドライバ」には敵いません!おそらく一生頑張っても、到達できない領域のようです。
少しずつですが、プログラミング技術を磨いていきたいと思います。
最後に、メガドラミニ2に「ファンタジーゾーン」が収録されることになりました。今回のブログのサウンドドライバはメガドラミニ2とは別物になります。「ファンタジーゾーン」はPCM機能なしで、Z80で100%動作するバージョンです。YM2151(8ch)のサウンドを頑張ってYM2612(6ch)にアレンジ移植しました。セガの方々の監修を得て素晴らしいものになっていると思いますので、宜しくお願いします!