Forked from: yuichiroharai's Ripple Beat - 音に反応する波紋 diff:1 forked from: Ripple Beat - 音に反応する波紋 lewis_c1986 forked:0favorite:0lines:712license : MIT License modified : 2011-11-02 20:08:43 Embed Tweet // forked from yuichiroharai's Ripple Beat - 音に反応する波紋 package { // ---------------------------------------------------------------------------------------------------- // インポート // import com.adobe.serialization.json.*; import flash.display.*; import flash.events.*; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.media.*; import flash.net.*; import flash.system.ApplicationDomain; import flash.system.SecurityDomain; import flash.system.LoaderContext; import flash.system.System; import flash.text.*; import flash.text.Font; import flash.utils.ByteArray; import flash.utils.getTimer; import net.hires.debug.Stats; /** * Ripple Beatの波紋エフェクトのサンプル * http://www.yuichiroharai.com/ripplebeat/ * * @author Yuichiroh Arai */ public class RippleBeatSample extends Sprite { // ---------------------------------------------------------------------------------------------------- // メイン処理 // private const FPS:uint = 60; // フレームレート private const STAGE_SIZE:uint = 465; // ステージサイズ // トラックのサンプル // From Within / Johannes Heil / Break New Soil Recordings // Singa / Kaiserdisco / MBF // Braumstig (Rodriguez Jr. Remix) / Joachim Pastor / Mistakes Music // Lifetimes (Pan-Pot Tribute To Life Remix) / Slam / Soma Records // Callisto / Marc Romboy, Stephan Bodzin / Systematic Recordings // Agent Minimal / Louie Cut / Piso Records private var TRACK_ID_LIST:Vector.<String> = Vector.<String>(["2739989", "2436514", "3017670", "2077856", "844498", "2815309"]); private var _trackIdIndex:int=0; /** * コンストラクタ */ public function RippleBeatSample():void { stage.frameRate = FPS; stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; _initBack(); //_initStats(); // 埋め込みフォントを取得 _loadFont(complete); function complete():void { _initMessage(); _initInfo(); _initImage(); _initSelect(); _initControl(); stage.addEventListener(Event.RESIZE, _onResize); stage.addEventListener(Event.FULLSCREEN, _onResize); stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:Event):void{_changeImageRipple()}); // トラックをロード _loadTrack(TRACK_ID_LIST[_trackIdIndex]); } } /** * トラックIDを指定してトラックをロード * * @param id BeatportのトラックID */ private function _loadTrack(id:String):void { _textFieldInfo.visible = false; _hideImage(); _hideSelect(); _hideControl(); _changeMessage("NOW LODING"); _showMessage(); _loadBeatport(id, step1, error); function step1():void { _makeRipple(step2); } function step2():void { _hideMessage(); _changeInfo(); _textFieldInfo.visible = true; _changeImage(); _changeSelect(); _changeControl(); _showImage(); _loadAndPlaySound(step3); } function step3():void { _showSelect(); _showControl(); } function error():void { _hideMessage(); _changeMessage("LOADING ERROR..."); _textFieldMessage.visible = true; _showSelect(); } } /** * 前or次のトラックをロード * * @param prev 前のトラックをロードするかどうか。デフォルト(false)は次のトラックをロード。 */ private function _loadTrackOrder(prev:Boolean=false):void { if (prev) { if (--_trackIdIndex < 0) _trackIdIndex = TRACK_ID_LIST.length-1; _loadTrack(TRACK_ID_LIST[_trackIdIndex]); } else { if (++_trackIdIndex > TRACK_ID_LIST.length-1) _trackIdIndex = 0; _loadTrack(TRACK_ID_LIST[_trackIdIndex]); } } /** * 任意のトラックをロード * * @param index トラックリストのインデックス */ private function _loadTrackSelect(index:uint):void { _trackIdIndex = (index > TRACK_ID_LIST.length-1) ? TRACK_ID_LIST.length : index; _loadTrack(TRACK_ID_LIST[_trackIdIndex]); } /** * ステージリサイズ時の処理 */ private function _onResize(e:Event):void { _moveMessage(); _moveInfo(); _moveImage(); _moveSelect(); _moveControl(); _resizeBack(); } // ---------------------------------------------------------------------------------------------------- // ジャケット画像、ボーダーの表示 // private const IMAGE_SIZE_MAX:uint = 212; private var _bmpImage:Bitmap; private var _bmpBorder:Bitmap; private var _bmpRipple:Bitmap; private var _rippleImage:Boolean=false; /** * 表示画像の初期化 */ private function _initImage():void { _bmpRipple = new Bitmap(); addChild(_bmpRipple); _bmpImage = new Bitmap(); addChild(_bmpImage); _bmpBorder = new Bitmap(); addChild(_bmpBorder); } /** * 表示画像の変更 */ private function _changeImage():void { _bmpImage.bitmapData = _track.image; _bmpBorder.bitmapData = _track.border; _moveImage(); } /** * 表示画像の配置を更新 */ private function _moveImage():void { _bmpImage.x = _bmpRipple.x = int((stage.stageWidth - _bmpImage.width)/2); _bmpImage.y = _bmpRipple.y = int((stage.stageHeight - _bmpImage.height)/2); _bmpBorder.x = _bmpImage.x - 1; _bmpBorder.y = _bmpImage.y - 1; } /** * 表示画像の表示 */ private function _showImage():void { if (_rippleImage) { _bmpRipple.visible = true; } else { _bmpImage.visible = true; } _bmpBorder.visible = true; } /** * 表示画像の非表示 */ private function _hideImage():void { _bmpImage.visible = false; _bmpRipple.visible = false; _bmpBorder.visible = false; } /** * ジャケット画像と波紋画像の表示を切り替え */ private function _changeImageRipple():void { if (_rippleImage) { _rippleImage = false; _bmpImage.visible = true; _bmpRipple.visible = false; _bmpRipple.bitmapData = null; } else { _rippleImage = true; _bmpImage.visible = false; _bmpRipple.visible = true; _bmpImage.filters = null; } } // ---------------------------------------------------------------------------------------------------- // DisplacementMapFilterで使用する波紋エフェクトのBitmapDataを作成 // // 波紋の波長 private const RIPPLE_WAVELENGTH:uint = 4; private var _rippleList:Vector.<BitmapData>; /** * 波紋エフェクトのBitmapDataのリストを作成 * * @param callback コールバック関数 */ private function _makeRipple(callback:Function):void { var num:uint, width:uint, height:uint, widthHarf:uint, heightHarf:uint, lengthList:Vector.<Number>; if (_rippleList != null) { for (num=0;num<_rippleList.length;num++) { if (_rippleList[num] != null) _rippleList[num].dispose(); } } _rippleList = new Vector.<BitmapData>(RIPPLE_WAVELENGTH, true); width = _track.image.width; height = _track.image.height; widthHarf = uint(width/2); heightHarf = uint(height/2); makeData(); // 処理に時間がかかるため、1フレームごとに実行。 num = 0; addEventListener(Event.ENTER_FRAME, enterframe); function enterframe(e:Event):void { if (num < RIPPLE_WAVELENGTH) { // 位相をずらしながら、BitmapDataを生成 _rippleList[num] = makeBitmapData(num); } else { removeEventListener(Event.ENTER_FRAME, enterframe); if (callback is Function) callback.apply(); } ++num; } // 事前に各ピクセルの中心からの距離を計算 function makeData():void { var area:uint, d:Number, diagonal:Number, i:uint, j:uint, ii:uint, ij:uint, x:int, y:int, xx:uint, yy:uint, ll:Number; area = width * height; d = Math.sqrt(widthHarf*widthHarf + heightHarf*heightHarf); diagonal = (d == uint(d)) ? d : uint(d+1); ++diagonal; lengthList = new Vector.<Number>(area, true); for (j=0;j<height;j++) { ij = j * height; y = j - heightHarf; yy = y*y; for (i=0;i<width;i++) { ii = ij + i; x = i - widthHarf; xx = x*x; ll = xx + yy; lengthList[ii] = Math.sqrt(ll); } } } // 位相を指定してBitmapDataを作成 function makeBitmapData(phase:uint=0):BitmapData { var i:uint, j:uint, ij:uint, ii:uint, x:int, y:int, len:Number, unit:Number, amp:Number, sx:Number, sy:Number, c:uint, bitmapData:BitmapData; unit = 2*Math.PI/RIPPLE_WAVELENGTH; bitmapData = new BitmapData(width, height, false, 0x008080); bitmapData.lock(); for (j=0;j<height;j++) { ij = j * height; y = j - heightHarf; for (i=0;i<width;i++) { ii = ij + i; x = i - widthHarf; len = lengthList[ii]; amp = Math.round(Math.sin(((len-phase) % RIPPLE_WAVELENGTH)*unit) * 1000000000000000) / 1000000000000000; sx = x*0x80/len*amp; sy = y*0x80/len*amp; c = (0x80 - int(sx + 0.5))*0x100 + 0x80 - int(sy + 0.5); bitmapData.setPixel(i, j, c); } } bitmapData.unlock(); return bitmapData; } } // ---------------------------------------------------------------------------------------------------- // サウンドのロード、再生、停止など // private var _sound:Vector.<Sound>; private var _soundChannel:SoundChannel; private var _soundPosition:Number=0; /** * サウンドをロードしてから再生 * * @param callback サウンドのオープン(≒再生)時のコールバック */ private function _loadAndPlaySound(callback:Function):void { if (_soundChannel != null) { _soundChannel.stop(); } if (_sound != null && _sound[0] != null) { _sound[0].removeEventListener(Event.COMPLETE, _onCompleteSound); try { _sound[0].close(); } catch (e:Error) {} delete _sound[0]; _sound = null; removeEventListener(Event.ENTER_FRAME, _onPlayingSound); } _resetSpectrum(); _soundPosition = 0; _sound = Vector.<Sound>([new Sound()]); _sound[0].addEventListener(Event.OPEN, open); _sound[0].load(new URLRequest(_track.urlSound), new SoundLoaderContext(1000, true)); function open(e:Event):void { _soundChannel = _sound[0].play(_soundPosition); _soundChannel.addEventListener(Event.SOUND_COMPLETE, _onCompleteSound); addEventListener(Event.ENTER_FRAME, _onPlayingSound); _sound[0].removeEventListener(Event.OPEN, open); if (callback is Function) callback.apply(); } } /** * サウンドを再生 */ private function _playSound():void { if (_sound == null || _sound[0] == null) return; _soundChannel = _sound[0].play(_soundPosition); _soundChannel.addEventListener(Event.SOUND_COMPLETE, _onCompleteSound); addEventListener(Event.ENTER_FRAME, _onPlayingSound); } /** * サウンドをポーズ */ private function _pauseSound():void { if (_soundChannel == null || _sound == null || _sound[0] == null) return; _soundPosition = _soundChannel.position; _soundChannel.stop(); _soundChannel.removeEventListener(Event.SOUND_COMPLETE, _onCompleteSound); _soundChannel = null; removeEventListener(Event.ENTER_FRAME, _onPlayingSound); _bmpImage.filters = null; } /** * サウンドの再生完了時の処理。次のトラックを自動再生。 */ private function _onCompleteSound(e:Event):void { if (_soundChannel == null || _sound == null || _sound[0] == null) return; _switchControl(); _soundPosition = 0; _soundChannel.removeEventListener(Event.SOUND_COMPLETE, _onCompleteSound); _soundChannel = null; removeEventListener(Event.ENTER_FRAME, _onPlayingSound); _bmpImage.filters = null; _loadTrackOrder(); } // ---------------------------------------------------------------------------------------------------- // スペクトラム // private const POINT_0:Point = new Point(0, 0); private const SPECTRUM_MAX:Number = 1.4142136; private var _spectrumCurrent:Number; private var _spectrumTarget:Number; private var _spectrumMax:Number; private var _phaseCurrent:Number; /** * スペクトラムのリセット */ private function _resetSpectrum():void { _spectrumCurrent = _spectrumTarget = _spectrumMax = _phaseCurrent = 0; } /** * サウンドに合わせて波紋エフェクトを適用 */ private function _onPlayingSound(e:Event):void { var spectrum:Number, phase:Number, scale:Number, dmf:DisplacementMapFilter; // 周波数帯の低い方の1/4を使用。0-1の範囲に変換。 spectrum = _analyzeSound(2)[0]/SPECTRUM_MAX; // トラック中の最大値を取得し、その中での現在値を0-1の範囲に変換。 if (_spectrumMax < spectrum) _spectrumMax = spectrum; if (_spectrumMax > 0) spectrum = spectrum/_spectrumMax; // スペクトラムの値が0% if (spectrum == 0) { _spectrumTarget = spectrum; phase = 0; // スペクトラムの値が80%より上 } else if (spectrum > 0.8) { _spectrumTarget = spectrum; phase = (0.5+spectrum)*30/FPS; // スペクトラムの値が80%以下、30%より上 } else if (spectrum > 0.3) { _spectrumTarget = spectrum/3; phase = (0.2+spectrum)*30/FPS; // スペクトラムの値が30%以下、0%より上 } else { _spectrumTarget = 0.1; phase = 0.5*30/FPS; } // 前の値から次の値へ75%ずつ変位 _spectrumCurrent += (_spectrumTarget - _spectrumCurrent)*0.75; // 位相の現在値を計算 if ((_phaseCurrent += phase) >= 4) _phaseCurrent -= 4; scale = _spectrumCurrent*12; if (_rippleImage) { _bmpRipple.bitmapData = _rippleList[uint(_phaseCurrent)]; } else { dmf = new DisplacementMapFilter(_rippleList[uint(_phaseCurrent)], POINT_0, 2, 4, scale, scale, DisplacementMapFilterMode.CLAMP, 0, 0); _bmpImage.filters = [dmf]; } } // ---------------------------------------------------------------------------------------------------- // サウンド解析 // private const STRETCH_FACTOR_LIST:Vector.<Number> = Vector.<Number>([257, 129, 65, 33, 17, 9, 5, 3, 2, 1]); private const SPECTRUM_LENGTH_LIST:Vector.<Number> = Vector.<Number>([1, 2, 4, 8, 16, 32, 64, 128, 256, 256]); // 全周波数帯を2^divに分割し、左右のチャンネルの大きい方のスペクトラムデータを取得します。 private function _analyzeSound(div:int=0):Vector.<Number> { var i:uint, len:uint, size:uint, position:uint, l:Number, r:Number, stretchFactor:uint, bytes:ByteArray, vector:Vector.<Number>; if (div > 9) div = 9; stretchFactor = STRETCH_FACTOR_LIST[div]; len = SPECTRUM_LENGTH_LIST[div]; size = 1024/len; bytes = new ByteArray(); SoundMixer.computeSpectrum(bytes, true, stretchFactor); vector = new Vector.<Number>(len, true); for (i=0; i<len; i++) { position = i*size; bytes.position = position; l = bytes.readFloat(); bytes.position = position + 1024; r = bytes.readFloat(); vector[i] = (l > r) ? l : r; } return vector; } // ---------------------------------------------------------------------------------------------------- // Beatport API // private const BP_RGB:uint = 0xa0d626; // Beatportカラー //private const BP_TRACK_JSON = "http://api.beatport.com/catalog/tracks?format=json&v=1.0"; private const BP_TRACK_URL_XML:String = "http://api.beatport.com/catalog/tracks?format=xml&v=1.0"; private const BP_TRACK_IMAGE_URL:String = "http://geo-media.beatport.com/image_size/212x212/"; // 212×212のジャケット画像取用 private const BP_TRACK_BORDER_ARGB:uint = 0xff808080; private var _urlLoader:URLLoader; private var _loader:Loader; private var _track:Track; /** * Beatport APIを通してトラック情報とジャケット画像をロードします。 * * @param id BeatportのトラックID * @param callbackComplete ロード成功時のコールバック関数 * @param callBackError エラー時のコールバック関数 */ private function _loadBeatport(id:String, callbackComplete:Function, callbackError:Function):void { if (_track != null) _track.destroy(); _track = new Track(); _urlLoader = new URLLoader(); _urlLoader.addEventListener(Event.COMPLETE, onSuccessInfo); _urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError); _urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); //_urlLoader.load(new URLRequest(BP_TRACK_JSON + "&id=" + id)); _urlLoader.load(new URLRequest(BP_TRACK_URL_XML + "&id=" + id)); // トラック情報のロード成功時 function onSuccessInfo(e:Event):void { // var resultList:Array; var resultList:XMLList; _urlLoader.removeEventListener(Event.COMPLETE, onSuccessInfo); _urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, onError); _urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError); _urlLoader = null; /*resultList = JSON.decode(e.target.data).results; if (resultList.length > 0) { _decodeBeatportJson(resultList[0]); } else { if (callbackError is Function) callbackError.apply(); return; }*/ resultList = new XMLList(e.target.data).result; if (resultList.length() > 0) { _parseBeatportXml(resultList[0]); } else { if (callbackError is Function) callbackError.apply(); return; } // 続いてジャケット画像のロード _loader = new Loader(); _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onSuccessImage); _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError); _loader.load(new URLRequest(_track.urlImage), new LoaderContext(true)); } // ジャケット画像のロード成功時 function onSuccessImage(e:Event):void { var bmpdTemp:BitmapData; // BitmapDataを抜き出し _track.image = Bitmap(e.target.content).bitmapData; // 画像が小さい場合は2倍に拡大 if (_track.small) { bmpdTemp = new BitmapData(_track.image.width*2, _track.image.height*2, false, 0); bmpdTemp.draw(_track.image, new Matrix(2, 0, 0, 2, 0, 0), null, null, null, true); _track.image.dispose(); _track.image = bmpdTemp; } // ボーダーの作成 _track.border = makeBorderBitmapData(_track.image.width+2, _track.image.height+2, BP_TRACK_BORDER_ARGB) _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onSuccessImage); _loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onError); _loader = null; if (callbackComplete is Function) callbackComplete.apply(); } // ロード失敗時のリスナー function onError(e:ErrorEvent):void { if (callbackError is Function) callbackError.apply(); } } /** * Beatport APIで取得したJSONデータをデコードします。 * * @param json トラック情報の入ったJSONオブジェクト */ /*private function _decodeBeatportJson(jsonObject:Object):void { var mixName:String, artist:String, artistList:Array, performer:Object; _track.urlSound = jsonObject.sampleUrl; // 画像のURL(大きい画像) if (jsonObject.images.large != undefined) { _track.urlImage = BP_TRACK_IMAGE_URL + jsonObject.images.large.url.match(/([^\/]*)?$/)[0]; // 212×212 // 画像のURL(小さい画像) } else { _track.small = true; _track.urlImage = jsonObject.images.medium.url; // 60×60 } mixName = (jsonObject.mixName == "" || jsonObject.mixName == "Original Mix") ? "" : " (" + jsonObject.mixName + ")"; artistList = []; for each (performer in jsonObject.artists) { if (performer.type == "Artist") { artistList.push(performer.name); } } artist = artistList.join(", "); _track.info = String(jsonObject.name).toUpperCase() + String(mixName).toUpperCase() + " / " + String(artist).toUpperCase() + " / " + String(jsonObject.label.name).toUpperCase(); }*/ /** * Beatport APIで取得したXMLデータを解析します。 * * @param xml トラック情報の入ったXMLオブジェクト */ private function _parseBeatportXml(xml:XML):void { var mixName:String, artist:String, artistList:Array, performer:Object; _track.urlSound = xml.document.track.@url; // 画像のURL(大きい画像) if (xml.document.track.image.(@ref=='release'&&@width=='500') != undefined) { _track.urlImage = BP_TRACK_IMAGE_URL + xml.document.track.image.(@ref=='release'&&@width=='500').@url.match(/([^\/]*)?$/)[0]; // 212×212 // 画像のURL(小さい画像) } else if (xml.document.track.image.(@ref=='release'&&@width=='60') != undefined) { _track.small = true; _track.urlImage = xml.document.track.image.(@ref=='release'&&@width=='60').@url; // 60×60 リリース画像 } else if (xml.document.track.image.(@ref=='label'&&@width=='60') != undefined) { _track.small = true; _track.urlImage = xml.document.track.image.(@ref=='label'&&@width=='60').@url; // 60×60 レーベル画像 } else { _track.small = true; _track.urlImage = xml.document.track.image.(@ref=='defalut'&&@width=='60').@url; // 60×60 デフォルト画像 } mixName = (xml.document.track.mixName == "" || xml.document.track.mixName == "Original Mix") ? "" : " (" + xml.document.track.mixName + ")"; artistList = []; for each (performer in xml.document.track.performer) { if (performer.@ref == "Artist") { artistList.push(performer.name); } } artist = artistList.join(", "); _track.info = String(xml.document.track.name).toUpperCase() + String(mixName).toUpperCase() + " / " + String(artist).toUpperCase() + " / " + String(xml.document.track.label.name).toUpperCase(); } // ---------------------------------------------------------------------------------------------------- // トラック情報(タイトル / アーティスト / レーベル)の表示 // private var _textFieldInfo:TextField; /** * トラック情報を初期化 */ private function _initInfo():void { _textFieldInfo = new TextField(); _textFieldInfo.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff); _textFieldInfo.embedFonts = true; _textFieldInfo.autoSize = TextFieldAutoSize.LEFT; _textFieldInfo.multiline = false; _textFieldInfo.selectable = false; addChild(_textFieldInfo); } /** * トラック情報のテキストを変更 */ private function _changeInfo():void { _textFieldInfo.text = _track.info; _moveInfo(); } /** * トラック情報の配置を更新 */ private function _moveInfo():void { _textFieldInfo.x = int((stage.stageWidth - _textFieldInfo.width)/2); _textFieldInfo.y = int((stage.stageHeight + IMAGE_SIZE_MAX)/2 + 50); } // ---------------------------------------------------------------------------------------------------- // トラックを再生/停止するコントローラ // private const CONTROL_SIZE:uint = 50; private var _bmpControlPlay:Bitmap; private var _bmpControlPause:Bitmap; private var _buttonControl:SimpleButton; private var _buttonPlay:Boolean; /** * コントローラを初期化 */ private function _initControl():void { var s:Shape, g:Graphics, bmp:Bitmap, bmpd:BitmapData; s = new Shape(); g = s.graphics; // 再生 g.clear(); g.lineStyle(1, 0, 0.25); g.beginFill(0, 0.75); g.drawCircle(25, 25, 20); g.endFill(); g.lineStyle(0, 0, 0); g.beginFill(BP_RGB, 0.9); g.moveTo(19, 15); g.lineTo(34, 25); g.lineTo(19, 35); g.lineTo(19, 15); g.endFill(); bmpd = new BitmapData(CONTROL_SIZE, CONTROL_SIZE, true, 0); bmpd.draw(s); _bmpControlPlay = new Bitmap(bmpd); _bmpControlPlay.visible = false; addChild(_bmpControlPlay); // 停止 g.clear(); g.lineStyle(1, 0, 0.25); g.beginFill(0, 0.75); g.drawCircle(25, 25, 20); g.endFill(); g.lineStyle(0, 0, 0); g.beginFill(BP_RGB, 0.9); g.drawRect(18, 17, 4, 16); g.drawRect(28, 17, 4, 16); g.endFill(); bmpd = new BitmapData(CONTROL_SIZE, CONTROL_SIZE, true, 0); bmpd.draw(s); _bmpControlPause = new Bitmap(bmpd); _bmpControlPause.visible = false; addChild(_bmpControlPause); // 透明ボタン bmp = new Bitmap(); _buttonControl = new SimpleButton(bmp, bmp, bmp, bmp); _buttonControl.addEventListener(MouseEvent.ROLL_OVER, onRollOver); _buttonControl.addEventListener(MouseEvent.ROLL_OUT, onRollOut); _buttonControl.addEventListener(MouseEvent.CLICK, onClick); addChild(_buttonControl); _moveControl(); function onClick(e:MouseEvent):void { if (_buttonPlay) { _pauseSound(); } else { _playSound(); } _switchControl(); } function onRollOver(e:MouseEvent):void { if (_buttonPlay) { _bmpControlPause.visible = true; } else { _bmpControlPlay.visible = true; } } function onRollOut(e:MouseEvent):void { if (_buttonPlay) { _bmpControlPause.visible = false; } else { _bmpControlPlay.visible = false; } } } /** * コントローラの透明ボタンのサイズをトラック画像に合わせて更新 */ private function _changeControl():void { var bmp:Bitmap; bmp = Bitmap(_buttonControl.hitTestState); if (bmp.bitmapData != null) bmp.bitmapData.dispose(); bmp.bitmapData = new BitmapData(_track.image.width, _track.image.height, true, 0); _moveControl(); _buttonPlay = true; } /** * コントローラの再生/停止を切り替え */ private function _switchControl():void { if (_bmpControlPlay.visible || _bmpControlPause.visible) { if (_buttonPlay) { _bmpControlPlay.visible = true; _bmpControlPause.visible = false; _buttonPlay = false; } else { _bmpControlPlay.visible = false; _bmpControlPause.visible = true; _buttonPlay = true; } } else { _buttonPlay = !_buttonPlay; } } /** * コントローラの配置を更新 */ private function _moveControl():void { _bmpControlPlay.x = int((stage.stageWidth - CONTROL_SIZE)/2); _bmpControlPlay.y = int((stage.stageHeight - CONTROL_SIZE)/2); _bmpControlPause.x = int((stage.stageWidth - CONTROL_SIZE)/2); _bmpControlPause.y = int((stage.stageHeight - CONTROL_SIZE)/2); _buttonControl.x = int((stage.stageWidth - _buttonControl.width)/2); _buttonControl.y = int((stage.stageHeight - _buttonControl.height)/2); } /** * コントローラを表示 */ private function _showControl():void { _buttonControl.visible = true; _buttonControl.mouseEnabled = true; } /** * コントローラを非表示 */ private function _hideControl():void { _buttonControl.visible = false; _buttonControl.mouseEnabled = false; } // ---------------------------------------------------------------------------------------------------- // トラックの選択と現在位置表示のナビゲーション // private const SELECT_SIZE:uint = 12; private var _spSelect:Sprite; private var _bmpdSelect:BitmapData; private var _buttonSelectList:Vector.<SimpleButton>; /** * 選択ナビゲーションを初期化 */ private function _initSelect():void { var i:uint, len:uint, s:Shape, g:Graphics, bmp:Bitmap, button:SimpleButton; _spSelect = new Sprite(); addChild(_spSelect); _buttonSelectList = new Vector.<SimpleButton>(); s = new Shape(); g = s.graphics; // ○ g.beginFill(0x404040, 1); g.drawCircle(6, 6, 6); g.endFill(); _bmpdSelect = new BitmapData(SELECT_SIZE, SELECT_SIZE, true, 0); _bmpdSelect.draw(s); len = TRACK_ID_LIST.length; for (i=0;i<len;i++) { bmp = new Bitmap(_bmpdSelect); button = new SimpleButton(bmp, bmp, bmp, bmp); button.x = i*20; _spSelect.addChild(button); _buttonSelectList[i] = button; button.addEventListener(MouseEvent.CLICK, _onClickSelect); button.addEventListener(MouseEvent.ROLL_OVER, _onRollOverSelect); button.addEventListener(MouseEvent.ROLL_OUT, _onRollOutSelect); } _changeSelect(); _moveSelect(); } private function _onClickSelect(e:MouseEvent):void { _loadTrackSelect(_buttonSelectList.indexOf(e.target)); } private function _onRollOverSelect(e:MouseEvent):void { _buttonSelectList[_buttonSelectList.indexOf(e.target)].transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0x80, 0x80, 0x80, 0); } private function _onRollOutSelect(e:MouseEvent):void { _buttonSelectList[_buttonSelectList.indexOf(e.target)].transform.colorTransform = new ColorTransform(); } /** * 選択ナビゲーションの要素を追加 */ private function _addSelect():void { var i:uint, bmp:Bitmap, bmpd:BitmapData, button:SimpleButton; i = _buttonSelectList.length; bmp = new Bitmap(_bmpdSelect); button = new SimpleButton(bmp, bmp, bmp, bmp); button.x = i*20; _spSelect.addChild(button); _buttonSelectList.push(button); button.addEventListener(MouseEvent.CLICK, _onClickSelect); button.addEventListener(MouseEvent.ROLL_OVER, _onRollOverSelect); button.addEventListener(MouseEvent.ROLL_OUT, _onRollOutSelect); _moveSelect(); } /** * 選択ナビゲーションの現在位置を変更 */ private function _changeSelect():void { var i:uint, len:uint; len = _buttonSelectList.length; for (i=0;i<len;i++) { if (i == _trackIdIndex) { _buttonSelectList[i].mouseEnabled = false; _buttonSelectList[i].transform.colorTransform = new ColorTransform(0, 0, 0, 1, ((BP_RGB >> 16) & 255)*0.8, ((BP_RGB >> 8) & 255)*0.8, (BP_RGB & 255)*0.8, 0); } else { _buttonSelectList[i].mouseEnabled = true; _buttonSelectList[i].transform.colorTransform = new ColorTransform() } } } /** * 選択ナビゲーションの配置を更新 */ private function _moveSelect():void { _spSelect.x = int((stage.stageWidth - _spSelect.width)/2); _spSelect.y = int((stage.stageHeight + IMAGE_SIZE_MAX)/2 + 15); } /** * 選択ナビゲーションを表示 */ private function _showSelect():void { _spSelect.visible = true; _spSelect.mouseChildren = true; } /** * 選択ナビゲーションを表示 */ private function _hideSelect():void { _spSelect.visible = false; _spSelect.mouseChildren = false; } // ---------------------------------------------------------------------------------------------------- // 画面の中心にメッセージを表示 // private var _textFieldMessage:TextField; private var _messageTime:uint; /** * メッセージ表示を初期化 */ private function _initMessage():void { _textFieldMessage = new TextField; _textFieldMessage.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff); _textFieldMessage.embedFonts = true; _textFieldMessage.autoSize = TextFieldAutoSize.LEFT; _textFieldMessage.multiline = false; _textFieldMessage.selectable = false; addChild(_textFieldMessage); } /** * メッセージ表示のテキストを変更 * * @param text 表示メッセージ */ private function _changeMessage(text:String):void { _textFieldMessage.text = text; _moveMessage(); } /** * メッセージ表示の配置を更新 */ private function _moveMessage():void { _textFieldMessage.x = int((stage.stageWidth - _textFieldMessage.width)/2); _textFieldMessage.y = int((stage.stageHeight - _textFieldMessage.height)/2); } /** * メッセージ表示の点滅を開始 */ private function _showMessage():void { addEventListener(Event.ENTER_FRAME, _blinkMessage); _textFieldMessage.visible = true; } /** * メッセージ表示の点滅を終了 */ private function _hideMessage():void { removeEventListener(Event.ENTER_FRAME, _blinkMessage); _textFieldMessage.visible = false; } /** * メッセージ表示を一定間隔で点滅 * * @param e イベント */ private function _blinkMessage(e:Event):void { var timer:uint; if ((timer = getTimer()) - _messageTime > 25) { _messageTime = timer; _textFieldMessage.visible = !_textFieldMessage.visible; } } // ---------------------------------------------------------------------------------------------------- // 背景 // private var _bmpBack:Bitmap; /** * 背景用のBitmapを作成 */ private function _initBack():void { _bmpBack = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0)); addChildAt(_bmpBack, 0); } /** * 背景用のBitmapをリサイズ */ private function _resizeBack():void { _bmpBack.bitmapData.dispose(); _bmpBack.bitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0); } // ---------------------------------------------------------------------------------------------------- // フォント内蔵のSWFをロード、登録 // private const FONT_CLASS_KROEGER_0655:String = "Kroeger0655"; private const FONT_NAME_KROEGER_0655:String = "kroeger 06_55"; private const FONT_SWF_URL:String = "http://global.yuichiroharai.com/swf/FontKroeger.swf"; /** * フォント内蔵のSWFをロード * * @param callback コールバック関数 */ private function _loadFont(callBack:Function):void { var loader:Loader; loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete); loader.load(new URLRequest(FONT_SWF_URL), new LoaderContext(true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain)); function complete(e:Event):void { try { Font.registerFont(loader.contentLoaderInfo.applicationDomain.getDefinition(FONT_CLASS_KROEGER_0655) as Class); } catch (e:Error) { return; } loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete); loader = null; if (callBack is Function) callBack.apply(); } } // ---------------------------------------------------------------------------------------------------- // スタッツ // /** * スタッツを表示 */ private function _initStats():void { var stats:Stats; stats = new Stats(); addChild(stats); } // ---------------------------------------------------------------------------------------------------- // ユーティリティメソッド // /** * ボーダーBitmapDataを作成 * * @param width 横幅 * @param height 高さ * @param argb ARGBカラー * @return ボーダーBitmapData */ public function makeBorderBitmapData(width:uint, height:uint, argb:uint):BitmapData { var bmpd:BitmapData, i:uint; bmpd = new BitmapData(width, height, true, 0); bmpd.lock(); for (i=0;i<height;i++) { bmpd.setPixel32(0, i, argb); bmpd.setPixel32(width-1, i, argb); } for (i=1;i<width-1;i++) { bmpd.setPixel32(i, 0, argb); bmpd.setPixel32(i, height-1, argb); } bmpd.unlock(); return bmpd; } } } // ---------------------------------------------------------------------------------------------------- // トラックデータを格納するクラス // import flash.display.BitmapData; import flash.media.Sound; class Track { public var info:String; // トラック名 (ミックス名) / アーティスト / レーベル public var urlSound:String; // サウンドのURL public var urlImage:String; // ジャケット画像のURL public var image:BitmapData; // ジャケット画像 public var border:BitmapData; // ボーダー画像 public var small:Boolean=false; // 小さい画像のトラックかどうか public function destroy():void { info = null urlSound = null; urlImage = null; if (image != null) image.dispose(); image = null; if (border != null) border.dispose(); border = null; small = false; } } Code Fullscreen Preview Fullscreen