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

FeliCaでDJもどき forked from: FeliCa Flash Contest - FeliCa Search sample

FeliCaでDJもどき
@created by Hiiragi

コードがどんどん汚くなっていく・・・。

使い方
FeliCaリーダー/ライターにFeliCa搭載端末を置いて、
Melo1とかのボタンを押すとIDmの読み込みを開始します。
その情報に従ってフレーズを構築して音を鳴らす感じです。 

あと、idmによって音が変わるようにしました。

発音時に左側が光るようになってますが、たまに光らないです。
帯もたまに出ない感じです。
指標にもならないので、「光ってるなー」くらいに見てください。

新機能として、キーボードパッドをつけてみました。
左の波形スイッチで波形を切り替えて、右のパッドをグリグリやると音が鳴ります。
赤色がキーの主音、緑色が全体の音と合わせても絶対に外れない音です。
これらのマークのところを目標にしてグリグリすれば、必ず音が外れない仕組みになってます。
残念ながら、FlashPlayerの特性上、発音の遅延は避けられません。

駅とかのポスターとかに、みんながタッチして音楽を奏でたら素敵ですよね。

FlashDevelopで開発してたんですが、デバッグ用プロジェクタがめちゃくちゃ重くてげんなりです。
読み込めなくなったら、おそらくFeliCaリーダーが占有されている状態なので、
しばらく待った後に再読み込みしてください。
Get Adobe Flash player
by Hiiragi 06 Mar 2011
// forked from felicacontest2010's FeliCa Flash Contest - FeliCa Search sample
package  
{
    /*
    * FeliCaでDJもどき
    * @created by Hiiragi
    * 
    * コードがどんどん汚くなっていく・・・。
    * 
    * 使い方
    * FeliCaリーダー/ライターにFeliCa搭載端末を置いて、
    * Melo1とかのボタンを押すとIDmの読み込みを開始します。
    * その情報に従ってフレーズを構築して音を鳴らす感じです。 
    *
    * あと、idmによって音が変わるようにしました。
    * 
    * 発音時に左側が光るようになってますが、たまに光らないです。
    * 帯もたまに出ない感じです。
    * 指標にもならないので、「光ってるなー」くらいに見てください。
    * 
    * 新機能として、キーボードパッドをつけてみました。
    * 左の波形スイッチで波形を切り替えて、右のパッドをグリグリやると音が鳴ります。
    * 赤色がキーの主音、緑色が全体の音と合わせても絶対に外れない音です。
    * これらのマークのところを目標にしてグリグリすれば、必ず音が外れない仕組みになってます。
    * 残念ながら、FlashPlayerの特性上、発音の遅延は避けられません。
    * 
    * 
    * 
    * 駅とかのポスターとかに、みんながタッチして音楽を奏でたら素敵ですよね。
    * 
    * FlashDevelopで開発してたんですが、デバッグ用プロジェクタがめちゃくちゃ重くてげんなりです。
    * 読み込めなくなったら、おそらくFeliCaリーダーが占有されている状態なので、
    * しばらく待った後に再読み込みしてください。
    */
    
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.media.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import flash.utils.*;
    
    import net.hires.debug.Stats;
    
    import org.si.sion.*;
    import org.si.sion.events.*;
    import org.si.sion.utils.*;
    import org.si.sion.sequencer.*;
    import org.si.sion.module.*;
    
    import com.sony.jp.felica.*;
    import com.sony.jp.felica.event.*;
    import com.sony.jp.felica.error.*;
    
    import mx.controls.Button;
    
    [SWF(width = 465, height = 465, frameRate = 60, backgroundColor = 0x222222)]
    public class FeliCa extends Sprite
    {
        private var _felicaPhraseVec:Vector.<FelicaPhrase> = new Vector.<FelicaPhrase>(3);
        private var _note:Vector.<int> = Vector.<int>([60, 62, 64, 67, 69, 72, 74, 76, 79, 81, 
                                                        48, 50, 52, 55, 57, 60, 62, 64, 67, 69,
                                                        45, 52, 57,
                                                        60, 61, 62, 63, 64]);
                                                        
        private var _score:Vector.<int> = new Vector.<int>();
        private var _voice:Vector.<SiONVoice> = new Vector.<SiONVoice>();
        private var _drumScorePattern:Vector.<Vector.<int>> = new Vector.<Vector.<int>>;
        
        private var _percusVoiceArray:Vector.<SiONVoice> = new Vector.<SiONVoice>;
        
        private var _beatCounter:int = 0;
        private var _sionDriver:SiONDriver = new SiONDriver();
        
        private var _timer:Timer = new Timer(3000, 1);
        
        private var _loader:Loader = new Loader();
        private var _urlRequest:URLRequest;
        private var _soundPartsArray:Array = [];
        
        private var _statusSp:Sprite = new Sprite();
        private var _statusTextField:TextField = new TextField();
        private var _soundAnalyzer:SoundAnalyzer;
        
        private var _wavesCanvas:BitmapData;
        private var _wavesCanvasRect:Rectangle;
        private var _wavesCanvasCtf:ColorTransform;
        private var _attackLightArray:Vector.<AttackLight>;
        private var _colorArray:Array = [];
        
        //現在選択しているパート
        private var _selectedPart:int = 1;
        private var _selectedDrumPart:int = 0;
        
        //  FeliCaProxy との通信を行うコントロールクラス
        private var fc:FeliCaControl = new FeliCaControl();
        
        public function FeliCa()
        {
            
            
            _statusTextField.defaultTextFormat = new TextFormat(null, 30, 0xFFFFFF, FontStyle.BOLD);
            _statusTextField.autoSize = TextFieldAutoSize.LEFT;
            _statusTextField.y = this.stage.stageHeight / 2 - 25;
            statusTextSet("FeliCa Proxy Holding now");
            _statusSp.addChild(_statusTextField);
            
            _statusSp.graphics.beginFill(0x000000, .3);
            _statusSp.graphics.drawRect(0, 0, this.stage.stageWidth, this.stage.stageHeight);
            _statusSp.graphics.endFill();
            _statusSp.graphics.beginFill(0x000000, .8);
            _statusSp.graphics.drawRect(0, this.stage.stageHeight / 2 - 25, this.stage.stageWidth, 50);
            _statusSp.graphics.endFill();
            
            _wavesCanvas = new BitmapData(465, 465, true, 0);
            
            //soundLoadStart();
            init();
        }
        
        private function statusTextSet(txt:String):void
        {
            _statusTextField.text = txt;
            _statusTextField.x = this.stage.stageWidth / 2 - _statusTextField.width / 2;
        }

        
        //private function soundLoadStart():void
        //{
            //_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, soundLoadComplete);
            //_urlRequest = new URLRequest("FeliCaAssets.swf");
            //var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
            //_loader.load(_urlRequest, context);
        //}
        //
        //private function soundLoadComplete(e:Event):void 
        //{
            //_soundPartsArray[0] = new (_loader.contentLoaderInfo.applicationDomain.getDefinition("kick") as Class)();
            //_soundPartsArray[1] = new (_loader.contentLoaderInfo.applicationDomain.getDefinition("snare") as Class)();
            //_soundPartsArray[2] = new (_loader.contentLoaderInfo.applicationDomain.getDefinition("ch") as Class)();
            //_soundPartsArray[3] = new (_loader.contentLoaderInfo.applicationDomain.getDefinition("oh") as Class)();
            //_soundPartsArray[4] = new (_loader.contentLoaderInfo.applicationDomain.getDefinition("crash") as Class)();
            //init();
        //}
        
        public function init():void
        {
            //SiON
            //_felicaPhraseVec[0] = new FelicaPhrase("011721103f08972b", false);
            //_felicaPhraseVec[1] = new FelicaPhrase("01010701360dd007", false);
            
            _felicaPhraseVec[0] = new FelicaPhrase(null, false);
            _felicaPhraseVec[1] = new FelicaPhrase(null, false);
            _felicaPhraseVec[2] = new FelicaPhrase(null, false);
            
            _drumScorePattern[0] = Vector.<int>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
                                                 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
                                                 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
                                                 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0
                                                 ]);
            
            //_drumScorePattern[1] = Vector.<int>([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
                                                 //0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
                                                 //1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
                                                 //0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
                                                 //1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0
                                                 //]);
            //
            //_drumScorePattern[2] = Vector.<int>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                 //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                 //0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
                                                 //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
                                                 //1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0
                                                 //]);
                                                 
            _drumScorePattern = convertDrumPattern(_drumScorePattern);
            _soundAnalyzer = new SoundAnalyzer();
            createSionScoreAndVoice();
            
            _sionDriver.setBeatCallbackInterval(1);
            _sionDriver.addEventListener(SiONTrackEvent.BEAT, beatListner);
            _sionDriver.setTimerInterruption(1, timerInterruption);
            
            var preset:SiONPresetVoice = new SiONPresetVoice();
            _percusVoiceArray[0] = preset["valsound.percus10"];    //CC
            _percusVoiceArray[1] = preset["valsound.percus23"];    //OH
            _percusVoiceArray[2] = preset["valsound.percus18"];    //CH
            _percusVoiceArray[3] = preset["valsound.percus29"];    //snare
            _percusVoiceArray[4] = preset["valsound.percus2"];    //bass
            
            
            
            //_sionDriver.setSamplerSound(64, _soundPartsArray[0]);
            //_sionDriver.setSamplerSound(63, _soundPartsArray[1]);
            //_sionDriver.setSamplerSound(62, _soundPartsArray[2]);
            //_sionDriver.setSamplerSound(61, _soundPartsArray[3]);
            //_sionDriver.setSamplerSound(60, _soundPartsArray[4]);
            

            
            var tFormat:TextFormat = new TextFormat("_serif", 16, 0xFFFFFF);
            var btn1:ControllerButton = new ControllerButton("Melo1", "btn1",60, 30, 3, tFormat,0, 0x222222);
            var btn2:ControllerButton = new ControllerButton("Melo2", "btn2",60, 30, 3, tFormat,0, 0x222222);
            var btn3:ControllerButton = new ControllerButton("Bass", "btn3",60, 30, 3, tFormat,0, 0x222222);
            //var btn4:ControllerButton = new ControllerButton("Drum", "btn4", 100, 40, 5, tFormat);
            
            btn1.y = btn2.y = btn3.y = 430;
            btn1.x = 10;
            btn2.x = 70;
            btn3.x = 130;
            //btn4.x = 350;
            
            btn1.addEventListener(MouseEvent.CLICK, cardReadStart);
            btn2.addEventListener(MouseEvent.CLICK, cardReadStart);
            btn3.addEventListener(MouseEvent.CLICK, cardReadStart);
            //btn4.addEventListener(MouseEvent.CLICK, drumPatternEdit);
            
            
            var wavesCanvasBmp:Bitmap = new Bitmap(_wavesCanvas);
            _wavesCanvasRect = _wavesCanvas.rect;
            _wavesCanvasCtf = new ColorTransform(0.995, 0.995, 0.995, 0.995);
            this.addChild(wavesCanvasBmp);
            
            _attackLightArray = new Vector.<AttackLight>();
            
            var verticalGridLine:Sprite = new Sprite();
            this.addChild(verticalGridLine);
            
            var h:int = 400 / _note.length;
            this.graphics.beginFill(0x200000);
            this.graphics.drawRect(0, 0, 465, h * 10);
            this.graphics.endFill();
            this.graphics.beginFill(0x002000);
            this.graphics.drawRect(0, h * 10, 465, h * 10);
            this.graphics.endFill();
            this.graphics.beginFill(0x000020);
            this.graphics.drawRect(0, h * 20, 465, h * 3);
            this.graphics.endFill();
            
            //グリッド描画と色設定とAttackLight設置
            this.graphics.lineStyle(1, 0x666666);
            verticalGridLine.graphics.lineStyle(1, 0x666666);
            
            for (var i:int = 0; i < 16; i++)
            {
                this.graphics.moveTo(465 / 16 * i, 0);
                this.graphics.lineTo(465 / 16 * i, 400 - 9);
                _colorArray[i] = HSVtoRGB(360 / 16 * i);
            }
            this.graphics.moveTo(465, 0);
            this.graphics.lineTo(465, 465);
            
            for (i = 0; i < _note.length ; i++)
            {
                verticalGridLine.graphics.moveTo(0, h * i + 400 / + h / 2 -1);
                verticalGridLine.graphics.lineTo(465, h * i + 400 / + h / 2 -1);
                
                var al:AttackLight = new AttackLight();
                al.y = h * i - 10;
                verticalGridLine.addChild(al);
                _attackLightArray[i] = al;
            }
            
            this.addChild(btn1);
            this.addChild(btn2);
            this.addChild(btn3);
            //this.addChild(btn4);
            
            var keyboard:Keyboard = new Keyboard(465);
            keyboard.y = 390;
            this.addChild(keyboard);
            
            _soundAnalyzer.x = 465 - 256;
            _soundAnalyzer.y = 423;
            this.addChild(_soundAnalyzer);
            
            //this.addChild(new Stats());
            
            this.addEventListener(Event.ENTER_FRAME, canvasScroller);
            _timer.addEventListener(TimerEvent.TIMER, connectionCloser);
            
            
            //  リスナー登録
            fc.addEventListener(OpenStatusEvent.OPEN_COMPLETE, onOpenComplete);
            fc.addEventListener(OpenStatusEvent.OPEN_FAILURE, onOpenFailure);
            fc.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_COMPLETE, onFeliCaAccessComplete);
            fc.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_FAILURE, onFeliCaAccessFailure);
            fc.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_PARAMETER_ERROR, onFeliCaAccessParameterError);             
            tracer("FeliCaProxy との認証を開始します。");
            //fc.open(10250);
            fc.open(10250,"__FELICA_STANDARD_KEY__", ""); 
            
            _sionDriver.play();
        }
        
        private function HSVtoRGB(hue:Number, saturation:Number=1, value:Number=1):uint {
            var Hi:int     = Math.floor(hue / 60) % 6;
            var f:Number = hue / 60 - Hi;
            var p:Number = value * (1 - saturation);
            var q:Number = value * (1 - f * saturation);
            var t:Number = value * (1 - (1 - f) * saturation);
            
            var r:Number = 0;
            var g:Number = 0;
            var b:Number = 0;
            
            switch (Hi) {
                case 0:
                    r=value;    g=t;    b=p;
                    break;
                case 1:
                    r=q;    g=value;    b=p;
                    break;
                case 2:
                    r=p;    g=value;    b=t;
                case 3:
                    r=p;    g=q;    b=value;
                    break;
                case 4:
                    r=t;    g=p;    b=value;
                    break;
                case 5:
                    r=value;    g=p;    b=q;
                    break;
            }

            r = Math.floor(r*255);
            g = Math.floor(g*255);
            b = Math.floor(b*255);

            return r << 16 | g << 8 | b;
        }
        
        private var _ctfCnt:int = 0;
        private function canvasScroller(e:Event):void 
        {
            _wavesCanvas.lock();
            _wavesCanvas.scroll(5, 0);
            _ctfCnt++;
            if (_ctfCnt >= 3)
            {
                _wavesCanvas.colorTransform(_wavesCanvasRect, _wavesCanvasCtf);
                _ctfCnt = 0;
            }
            
            _wavesCanvas.unlock();
        }
        
        
        private var feliCaReadFlag:Boolean = false;
        
        private function connectionCloser(e:TimerEvent):void 
        {
            tracer("制限時間により読み取りを終了します。");
            feliCaReadFlag = false;
        }
        
        private function cardReadStart(e:MouseEvent):void 
        {
            if (feliCaReadFlag)
            {
                tracer("現在FeliCa読み取り中です。");
            }
            else
            {
                switch (e.target.name)
                {
                    case "btn1":
                        _selectedPart = 0;
                        break;
                    case "btn2":
                        _selectedPart = 1;
                        break;
                    case "btn3":
                        _selectedPart = 2;
                        break;
                }
                
                RwLock();
                feliCaReadFlag = true;
                _timer.reset();
                _timer.start();
                this.addChild(_statusSp);
            }
        }
        
        private function drumPatternEdit(e:MouseEvent):void 
        {
            
        }
        
        private function onOpenComplete(e:OpenStatusEvent):void 
        {
            tracer("FeliCaProxy との認証に成功しました。");
            //RwLock();
        }
        
        private function onOpenFailure(e:OpenStatusEvent):void 
        {
            var error:Error =   e.object as Error;
            tracer( "FeliCaProxy との相互認証に失敗しました。\n" +
                            "   ERROR : (" + error.errorID + ") " + error.message);
        }
        
        private function onFeliCaAccessComplete(e:FeliCaStatusEvent):void 
        {
            if (e.object is FeliCaSessionResponse)
            {
                var session:FeliCaSessionResponse = e.object as FeliCaSessionResponse;
                
                //  リーダ/ライタの専有
                if (session.type == FeliCaSessionResponse.HOLD)
                {
                    statusTextSet("R/W Hold Complete");
                    tracer("リーダ/ライタの専有をしました。");
                    
                    //  リーダ/ライタのオープンを実行
                    RwOpen();
                }
                //  リーダ/ライタの開放
                else
                {
                    tracer("リーダ/ライタの専有を開放しました。");
                    this.removeChild(_statusSp);
                    
                    //  FeliCaProxy の切断
                    //FeliCaProxyClose();
                }
            }
            else if (e.object is FeliCaOpenReaderWriterAutoResponse)
            {
                tracer("リーダ/ライタのオープンに成功しました。");
                statusTextSet("R/W Open Complete");
                //  FeliCa を検出するために、Polling の実行
                Polling();
            }
            else if (e.object is FeliCaPollingAndGetCardInformationResponse)
            {
                var response:FeliCaPollingAndGetCardInformationResponse = e.object as FeliCaPollingAndGetCardInformationResponse;
                
                statusTextSet("set FeliCa idm = " + response.idm);
                
                //  検出した FeliCa の情報を表示
                tracer( "FeliCa を検出しました。\n" +
                                        "  idm = " + response.idm + "\n" +
                                        "  pmm = " + response.pmm);
                
                if (_selectedPart != -1 && _felicaPhraseVec[_selectedPart].idm != response.idm)
                {
                    trace("_selectedPart = " + _selectedPart + " , idm = " + response.idm);
                    _felicaPhraseVec[_selectedPart] = new FelicaPhrase(response.idm, true);
                    createSionScoreAndVoice();
                }
                
                //  リーダ/ライタのクローズを実行
                if (feliCaReadFlag)
                {
                    Polling();
                }
                else
                {
                    RwClose();  
                }
            }
            else if (e.object is FeliCaCloseReaderWriterResponse)
            {
                tracer("リーダ/ライタのクローズに成功しました。");
                
                //  リーダ/ライタ専有の開放
                RwUnlock();
            }
        }
        
        private function onFeliCaAccessFailure(e:FeliCaStatusEvent):void 
        {
            var errorMsg:String;
            if (e.object is FeliCaAccessError)
            {
                var error1:FeliCaAccessError =e.object as FeliCaAccessError;
                errorMsg =  "   ERROR: (" + error1.errorID + ")" + error1.message + "\n" +
                            "     FeliCa Error Code (" + error1.felicaError + ")\n" +
                            "     RW Error Code (" + error1.rwError + ")\n" +
                            "     FeliCaProxy Error Code (" + error1.felicaProxyError + ")";  
            }
            else if (e.object is Error)
            {
                var error2:Error =e.object as Error;
                errorMsg = "   ERROR : (" + error2.errorID + ") " + error2.message;
            }
            
            tracer("FeliCa アクセスに失敗しました\n" + errorMsg);
            
            //  FeliCaProxy の切断
            if (feliCaReadFlag)
            {
                Polling();
            }
            else
            {
                RwUnlock();
                //FeliCaProxyClose();
            }
        }
        
        private function onFeliCaAccessParameterError(e:FeliCaStatusEvent):void 
        {
            var error:Error = e.object as Error;
            tracer( "FeliCa アクセスでパラメータエラーが発生しました。\n" +
                                    "   ERROR: (" + error.errorID + ")" + error.message);
            
            //  FeliCaProxy の切断
            FeliCaProxyClose();
            
        }
        
        //  リーダ/ライタの専有を実行
        private function RwLock():void
        {
            //  リーダ/ライタを専有する為の情報の設定
            var request:FeliCaSessionRequest = new FeliCaSessionRequest();
            
            request.type            = FeliCaSessionRequest.HOLD;    // リーダ・ライタ専有要求
            request.lockTimeout     = 10;                           // 専有(Lock)するまでのタイムアウト時間(秒)
            request.unlockTimeout   = 60;                           // 専有(Lock)してから開放(Unlock)するまでの見込み時間(秒) 
                                                                    // FeliCaProxyは、このunlockTimeout時間経過した場合自動でR/W開放を行う。
            
            //  リーダ/ライタ専有を実行
            tracer("リーダ/ライタ専有を実行します。");
            fc.access(request);
        }
        
        //  リーダ/ライタ専有の開放を実行
        private function RwUnlock():void
        {
            //  リーダ/ライタ専有を開放する為の情報の設定
            var request:FeliCaSessionRequest = new FeliCaSessionRequest();
            
            request.type = FeliCaSessionRequest.RELEASE;    // リーダ・ライタ開放要求
            
            //  リーダ/ライタ専有開放を実行
            fc.access(request);
        }
        
        //  リーダ/ライタのオープンを実行
        private function RwOpen():void
        {
            //  [open_reader_writer_auto] コマンドを実行
            fc.access(new FeliCaOpenReaderWriterAutoRequest());
        }
        
        //  リーダ/ライタのクローズを実行
        private function RwClose():void
        {
            //  [close_reader_writer] コマンドを実行
            fc.access(new FeliCaCloseReaderWriterRequest());
        }
        
        //  FeliCa を検出するために、Polling の実行
        private function Polling():void
        {
            //  [polling_and_get_card_information] コマンドを実行する為の情報の設定
            var request:FeliCaPollingAndGetCardInformationRequest = new FeliCaPollingAndGetCardInformationRequest();
            
            request.systemCode  = "FFFF";       // ポーリングするシステムコード
            
            //  [polling_and_get_card_information] コマンドを実行
            fc.access(request);
        }
        
        //  FeliCaProxy の切断
        private function FeliCaProxyClose():void
        {
            if (fc.close() == true)
            {
                tracer("FeliCaProxy との接続を切断しました。");
            }
            else
            {
                tracer("FeliCaProxy との接続を切断に失敗しました。");
            }
        }
        
        ////////////////////////以下、SiON用ファンクション
        //DrumPatternを変換
        private function convertDrumPattern(vec:Vector.<Vector.<int>>):Vector.<Vector.<int>>
        {
            var tempVec:Vector.<Vector.<int>> = vec.concat();
            var len:int = tempVec.length;
            
            for (var i:int = 0; i < len ; i++) 
            {
                var tempVec2:Vector.<int> = new Vector.<int>(5);
                var len2:int = tempVec[i].length;
                for (var j:int = 0 ; j < len2; j++)
                {
                    if (tempVec[i][j] == 1) tempVec2[(j / 16) >> 0] |= 1 << (j % 16);
                }
                tempVec[i] = tempVec2;
            }
            
            return tempVec;
        }
        
        //Create
        private function createSionScoreAndVoice():void
        {
            _score = new Vector.<int>();
            _score = _score.concat(_drumScorePattern[_selectedDrumPart], _felicaPhraseVec[2].baseScore, _felicaPhraseVec[1].melo2Score, _felicaPhraseVec[0].melo1Score);
            //trace(_score);
            _voice = Vector.<SiONVoice>([_felicaPhraseVec[0].melo1Voice, _felicaPhraseVec[1].melo2Voice, _felicaPhraseVec[2].baseVoice]);
            //_soundAnalyzer.barRedColor = _felicaPhraseVec[0]color;
            //_soundAnalyzer.barGreenColor = _felicaPhraseVec[1].color;
            //_soundAnalyzer.barBlueColor = _felicaPhraseVec[2].color;
            _soundAnalyzer.color = _felicaPhraseVec[_selectedPart].colors[0];
        }
        
        //描画
        private function beatListner(e:SiONTrackEvent):void 
        {
            _wavesCanvas.lock();
            var beatIndex:int = _beatCounter & 15;
            var height:int = 400;
            var len:int = _score.length;
            var diffHeight:int = height / len;
            
            var color:uint;
            for (var i:int = 0; i < len ; i++)
            {
                if (_score[i] & (1 << beatIndex))
                {
                    if (i < 10) color = 0xFF << 24 | _felicaPhraseVec[0].colors[i];
                    else if (i < 20) color = 0xFF << 24 | _felicaPhraseVec[1].colors[i % 10];
                    else if (i < 23) color = 0xFF << 24 | _felicaPhraseVec[2].colors[i % 20];
                    else color = 0xFF << 24 | _colorArray[beatIndex];
                    
                    _wavesCanvas.fillRect(new Rectangle(0, diffHeight * i, 5, diffHeight), color);
                    _attackLightArray[i].lightUp();
                    //trace(_attackLightArray[i]);
                    //_wavesCanvas.setPixel32(0, diffHeight * i, 0xFFFFFFFF);
                }
            }
            _wavesCanvas.unlock();
        }
        
        //音
        private function timerInterruption():void
        {
            var beatIndex:int = _beatCounter & 15;
            var len:int = _score.length;
            var st:SiMMLTrack;
            for (var i:int = 0; i < len ; i++)
            {
                if (_score[i] & (1 << beatIndex))
                {
                    if (i < 10) _sionDriver.noteOn(_note[i], _voice[0], 1);
                    else if (i < 20) _sionDriver.noteOn(_note[i], _voice[1], 1);
                    else if (i < 23) _sionDriver.noteOn(_note[i], _voice[2], 1);
                    else 
                    {
                        //var preset:SiONPresetVoice = new SiONPresetVoice();
                        //var voice:SiONVoice = preset["valsound.percus1"];
                        //st = _sionDriver.playSound(_note[i], 1);
                        //trace(i - 23);
                        st = _sionDriver.noteOn(40, _percusVoiceArray[i - 23], 1);
                        //st.velocity = 255;
                    }
                }
            }
            
            //Drum
            //if (_beatCounter % 4 == 0) 
            //{
                //_sionDriver.noteOn(40, _percusVoiceArray[0], 4);
                //st = _sionDriver.playSound(60, 10);
                //st.velocity = 255;
                //
                //if (_beatCounter % 16 == 4 || _beatCounter % 16 == 12)
                //{
                    //_sionDriver.noteOn(36, _percusVoiceArray[2], 4);
                //}
            //}
            

            _beatCounter++;
        }
        
        
        
        
        private function tracer(str:String):void 
        {
            //trace(str);
        }
    }
    
}

import flash.display.*;
import flash.filters.BlurFilter;
import flash.filters.GlowFilter;
import flash.media.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.utils.*;
import org.si.sion.*;
import org.si.sion.utils.*;

class FelicaPhrase extends Object
{
    private var _idm:String = "";
    
    private var _melo1Voice:SiONVoice;
    private var _melo2Voice:SiONVoice;
    private var _baseVoice:SiONVoice;
    
    private var _melo1Score:Vector.<int> = new Vector.<int>(10);
    private var _melo2Score:Vector.<int> = new Vector.<int>(10);
    private var _baseScore:Vector.<int> = new Vector.<int>(3);
    
    private var _colors:Array;
    
    public function FelicaPhrase(idm:String, doDispatch:Boolean = true) 
    {
        var sionPreset:SiONPresetVoice = new SiONPresetVoice();
        
        _idm = (idm == null) ? "0000000000000000" : idm;
        
        ////初期情報設定    検証用idm = 011721103f08972b
        
        //音符
        var notesStr:String = _idm.substr(6, 10);    
        //休符情報(0は休符・1は音符)(1110110110001110)
        //var restNum:int = int("0x" + _idm.substr(5, 1) + _idm.substr(4, 1) + _idm.substr(3, 1) + _idm.substr(2, 1));
        //if (restNum != 0) restNum ^= 0xFFFF;
        
        //trace(restNum.toString(2));
        trace("idm = " + _idm);
        
        //melo1ScoreCreate
        var pos:int;
        //trace("notesStr = " + notesStr);
        for (var i:int = 0; i < notesStr.length; i++)
        {
            pos = 15 - int("0x" + notesStr.substr(i, 1));
            _melo1Score[i] = (int("0x" + notesStr) == 0) ? 0 : 1 << int("0x" + notesStr.substr(i, 1));
        }
        _melo1Score = redundancyDelete(_melo1Score, 16);
        
        trace("_melo1Score = " + _melo1Score);
        
        //melo2ScoreCreate
        var notesStr2:String = ("0000000000" + parseInt(int("0x" + notesStr).toString(2).split("").reverse().join(""), 2).toString(16)).substr(-10, 10);
        for (i = 0; i < notesStr2.length; i++)
        {
            pos = 15 - int("0x" + notesStr2.substr(i, 1));
            _melo2Score[i] = (int("0x" + notesStr2) == 0) ? 0 : 1 << int("0x" + notesStr2.substr(i, 1));
        }
        
        _melo2Score = redundancyDelete(_melo2Score, 16);
        trace("_melo2Score = " + _melo2Score);
        
        //baseScoreCreate
        var notesStrBass:String = "";
        for (i = 1; i <= 8 ; i++)
        {
            notesStrBass += ("0000" + int("0x" + notesStr.substr( -i, 1)).toString(2)).substr(-4, 4);
        }
        var index:int;
        for (i = 0; i < 16; i++)
        {
            index = parseInt(notesStrBass.substr(i * 2, 2), 2);
            if (index != 0)
            {
                _baseScore[index - 1] += 1 << i;
            }
        }
        trace("_baseScore = " + _baseScore);
        
        //voiceSet
        _melo1Voice = sionPreset["valsound.lead" + (int("0x" + notesStr.substr(-2, 2)) % 42 + 1)];
        _melo2Voice = sionPreset["valsound.piano" + (int("0x" + notesStr.substr(-4, 2)) % 19 + 1)];
        _baseVoice = sionPreset["valsound.bass" + (int("0x" + notesStr.substr( -6, 2)) % 53 + 1)];
        
        //_melo1Voice = sionPreset["valsound.lead1"];
        //_melo2Voice = sionPreset["valsound.piano2"];
        //_baseVoice = sionPreset["valsound.bass3"];
        
        _colors = [];
        var colorStr:String = _idm.substr( -8, 8);
        _colors.push(parseInt(colorStr.substr( 0, 6), 16));
        _colors.push(parseInt(colorStr.substr( 1, 6), 16));
        _colors.push(parseInt(colorStr.substr( 2, 6), 16));
        _colors.push(parseInt(colorStr.substr( 1, 5) + colorStr.substr(0, 1), 16));
        _colors.push(parseInt(colorStr.substr( 2, 5) + colorStr.substr(1, 1), 16));
        _colors.push(parseInt(colorStr.substr( 3, 5) + colorStr.substr(2, 1), 16));
        _colors.push(parseInt(colorStr.substr( 2, 1) + colorStr.substr( 5, 1) + colorStr.substr( 3, 1) + colorStr.substr( 1, 1) + colorStr.substr( 0, 1) + colorStr.substr( 4, 1), 16));
        _colors.push(parseInt(colorStr.substr( 3, 1) + colorStr.substr( 6, 1) + colorStr.substr( 4, 1) + colorStr.substr( 2, 1) + colorStr.substr( 1, 1) + colorStr.substr( 5, 1), 16));
        _colors.push(parseInt(colorStr.substr( 4, 1) + colorStr.substr( 7, 1) + colorStr.substr( 5, 1) + colorStr.substr( 3, 1) + colorStr.substr( 2, 1) + colorStr.substr( 6, 1), 16));
        _colors.push(parseInt(colorStr.substr( 3, 1) + colorStr.substr( 0, 1) + colorStr.substr( 5, 1) + colorStr.substr( 4, 1) + colorStr.substr( 1, 1) + colorStr.substr( 2, 1), 16));
        _colors.push(parseInt(colorStr.substr( 4, 1) + colorStr.substr( 1, 1) + colorStr.substr( 6, 1) + colorStr.substr( 5, 1) + colorStr.substr( 2, 1) + colorStr.substr( 3, 1), 16));
        _colors.push(parseInt(colorStr.substr( 5, 1) + colorStr.substr( 2, 1) + colorStr.substr( 7, 1) + colorStr.substr( 6, 1) + colorStr.substr( 3, 1) + colorStr.substr( 4, 1), 16));
        _colors.push(parseInt(colorStr.substr( 5, 1) + colorStr.substr( 4, 1) + colorStr.substr( 2, 1) + colorStr.substr( 0, 1) + colorStr.substr( 3, 1) + colorStr.substr( 1, 1), 16));
        _colors.push(parseInt(colorStr.substr( 6, 1) + colorStr.substr( 5, 1) + colorStr.substr( 3, 1) + colorStr.substr( 1, 1) + colorStr.substr( 4, 1) + colorStr.substr( 2, 1), 16));
        _colors.push(parseInt(colorStr.substr( 7, 1) + colorStr.substr( 6, 1) + colorStr.substr( 4, 1) + colorStr.substr( 2, 1) + colorStr.substr( 5, 1) + colorStr.substr( 3, 1), 16));
        _colors.push(parseInt(colorStr.substr( 4, 1) + colorStr.substr( 2, 1) + colorStr.substr( 5, 1) + colorStr.substr( 1, 1) + colorStr.substr( 7, 1) + colorStr.substr( 0, 1), 16));
        
        var colorPetternArray:Array = [["r", "g", "b"], ["g", "b", "r"],["b", "r" , "g"], ["r", "b", "g"]];
        var colorPetternIndex:int = parseInt(parseInt(_idm, 16).toString(16).substr( -2, 2), 2);
        for (i = 0; i < _colors.length; i++)
        {
            _colors[i] = intLimiter(_colors[i], colorPetternArray[colorPetternIndex][i % 3]);
        }
        trace("colors = " + _colors);
    }
    
    private function intLimiter(value:int, pettern:String):int
    {
        const MIN_LIMIT:int = 0x55;
        const MAX_LIMIT:int = 0xFF;
        var r:int = value >> 16;
        var g:int = value >> 8 & 0xFF;
        var b:int = value & 0xFF;
        
        if (r < MIN_LIMIT) r = (pettern == "r") ? MAX_LIMIT : MIN_LIMIT;
        if (g < MIN_LIMIT) g = (pettern == "g") ? MAX_LIMIT : MIN_LIMIT;
        if (b < MIN_LIMIT) b = (pettern == "b") ? MAX_LIMIT : MIN_LIMIT;
        
        return r << 16 | g << 8 | b;
    }
    
    private function redundancyDelete(vec:Vector.<int>, num:int):Vector.<int>
    {
        var len:int = vec.length;
        var flag:Boolean = false;
        
        for (var i:int; i < num; i++)
        {
            for (var j:int = 0; j < len; j++)
            {
                if (vec[j] & 1 << i)
                {
                    if (!flag) flag = true;
                    else vec[j] = 0;
                }
            }
            flag = false;
        }
        return vec;
    }
    
    public function get melo1Score():Vector.<int> { return _melo1Score; }
    public function get melo2Score():Vector.<int> { return _melo2Score; }
    public function get baseScore():Vector.<int> { return _baseScore; }
    
    public function get melo1Voice():SiONVoice { return _melo1Voice; }
    public function get melo2Voice():SiONVoice { return _melo2Voice; }
    public function get baseVoice():SiONVoice { return _baseVoice; }
    
    public function get idm():String { return _idm; }
    
    public function get colors():Array { return _colors; }
    
}




class SoundAnalyzer extends Bitmap
{
    private var _byteArray:ByteArray;
    private var _canvas:BitmapData;
    
    private var _ctf:ColorTransform;
    private var _rect:Rectangle;
    private var _plotHeight:int;
    
    private var _barRedColor:int = 0;
    private var _barGreenColor:int = 0;
    private var _barBlueColor:int = 0;
    
    private var _color:int = 0x666666;
    
    public function SoundAnalyzer()
    {
        _plotHeight = 40;
        _byteArray = new ByteArray();
        _canvas = new BitmapData(256, _plotHeight, false, 0x0);
        _ctf = new ColorTransform(.9, .9, .9);
        _rect = new Rectangle(0, 0, 256, 50);
        
        
        this.bitmapData = _canvas;
        
        this.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
    }
    
    private var _leftByteArray:ByteArray;
    private var _rightByteArray:ByteArray;
    
    private function onEnterFrameHandler(e:Event):void 
    {
        SoundMixer.computeSpectrum(_byteArray, true, 0);
        _canvas.colorTransform(_rect, _ctf);
        
        
        //var color:int = 0x44 << 16 | _barRedColor << 16 | 0x44 << 8 | _barGreenColor << 8 | 0x44  | _barBlueColor;
        
        var x:int = 0;
        var h:int = 0;
        
        _leftByteArray = new ByteArray();
        _rightByteArray = new ByteArray();
        for (var i:int = 0; i < 512; i++)
        {
            if (i < 256) _leftByteArray.writeFloat(_byteArray.readFloat());
            else _rightByteArray.writeFloat(_byteArray.readFloat());
        }
        
        _leftByteArray.position = 0;
        _rightByteArray.position = 0;
        
        _canvas.lock();
        for (i = 0; i < 250; i++)
        {
            
            h = (_leftByteArray.readFloat() + _rightByteArray.readFloat()) / 2 * _plotHeight;
            for (var j:int = 0; j < h; j++)
            {
                _canvas.setPixel(x, _plotHeight - j, _color);
            }
            x++;
        }
        _canvas.unlock();
        
    }
    
    public function get color():int { return _color; }
    
    public function set color(value:int):void 
    {
        _color = value;
    }
    
    //public function get barRedColor():int { return _barRedColor; }
    //
    //public function set barRedColor(value:int):void 
    //{
        //_barRedColor = multiplierLimiter(value);
    //}
    //
    //public function get barGreenColor():int { return _barGreenColor; }
    //
    //public function set barGreenColor(value:int):void 
    //{
        //_barGreenColor = multiplierLimiter(value);
    //}
    //
    //public function get barBlueColor():int { return _barBlueColor; }
    //
    //public function set barBlueColor(value:int):void 
    //{
        //_barBlueColor = multiplierLimiter(value);
    //}
    //
    //private function multiplierLimiter(value:int):Number
    //{
        //if (value > 0xbb)
        //{
            //value /= Math.ceil(value / 0xbb);
        //}
        //else if (value < 0)
        //{
            //value = 0;
        //}
        //
        //return value;
    //}
    

}

class AttackLight extends Bitmap
{
    //private var _canvas:BitmapData;
    private var _sourceSp:Sprite;
    
    private var _ctf:ColorTransform;
    private var _timer:Timer;
    
    public function AttackLight() 
    {
        this.bitmapData = new BitmapData(150, 25, true, 0);
        //_canvas = new BitmapData(100, 80, true, 0);
        _ctf = new ColorTransform(0.8, 0.8, 0.8, 0.8);
        _timer = new Timer(16, 120);
        _timer.addEventListener(TimerEvent.TIMER, update);
        
        _sourceSp = new Sprite();
        var g:Graphics = _sourceSp.graphics;
        //var mtx:Matrix = new Matrix();
        //mtx.createGradientBox(25, 25, 0, 0, 0);
        //g.beginGradientFill(GradientType.RADIAL, [0xDDDDFF, 0xFFFFFF], [1, 1], [0, 255], mtx);
        g.beginFill(0xFFFFFF);
        g.drawCircle(0, 8, 8);
        //g.drawRoundRect(0, 0, 50, 25, 5);
        g.endFill();
        
        _sourceSp.filters = [new GlowFilter(0xFFFFFFFF, 1, 96, 16, 20, 2), new BlurFilter(8,4,2)];
        
        //this.addChild(_sourceSp);
        //this.addChild(new Bitmap(_canvas));
        //this.stage.addEventListener(MouseEvent.CLICK, lightUp);
    }
    
    public function lightUp(e:MouseEvent = null):void
    {
        this.bitmapData.draw(_sourceSp, new Matrix(1, 0, 0, 1, 0, 8));
        _timer.reset();
        _timer.start();
    }
    
    private function update(e:TimerEvent):void 
    {
        this.bitmapData.colorTransform(this.bitmapData.rect, _ctf);
    }
}
    
class ControllerButton extends Sprite
{
    private var _backSp:Sprite;
    private var _rollOverSp:Sprite;
    private var _mouseDownSp:Sprite;
    
    private var _tf:TextField;
    private var _tFormat:TextFormat;
    private var _labelText:String;
    private var _id:String;
    private var _width:Number;
    private var _height:Number;
    private var _color1:int;
    private var _color2:int;
    private var _roundRadius:Number;
    
    public function ControllerButton(labelText:String, name:String = null, width:Number = 80, height:Number = 20, roundRadius:Number = 5, tFormat:TextFormat = null, color1:int = 0x000000, color2:int = 0x333333) 
    {
        //引数の取得・設定
        _labelText = labelText;
        if (name != null) this.name = name;
        _width = width;
        _height = height;
        _tFormat = tFormat;
        _roundRadius = roundRadius;
        _color1 = color1;
        _color2 = color2;
        
        //テキスト設定
        _tf = new TextField();
        _tf.autoSize = TextFieldAutoSize.LEFT;
        _tf.antiAliasType = AntiAliasType.ADVANCED;
        if (tFormat == null) _tf.defaultTextFormat = new TextFormat(null, null, 0xFFFFFF);
        else _tf.defaultTextFormat = tFormat;
        
        //初期化、表示リスト追加、リスナー追加
        _backSp = new Sprite();
        _rollOverSp = new Sprite();
        _mouseDownSp = new Sprite();
        
        addChild(_backSp);
        addChild(_mouseDownSp);
        addChild(_rollOverSp);
        addChild(_tf);
        
        this.addEventListener(MouseEvent.ROLL_OVER, onRollOverHandler);
        this.addEventListener(MouseEvent.ROLL_OUT, onRollOutHandler);
        this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
        this.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
        
        createBtn();
    }
    
    //ボタン形状の描画
    private function createBtn():void
    {
        _tf.text = _labelText;
        _width = (_width >= _tf.width) ? _width : _tf.width;
        
        backSpDraw();
        rollOverSpDraw();
        mouseDownDraw();
        
        _tf.x = _width / 2 - _tf.width / 2;
        _tf.y = _height / 2 - _tf.height / 2;
        
        this.mouseChildren = false;
        this.buttonMode = true;
        
        _rollOverSp.visible = false;
        _mouseDownSp.visible = false;
    }
    
    //平常時のボタングラフィック
    private function backSpDraw():void
    {
        var _mtx:Matrix = new Matrix();
        _mtx.createGradientBox(_width, _height, Math.PI / 2);
        _backSp.graphics.beginGradientFill(GradientType.LINEAR,[_color1, _color2, _color1], [1,1,1],[0,126,255],_mtx);
        _backSp.graphics.drawRoundRect(0, 0, _width, _height, _roundRadius, _roundRadius);
        _backSp.graphics.endFill();
    }
    
    //ロールオーバ-したとき時のボタングラフィック
    private function rollOverSpDraw():void
    {
        _rollOverSp.graphics.beginFill(0xFFFFFF, .3);
        _rollOverSp.graphics.drawRoundRect(0, 0, _width, _height, _roundRadius, _roundRadius);
        _rollOverSp.graphics.endFill();
    }
    
    //ボタンを押した時のボタングラフィック
    private function mouseDownDraw():void
    {
        var _mtx:Matrix = new Matrix();
        _mtx.createGradientBox(_width, _height, Math.PI / 2);
        _mouseDownSp.graphics.beginGradientFill(GradientType.LINEAR,[_color2, _color1, _color2], [1,1,1],[0,126,255],_mtx);
        _mouseDownSp.graphics.drawRoundRect(0, 0, _width, _height, _roundRadius, _roundRadius);
        _mouseDownSp.graphics.endFill();
    }
    
    //MouseEvent.ROLL_OVER時の描画変更
    private function onRollOverHandler(e:MouseEvent):void 
    {
        _rollOverSp.visible = true;
    }
    
    //MouseEvent.ROLL_OUT時の描画変更
    private function onRollOutHandler(e:MouseEvent):void 
    {
        _rollOverSp.visible = false;
        _mouseDownSp.visible = false;
    }
    
    //MouseEvent.MOUSE_DOWN時の描画変更
    private function onMouseDownHandler(e:MouseEvent):void 
    {
        _mouseDownSp.visible = true;
    }
    
    //MouseEvent.MOUSE_UP時の描画変更
    private function onMouseUpHandler(e:MouseEvent):void 
    {
        _mouseDownSp.visible = false;
    }
    
    
    
    
    //getter/setter
    public function get labelText():String { return _labelText; }
    
    public function set labelText(value:String):void 
    { 
        _labelText = value;
        createBtn();
    }
    
    public function get id():String { return _id; }
    
    public function set id(value:String):void 
    {
        _id = value;
    }
}

class Keyboard extends Sprite
{
    private const SINE:String = "sineWave";
    private const TRIANGLE:String = "triangleWave";
    private const SQUARE_50:String = "square50Wave";
    private const SQUARE_25:String = "square25Wave";
    private const SQUARE_12_5:String = "square12.5Wave";
    private const SAW:String = "sawWave";
    
    private var _waveTypeArray:Array = [SINE,
                                        TRIANGLE,
                                        SQUARE_50,
                                        SQUARE_25,
                                        SQUARE_12_5,
                                        SAW];
    private var _waveType:String = SINE;
    
    private var _w:int;
    
    private var _padding:int;
    private var _menuIconSp:Sprite;
    private var _menuIconFilmSp:Sprite;
    private var _keyboardSp:Sprite;
    private var _imageSoundWave:ASMovieClip;
    
    private var _keyboardWidth:int;
    private var _sound:Sound;
    private var _sc:SoundChannel;
    private var _baseFreq:Number = 220;
    private var _phase:Number = 0;
    private var _frequency:Number = 0;
    private var _keyDiffX:Number = 0;
    private var _PI2:Number = Math.PI * 2;
    private var _stf:SoundTransform;
    
    public function Keyboard(w:int, h:int = 30)
    {
        _w = w;
        
        _padding = 2;
        var keyboardNoteNum:int = 25;
        var pentaTonic:Array = [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1];
        
        var g:Graphics = this.graphics;
        g.lineStyle(1, 0x666666);
        g.beginFill(0);
        g.drawRect(0, 0, w, h);
        g.endFill();
        
        _menuIconSp = new Sprite();
        _menuIconSp.mouseChildren = false;
        g = _menuIconSp.graphics;
        g.lineStyle(1,0x999999);
        g.beginFill(0x0, 1);
        g.drawRect(_padding, _padding, h - _padding * 2, h - _padding * 2);
        g.endFill();
        _menuIconSp.addEventListener(MouseEvent.CLICK, changeWave);
        _menuIconSp.addEventListener(MouseEvent.ROLL_OVER, iconRollOverOut);
        _menuIconSp.addEventListener(MouseEvent.ROLL_OUT, iconRollOverOut);
        this.addChild(_menuIconSp);
        
        _imageSoundWave = new ASMovieClip();
        _imageSoundWave.isLoop = true;
        _menuIconSp.addChild(_imageSoundWave);
        
        //iconDraw
        var len:int = _waveTypeArray.length;
        var drawMaxCnt:int = 360;
        var cy:Number = h / 2;
        var dx:Number = 20 / drawMaxCnt;
        
        for (var i:int = 0; i < len; i++) 
        {
            var sp:Sprite = new Sprite();
            sp.graphics.lineStyle(0.25, 0xFFFFFF);

            switch (_waveTypeArray[i]) 
            {

                case SINE:
                    var degree:Number = 0;
                    sp.graphics.moveTo(5, cy); 
                    for (var ii:int = 0; ii < 360; ii++ )
                    {
                        degree++;
                        sp.graphics.lineTo(degree * dx + 5, cy + 10 * Math.sin(degree * Math.PI / 180));
                    }
                    break;
                
                case TRIANGLE:
                    sp.graphics.moveTo(5, cy + 6);
                    sp.graphics.lineTo(15, cy - 6);
                    sp.graphics.lineTo(25, cy + 6);
                    break;
                    
                case SQUARE_50:
                    sp.graphics.moveTo(5, cy + 6);
                    sp.graphics.lineTo(5, cy - 6);
                    sp.graphics.lineTo(15, cy - 6);
                    sp.graphics.lineTo(15, cy + 6);
                    sp.graphics.lineTo(25, cy + 6);
                    break;
                    
                case SQUARE_25:
                    sp.graphics.moveTo(5, cy + 6);
                    sp.graphics.lineTo(5, cy - 6);
                    sp.graphics.lineTo(10, cy - 6);
                    sp.graphics.lineTo(10, cy + 6);
                    sp.graphics.lineTo(25, cy + 6);
                    break;
                    
                case SQUARE_12_5:
                    sp.graphics.moveTo(5, cy + 6);
                    sp.graphics.lineTo(5, cy - 6);
                    sp.graphics.lineTo(7.5, cy - 6);
                    sp.graphics.lineTo(7.5, cy + 6);
                    sp.graphics.lineTo(25, cy + 6);
                    break;
                    
                case SAW:
                    sp.graphics.moveTo(5, cy);
                    sp.graphics.lineTo(10, cy - 10);
                    sp.graphics.lineTo(10, cy + 10);
                    sp.graphics.lineTo(20, cy - 10);
                    sp.graphics.lineTo(20, cy + 10);
                    sp.graphics.lineTo(25, cy);
                    break;
            }
            
            sp.graphics.endFill();
            _imageSoundWave.addFrame(sp);
        }
        
        _menuIconFilmSp = new Sprite();
        g = _menuIconFilmSp.graphics;
        g.beginFill(0xFFFFFF, .3);
        g.drawRect(_padding, _padding, h - _padding * 2, h - _padding * 2);
        g.endFill();
        _menuIconFilmSp.visible = false;
        _menuIconSp.addChild(_menuIconFilmSp);
        
        
        _keyboardSp = new Sprite();
        g = _keyboardSp.graphics;
        _keyboardWidth = w - _padding * 2 -_menuIconSp.width - _padding;
        var keyboardHeight:int = h - _padding * 2;
        _keyDiffX = _keyboardWidth / keyboardNoteNum;
        g.beginFill(0);
        g.lineStyle(1, 0x999999);
        g.drawRect(0, 0, _keyboardWidth, keyboardHeight);
        g.lineStyle();
        
        for (i = 0; i < keyboardNoteNum; i++) 
        {
            if (pentaTonic[i] == 1)
            {
                if (i % 12 == 0)
                {
                    g.beginFill(0x220000);
                }
                else
                {
                    g.beginFill(0x001100);
                }
                g.drawRect(_keyDiffX * i, 1, _keyDiffX, keyboardHeight - 2);
            }
        }
        g.endFill();
        _keyboardSp.x = _padding + _menuIconSp.width + _padding;
        _keyboardSp.y = _padding;
        _keyboardSp.addEventListener(MouseEvent.MOUSE_UP, waveStop);
        _keyboardSp.addEventListener(MouseEvent.MOUSE_DOWN, waveStart);
        _keyboardSp.addEventListener(MouseEvent.ROLL_OUT, waveStop);
        //_keyboardSp.addEventListener(MouseEvent.MOUSE_MOVE, waveNoteSearch);
        
        g.beginFill(0, 0);
        g.lineStyle(1, 0x999999);
        g.drawRect(0, 0, _keyboardWidth, keyboardHeight);
        this.addChild(_keyboardSp);
        
        
        //Sound
        _sc = new SoundChannel();
        _sound = new Sound();
        _sound.addEventListener(SampleDataEvent.SAMPLE_DATA, waveCreate);
        _stf = new SoundTransform(.2);
    }
    
    private function waveCreate(e:SampleDataEvent):void 
    {
        var smpl:Number;
        var w:Number = _PI2 * _frequency / 44100;
        var buffer:int = 2048;
        var PI:Number = Math.PI;
        
        for (var i:int = 0; i < buffer; i++) 
        {
            switch (_waveType) 
            {
                case SINE:
                    smpl = Math.sin(_phase);
                    break;
                
                case TRIANGLE:
                    smpl = (_phase < PI) ? -2 / PI * _phase + 1 : 2 / PI * _phase - 3;
                    break;
                    
                case SQUARE_50:
                    smpl = (_phase < PI) ? 1 : -1;
                    break;
                    
                case SQUARE_25:
                    smpl = (_phase > PI/4 && _phase < PI/2) ? 1 : -1;
                    break;
                    
                case SQUARE_12_5:
                    smpl = (_phase > PI/8 && _phase < PI/4) ? 1 : -1;
                    break;
                    
                case SAW:
                    smpl = - _phase / PI + 1;
                    break;
            }
            
            if (smpl >= 1) smpl = 1;
            else if (smpl <= -1) smpl = -1;
            
            e.data.writeFloat(smpl);
            e.data.writeFloat(smpl);
            
            _phase = (_phase >= _PI2) ? _phase - _PI2 : _phase;
            _phase += w;
        }
    }
    
    private function iconRollOverOut(e:MouseEvent):void 
    {
        _menuIconFilmSp.visible = !_menuIconFilmSp.visible;
    }
    
    private function changeWave(e:MouseEvent):void 
    {
        _imageSoundWave.nextFrame();
        _waveType = _waveTypeArray[_imageSoundWave.currentFrame - 1];
    }
    
    
    private function waveNoteSearch(e:Event = null):void 
    {
        var posX:Number = mouseX - _keyboardSp.x;
        _frequency = _baseFreq * Math.pow(2, Math.floor(posX / _keyDiffX) / 12);
    }
    
    private function waveStart(e:MouseEvent):void 
    {
        waveNoteSearch();
        if (_waveType == SQUARE_50 || _waveType == SQUARE_25)
        {
            _stf.volume = .15;
        }
        else if (_waveType == SQUARE_12_5 || _waveType == SAW)
        {
            _stf.volume = .20;
        }
        else
        {
            _stf.volume = .3;
        }
        _sc.stop();
        _sc = _sound.play(0, 0, _stf);
        this.addEventListener(Event.ENTER_FRAME, waveNoteSearch);
    }
    
    private function waveStop(e:MouseEvent):void 
    {
        _sc.stop();
        this.removeEventListener(Event.ENTER_FRAME, waveNoteSearch);
    }
}



    
class ASMovieClip extends Sprite
{
    private const PLAY:String = "play";
    private const REVERSE_PLAY:String = "reversePlay";
    
    private var _frames:Array;
    private var _frameObject:Sprite;
    
    private var _timer:Timer;
    private var _enterFrameDelayTime:int;
    private var _playDirectionFlag:String;
    private var _startUpFlag:Boolean;
    private var _currentFrame:int;
    
    private var _isLoop:Boolean;
    
    public function ASMovieClip() 
    {
        _enterFrameDelayTime = 33;
        _timer = new Timer(_enterFrameDelayTime);
        _frameObject = new Sprite();
        _timer.addEventListener(TimerEvent.TIMER, timerEventHandler);
        init();
    }
    
    private function init():void
    {
        if (this.contains(_frameObject)) this.removeChild(_frameObject);
        _frames = [];
        _frameObject = new Sprite();
        _startUpFlag = false;
        _currentFrame = 1;
        _isLoop = false;
    }
    
    //////////////////////////////////////////////////
    ////////// Public
    //////////////////////////////////////////////////
    public function addFrame(displayObject:DisplayObject, displayNow:Boolean = false):void
    {
        _frames.push(displayObject);
        if (displayNow || _frames.length == 1) 
        {
            gotoAndStop(_frames.length);
        }
    }

    public function addFrameAt(displayObject:DisplayObject, frameNumber:uint, displayNow:Boolean = false):void
    {
        if (frameCheck(frameNumber, true))
        {
            _frames.splice(frameNumber - 1, 0, displayObject);
            
            if (displayNow || _frames.length == 1) 
            {
                gotoAndStop(frameNumber);
            }
        }
    }
    
    public function removeFrameAt(frameNumber:uint):void
    {
        if (frameCheck(frameNumber))
        {
            _frames.splice(frameNumber - 1, 1);
            
            if (_frames.length > 0)
            {
                var position:int = (frameNumber > _frames.length) ? _frames.length : frameNumber;
                gotoAndStop(position);
            }
            else
            {
                init();
                return;
            }

        }
    }

    public function removeAllFrames():void
    {
        init();
    }
    
    
    //Movie系ファンクション
    public function gotoAndPlay(frameNumber:uint = 1, enterFrameDelayTime:uint = 33, isLoop:Boolean = false):void
    {
        _playDirectionFlag = PLAY;
        gotoAndStop(frameNumber);
        playBaseFunction(frameNumber, enterFrameDelayTime, isLoop);
    }
    
    public function gotoAndReversePlay(frameNumber:uint = 1, enterFrameDelayTime:uint = 33, isLoop:Boolean = false):void
    {
        _playDirectionFlag = REVERSE_PLAY;
        gotoAndStop(frameNumber);
        playBaseFunction(frameNumber, enterFrameDelayTime, isLoop);
    }
    
    public function gotoAndStop(frameNumber:uint):void
    {
        if (frameCheck(frameNumber))
        {
            if (this.contains(_frameObject)) this.removeChild(_frameObject);
            _frameObject = _frames[frameNumber - 1];
            _currentFrame = frameNumber;
            this.addChildAt(_frameObject, 0);
            if (_startUpFlag) frameMoveEventDispatcher();
            _startUpFlag = true;
        }
    }
    

    
    public function play(enterFrameDelayTime:uint = 33, isLoop:Boolean = false):void
    {
        _playDirectionFlag = PLAY;
        gotoAndStop(_currentFrame);
        playBaseFunction(_currentFrame, enterFrameDelayTime, isLoop);
    }
    
    public function stop():void 
    {
        timerStop();
        stopEventDispatcher();
    }
    
    public function nextFrame():void
    {
        if (_currentFrame == _frames.length)
        {
            if (_isLoop)
            {
                gotoAndStop(1);
                loopCompleteEventDispatcher();
            }
            else
            {
                timerStop();
                stopEventDispatcher();
                return;
            }
        }
        else if (_currentFrame < _frames.length)
        {
            _currentFrame++;
            gotoAndStop(_currentFrame);
        }
    }
    
    public function prevFrame():void
    {
        if (_currentFrame == 1)
        {
            if (_isLoop)
            {
                gotoAndStop(_frames.length - 1);
                loopCompleteEventDispatcher();
            }
            else
            {
                timerStop();
                stopEventDispatcher();
                return;
            }
        }
        else if (_currentFrame > 1)
        {
            _currentFrame--;
            gotoAndStop(_currentFrame);
        }
    }
    
    //////////////////////////////////////////////////
    ////////// Private 
    //////////////////////////////////////////////////
    
    private function playBaseFunction(frameNumber:uint, enterFrameDelayTime:uint, isLoop:Boolean):void
    {
        var isLoop_temp:Boolean = _isLoop;    //一時的保存
        _isLoop = isLoop;
        
        if (frameCheck(frameNumber))
        {
            if (loopCheck())
            {
                _isLoop = isLoop;
                _enterFrameDelayTime = enterFrameDelayTime;
                _timer.delay = _enterFrameDelayTime;
                _timer.start();
                playStartEventDispatcher();
            }
            else
            {
                _isLoop = isLoop_temp;
                return;
            }

        }
    }
    
    private function timerEventHandler(e:TimerEvent):void 
    {
        if (loopCheck())
        {
            switch (_playDirectionFlag)
            {
                case PLAY:
                    if (_isLoop && _currentFrame == _frames.length)
                    {
                        gotoAndStop(1);
                        loopCompleteEventDispatcher();
                    }
                    else
                    {
                        nextFrame();
                    }
                    break;
                    
                case REVERSE_PLAY:
                    if (_isLoop && _currentFrame == 1)
                    {
                        gotoAndStop(_frames.length);
                        loopCompleteEventDispatcher();
                    }
                    else
                    {
                        prevFrame();
                    }
                    break;
                
                default:
                    timerStop();
                    throw new Error("再生用のフラグが規定の定数ではありません。");
                    break;
            }
        }
        else
        {
            timerStop();
            stopEventDispatcher();
        }
    }
    
    //EventDispatch
    private function playStartEventDispatcher():void
    {
        this.dispatchEvent(new FrameEvent(FrameEvent.PLAY_START));
    }
    
    private function frameMoveEventDispatcher():void
    {
        this.dispatchEvent(new FrameEvent(FrameEvent.FRAME_MOVE));
    }
    
    private function loopCompleteEventDispatcher():void
    {
        this.dispatchEvent(new FrameEvent(FrameEvent.LOOP_COMPLETE));
    }
    
    private function stopEventDispatcher():void
    {
        this.dispatchEvent(new FrameEvent(FrameEvent.STOP));
    }
    
    
    private function timerStop():void
    {
        if (_timer.running) _timer.stop();
    }
    
    private function loopCheck():Boolean
    {
            //最後のフレームにいるときに、ループしない設定でplayしても意味ない。
            //同様に、最初のフレームにいるのに、ループしない設定でreversePlayしても意味ない。
            if ((_currentFrame == _frames.length && _playDirectionFlag == PLAY && !isLoop) || 
                    (_currentFrame == 1 && _playDirectionFlag == REVERSE_PLAY && !isLoop))
            {
                return false;
            }
            else
            {
                return true;
            }
    }
    
    private function frameCheck(frameNumber:uint, addToArray:Boolean = false):Boolean
    {
        if (framesEmptyCheck())
        {
            if (framesFrameNumberLengthCheck(frameNumber,addToArray))
            {
                return true;
            }
        }
        return false;
    }
    
    private function framesEmptyCheck():Boolean
    {
        if (_frames.length > 0)
        {
            return true;
        }
        else
        {
            throw new Error("シーンの登録数が0です。");
        }
    }
    
    private function framesFrameNumberLengthCheck(frameNumber:uint, addToArray:Boolean):Boolean
    {
        frameNumber--;
        
        if (_frames.length  > frameNumber || (addToArray && _frames.length  >= frameNumber))
        {
            if (frameNumber + 1 > 0)
            {
                return true;
            }
            else
            {
                throw new Error("フレームは1から始まります。 : \n\t指定されたフレーム : " + frameNumber + ")");
            }
            
        }
        else
        {
            throw new Error("指定されたインデックスは範囲外です。\n\t現在登録されているフレーム数 : " + _frames.length + "\n\t指定されたフレーム : " + (frameNumber + 1));
        }
    }
    
    
    //getter / setter
    public function get currentFrame():int { return _currentFrame; }
    
    public function set currentFrame(index:int):void 
    {
        gotoAndStop(index);
    }
    
    public function get isLoop():Boolean { return _isLoop; }
    
    public function set isLoop(value:Boolean):void 
    {
        _isLoop = value;
    }
    
    public function get frames():Array { return _frames; }
    
    public function set frames(value:Array):void 
    {
        _frames = value;
    }
    
    public function get frameObject():Sprite { return _frameObject; }
    
    public function set frameObject(value:Sprite):void 
    {
        _frameObject = value;
    }
    
    public function get enterFrameDelayTime():int { return _enterFrameDelayTime; }
    
    public function set enterFrameDelayTime(value:int):void 
    {
        _enterFrameDelayTime = value;
        _timer.delay = _enterFrameDelayTime;
    }
}



class FrameEvent extends Event
{
    public static const PLAY_START:String = "framePlayStart";
    public static const STOP:String = "frameStop";
    public static const FRAME_MOVE:String = "frameMove";
    public static const LOOP_COMPLETE:String = "frameLooComplete";
    
    
    
    
    public function FrameEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
    {
        super(type, bubbles, cancelable);
    }
}