Javascriptで音声と照明操作


Javascriptで照明を操作 [Cylon.js x Philips Hue]の続きです。

ちなみにこの辺のデモを次回のIoTLTでやる予定です。(みんな来てね!)

ブラウザで音声を受けて -> Milkcocoa -> Cylon.js -> Hueを操作って流れをやってみたいと思います。 やっぱりMilkcocoa使うと接続がめちゃ楽です。

WebAudioはp5.js経由で使ってみます。

p5.js is 何

http://p5js.org/
ビジュアライズとかが簡単にできるJSライブラリです。このライブラリはアート系の人がよく使ってるイメージです。

参考: p5.jsでProcessingのようにリッチなWeb表現を作るチュートリアル

グローバル汚染とかがあるから他のライブラリと共存させる場合は気をつけた方がいいかも。
とはいえサクッと使えるので便利です。

p5.jsで音を認識

内部的にWebAudioを使っててラップしてくれてるサンプルです。

サンプルがいっぱいあるのがいいですね。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.7/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.7/addons/p5.sound-min.js"></script>
    <script src="p5-audio.js"></script>
  </head>
  <body>

  </body>
</html>
p5-audio.js
var input;
var analyzer;

function setup() {
  createCanvas(710, 200);

  // Create an Audio input
  mic = new p5.AudioIn();

  // start the Audio Input.
  // By default, it does not .connect() (to the computer speakers)
  mic.start();
}

function draw() {
  background(200);

  // Get the overall volume (between 0 and 1.0)
  var vol = mic.getLevel();

  fill(127);
  stroke(0);

  // Draw an ellipse with height based on volume
  var h = map(vol, 0, 1, height, 0);
  ellipse(width/2, h - 25, 50, 50);
}

実行するとこんな感じで、声や音に連動して円が上下します。
大きい音をだすと、上にジャンプする感じですね。

var vol = mic.getLevel();の部分のvolが音量が入ってくるのでそのまま使えそうです。

p5.jsにMilkcocoaをつなげる

Milkcocoaのライブラリを読み込みます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="http://cdn.mlkcca.com/v2.0.0/milkcocoa.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.7/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.7/addons/p5.sound-min.js"></script>
    <script src="p5test.js"></script>
  </head>
  <body>

  </body>
</html>

コメントは追記した部分だけにしました。

p5-sound.html
var input;
var analyzer;
var milkcocoa = new MilkCocoa("{your-app-id}.mlkcca.com"); //追記
var ds = milkcocoa.dataStore('hue'); //追記
var counter = 0; //追記

function setup() {
  createCanvas(710, 200);
  mic = new p5.AudioIn();
  mic.start();
}

function draw() {
  background(200);
  var vol = mic.getLevel();
  fill(127);
  stroke(0);
  var h = map(vol, 0, 1, height, 0);
  ellipse(width/2, h - 25, 50, 50);
  //以下5行追記
  counter++;
  if (counter % 30 === 0){//Milkcocoa側の負担を考えて間引き
    console.log(counter);
    ds.send({vol:vol});
  }
}

p5.jsで何か作るときにbackground()の挙動でハマっていたdraw()とかの挙動の話をしたようなしてないような。
とりあえずdraw()の中は繰り返し呼び出される(requestanimationframeかな?)のでvolの値(音量)も繰り返し更新されます。

なのでds.send({vol:vol});で音量の情報をMilkcocoaに送ります。

ここからはCylon.js (Node.js)側

前回(Javascriptで照明を操作 [Cylon.js x Philips Hue])と同様に、Milkcocoaから受け取ったデータを元にHueを操作します。今回は音量に応じて明るくしてみましょう。

参考: https://github.com/hybridgroup/cylon-hue/blob/master/examples/brightness/brightness.js

参考: https://github.com/hybridgroup/cylon-hue/blob/master/lib/light.js#L132-L142

このCylon-hueのライブラリをみてみると、brightnessってメソッドがあって0~100で明るさを制御できるみたいです。p5.js側から送られるvolの値は0~1の間らしいので、調節して100倍にしています。

hue-sound.js
var Cylon = require('cylon');
var Milkcocoa = require('milkcocoa');
var milkcocoa = new Milkcocoa("{your-app-id}.mlkcca.com");
var ds = milkcocoa.dataStore('hue');
var hue;

Cylon.robot({
  connections: {
    hue: { adaptor: 'hue', host: '192.168.2.2', username: 'newdeveloper' }
  },

  devices: {
    bulb: { driver: 'hue-light', lightId: 1 }
  },

  work: function(my) {
    my.bulb.turnOn();
    hue = my;
  }
}).start();

ds.on('send',function(data){
  var level = data.value.vol * 100; //ここの数値はその場のうるささ?などで変えた方がいいかも
  console.log(level);
  hue.bulb.brightness(level);
});

実行してみるとこんな感じ。

動画もあります。 https://goo.gl/photos/iDftwcfdM1zbB19M6

まとめ

WebAudioの機能をブラウザ側で使っても、JS経由でサクッとHueとつなげられますね。

Node.jsでWebAudioのインターフェイス実装しているNode Web Audio APIがあるみたいなので、同じようなことできないか模索中です。