jsのオーディオライブラリ、howler.jsを試してみた

# 注意

**私はaudioのファイル形式など詳しくありません、個人的に興味があり公式に書いてあることを試してみたという内容です。**
**詳しく知りたい方は以下の公式などを参照し、本記事は読まなくて良いです。間違いなどありましたらご指摘お願いします**:bow:

- [goldfire/howler.js - github](https://github.com/goldfire/howler.js#documentation)
- [howler.js - JavaScript audio library for the modern web](https://howlerjs.com/)

# howler.jsとは

jsで扱えるオーディオライブラリ


![Screen Shot 2019-03-21 at 23.09.46.png](https://qiita-image-store.s3.amazonaws.com/0/142910/bc636bf7-0a96-7375-e2cc-51a3c49950ed.png)

2019/03/19現在

- [githubスター数](https://github.com/goldfire/howler.js) : :star2: 13845 :star2: 


# install

npmを使って試してみました

```bash:bash
npm init -y
npm i -D howler
```

# すぐ試せるサンプル

こちらに用意しました

https://github.com/okumurakengo/00011_howler

この記事のサンプルコードは全てこちらにあります。

# 確認バージョン

- howler.js 2.1.1
- node v10.14.1

# Quick Start

```html:quickStart.html
<button>play</button>
```

```js:quickStart.js
import { Howl, Howler } from 'howler';

var sound = new Howl({
    src: [
        'audio/piano.ogg',
        'audio/piano.mp3',
    ]
});

document.querySelector("button").addEventListener("click", e => sound.play() );
```

`piano.ogg`を再生してくれました

![v0FLDNsn22.gif](https://qiita-image-store.s3.amazonaws.com/0/142910/45a1e61b-85a7-fdc4-fbdd-3bc26f98e671.gif)

Safariではogg形式のファイルに対応していないため、mp3で再生されたことを確認

![Screen Shot 2019-03-21 at 16.png](https://qiita-image-store.s3.amazonaws.com/0/142910/56ead4ec-f5c1-5494-f534-452461ca0f1e.png)


なので、この書き方ですと、

```js
const sound = new Howl({
    src: [
        'audio/piano.ogg',
        'audio/piano.mp3',
    ]
});
```

このようにタグで書いたのと同じように扱ってくれるようです

```html
    <audio controls>
        <source src="audio/piano.ogg">
        <source src="audio/piano.mp3">
    </audio>
```

# Typescript

```bash:bash
npm i -D typescript howler @types/howler
```

```js
import { Howl, Howler } from 'howler';

const sound: Howl = new Howl({
    src: ['audio/piano.mp3'],
});
```

# Examples

### optionの指定

このように引数を渡すと色々なオプションを渡すことができます

```js:option.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
    autoplay: true,
    loop: true,
    volume: 0.5,
    onend: () => { // 再生完了時のendイベント
        console.log('Finished!');
    }
});
```

ループ再生だと再生が終端までくるたびにendイベントが呼ばれるようです

![Screen Shot 2019-03-21 at 17.15.22.png](https://qiita-image-store.s3.amazonaws.com/0/142910/acc494f5-b418-4250-4dfc-bf828b51dce2.png)


### sound sprite

`sound.play("hogesprite")` とすることで再生開始位置と再生秒数を設定できるようです

```js:soundSprite.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
    sprite: {
        play1: [0, 3000], // 開始から3秒間を再生
        play2: [3000, 1000], // 開始3秒から1秒間再生
        play3: [60000, 5000], // 開始1分から5秒間再生
    }
});
  
document.body.insertAdjacentHTML("afterbegin", `
    <button id="play1">play1</button>
    <button id="play2">play2</button>
    <button id="play3">play3</button>
`);

play1.addEventListener("click", e => sound.play("play1") );
play2.addEventListener("click", e => sound.play("play2") );
play3.addEventListener("click", e => sound.play("play3") );
```

### Listen for events

イベントを設定することができます

```js:listenEvents.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
});

// 最初の呼び出し後にリスナーをクリアします (このイベントは一回しか実行されない)
sound.once('load',() => {
    console.log('Load!');
});

// サウンドの再生が終了したときに発生します。
sound.on('end',() => {
    console.log('Finished!');
});
```

### Control multiple sounds:

複数音楽を再生してそれぞれ制御できます

```js:multipleSounds.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
});

button.addEventListener("click", e => {
    // 同じサウンドを2回再生する
    const id1 = sound.play();
    const id2 = sound.play();

    // 1つ目の再生は10秒かけて音量を 1 -> 0 に変化させる
    sound.fade(1, 0, 10000, id1);
    // 2つ目の再生は再生速度を速くする
    sound.rate(1.5, id2);
});
```

# Methods

### `pause`

再生を一時停止する。
一時停止した後に `play()` を実行すると途中から再生できる

```js:pause.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
});

document.body.insertAdjacentHTML("afterbegin", `
    <button id="play">再生</button>
    <button id="pause">一時停止</button>
`);

play.addEventListener("click", e => {
    sound.play() // 一時停止したところから再生
});
pause.addEventListener("click", e => {
    sound.pause(); // 一時停止
});
```

### `stop`

再生をストップする。
もう一度 `play()` を実行すると途中から最初から再生される

```js:stop.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
});

document.body.insertAdjacentHTML("afterbegin", `
    <button id="play">再生</button>
    <button id="stoped">再生終了</button>
`);

play.addEventListener("click", e => {
    sound.play() // 最初から再生される
});
stoped.addEventListener("click", e => {
    sound.stop(); // 再生を終了
});
```

### `mute`

```js:mute.js
sound.mute(true); // ミュート
sound.mute(false); // ミュート解除
```

### `volume`

```js:volume.js
sound.play();
sound.volume(0.2); // ボリュームは 0.0 〜 1.0 の間で設定できる
```

### `fade`

```js:fade.js
sound.play();
sound.fade(1, 0, 5000); // 5秒かけて音量を 1 -> 0 にする
```

### `rate`

```js:rate.js
sound.play();
sound.rate(2); // 速度を変更する 0.5 〜 4.0 の間で指定する(1だとデフォルトの速度)
```
### `seek`

```js:seek.js
sound.play();
sound.seek(30); // 再生位置を30秒の部分に移動
```

### `state`

音声ファイルの読み込み状態を確認できる

```js:state.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ['audio/piano.mp3'],
});
console.log(sound.state()); // loading

sound.once('load', () => {
    console.log(sound.state()); // loaded
    sound.unload();
    console.log(sound.state()); // unloaded
});
```

### `duration`

```js:duration.js
console.log(sound.duration()); // 0 (まだ読み込んでいないため)
sound.once('load', () => {
    console.log(sound.duration()); // オーディオソースの長さを取得
});
```

### `off`

```js:off.js
const sound = new Howl({
    src: ['audio/piano.mp3'],
});
sound.on("volume", () => {
    console.log("volume!")
})

button.addEventListener("click", e => {
    sound.play();
    setTimeout(() => sound.volume(0.2), 1000); // イベント実行される
    setTimeout(() => sound.off(), 2000); // 引数なしでoff()と実行すると全てのイベントを削除
    setTimeout(() => sound.volume(0.5), 3000); // イベント実行されない
});
```

### `load`

デフォルトで`load()`は読み込み時に行われるが、`preload:false` とした場合は、自分で呼ぶ必要がある

```js:load.js
const sound = new Howl({
    src: ['audio/piano.mp3'],
    preload: false,
});
sound.on("load", () => {
    console.log("load!") // ↓のクリックの後にこのイベントが実行されることになる
})

button.addEventListener("click", e => {
    sound.load();
    sound.play();
});
```

### `unload`

```js:unload.js
const sound = new Howl({
    src: ['audio/piano.mp3'],
});

button.addEventListener("click", e => {
    sound.play();
    setTimeout(() => { 
        sound.unload()  // 再生終了される
        console.log(sound.state()) // unloaded
    }, 2000);
});
```

# Options

```js:options.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ["audio/piano.mp3"],
    volume: 0.5, // デフォルト:1 音量 0.0〜1.0
    html5: false, // デフォルト:fasle trueだとHTML5オーディオを強制
    loop: false, // デフォルト:false ループをするかしないか
    preload: true, // デフォルト:true Howlの定義時に自動でファイルを読み込むか
    autoplay: false, // デフォルト:false 自動再生するか
    mute: false, // デフォルト:false ミュートするか
    sprite: {
        hoge: [30000, 5000, true], // sound.play("hoge") とすると開始30秒の位置から5秒間再生する、第３引数はloopするかしないか
    },
    rate: 1.5, // デフォルト:1.0 再生速度 0.5〜4.0
    pool: 5, // デフォルト:5 非アクティブサウンドのプールのサイズ。公式によると、通常これを変更する必要はないとのこと
    format: ['mp3'], // 通常は拡張子からファイル形式を自動的にするが、抽出がうまくいかない状況でも指定することができる
});
```

# Events

オプションで指定する方法

```js
const sound = new Howl({
    src: ["audio/piano.mp3"],
    onload: () => {
        console.log("load!");
    }
});
```

または`on`を使用し、`onload`イベントを設定したい場合は`"load"`を第一引数に渡すと同じように設定できる

```js
const sound = new Howl({
    src: ["audio/piano.mp3"],
});
sound.on("load", () => {
    console.log("load!");
})
```

イベントが想定通り発生されるか確認してみました

```events.js
import { Howl, Howler } from 'howler';

const sound = new Howl({
    src: ["audio/piano.mp3"],
});
sound.on("load", () => console.log("load!"));
sound.on("unlock", () => console.log("unlock!")); // タッチ/クリックイベントによってオーディオが自動的にロック解除されたときに発生
sound.on("play", () => console.log("play!"));
sound.on("end", () => console.log("end!"));
sound.on("pause", () => console.log("pause!"));
sound.on("stop", () => console.log("stop!"));
sound.on("mute", () => console.log("mute!"));
sound.on("volume", () => console.log("volume!"));
sound.on("rate", () => console.log("rate!"));
sound.on("seek", () => console.log("seek!"));
sound.on("fade", () => console.log("fade!"));

button.addEventListener("click", e => {
    sound.play();
    setTimeout(() => sound.pause(), 2000); // pauseイベント発生
    setTimeout(() => sound.play(), 4000); // pauseからの再生後もplayイベント発生
    setTimeout(() => sound.stop(), 6000); // stopイベント発生
    setTimeout(() => sound.play(), 8000);
    setTimeout(() => sound.mute(true), 10000); // muteイベント発生
    setTimeout(() => sound.mute(false), 12000); // muteイベント発生
    setTimeout(() => sound.volume(0.5), 14000); // volumeイベント発生
    setTimeout(() => sound.rate(1.2), 16000); // rateイベント発生
    setTimeout(() => sound.seek(5), 16000); // seekイベント発生
    setTimeout(() => sound.fade(0.5, 1, 1000), 18000); // フェードイン/フェードアウトを終了したときに発生
});
```

![Screen Shot 2019-03-21 at 20.48.34.png](https://qiita-image-store.s3.amazonaws.com/0/142910/993d6afb-10c0-c8cf-cb0d-4f80d6f1096f.png)

公式によるとエラーイベントも設定できるようです

```js
const sound = new Howl({
    src: ["audio/piano.mp3"],
});
sound.on("loaderror", () => {
    console.log("loaderror!"); // サウンドが読み込めないときに発生
})
sound.on("playerror", () => {
    console.log("playerror!"); // サウンドが再生できないときに発生
})
``` 

# Global Options

グローバルオプションの一部です、 **コメントは全て公式のgoogle翻訳**です:bow:


```js:globalOptions.js
import { Howl, Howler } from 'howler';

// Web Audio APIが利用可能な場合はtrue
console.log(Howler.usingWebAudio);

// 利用可能なオーディオがない場合はtrue
console.log(Howler.noAudio);

// モバイル（iOS、Androidなど）デバイスおよびデスクトップのChrome / Safariでオーディオを自動的に有効にしようとします。
console.log(Howler.autoUnlock);
```

# Global Methods

グローバルメソッドの一部で、`volume`と`unload`を試してみました

```js:globalMehtods.js
import { Howl, Howler } from 'howler';

// 全てのボリュームを0.5にする
Howler.volume(0.5);

const sound1 = new Howl({
    src: ['audio/piano.mp3'],
});
const sound2 = new Howl({
    src: ['audio/piano.ogg'],
});

button.addEventListener("click", e => {
    sound1.play();
    sound2.play();
    setTimeout(() => Howler.unload(), 3000); // 全て再生中止する
});
```

---

最後まで読んでいただいてありがとうございましたm(_ _)m