howler.jsを使ってみた

howler.js入門

 Web Audio APIに挑戦してみたもののゲーム系アプリを作るだけなら不要な機能も多いし、使いにくい。ブラウザ依存な部分もあるようだし…ということでいろいろ探してみてhowler.jsというのが良さそうなので使ってみました。

導入

 まずは入手。GitHubで公開されているので、公式サイト経由でダウンロードしに行きます。

howler.js(https://howlerjs.com/)
[Download v2.*.*] → [Clone or download] → [Download ZIP]

 ライセンスはMITライセンスのようですね。ファイル内にラインセンス表記してあるようなので、jsファイルを改変せずに使えば問題ないのだと思います。

 解凍すると、フォルダがいっぱいあって分かんねーと途方に暮れます。 呆然としながらひと通りフォルダ内を眺めた後に解説を見る。

github フォルダ構成 フォルダ - オープンソースプロジェクトの/ distディレクトリの意味は?
https://code.i-harness.com/ja/q/15c8d43

 どうやらこういう感じのようです。

フォルダ内容
dist実際に使用するときに使うファイル
examplesデモとサンプルと解説
srcソースコード
tests各ブラウザでの動作確認サンプル

 examplesフォルダにはサンプルが入っています。 とりあえずひと通り遊んでみます。3dがChromeで音出ねぇよ…Edgeでは出るのに。どうやらローカルファイルだと制限がかかることがあるようです。公式サイト(https://howlerjs.com/)のDemosにあるSpatial Audioを実行すると音出ました。
distフォルダに必要なファイルが入っているはずなので見てみます。

jsファイル内容
howler.js本体部分と Spatial プラグイン
howler.min.jshowler.core.min.js + howler.spatial.min.js
howler.jsのサイズを小さくしたもの。
howler.core.min.js本体部分のみ
howler.spatial.min.jsSpatial プラグイン

 howler.js本体の部分とプラグインが1個だけ用意されているようです。 プラグインは Spatial プラグインという名前のようで、説明によると「Webオーディオがサポートされている場合は、ステレオおよび3Dオーディオのサポートを追加します。」だそうです。 examples\3dフォルダに入っているサンプルのような3Dゲームなどで使うもののようです。

 とりあえずhowler.min.jsを使っておけば問題なさそうです。 3Dオーディオがいらないなら、howler.core.min.jsだけでいいようです。 howler.min.jsを自分の作業環境にコピーしておきます。私の場合はjsフォルダ作ってその中にjsファイルを入れるようにしています。

閑話休題 1

 Chromeで日本語翻訳するとスクリプトも翻訳されてしまうので大変不便。
まずはUserScriptでjQueryを@requireして…

$("pre, h4").wrapInner("<code></code>");

 あとは普通に開いてスクリプトが走ったら、右クリックして「日本語に翻訳」。 これで読みやすくなった。

前提

 前提となる私の開発環境を書いてませんでした。
ブラウザ:Chrome(たまにEdgeで確認)
開発環境:ローカル環境
完成したら自分のサイトにアップロードしてテストするという感じです。

まずはhowler.jsのドキュメントから

 公式ドキュメントのExamplesを上から順に見ていけばすぐに使えるようになります。
しかし注意点が一つあります。単にsound.play();となっている部分は次のように書き換えないと動作しないブラウザがあるので注意です。

<button id="play">Play</button><br>
…
document.querySelector('#play').addEventListener('click', function(){
  sound.play();
});

ではExamplesを上から見ていきます。

Most basic, play an MP3:
srcに指定したファイルを再生します。

More playback options:
src: ブラウザが対応しているファイル形式をsrcに指定された候補から順に探して再生します。
autoplay: 音声の読み込みが完了すると自動的に再生が始まります。
loop: ループ再生。
volume: 音量を0.5に設定。初期値・最大値は1.0なので半分の音量で再生。
onend: 再生終了時に実行する内容。

Define and play a sound sprite:
サウンドスプライトを使用します。1個の音声ファイルから指定時間を切り取って音声素材として使用します。
キャラクターのアクションイラストをタイル状に並べて1個のファイルに纏めておき、ゲームで使うときはプログラム切り出して使う昔ながらのスプライトと似たものと考えると良さそうです。最近ではCSSスプライトもあるのでそちらの方なら知っている方もいるかも知れません。

Listen for events:
イベント取得の例です。
sound.once('load', function(){…});は、音声データの読み込みが完了すると実行されます。しかしサンプルのままだと一部ブラウザでは音が再生されません。対策は後述。
sound.on('end', function(){…});は、音声再生が終了すると実行されます。

Control multiple sounds:
サウンドIDを使って、1つの音源から作った複数のサウンドを別々に制御するサンプルです。

ES6:
import の行はコメントにしないと動作しません。

閑話休題 2

 最近console.log()が出力されない…。と悩んでいました。

【2017お盆明け】Chromeのコンソールログが表示されない時の対処法
http://blog.yuhiisk.com/archive/2017/08/17/chrome-devtool-console.html

 デベロッパーツールのConsoleの設定が変わっている場合があるようです。 ということで適当に触ってたら治りました。

モバイル/ Chromeの再生

 モバイルブラウザ / Chrome / Safari では音の自動再生は行われません。 必ずユーザー操作が入ってから再生される仕様になっています。 開いた途端に大音量で音楽が再生されるサイトは昔から個人サイトから企業サイトまでたまに見かけましたが、例外なく迷惑だと感じていました。最近は広告で同様のことが起こっていて、その対策として自動再生が制限される仕様になったようです。ありがたいですね。

なぜ、各ブラウザが動画の自動再生をできなくしていく方向性になったのか?
https://arakan-pgm-ai.hatenablog.com/entry/2018/04/23/100000

 一方でいつまで待っても再生が始まらないのは、それはそれで困ります。 howler.jsではそのあたりもちゃんと考えられていました。ドキュメントにサンプルがあります。

  // Howler.autoUnlock = false;  // false = touchendイベントが発生しても再生しない
  var sound = new Howl({
    src: ['./audio/pianoC.mp3'],
    onplayerror: function() {
      // 一番下の sound.play() で再生されなかった場合に実行されます。
      sound.once('unlock', function() {
        // touchendイベントが発生して音声の再生がロック解除されると実行されます。
        console.log('Play! [touchend]');
        sound.play();
      });
    }
  });

  // モバイルブラウザ / Chrome / Safari では再生されません。
  // playerrorイベントを発火します
  console.log('Play!');
  sound.play();

サンプル
 モバイルブラウザおよびChrome / Safariの場合は、画面をタッチ(クリック)すると再生が始まります。それ以外のブラウザは開いたらすぐに再生します。(ローカル環境ではそういう動きをします。しかしサーバーに上げたら開いてすぐに音が出ました。評価点の計算方法の違いとかなんとかが原因だと思います。)
なるほどー再生失敗したらロック解除イベントで再生するのか。しかしこれだとブラウザごとに動作が異なるから、同じ動作をするようにしたほうがいいのかもしれませんね。例えばこんな感じ。

  var sound = new Howl({
    src: ['./audio/pianoC.mp3'],
    onunlock: function() {
      // touchendイベントが発生して音声の再生がロック解除されると実行されます。
      console.log('Play!');
      sound.play();
    }
  });

サンプル
 これでEdgeの場合も、画面をタッチ(クリック)すると再生するようになります。

ピアノを作ってみた

 こういうのは何か作ってみないと便利さがわかりません。とりあえず楽器でも作ってみます。

 まずは楽器の素材探し。 意外と楽器音は少ないようです。需要が少ないのでしょうか。ともかく手頃な音源で利用規約も緩めなのがちょうど見つかったのでお借りします。

無料効果音で遊ぼう!
http://taira-komori.jpn.org/index.html

 素材が揃ったのでHTMLとCSSで適当に鍵盤を作ります。そしてスクリプトは特に何もいらないので基本的なスクリプトを真似ます。

  var sound_C  = new Howl({ src: ['./audio/pianoC.mp3'] });
  var sound_D  = new Howl({ src: ['./audio/pianoD.mp3'] });
  …
  document.querySelector('#C').addEventListener( 'click', function(){ sound_C.play();  });
  document.querySelector('#D').addEventListener( 'click', function(){ sound_D.play();  });
  …

サンプル
 ピアノの鍵盤できました。超簡単。 本来は音声データの読み込み完了まで待機する処理とかがいるとは思うのですが、よくわからないのでこれで良しとします。 むしろピアノらしいCSS作るほうが難しいんじゃないか?という気がします。

もう少しやってみようかな

 音量変更や再生速度の変更などの命令もあるので、音楽プレイヤーも簡単に作れそうです。 本格的な音の加工や分析には向いていませんが、ゲームやアプリの効果音などに向いている気がしました。ブラウザ依存の部分を吸収してくれているそうなので、ありがたいですね。 Tone.jsも気になりますが、もう少しこれで遊んでみようと思います。

関連記事

  1. ブラウザで音を再生してみた 趣旨  最近のWebブラウザは、Web Audio API ...
  2. ブラウザで音を作ってみた 音を作る  前回は音声ファイルやマイクなど外部から音のデータ...
  3. 音を可視化してみた 音声ファイルの読み込み(再)  最初に戻って音声ファイルを再...
  4. 音を可視化してみた2 音を分析 その2  前回、音声を周波数分析してカラーマップ表...