メニューを閉じる

テクノデジタルグループ

メニューを開く

2017.10.18

プログラミング

Web Audio APIを使って簡単なプレイヤーを作ってみる(3)

こんにちは、新卒のshiroです。
前回前々回に引き続き、今回もweb audio apiを利用した、ブラウザ上で動く簡単なミュージックプレイヤーを作成していきます。

今回作成する機能は以下の3つです。

ファイルの取り込み
一時停止/再開
リピート

今回も早速作っていきましょう。

ファイルの取り込み

前回までlistとaudioNameにファイルパスと音声ファイルのタイトルを入れていたと思うので、削除してください。

ファイルの取り込みは以下のコードになります。

// ファイル読み込み
var player_input = function() {
  list = [];
  audioName = [];
  for(let i = 0; i < inputFile.files.length; i++) {
    if(inputFile.files[i].type.match(/audio\/.+/)) {
      list.push(window.URL.createObjectURL(inputFile.files[i]));
      audioName.push(inputFile.files[i].name.replace(/\.\w+$/, ""));
    }
  }
}

ここでは最初にlistとaudioNameの初期化を行っています。
これは、再度ファイルの取り込みをした際に前のデータが残らないようにしています。
files.lengthで取り込んだファイルの数がわかるので、その-1回処理を行います。
if文で音声ファイルか確認したのち、createObjectURL()でオブジェクトURLを生成、listに入れていきます。

次に取得した名前をreplace()し、拡張子を削除したものをaudioNameに入れています。
正規表現で使っている”\.\w+$”は「.以降がa-z、A-Z、0-9、_のいずれかを含む1文字以上であり、かつ後端である」ことを条件としています。

player_play()に

if(list.length === 0) {
  return alert("File is not found.");
}

を追加することで、ファイルが無い場合以降の処理を行わないようにします。

簡単ですが、これだけで取り込みの機能が実装できます。

一時停止/再開

突然ですが、Web Audio Apiの機能を調べてたどり着いた方の中には一時停止で悩んでいる方もいらっしゃるのではないでしょうか。
私も悩んだ一人でした。

ということで、個人的にプレイヤー作成一番の鬼門である一時停止/再開です。

sound()のstartTime辺りを変更します。

if(!playing) {
  // 初めて音を再生する際、再生開始時のcontext.currentTimeが0とは限らないため取得
  startTime = context.currentTime;
  // 再生開始時間を取得
  audioTime = startTime;
  // 実再生開始時間を設定
  resumeTime = 0;
  playing = true;
} else {
  // 再生開始時間を取得
  audioTime = context.currentTime;
  // 実再生開始時間を設定
  resumeTime = pauseTime;
}

再生前の処理は変わりませんが、ポーズ中の処理を追加しています。
audioTimeにAudioContext.currentTimeを入れます。
resumeTimeには後ほど作成するpauseTimeを入れます。
これで再開時にはポーズした時間から再生するようになります。

そのままAudioBufferSourceNode.start()の下に以下の処理を追加します。

// 再生が終了した際の処理
source.onended = function() {
  // contextの時間経過を停止
  context.suspend().then(function() {
    dispTime = timeBar.value;
    playerStatus();
    if(!pausing) {
      clearPlayer();
    }
  });
}

AudioBufferSourceNode.onendedは、曲が終了(末尾まで再生/途中で停止)した際に発火するイベントです。
この時、AudioContext.suspend()を呼ぶことで、AudioContextが一時的に中断されます。
また、thenを繋げることでsuspend()が完了した際の処理を呼んでいます。
if文で一時停止ではないときにプレイヤーをクリアしています。

player_play()のlet bgm =…からを以下に変更します。

let bgm = list[listNum];
title.innerHTML = audioName[listNum];
getAudioBuffer(bgm,function(buffer) {
  context.resume().then(function() {
    sound(buffer, false);
    pausing = false;
    playerStatus();
  });
});

AudioContext.resume()が追加されていますが、これはAudioContext.suspend()の反対で、中断されたAudioContextを再開する処理になります。

player_playの下あたりにポーズ用の関数を追加します。

// 一時停止
var player_pause = function() {
  pauseTime = context.currentTime - startTime;
  pausing = true;
  soundFile.stop(0);
}

ここでpauseTimeに現在の時間を入れるのですが、currentTimeからstartTimeを引いています。
これは前回説明した、実際の再生開始時間の誤差があるためです。

player_stopにも手を加え、clearPlayer()の呼び出し条件を変更します。

// 停止
var player_stop = function() {
  if (soundFile != null || pausing) {
    soundFile.stop(0);
    if(pausing) {
      clearPlayer();
    }
  }
}

これは先ほどonended時の処理でclearPlayer()を呼びだしているため二重処理防止のためであるのと、ポーズ中でonendedの処理を呼べないときのためになります。

次いで先ほどから登場するplayerStatus()の処理を追加します。

// 再生中なら一時停止ボタンを、
// 一時停止中なら再生ボタンを表示
var playerStatus = function() {
  if(context.state === 'running') {
    play.style.display="none";
    pause.style.display="inline";
  } else {
    play.style.display="inline";
    pause.style.display="none";
  }
  displayTime(audioTime);
}

AudioContext.stateはAudioContextの状態を示しています。
今回、running(動作中)はポーズボタンを、suspended(中断中)は再生ボタンを表示するようにしています。
onendedとplayer_play()でそれぞれ呼び出しているのはそのためになります。

displayTime()にも手を加えます。とはいえ、こちらはif文の条件に” && !pausing”を加えるだけです。

clearPlayer()には

pausing = false;

を追加します。

かなり手を加えることになりましたが、これで一時停止と再開が完了です。

まとめると、一時停止時にAudioContextを中断し、再開時にAudioContextも再開しています。
そして再生開始部分を中断した時間に合わせる、ということをしています。

リピート

さて、簡単なプレイヤーの作成も大詰めです。リピート機能の設定です。
今回は1曲リピートではなく、listの最後を再生したらまた最初の曲を再生していくものです。
また、次曲の再生もリピート機能がオンであるときのみとします。

sound()のonendedのclearPlayer();直下に以下のコードを追加します。

if(repeatFlag) {
  if(listNum < list.length - 1) {
    listNum++;
  } else {
    listNum = 0;
  }
  player_play();
}

リピートフラグが立っている場合、次の曲を設定し、再生するようしています。

次にリピートボタンの処理を記述します。

// リピート
var player_repeat = function() {
  if(repeatFlag) {
    repeatFlag = false;
    repeatBtn.src = "icon\\リピート_false.png";
  } else {
    repeatFlag = true;
    repeatBtn.src = "icon\\リピート_true.png";
  }
}

押下時のリピートフラグに合わせてオン/オフし、画像もわかりやすいよう差し替えています。

ストップ時にリピートフラグを折るため、soundFile.stop(0);の前に一行追加します。

repeatFlag = false;

これでリピート処理が完成し、晴れてプレイヤーが完成しました。

Web Audio APIにはここで紹介していない機能がたくさんあるので、調べて追加実装してみるのも良いと思います。

第1回はこちら
第2回はこちら

EOF.


【記事への感想募集中!】

記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!
  • こんな記事が読んでみたい、こんなことが知りたい、調べてほしい!という意見も募集中!
  • いただいた感想は今後の記事に活かしたいと思います!

感想フォームはこちら


【テクノデジタルではエンジニア/デザイナーを積極採用中です!】

下記項目に1つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事