一昔前に流行った言葉で「リッチコンテンツ」というのがあります。
WEBマーケティング系をやっている人であれば、「懐かしい」と感じるかもしれません。
リッチコンテンツとは
言葉自体は古く感じますが、インターネットWEBページにおいて、動画や音楽、効果音を再生する事は、コンテンツとしてクオリティを感じてもらいやすいと思います。
今回はMP3をWEBページで再生する時に、AudioAPIの扱いに少し戸惑ったので、まとめておくために記事にしておきました。
WEBページでmp3を再生する方法
1. audioタグ
もっとも簡単な方法ですが、audioタグにmp3ファイルのURLを指定するだけで、コントローラも含めて簡単に表示する事ができ、手軽に再生できます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>mp3-player</title>
</head>
<body>
<h1>MP3 Player</h1>
<audio src="https://maoudamashii.jokersounds.com/music/bgm/mp3/bgm_maoudamashii_piano41.mp3" controls>
<p>audioタグをサポートしていないブラウザです。</p>
</audio>
</body>
</html>
2. sourceタグ
audioタグとほぼ同じですが、少し書き方を変えて登録でき、複数のコンテンツに対応できます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>mp3-player</title>
</head>
<body>
<h1>MP3 Player</h1>
<audio controls="controls">
<source src="https://maoudamashii.jokersounds.com/music/bgm/mp3/bgm_maoudamashii_piano41.mp3" type="audio/mpeg">
<p>audioタグをサポートしていないブラウザです。</p>
</audio>
</body>
</html>
3. AudioContext
mp3ファイルの読み込みを完了してから、色々な作業を行いたい場合に、onloadイベントを利用できないので、AudioContextを利用する必要があります。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>mp3-player</title>
<link rel="stylesheet" href="context.css">
</head>
<body>
<h1>MP3 Player</h1>
<button id="play">play</button>
<button id="stop">stop</button>
<div id="info"></div>
<script src="context.js"></script>
</body>
</html>
#info,
button{
border:1px solid #AAA;
margin:8px 4px;
padding:4px;
border-radius:4px;
text-align:center;
font-size:12px;
display:inline-block;
}
#info{
width:200px;
}
button{
width:100px;
}
;(function(){
var $$ = function(soundFile){
window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext;
try {
$$.prototype.context = new AudioContext();
} catch (error) {
alert('このブラウザは未対応です');
}
var request = new XMLHttpRequest();
request.open('GET', soundFile, true);
request.responseType = 'arraybuffer';
request.onload = function () {
console.log("music loaded !");
$$.prototype.setEvent();
$$.prototype.context.decodeAudioData(
request.response,
function(buffer) {
$$.prototype.buffer = buffer;
$$.prototype.setEvent2();
console.log(buffer);
},
function(e) {
console.error('ERROR: context.decodeAudioData:', e);
}
);
};
request.send();
};
$$.prototype.data = {
startTime : 0,
currentTime : 0
};
$$.prototype.setEvent = function(){
var btn_play = document.getElementById('play');
var btn_stop = document.getElementById('stop');
btn_play.addEventListener('click', function() {
$$.prototype.play();
return;
if (btn_play.textContent !== "play") {
$$.prototype.pause();
btn_play.innerHTML = 'play';
}
else {
$$.prototype.play();
btn_play.innerHTML = 'pause';
}
});
btn_stop.addEventListener('click', function() {
$$.prototype.stop();
btn_play.innerHTML = 'play';
});
};
$$.prototype.setEvent2 = function(){
$$.prototype.btn_info = document.getElementById('info');
setInterval(function(){
time = $$.prototype.setFormatTime($$.prototype.getCurrentTime());
dura = $$.prototype.setFormatTime($$.prototype.buffer.duration);
$$.prototype.btn_info.innerHTML = time +" / "+ dura;
},30);
};
// タイムラインの時間表示フォーマット
$$.prototype.setFormatTime = function(time){
var time2 = parseInt(time * 10 , 10) /10;
var m = parseInt(time2 / 60 , 10);
m = (m < 10) ? "0" + m.toString() : m;
var s = parseInt(time2 % 60 , 10);
s = (s < 10) ? "0" + s.toString() : s;
var ms = parseInt((time % 1) * 100);
ms = (ms < 10) ? "0" + ms.toString() : ms;
return m +":"+ s +":"+ ms;
};
$$.prototype.play = function(){
if(typeof $$.prototype.source !== "undefined"){return;}
var context = $$.prototype.context;
var buffer = $$.prototype.buffer;
$$.prototype.source = context.createBufferSource();
$$.prototype.source.connect(context.destination);
$$.prototype.source.buffer = buffer;
$$.prototype.source.start(0,$$.prototype.data.currentTime);
$$.prototype.data.startTime = $$.prototype.context.currentTime - $$.prototype.data.currentTime;
};
$$.prototype.stop = function(){
if(typeof $$.prototype.source === "undefined"){return;}
$$.prototype.source.disconnect();
$$.prototype.source.stop();
$$.prototype.data.currentTime = $$.prototype.context.currentTime - $$.prototype.data.startTime;
delete $$.prototype.source;
}
$$.prototype.getCurrentTime = function() {
if(typeof $$.prototype.source === "undefined") {
return $$.prototype.data.currentTime;
}
if($$.prototype.data.startTime) {
return $$.prototype.context.currentTime - $$.prototype.data.startTime;
}
return 0;
};
new $$("get.php?url=https://maoudamashii.jokersounds.com/music/bgm/mp3/bgm_maoudamashii_piano41.mp3");
})();
<?php
header("Access-Control-Allow-Origin: *");
echo file_get_contents($_REQUEST["url"]);
AudioContextを極める
audioタグとsourceタグは、さほど注意点はなく、読み込みタイミングなどを厳密にコントロールしないのであれば、mp3ファイルに対してファイルリンクをセットするぐらいなのですが、AudioContextを使ったやり方はかなり癖が強かったので、下記に説明しておきます。
フロー説明
1. ajaxにより、mp3を読み込む
2. データ読み込み完了したonsuccessのタイミングで、音源の秒数などを取得
3. 再生タイミングで"createBufferSource"を実行して音源を都度セット
4. 停止タイミングで、sourceに保存しているデータをdeleteします。
つまずきポイント
何故かわから無いのですが、context読み込みが完了し始めた段階で再生していないのにも関わらず、currentTimeがカウントアップされていきます。
そのため、startTime , pauseTimeをそれぞれ保持して、ポーズ→再生などの際に値を計算してはめこまなければいけません。
audioタグでは、こうしためんどくささはなく、jsでcurrentTimeが普通に取得できたのに、この仕様は正直いただけない感じですね。
音源設置の注意
通常は、フリー音源サイトのmp3をファウンロードして、mp3ファイルを同じサーバーに設置するのですが、今回は手抜きをして、フリー音源サイトの直リンクで行なっています。
その際に、サーバーアクセスに問題があったので、phpで一旦サーバーダウンロードする仕様にしています。
この点は、あまり真似していただかなくていいです。
音源リンク
今回の記事で使用させていただいたフリー音源のサイトです。
無料・フリー高音質BGM音楽素材/魔王魂
0 件のコメント:
コメントを投稿