Merry Christmas!(早い)
先日、【React.js】LT忘年会というイベントでReactでVisual Equlizerを作って発表してきました。
LTということもあり、説明ができなかったことが殆どで、
特に音楽を視覚化についてほとんど何も言っていないのでこちらにまとめてみました。
デモ
音楽ファイルをDnDしてみて下さい。音に合わせて、ネオンのようなクリスマスの画像がゆらゆらアニメーションします。
なるべく静かな曲の方がいいかもしれません、開発ではマライアキャリーのAll I want Christmas is youや山下達郎のクリスマスイブなんかでやっていました。
アニメーションは音楽の各音域の強さを解析することによって数値化し、それを元にCSSでアニメーションをやっています。
参考
Web Audio APIを使ってオーディオビジュアライザを作る
制作にあたり、こちらのブログを参考にさせていただきました。
短いコードに必要なサンプルの全てが詰め込まれており、非常に勉強になりました。
つかったAPI
File API
音楽ファイルの読み込みにはFile APIを使います。
セキュリティの問題から、ユーザーの操作を起点とした読み込みしか許可されていません。
Electronを使えばゆるく作ることができるんですかね。
Web Audio API
音の解析には フーリエ変換 を使います。
高校時代、物理も数学も10点台をさまよっていた僕にはちんぷんかんぷんですが。
とてもありがたいことに、JSには __Web Audio API__というものがあり、
AnalyserNodeクラスを使ってフーリエ変換を丸投げできます。
解析された結果は、intが格納された配列が戻ってくるので、これをつかえば良いわけです。
やっていきかた
大げさに、パラメータの調整
お わ び
懇親会でデータの間引きの説明をさせていただきましたが、よくよく検討したところ効果がありませんでした。
フーリエ解析による結果は以下のようになります。
(図は実際の結果に近いものを表計算ソフトで作ったものです)
左が低い音、右が高い音になります。
高音域が全く出ておりません。
音の厚みを考えると、低音域を厚くするのがセオリーなのでしょうがないと思いますが
今のデータを元にアニメーションをつくってもぼんやりしたものになってしまいます。
大げさな表現をするためには小さい数字はそのまま、大きい数字はより大きく見せればOKです。
パッと思いつかなかったので単純に値を二乗します。
例:
1 4 8
↓ 二乗
1 16 64
単純な計算ですが、それなりにメリハリがつきますね。
ちょっとの大小の変化が大げさなアニメーションになります。
ただ、このやり方の場合サビで盛り上がってくると視覚的な変化がなくなってしまいます。
要改善点です。
フレームレートの調節
今回はJavaScriptの requestAniamatinoFrame
を用いてループを行っています。
このメソッドはブラウザの描画タイミングに合わせてうまい具合に処理を実行してくれるもので、
おおよそ毎秒60回(60FPS)渡した引数を実行してくれます。
setTimeout
でアニメーションを行った場合とはくらべ、パフォーマンスが段違いです。
ただし、この粒度でアニメーションを行うととてもチカチカしたものになります。
なぜなら波形をイメージしてみると想像できますが、音は振幅がとても細かいためです。
なのでイイカンジに12FPSや5FPSなど音を解析にかける頻度を減らす必要があります。
ここらへんは適当にカウンタを用意して対応しました。
ただし、間引きをおこなっても チカチカ が パッパッ に変わるだけで、おおよそイイカンジのアニメーションからは遠いです。
おそらく下のような感じに波形がなるからでしょう。
CSS transitionによるヤスリがけ
間引きを行ったことによって隙間が目立ってしまいました。
ある時間からある時間へのなめらかな橋渡しをしてあげねばいけません。
CSSによるヤスリがけの結果、以下のような波形になります。
(赤線がやすったもの)
真面目にReactでこれを書こうとするとめんどくさそうですが、 CSSさんに丸投げしましょう。
本来はイージングで曲線の緩急をつけるべきかもしれませんが、変化の激しいVisual Equlizerではこれで十分です。
星のきらめき表現
作った画像には天の川のような細かい星のグラフィックがあります。
これは常に表示させたいため、比較的常に音がでている低音域のデータを使いました。
先に述べたように低音は基本、フルバースト状態ですので 全然アニメーションしない のなんのって
僕の頭の中のイメージでは星の煌き、つまりは チカチカ するアニメーションをさせたいため、乱数で味付けすることによって揺さぶりをかけました。
コクのあるアルゴ が大活躍です。
Math.Random() * Math.Random() * Math.Random() * Math.Random() * Math.Random() / 5;
これをデータにから引きます。
今後の展望
制作をすすめるにあたって、すぐに物足りなく感じはじめました。
- 音色による解析
- アニメーションの不確定要素の追加
この2点を実現したいなあと。
音色による解析
これはつまりは、 楽器ごと に音を分解して利用したいということです。
本当ならバスドラムの刻む4分音符に合わせて映像的な揺さぶりをかけたいのですが、
ベースに混ざってうまくリズムを取り出すことが出来ません。
詳しいことは専門家の方におまかせしたいのですが、そもそも
音というものは複数の音域(音の高さ)が混ざり合うことによって 音色 が生まれます。
一つの音は基音と倍音という2種類の音に分けて分解することが出来ます。
基音はその音の高さを決め、倍音がどう含まれているによって音色が変わってきます。
余談ですが、一般には倍音が多ければ多いほど 豊かな音 といえるそうです。
倍音の構成パターンを解析すれば特定の楽器がならす音が特定できるのではと思います。
ただ、これはリアルタイムで処理するのは難しいと勝手に想像しており、
再生を行う前に音楽に含まれる構成パターンを抽出した上で、それらを元に
一つの音楽から特定の楽器のならす音を解析できるのではと考えています。
できるんでしょうか?^^;
アニメーションの不確定要素の追加
予定調和的なアニメーションもいいですが、せっかくコードで表現しているため、
毎回実行するたびに新な発見がある物を作りたいものです。
今回ランダム要素は星空の表現にのみ使いましたが、もっと不確定要素をメインに据た表現を考えていきたいです。
あるルールに従い、音楽からの刺激を受けて自律的に視覚を変えていく何か、が面白そうかなと思います。
まとめ
改めて整理してみると、どうでもいい処理が大量に入ってて残念な気持ちになりました。
(このまとめでは削っています。)
今回Visual Equlizerを作るのは、はじめてのチャンレジだったので継続してブラッシュアップしていきたいです。
またこういったプログラミングによる視覚表現の入門としてに
「ジェネラティブ・アート―Processingによる実践ガイド」
は超おすすめです。
三角関数の素晴らしさを実感できます。数学苦手でもOKです。
改めて思い返してみると全然React関係なかったなとか思ったり思わなかったり