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インスタンスを利用することで可能になります。

ポイントは以下。

  1. Howler.masterGainAnalyserNodeを繋げる
  2. AnalyserNodeGainNodeを繋げる
  3. GainNodeAudioDestinationNodeを繋げる

各ノードを重複せずに繋げて最終的に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倍にして計算して音の集まる領域にずらして描画しました。
等倍にした場合は下記のデモのように左に波形が集中した形になります。

波形SVGの描画領域を等倍にした場合のデモ

そして後で書きますが、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の停止処理を追記すること可能です。

完成デモ

完成したデモはこちら。

SVGで動くオーディオビジュアライザー

※自動再生ではありませんのでページ遷移しても再生ボタンを押すまでは音声は出ません。ボタンをクリックしたら音楽が流れますので音量には注意してください。

さいごに

今回はhowler.jsの応用編としてSVGアニメーションを使用したオーディオビジュアライザーを作ってみました。

Web Audio APIはけっこうなクセあり。
普通に実装してもChromeでは動いてもPCのSafariで動かなかったり、PCのSafariで動いても今度はiOS Safariでタッチイベント周りの制限で動かなかったりでややこしすぎたので、ブラウザ対応できるhowler.jsがあって本当に助かりました。

SVGの描画の部分とかはちょっと考え方が数学的でややこしいけど、正直Vueとかでajax使ってAPIゴニョゴニョする系のフロントエンド技術よりも、こういうビジュアル表現やエフェクトなどのデザイン寄りの技術について調べる方が個人的には好きです。

今回は簡単な表現でしたが、次はThree.jsを使ったダイナミックな3D演出にも挑戦してみたいと思います!

この記事では触れていないストリーミング音源を使った方法については下記の記事へどうぞ。

記事一覧

RELATED

inoue
TRY

【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた

inoue
TRY

【netlify】ビルドイメージを更新 [ Ubuntu Xenial 16.04 → Ubuntu Focal 20.04 ]

inoue
TRY

スクリーンショットのAPI「screendot」を使ってみた

inoue
TRY

DartSassがなかなか辛かったのでGulpを修正してみた

inoue
TRY

【howler.js】ストリーミング音源からオーディオビジュアライザーを作る

inoue
TRY

Simple GA Ranking[ver2.1.6]が表示されないので調べてみた

NEW POSTS

inoue
TIPS

【CSS + JS】テキストの無限ループアニメーション

inoue
TIPS

【Shopify】カートへの遷移を飛ばしてチェックアウトに進むボタンを設置する

inoue
TIPS

【JS】PhotoSwipe v5を使って画像をポップアップ表示する

inoue
TIPS

gulpでjpg・pngからAVIF画像を生成する

inoue
TIPS

【JS】MutationObserverでDOMを監視[PhotoSwipe(v5)+Swiper(v8)連携]

inoue
TIPS

【Google Sheets API】 スプレッドシートのデータをJSONで取得する

ブログ記事一覧
  • HOME
  • TRY
  • howler.jsを使ってオーディオビジュアライザーを作ってみる