C#
WPF
FM音源
けものフレンズ
YMF825

YMF825を使ってFM音源でサファリメロディーを響かせてみた

🎄この記事は けものフレンズ Advent Calendar 2017 22日目の記事です🎄

世界中にサファリメロディーを響かせたい、それをFM音源で実現させたことについての記事です。
ハード、ソフトの両面からアプローチを紹介していきます。

きっかけ

ニコニコ動画で PC-88 の実機演奏動画があり、FM音源 で何か演奏してみたいと考えました。

もともとFM音源で演奏させるハードとして RE:Birth シリーズや FMの塔 を持っていましたが、自身でデータを打ち込んで実機演奏させたことはありませんでした。
偶然にも長期間、趣味に時間をかけられる機会が得られたため、ハードとソフトの両方を自作して演奏させてみよう、というのがきっかけです。

演奏させるために必要なコト、モノ

FM音源に限りませんが、「演奏」には「音源」と「制御」が必要です。
ピアノ演奏には、「ピアノという音源」と「ピアニストという制御」が必要です。FM音源での演奏も同様に、FM音源自体とそれをコントロールするためのシーケンサが必要です。

今回はFM音源は専用ICを使い、さらに MIDI を使って制御を行うことにしました。

MIDI を使って制御することで、演奏データの作成と編集は他ソフトを使えるようになり作業量が軽減します。
専用ICは MIDI の情報を直接扱えないために MIDI -> ICレジスタ への変換ドライバを自前で用意する必要があります。また、音色の制御も必要なため、音色エディタも必要となります。

(ところで、音源は IC でなくともエミュレータであればハード的にも楽になります。ただ、私は制限されたリソースの中で音楽を作ることにも興味があります。完全にソフトウェアに完結するのは本当に手軽ですが、できることが増えるため、後々に考えるべきことも増えてしまうことが多いです)

YMF825 と YMF825Board

今回は音源モジュールに YMF825Board を用いました。単なる音源ICである YMF825 を、水晶振動子やヘッドフォン端子などを付属し、より扱いやすいモジュールにしたものが YMF825Board です。秋月電子 などで販売しており、容易に入手が可能です。

YMF825 の簡単なスペックは以下の通りです。

  • 電源: 5V
  • ロジックレベル: 5V または 3.3V に改造可能
  • 同時発音数: 最大 16 音
  • 接続インタフェース: SPI (max 10MHz)
  • DAC搭載 (モノラル出力)
  • 3-バンドイコライザ搭載

今回は YMF825Board を 同時に2枚使用 し、それぞれ左チャネルと右チャネルに割り当てることでステレオ出力としました。

FT232H, Arduino, そして FT232HL

さて、YMF825 を扱うためには接続インタフェースは SPI (Serial Peripheral Interface) である必要があります。PC から SPI を直接使うことはできないため、USBを経由して USB から SPI に信号を変換するデバイスを使用しなくてはなりません。

Raspberry Pi や Arduino のようなデバイスは標準で SPI に対応しています。また、USB から SPI に変換するデバイスも多数発売されています。
今回は検証と実験のために以下のデバイスにて回路を組みました。

どのデバイスも PC から受け取ったデータを SPI に変換する機能を搭載あるいはプログラム可能です。後述の経緯により、最終的には Arduino Nano と AE-FT232HL を使用しました。

LibMPSSE-SPI のレイテンシと解決

Adafruit FT232H Breakout

当初は画像のように Adafruit FT232H Breakout を使っていましたが、問題にぶつかってしまいました。
PC から FT232H を介して SPI を扱えるライブラリである LibMPSSE-SPI を使用していましたが、1回の書き込み命令ごとに必ず 1 ms のレイテンシ(待ち時間)が必要になること がわかりました。

YMF825 の場合、1回の書き込み命令で1レジスタ分書き込むことができ、複数のレジスタを1回の命令で書き込むことはできません。また、YMF825 は1音鳴らすためには3バイト分、消音するのに2バイト分を最低でもレジスタに書き込む必要があります。MIDI のように16チャネル分16音を鳴らす想定でいるため、16音同時発音には最短でも 48 ms かかります。

48 ms という時間は一見して高速に見えます。しかし演奏目的の場合、音量や細かい音程、音色データも送る必要があるために、テンポの乱れやもたつきが頻発し、演奏が破綻します。さらにステレオの場合は2倍のレジスタ書き込みが必要なために、96 ms となります。

Arduino Nano

この USB to SPI でのボトルネックを解決すべく、次に使用したのが Arduino Nano です。
PC からのデータをシリアル通信で受け取り、SPI に変換する スケッチ を書きました。Arduino を扱うのはこれが最初だったこともあり少々手間取りましたが、1回のレジスタ書き込みにかかる時間は 208 μs1 と4.8倍ほど高速になりました。

AE-FT232HL

Arduino Nano でもギリギリ演奏ができるレベルに達していたのですが、今回 YMF825Boardステレオ化基板 を制作者の方から人柱として拝領することができたため、これにともなって AE-FT232HL を使って高速化を行いました。ブレッドボードからきちんとした基板の上で動かし、さらに電源周辺も最適化されたため音質は大幅に改善しています。

実は前述の Adafruit FT232H 使用時には気が付きませんでしたが、LibMPSSE-SPI よりもさらに低レベルの D2XX というライブラリを使うことで高速に SPI を操作可能ということがわかりました。理論値の計測はしていませんが、Arduino Nano 使用時よりも実測値で 40~50倍2 ほどレジスタの書き込み時間を短縮することに成功しました。

YMF825 MIDI Driver

次はソフトウェアについて考えていきます。
前述のように、MIDI のデータを YMF825 は直接解釈できないため、変換を行うドライバを作る必要があります。YMF825 MIDI Driver を C# で制作し、画像のような構成を取りました。

MIDI Driver では、MIDI-IN から受け取った MIDI メッセージを解読して、YMF825 の命令に変換する部分です。そのため、MIDI ノートナンバーやピッチベンド、ボリューム、エクスプレッション、ベロシティなどを記憶し、それぞれ周波数と音量の値に変換しています。

YMF825 Driver では、MIDI Driver から受け取った命令を YMF825 が直接解釈できる アドレスとレジスタ のデータに変換します。また、レジスタ書き込みには一部で不可分なものがある3ため、レジスタ書き込みをまとめ、一括で書き込むための セクション という機構を導入しました。

SPI WrapperD2XX で SPI 通信を行うためのラッパークラスです。低レベルAPIの操作やバッファ管理、排他処理を行っています。

トーンエディタGUI制作

MIDI だけでは演奏の情報しか扱わないため、音色の情報についてもエディタを用意する必要がありました。
せっかくの GUI なので、FM音源のトーンパラメータの数値を直接弄るようなことは避け、画像のようなスライダやコンボボックスを使用した GUI にしました。特に、アルゴリズムやオペレータの波形などは数値表示ではわかりにくいため、画像を表示して選択できるようにしています。

また、ようこそジャパリパークへ のオーイシおにいさんパートを演奏するにあたり、バンドパスフィルタをかけたような篭った音はFM音源だけでは難しいため、YMF825 に搭載されている 3-バンドイコライザ を使用しました。イコライザと銘打たれていますが、実際は画像のように 双2次フィルタ (Biquad filter) となっており、各係数を 実数で 直接指定できるため、自由度の高いフィルタを実現できます。

こちらも GUI の持ち味を活かし、双2次フィルタのブロック図を表示させてみました。

また、今回は検証しながらの開発だったこともあり、レジスタが正しい値になっているかを確かめるためのレジスタマップも制作しました。本来ならばこのレジスタマップは IPC (プロセス間通信) で表示させたかったのですが、断念したためにホストアプリケーションに埋め込むような形になっています。こうした経緯もあり、このウィンドウだけ Windows Forms を使っています。他はすべて WPF です。

世界中に響けサファリメロディー

実機で演奏した動画を Youtube にて公開しています。
シーケンサを左上に、レジスタマップを右下に表示しています。

ようこそジャパリパークへ

AE-FT232HL、YMF825ステレオ化基板を使った高速・音質向上版です。イコライザを使用しています。

ぼくのフレンド

こちらのほうが制作は先です。Arduino Nano をブレッドボード上で使用したもので、低速版です。
実は MIDI Driver のバグにより、音色のビブラートが まったく かかっていません。

おわりに

回路製作、プログラム制作開始は10月上旬、それから3ヶ月で演奏できるレベルまで到達できました。実は自身、本日が誕生日でしたが25歳最後の大仕事ということで、サファリメロディーを響かせることができました。

久しぶりに WPF を使ったため GUI 制作に一番時間がかかってしまいましたが、こちらもバイナリは公開予定ですので以下の「ソース」からご参照ください。

けものフレンズ Advent Calendar 2017 を作らせていただきましたが、宣伝不足の中で参加表明・寄稿してくださった方々にこの場にて感謝の意を表したいと存じます。誠にありがとうございました。

2018年も けものフレンズと、けものフレンズを愛する皆さんにとって実り多き一年となることを切に願っています。

ソース

自身の制作物


  1. Arduino Nano と 115,200 baud/s で通信をし、書き込み命令を送るのに3バイト (24バイト) 送るため、$$\frac{24\,\rm{bytes}}{115200\,\rm{baud/s}} = 208.333...\,\rm{\mu s} $$ よりおよそ 208 μs かかる。ただし SPI 書き込みの時間は考慮していない。 

  2. 詳細は https://twitter.com/nanase_coder/status/939907411028017152 を参照。 

  3. Fnum/Block指定 (0x0d, 0x0e)、ボイス番号指定 (0x0b) など、順序に依存した一連のレジスタ書き込みのことを指す。