WEBページでMP3を扱う方法

2018年6月21日

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

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

このブログを検索

プロフィール

自分の写真
プログラミングとサーバーを心の底から楽しむクリエーターです。 経営者であり、開発者でもありますが、得意としているのは、アイデア創出で、出来高は無限大です。

ブログ アーカイブ

QooQ