[Javascript] AudioAPIを使って、再生コントロールと同時に音量コントロールをする方法

2019年11月1日

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

日々「楽しい」を求めてプログラミングやその他の活動をしている下駄です。 ゲーム制作会社が、インターネットを利用したサービス展開しないと、企業維持ができなくなり、色々な娯楽がWEBと親和性を持ってきましたが、テレビも電話も色々な家電や、生活のあらゆるモノがWEB化しています。 IoTと言ってしまうとなんだかビジネスっぽく感じますが、腕時計やメガネがスマートフォンで管理されるのが当たり前になってきて「ウェアラブル」という言葉がようやく日の目を見始めてきた感じがしますが、洋服や靴もデジタル化するのはもう少し先の未来になりますが、確実に何かしらのIT化が行われるのは間違いないでしょうね。 インターネット黎明期においては、ホームページで音楽を流す事は結構ないらんことしいのホームページとしてウザがられてきましたが、ここ最近ではそんなに珍しくもなくなってきているようです。 HTML5にはaudioタグという便利なタグがあり、誰でも簡単にブラウザに音楽を設置することが可能になってきましたが、ゲームや音を効果的なサービスに組み込む場合は、audioAPIを使って便利にコントロールしたほうが良さそうです。

audioAPIを使いたい

audioAPIはHTML5audioと違い、javascriptでゴリゴリにプログラミングしないと仕様出来ないため、フロントエンジニアが簡単に設置するというレベルではありません。 ただ、データのキャッシュ化やメモリ管理などがプログラミングによって管理できるため、タイミングを合わせて利用するゲーム効果音などで便利に使用することができます。 今回は、音楽ファイルを読み込んで「再生」「停止」「音量」を簡単にコントロールできるスニペットを掲載しておきますので、簡易に使いたい人はコピペしてお使いください。

ソース

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>audio api</title> <script src="audioAPI.js"></script> </head> <body> <h1>Audio API</h1> <button id="play">play</button> <button id="mute">solo</button> </body> </html> window.audio_play = (function(){ var __event = function(target, mode, func){ if (target.addEventListener){target.addEventListener(mode, func, false)} else{target.attachEvent('on' + mode, function(){func.call(target , window.event)})} }; var $$ = function(file){ switch(document.readyState){ case "complete" : this.set(file);break; case "interactive" : __event(window , "DOMContentLoaded" , (function(file){this.set(file)}).bind(this,file));break; default : __event(window , "load" , (function(file){this.set(file)}).bind(this,file));break; } }; $$.prototype.set = function(file){ if(!file){return} this.load(file); __event(document.getElementById("play") , "click" , (function(e){this.play(e)}).bind(this)); __event(document.getElementById("mute") , "click" , (function(e){this.mute(e)}).bind(this)); }; // mp3データの読み込み $$.prototype.load = function(file){ var request = new XMLHttpRequest(); request.open('GET', file, true); request.responseType = 'arraybuffer'; request.onload = (function(e){this.loaded(e)}).bind(this); request.send(); }; // mp3読み込み完了時処理 $$.prototype.loaded = function(e){ if(!e.target){return} // var request = e.target; switch(e.target.status){ case 200: console.log("Success : loaded. ("+ e.target.responseURL +")"); break; case 404: console.log("Error : File not found. ("+target.responseURL+")"); return false; } this.context = new (window.AudioContext || window.webkitAudioContext)(); this.context.decodeAudioData(e.target.response, (function(buffer){this.context.buffer = buffer}).bind(this)); this.context.playTime = 0; this.context.pauseTime = 0; this.context.gainValue = 1; }; $$.prototype.play = function(e){ if(!this.context || !e || !e.target){return} // play if(e.target.textContent == "play"){ this.gainNode = this.context.createGain(); this.gainNode.connect(this.context.destination); this.gainNode.gain.value = this.context.gainValue; this.gainSource = this.context.createBufferSource(); this.gainSource.connect(this.gainNode); this.gainSource.buffer = this.context.buffer; this.gainSource.start(0, this.context.pauseTime); this.context.playTime = this.context.currentTime - this.context.pauseTime; e.target.textContent = "pause"; } // pause else{ this.gainSource.disconnect(); this.gainSource.stop(); this.context.pauseTime = this.context.currentTime - this.context.playTime; e.target.textContent = "play"; } }; $$.prototype.mute = function(e){ if(!this.context || !this.gainNode || !e || !e.target){return} // solo->half (1->0.5) if(e.target.textContent == "solo"){ this.gainNode.gain.value = 0.5; this.context.gainValue = 0.5; e.target.textContent = "half"; } // half->mute (0.5->0) else if(e.target.textContent == "half"){ this.gainNode.gain.value = 0; this.context.gainValue = 0; e.target.textContent = "mute"; } // mute->solo (0->1) else{ this.gainNode.gain.value = 1; this.context.gainValue = 1; e.target.textContent = "solo"; } }; return $$; })(); new audio_proc("s.mp3"); インスタンスとして設置しているので、"audio_proc"にmp3ファイルパスを添えて起動すると、再生準備が簡単にできます。

解説

audioAPIの難点として、自動再生ができないというデメリットがあります。 HTML5audioは、autoplayが機能として実装できるので、WEBページを読み込んだ段階で音楽再生をすることができるんですが、audioAPIの場合は、ユーザーのクリックイベントなどアクションをフラグにしないと再生開始が行なえません。 ゲームで使おうとする場合、起動したタイトル画面では、HTML5audioを使ってBGMを流し、「スタートボタン」を押したらaudioAPIでコントロールするのがいいでしょう。 今回「音量」まで仕様で入れたのは、audioAPIの仕様が結構複雑で、単純に音楽を再生するだけであればもっと簡単なソースで書けるのですが、音量をコントロールしようとすると「gain」コントロールというのをしなければいけないため、gainNodeという受け皿を作って操作しています。 僕の調べた所で、最も簡単な書き方でコーディングしてみました。 あとaudioAPIで最もめんどくさいのが、「再生」と「停止」の方法が通常のプログラミングでは考えにくい面倒くささであるという点です。 なんとなく、音楽ソースを"start"させて"stop"させるだけだと思いがちですが、audioソースのstartはメモリ展開してから1回しか行えないというルールがあり、2度目の再生がうまく行かない経験をした人は頭をひねることでしょう。 そのため、再生のたびに、"createBufferSource()"でメモリ展開を毎回行っています。 まあ、お決まりごとだと割り切って関数化してしまえばさほど問題はないでしょう。 これを使って色々なエンタメWEBサイトが作れそうですね。

人気の投稿

このブログを検索

ごあいさつ

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

ブログ アーカイブ