コンテンツへスキップ
ものがたり
戻る

MIDI 2.0の時代に備えて「FPGAとARMで作る自作 USBオーディオインターフェース」(同人誌)を読み解く

これは【推し祭り】技術書典で出会った良書 Advent Calendar 2019https://adventar.org/calendars/3997のクロスポスティングです。

目次

音楽技術書をもっと増やしたい…!

技術書典は誰でもフルスクラッチで執筆から始められる技術同人誌の即売会で、いわゆる「商業」では販売部数の見込みが立たず全く出版の機会が無いようなマイナー技術の本であっても、自分の信念がある限り何の躊躇もなく執筆して販売するところまでもっていけます1

個人的には、書店のコンピューター関連書籍のコーナーにCG・DTM関連のコーナーがあるように、技術書典にもグラフィックス方面のテクニックに関連する書籍がいくつか出ているので、音楽の打ち込み指南などの書籍も出てほしいなと思っているところですが、今回は音楽関連の技術書としてハードウェア方面でカテゴライズされていそうな「FPGAとARMで作る自作 USBオーディオインターフェース #1 USB-MIDIデバイス編」を紹介します。

mmitti.info

USB-MIDIデバイスってなんじゃらほい?と思われるかもしれませんが、ひとつはMIDIキーボードなどの外部MIDI入力デバイス、もうひとつは外部MIDI出力デバイス、いわゆるMIDI音源モジュールです。今どきはあまり見かけないものですが、Roland(GS音源)、Yamaha(XG音源)、KORGといった会社がよくキーボードの付いていないシンセサイザーを出していました。本書の場合は「DTMにお金をかけない」ためにMIDI音源モジュールを自作することが主眼にあるようです。2

本書の紹介でも十分な内容になるかと思いますが、ちょうど先月ロンドンで行われたADC (Audio Developers Conference) 2019でMIDI 2.0に関するセッションが行われていたので、MIDI 2.0の時代にこういった自作ハードウェアは使えるのか?といった話も補足的にまとめておこうと思います。

本書の内容

本書はFPGAを使ってUSB-MIDIインターフェースを制作するための情報がまとめられている本です。著者がDigilentのPynq-Z1を使って自らUSB-MIDIインターフェースを制作してきたことをもとに書かれているので、具体的かつ詳細にまとめられています。ほとんどのページに図表が入っていてかなり親切に書かれています。

USB-MIDIデバイス編、とあるのは、今回はオーディオI/Oに関連する部分の言及がほぼ無く、オーディオとMIDIを両方処理する部分は「次回」になるようです。もっともあとがきから察するに、次回はオーディオ部分が中心で、MIDIメッセージによってリバーブ/コーラス/ディレイなどのDSP処理をかませたり、ピッチ指定によって周波数を変換したりといった、MIDI音源モジュールらしい部分は、次回よりさらに先ということになるのでしょう(想像)。ここまで到達すると、洋書でも無いレベルなんじゃないかと思いますし、ぜひとも完結したものが見たい…! 3

MIDIの基礎知識

USB-MIDI音源モジュールを制作するためには、まずMIDIの知識が必要になります。MIDI仕様の中には、MIDIメッセージをシリアル通信の規格であるUARTに基づいて接続する方式に関する規定も含まれていて、本書でもしっかり関わってくる部分なので、きちんと言及されています。4

実装者向けの記述としても、ランニングステータスはきちんと処理する(受ける側は省略されたりされなかったりする送信側の挙動にまんべんなく対応しないといけない)とか、アクティブセンシングとは何であってどのように対応しないといけないとかいった話が、ちょいちょい親切に書かれていて、読み込む価値があります。

MIDI回路(FPGA)

MIDIの基本仕様の話が終わると、いよいよFPGAでこのMIDI回路をどのように実装するかという話になります。この段階では、まだUSB-UARTの接続に関する話題は出てきません。MIDIインターフェース、オーディオインターフェースの部分はFPGAだけで完結します。

FPGAの回路設計は概ねわたしの守備範囲外なので概ね表層的な話しか読み取っていないのですが(この本ではMIDIとかは詳しく解説しているけど、FPGAについてはほぼ知っていることが前提のようなので、他の資料で予習する必要がありそう)、設計レベルではブロック図やステートチャートでメッセージがどのようにやり取りされているかが親切に示されています。

実装されているのは(1) Advanced Extensible Interface (AXI) に基づいてARM CPUとMIDIインターフェースを接続する回路、(2) MIDIシリアル通信用のクロックジェネレーター回路、(3) MIDIバスからUARTに変換してシリアル出力ための回路、(4) 逆にUARTを経由して届いたメッセージをMIDIバスに変換する回路(ここはシステムメッセージとチャンネルメッセージが分岐するのでややこしいらしく、説明も長い)…とあり、これらをCPUプログラムとして配線・論理合成するところまで説明されているので、FPGA使いの人には十分わかりやすいであろう内容なんだと思います。わたしはFPGAの知見が無いので「ステートマシンの様子とか詳しく書かれているし、やればわかりそう」という次元の印象です。

MIDI外部回路の接続(5PINのコネクター)に関する説明の短い章もあります。

USB

本書の後半は、PC側からUSBを経由してARM CPUの搭載されたFPGAベースのMIDIデバイスを操作するために必要になるUSB-MIDI接続の部分に関する説明になっていて、まずはUSB通信の仕様について詳しくまとめられています。USBエンドポイントとは何か、USBインターフェースとは何か、といったレベルの解説からあるので、この分野の素人であるわたしでも読める内容でした。物理層は一般的な基板側にあって自前で実装する必要がないので、データリンク以上の話が中心となっています(実践的にもそれで十分そう)。なお本書で説明されるUSBは2.0です(2.0の仕様で十分実現可能であるようです)。

USBパケットの構成要素や、転送方式(USB-MIDIで使用するのはバルク転送とコントロール転送のみです)、USB接続状態の遷移、標準リクエスト、ディスクリプターなど、おそらくUSBハードウェア開発全般に通じる内容なので、ここは他の資料で勉強できそうな部分ですが、親切に書かれているので本書だけで読み進められます。USB-MIDIに関連する部分だけを勉強するには効率的かも? データパケットの説明も含まれているのですが、エラーを明示的に返す場合に実装する必要があることを踏まえてのものです。

USB-MIDIはオーディオクラスのサブクラスとして標準で規定されているため、USB標準に準拠してデバイスを実装すれば、ドライバーを自分で実装する必要が基本的にはなくなるということも説明されています(そのため、USB-MIDIの章ではソフトウェア実装の説明がほとんどありません)。

USB-MIDIの仕様

USBの説明が終わるといよいよUSB-MIDIの仕様の説明に入ってきます(仕様についてはUSB-IFで規格化されているので、この本でなくても学べることではあります)。冒頭から、1本のUSB仮想ケーブルで16本のMIDIケーブルを扱えるという話があって、なるほど確かにこれでMIDI IN / MIDI OUTが8組処理できるな…という発見があります。

前章ではUSB標準の一部としてデバイスディスクリプターを送信する部分を実装する必要があることが説明されており、この章ではUSB-MIDIデバイスのディスクリプターに求められる内容としてポート数や接続に関するトポロジーがあり、それらをどう記述するか、といったことが説明されます。

それからUSB MIDIストリーミング インターフェース(USBのインターフェースの何たるかについては前章で説明があります)でやり取りされるUSB-MIDIのイベントパケットの形式の説明を経て、USB-MIDIデバイスディスクリプターの内容のうち固定値のある部分についての割と長い説明を経てこの章は終わりです。ほぼ仕様のみの話です。

USB-MIDIの実装

ここまでの説明(どれも必要なやつ)を経て、ようやくこのUSB-MIDIを筆者がどう実装されたか説明されています。前半はUSB-MIDIディスクリプターの内容(固定値でない部分)、後半はUSB処理を行うファームウェアで実装されているコードの説明です(使用するマイコンによって実装が変わるので擬似コードのみ)。USBエンドポイントのメッセージ処理は割り込みハンドラー(そういえばこの辺の基礎的な単語はわからないと読めない気がする)として実装され、標準で必須になるEP0とMIDIイベントの送受信に使われるものとで2つあります。EP0のほうも説明がありますが、ファームウェアによってはほぼ実装が丸投げできそうで、Zynqではもろもろ丸投げできたようです。MIDIイベントのほうは、USBメッセージは受信したら即応しないといけないという仕様の都合上、一度リングバッファーにenqueueすることになりそうです(本書の実装ではそうなっています)。

リングバッファーのdequeueはファームウェアのmain関数の中でループ処理で行われ、dequeueされたメッセージはAXI-MIDIの回路にMIDIイベントとして書き込まれます。一方で、MIDI入力メッセージが合った場合には、このループの中でAXI-MIDI回路の対応レジスタの状態をチェックして、メッセージありとなっていたらUSB MIDIメッセージに変換して入力側としてのリングバッファーにenqueueするようです(これはUSBホスト側がfetchするまで保持することになるでしょう)。

…といった全体的な処理の流れが、本書を読んでいくとわかります。MIDIトランスポート、USB、USB-MIDIに関しては素人だったわたしでも読めるレベルでまとめられていて親切な本です。

MIDI 2.0で変わること

さて本書は当然ながらMIDI仕様を前提に書かれていて、MIDI仕様といえば1980年代に策定されたものなのですが、2019年になって、38年ぶりにこの仕様に変更を加えたMIDI 2.0と呼ばれる仕様が議論されつつあります。MIDI 2.0には、MIDI 1.0を前提としたMPE (MIDI Polyphonic Expression)やMIDI-CI (Capability Inquiry) といった既成の仕様に基づく機能拡張も含まれているのですが、他にもMIDIメッセージの拡張やチャンネル数の拡大など、全般的にモダンな内容になる予定です。

www.midi.org

www.dtmstation.com

MIDI 2.0の時代になるとMIDI 1.0にのみ対応したデバイスは使えなくなる、ということはなく、MIDI 2.0はMIDI 1.0と基本的には後方互換性を維持した仕様になるようです。たとえばMIDI-CIでは双方向的なメッセージングが必要になるわけですが(MIDI 1.0にはリクエスト/レスポンスという概念がありません)、MIDI-CIに基づくメッセージをデバイス側が理解しない場合にはレスポンスが返ってこないわけで、その場合はホスト側はMIDI 1.0を前提としたメッセージを送ることになります。その場合でも、MPEのメッセージはMIDI 1.0の形式で送信できるので、たとえば未来のMPEデバイスはMIDI 2.0の形式でメッセージを送信しつつ、2019年時点で現存するROLI BLOCKS(MIDI 2.0を解さない)にはMPEに基づくメッセージを送信する、といった処理の分岐が可能です。

この意味で、MIDI 1.0のみを対象とするUSB-MIDIデバイスの開発に関する本書の内容は、まだ十分に役に立つと言えるでしょう。本書では入出力の双方が実装されていることがうかがえるので、MIDIメッセージを受け取った側でMIDI-CIに基づくリクエスト/レスポンスを処理出来る可能性は十分にあります。おそらくメッセージングは単発のリクエスト/レスポンスで処理可能で、何らかの状態管理を必要とするものではないとは思いますが、MIDI-CIのProfile ConfigurationとProperty Exchangeがどんな内容になるのかは見ておいても良いかもしれません。AppleがCore MIDIでMIDI-CIをサポートしています。

もっとも、MIDI-CIのサポートだけではMIDI 2.0に対応できているとはいえません。MIDI 2.0仕様には、新しくUniversal MIDI Packet(以降UMP)と呼ばれるパケットのフォーマットが含まれています。これは最大128ビットのメッセージを含むパケットであり、MIDI 1.0の範囲を超えるものです。MIDI 2.0ではこれをチャンネルボイスメッセージに適用して高分解能のメッセージ(コントロールチェンジが128段階から65536段階になったものを想像してください)のやり取りが可能になります。MIDI 2.0対応デバイスであるためには、UMPを処理できるようになる必要があるでしょう。もっとも、高分解能のメッセージであっても、MIDI 1.0の機能にマッピングされる範囲では、精度を落として7ビット値(ピッチベンドなら14ビット)で送信する等の措置がとられるようです。

また、MIDI 2.0のUMPにはJitter補正のためのタイムスタンプを含めるようになったようです(フォーマットの詳細は公知情報からは不明です)。これまでソフトウェアのレベルで処理されていた(と思われる)タイムスタンプ補正がMIDIメッセージでやり取りされるハードウェアのレベルで要求され、メッセージのバッファリングの実装が影響を受ける性質の仕様であるかもしれません。ordered queueに実装させられるのはちょっと嫌かも…?

また、チャンネル数が拡大されて、ユーザー的には最大256チャンネルまで利用できるようになるのですが、これは16のグループごとに16チャンネルを操作できるようにUMPが設計されている、というアプローチになっていて、これはもしかしたらUSB-MIDIのインターフェースがそのまま使えるということなのかもしれません(詳細は要確認ですが)。MMAはUSBの仕様を策定できる立場にはないので(USBの仕様を決めるのはUSB-IF)、MIDI 2.0では可能な限りUSB-MIDIの仕様がそのまま使えるような仕様を目指すのではないかと思います(想像)。

…とまあ、いろいろと考慮事項が増えるようですが、MIDI 2.0はまだ仕様策定中であり、実装したデバイスも無ければMacOSのMIDI-CIサポート以外は何もない状態なので、まだまだ未来形の話と考えても良いでしょう。


コメント

mmitti(青ペンギン) — 12/14/2019 15:05:40

この度はご丁寧に記事にしていただいてありがとうございます。 元は大学の授業で作ったreface DXの取説だけ見て中身を想像して作ったFM音源を家で動かすというのを目標にした周りを整備しつつ同人誌にした感じです。 とりあえずはFM音源の解説まで行きたいのですが、多分数年規模になりそうです。 ちなみにUSBオーディオの部分は来年の秋くらいに出せれればいいなと思っていたりしますが、間に合うのか.. 同人誌の方は設計がいろいろ残念な状態であわてて仕上げたので、例えばUSB MIDIのパケットフォーマットと自作回路で受け取るフォーマットが違うせいでCPUで無駄に変換したりとまだまだ改良できるところがあったりします。 FPGAの方を端折っているのはFPGAメーカーによって開発ツールの依存が高いのと、開発者人口が少ないので、あまり細かく書いても仕方がないだろうということで割とふわりと書いています。 おまけにUSBのファームウェアの処理もFPGAボードに乗っているCPUに依存していたので疑似コードになってしまったわけです(CPUに乗ってるUSBコントローラーのドキュメントがほぼなくてつらかった)。 本書の方で物理層ICと書いていましたが、ここら辺の話がUSBの仕様書の方にはあまり書いておらず、(仕様書的にはバスインターフェース層に相当)ICチップの方でPHYと名前がついて発売されているみたいです。 まぁ物理層ICと名前がついていますが、電気信号を作るほかに簡易的なエラー訂正とかもしてくれるという感じですね。 USBの仕様的には3層に分かれていてバスインターフェース層にデータリンクと物理層が入っているという感じだと思います。(軽くしか調べていないので間違っていたらすいません。) USB2.0も仕様が固まったら追いたいところですけど、Windowsに標準ドライバーが来てからかなと思っていたりします(デバイスドライバーは書きたくない) USBオーディオ、箸休めでファミコン音源(のくせに128音16チャンネル対応)、昔作った怪しいFM音源、SoundFontやUTAU音源の読み込みなど壮大な計画はありますので次回以降もお楽しみにしていてください。 と思ったことを適当に書かせていただきました。 質問等がありましたらメールやTwitterなどで気楽にお願いします。 あと、サポートページの方にこちらのリンクを掲載してもよろしいでしょうか?

atsushieno — 12/15/2019 22:46:49

や、詳しくコメントいただきありがとうございます。 MIDI 2.0については、(本文でもちょっと言及した)ADC2019でMIDI Manufacturers Associationのブースでプラットフォームサポートについて質問したら、MSもMIDI 2.0の存在は認知している(具体的な話は何もない)、という感じだったので、まだしばらく放置しておいても大丈夫そうです(わたしもドライバ自作はやりたくないなーと思います)。 いったん汎用オーディオデバイスが出来ると、その上でいろいろ動かせるソフトウェアが出てくるので、いろいろ可能性が広がりますよね。FM音源やFC音源のエミュレーターの類もそれらを操作するモダンな音源ドライバも、ARM CPUで動くものはいけそうですし、次回以降でどんな実装が加わってどんな感じに解説されるのか楽しみにしています。 完成したらまたぜひ技術書典で音楽技術書のカテゴリーを賑やかしてください…!

atsushieno — 12/15/2019 22:49:44

あ、すみません書き忘れましたがリンクはぜひご自由にお願いします〜

Footnotes

  1. もちろんイベント自体のルールや行動規範はあるわけですが

  2. ハードウェア制作費は…ゲフンゲフン

  3. まあCQ出版あたりでしれっと出ていてもおかしくはない気もしてきました…

  4. ちなみに本書では物理層となっているのですが、わたしにはデータリンク層にも見えるというか、どこまでが物理層といえるのかOSIモデルよくわからん…という感じです。


この記事を共有:

前の記事
オーディオプラグインの理想的なGUIフレームワークを模索する
次の記事
JUCEモジュールを作って外部ライブラリを参照する