開発環境 Apache Flex SDK 4.12.1
FlashDevelop 4.6.1
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 ActionScript 3/AS3 Project
プロジェクト名 EzPlay


Main.as
package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.media.SoundTransform;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
 
    public class Main extends Sprite 
    {
        private var input:TextField = new TextField;
        private var mml:String;
        private var pos:int;
        private var waveform:Vector.<Number>;
 
        private const PI2:Number = Math.PI * 2;
        private const scale:Object = { A:9, B:11, C:0, D:2, E:4, F:5, G:7 };
        private const timebase:int = 960;
        private var q:int = 7; // 音の長さの割合
        private var tempo:int;
        private var octave:int;
        private var deflen:int;
 
        private var sound:Sound = new Sound;
        private var soundChannel:SoundChannel = null;
 
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
 
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
 
            input.type = TextFieldType.INPUT;
            input.multiline = true;
            input.defaultTextFormat = new TextFormat(null, 16);
            input.text = "t100 l4 o4\n" +
                "ccgg aag2 ffee ddc2\n" + // Twinkle, twinkle, little star, How I wonder what you are!
                "ggff eed2 ggff eed2\n" + // Up above the world so high, Like a diamond in the sky.
                "ccgg aag2 ffee ddc2\n"; // Twinkle, twinkle, little star, How I wonder what you are!
            input.border = true;
            input.x = 10;
            input.y = 10;
            input.width = 400;
            input.height = 200;
            addChild(input);
 
            var tf:TextFormat = new TextFormat;
            tf.size = 24;
            tf.align = TextFormatAlign.CENTER;
 
            var play:TextField = new TextField;
            play.defaultTextFormat = tf;
            play.border = true;
            play.selectable = false;
            play.text = "Play";
            play.x = 100;
            play.y = 220;
            play.width = 80;
            play.height = 30;
            addChild(play);
 
            var stop:TextField = new TextField;
            stop.defaultTextFormat = tf;
            stop.border = true;
            stop.selectable = false;
            stop.text = "Stop";
            stop.x = 200;
            stop.y = 220;
            stop.width = 80;
            stop.height = 30;
            addChild(stop);
 
            sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
 
            play.addEventListener(MouseEvent.CLICK, onPlay);
            stop.addEventListener(MouseEvent.CLICK, onStop);
        }
 
        // 再生ボタン
        private function onPlay(e:MouseEvent):void 
        {
            mml = input.text.toUpperCase();
            waveform = new Vector.<Number>;
            tempo = 120;
            octave = 4;
            deflen = 4;
            for (pos = 0; pos < mml.length; ) 
            {
                var cmd:String = mml.charAt(pos++);
                switch (cmd)
                {
                    case "<":
                        octave--;
                        break;
                    case ">":
                        octave++;
                        break;
                    case "A": case "B": case "C": case "D": case "E": case "F": case "G":
                        note(cmd);
                        break;
                    case "L":
                        deflen = getValue();
                        break;
                    case "O":
                        octave = getValue();
                        break;
                    case "T":
                        tempo = getValue();
                        break;
                    case "R":
                        rest();
                        break;
                    default:
 
                }
            }
 
            var st:SoundTransform = new SoundTransform;
            st.volume = 0.3;
            soundChannel = sound.play(0, 0, st);
        }
 
        // 音符
        private function note(cmd:String):void 
        {
            var acci:int = getAccidental();
            var len:int = getValue();
            var dot:int = getDot();
            var tie:Boolean = getTie();
 
            var noteno:int = (octave + 1) * 12 + scale[cmd] + acci;
            var tick:int = calcTick(len, dot);
            var qtick:int = tie ? tick : tick * q / 8;
            generateNote(qtick, noteno);
            generateRest(tick - qtick);
        }
 
        // 休符
        private function rest():void 
        {
            var len:int = getValue();
            var dot:int = getDot();
 
            var tick:int = calcTick(len, dot);
            generateRest(tick);
        }
 
        // tick計算
        private function calcTick(len:int, dot:int):int 
        {
            if (len == 0) len = deflen;
            var tick:int = timebase * 4 / len;
            var n:int = Math.pow(2, dot);
            tick += tick * (n - 1) / n;
            return tick;
        }
 
        // 音符生成
        private function generateNote(tick:int, noteno:int):void 
        {
            var freq:Number = 440 * Math.pow(Math.pow(2, noteno - 69), 1 / 12);
            var n:int = Math.round(tick * 44100 * 60 / (timebase * tempo));
            for (var i:int = 0; i < n; i++) 
            {
                var t:Number = (i * freq / 44100) % 1;
                var h:Number;
                //h = Math.sin(PI2 * t);
                h = (t < 0.25) ? 0.5 : -0.5;
                waveform.push(h);
            }
        }
 
        // 休符生成
        private function generateRest(tick:int):void 
        {
            var n:int = Math.round(tick * 44100 * 60 / (timebase * tempo));
            for (var i:int = 0; i < n; i++) 
            {
                waveform.push(0);
            }
            trace("r" + n);
        }
 
        // 変化記号
        private function getAccidental():int 
        {
            var acci:int = 0;
            for ( ; pos < mml.length; pos++) 
            {
                switch (mml.charAt(pos)) 
                {
                    case "+": case "#":
                        acci++;
                        break;
                    case "-":
                        acci--;
                        break;
                    default:
                        return acci;
                }
            }
            return acci;
        }
 
        // 値
        private function getValue():int
        {
            var value:int = 0;
            for ( ; pos < mml.length; pos++) 
            {
                var num:int = mml.charCodeAt(pos) - 0x30;
                if (num < 0 || 9 < num) break;
                value = value * 10 + num;
            }
            return value;
        }
 
        // 付点
        private function getDot():int 
        {
            var dot:int = 0;
            for ( ; pos < mml.length; pos++) 
            {
                if (mml.charAt(pos) != ".") break;
                dot++;
            }
            return dot;
        }
 
        // タイ
        private function getTie():Boolean
        {
            if (mml.charAt(pos) == "&")
            {
                pos++;
                return true;
            }
            return false;
        }
 
        // 停止ボタン
        private function onStop(e:MouseEvent):void 
        {
            if (soundChannel == null) return;
 
            soundChannel.stop();
            soundChannel = null;
        }
 
        // サンプルデータ要求
        private function onSampleData(e:SampleDataEvent):void 
        {
            var len:int = Math.min(waveform.length - e.position, 8192);
            for (var i:int = 0; i < len; i++) 
            {
                var value:Number = waveform[e.position + i];
                e.data.writeFloat(value);
                e.data.writeFloat(value);
            }
        }
 
    }
 
}
 
最終更新:2014年06月23日 17:54