このページの本文へ

Audio Data APIでブラウザーをシーケンサーに! (3/6)

2010年11月02日 10時00分更新

文●古籏一浩

  • この記事をはてなブックマークに追加
本文印刷

MMLを解析して楽曲を演奏する

 次に、MMLを解析して楽曲を演奏します。MMLデータを順番に解析していくために、再生(解析)中の位置を示す変数ptrを用意します。MMLデータは1音ずつ配列に入っているので、音が鳴り止んだら変数ptrの値を1つ増やしていきます。最後まで解析して音を鳴らせばMMLデータを元にした演奏ができます。

 演奏が終了するとオーディオオブジェクトにendedイベントが発生します。本来はこのendedイベントを捕捉して変数ptrの値を増やせればよいのですが、Firefox 4ベータ版の仕様なのか、自前で音を生成した場合はendedイベントが発生しません。同様に、MozAudioAvailableイベントも発生しません。

 そこでやむを得ずsetTimeout()を使い、演奏した秒数後にMMLを処理する関数を呼び出します(この方法では正確な音長は処理できませんが、今回は簡易的に採用しています)。

setTimeout("ptr++;playMML()", sec*1000);

 ここまでをまとめたのがサンプル2です。演奏ボタンをクリックするとテキストエリアに入力されたMMLデータが演奏されます。

【図】fig02.png

演奏ボタンをクリックするとMMLが解析され、対応する音が出力される

サンプル2

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8" /> 
<title>MMLを使って演奏する2</title> 
</head> 
<body>
<h1>MMLを使って演奏する2</h1>
<form>
<input type="button" value="演奏" onclick="initMML()" /><br />
<textarea cols="20" rows="5" id="track1">A4</textarea>
</form>
<script type="text/javascript">
var freq = [];  // 音階に応じた周波数を入れる配列
freq["R"] = 1;
freq["C"] = 261;
freq["D"] = 293;
freq["E"] = 329;
freq["F"] = 349;
freq["G"] = 392;
freq["A"] = 440;
freq["B"] = 493;
freq["#C"] = 277;
freq["#D"] = 311;
freq["#F"] = 370;
freq["#G"] = 415;
freq["#A"] = 466;
// 演奏前の初期化を行う
function initMML(){
    tempo = 60;   // テンポ設定(グローバル変数)
    ptr = 0;    // 読み出し位置を初期化(グローバル変数)
    playMML();
}
// 再生処理
function playMML(){
    var data = document.getElementById("track1").value;
    var MML = data.split(" ");  // 空白
    if (ptr >= MML.length) return;  // 最後まで演奏が終わっていたら以後の処理はしない
    var sdata = MML[ptr];
    var onkai = sdata.match(/[a-z]+/i)[0].toUpperCase();
    var sec = sdata.match(/\d+/);
    if (sdata.charAt(0) == "#") { onkai = "#"+onkai; }
    var sec = (60 / tempo) / sec; // 音長を計算
    startAudio(freq[onkai], sec);
}
// 指定された周波数の音を指定時間出力する
function startAudio(freq, sec){
    var sampleRate = 44100;   // 44.1kHz
    var audio = new Audio();
    audio.mozSetup(1, sampleRate);  // 1ch, 44kHz
    var bufferSize = Math.ceil(sampleRate * sec); // 再生秒数
    var data = new Float32Array(bufferSize);
    var k = 2* Math.PI * freq / sampleRate;
    for(var i=0; i<data.length; i++){
        data[i] = Math.sin(k * i);
    }
    audio.mozWriteAudio(data);
    setTimeout("ptr++;playMML()", sec*1000);
    audio.play();
}
</script> 
</body> 
</html> 

この連載の記事

一覧へ

この記事の編集者は以下の記事をオススメしています