2009-3-12 鍵盤で演奏
鍵盤テスト
・Adobe - デベロッパーセンター : Flash Player 10で広がるFlashの音の世界
http://www.adobe.com/jp/devnet/flash/articles/flp10_sound.html
・Soil.Y研究所 実験その三 音階と周波数の関係
http://tissoil.orz.hm/~soil/?co=audio_ex3&ref=
package
{
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.SampleDataEvent;
import flash.geom.Matrix;
import flash.media.Sound;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
/**
* 鍵盤テスト
*
* ・Adobe - デベロッパーセンター : Flash Player 10で広がるFlashの音の世界
* http://www.adobe.com/jp/devnet/flash/articles/flp10_sound.html
*
* ・Soil.Y研究所 実験その三 音階と周波数の関係
* http://tissoil.orz.hm/~soil/?co=audio_ex3&ref=
*
*/
[SWF(width="320", height="240", backgroundColor="0xFFFFFF", frameRate="10")]
public class Main extends Sprite
{
// ループの処理回数
private const RESOLUTION_HIGH:Number = 8192;
private const RESOLUTION_MIDDLE:Number = 8192 / 2;
private const RESOLUTION_LOW:Number = 8192 / 4;
// PI * 2
private const PI2:Number = Math.PI * 2;
// 音量
private const VOLUME:Number = 0.2;
// 1 ステップ分の音の高さの変化量
private const FR:Array = [
PI2 * 261.6 / 44100, // C
PI2 * 277.2 / 44100, // C#
PI2 * 293.7 / 44100, // D
PI2 * 311.1 / 44100, // D#
PI2 * 329.6 / 44100, // E
PI2 * 349.2 / 44100, // F
PI2 * 370.0 / 44100, // F#
PI2 * 392.0 / 44100, // G
PI2 * 415.3 / 44100, // G#
PI2 * 440.0 / 44100, // A
PI2 * 466.2 / 44100, // A#
PI2 * 493.9 / 44100, // B
PI2 * 523.2 / 44100, // C
];
// 白鍵と黒鍵の順番
private const KEY_COLOR:Array = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0];
// 鍵盤ごとの音
private var sample:Array = new Array();
// キーが押された時 True
private var key:Array = new Array();
/**
* コンストラクタ
*/
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化メソッド
* @param e
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
// 白鍵と黒鍵を描く
var white_index:int = 0;
for (var i:int = 0; i < 13; i++)
{
var sprite:Sprite;
sprite = new Sprite();
sprite.name = i.toString();
if (KEY_COLOR[i] == 0)
{
sprite.x = white_index * 40;
sprite.y = 20;
white_index++;
drawRect(sprite.graphics, 0, 0, 40, 120, 0xFFFFFF, 0xDDDDDD);
sprite.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
sprite.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
sprite.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverWhite);
sprite.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutWhite);
addChildAt(sprite, 0);
} else {
sprite.x = white_index * 40 - 15;
sprite.y = 20;
drawRect(sprite.graphics, 0, 0, 30, 80, 0x000000, 0x888888);
sprite.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
sprite.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
sprite.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverBlack);
sprite.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutBlack);
addChild(sprite);
}
sample[i] = 0.0;
}
// テキストフィールドを置く
var textField:TextField = new TextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.text = "マウスで鍵盤を押してください。\n" +
"鍵盤の上以外の場所でボタンを離すと、音が鳴り続けます。\n" +
"マウスを押してから音が鳴るまで若干遅れがあります。"
textField.x = 10;
textField.y = 170;
addChild(textField);
// サウンドオブジェクトを作成して音をループさせる
var sound:Sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
sound.play(0, 1);
}
/**
* 鍵盤の上でマウスが押された時
* @param event
*/
private function onMouseDown(event:MouseEvent):void
{
key[parseInt(event.currentTarget.name)] = true;
}
/**
* 鍵盤の上でマウスが離された時
* @param event
*/
private function onMouseUp(event:MouseEvent):void
{
key[parseInt(event.currentTarget.name)] = false;
// 押し始めた時のプチノイズを消す
sample[parseInt(event.currentTarget.name)] = 0;
}
/**
* 白鍵の上にマウスが乗った時
* @param event
*/
private function onMouseOverWhite(event:MouseEvent):void
{
event.target.graphics.clear();
drawRect(event.target.graphics, 0, 0, 40, 120, 0x8888FF, 0xEEEEFF);
}
/**
* 白鍵の上からマウスが離れた時
* @param event
*/
private function onMouseOutWhite(event:MouseEvent):void
{
if (key[parseInt(event.currentTarget.name)] == true)
return;
event.target.graphics.clear();
drawRect(event.target.graphics, 0, 0, 40, 120, 0xFFFFFF, 0xDDDDDD);
}
/**
* 黒鍵の上にマウスが乗った時
* @param event
*/
private function onMouseOverBlack(event:MouseEvent):void
{
event.target.graphics.clear();
drawRect(event.target.graphics, 0, 0, 30, 80, 0x000000, 0x8888FF);
}
/**
* 黒鍵の上からマウスが離れた時
* @param event
*/
private function onMouseOutBlack(event:MouseEvent):void
{
if (key[parseInt(event.currentTarget.name)] == true)
return;
event.target.graphics.clear();
drawRect(event.target.graphics, 0, 0, 30, 80, 0x000000, 0x888888);
}
/**
* オーディオデータ要求イベント
* @param event
*/
private function onSampleData(event:SampleDataEvent):void
{
// 波形の長さ分繰り返す
for (var i:int = 0; i < RESOLUTION_MIDDLE; i++) {
var s:Number = 0;
// 鍵盤が押されていたら、その音量を足す
for (var n:int = 0; n < 13; n++)
{
if (key[n]) {
s += Math.sin(sample[n]);
sample[n] += FR[n];
}
}
// 音量調整
s *= VOLUME;
// 波形を書き込む
event.data.writeFloat(s);
event.data.writeFloat(s);
}
}
/**
* 鍵盤を描く
* @param g 描く対象の Graphics オブジェクト
* @param x 鍵盤の中心の X 座標
* @param y 鍵盤の中心の Y 座標
* @param width 鍵盤の幅
* @param height 鍵盤の高さ
* @param colorLight 明るい場所の色
* @param colorDark 暗い場所の色
*/
private function drawRect(g:Graphics, x:Number, y:Number, width:Number, height:Number, colorLight:uint, colorDark:uint):void
{
var colors:Array = [colorLight, colorDark];
var alphas:Array = [1.0, 1.0];
var ratios:Array = [0, 255];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(width,
height,
-Math.PI / 2,
x,
y);
g.lineStyle(1, 0x000000);
g.beginGradientFill(GradientType.LINEAR,
colors,
alphas,
ratios,
matrix);
g.drawRect(x, y, width, height);
g.endFill();
}
}
}