0

Arduino MicroをUSB MIDIデバイスにする

MIDIデバイスを自作し、ブラウザのWeb MIDI APIと通信した。
rkistner/arcoreを使ったら簡単にできた。

もともとLeonardo以降のATMega32U4を使っているArduinoはMPU内にUSB機能が内蔵されていて、その部分もプログラマブルなのでキーボードやマウスにしたりとかできる。

セットアップ


% git clone git@github.com:rkistner/arcore.git
% cd arcore/
% ./install.sh

~/Documents/Arduino/hardware/arcore にシンボリックリンクが貼られる。Arduino IDEを再起動するとターゲットボードが増えてるので選択する。



プログラムを書く


analogReadでセンサーを読んでMIDI channel1にコントロールメッセージを送る。analogReadは10bitだがMIDIデータは7bitなので下3bitを捨てる。
MIDIEventの0x0Bはコントロールメッセージという意味。0xB0は10110000で下4bitの1〜16でMIDIチャンネルを表すので論理和する。(0から始まるので、この場合チャンネル2になる)
3、4番目の引数は7bit(0~127)ならなんでもいい。
void setup() {
}

int an;

void loop() {
an = analogRead(0);
if(MIDIUSB.available()){
MIDIEvent e = {0x0B, 0xB0|1, 10, an>>3};
MIDIUSB.write(e);
}
}

ChromeのWeb MIDI APIがちょうどコントロールメッセージをonmessageイベントで受信できるので、ブラウザからMIDIデバイス化したArduinoのセンサーが読めるようになった。
http://shokai.github.io/WebMidiAPIStudy/dump/

関連:AndroidタブレットでWeb MIDI API


USBシリアル通信と併用もできる。ブラウザにMIDIデータが流れるし、同時にArduino等のシリアルコンソールを開くとそっちにも数値が流れてくる。
void setup() {
pinMode(13, true);
Serial.begin(9600);
}

int an;

void loop() {
an = analogRead(0);
if(MIDIUSB.available()){
MIDIEvent e = {0x0B, 0xB0|1, 10, an>>3};
MIDIUSB.write(e); // MIDI送信
}
Serial.println(an); // シリアル通信からもAD変換器の値を送ってみる

// 動作確認用にLEDを点滅させる
digitalWrite(13, true);
delay(100);
digitalWrite(13, false);
delay(100);
}

0

ブラウザ/NodeでKORG nanoKONTROL1/2を使えるライブラリをES6で作った

作った。

https://www.npmjs.com/package/korg-nano-kontrol

% npm i korg-nano-kontrol -save

ブラウザならWeb MIDI APIで、Nodeならmidi npmでMIDIコントローラと通信するようになっているのでrequireすればあとは適当に動く。
あと、最初coffeeで書いて全部完成したんだけどbabel(ES6)で書き直してみた。というのもES6は前々から使ってみたかったんだけど、1から機能を1つずつ勉強するのは苦手なので、既に慣れてるcoffeeの機能をフルに使ってある程度の大きさの物を実装してからES6で書きなおす事で色々な機能を一気に使わざるを得ない状況を作って勉強してみた。

KORG nanoKONTROLとは

EdisonとMIDIコントローラでHueを調光する
とか
Node.jsとMIDIコントローラでHueを調光する
で使っている便利なMIDIコントローラー。ツマミとスライダーがたくさん付いている。

もともとkorg-nanoというライブラリがある

んだけど、nanoKONTROL2に対応していなかったのと、修正しようにも2つのデバイスに対応するなら1から作ったほうが早そうな設計だったのでついでにWeb MIDI APIにも対応させて作ってみた。

使いやすかったのでAPIはほぼそのままにしてある。

使う


connect()するとPromiseが返ってくる
var nanoKONTROL = require('korg-nano-kontrol');

nanoKONTROL.connect()
.then(function(device){
console.log('connected!' + device.name);
// do something
})
.catch(function(err){
console.error(err);
});

で、

device.on('slider:0', function(value){ // スライダー0番を取得
console.log("slider:0 >>> "+value);
});
とか
device.on('knob:*', function(value){ // 全ノブ取得
console.log(this.event+' => '+value);
});
とかすると取れる。



Web MIDI API

ブラウザでもBrowserifyで固めれば同様に使える



EventEmitter2

EventEmitter2にはワイルドカードでイベントを受け取れる機能がある。上でdevice.on(“knob:*”, func)とかやってるのがそれ。

ES6ではclass nanoKONTROL2 extends EventEmitter2して、コンストラクタの中でsuper({wildcard: true, delimiter: “:”})したら有効になった。


coffeeからbabel(ES6)に書き直した

簡単に感想を列挙すると

coffee-scriptよりは機能が少ない。
coffeeのfor k,v of objでkey/valueを回せるのと、do (arg) ->でクロージャ即時実行と、添字付きfor文と後置if文が使いたい。
でもfor ofはES6組み込みクラスのMapをイテレータでfor [k,v] of Mapすればいいし、doはletがあれば必要ない。

unlessがほしい。ifに!つけるのつらい。
関数宣言する時にexport付ければexportできるのは便利。
テンプレート文字列もよい。
[3…8]みたいなのはlodashの_.range(3,8)で代用できる。
関数のデフォルトパラメータ指定便利。
classは違和感なく書ける。getter/setterやstaticの定義も便利。
for(let i of array)を使うとnode 0.12やChromeでは動くけど0.10やSafariでは動かないJSができる。Symbol is not definedエラーが出る。

coffeeで書くのに比べてコード量は1.3倍ぐらいになる。
でもまあ、node 0.12以上で動かすならどっちで書いてもいいかなという感じがした。
古い環境をターゲットにするならcoffeeの方が安心感がある。

ESLint

lintツールにESLintを使ってみた。coffee-lintより色々しっかり見てくれてる気がする。

.eslintrcを置くと全ルールがカスタムできてよい。

parserにbabel-eslintを指定するとES6がlintできる。


gruntやめてnpm runにした

参考:Grunt/Gulpで憔悴したおっさんの話 – MOL

grunt-babelが複数ファイルの変換設定がかっこよく書けないのと、gulpがやはり理解不能なのでコンパイルはbabel –watchでいいやと思った。

parallelshellで複数コマンド同時実行できるので、esw(eslint-watch)も一緒に実行してる。

あと、npm2.0からnpm run コマンド名 — 追加の引数という感じに–を挟むと引数を追加して実行できるので、babelのビルド設定をそのままに–watchを追加して実行できてよい。

watchという続けて書いたコマンドをファイル更新監視して実行してくれるnpmもあるんだけど、なんか反応が遅いのでeslint-watchとbabel –watchで良いやとなった。これだとEdison上でもサクサク動いて良い。
package.json
  "scripts": {
"test": "eslint src/*.es6 src/*/*.es6",
"build": "babel src/ --out-dir lib/ --source-maps inline",
"watch": "parallelshell 'npm run build -- --watch' 'esw src/ --watch'",
"buildSample": "browserify --debug samples/webmidi/src/main.js -o samples/webmidi/dist/bundle.js"
},

0

EdisonとMIDIコントローラでHueを調光する

これ
Node.jsとMIDIコントローラでHueを調光する

Macminiにつないで常用してたので、けっこうアップデートしてる。
https://github.com/shokai/hue-korg-control

やっぱりスマホアプリよりも物理的なツマミやスライダーが複数あったほうが複数のHueを操作するのには向いてると思う

Edisonは起動が速くて、電源入れて10秒ぐらいでWiFiつながってsystemdに登録しておいたhue-korg-controlが起動して調光できるようになる。たまにnano KONTROLが認識されてないのでEdisonにUSBホストケーブル挿し直す必要あるけど


EdisonにUSB MIDIコントローラを接続する

EdisonにArduinoをUSB接続すると同じ要領で、USBホストケーブルを使ってkorg NANO KONTROLをつないだ。

使ってるUSBホストケーブルはこれ

もう売ってない初代nano KONTROL使ってるんだけど、2でも動くだろたぶん


alsaインストール

midiデバイスはNode.jsからだとmidi npmを使って制御する。中で使われてるRtMidiがalsaに依存しているので、opkgでインストールする

% opkg install alsa-lib-dev alsa-dev


hue-korg-control起動

shokai/hue-korg-controlをgit cloneしてnpm installしてnpm start


serviceとして登録する

Edison起動時にhue-korg-controlを起動するようにsystemdを設定した

/lib/systemd/system/edison_config.service とかを参考にした


/lib/systemd/system/hue-korg-control.service
[Unit]
Description=hue-korg control service
After=mdns.service

[Service]
ExecStart=/bin/su root -c 'cd /home/root/src/hue-korg-control && npm start'
Restart=always
RestartSec=10s
Environment=NODE_ENV=development

[Install]
WantedBy=default.target
環境変数を複数設定したい時は単純にEnvironment=を複数書けばいいらしい

% systemctl enable hue-korg-control  # 登録
% systemctl start hue-korg-control # 起動

rebootして起動してたらok


ログはjournalctlでtail -fみたいに見れる
% journalctl -u hue-korg-control -f

0

AndroidタブレットでWeb MIDI API

前:Node.jsとMIDIコントローラでHueを調光する

音楽やる気はないけどMIDIデバイスは入出力デバイスとして面白い。スライダーとかツマミとか色々あるし、MIDIで制御できるドラム叩きロボットとかもある。
とりあえず電子工作なしで買ってきたデバイス接続するだけでPCでもスマホでもWebブラウザから使えるというのは面白い。


Web MIDI API

Web MIDI APIはブラウザでMIDIデバイスが使えるHTML5のAPIで、現在はGoogle Chromeだけが対応している。
chrome://flags でWebMIDIを有効にし、MIDIデバイスを接続してからChromeを再起動する必要がある。
Chrome起動後にMIDIデバイスつなげても認識しないので注意。


試した

http://shokai.github.io/WebMidiAPIStudy/


Android版Chromeも対応しているので、USBホストケーブルでNexus7に接続して試してみた。
流れてきたデータを全部表示するだけだけど、Nodeのmidi npmで試した時とほぼ同じ手順でMIDIデバイスに接続できる。流れてくるデータもnode版はArrayでWebMIDIはUInt8Arrayなだけなので、MIDIデバイス用のラッパーライブラリ作るとしたらブラウザ・Nodeの両対応は簡単そう。



Mac版Chromeでも動く。Android版では取得できなかったデバイスのmanifacturerとnameプロパティがちゃんと取れた。


実装

https://github.com/shokai/WebMidiAPIStudyにある。

requestMIDIAccessはPromiseで使う
return if typeof navigator.requestMIDIAccess isnt 'function'

navigator.requestMIDIAccess()
.then (midi) ->
return new Promise (resolve, reject) ->
console.log "#{midi.inputs.size} input devices"
console.log "#{midi.outputs.size} output devices"
it = midi.inputs.values() # inputデバイスのリストがiteratorでくる
loop
input = it.next()
break if input.done
return resolve input.value # デバイス発見した
reject "input device not found"

.then (input) ->
console.log "Input Device found: #{input.manufacturer} - #{input.name}"
input.onmidimessage = (msg) ->
console.log msg.data # UInt8Arrayでデータが読める

.catch (err) ->
console.error err


気づいたこと


充電できない

AndroidではMIDIデバイスを使っているとUSBポートが埋まるので充電できない。Qiでなら充電できるかと思ったけどNexus5とNexus7ではMIDIと同時に充電は無理だった。


複数アプリから1つのMIDIデバイスを使える

Macでは複数のブラウザウィンドウで同時に1つのMIDIデバイスからのデータが読めた。またブラウザと同時にNode.jsからも使えた。
Macでは /System/Library/Frameworks/CoreMIDI.framework/MIDIServer が仲介しているっぽい。


参考になった

0

Node.jsとMIDIコントローラでHueを調光する

できた

MIDIコントローラ、安いしツマミとかスライダーがいっぱい付いてて便利だと思う。

ツマミで色相(hue)、スライダーでbrightness(輝度)を調整できる。
動画では使ってないけど横のボタンで彩度(saturation)を0にして真っ白にもできる。



ソースコード

これをgit cloneしてnpm installしてnpm startすれば起動する。
https://github.com/shokai/hue-korg-control

MIDIコントローラの制御にはkorg-nano npmを使っている。KORG nanoKontrolを操作すると”knob:1″とか”slider:3″とか”button:play”というイベントを発火させてくれるのでEventEmitterで受けるだけでいい。

Hueの操作は、nodeのhueライブラリにどうもしっくり来るものが無かったので1から自作した。HueのAPIは単純なのに、どれもなんだか過剰にwrapしすぎているように見える。
Web+DB Press vol.83でHueのAPIについては解説してて、それを見たらすぐ実装できた。


MIDIコントローラ

家にたまたまあったKORG nanoKontrolで操作している。nanoKontrolは絶版になってて中古で1万円ぐらいなんだけど、後継機のnanoKontrol2が3〜4千円ぐらいで売ってる。たぶんそっちでも同じように使える。

USB接続で、ドライバなしでMacに接続していきなり使えて便利だった。なんか便利っぽいのでもう1,2個ぐらいほしい。



NodeでMIDI

MIDIデバイスはUSBで接続できるやつも最近はたくさんあるみたいだし、ツマミ・スライダー・ボタンがたくさん付いているのでコントローラとして優秀だと思う。

Node.jsの場合はmidi npmでMIDIデバイスとやりとりできる。midi npmはRtMidiというMac/Windows/Linux対応してるC++ライブラリのラッパーなので、Raspberry Piとかでも動かせそう。

midiは大変簡単なバイナリプロトコルで、1byte(8bit)の1番上の1bitが1ならコマンド、0ならデータで、のこり7byteにコマンドやデータ内容が書かれている。
今回はkorg-nano npmを使っているが、midiデバイスをNodeで扱うとしたらこんな感じでできる。

EventEmitter = require('events').EventEmitter

midi = require 'midi'
debug = require('debug')('midi-device')

module.exports = class Device extends EventEmitter

constructor: (device_name=".*") ->
@input = new midi.input
for i in [0...@input.getPortCount()]
name = @input.getPortName i
debug "found device [#{i}] \"#{name}\""
if new RegExp(device_name, 'i').test name
debug "openPort #{i}"
@input.openPort i
break

## midi messageを受信
@input.on 'message', (delta, raw) =>
@emit 'message', {delta: delta, raw: raw}

device = new Device("keyboard")

device.on 'message', (data) ->
console.log data.raw


Rubyではmidi gemというのがあって、試してないけどgithubを見た感じよくメンテナンスされているように見えるので、これでもいい気がする。