みんなの「作ってみた」

【令和開幕ハッカソン】Web Audio APIを使って音声を逆再生するサービスを作ってみた

2019/06/03

harhogefoo
harhogefoo
今日も1日がんばるぞい!

はじめに

こんにちは。令和元年のGW10連休いかがお過ごしでしたしょうか?

私が所属する会社では「10連休だし何かサービスを作ろうぜ!」ということで
任意の仲間同士でGW中に1人1サービスを作るGWハッカソンを開催しました。大学のサークルみたいですね。


GWハッカソンのまとめ記事もありますので、こちらも読んでいただけたら嬉しいです
https://praha-inc.hatenablog.com/entry/2019/05/15/202420


今回作ったサービスはこちら

HEISEI REVERSE PLAYER
https://heisei-reverse-player.kukan-tech.com/

平成の名曲を逆再生でイントロドンするWebアプリです。

この記事では「HEISEI REVERSE PLAYER」の開発経緯とその技術について共有します。

対象読者

  • 個人開発者
  • Web Audio APIをこれから触ってみたい方

動機

動機は単純な理由でした。

  • iTunes Search APIを使って何か作りたい
  • 元号が変わるシーズンなので何かそれに沿ったものを作りたい
  • 平成を振り返る?
  • 平成振り返りイントロドン?

要件

  • 逆再生で音声が再生できること
  • 音声のソースは著作権に違反しないこと
  • Webアプリであること(※Webにこだわる理由は後述します)

使用したもの

  • Nuxt.js(v2.6)
  • Web Audio API
  • iTunes Search API
  • Firebase hosting

技術選定理由

個人的な話ですが、私個人の開発モチベーションの源泉が「人に使ってもらうこと」なので
多くの人が使えるであろう「ブラウザで動くもの」 = 「Web」 にこだわりました。

あとは弊社でNuxt.jsを採用しているので爆速開発が期待できました。

Webで音声を再生する

Webで音声を再生する方法について紹介します。

audioタグを使う

お馴染みののHTML5!
以下のようなコードで再生できます。

audio.html
<audio src="sample/sample.mp3">

通常の音声再生はこれでいいのですが、今回やりたいことは「逆再生」です。

Web Audio APIを使う

Web Audio APIを使えば逆再生なんてお手のものなんです。自由にエフェクトをかけられるようですね。
JavaScriptを使ってブラウザ上で音声の加工ができるんですよ!すごい!

Web Audio APIとは

とは言ったものの、意外とつらいんですこれが。
Chromeでは再生できるけれども、Safariでは再生できないなんてことが普通に起きるんです。

IE?なにそれ美味しいのって感じですね。IEではデバッグしていません。

Web Audio APIを利用した実装で得た知見

Web Audio APIを利用した実装でハマったポイントや得た知見紹介していきます。

ハマったポイント

Safariで音声が再生できない

そもそもブラウザで提供しているWeb Audio APIのクラスが違うので、APIを利用する場合以下のように記述する必要があります。

Node.js
window.AudioContext = window.AudioContext || window.webkitAudioContext

webkitAudioContext がSafariのAudio APIでした。

Safari限定でWeb Audio APIのasync await構文が対応していない

Safariで Web Audio APIの async await構文が対応していませんでした。 then, catchを使う必要があります。
※ 後述したコードにコメント書いていますのでご確認ください。

得た知見

Safariで音声の自動再生ができない

Safariのポリシーで音声を再生するにはユーザのアクションをトリガーする必要があるとのことです。
なので音声を再生する場合、ボタンを押下した時にWeb Audio APIを再生する関数を実行する必要があります。
今回はボタンを押下したタイミングで音声を再生するため問題ありませんでした。

どうしても自動再生がやりたい人はこちらを参照してください。
Web Audio APIの闇

Web Audio APIで音声を逆再生にするスクリプト

Node.js
window.AudioContext = window.AudioContext || window.webkitAudioContext
const context = new AudioContext()

export const getAudioSourceWithPlay = (path, isReverse) => {
  const source = context.createBufferSource()
  // fetch APIで音声ファイルを取得
  fetch(path)
    .then(response => response.arrayBuffer())
    .then(arrayBuffer => {
      // 音声ファイルをデコード
      // SafariのdecodeAudioDataがpromise構文に対応していない
      // SafariではSuccess callbackが後から呼ばれることがあるため、source.start(0)もここで呼び出す必要がある
      context.decodeAudioData(arrayBuffer, function(buf) {
        // 逆再生
        if (isReverse) {
          Array.prototype.reverse.call(buf.getChannelData(0)) // left
          Array.prototype.reverse.call(buf.getChannelData(1)) // right
        }
        source.buffer = buf
        source.loop = false
        source.connect(context.destination)
        source.start(0)
      })
    })
  return source
}

開発課題

開発課題についてまとめておきます。

音声再生に時間がかかる

これは音声取得・再生のトリガーをボタン押下時にまとめてしまったため3Gなどの低速回線だとUX悪いです。
事前に取得して圧縮するなどの方法が考えられそうです。

UIがいまいち

Vuetifyを使いましょう。

まとめ

開発期間は3日ぐらいでした。
今回は、iTunes Search APIとWeb Audio APIを初めて利用したので、その仕様の調査に費やす時間が長かったかなと。
手を動かした時間は1.5日ぐらいだったと思います。

HEISEI REVERSE PLAYERでした。
https://heisei-reverse-player.kukan-tech.com/

Happy Coding!