2015年9月4日(金)に開催されたCreateJS勉強会 (第6回)にて「SoundJSを使って音を見えるものへ」というテーマでライトニングトークをしました。発表時に使用したスライドと時間の都合上紹介できなかったことを記事として公開します。
音をビジュアライズしているコンテンツ
今回のテーマである音は目に見えません。その音を効果的にビジュアライズしているコンテンツをFWAのSITE OF THE DAYから3つピックアップしました。この他にもFWAではさまざまなコンテンツが紹介されているのですが、音をビジュアライズする手法は楽曲のプロモーションサイトに多く使われていました。
YARA’N’YARED
2015年5月16日にSITE OF THE DAYに選ばれたコンテンツ「YARA’N’YARED」。3D空間にある山の上に白いバリアのようなものがあり、それが音のテンポに合わせてフェードイン・アウトして幻想的な雰囲気を出しています。
Dope
2015年7月6日にSITE OF THE DAYに選ばれたコンテンツ「Dope」。背景で動画を表示しつつ、画面をクリックするとライン状に広がったカラフルな光を重ねることで、コンテンツのポップな演出をさらに引き立てています。
HANA MUSIC VIDEO | Kitasenju Design
2015年8月11日にSITE OF THE DAYに選ばれたKitasenju Design氏のポートフォリオサイト内の作品の1つ「HANA MUSIC VIDEO」。こちらも音のテンポに合わせて変化することは先ほどと同じですが、背景や顔の3Dオブジェクトを「ぐにゃぐにゃ」と変形させています。
音はどうやってビジュアライズするのか?
では実際にどうやって音をビジュアライズするのでしょうか? 先ほど紹介したコンテンツのソースコードを読んでみると、ある手法が共通で使われていました。
音を音の高さで分割する「フーリエ変換」
音楽などのサウンドデータは複数の波形が合わさって1つの波形になっています。フーリエ変換を使うと、その合わさった波形を周波数ごとに分割できます。わかりやすくいうと「音を音の高さで分割する」ということです。その分割した周波数(音の高さ)ごとに振幅(音の大きさ)が取得できるので、その値をビジュアライズするロジックに渡してあげることで音に連動したコンテンツを作成できます。
SoundJSとWeb Audio APIでフーリエ変換を使う
そのフーリエ変換を難しい数式など考えずに手軽に扱いたかったためSoundJSとWeb Audio APIを選びました。
SoundJSの再生方式
SoundJSではさまざまな環境でも再生できるように、以下の3つの再生方式がサポートされています。フーリエ変換では波形の解析を行うのでWebAudioPluginを使用します。
- HTMLAudioPlugin
HTML5のaudioタグを使用した方式。簡単に再生できますが、音にエフェクトを加えるなどの複雑なことはできません。 - WebAudioPlugin
JavaScriptで音を制御するWeb Audio APIを使用した方式。音の再生・編集・解析はもちろんのこと、音を生成することもできます。 - FlashAudioPlugin
Flash Playerを使用した方式。ブラウザごとの挙動の差を吸収するために使用されます。
フーリエ変換を使ってビジュアライズ
フーリエ変換を使って簡易的なサウンドビジュアライザーを作成しました。サウンドの解析部分をSoundJSとWeb Audio APIで行い、ビジュアライズ部分ではThree.jsを使って3Dで表現しています。音の高さごとに音の大きさを取得し、3D空間(Three.js)に配置されている立方体の上下方向の座標に用いることで波を表現しています。
音をビジュアライズするために必要な処理
SoundJSでサウンドデータの読み込み〜再生
下記のように数行でサウンドデータの読み込み〜再生できます。
// fileloadイベント
createjs.Sound.on("fileload", function() {
// 無限ループで再生
createjs.Sound.play(SOUND_ID, { loop: -1 });
});
// サウンドの登録 読み込み
createjs.Sound.registerSound({
id: SOUND_ID,
src: SOUND_PATH
});
Web Audio APIでフーリエ変換
フーリエ変換は波形の解析ができるWeb Audio APIで行います。フーリエ変換で音の波形を何分割にするのかを指定し、音の高さごとの音の大きさを数値の入った配列で取得できます。その値をビジュアライズするロジックに渡します。
// WebAudioPluginを取得
var context = createjs.Sound.activePlugin.context;
// アナライザーを生成
var analyserNode = context.createAnalyser();
// フーリエ変換を行う分割数。2の乗数でなくてはならない
analyserNode.fftSize = FFTSIZE;
// オーディオの出力先を設定
analyserNode.connect(context.destination);
// 波形データを格納する配列の生成
var freqByteData = new Uint8Array(FFTSIZE / 2);
// それぞれの周波数の振幅を取得
analyserNode.getByteFrequencyData(freqByteData);
フーリエ変換で取得した値でビジュアライズ
フーリエ変換で取得した数値は配列で返ってくるので、1つずつ抽出し3D空間の表示要素の座標に反映します。
// 立方体の描画
for (var i = 0; i < FFTSIZE / 2; i++) {
// フーリエ変換で取得した値を抽出
var freqData = freqByteData[i];
if (!freqData) freqData = 0;
else freqData /= 256;
// 座標を更新
boxArray.position.y = freqData * 1000;
}
SoundJSでハマったところ
音を手軽に扱えるSoundJSですが、いくつかハマったところがあったので共有します。
-
サウンドループ時に途切れる
MP3形式で書き出されたループ音源を再生すると、ループするタイミングで一瞬途切れてしまいます。ファイル形式として「wav」「ogg」「m4a」(AAC)のいずれかを選択することでこの現象は解消されました。コンテンツの仕様などでどうしてもMP3形式を使用したいという場合は、ループの前後にフェードイン・アウトを加える必要があります。 -
Google Chromeで音声の右チャンネルが聴こえない
バージョン0.6.0・0.6.1のSoundJSでWebAudioPluginを使用すると発生します。GitHubでの開発版ではすでに修正されているので次期バージョンでは解消されることでしょう。公開までにSoundJSを使用する場合は、CDNで公開されているものではなくGitHubからzipファイルをダウンロードしてその中の「soundjs-NEXT.min.js」を使用するなど注意してください。
サウンドビジュアライズの小ネタ
こちらは発表で紹介できなかったことなのですが、実際に音をビジュアライズして見つけた小ネタです。
-
ループ音源をつくるならGarageBandがオススメ
今回使用したループ音源は自作しています。使用したのはMacに搭載されているGarageBandというアプリケーションで、楽器を弾いたことのない私でも簡単に作成することができました。作った音源は商用利用も可能となっています(素材音をそのまま書き出すことは禁止)。ライセンスの詳細は「GarageBand のロイヤルティフリーのループを商用利用する - Apple サポート」にてご確認ください。 -
音程差の大きな音を組み合わせると効果的
音源作りも試行錯誤したのですが、低音と高音の音を組み合わせることでメリハリがつき、よりインパクトのある表現になります。 -
フレームレートよりもユーザーの体験を最優先に考える
今回作成したビジュアライザーは60fpsを基本に実装していますが、立方体の描画スピードはその半分の30fpsまで落としています。60fpsで実装すると立方体の動きが速すぎて砂嵐のような見え方になってしまったのですが、思い切って半分の30fpsにすることでイメージしていた表現を実現できました。演出を作成する際、実現できる最大のフレームレートで実装することが多いですが、場合によってはあえて落とすことも有効です。
まとめ
今回紹介したことをまとめると下記のようになります。
- 音のビジュアライズにはフーリエ変換が有効
- フーリエ変換とは、音を周波数(音の高さ)で分割する方式
- フーリエ変換はSoundJSとWeb Audio APIで手軽に扱える
私もサウンドビジュアライズの仕組みを知るまでは「わからないことがわからない」状態で苦手意識がありました。ですが、今回紹介した手法を使うと手軽に音をビジュアライズすることができるので、ぜひみなさんもかっこいいサウンドビジュアライザーに挑戦してみてください!
最後に話が脱線してしまうのですが、今回紹介したフーリエ変換をWikipediaで調べると複雑な数式が山のようにでてきます。このような取っつきにくい部分に対して初心者はハードルを感じてしまうこともあるかと思います。そのようなときはSoundJSなどのライブラリを使うことで、ビジュアライズなどの時間をかけたい部分に注力することができ、コンテンツのクオリティをもう一層上にあげられるのではないかと私は考えます。