WebGL Advent Calendar 3日目の記事です。初めて赤くなりました!
ブラウザで、Youtube上の曲を元にしてGLSL(WebGL)でリアルタイムビジュアライズします。応用編としてitunesの曲や自分の声でもできるようになりました。(無理矢理)
Web Audio APIのアナライザーノードというのは使ったことがなかったんですが、mdnのデモを見ていて、結構感度が良かったのでゴニョゴニョやってみる。
音のソースとして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
##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
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のビジュアライザーになるやん。
ということでこっちの方も作ってみました。
demo : https://hp0me.github.io/glsl_webaudio_visualizer/you.html
とはいっても、このままだとマイクの音も入って、曲の大事な部分で邪魔をしたりしてしまいます。こういう時は、環境設定でマイクのインプットを切ります。w
若干無理矢理ですが、itunesのビジュアライザーの完成!(他の音を出さなければね・・・)