// 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); } } FeliCaでDJもどき forked from: FeliCa Flash Contest - FeliCa Search sample