【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた
howler.jsを使って
オーディオビジュアライザーを
作ってみる
目次
はじめに
前回の記事では、howler.jsの使い方をメモしました。
今回はhowler.jsを使って簡単な「オーディオビジュアライザー」を作ってみたいと思います。
オーディオビジュアライザーって?
音の強弱やリズムに連動して、音楽を視覚的に表現する機能のことです。
別の言い方だと「オーディオスペクトラム」とも言われているみたいですが、ほとんど同じ意味かなと思います。
よく音を表現する方法で↑の画像のようなグラフが波打つように動いたり跳ねたりする表現を見たことがあると思います。
今回は上の画像とは違いますが、こういった音に合わせて動く簡単なエフェクトをJavaScriptで作ってみようと思います。
howler.js(Web Audio API)+ SVGアニメーション
howler.jsはWeb Audio APIをベースにしていますので、AudioContext
インスタンスから音の周波数の波形データを取得することが可能です。今回はこれを使って音に合わせて波形をSVGで視覚化してみたいと思います。
・・・それってどういうこと?って感じですよね。僕も最初からこういう感じで説明されると全く意味がわからなかったと思います。笑
少し噛み砕いて説明すると、howler.jsを使うと「Web Audio API」という音源を操作できるAPIを使うことになります。そのAPIから取得できる情報の中に、再生されている音に合わせて変化する配列があります。その配列を音源が再生されている間に毎フレームごとに取得してSVGのパスをアニメーションさせよう!というのが今回の試みです。
つくったデモはこちら。
AudioVisualizer [ howler.js + SVG ]
Githubにソース置いてます。
https://github.com/inos3910/audio-visualizer-by-howlerjs
今回のデモを作るのに参考にさせていただいたのはこれらの記事です。
Web Audio APIを利用してオーディオビジュアライザを作成する ~getByteFrequencyDataで取得する配列のどの要素がどの周波数(Hz)の波形データを格納しているか確認する~
https://qiita.com/soarflat/items/004cac51b818b9483764
Web Audio APIとVue.jsで波形を見るためのオシロスコープをSVGとCanvasでつくる
https://kuroeveryday.blogspot.com/2017/11/oscilloscope-with-web-audio-api-and-vuejs.html
WebAudio APIを触る。
https://co-lab.contents.ne.jp/20171227-193
音を操るWeb技術 - Web Audio API入門
https://ics.media/entry/200427/
CSS・SVGとVue.jsでのアニメーション作成入門
https://ics.media/entry/200225/
ライブラリに頼らない表現力を身に付けよう
最後の記事はSVGアニメーションの部分を参考にさせてもらいました。
オーディオビジュアライザーを調べると、canvasを使ったアニメーションばかりが掲載されていたのですが、3D表現を使わないような線描画ならSVGの方が効率いいだろうなと思ったのでSVGにしました。
個人的にはhowler.jsで音源を扱う前に、上記の参考記事を見ながらWeb Audio APIの使い方を先に調べて、ある程度ビジュアライザーが動くところまで作ってみたら、howler.jsのありがたみがものすごくわかりました。Web Audio APIについての理解も深まるので、まずはhowlerなしで勉強してみるのもおすすめです。
実装方法
html
まずはhtmlファイルを用意します
ボタンの配置とか全体のCSSについては割愛させていただきます。
最低限整えるだけなのでお好みで。
JS
Vueで書いてもいいかなと思ったんですが、今回はES6のネイティブで書きました。特定のフレームワークに依存すると、そういうのが使えないレガシー案件や、ここからThree.jsでさらに3Dアニメーションに拡張したい時などにちょっとめんどくさいかなと思ったので。
オーディオのコントローラーをつくる
まずはオーディオを再生・停止できる状態まで作ります。
Web Audio APIを使って波形データを取得する
次に参考記事にならって、再生中のオーディオの波形データを取得します。
howler.jsでWeb Audio APIの情報にアクセスするにはGlobal Optionsのctxから取得したAudioContext
インスタンスを利用することで可能になります。
ポイントは以下。
Howler.masterGain
にAnalyserNode
を繋げるAnalyserNode
にGainNode
を繋げるGainNode
にAudioDestinationNode
を繋げる
各ノードを重複せずに繋げて最終的にAudioDestinationNode
につなげることがポイントです。これについてはStack Overflowの下記記事にヒントがありました。
Connect analyzer to Howler sound
https://stackoverflow.com/questions/32460123/connect-analyzer-to-howler-sound
SVGをアニメーションさせる
SVGの<path>
要素のd属性を波形に合わせてアニメーションさせます。
アニメーションにはrequestAnimationFrame
を使います。
drawAudioVisualizer()
関数が主な処理内容です。
ポイントは以下。
AnalyserNode.getByteFrequencyData()
で波形データを配列に格納するrequestAnimationFrame
で毎フレームごとの波形データを配列で取得- SVGの
<path>
要素のd属性に取得した配列のデータを流し込む
1番わかりにくいのがSVGパスの書き方でしょうか。
詳しく見ていきます。
計算方法がちょっとややこしいですが、要はデータをそのまま流し込むとSVGの描画領域(ViewBox)からはみ出してしまうので、波形データの最大値に合わせて座標を計算する必要があるのでこのような計算になっています。このデモではSVGの描画領域の中央に水平に引いたラインから上下・交互にパスを描画するようにしていますが、それは意図的に取得した値を交互にマイナスとプラスに変換して上下に動かすことで表現しています。さらに上下がはみ出さないように波の高さは半分に調整しています。
また、引数のbarWidth
に関しては「SVGの横幅÷波形データの全体数」を入れます。ただ、今回の音源では波形データの始めの方に音が集中しているため、SVGの横幅を1.5倍にして計算して音の集まる領域にずらして描画しました。
等倍にした場合は下記のデモのように左に波形が集中した形になります。
そして後で書きますが、this.gainNode.gain.value
を乗算することで、フェードアウトなど処理を加えて音源のボリュームコントロールした際に、ビジュアライザーも徐々にアニメーションをフェードアウトするような表現に合わせることが可能になります。
このようにいくつかの条件を加えて計算してd属性に付与する値を作るので若干ややこしい計算になっています。
ちなみにd属性は「draw(線を引く)」の頭文字から来てるみたいです。
このd属性を使ったパスへの流し込みについては下記の記事にわかりやすく書かれていましたので参考にさせていただきました。
Web Audio APIとVue.jsで波形を見るためのオシロスコープをSVGとCanvasでつくる
https://kuroeveryday.blogspot.com/2017/11/oscilloscope-with-web-audio-api-and-vuejs.html
ひとまずはここまでである程度デモのように動くようになります!
フェードアウト処理を追加する
ここまでの状態をコピペで作ると動くようになるのですが、細かい点で最初に紹介したデモのようにはなりません。下記のデモのように音源を停止させると、そこで問答無用でピタっと音もアニメーションも止まってしまいます。
細かいですが、できれば音源はフェードアウトのような感じに、アニメーションも音源のフェードアウトに合わせて徐々に動きを小さくして最終的にはデフォルトの水平線の状態に戻ってほしいですね。
音源のフェードアウトはhowler.jsのfade()
メソッドを使えば簡単に設定できます。
ポイントはstopAudio()
関数の変更です。
音源のフェードアウトはhowler.jsのfade()
メソッドで1.5秒(1500ミリ秒)に設定。合わせてWeb Audio APIでボリュームコントロールできるgainNodeでgainNode.gain.linearRampToValueAtTime()
メソッドを使い2秒かけて0になるように設定します。gainNodeは最大が1、最小が0(ミュート)となっているため、SVGのパスアニメーションの部分で記述した通り、2秒かけて徐々にフェードアウトさせた値を毎フレームごとにY座標に乗算することでアニメーションも徐々にフェードアウトするような形になります。
1.5秒とか2秒とかは特に明確な理由がないので感覚的なものですが、howler.jsのフェードアウトは簡単ですがそんなに精度が高い訳ではなくフェードのイージングが調整できるわけではないので、両方1秒とかに合わせると音とアニメーションが途中でブチ切れる感じが残ります。任意の値で構いませんが、多少gainNodeのボリューム調整を後ろ倒しにすることでアニメーションの余韻を残した方が良い感じになる気がしたのでこうしました。
また、フェード後のアニメーションの停止に関してはdrawAudioVisualizer()
にrequestAnimationFrame
の停止処理を追記すること可能です。
完成デモ
完成したデモはこちら。
※自動再生ではありませんのでページ遷移しても再生ボタンを押すまでは音声は出ません。ボタンをクリックしたら音楽が流れますので音量には注意してください。
さいごに
今回はhowler.jsの応用編としてSVGアニメーションを使用したオーディオビジュアライザーを作ってみました。
Web Audio APIはけっこうなクセあり。
普通に実装してもChromeでは動いてもPCのSafariで動かなかったり、PCのSafariで動いても今度はiOS Safariでタッチイベント周りの制限で動かなかったりでややこしすぎたので、ブラウザ対応できるhowler.jsがあって本当に助かりました。
SVGの描画の部分とかはちょっと考え方が数学的でややこしいけど、正直Vueとかでajax使ってAPIゴニョゴニョする系のフロントエンド技術よりも、こういうビジュアル表現やエフェクトなどのデザイン寄りの技術について調べる方が個人的には好きです。
今回は簡単な表現でしたが、次はThree.jsを使ったダイナミックな3D演出にも挑戦してみたいと思います!
この記事では触れていないストリーミング音源を使った方法については下記の記事へどうぞ。