In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

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=
Get Adobe Flash player
by hikipuro 12 Mar 2009
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();
        }
    }
    
}