【Web Audio API入門】音楽プレイヤー作成 第2弾

2014年9月15日

Pocket

aud0002-009 のコピー

音楽プレイヤー作成 第2弾です!
今回は、一時停止、音量調整機能を実装します。
 

音量調節

inputの属性rangeを使用してボリュームを調節するつまみを作ります。
rangeのValueは0から100までです。真ん中の50に初期値を設定します。
rangeが変更されたらvolumeChange()のファンクションが呼び出されます。
 
HTML

<body>
    <p class="botton" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>

 
音量を調整するにはGainNodeを使用します。
gainNodeのValue属性に音量の値を設定することによって音量を設定できます。
 
JavaScript

function play(){
     //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜

     //GainNodeを作成する
     gainNode = context.createGain();

     //sourceをGainNodeへ接続する
          source.connect(gainNode);

     //GainNodeをAudioDestinationNodeに接続
     gainNode.connect(context.destination);

     //音量を表記
     gainNode.gain.value = 3.0;

     //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜
}

function volumeChange(){
    //range属性のvalue取得
    var value = document.getElementById( "volume" ).value;
    //gainNodeの値に変更
    var volume = ( value / 10 ) - 1;

    //gainNodeに代入
    gainNode.gain.value = volume;
} 

range属性からvalueを取得し、gainNodeのvalueに代入します。
rangeのvalueをそのまま代入すると音がでかすぎるので、valueの値を10分の1にします。
gainNodeのvalueは-1で音がなくなるのでrangeが0のとき、gainNodeが-1になるようにvalueから-1をしています。
 
 

一時停止

再生をストップしたら、AudioBufferSourceNodeが削除されるので、次に再生を押しても始めからのスタートになってしまいます。
一時停止ができないプレイヤーは使い勝手が悪いので、一時停止機能を作っていきます。
 
実はstart()関数には、スタートする時間と、曲のどの位置からスタートするかを入れれるのです。
start(スタート時間,曲のスタートする位置の時間)と表記します。
とは言うものの、その時間は自分で計算しなくてはなりません。
 
少し複雑なコードになってきました。
 
HTML

<body>
    <p id="playBotton" class="botton play" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>

 
JavaScript

//始めからスタートのフラグをたてる
var first_flg = true;

function play(){

    if($('#playBotton').hasClass('pause')){

        pause();

    }else if($('#playBotton').hasClass('play')){

         //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜

         //始めからの再生の場合
        if(first_flg){
    	    //スタート時間を変数startTimeに格納
    	    startTime = context.currentTime;
    	    replayTime = startTime;
    	    //停止されている時間を初期は0にしておく
    	    pausingTime = 0;
    	    first_flg = false;
        }else{
    	    //再スタート時間を変数replayTimeに格納
    	    replayTime = context.currentTime;
    	    //再スタートの時間からpauseした時間を引いて、停止されている時間の合計に足していく
    	    pausingTime += replayTime - pauseTime;
        }

        //replayTimeからstartTimeとpausingTime引いた時間が曲のスタート時間
        var playTime = replayTime - startTime - pausingTime;

        //再生
        source.start(0,playTime);

        //クラスとテキスト変更
        $('.play').removeClass('play').addClass('pause').html('PAUSE');
    }
} 

function pause() {	
    //止めた時間を変数pauseTimeに格納
    pauseTime = context.currentTime;
    source.stop(0);

    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}

function stop(){
    source.stop();
    //初期値に戻す
    first_flg = true;
    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}

ここで重要なのがcontext.currentTime属性です。
context.currentTimeはcontextが作成された時点からの時間を取得します。
なので、再生ボタンを押した時間ではありません。
これがややこしいのですが、この時間をもとにスタートした時間やストップした時間を変数などに格納し、足したり引いたりして目的の数値を計算します。
再生ボタンにidをふり、play()が呼び出されたとき、id=”playBotton”がplayのクラスを持っていたら再生をpauseのクラスを持っていたら一時停止するように分岐しています。
 
 
 

DEMO

下記は今回の機能を追加したソースです。
 
DEMO
 
 
HTML

<!DOCTYPE html>
<html>
<head>
    <!--jQueryを使用する-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
    <p id="playBotton" class="botton play" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>
</html>

 
JavaScript

window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext; 
try {
    var context = new AudioContext();
} catch (error) {
    alert('このブラウザは未対応です');
}

 
var xml = new XMLHttpRequest();
//読み込むデータのURLを書く
xml.open('GET', '音楽ファイル', true);
xml.responseType = 'arraybuffer';
xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;
            };
            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };
 
            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);
 
        }
    }
};
xml.send(null);


//始めからスタートのフラグをたてる
var first_flg = true;   

function play(){

    if($('#playBotton').hasClass('pause')){

        pause();

    }else if($('#playBotton').hasClass('play')){

        //AudioBufferSourceNodeを作成する
        source = context.createBufferSource();
        //bufferプロパティにAudioBufferインスタンスを設定
        source.buffer = buffer;
        //ループ
        source.loop = false; 
        //AudioBufferSourceNodeインスタンスをdestinationプロパティに接続
        source.connect(context.destination);

        //GainNodeを作成する
        gainNode = context.createGain();
        //sourceをGainNodeへ接続する
        source.connect(gainNode);
        //GainNodeをAudioDestinationNodeに接続
        gainNode.connect(context.destination);
        gainNode.gain.value = 4;

        source.start = source.start || source.noteOn;
        source.stop  = source.stop  || source.noteOff;

        //始めからの再生の場合
        if(first_flg){
    	    //スタート時間を変数startTimeに格納
    	    startTime = context.currentTime;
    	    replayTime = startTime;
    	    //停止されている時間を初期は0にしておく
    	    pausingTime = 0;
    	    first_flg = false;
        }else{
    	    //再スタート時間を変数replayTimeに格納
	    replayTime = context.currentTime;
	    //再スタートの時間からpauseした時間を引いて、停止されている時間の合計に足していく
	    pausingTime += replayTime - pauseTime;
        }

        //replayTimeからstartTimeとpausingTime引いた時間が曲のスタート時間
        var playTime = replayTime - startTime - pausingTime;

        //再生
        source.start(0,playTime);

        //クラスとテキスト変更
        $('.play').removeClass('play').addClass('pause').html('PAUSE');
    }
}

 
function pause() {	
    //止めた時間を変数pauseTimeに格納
    pauseTime = context.currentTime;
    source.stop(0);

    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function stop(){
    source.stop();
    first_flg = true;
    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function volumeChange(){
    //range属性のvalue取得
    var value = document.getElementById( "volume" ).value;
    //gainNodeの値に変更
    var volume = ( value / 10 ) - 1;

    //gainNodeに代入
    gainNode.gain.value = volume;
} 

 
 
 
今回はコードの量の割には機能がしょぼい感じがしますが、とりあえずオーディオになってきましたね。
次回は、音楽データの視覚化についてリポートします。
 
 
 
【Web Audio API入門】音楽プレイヤー作成 第1弾
【Web Audio API入門】音楽プレイヤー作成 第3弾

このサイトについて


『意識低い系女と高い系男の一年戦争』はクリエイティブ会社エアゼの代表2人が運営するブログです。エアゼは、アプリ・Web・IoT・インタラクティブコンテンツのデザイン・開発を手がけています。

エアゼ ホームページ