LoginSignup
57
54

More than 5 years have passed since last update.

Web AudioでYoutube、itunes上の曲を元に、WebGL(GLSLシェーダー)でリアルタイムビジュアライズ

Posted at

WebGL Advent Calendar 3日目の記事です。初めて赤くなりました!


ブラウザで、Youtube上の曲を元にしてGLSL(WebGL)でリアルタイムビジュアライズします。応用編としてitunesの曲や自分の声でもできるようになりました。(無理矢理)

Web Audio APIのアナライザーノードというのは使ったことがなかったんですが、mdnのデモを見ていて、結構感度が良かったのでゴニョゴニョやってみる。

↓イメージ(canvasとvideoの二枚重ね)
スクリーンショット-2015-12-02-20.33.01.png

音のソースとしてYoutube(実際にはマスターのオーディオ)を使い、背景でも流しつつ、Web Audio APIで取得します。
その上にcanvasを置いて、WebGL経由でGLSLのシェーダーを置いていきます。
最後に音域データを料理して、シェーダーに反応させます。ビートを刻んでいる感じになりました。

何はともあれ、demoをご覧ください

音量によって変わるので、各自のマスターの音量を調節してください。かなり大きめで開発したので大きめがおすすめ。ちなみにミュートにして声を出すと声に反応します。

demo : https://hp0me.github.io/glsl_webaudio_visualizer/
(要Chrome or FF &マイク許可。光が良い感じになるようにボリュームを調整してください。)

code : https://github.com/hp0me/glsl_webaudio_visualizer

29g51155224222822233323233uurll3k3.gif

Web Audio APIのアナライザーノードで、曲を音域ごとに区切っていく

音はWeb Audio API(HTML5)のcreateAnalyser()で分析します。

そのデータを、
・音域の総和を色に変換する。
・音域を区切る。
・リズムを刻むようにうまいことオフセットをかける。

・WebAudioのアナライザー詳細
http://www.g200kg.com/jp/docs/webaudio/analyser.html

・曲はDave Crowe氏のビートボックス。この動画単体でもすごい
https://www.youtube.com/watch?v=Onr12llWDGo

https://mdn.github.io/voice-change-o-matic/
これをみていけるなと思ったんです。

このAPIに関して、MDNに詳細あり
https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/getByteTimeDomainData

WebAudioで音を区切る部分
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90; //最小値
analyser.maxDecibels = 0; //最大値
analyser.smoothingTimeConstant = 0.65; //落ち着くまでの時間

analyser.fftSize = 32; //音域の数
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);

var bufferLength = analyser.frequencyBinCount;

//↓の配列に音域ごとの大きさが入る
var dataArray = new Uint8Array(bufferLength);

var source;

//Youtubeの音を拾う
navigator.webkitGetUserMedia (
  {
     audio: true
  },
  function(stream) {
    source = audioCtx.createMediaStreamSource(stream);
    source.connect(analyser);
        getAudio();
  },
  function(err) {
     console.log(err);
  }
);

//dataArrayに音域情報を入れる。繰り返す
function getAudio() {
  requestAnimationFrame(getAudio);
  analyser.getByteFrequencyData(dataArray);
}

youtubeをバックグラウンド再生してcanvasを重ねる

動画の背景埋め込みには↓の方法を採用
「baserJSで埋め込んだYouTubeを背景動画にする」
http://qiita.com/YusukeHirao/items/b99b591fa9765763d508

$('.youtube').bcYoutube().bcBackground();

その上に重ねたcanvasに、opacityをかけることで背景の動画と混ざり合うわけです。
音はYoutubeから鳴っている音がWebAudioのInになります。

GLSLでシェーダーを書く

GLSLシェーダーの書き方は@doxasさんの記事にたくさんあるので、最早まとめるまでもない雰囲気

「こぴぺするだけ簡単 WebGL + GLSL テンプレート」
http://qiita.com/doxas/items/000f2ad6f82c27bd389e

さきほどの区切った音域ごとの値をもらってきます。

<script id="fs" type="xs/fs">
precision mediump float;
uniform float rad; // 回転のステップ
uniform float circleSize; // ◯の大きさ
uniform float blueIntensity; // 青の強さ
uniform float redIntensity; // 赤の強さ
uniform vec2  resolution;

void main(void)
{

  vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / max(resolution.x, resolution.y);

  vec3 color = vec3(0.0);

  //回る◯パーティクル、たすきがけ
  for(float i = 0.0; i < 6.0; i++){
      vec2 q = p + vec2(cos(rad + i) + circleSize * 30.0, sin(rad + i + 2.0) + circleSize * 30.0 - 0.3) * 0.5;
      color.g += circleSize / length(q * 1.5);
      color.b += circleSize / length(q * 1.5) * 0.6;
  }
  for(float i = 0.0; i < 6.0; i++){
      vec2 q = p + vec2(cos(rad - i), sin(rad + i + 2.0) + circleSize * 30.0 - 0.3) * 0.5;
      color.g += circleSize / length(q * 1.5) * 0.6;
      color.b += circleSize / length(q * 1.5) * 0.6;
  }

  //青、赤の強さを決定
  color.b += blueIntensity;
  color.r += redIntensity;

  //色を決定
  gl_FragColor = vec4(color, 1.0);

}

</script>

<script id="vs" type="xs/vs">
//今回はいじらない
attribute vec3 position;
void main(void)
{
  gl_Position = vec4(position, 1.0);
}
</script>

シェーダーにオーディオの分析データを料理して送る

いい感じの値になるようにさばきます。ここは最大のポイント。アルゴリズムやパラメータのチューニング次第で面白くなったりつまらなくなったりします。

・青は全ての音域の総和を拾うようにします。こうすることで曲の盛り上がり、盛り下がりを拾う効果を狙う。

・赤は特定音域だけを広います。これで曲のブレーク中、ある音域だけが強調されて青とうまく混ざる。

・◯の軌道、これはある値より低い時は戻るようにします。こうすると、ビートが強調される。プラス、ブレイクの時とかにシューンと戻っていくのでブレイク感が出ます。それと大きさは青に比例するようにします。

音をさばく部分
//音域の総和を得る
var dNum = 0;
for(var i = 0; i < dataArray.length;i++){
  dataArray[i] *= 2.5; //増幅させる
  dNum += dataArray[i];
}

//青は、総和をビジュアライズする
var blue = dNum * 0.00023;

//赤は特定の音域のみ拾う
var red = dataArray[6] * 0.002;

//◯の軌道。低い時は戻るようにする
var vr = dataArray[6] * 0.0003;

if(vr <= 0.04){
  vr -= 0.02;
}else{
  vr += 0.04;
}

//◯の大きさは青に比例する
var circleSize = red * 0.01 +  blue * 0.04;
rad += vr;

思わぬ副産物・・・こっちがメインか?!

音量をMacのミュートボタンで切って、マイクに向かってボイスパーカッションとかをすると面白いです。というかこういう用途の方がありかも。というかitunesのビジュアライザーになるやん。

ということでこっちの方も作ってみました。:tada:
demo : https://hp0me.github.io/glsl_webaudio_visualizer/you.html

とはいっても、このままだとマイクの音も入って、曲の大事な部分で邪魔をしたりしてしまいます。こういう時は、環境設定でマイクのインプットを切ります。w
スクリーンショット 2015-12-02 21.24.04.png

若干無理矢理ですが、itunesのビジュアライザーの完成!(他の音を出さなければね・・・)

57
54
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
54