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を見た感じよくメンテナンスされているように見えるので、これでもいい気がする。

0

exiftoolでmp4のメタデータを編集する

exiftool 9.31だとメタデータ見るだけしかできなかったけど、9.76にアップデートしたら書き換えもできるようになってた。
exiftoolのサイトにもR/W可能って書いてある

% brew update
% brew unlink exiftool
% brew install exiftool
% exiftool video.mp4 '-title=これはまじでやばい'

mp4のメタデータはexiftoolで読めることからもexifを使っているのだ、とてっきり思っていたけど、XMP(extensible metadata platform)というXML形式を使っているらしい。

それの読み書きもサポートしているexiftoolってもはやexifでもなんでもないなと思った

0

テストがあるとプルリクしやすい

印象としてそんな感じがする。

だいたいプルリクする時って、バグを見つけて直すのはすぐできるんだけど、自分の修正が何か別のところで副作用を起こしているかもしれない、という不安があってグダグダ色々検証したり他の部分のコードも一応読んだりする時間の方が長いと思う。
そういう時にとりあえずテスト通っていれば、テスト書いたリポジトリ主がokしているような気になってくるから、すぐプルリク出せる。

なるべくrake testとかnpm testとかコマンド一発実行すればテストが走るようにしておいてくれるとプルリクしやすくてうれしい。

プルリク受け入れる側も、Travis CIとかでプルリク自体にテスト通過しましたバッジがついていると安心感がある。


テストの書き方色々ある

去年からnode.js使い始めて、色々作ってるんだけどテストの書き方色々ある気がするのでメモしておく。
具体的な書き方は各リポジトリの中見ればわかる。


テストが書きにくいものは内部ライブラリのテスト書く

UIとか画像処理のテストとか書きにくい。
あとhubot scriptのテストの書き方がよくわからない。robot.respondとか、ユーザーの入力にフックしてるようなのの書き方がドキュメントどこ探しても見つからなかった。

hubot-rss-readerの場合、rss-checkerという内部ライブラリをhubot scriptと別ファイルに作っておいて、mochaでテスト書いた。hubot scriptの方はテスト書いてない。
それをgrunt-simplemochaで実行できるようにして、さらにgrunt testをnpm testから実行できるようにしている。package.jsonのscriptsにコマンドが書けるので便利。

{
"name": "hubot-rss-reader",
"private": false,
"version": "0.6.5",
"description": "Hubot RSS Reader",
"main": "scripts/hubot-rss-reader.coffee",
"scripts": {
"test": "grunt test" (注:これがnpm testで実行できる)
},
(略)
.travis.ymlを置いて、GitHubからTravis CIへのフックを設定すればgit pushしたりプルリク受けたりするだけでTravis CI上でnpm testが走るようになる。


アカウント情報を暗号化してTravis CIに保存できる

gyazo-api npmのテストでは、毎回gyazoに画像をアップロードしてリスト取得して削除している。
oauthのaccess tokenが必要なので、travis encryptしてtokenを保存している。

% travis encrypt GYAZO_TOKEN=a1b2cde --add env
これを実行すると.travis.ymlに環境変数を暗号化して保存できる。

language: node_js
node_js:
- '0.10'
env:
secure: asdfadajowejfoaiwejfoawiejfpaiup(暗号化されたtoken)

Travis CI: Environment Variables


ローカルで実行する時は普通に環境変数でtokenを渡せばtest実行できる。
% GYAZO_TOKEN=a1b2cdef npm test


サーバーでtest実行できない時は、lintだけでもかけておく

というかlintは設定するコスト低いので全てのプロジェクトでかけるようにはしている。

testできないものの例としては、node-ble-firmataはあらかじめ特別なファームウェアを書き込んだBLE付きArduinoを用意する必要があるので、これはどうやってもTravis CIでテスト実行できない。
しょうがないので、testは手元でやるとして、CIではcoffee-lintだけかけておく。coffeeはわりと文法間違える人いるのでlintだけでもあるとなんか安心感が違う。

普通にnpm installするとbluetooth関係のnpmをインストールしようとしてCライブラリが無くてTravis CIではビルド失敗するので、devDependenciesだけワンライナーでインストールするようにした。

language: node_js
node_js:
- '0.10'
install: node -e 'console.log(Object.keys(require("./package.json").devDependencies).join(" "))' | xargs npm install
script: npm run lint
これでnpm run lintだけが実行される。

ちなみにnpm install –devしたらdevDependenciesだけインストールできそうだったんだけど、依存解決が無限ループして20分ぐらいインストールし続けて終了するのでやめた。


複数の言語でテストする

socket.io-client-simple gemなんかがそうで、nodeで立てたsocket.ioサーバーにrubyで接続して通信できるかテストをしている。

.travis.ymlでメイン言語をrubyにして、それとは別にnodeのバージョン指定をするとrubyもnodeもインストールされる。npm installはbefore_scriptのタイミングでやると、gemのインストール→npmのインストール→rake test実行 という順番になる。
language: ruby
node_js:
- '0.10'
rvm:
- '2.1.2'
before_script:
- npm install


slackに通知する


Travis CI: Configuring Build Notificationsに書いてあるが、slackでtravis integrationを追加してtokenを取得してから、

% travis encrypt "[account]:[token]" --add notifications.slack

で.travis.ymlに通知設定が保存される。CI終わったらslackに通知が来る。


その他

あとは、READMEにサンプルコードの実行方法を書いておいたり、基本的な機能がすぐ試せる実行コマンドを付けておくとissueとかのトラブルシュートに役立つ。なんかきかれたら「〜〜を実行できる?」とか質問しやすい。

coffee-lintで1行の文字数が最大80文字という設定がデフォルトになってるけど、80文字というのは昔のパンチカードの文字数が80文字だったからMacとかのターミナルの横幅もデフォルト80文字になって未だに引きずっている意味のない数値らしいので、80文字にこだわる必要はない。
むしろ長いURL文字列を作る時とかに書きにくくなる。coffee-lintでは0を指定すると制限解除できる。

    coffeelint:
options:
max_line_length:
value: 0

0

RICOH THETAのシャッター音を消す

http://npmjs.org/package/ricoh-theta

音量設定オプションをthetaコマンドに付けた。
THETAにWiFiで接続してから

% npm install ricoh-theta -g
% theta --volume 0

0x502C AudioVolume | RICOH THETA Developersを使って設定している。


初期型の2013年モデルはシャッター音が消せないという公式見解だけど、消せた。去年ファームウェア入れた気がするのでそのせいかもしれないけど。


0

Node.jsでRICOH THETAを操作する

node.jsでRICOH THETAを操作できるnpmを作った。nodeが入ってるMacやLinuxをWiFiでTHETAに接続して使う。

https://github.com/shokai/node-ricoh-theta
https://www.npmjs.com/package/ricoh-theta

不具合・質問などはtwittergithubのissueにお願いします。


ネットを探した感じだと、thetaのシャッターを切るコード片は色々な言語で実装されてた。
でもそれらはちゃんとPTP-IPのコネクションやセッションを管理せず撮影命令のパケットを送るだけなので、撮影した写真を吸い出したり、リスト取得、削除はできない。
そこでptp.jsにそれらの機能を追加して、それをさらにラップしてricoh-theta npmを作った。


インストール

グローバルにインストールするとthetaというコマンドが使える。
% npm install ricoh-theta -g
% theta --help


crontabに
* * * * * theta --capture tmp.jpg && open tmp.jpg
とか書いて大きいモニタに表示しておくだけで結構おもしろい。


ライブラリとして使う


もちろんライブラリとしてもこんな感じで使える。
var Theta = require('ricoh-theta');

var theta = new Theta();
theta.connect('192.168.1.1');

// capture
theta.on('connect', function(){
theta.capture(function(err){
if(err) return console.error(err);
console.log('capture success');
});
});

// get picture
theta.on('objectAdded', function(object_id){
theta.getPicture(object_id, function(err, picture){
fs.writeFile('tmp.jpg', picture, function(err){
console.log('picture saved => tmp.jpg');
theta.disconnect();
});
});
});
取得した写真はbufferなので、ファイルに書き出さずにそのままhttpで配信するとかも容易。

captureからのコールバックで撮影したオブジェクトのIDを受け取るのではなく、objectAddedという別イベントにしてある。PTP-IPがそれらを別に扱っているのでそうした(今後のTHETAでどっちが先に発火するか、逆になる可能性あるし)
この書き方だと、APIに接続していればリモートシャッターではなく本体の撮影ボタンを自分で押して撮って、オブジェクト追加通知をnodeで受けて写真を吸い取るという事もできる。

そんなわけで、最初は接続→撮影→取得っていう手続きすればいいんだからPromiseでやろうと思ったけど、socket.io風のインタフェースに落ち着いた。

PTPではオブジェクトIDのほかにストレージIDというのもあって、これは例えばデジカメで内蔵メモリとSDカードとを切り替えて使う時に指定するためのIDなんだけど、thetaは内蔵メモリしかないから常にID:1が使われている。
もし今後マイクロSDを追加できるTHETAがでてきたら、APIを変えると思う。




ptp.jsへの追加分はプルリクしておいたんだけど、今のところricoh-theta npmがインストールするptp.jsは俺のgithubのread_dataブランチからインストールするようになっている。
(2015年1月31日:mergeされたのでnpmjs.orgから普通にインストールするようにした)

nodeって、マイナーなプロトコルの基本実装がnpmになっている事が多かったり、変更が本家にmergeされていなくても言語のパッケージマネージャがgithubから依存解決できたりというのがすごい良いと思う。