2025.08.29
Laravelで空判定にif文を使うとハマる理由
2017.09.05
プログラミングWeb Audio APIを使って簡単なプレイヤーを作ってみる(1)

こんにちは、新卒のshiroです。
実は入社前にほとんどプログラミングをしたことがないため、記事を書きながら勉強している最中です。
では、本題です。
今回から数回に分けてweb audio apiを利用して、ブラウザ上で動く簡単なミュージックプレイヤー(上記画像)を作成します。
HTMLファイルからjsファイルを分離して開発を行うため、以下に各種ファイルが入ったzipを添付します。
playerフォルダを任意の場所に展開してください。
主にjsフォルダ内のplayer.jsを編集して作成していきます。
なお、今回使用しているアイコンは素材サイト様からお借りしており、再配布はできないため入っていません。下記URLからのダウンロードをお願いします。
また、音声ファイルも同様の理由で配布できませんので、こちらも各自用意をお願いします。
各種ファイル:player.zip
素材サイト様:ICOON MONO
なお、今回はfirefox55.0.2での動作を前提としています。
具体的に以下の機能を実装します。
・再生/停止
・音量の変更
・再生中音楽のタイトル表示
・再生時間の表示
・ファイルの取り込み
・一時停止/再開
・リピート
再生/停止
今回はその中の「再生/停止」と「音量の変更」の実装を行いたいと思います。
player.jsの中に既に変数が記載されていますので、listの[]内に”音声ファイルの相対パス(拡張子まで)”を、audioNameの[]に”音声ファイル名”を記述しておいてください。
これらは後に「フォルダを指定したファイル取り込み」を作成する際、自動で入力されるようにします。
では、web audio apiの要であるaudioContextやデコードの処理を作成します。
古いwebkit系ブラウザでは、プレフィックスが必要です。
// AudioContextの作成
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
context.createGain = context.createGain || context.createGainNode;
// Bufferへのデコード
var getAudioBuffer = function(url,fn) {
  let request = new XMLHttpRequest();
  request.responseType = "arraybuffer";
  request.onreadystatechange = function() {
    // XMLHttpRequestの処理が完了しているか
    if (request.readyState === 4) {
      // レスポンスのステータスを確認
      // 200はリクエストに成功
      if (request.status === 0 || request.status === 200) {
        context.decodeAudioData(request.response, function(buffer) {
          fn(buffer);
        });
      }
    }
  };
  req.open("GET", url, true);
  req.send("");
};
XMLHttpRequest.readyStateはMDN web docsによると
| Value | State | Description | 
|---|---|---|
| 0 | UNSENT | Client has been created. open() not called yet. | 
| 1 | OPENED | open() has been called. | 
| 2 | HEADERS_RECEIVED | send() has been called, and headers and status are available. | 
| 3 | LOADING | Downloading; responseText holds partial data. | 
| 4 | DONE | The operation is complete. | 
となっており、ロードが完了している4を条件としています。
また、XMLHttpRequest.statusに関して、
・正常なレスポンスが返ってきている200
に加えて、
・file://等を読み込んだ時に返ってくる0
である場合、今回は正常と判断しています。
次に実際の再生処理の実装です。
var sound = function(buffer) {
  if (volumeControl == null) {
    volumeControl = context.createGain();
  }
  let source = context.createBufferSource();
  volumeControl.connect(context.destination);
  source.buffer = buffer;
  source.connect(volumeControl);
  // 外部の関数からはsoundFileで処理を行うことにする
  soundFile = source;
  playing = true;
  changeVolume();
  // 音の再生
  source.start();
}
既にvolumeControlが出てきていますが、字面の通り音量関係で使用しています。
createGainが音量のノードを生成する処理になります。
実際の音量変更は後ほど別に処理を追加します。
createBufferSourceは再生に必要なsourceを作成しています。
source.connect(volumeControl)でvolumeControlをsourceに接続しています。
こうすることで、volumeContorol.gain.valueの値を変更した際に音量を変更することができます。
source.start()で音声の再生を開始します。
ただし、ワンショットのように短い音声ではなく4~5分ある曲のような場合、実際の再生まで数秒の遅延が生じます。
sourceはグローバルではないので、最終的にsoundFileに入れています。
次いで、プレイヤーの設定をしていきます。
// プレイヤーの処理
// 再生
var player_play = function() {
  let bgm = list[0];
  getAudioBuffer(bgm,function(buffer) {
    sound(buffer);
  });
}
// 停止
var player_stop = function() {
  if (soundFile != null) {
    soundFile.stop(0);
  }
}
getAudioBufferの第1引数に音声ファイルのパスが渡されることによって、最初に作ったデコードを通して最終的にsoundを呼び出す形になります。
止める際は、soundFile.stop()と簡単です。
これで再生と停止ができます。
音量の変更
// 音量の変更
var changeVolume = function() {
  if (volumeControl != null) {
    volumeControl.gain.value = volume.value;
  }
}
これだけです。
先ほど、sound()内にvolumeControlを作成しました。
これにのgain.valueにrangeの値を代入しています。
HTMLを見てもらうとわかりますが、onchangeの度にこの関数を呼び出しており、これにより音量の変更を行っています。
ここで注意するべき点は、gain.valueは通常0から1の値を取るということです。
「通常」と書いているのは、0~1の外の値を取ってもエラーになることはないためです。
ただ実際どのように変わるのかは、-1にしてみてもよくわかりませんでした。
今回はただのボリュームコントローラーとして使用しているので、0から1の値を取るようにしています。
volumeControlが生成されていない状態で値を代入しようとすれば、当然エラーが返ってくるため、if文で囲っています。
また、再生開始時に音量が設定されるようsound()内でchangeVolume()を呼んでいます。
ここで直接値を指定してもいいのですが、音量の変更時に呼び出す必要があり、やることは結局同じなので、こちらに集約しています。
今回は以上となります。
次回は「再生中音楽のタイトル表示」と「再生時間の表示」を作成していこうと思います。
EOF.
【記事への感想募集中!】
記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!【テクノデジタルではエンジニア/デザイナーを積極採用中です!】
下記項目に1つでも当てはまる方は是非、詳細ページへ!Qangaroo(カンガルー)
【テクノデジタルのインフラサービス】
当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。
最近の記事
1
2025.08.29
Laravelで空判定にif文を使うとハマる理由
2

2025.08.29
Git SSH接続でfetch/pullができなくなった時の対処法
3

2025.08.28
【体験談】Amazon Linux 2でMySQLインストール時のOpenSSL・GPG key エラーにハマった話
4
2025.08.28
【AWS】SSMポートフォワーディングとInstance Connectを利用したプライベートEC2へのSSH接続手順
5
2025.07.24
Log::info()が使えない!?Laravel.logのPermission denied エラーを解決する(Docker環境)
タグ検索