HTML5で音声を再生するには単純にaudio
タグを使うだけで実現できますが、今回はJavaScriptから再生や停止をコントロールしたいと思います。
音声ファイルを再生する
実行例
以下から実際のサンプルをお試しいただけます。ボタンを押す度に再生と一時停止を繰り返します。 miku3.net
音声ファイルは「魔王魂」さんからお借りしました。
ソース
ボタンの上に表示されるアイコンはFontAwesomeを利用しています。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>HTML5 Audio Sample1</title> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> <style> footer{ text-align:right; font-size:12px; } #btn-play{ width:100px; height:40px; padding:10px; font-size:18px; } </style> </head> <body> <h1>HTML5 Audio Sample1</h1> <!-- 音声ファイル --> <audio id="bgm1" preload loop> <source src="op.ogg" type="audio/ogg"> <source src="op.mp3" type="audio/mp3"> </audio> <!-- 再生ボタン --> <button id="btn-play" type="button"><i class="fas fa-play"></i></button> <script> const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ // pausedがtrue=>停止, false=>再生中 if( ! bgm1.paused ){ btn.innerHTML = '<i class="fas fa-play"></i>'; // 「再生ボタン」に切り替え bgm1.pause(); } else{ btn.innerHTML = '<i class="fas fa-pause"></i>'; // 「一時停止ボタン」に切り替え bgm1.play(); } }); /** * [event] 再生終了時に実行 */ bgm1.addEventListener("ended", ()=>{ bgm1.currentTime = 0; // 再生位置を先頭に移動(こいつはなくても大丈夫です) btn.innerHTML = '<i class="fas fa-play"></i>'; // 「再生ボタン」に変更 }); </script> </body> </html>
解説
JSで再生と一時停止
audioタグをJavaScriptで操作するのは非常に簡単です。例のようにdocument.querySelector()
などでHTMLの要素を取得、play()
メソッドで再生、pause()
で一時停止します。
const bgm1 = document.querySelector("#bgm1"); // <audio> if( ! bgm1.paused ){ bgm1.pause(); } else{ bgm1.play(); }
ただ残念ながら最近のブラウザーはセキュリティの関係でこれだでは動作してくれません。
自動再生はできない
最近のブラウザはセキュリティの関係で自動的に音声を再生することができません。
ページが読み込まれるとすぐに音声(または音声トラックを含む動画)の再生を自動的に開始することは、ユーザーにとって歓迎されない驚きです。 (中略)ユーザーがこれを制御できるようにするために、ブラウザーは多くの場合、さまざまな形式の自動再生のブロックを提供します。
メディアおよびウェブオーディオ API の自動再生ガイド(MDN)
そのため音声を再生するためには、以下のいずれか1つ以上の条件をクリアする必要があります。
- 音量が0またはミュートに設定されている場合
- ユーザーがクリック、タップ、キーを押すなどの操作を行った場合
- サイトがブラウザの「ホワイトリスト」に登録されている場合
- サイトがブラウザの「自動再生機能ポリシー」により許可されている場合
初めて訪問したユーザーに音を再生してもらうためには現実的には2番の方法を取ることが多いでしょう。そこで今回のサンプルではユーザーがボタンをクリックしたイベントに紐付けて音声を再生しています。
const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ // 再生する bgm1.play(); });
なおページが表示されたあと一度でも音声を再生しておけば、あとは自由に好きなタイミングで鳴らすことができます(ページを移動したり再読み込みした場合はもう一回クリックしてもらう必要があります)
複数のファイル形式を提供する
今回のサンプルではOgg形式の音声ファイルを利用していますが、ブラウザによっては対応していないため再生することができません。
以下、簡単な対応表示になります。詳細な対応バージョンなどが知りたい場合は「形式」のリンクをクリックすると参考にさせていただいた「Can I use」へ飛びます。
形式 | IE | Edge | FireFox | Chrome | Safari | Safari(iOS) | Browser | Chrome |
---|---|---|---|---|---|---|---|---|
Ogg | ❌ | ⭕ | ⭕ | ⭕ | ❌ | ❌ | ⭕ | ⭕ |
MP3 | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ |
WAV | ❌ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ |
- はAndroidの意
- Android BrowserはAndroid6あたりまで標準で搭載されていたブラウザーです。
そこでブラウザがファイル形式に対応していない場合を考え、source
タグを利用すると複数のファイル形式を同時に提供することが可能です。これでOgg形式に対応していないブラウザはMP3形式が採用されるというわけです(逆のパターンもあり)。
<audio id="bgm1" preload loop> <source src="op.ogg" type="audio/ogg"> <source src="op.mp3" type="audio/mp3"> </audio>
audioタグのみで再生する
audioタグにcontrols
属性を付けてあげると簡単な再生機能が表示されます。
<audio src="op.ogg" controls loop></audio>
以下が実行例です。例えば自分の作った楽曲をブログなどで公開する場合はこちらが手軽ですね。ただし前述の通りサイトを訪れた瞬間に自動的に音声を再生することができない点に注意が必要です。
audioタグで用意されている属性は以下の通りです。
- autoplay
- 再生可能な状態になった時点で自動的に再生が始まります。現在では実質的に利用することができません。
- controls
- ブラウザが再生や一時停止、シークなどの簡単な機能を提供します。
- loop
- 最後まで再生すると一番最初に自動的に戻ります。ループ再生ですね。
- muted
- ミュート(無音)になります。
- preload
- 再生されるかどうかに関わらずファイル全体をダウンロードします。
none
を指定した場合はダウンロードせず、metadata
を指定するとファイルの長さなどの情報のみサーバから取得します。
audioタグを利用しない
Audioクラスを利用するとHTMLのaudioタグを一切使うことなく、JavaScriptのみで完結します。
const bgm1 = new Audio("op.ogg"); btn.addEventListener("click", ()=>{ bgm1.play(); });
audioタグが提供する便利機能(対応ファイル形式を自動的に判別、preload
など)は自分で実装することになるのでご注意を。
再生時のコントロール方法
ボリューム
ボリュームの調整は文字通りvolume
プロパティを介して行います。volume
を参照すると現在設定されているボリュームが返ります。volume
には0〜1の間の値を設定します。0が無音、1が最大音量です。
const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ const volume = bgm1.volume; // 現在のボリュームを取得 bgm1.volume = volume + 0.2; // 現在のボリュームを上げる bgm1.play(); });
注意点としてiPhoneやiPadなどiOSのWebブラウザではボリュームの変更ができません。参照は可能ですが常に1が返ってきます。
またmuted
プロパティにtrue
を渡しても同様にミュートすることができます。意図的に無音にする場合はこちらの方が分かりやすそうですね。
bgm1.muted = true; //ミュート bgm1.muted = false; //ミュート解除
フェードイン/フェードアウト
長くなったので別の記事にしました。以下をご覧ください。 blog.katsubemakito.net
原理としてはsetInterval()
で少しずつ音量を変化させてあげる感じです。こちらもiOSのWebブラウザでは動作しませんのでご注意を。
曲の長さを知りたい
duration
プロパティを参照します。
const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ console.log( bgm1.duration ); // コンソールに表示 });
ミリ秒単位で返ってきますね。
51.644082
現在の再生位置を知りたい
currentTime
プロパティを参照します。
const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ if( ! bgm1.paused ){ bgm1.pause(); console.log( bgm1.currentTime ); // 停止した再生位置をコンソールに表示 } else{ bgm1.play(); } });
こちらもミリ秒単位で返却されますね。
1.600941 5.156189
再生位置を変更したい
いわゆるシークするには、先ほどのcurrentTime
に移動先の秒数を設定します。
const bgm1 = document.querySelector("#bgm1"); // <audio> const btn = document.querySelector("#btn-play"); // <button> btn.addEventListener("click", ()=>{ bgm1.currentTime = 10.0; // 10秒の位置から再生開始 bgm1.play(); }
絶対的な位置ではなく、相対的に3秒だけ先送りしたい場合は単純にプラスしてあげるだけです。
bgm1.currentTime += 3.0;
イベント処理
たくさんのイベントが用意されていますが、主要なものを抜粋します。
イベント | 説明 |
---|---|
loadedmetadata | 再生時間などのメタ情報の読み込みが完了した |
loadeddata | 現在の再生位置で再生を開始できる準備が完了した |
play | 再生を開始した |
pause | 再生を停止した |
ended | 再生が完了した |
timeupdate | 再生位置が変更された |
volumechange | ボリュームが変更された |
error | エラーが発生した |
addEventListener
でイベント毎に処理を定義します。
const bgm1 = document.querySelector("#bgm1"); // <audio> bgm1.addEventListener("loadeddata", ()=>{ console.log("event: 再生できるよ!"); }); bgm1.addEventListener("play", ()=>{ console.log("event: 再生を開始したよ!"); });
その他のイベントはMDNなどをご覧ください。 developer.mozilla.org
課題
onloadイベントが取れない
現時点で音声ファイルの読み込み(ダウンロード)が完了したイベントが取れません。ストリーミング再生が前提となっており再生可能になったら(途中までダウンロードしたら)再生するという考え方が基本なようです。これだと例えばボタンを押した瞬間に鳴らしたいといった場合に困りますよね。
これを検知するためには別の方法を取る必要があります。別の記事にしましたので詳しくはこちらを参照ください。 blog.katsubemakito.net
iOSでボリュームの調整ができない
iOSのブラウザを対象環境とする場合に、音量の調整が必要な場合はWeb Audio APIを利用する必要があります。