Arduino で YAMAHA YM2151 を VGM ファイルで演奏させる

1990年代の多くのアーケードゲーム機に搭載されていた音源チップ YAMAHA YM2151 を Arduino からこの手でどうしても発声させてみたい。

電子工作を始めて Lチカもそこそこに製作を始めた”未来ガジェット”のひとつです。

結構前につくったものでしたが、どのように製作したか忘れぬよう github に Arduino スケッチと参考させていただいた資料・回路図のリンクを掲載してみました。

Play back the VGM format file with Arduino. (only YM2151)

https://github.com/h1romas4/arduino-vgmplayer

本スケッチでは VGM Format と呼ばれる、音源チップに流すデーターダンプ形式を、そのまま YM2151 に write して発声させる方式を採っています。

このことから Arduino のスケッチは 100行ほどの単純なものになり、まずは発声させてみたい方にはちょうど良い規模感のプログラムになっています。たとえば PSG を同時に鳴らしたい、なんて時も数行足してもらえれば実装できると思います。

演奏データとなる VGM ファイルは mml2vgm を使わせて頂き MML (Music Macro Language)で作成しました。MML の書き方は体が覚えていることでしょう 😀

https://github.com/kuma4649/mml2vgm

[概要]
このツールは、ユーザーが作成したMMLファイルを元にVGM/XGMファイルを作成します。

[機能、特徴]
[VGM]
・メガドライブ2台分の音源構成(YM2612 + SN76489 + RF5C164)*2にそったVGMを生成します。
(他にYM2151,YM2203,YM2608,YM2610B,SegaPCM,HuC6280に対応しています。)

github 上のサンプルは次のようにしてみました。(カエルの歌の3声輪唱です)

assets/vgmsaple.gwi

'@ M 110
   AR  DR  SR  RR  SL  TL  KS  ML  DT1 DT2 AME
'@ 022,005,000,004,005,041,000,001,005,000,000
'@ 016,008,008,008,002,000,001,002,005,000,000
'@ 031,018,000,004,010,044,000,008,009,000,000
'@ 031,009,007,008,002,003,001,001,009,000,000
   ALG FB
'@ 004,007

'X6 T160@110l4 r1r1r1r1 cdefedcrefgagfercrcrcrcrc8c8d8d8e8e8f8f8edc
'X7 T160@110l4 r1r1     cdefedcrefgagfercrcrcrcrc8c8d8d8e8e8f8f8edc
'X8 T160@110l4          cdefedcrefgagfercrcrcrcrc8c8d8d8e8e8f8f8edc

このテキストファイルを mml2vgm により .vgm 化して、Arduino のスケッチから PROGMEM で Flash メモリーに書き込んでいます。(music/vgmsample.h

曲の大きさによっては Arduino の 32KByte Flash に載りきらないため、作例では EEPROM を接続し書き込んだデーターを演奏させることもしています。(ちなみに EEPROM を単純に 1Byte 読みすると速度が追いつかなかったため、先読みのリングバッファのような実装を入れました)

ハードの方は Arduino UNO のシールドで実装しています。(まずはブレッドボードで動作を確認した方が良いと思います)

足の数に対して基板が結構小さく、おまけに全部ビニール線で繋いだため結構大変でした。。とはいえ、初心者の自分が、2日くらいハンダ付けをがんばれば完成しましたので、おそらくみなさまいけるかと思います。(部品は AliExpress で入手しています)

さて完成した機械から奏でられた音色は…

リーディングシュタイナー発動…!!!

苦労した甲斐もありまして、無事タイムリープに成功。 😀

子供の頃からゲームの音楽と言えば FM 音源で、なんとかいい音で聴こうと PC からラインを引っ張り出してステレオコンポに接続して、何度も何度も聴いていたことを思い出します。

この機械は、電源を入れればすぐ楽曲が奏でられますので「古の電子オルゴール」として現在も活躍中です。

Codenvy (Eclipse Che) で Spring Boot + Gradle ウェブプロジェクトを動作させる

ブラウザ版 Eclipse である Eclipse Che は、Docker を活用しさまざまな言語の開発環境をクリックひとつで構築でき、ブラウザから操作できる利点と合わせ「どこでも開発」が実現できるんじゃないかと思わせる、現在も活発に開発が進んでいる期待のプロジェクトです。 😀

今回、Eclipse Che の Saas である Codenvy を使って Spring Boot + Gradle ウェブプロジェクトを動作させるケースで、ハマりポイントや手間が結構ありましたので設定を記載したいと思います。

現在 Eclipse Che 上で Spring Boot + Gradle を動かそうとすると、いくつかの問題点があります。

  • Gradle (build.gradle) を解釈してくれないないため、ソースやクラスパスを通すことができない。 Eclipse でいうところの buildship 相当の実装がまだされていない。
  • IDE にインクリメンタルビルドが実装されてない(ですよね?)ため、Spring Boot DevTool のリロード機能を使うことができない。
  • Codenvy のリソースの問題か、ブラウザ上で動作する JS の問題か、結構フリーズする…

最後の問題はさておき、上の 2点は gradle を駆使してなんとかすることができましたので、Codenvy のログイン後からの手順を書いてみます。

Workspace の作成

プロジェクトを動作させるためのワークスペースを作成します。左メニュー Workspaces から Add を押下します。

SELECT STACK のフィルターで All を選択し、検索文字列に java debian を入力し “Java Debian” スタックを選択します。(2018/06/09 時点で CentOS を使っている Docker イメージを選択すると Workspace 開始がエラーになりましたので Debian にしています)

また、マシンのメモリーはデフォルト 2G になっていますが、3G まで無料で使えるようなので上げてしまってもいいかもしれません。

次に Spring Boot + Gradle (gradlew 入り)のソースコードを git から取得するため Add Project に git の Repository を指定します。

ここではサンプルで自分が公開している Spring Boot + Vue.js + Gradle + webpack のテンプレートプロジェクトを指定しています。

https://github.com/h1romas4/springboot-template-web.git

保存したら Create ボタンを押下してワークスペースを作成します。作成後、画面がワークスペースに遷移し Docker で環境が構築され起動し、git からリポジトリーからソースコードが取り込まれます。

build.gradle を修正し pom.xml を生成する

Eclipse Che は現在 build.gradle を認識できないため、このままであると .java はただのテキストファイル扱いで補完などができません。これを解決するため、Eclipse Che が扱える Maven の pom.xml を生成します。

Gradle に pom.xml を生成するプラグインがありますので、プロジェクトの build.gradle を次のように修正します。

maven プラグインを追加。(と maven プラグインが要求するため groud, version を追加)

plugins {
    id 'java'
    id 'eclipse'
    id 'maven'
    id 'com.moowork.node' version '1.2.0'
    id 'org.springframework.boot' version '1.5.9.RELEASE'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

次に、dependencies に使うバージョンを追記します。(Gradle の Spring Boot プラグインは指定したプラグインのバージョンから、依存関係のライブラリバージョンも自動で認識してくれますが、Maven プラグインからは参照できないため)

また合わせて、gradle build 時に pom.xml が自動的に生成されるようにタスクを追加します。(task createPom 以降)

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE')
    compile('org.thymeleaf:thymeleaf-spring4:3.0.2.RELEASE')
    compile("org.springframework.boot:spring-boot-devtools:1.5.9.RELEASE")
}

task createPom {
    description "Generates a pom.xml in the project root directory; useful e.g. for IDEs which can read POM but don't directly support Gradle."
    doLast {
        pom {
        }.writeTo("pom.xml")
    }
}

compileJava.dependsOn createPom

build.gradle の修正が終わったら、画面下部の Terminal から次のコマンドを入力し初期ビルドします。

$ cd springboot-template-web/
$ ./gradlew build
$ mvn package
$ ./gradlew build

mvn package の後に再度 ./gradlew build しているのは”おまじない”です。(pom.xml に刺激を与えることで Eclipse Che が Maven プロジェクトとして認識してくれるようです。この手順を確立するまでハマりました。。)

Eclipse Che が pom.xml を認識するとプロジェクトのツリーに External Libraries として無事 dependencies が入るはずです。

.java も Java ソースファイルとして扱ってくれ、補完なども効くようになります。

アプリケーションの起動

Spring Boot のウェブアプリケーションを起動するために実行構成を作成します。

Create new command から bootRun タスクを次のように作成します。

Command Line

cd ${current.project.path} && ./gradlew bootRun

Preview URL

${server.8080}

なお、それぞれの入力部分はマルチラインになっていますが、必ず 1行で書いてください。空行でも改行コードが混在すると Windows(のブラウザ)では動かなくなります。どうやら LF スプリットしているらしく Linux なら動作してしまうという…(ハマり2)

Save 後 RUN ボタンでアプリケーションが起動します。

タスクのビューの preview: 欄にある URL をクリックするとポート 8080 で起動したアプリケーションにブラウザから接続でき、実行を確認することができます。

なお、アプリの停止は画面上部右の「■」から行えます。

インクリメンタルビルドとリロード

この Spring Boot プロジェクトには Spring DevTool の依存関係が入っており、Eclipse ではソースを修正すると自動的にアプリケーションが再起動し、ビルドアンド確認が簡単にできるように設定されています。

残念ながら Eclipse Che はソース修正後に自動的にコンパイルは走らないようなので、bootRun しているとは別の gradle を使って、ウォッチとインクリメンタルビルドをしてあげます。

Terminal から次のコマンドを入力します。

./gradlew build --continuous

これでファイルウォッチに入りますので、.java ファイル修正でアプリケーションが自動的に再起動されるはずです。(停止は Ctrl + d です)

webpack ビルド

このプロジェクトは webpack/nodejs のビルドを使い、JavaScript を ES2015 としたり CommonJS を取り入れたりしています。 nodejs のランタイムは Gradle のプラグインにより自動的にダウンロードされるようになっていますので、上部メニューの Run から Terminal で新しいターミナルを開き次のコマンドを入力するとビルドがかかります。

./gradlew webpack

また、JavaScript の修正からの自動ビルドをするには次のコマンドを入力するとウォッチモードに入ります。

./gradlew watch

詳しくは「フロントエンド技術を導入した Java ウェブアプリケーション開発」をご覧ください。

さて、Eclipse Che にて .js を開くと…

おっ(ΦдΦ)!!という感じになりましたが、自分の環境ではこの後ブラウザが何度やってもフリーズしてしまいました。。いい感じに動きそうなだけに、無念。。

最後に

実際に Codenvy で Eclipse Che を使ってみるとフリーズも多くまだまだこれからといった印象ですが、今後はエディタ部が Eclipse Orion ベースのものから VS Code でおなじみ Monaco Editor になるなど改良が進んでいくようです。

個人的にはブラウザから使うより、Eclipse Che の REST API を活用して任意のクライアントから Docker 環境や language-server に接続できる方向にも発展してくれると嬉しいですが、継続してウォッチしていきたいと思います。

とりあえず、本手順でいろいろ検証できると思いますので、余暇にでもお試しください。 🙂

Arduino Pro Micro を使ってセガサターンのコントローラーを USB に変換する

Arduino Pro Micro の勉強も兼ねまして、セガサターンのバーチャスティックを USB HID 化して PC に接続できるようにしてみました。

使いました Arduino Pro Micro 互換機はこちらです。

KEYESTUDIO Pro Micro Atmega32U4 5V、ピンヘッダーを交換Pro Micro for Arduino

この機械は SparkFun  社が設計した本家の Arduino には存在しないラインナップで、KeyeStudio のはさらにその互換機になります。 1000円くらいなり。

ということで、まずは Arduino のボードマネージャーに以下の URL を指定して、SpackFun Pro Micro をボードに追加します。

https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json

ボードを追加したら書き込み対象の Arduino に、 SpackFun Pro Micro の 5V/16MHz を指定します。 vscode-arduino を使っている場合は、arduino board configuration が次のようになります。

デフォルトが 3.3V/8Mhz になるようですので要注意です。 この指定でもすんなり書き込めてしまうようですが、どんなプログラムを実行しても不明な USB デバイスになってしまう悲しい機械になってしまいます。(ちょっとはまりました…

また、Pro Micro に USB HID になるプログラムを書き込み、実行が始まると USB HID と COM ポートが OS に認識されますが、この際に COM ポートが書き込み時のものと異なるポートに配置され、次回のプログラム書き込みができなくなるケースがあるようです。 Windows であればデバイスマネージャから、どのように認識されたかを確認して、書き込みできない場合は COM ポートの設定を合わせてみてください。

特殊な操作として、起動中の Pro Micro の RST 端子を GND にちょいちょいと 2回落とすとリセットがかかり初期状態の COM ポートが 8秒間だけ現れる機能があります。

8MHz で設定してしまったなど、どうしても書き込みができなくなった場合は、コンパイルから書き込みに入ったあたりでリセットをかけ、出現した COM ポートめがけて Lチカなどを転送すると元に戻ってほっとします。 😀

てなわけで若干癖があるボードですが、無事セガサターンのバーチャスティックを USB 化することができました。

結線やソースコードは github に公開してみました。

Convert Sega Saturn controller to USB HID joypad using Arduino Leonardo / Pro Micro.

https://github.com/h1romas4/arduino-saturn-joystick

ジョイスティックデバイスとして認識したら、Windows では次の画面で動作確認をすることができます。

ボタンキーアサインは手持ちしていました HORI のファイティングスティックmini を真似てつくってみました。

ソースコードの次の部分でボタン番号を指定できますので、好みに変えてみてください。 0,1,2… が画面上 1,2,3… ボタン相当です。(9は存在しないボタン)

uint8_t buttonMap[3][4] = {
    { 4, 9, 9, 9 },     // L  -  -  - 
    { 6, 0, 3, 5 },     // R  X  Y  Z
    { 8, 1, 7, 2 }      // S  A  C  B
};

なるべく入力断面を合わせたり、遅延しないようにつくったつもりですが果たして…

違和感なく動作しているようなので、ザック島に急ぎます。3D プリンターでケースをつくろう。 🙂