
音をFlashPlayerで生成して鳴らすことができるようになったので、その音の音階(高さ)や音価(長さ)を変化させて、一つ簡単なメロディーを演奏させてみたいと思います。
2008.10.28追記
> 最新のFlash Player 10に対応しました。
今回は伝説のあの楽曲、「チャルメラ」を演奏させてみます。
一応、譜面を作ってみました。アストロ・チャルメラです。

テンポ(一分間に四分音符が鳴る数)は、120とします。
それではコードとサンプルデモをどうぞ。
AstroDynamicSoundTest2.as
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.utils.Timer;
public class AstroDynamicSoundTest2 extends Sprite
{
private var sound:Sound;
private var ch:SoundChannel;
private var timer:Timer;
private var G3:Number = 391.995;
private var A4:Number = 440.000;
private var B4:Number = 493.883;
private var pitch:Number = 0;
private var volume:Number;
private var samplingRate:uint = 44100;
private var bufferSize:uint = 2048;
public function AstroDynamicSoundTest2()
{
// プリロード
this.loaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
}
private function loadCompleteHandler(event:Event):void
{
this.loaderInfo.removeEventListener(Event.COMPLETE, loadCompleteHandler);
sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataHandler);
ch = sound.play();
var bpm:Number = 120;
var bps:Number = 60 / bpm;
var tick:Number = bps * 1000;
tick /= 4; //for 16note
tick = Math.round(tick);
var duration:uint = 27;
volume = .2;
timer = new Timer(tick, duration);
timer.start();
timer.addEventListener(TimerEvent.TIMER, function (e:TimerEvent):void
{
var target:Object = e.currentTarget;
switch(target.currentCount)
{
case 1:
case 10:
case 14:
case 18:
volume = .2;
pitch = G3;
break;
case 2:
case 9:
case 15:
case 17:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
volume = .2;
pitch = A4;
break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 16:
volume = .2;
pitch = B4;
break;
case 11:
case 12:
case 13:
volume = 0;
break;
}
if (duration <= target.currentCount) {
ch.stop();
target.removeEventListener(TimerEvent.TIMER, arguments.callee);
}
});
}
private function onSampleDataHandler(e:SampleDataEvent):void
{
var freq:Number = (Math.PI * 2) * pitch / samplingRate;
for (var c:int = 0; c < bufferSize; c++)
{
var sample:Number = Math.sin(Number(c + e.position) * freq) * volume;
e.data.writeFloat(sample);
e.data.writeFloat(sample);
}
}
}
}
サンプルデモ(Flash Player 10 beta 2が必要です)
アストロ・チャルメラです(サイン波でソラシーラソ、ソラシラソラーって言ってるだけですけど)。
構造としては、前回のサンプルに、Timerを加えて、時間に応じて、音階や音量を変化するというもの。
ちなみに音価は、タイマーのカウントで表しています。
タイマーのカウント間隔を計算するには、四分音符の長さをテンポ(bpm)から割り出す必要があります。単純に四分音符が刻まれている間隔を知りたいだけなら、テンポ(一分間に鳴らされる四分音符の数)から1分間=60秒を割って、それをミリ秒で表せば、FlashのTimerでその間隔を計ることができます。
このサンプルは、タイマーの1カウント = 16分音符になっていて、たとえば四分音符を表したいときは、4カウント使う必要があります。なので、四分音符の間隔からさらに今回は「4」で割っています。
これは、分解能が4である、「ステップシーケンサー」と呼ばれる作曲ソフト、音楽機材とほぼ同じ方式です。
また、休符はとりあえず音量(波形の振幅)を0にすることで、それっぽくしています。
これで簡単なメロディーは作れるようになりました。なんか、着メロ作ってる気分ですね。単音の。

