WEBページでMP3を扱う方法

2018年6月21日

Sound テクノロジー プログラミング

一昔前に流行った言葉で「リッチコンテンツ」というのがあります。 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音楽素材/魔王魂

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ