YMF825で着メロ(SMAF)を鳴らす

# TL;DR

[YMF825](https://yamaha-webmusic.github.io/ymf825board/intro/) でSMAFフォーマットの着メロ（`*.mmf`, `*.spf`）を再生するプレイヤーを作りました。

- [but80/**smaf825**](https://github.com/but80/smaf825)

着メロファイルなんてもう残ってないよ！ という人は、[ゲーム音楽館](http://game-melody.com/) あたりを訪れると幸せになれると思います。和音数の少ないものは再生できる可能性が高いです。

<!-- 鳴らしてみた動画はこちら -->

# 経緯

スマホが世を席巻する以前、au や Vodafone（現Softbank）のガラケーにはMAシリーズというヤマハのFM音源チップが搭載されていました。当時MA-3やMA-5をよくいじっていた僕は、ガラケーを持たなくなってからも「あの音源部だけ単品で欲しいなー」と常々思っていたものです。
そんな折、MAシリーズと互換性の高い音源チップ **YMF825** が [扱いやすくなって販売中](https://www.switch-science.com/catalog/3399/) と聞き、「こんなの待ってました！」とばかりに入手、眠っていたArduinoに繋いでいじってみることにしました。

- 最初に参考にした記事 : [YMF825BoardをArduinoで鳴らしてみる](https://fabble.cc/yamahafsm/ymf825boardarduino)

とりあえずドレミを単音で奏でてみた的なサンプルはけっこうあるのですが、「チップのトータルなポテンシャルを知りたい！」とか「当時鳴らしていた曲が再現できるか確認したい！」という欲望がまずあったので、じゃあ当時の着メロフォーマットであるSMAFをそのまま再生するプレイヤーをまず作ってみよう、と思ってできたのがこちらです。

# 設計

電子工作やArduinoには慣れていないし、単体だとメモリ容量もたかが知れているので、「Arduino側の処理は可能な限り軽くして、Mac側でほとんど処理してしまいたい」。

ということで、Arduinoに転送するスケッチは「シリアル通信でMacから受け取ったレジスタ番号とデータ列をリアルタイムにSPIでYMF825へ送信する」機能に絞りました（最初からそんな感じの用途の製品もあるようですが、今後の拡張性・入手のしやすさ・資料の豊富さからArduinoを使うことにしました）。
残りの処理は全部Mac側で行うものとし、コードはGoで書きました。

ちなみに、YMF825はシーケンサ機能も持っているようで、レジスタ・データ・待機時間を並べたものをFIFOに書き込むとその通り再生してくれるとのことですが、使い方の詳細がわからないので今回は使用していません。シーケンサというよりは多分「YMF825の内蔵クロックで再生する」ためのただのバッファのように思われます。

# 実装

いざ作ろうとしたところでショックを受けたのが、 [**SMAF公式サイトがなくなっている**](http://smaf.yamaha.co.jp/) ということでした　:innocent: 
さらに「当時はもっと詳しい資料持ってたはずなのにどっかいっちゃった」という状況で、現存する資料集めに加えて `.mmf` や `.vm5` 等をバイナリエディタで解析する作業が発生しましたが、過去に自分で書いたTSXBINマクロが見つかったので、これが大いに役立ちました。ありがとう、過去の自分…。

以下、実装していてハマったポイントです。

## 音が割れる

前述の公式サンプルでは `SeqVol`（レジスタ#9の上位5ビット）が[けっこう大きめに設定されています](https://github.com/yamaha-webmusic/ymf825board/blob/3ea7d82338d07490d16302b4f0368f8160e4d68f/sample1/ymf825board_sample1/ymf825board_sample1.ino#L76)が、この値が大きいと、和音を鳴らしたときにミキサー部で音割れします。音をたくさん重ねるほど（特に位相が揃っているほど）、この値を小さくする必要があります。
`smaf825` では `16` をデフォルト値に設定しています。ほとんどのケースで音割れしなくなりました。

## 音色パラメータの互換性

YMF825の音色パラメータはMA-3以降のMAシリーズのFM音源部とほぼ互換ですが、以下のパラメータが足りません。

- `PANPOT`
- `PE` （Panpot Enable）
- `SUS` （キーオフ後もサスティンレートを維持するフラグ）

パンはあきらめるとして、`SUS` については他のパラメータとノートのデュレーションを調整すれば代替できそうです。が、今回は単純に無視していますので `SUS` がONな音色を使用しているMMFは正確に再生されません。

また、MA-2ではFM音色パラメータの名前が違うのですが、内容的にはほぼそのまま互換性があります。MA-2で使用できない機能は以下のとおりです。

- `DT` (デチューン)
- `XOF` (キーオフの無視)
- `SR` (Sustain Rate) は `RR` (Release Rate) と共用。ただし `EGT` をONにすることで `SR` だけを `0` に固定可能
- `BO` (オクターブシフト)
- `ALG` (アルゴリズム) の選択肢が少ない。ただし番号には互換性がある
- `FB` (フィードバック) がグローバルパラメータとして定義されており、第１オペレータにしか作用しない

これらを無視してMA-3のパラメータに変換すれば、YMF825でも同等のトーンを再現できます。具体的な変換処理は以下のように行っています。

- [グローバル部](https://github.com/but80/smaf825/blob/9fd411214a6281a17184f586c3130db1fe69617d/smaf/voice/vmafm.go#L224-L240)
- [オペレータ部](https://github.com/but80/smaf825/blob/9fd411214a6281a17184f586c3130db1fe69617d/smaf/voice/vmafm.go#L106-L132)

## 16チャンネル・16音色に収まらない

YMF825は16チャンネル・16音色という仕様で一見合理的に思えますが、MA-3以降のMMFでドラムトラックが含まれている場合などは１チャンネル中で複数の音色が使用される場合があります。実際、当時作成したMMFを再生しようとしたら、同時発音数は十分間に合っているにもかかわらず、定義されている音色数が２０以上ありました。
このような場合、収まらなかった音色は転送されず、その音色が割り当てられているノートは無視される仕様としました。

また、そもそもMMF内の1チャンネル中で和音を使用している場合もあり、本来はこれをYMF825の未使用チャンネルに割り当てる処理が必要となります。16チャンネルでは到底足りない場合も発生することでしょう。
この処理は未実装なので、ドラムトラック以外の全チャンネルは強制的にモノモードONで再生されます。昔のゲームミュージックを再現するような場合は「1トラック1音」が原則だと思いますので、それを意識して作られたファイルは問題ないと思います（とはいえ、実際には作り手のクセによるでしょう）。

ちなみにSPFフォーマットはたしか全チャンネルをモノで制作するのが前提だったと思うので、MMFよりもSPFの方が再現度は高いと思われます。ただしSPFは1ファイルあたり4トラック上限のため、複数ファイルに分割して同時再生する技などもありましたので、そのような前提で作られたSPFは１ファイル分のチャンネルしか再生できません。

# 再生してみた

筆者の耳に一番馴染んでいるFM音源は、OPLLことYM2413（MSX2+に搭載されていた音源）で、以前、MSX版魔導物語（ぷよぷよ）の「魔導音頭」をMA-5で再現してみたことがありました（別名義で[ゲーム音楽館に投稿してました](http://game-melody.com/t.cgi?n=N96864&w=ma5)）。

ということで、こちらが「魔導音頭MSX版をMA-5で再現してみたMMFをYMF825で再生してみた」ものになります。

https://soundcloud.com/bucchigiri/madoondo-ymf825

そこそこいい感じの再現度です。エンベロープの雰囲気とかが微妙に違う気もしますが、ガラケー実機がもうないので公式シミュレータでしか確認できません。そもそもシミュレータも実機とは微妙に違ったりするので、細部の確認はちょっと難しそうですね。個人的にはそこまで求めてないので、だいたいでオッケーです。

次、「世界樹の迷宮」より「鉄華 初太刀」のカバーです。これもMA-5で作ったんですが、ドラムにPCMを使っていたので、ドラムトラックは再生できていません。パンも効いていないので、音量バランスもだいぶ違って聞こえてます。
(2017.10.28追記) ベロシティとエクスプレッションから `VoVol` を算出する式が不適切だったことも理由のようでした。この問題は `v1.1.0` にて修正しました（MA-2・3のベロシティカーブも併せて修正しました）。

https://soundcloud.com/bucchigiri/sekaq-tekka-ymf825

他もそこそこ再生できてましたが、マイクロキャビンの曲なんかはPSGノイズのパターンが多くてトーン数過多のため、ドラムトラックが一部しか再生されませんでした。

# 以上です

お手元のSMAFファイルや、冒頭にも紹介した [ゲーム音楽館](http://game-melody.com/) あたりでDLした曲を再生するなどしてお楽しみいただければと思います。わんにゃ〜☆さんの[ファンタジーゾーン曲](http://game-melody.com/s.cgi?n=fantazyzone1&w=ma3)なんかがいい感じでした（2017.11.01 一部の曲は残念ながら `[WARNING] Too many tones` でした）。過去に公式で配布されていたツール類をまだお持ちの方は、シミュレータで新たに曲を作ってから当ツールで再生したものを録音するといった使い方もできるかもしれません。

ちなみにSMAFは音楽に合わせてLEDやバイブレータ、テキスト表示などをコントロールするためのチャンクが定義されていて、なんだか電子工作ととても相性が良さそうです。今回この `smaf825` では対応してませんが、その辺の機能拡張ができたらいろいろ面白いこともできそうですね。

# 補足

- `smaf825 dump -j <file>` とすると、JSON形式で `.mmf` や `.vm5` をダンプできます。着メロファイルやライブラリから音色データを抜き出す用途に利用すると良いでしょう。 ただし、YMF825 にそのまま食わせられるバイナリ形式での
ダンプには未対応です（ちょっといじれば簡単にできると思います）。
 ダンプ機能も実装しました。(2017.10.26)
- コマンドの使用方法については `smaf825 -h`, `smaf825 play -h`, `smaf825 dump -h` にてヘルプをご覧ください。
- その他、[リポジトリのREADME](https://github.com/but80/smaf825)をお読みください。