ピタゴラス音律

by atsushi015 forked from サイン波形の生成を高速にやってみたつもりだったが… (diff: 9)
キーボードの2列目と3列目で演奏できるみたいです
♥0 | Line 230 | Modified 2014-06-30 00:48:44 | MIT License
play

ActionScript3 source code

/**
 * Copyright atsushi015 ( http://wonderfl.net/user/atsushi015 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/w1nP
 */

// forked from atsushi015's サイン波形の生成を高速にやってみたつもりだったが…
// forked from terra1119's flash on 2010-3-7
package {
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent
    import flash.events.MouseEvent;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.filters.BlurFilter;
    import net.hires.debug.Stats;

    [SWF(width="400", height="300", frameRate="30", backgroundColor="#000000")]
    public class Main extends Sprite {
        public static const SINE:String = "sine";
        public static const SAW:String = "saw";
        public static const TRIANGLE:String = "triangle";
        public static const PULSE:String = "pulse";
        public static const NOISE:String = "noise";

        private var sound:Sound;
        private var channel:SoundChannel;
        private var frequency:Number;
        private var keyboardTable:Array;
        private var waveType:String;
        private var volume:Number;
        private var isKeyDown:Boolean=false;
        private var blurObj:BlurFilter;
        private var noteNumber:uint;
        private var frequencyArray:Array=[];
private var selectedKey:uint;//現在の鍵盤番号を格納する変数

        public function Main() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            init();
        }

        private function init():void {
            //frequencyArray=create_fs_array();
            initKeyboardTable();
            waveType = SINE;
            volume = 0.5;
            sound = new Sound();
            sound.addEventListener(SampleDataEvent.SAMPLE_DATA,waveGenerator);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  
            // デバッグ用のスタッツを表示しています
            addChild(new Stats);
       }
        
        private function keyDownHandler(e:KeyboardEvent):void {
            stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            isKeyDown=true;
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            if(getNote(e.keyCode)){
                frequency =noteNumber2frequency(noteNumber);
                if(isKeyDown)channel = sound.play();
                isKeyDown=false;
                createBall();
            }
            //if(isKeyDown)channel = sound.play();
            //isKeyDown=false;
            //createBall();
        };
        
        private function keyUpHandler(e:KeyboardEvent):void {
            isKeyDown=false;
            stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            channel.stop();
        }
        
        private function getNote(num:int):Boolean {
            switch(num){//numの値で評価する
                case 65://キーコードが65(A)の時
                    noteNumber=60;//音階をド(C4 MIDIノートナンバー=60)に設定する
                    selectedKey=0;//現在の鍵盤番号を0にする
                    break;
                case 87://キーコードが87(W)の時
                    noteNumber=61;//音階をド#(C#4 MIDIノートナンバー=61)に設定する
                    selectedKey=1;//現在の鍵盤番号を1にする
                    break;
                case 83://キーコードが83(S)の時
                    noteNumber=62;//音階をレ(D4 MIDIノートナンバー=62)に設定する
                    selectedKey=2;//現在の鍵盤番号を2にする
                    break;
                case 69://キーコードが69(E)の時
                    noteNumber=63;//音階をレ#(D#4 MIDIノートナンバー=63)に設定する
                    selectedKey=3;//現在の鍵盤番号を3にする
                    break;
                case 68://キーコードが68(D)の時
                    noteNumber=64;//音階をミ(E4 MIDIノートナンバー=64)に設定する
                    selectedKey=4;//現在の鍵盤番号を4にする
                    break;
                case 70://キーコードが70(F)の時
                    noteNumber=65;//音階をファ(F4 MIDIノートナンバー=65)に設定する
                    selectedKey=5;//現在の鍵盤番号を5にする
                    break;
                case 84://キーコードが84(T)の時
                    noteNumber=66;//音階をファ#(F#4 MIDIノートナンバー=66)に設定する
                    selectedKey=6;//現在の鍵盤番号を6にする
                    break;
                case 71://キーコードが71(G)の時
                    noteNumber=67;//音階をソ(G4 MIDIノートナンバー=67)に設定する
                    selectedKey=7;//現在の鍵盤番号を7にする
                    break;
                case 89://キーコードが89(Y)の時
                    noteNumber=68;//音階をソ#(G#4 MIDIノートナンバー=68)に設定する
                    selectedKey=8;//現在の鍵盤番号を8にする
                    break;
                case 72://キーコードが72(H)の時
                    noteNumber=69;//音階をラ(A4 MIDIノートナンバー=69)に設定する
                    selectedKey=9;//現在の鍵盤番号を9にする
                    break;
                case 85://キーコードが85(U)の時
                    noteNumber=70;//音階をラ#(A#4 MIDIノートナンバー=70)に設定する
                    selectedKey=10;//現在の鍵盤番号を10にする
                    break;
                case 74://キーコードが74(J)の時
                    noteNumber=71;//音階をシ(B4 MIDIノートナンバー=71)に設定する
                    selectedKey=11;//現在の鍵盤番号を11にする
                    break;
                case 75://キーコードが75(K)の時
                    noteNumber=72;//音階をド(C5 MIDIノートナンバー=72)に設定する
                    selectedKey=12;//現在の鍵盤番号を12にする
                    break;
                default://それ以外の場合
                    return false;//falseを返す
            }
            return true;//trueを返す
        }
        private function initKeyboardTable():void {
            keyboardTable =
            [
                [0, "F"],
                [0, "F#"],
                [0, "G"],
                [0, "G#"],
                [1, "A"],
                [1, "A#"],
                [1, "B"],
                [1, "C"],
                [1, "C#"],
                [1, "D"],
                [1, "D#"],
                [1, "E"],
                [1, "F"],
                [1, "F#"],
                [1, "G"],
                [1, "G#"],
                [2, "A"],
                [2, "A#"],
                [2, "B"],
                [2, "C"],
                [2, "C#"],
                [2, "D"],
                [2, "D#"],
                [2, "E"]
            ]
        }

        private function setFreqency(keyNum:uint):void {
            var keyStep:uint = keyNum % 12;
            keyStep = keyStep < 5 ? keyStep + 7 : keyStep - 5;
            var octave:Number = 110.5* Math.pow(2, keyboardTable[keyNum - 1][0]);
            //frequency = octave * Math.pow(2, keyStep / 12);
            frequency =noteNumber2frequency(keyNum);
        }
        
        
        static const C:Number = 440 * Math.pow(2/3, 3) * 2;
        private function noteNumber2frequency(v:uint):Number {
            if (v > 127)v = 127;
            var level:Number = (v - 60) / 2;
            if (level % 6 >= 3.5) level += .5;
            
            return ((level % 1.0 >= 0.5) ? 
                    C * Math.pow(2/3, (7 - (level + .5)%7) * 2 % 7) << ((7 - (level + .5)%7) % 4) + 1 :
                    C * Math.pow(3/2, (level%7) * 2 % 7) >> (level%7 % 4) );
        }

        private function waveGenerator(e:SampleDataEvent):void {
            var sample:Number;
            var f0:Number = frequency / 44100;
            var f1:Number = 44100 / frequency;
            var PI2:Number = 2 * Math.PI;
            var ere:Number = Math.cos(PI2 * f0);
            var eim:Number = Math.sin(PI2 * f0); 
            var presamplere:Number = Math.cos(PI2 * f0 * Number(e.position-1));
            var presampleim:Number = Math.sin(PI2 * f0 * Number(e.position-1));

    


            for ( var c:int=0; c < 8192; c++ ) {
                switch(waveType) {
                    //サイン波
                    case SINE:
                    sample = presamplere * eim + presampleim * ere;
                    presamplere = presamplere * ere - presampleim * eim;
                    presampleim = sample;
                    break;

                    //矩形波
                    case PULSE:
                    sample = (Math.sin(PI2 * f0 * Number(c + e.position)) < 0) ? 1 : -1;
                    break;

                    //のこぎり波
                    case SAW:
                    sample = 2 * (f0 + Math.sin(PI2 * f0 * Number(c + e.position)) * 0.15) * ((c + e.position) % f1) - 1;
                    break;

                    //三角波
                    case TRIANGLE:
                    sample = (Math.sin(PI2 * f0 * Number(c + e.position)) < 0) ?
                                (4 * f0 * ((c + e.position) % (f1 / 2)) - 1) :
                                (-4 * f0 * ((c + e.position) % (f1 / 2)) + 1);
                    break;

                    //ホワイトノイズ
                    case NOISE:
                    sample = Math.random() * 2 - 1;
                    break;

                    default: break;
                }

                //音量調節
                sample *= volume;

                //範囲外チェック
                sample = (sample < -1) ? -1 : sample;
                sample = (sample > 1) ? 1 : sample;

                e.data.writeFloat(sample);
                e.data.writeFloat(sample);
            }
        }
        private function createBall():void {
            blurObj=new BlurFilter();
            blurObj.blurX=2;
            blurObj.blurY=2;
            var ball:Sprite=new Sprite();
            addChild(ball);
            ball.graphics.beginFill(Math.random()*0xFFFFFF);
            ball.graphics.drawCircle(0,0,frequency/10);
            ball.graphics.endFill();
            ball.blendMode="add";
            ball.filters=[blurObj];
            ball.x=Math.random()*400;
            ball.y=Math.random()*300;
            ball.addEventListener(Event.ENTER_FRAME,efHandler);
        }
        private function efHandler(e:Event):void {
            var targetSprite:Sprite=e.target as Sprite;
            targetSprite.alpha-=0.05;
            blurObj.blurX+=2;
            blurObj.blurY+=2;
            targetSprite.filters=[blurObj];
            if (targetSprite.alpha<0) {
                targetSprite.removeEventListener(Event.ENTER_FRAME,efHandler);
                removeChild(targetSprite);
                targetSprite=null;                
            }
        }
    }
}