Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

【WebAudioAPI】超簡易MML(作り始めw)

 どうも!LSSです!!

 

WebAudioAPIでやりたかった事のひとつに、
MMLを再生するプレイヤーを作る」
があります。

「オクターブ変更は…」「音の長さを変えるには…」「休符は…」「テンポ指定は…」などなど、考えれば考えるほど大変そうになってきますw

 

ので、とりあえずは「ごくごく簡単なモノ」をまずは試しに作ってみました^^

(LSS得意のハードル下げw)

 

 

超簡易MMLプレイヤー

 

まずは「鳴らす」ボタンを押してください。

「ミファソミッ、ファソミレミファレッ、ミファレ…」みたいな短い音楽が流れます。

これが、そのボタンの上にある入力欄の文字列を解釈して、順に音を鳴らしたものになります。

 

入力欄の内容を書き換える事で、オリジナルの音楽を演奏できます!

といっても、「超簡易」ですので、入力できる文字は「cdefgab」のどれかと「r」の8種類しか認識しません^^;

「cdefgab」が「ドレミファソラシ」に対応し、「r」は休符となります。

例えば入力欄に「cde」と3文字だけ入れて「鳴らす」を押すと「ドレミ」と鳴ります。

 

 

MMLとは

「ミュージック マクロ ランゲージ」の略称です。

文字列で「cde」と書くと「ドレミ」と鳴らしてくれるようなプログラムの、「cde」に当たる部分です。

「ランゲージ」というからには一種の「言語」で、「音楽再生専門のプログラム言語」と捉える事もできます。

 

…ただし、今回ググってみたのですが、MMLの書き方のルールは明確な規格がなく、再生プログラムによってまちまちなようですね。

逆に言えば、これから自分が再生プログラムを作るには過去の規定に囚われずに好きに作っていい、という事?w

でも、やるなら分かりやすいものにしたいですね^^

 

 

 

「超簡易」とはいえ、MMLプレイヤーを名乗るのはおこがましいレベルw

今回のものは、1オクターブの範囲内でしか鳴らせないわ、音の長さも指定できない、半音階すら表現できない、と、あまりに簡単な作りとなっていますw

 

ただ、曲を書くのはとても楽になるので、これもまた機能追加した上で、演奏プログラムをお披露目したいですね^^

(最低でもオクターブ変更・音の長さ指定・副旋律の実装ぐらいは…。) 

 

 

一応…今回のコード!

 <p><input id="mml" size="30" type="text" value="efgerfgedefdrefdcdecrcdefrgrarbr" /></p>
<p><input id="btn" type="button" value="鳴らす" /></p>
<script>// <![CDATA[
AudioContext = window.AudioContext || window.webkitAudioContext;
ctxa=new AudioContext();
btn.addEventListener('click',mmlplay,false);
oct=4;
ngs=0.25;
onkai=[0,2,4,5,7,9,11];
pos=0;
function mmlplay(){pos=0;tmr();}
function tmr(){
if(mml.value.charAt(pos)>='a' && mml.value.charAt(pos)<='g'){tm0=setTimeout('tmr()',ngs*1000);oc0p(onkai['cdefgab'.indexOf(mml.value.charAt(pos))],ngs);pos++;}else{
if(mml.value.charAt(pos)=='r'){tm0=setTimeout('tmr()',ngs*1000);pos++;}else{pos++;}
}
}
function oc0p(a,b) {
oc0=ctxa.createOscillator();
oc0g=ctxa.createGain();
oc0t=ctxa.currentTime;
oc0.type='triangle';
oc0.frequency.value=442*Math.pow(2,(a-9)/12+oct-4);
oc0g.gain.setValueAtTime(0.01, oc0t);
oc0g.gain.linearRampToValueAtTime(0.3, oc0t+0.1 );
oc0g.gain.linearRampToValueAtTime(0.01, oc0t+b );
oc0.connect(oc0g);
oc0g.connect(ctxa.destination);
oc0.start();
oc0.stop(oc0t + b);
}
// ]]></script>

 

 

 

ってなとこで、今回はこのへんで!

次回もまた、よろしくお願いします^^