forked from: Ripple Beat - 音に反応する波紋
Ripple Beatの波紋エフェクトのサンプル
http://www.yuichiroharai.com/ripplebeat/
@author Yuichiroh Arai
/**
* Copyright bradsedito ( http://wonderfl.net/user/bradsedito )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rHGx
*/
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;
public class RippleBeatSample extends Sprite
{
private const FPS:uint = 60;
private const STAGE_SIZE:uint = 465;
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();
_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;
}
}