2013年3月22日金曜日

WebAudioとgetUserMediaをつかって外部入力にエフェクトをかける【JS】

最近Javascriptにはまっています。 HTML5ではハードウエアの機能にアクセスする手段が整い始めていて、加速度センサやマイク入力を使用することが簡単にできるそうです。

WebAudio
 WebAudioを使用すると事前に用意したオーディオファイルを再生するだけでなく、その場で波形を生成して再生することも可能です。近年ではこれをつかったおもしろいWebサイトが登場しています。

WebAudio Drum Machine
 実際にあるドラムマシンをシミュレートしたもの






RealTime Analyser
音声を解析してビジュアル表示したもの







他にもたくさんあるのですが、サンプルとして2例ほど紹介しました。

 WebAudioでは用意された様々なノードをConnectすることで波形を生成したり、フィルターやディレイをかけたり、フーリエ変換をかけて音声を数値化することも簡単にできてしまいます。

getUserMedia
 getUserMediaはクライアントのWebカメラやマイク入力を扱うことができます。これはWebブラウザを通してP2Pでコミュニケーションをとるということを目指しているようで、ドキュメントを見るとP2Pに関する関数などもあることがわかります。今回はVideoの入力は用いず、Audioのみ用いました。

実装の説明とか
 実装に関する説明はググってみれば詳しく乗っているサイトがあるはずなので見てみてください。今回私が参考にさせていただいたサイトさまを以下に載せさせて頂きます。

  1. WebAudio API 解説
  2. SlideShare WebRTC + WebAudio API = スーパーサイヤ人 by girigiribauer
  3. WebAudio: live input / Stoyan's phpied.com
作ったもの
  1. 聴覚遅延フィードバックの簡単なデモ
  2. 2012年のイグ・ノーベル章のスピーチジャマーっぽいものを作ってみました。
  3. 低い周波数のSin波を流すデモ
  4. 0〜30Hzの音を聞いた時に脳はどういう反応するか調べてみたくて作りました。
ぶっちゃけ1は先程示した参考サイトの3を2は参考サイト1のコードを一部改変したものなのでアレですが、WebAudioとgetUserMediaの連携あたりのコードが日本語で検索してもあまり出ないので誰かの参考になったらいいなということでソースコードを載せときます。

聴覚遅延フィードバックの簡単なデモ

HTML

JavaScript
 function fire(e, data) {    
    log.innerHTML += "\n" + e + " " + (data || '');
  }

  var audio_context;
  var volume;

  function iCanHazUserMedia(stream) {
    
    fire('I haz live stream');
    
    var input = audio_context.createMediaStreamSource(stream);
    volume = audio_context.createGainNode();
    volume.gain.value = 0.8;
    var delay = audio_context.createDelay();
    delay.delayTime.value = 0.2;
    input.connect(volume);
    volume.connect(delay);
    delay.connect(audio_context.destination);
    
    fire('input connected to destination');
  }


  function changeDelayTime(value) {
    if (!delay) return;
    delay.delayTime.value = value;
    fire('DelayTime' + value);
  }

  function changeVolume(value) {
    if (!volume) return;
    volume.gain.value = value;
    fire('volume' + value);
  }

  (function init(g){
    try {
      audio_context = new (g.AudioContext || g.webkitAudioContext);
      fire('Audio context OK');
      // shim
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
      fire('navigator.getUserMedia ' + (navigator.getUserMedia ? 'OK' : 'fail'));
      // use
      navigator.getUserMedia(
        {audio:true},
        iCanHazUserMedia, 
        function(e){fire('No live audio input ' + e);}
      );
    } catch (e) {
      alert('No web audio support in this browser');
    }
  }(window));

低い周波数のSin波を流すデモ

HTML

JavaScript
  var audio = new webkitAudioContext();
  var osc = audio.createOscillator();
  var volume = audio.createGainNode();
  osc.connect(volume);
  volume.connect(audio.destination);
  osc.frequency.value = 12;
  osc.type = "sine";

  function show(data){
    log.innerHTML = "\n" + " "+(data || '');
  }

  function changeVolume(value){
    if(!volume)return;
    volume.gain.value = value;
  }
  
  function changeFreq(value){
    osc.frequency.value = value;
    show("Freq."+value+"Hz");
  }

  function play(){
    osc.start(0);
  }

マイク入力なんかは工夫すればギターのエフェクターの簡単なシミュレートなんかができるんじゃないかと思います。興味がある方挑戦してみてはいかがでしょうか。

2013年3月14日木曜日

SoundCloud APIでちょっと便利なプレーヤをつくる(2)

前回サービスの概要を説明したPlayLister for SoundCloudβですが、今回は実装過程について説明をしていきます。Playerについては解説が難しいので、はじめにプレイリストの読み込みについて説明します。

動作環境はChromeを想定しています。

コード
 以下に示すように記述することで実現することができます。

このようなHTMLに対してJavascriptは
function setPlaylist(){
  track_num_max = 0;
  var url_list=document.forms["form"].elements["playlist"];
  var tracks = url_list.value.toString();
  tracks.replace(/(^\s+)|(\s+$)/g, "");
  track_urls = tracks.split("\n");
  track_num_max = track_urls.length;
}
となります。

コード解説
 それでは一行づつ解説を行いたいと思います。

・一行目
 一行目は取り込んだ文字列を改行コードで配列化した際に配列の数を入れる変数です。他の関数でも使用するため、グローバル変数になっています。先頭にvarという接頭語をつけることによってローカル変数となります。

・二行目
 二行目ではTextareaのオブジェクトを取得しています。オブジェクトを取得することでJavaScriptから内部の値等にアクセスすることができるようになります。

・三行目
 三行目ではtracksという変数に先ほど代入したTextareaのオブジェクトutl_listの内容を.valueとすることで取得し、その値をtoString()関数を用いて文字列にキャストして代入しています。

・四行目
 四行目では取得した文字列の前後の空白を削除しています。

・五行目
 五行目では改行コード\nを区切りとして文字列を配列化しています。例えば
this
is
a 
pen

という入力があった場合
tracks[0]="this",tracks[1]="is",tracks[2]="a",tracks[3]="pen"
というように配列してくれます。

・六行目
 六行目は配列の数を取得して代入しています。

以上がTextareaからのプレイリスト取得についての解説です。次回は取得した文字列配列もとにJavaScriptでHTMLのTableを作成する部分の解説を行いたいと思います。

2013年3月11日月曜日

SoundCloud APIでちょっと便利なプレーヤをつくる(1)

今回は、SoundCloudという面白い音楽サイトで公開されているAPIを使って自作の機能を追加した音楽プレーヤを作ってみました。

SoundCloudとはなんだ?という人はこちらを読めば楽しさが伝わるかと思います。

どんな機能を追加するか
 今回は公式として用意されている”セット”をより使いやすいものにします。iTunes等で言えばプレイリストの機能になります。本家で提供されている”セット”はiPhoneアプリでは聞くことができません。せっかく作った最高のミックステープをiPhoneで聞けないなんて…!これも改善したいポイントです。

言語は
 SoundCloud APIはさまざまな言語で使用することが可能です。本家のDevelopersページを見ていただければわかると思いますが、Ruby、PHP、Python、JavaScriptを始めとしてiPhoneアプリに使用することもできます。今回は、単純なプレイリスト付きプレーヤの開発を目指しますのでどの言語でも対応できるのですが解説が豊富でiPhoneのブラウザからも利用できそうなJavaScriptを選択しました。

開発前の下準備
 今回はウィジェットの機能を拡張することでプレイリスト機能付きのプレーヤを実現します。公式で用意されているSoundCloud Widget API Playgroundというページを参考にしました。このページではウィジェットに関する関数が沢山使われています。これらの関数を使うために自分の作るページにapi.jsというファイルを追加します。
具体的には
<script type="text/javascript" src="api.js"></script>
と記述すれば良いです。
このファイルはhttps://w.soundcloud.com/player/api.jsから取得することができます。

β版公開!
 完成したプレーヤは現在http://monitorgazer.web.fc2.com/http://iitani.com/scp/scp.htmlで公開中です。今後は曲送り機能とプレイリストの保存と共有、ランキング機能を実装したいと思っています。iPhoneでは、Chromeブラウザで動作確認しました。

現状
 現状のシステムとしてはHTMLのテキストエリア要素に曲のURLを貼り付けると順に再生するようになっています。また、プレイリストのリピート機能、一曲リピート機能、プレイリスト無限シャッフル機能がついています。

現状での便利な使い方
 個人的に実装できてよかった一番便利な機能は一曲リピート機能だと思っています。ある曲にハマると永遠とリピートして聞くのですが、SoundCloudにはそのような機能がなかったので便利に使っています。
 プレイリストはページをリロードするたびに初期値に戻ってしまうので、Evernoteなどにプレイリストを書きだしておいて、簡単にコピペできるようにするのが良いと思います。そうすればiPhoneでも便利に使えるはずです。今はプレイリストを作成するのに曲のURLを調べる作業に一手間かかるため、改良の余地が有りそうです。

実装過程
 需要はあまりないかもしれませんが次回以降のエントリで書きたいと思います。

追記(2013/03/13)
 ブラウザはChromeを推奨しています。他にも要望があれば適宜対応する予定です。iPhone,nexus7にて動作確認を行ったところ音楽の再生にユーザアクションが必要という制約のため自動再生が動作しないことを確認しています。曲の切り替えはできますが自動再生に対応しておりません。改善を行なっていく予定です。