hollywis's diary (はりうすブログ)

はりうすの活動日記です

クリスマスソングにあわせてLEDを光らせる話 | さいぞうのArduino初心者日記6

こんばんは。

さいぞうです。

この記事は、Arduino入門連載の6回目。

前回は、LEDを使ってモールス信号練習機を作った。

本来のチュートリアルからはかなり脱線してきたが、まあ面白かった。 hollywis.hatenablog.com

今回も脱線して、クリスマスなので、Soundcloudからクリスマスソングを取得し再生してそれに合わせてLEDをチカらせてみようと思う。

要はArduinoで簡単なオーディオビジュアライザを作る。

 
 

PWMでLEDの明るさを調整できる

一応、このセインスマートのチュートリアルに沿った連載として始めたのでやっておく。 http://www.sainsmart.com/starter-kits/uno-r3-smartkits/sainsmart-uno-r3-5v-servo-motor-starter-kit-with-basic-arduino-projects.html

今回やる4章のテーマは「PWM」。Pulse Width Modulationの略だ。

詳細はもうWikipediaでも見てください。 パルス幅変調 - Wikipedia

PWMで何ができるのかというと、LEDの例だと、これまで光らせるか光らせないかの2段階にしか制御できなかったのが、多段階でコントロールできるようになる!!  
 

こんな感じの回路を作って... f:id:hollywis:20151224164805p:plain

こんな感じのコードを書いて.... gist.github.com

実行すればこうなる! www.youtube.com

かんたん!

 
 

音に合わせてひからせる

これではすぐ終わってつまらないので、クリスマスソングにあわせて光らせてみよう。 音の出どころはSoundcloudにして、Ruby経由でArduinoに情報を送って光らせるという連携をしてみる。

 

Soundcloudの音楽を再生し、出力を数字にする

Soundcloudってのは音楽共有サイト。いろんな音楽を作った人が曲をアップしてて、皆が聞ける。

soundcloud.com

それだけじゃなく、APIが用意されていて、音楽を他のサイトに埋め込んだり、いろいろできる。

SoundCloud Developers

まず、ブラウザ上でSoundcloudの音楽を再生して、その音楽のパワーバーみたいのを出してみよう。 こちらのサイトに詳しいやり方があったので、これを丸パクリして、つくってみた。

電脳ゴリラ: Audio visualization using Processing.js

以下がHTMLにjavascriptのコードも入れたもの。

<h1>クリスマスソング!</h1>

power:<span id="show_power"></span>
<br />
<audio id="audio" controls autobuffer></audio>
<br />
<canvas id="canvas" ></canvas>

<script src="https://connect.soundcloud.com/sdk.js"></script>

<input type="hidden" id="sc_client_id" value="<%= VALUES['sound_cloud']['client_id'] %>" />


<script>
  var CLIENT_ID = document.getElementById('sc_client_id').value;
  var TRACK_URL = 'https://soundcloud.com/officialmichaelbuble/michael-bubl-its-beginning-to'; // 好きな曲のURL
  SC.initialize({
    client_id: CLIENT_ID
  });
  SC.get('/resolve', {url: TRACK_URL}, function(sound){
    if(sound.errors){
      // エラー処理
      for(var i = 0; i < sound.errors.length; i++){
        console.log(sound.errors[i].error_message);
      }
      return;
    }


    // SoundcloudのストリームURLを取得
    var audio = document.getElementById('audio');
    audio.crossOrigin = "anonymous";

    var streamUrl = sound.stream_url + '?client_id=' + CLIENT_ID;
    audio.setAttribute('src', streamUrl);


    // アナライザーを作る
    var audioCtx = new (window.AudioContext || window.webkitAudioContext);
    var analyser = audioCtx.createAnalyser();
    analyser.fftSize = 256;
    var source = audioCtx.createMediaElementSource(audio);
    source.connect(analyser);
    analyser.connect(audioCtx.destination);


    var showPowerElement = document.getElementById('show_power');


    var bytes = new Uint8Array(analyser.frequencyBinCount);
    var UNIT_COUNT = 80;

    var averagePower = 0;

    var draw = function(){
      analyser.getByteFrequencyData(bytes);
      averagePower = 0;

      for(var i = 0; i < UNIT_COUNT; i++){
        averagePower += bytes[i]
      }

      averagePower = averagePower/UNIT_COUNT;
      if(averagePower >= 255){
        averagePower = 254;
      }

      // 平均パワーを見せる
      showPowerElement.innerText = String(averagePower);
    };

    setInterval(draw, 500); // 繰り返し実行
  });
</script>

後でRubyを使う関係上、Railsでつくっているが、単にこの内容のHTMLファイルを作ってブラウザで読み込ませるだけでもうごくのではないか。  
 

注意点としては"var CLIENT_ID = document.getElementById('sc_client_id').value;"ってとこの=以降を自分のクライアントIDに入れ替えること。

クライアントIDが以下のURLからアプリ登録をすればもらえる。 http://soundcloud.com/you/apps/new f:id:hollywis:20151224170815p:plain

Ruby経由でArduinoに情報を送る

もうここの通りです。

Rubyでserialportを操作してArduinoを動かす - Laboratory of Scarlet

ただし、シリアルポートは私のmacの場合 /dev/cu.usbmodem1411 になった。

上記を参考に、WebブラウザからArduinoに数字を送るRailsアプリを作る。 RailsというのはRuby on RailsというRuby言語でできたフレームワークで、簡単に動的なWebサイトを作れる。 Rails自体のチュートリアルは下のサイトでも見てくれ。

Ruby on Rails チュートリアル:実例を使って Rails を学ぼう

 
Railsなので、SoundControllerというコントローラをつくり、serial_sendアクションに上のサイトのを参考にしたコードを書く。

class SoundController < ApplicationController
  def index

  end

  def serial_send
    @serial_port = "/dev/cu.usbmodem1411" #シリアルのポートを指定
    @serial_bps = 9600

    sp = SerialPort.new(@serial_port,@serial_bps)

    num = params["num"].to_i # 送る数字

    sp.write(num.to_s + '/') #serialへの書き込み "/"を数字の終了コードにした
    puts num.to_s

    render text: num
  end
end

 
ルーティングのroutes.rbにも以下のように設定

 get 'sound/serial_send/:num' => 'sound#serial_send'

 
これで、Webブラウザで例えば、

http://localhost:3000/sound/serial_send/50

というURLをいれると、50という数字がArduinoに送られる。  
 

ArudinoでRuby数字を受け取る

Rubyからというか、シリアルポートからデータを受け取るため、Arduinoのコードを以下のようにする。

gist.github.com

注意点としては、この辺を見て欲しいが、受け取った生データはasciiになっているってこと。

qiita.com

1バイトずつ受け取ったデータから48を引いて数字にして保存するとともに、前に受け取ったデータを10倍して前の桁のデータと解釈してる。

final_value=(final_value*10)+(received-48);

送るデータの最後には"/"をつけることにして、"/"がきたらその数字をLEDの明るさにしている。

ここまでのコードを合体!! 音楽に合わせてLEDを光らせる。

SoundcloudJavascriptRuby→シリアル通信→Arduinoって感じの情報の流れでさいごにLEDを光らせる

クリスマスソング!

URL here
<input type="text" id="sound_cloud_url" onChange="start_music()" />
<br />
power:<span id="show_power"></span>
<br />
<audio id="audio" controls autobuffer autoplay></audio>
<br />
<canvas id="canvas" ></canvas>

<script src="https://connect.soundcloud.com/sdk.js"></script>

<input type="hidden" id="sc_client_id" value="<%= VALUES['sound_cloud']['client_id'] %>" />




<script>
  function start_music(){
    var CLIENT_ID = document.getElementById('sc_client_id').value;
    var TRACK_URL = document.getElementById('sound_cloud_url').value;
    SC.initialize({
      client_id: CLIENT_ID
    });
    SC.get('/resolve', {url: TRACK_URL}, function(sound){
      if(sound.errors){
        // エラー処理
        for(var i = 0; i < sound.errors.length; i++){
          console.log(sound.errors[i].error_message);
        }
        return;
      }


      // SoundcloudのストリームURLを取得
      var audio = document.getElementById('audio');
      audio.crossOrigin = "anonymous";

      var streamUrl = sound.stream_url + '?client_id=' + CLIENT_ID;
      audio.setAttribute('src', streamUrl);


      // アナライザーを作る
      var audioCtx = new (window.AudioContext || window.webkitAudioContext);
      var analyser = audioCtx.createAnalyser();
      analyser.fftSize = 256;
      var source = audioCtx.createMediaElementSource(audio);
      source.connect(analyser);
      analyser.connect(audioCtx.destination);


      var showPowerElement = document.getElementById('show_power');


      var bytes = new Uint8Array(analyser.frequencyBinCount);
      var UNIT_COUNT = 80;

      var averagePower = 0;
      var previousPower = 0;
      var sendValue = 0;

      var draw = function(){
        analyser.getByteFrequencyData(bytes);
        previousPower = averagePower;
        averagePower = 0;

        for(var i = 0; i < UNIT_COUNT; i++){
          averagePower += bytes[i]
        }

        averagePower = averagePower/UNIT_COUNT;
        if(averagePower >= 255){
          averagePower = 254;
        }

        // 平均パワーを見せる
        showPowerElement.innerText = String(averagePower);

        sendValue = averagePower;
        if (Math.abs(previousPower-averagePower) < 10){ // 普通にやると変化がなさすぎてつまらないので、状態を持たせて変化を10倍する
          sendValue = averagePower + (previousPower-averagePower)*10
        }

        // ajaxでデータをサーバ側に送る
        $.ajax(
            '/sound/serial_send/'+sendValue
        )
      };

      setInterval(draw, 100); // 繰り返し実行
    });
  }

</script>

 
下記のコードで、Railsのサーバ側に音楽の出力の数字を送っている。

        // ajaxでデータをサーバ側に送る
        $.ajax(
            '/sound/serial_send/'+sendValue
        )

 
こんな風にうごく。

あとは、URLの入力欄を作り、そこにSoundcloudのページのURLを入力すると再生開始とともにLEDが光るというようにした。

youtu.be

今日はここまで。  

せんでん

忘れてたが、この記事の内容はこのキットだけを使ってやってます。

 
Arduinoとか抵抗とか全部入ってるからめんどくさい人はこれをかおう。


次回はこちら

第6章(予定)

総合もくじ

hollywis.hatenablog.com