computeSpectrum(FFT)のstretchFactor
SoundMixer.computeSpectrumメソッドのstretchFactor引数は「(2^n)+1」の値が良いようです。
http://dev.yuichiroharai.com/post/about-stretchfactor-of-computespectrum-fft/
/**
* Copyright yuichiroharai ( http://wonderfl.net/user/yuichiroharai )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/c6R9
*/
package {
// ----------------------------------------------------------------------------------------------------
// インポート
//
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.events.SampleDataEvent;
import flash.events.SecurityErrorEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundMixer;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.system.SecurityDomain;
import flash.text.Font;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.getTimer;
import net.hires.debug.Stats;
/**
* computeSpectrum(FFT)のstretchFactor
* 考察記事:
* http://dev.yuichiroharai.com/post/about-stretchfactor-of-computespectrum-fft/
*
* @author Yuichiroh Arai
*/
public class ComputeSpectrumSample extends Sprite {
// ----------------------------------------------------------------------------------------------------
// メイン処理
//
private const FPS:uint = 60; // フレームレート
private const STAGE_SIZE:uint = 465; // ステージサイズ
// トラックのサンプル
// Play It Loud! / Radiq / op.disc
private var TRACK_ID:String = "1837104";
/**
* コンストラクタ
*/
public function ComputeSpectrumSample():void {
stage.frameRate = FPS;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_loadFont(step1);
function step1():void {
//_initStats();
_initBack();
_initMessage();
_initInfo();
_initSpectrum();
_spSpectrum.visible = false;
_initSlideBar();
_spSlideBar.visible = false;
_initControl();
_hideControl();
_initStretchFactor();
_spStretchFactor.visible = false;
stage.addEventListener(Event.RESIZE, _onResize);
stage.addEventListener(Event.FULLSCREEN, _onResize);
_changeMessage("NOW LODING");
_showMessage();
_loadBeatport(TRACK_ID, step2, error);
}
function step2():void {
_hideMessage();
_spSpectrum.visible = true;
_spSlideBar.visible = true;
_spStretchFactor.visible = true;
_changeInfo();
_loadAndPlaySound();
}
function error():void {
_hideMessage();
_changeMessage("LOADING ERROR...");
_textFieldMessage.visible = true;
}
}
/**
* ステージリサイズ時の処理
*/
private function _onResize(e:Event):void {
_moveMessage();
_moveSpectrum();
_moveInfo();
_moveControl();
_moveStretchFactor();
_moveSlideBar();
_resizeBack();
}
// ----------------------------------------------------------------------------------------------------
// スペクトラム表示
//
private const SPECTRUM_SIZE_WIDTH:uint = 256;
private const SPECTRUM_SIZE_HEIGHT:uint = 200;
private var _spSpectrum:Sprite;
private var _bmpSpectrumBorder:Bitmap;
private var _bmpSpectrumMeter:Bitmap;
/**
* スペクトラムの表示エリア
*/
private function _initSpectrum():void {
_spSpectrum = new Sprite();
addChild(_spSpectrum);
_bmpSpectrumMeter = new Bitmap();
_bmpSpectrumMeter.x = _bmpSpectrumMeter.y = 1;
_spSpectrum.addChild(_bmpSpectrumMeter);
_bmpSpectrumBorder = new Bitmap(makeBorderBitmapData(SPECTRUM_SIZE_WIDTH+2, SPECTRUM_SIZE_HEIGHT+2, 0xff404040));
_spSpectrum.addChild(_bmpSpectrumBorder);
_moveSpectrum();
}
/**
* スペクトラムの表示エリアの配置を更新
*/
private function _moveSpectrum():void {
_spSpectrum.x = int((stage.stageWidth - SPECTRUM_SIZE_WIDTH+2)/2);
_spSpectrum.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2);
}
// ----------------------------------------------------------------------------------------------------
// サウンドのロード、再生、停止など
//
private var _sound:Vector.<Sound>;
private var _soundChannel:SoundChannel;
private var _soundPosition:Number = 0;
/**
* サウンドをロードして再生
*/
private function _loadAndPlaySound():void {
_sound = Vector.<Sound>([new Sound()]);
_sound[0].addEventListener(Event.OPEN, open);
_sound[0].load(new URLRequest(_urlSound), new SoundLoaderContext(1000, true));
function open(e:Event):void {
_showControl();
_switchControl();
_soundChannel = _sound[0].play(0);
addEventListener(Event.ENTER_FRAME, _onPlayingSound);
_sound[0].removeEventListener(Event.OPEN, open);
}
}
/**
* サウンドを再生
*/
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);
}
/**
* サウンドの再生完了時の処理。
*/
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);
}
// ----------------------------------------------------------------------------------------------------
// スペクトラム解析
//
private const SPECTRUM_MAX:Number = 1.4142136;
private const STRETCH_FACTOR_LIST_1:Vector.<Number> = Vector.<Number>([0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512]);
private const STRETCH_FACTOR_LIST_2:Vector.<Number> = Vector.<Number>([0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257]);
private var _spectrumIndex:uint=0;
private var _g:Graphics = graphics;
private var _timer:uint = 0;
/**
* サウンドに合わせてスペクトラムを描画。左右のチャンネルの大きい方を採用。
*/
private function _onPlayingSound(e:Event):void {
var i:uint, bytes:ByteArray, l:Number, r:Number, value:Number, h:uint, stretchFactor:uint, bmpd:BitmapData;
_g.clear();
stretchFactor = (_stretchFactorType) ? STRETCH_FACTOR_LIST_2[_spectrumIndex] : STRETCH_FACTOR_LIST_1[_spectrumIndex];
bytes = new ByteArray();
SoundMixer.computeSpectrum(bytes, true, stretchFactor);
bmpd = new BitmapData(SPECTRUM_SIZE_WIDTH, SPECTRUM_SIZE_HEIGHT, true, 0);
bmpd.lock();
for (i=0;i<256;i++) {
bytes.position = i*4;
l = bytes.readFloat();
bytes.position = i*4 + 1024;
r = bytes.readFloat();
value = (l > r) ? l : r;
h = int(value/SPECTRUM_MAX*200+0.5);
bmpd.fillRect(new Rectangle(i, SPECTRUM_SIZE_HEIGHT - h, 1, h), 0xff808080);
}
bmpd.unlock();
if (_bmpSpectrumMeter.bitmapData != null) _bmpSpectrumMeter.bitmapData.dispose();
_bmpSpectrumMeter.bitmapData = bmpd;
}
// ----------------------------------------------------------------------------------------------------
// stretchFactorの種類("2^N" or "(2^N) + 1")の切り替え
//
private var _spStretchFactor:Sprite;
private var _buttonStretchFactor1:SimpleButton;
private var _buttonStretchFactor2:SimpleButton;
private var _stretchFactorType:Boolean=true;
/**
* stretchFactorの種類切り替えボタンを初期化
*/
private function _initStretchFactor():void {
var text:TextField;
_spStretchFactor = new Sprite();
addChild(_spStretchFactor);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0x404040);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "2^N";
_buttonStretchFactor1 = new SimpleButton(text, text, text, new Bitmap(new BitmapData(text.width, text.height, false, 0)));
_buttonStretchFactor1.addEventListener(MouseEvent.CLICK, onClick);
_buttonStretchFactor1.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
_buttonStretchFactor1.addEventListener(MouseEvent.ROLL_OUT, onRollOut);
_spStretchFactor.addChild(_buttonStretchFactor1);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0x404040);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "(2^N) + 1";
_buttonStretchFactor2 = new SimpleButton(text, text, text, new Bitmap(new BitmapData(text.width, text.height, false, 0)));
_buttonStretchFactor2.x = _buttonStretchFactor1.width + 5;
_buttonStretchFactor2.addEventListener(MouseEvent.CLICK, onClick);
_buttonStretchFactor2.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
_buttonStretchFactor2.addEventListener(MouseEvent.ROLL_OUT, onRollOut);
_spStretchFactor.addChild(_buttonStretchFactor2);
if (_stretchFactorType) {
_buttonStretchFactor2.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xff, 0xff, 0xff, 0);
_buttonStretchFactor2.mouseEnabled = false;
} else {
_buttonStretchFactor1.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xff, 0xff, 0xff, 0);
_buttonStretchFactor1.mouseEnabled = false;
}
_moveStretchFactor();
function onClick(e:MouseEvent):void {
_switchStretchFactor();
_changeStretchFactor();
}
function onRollOver(e:MouseEvent):void {
SimpleButton(e.target).transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0x80, 0x80, 0x80, 0);
}
function onRollOut(e:MouseEvent):void {
if (!SimpleButton(e.target).mouseEnabled) return;
SimpleButton(e.target).transform.colorTransform = new ColorTransform();
}
}
/**
* stretchFactorの種類を切り替え
*/
private function _switchStretchFactor():void {
_stretchFactorType = !_stretchFactorType;
if (_stretchFactorType) {
_buttonStretchFactor2.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xff, 0xff, 0xff, 0);
_buttonStretchFactor2.mouseEnabled = false;
_buttonStretchFactor1.transform.colorTransform = new ColorTransform();
_buttonStretchFactor1.mouseEnabled = true;
} else {
_buttonStretchFactor2.transform.colorTransform = new ColorTransform();
_buttonStretchFactor2.mouseEnabled = true;
_buttonStretchFactor1.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xff, 0xff, 0xff, 0);
_buttonStretchFactor1.mouseEnabled = false;
}
}
/**
* stretchFactorの種類切り替えボタンの配置を更新
*/
private function _moveStretchFactor():void {
_spStretchFactor.x = int((stage.stageWidth - _spSlideBar.width)/2);;
_spStretchFactor.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2 - 29);
}
// ----------------------------------------------------------------------------------------------------
// stretchFactorを変更するためのスライドバー
//
private const SLIDE_BAR_WIDTH:uint = 120;
private var _spSlideBar:Sprite;
private var _slideBar:SlideBar;
private var _textSlideBar:TextField;
/**
* スライドバーを初期化
*/
private function _initSlideBar():void {
var text:TextField;
_spSlideBar = new Sprite();
addChild(_spSlideBar);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0555, 8, 0x808080);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "STRETCH FACTOR:";
text.x = -5;
_spSlideBar.addChild(text);
_textSlideBar = new TextField();
_textSlideBar.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff);
_textSlideBar.embedFonts = true;
_textSlideBar.autoSize = TextFieldAutoSize.LEFT;
_textSlideBar.multiline = false;
_textSlideBar.selectable = false;
_textSlideBar.text = STRETCH_FACTOR_LIST_2[_spectrumIndex].toString();
_textSlideBar.x = text.width + text.x;
_textSlideBar.y = -2;
_spSlideBar.addChild(_textSlideBar);
_slideBar = new SlideBar(SLIDE_BAR_WIDTH, STRETCH_FACTOR_LIST_2.length-1, SlideBar.createBar(7, 15, 0xffffffff), SlideBar.createRail(SLIDE_BAR_WIDTH, 1, 0xff404040));
_slideBar.value = _spectrumIndex;
_slideBar.onChange = onChange;
_slideBar.y = 24;
_spSlideBar.addChild(_slideBar);
_moveSlideBar();
function onChange(value:uint):void {
_spectrumIndex = value;
_changeStretchFactor();
}
}
/**
* スライドバー内のstretchFactorのテキストを変更
*/
private function _changeStretchFactor():void {
_textSlideBar.text = (_stretchFactorType) ? STRETCH_FACTOR_LIST_2[_spectrumIndex].toString() : STRETCH_FACTOR_LIST_1[_spectrumIndex].toString();
}
/**
* スライドバーの配置を更新
*/
private function _moveSlideBar():void {
_spSlideBar.x = int((stage.stageWidth - _spSlideBar.width)/2);
_spSlideBar.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2 - 68);
}
// ----------------------------------------------------------------------------------------------------
// トラックを再生/停止するコントローラ
//
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(0x202020, 0.95);
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(0x202020, 0.95);
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();
bmp.bitmapData = new BitmapData(SPECTRUM_SIZE_WIDTH, SPECTRUM_SIZE_HEIGHT, true, 0);
_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 _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 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 = _textInfo;
_moveInfo();
}
/**
* トラック情報の配置を更新
*/
private function _moveInfo():void {
_textFieldInfo.x = int((stage.stageWidth - _textFieldInfo.width)/2);
_textFieldInfo.y = int((stage.stageHeight + 150)/2 + 50);
}
// ----------------------------------------------------------------------------------------------------
// 画面の中心にメッセージを表示
//
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);
}
// ----------------------------------------------------------------------------------------------------
// Beatport API
//
private const BP_RGB:uint = 0xa0d626; // Beatportカラー
private const BP_TRACK_URL_XML:String = "http://api.beatport.com/catalog/tracks?format=xml&v=1.0";
private var _urlLoader:URLLoader;
private var _urlSound:String;
private var _textInfo:String;
/**
* Beatport APIを通してトラック情報とジャケット画像をロードします。
*
* @param id BeatportのトラックID
* @param callbackComplete ロード成功時のコールバック関数
* @param callBackError エラー時のコールバック関数
*/
private function _loadBeatport(id:String, callbackComplete:Function, callbackError:Function):void {
_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_URL_XML + "&id=" + id));
// トラック情報のロード成功時
function onSuccessInfo(e:Event):void {
var result:XML;
_urlLoader.removeEventListener(Event.COMPLETE, onSuccessInfo);
_urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
_urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
_urlLoader = null;
result = new XML(e.target.data).result[0];
if (result.toString() != "") {
_parseBeatportXml(result);
if (callbackComplete is Function) callbackComplete.apply();
} else {
if (callbackError is Function) callbackError.apply();
}
}
// ロード失敗時のリスナー
function onError(e:ErrorEvent):void {
if (callbackError is Function) callbackError.apply();
}
}
/**
* Beatport APIで取得したXMLデータを解析します。
*
* @param xml トラック情報の入ったXMLオブジェクト
*/
private function _parseBeatportXml(xml:XML):void {
var mixName:String, artist:String, artistList:Array, performer:Object;
_urlSound = xml.document.track.@url;
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(", ");
_textInfo = String(xml.document.track.name).toUpperCase() + String(mixName).toUpperCase() + " / " + String(artist).toUpperCase() + " / " + String(xml.document.track.label.name).toUpperCase();
}
// ----------------------------------------------------------------------------------------------------
// フォント内蔵のSWFをロード、登録
//
private const FONT_CLASS_KROEGER_0555:String = "Kroeger0555";
private const FONT_CLASS_KROEGER_0655:String = "Kroeger0655";
private const FONT_NAME_KROEGER_0555:String = "kroeger 05_55";
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_0555) as Class);
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();
}
}
// ----------------------------------------------------------------------------------------------------
// ユーティリティメソッド
//
/**
* ボーダー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;
}
// ----------------------------------------------------------------------------------------------------
// スタッツ
//
/**
* スタッツを表示
*/
private function _initStats():void {
var stats:Stats;
stats = new Stats();
addChild(stats);
}
}
}
// ----------------------------------------------------------------------------------------------------
// インポート
//
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* スライドバー(X軸)を構成するクラスです。
*/
class SlideBar extends Sprite {
// ----------------------------------------------------------------------------------------------------
// 変数
//
// スライドバーのボタン
private var _bar:SimpleButton;
// スライドバーのレール
private var _rail:Sprite;
// スライドバーの横幅
private var _width:uint;
// スライドバーの取り得る値の範囲
private var _range:uint;
/**
* バーの値です。
*/
public function get value():uint {
return _value;
}
public function set value(v:uint):void {
_value = (v > _range) ? _range : v;
_barMoveJust();
if (onChange is Function) onChange.apply(null, [_value]);
}
private var _value:uint = 0;
/**
* バーの移動係数です。
*/
public function get moveFactor():Number {
return _moveFactor;
}
public function set moveFactor(v:Number):void {
_moveFactor = (v >= 0 && v <= 1) ? v : 0.5;
}
private var _moveFactor:Number = 0.5;
// valueに対応するX座標
private var _x:Number=0;
// スライドバーが移動中かどうか
private var _moving:Boolean=false;
/**
* SlideBarの値が変更された時に呼び出されるコールバック関数です。
*/
public var onChange:Function;
// ----------------------------------------------------------------------------------------------------
// コンストラクタ
//
/**
* スライドバーを作成します。
*
* @param width スライドバーの幅
* @param range スライドバーの値の数
* @param bar スライドバーのバーを表すSimpleButtonです。
* @param rail スライドバーのレールを表すSpriteです。
*/
public function SlideBar(width:uint, range:uint, bar:SimpleButton, rail:Sprite) {
_width = (width < 2) ? 2 : width;
_range = (range < 2 || range > width) ? width : range;
addChildAt(_rail = rail, 0);
addChild(_bar = bar);
_bar.addEventListener(MouseEvent.MOUSE_DOWN, _barMouseDown, false, 0, true);
}
// ----------------------------------------------------------------------------------------------------
// スライドバーの操作
//
// バーのドラッグ開始
private function _barMouseDown(e:Event):void {
if (stage == null) return;
stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
// バーのドラッグ終了
private function _mouseUp(e:Event):void {
if (stage == null) return;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
// バーのドラッグ
private function _mouseMove(e:Event):void {
var temp:uint = _value;
if (stage == null) return;
if (!_moving) {
stage.addEventListener(Event.ENTER_FRAME, _barMove);
_moving = true;
}
if (mouseX < 0) {
_value = 0;
_x = 0;
} else if (mouseX > _width) {
_value = _range;
_x = _width;
} else {
_value = uint(mouseX/_width*_range + 0.5);
_x = uint(_width*_value/_range);
}
if (temp != _value && onChange is Function) onChange.apply(null, [_value]);
}
// バーの移動
private function _barMove(e:Event):void {
var diff:Number, abs:Number;
diff = _x - _bar.x;
abs = (diff < 0) ? -diff : diff;
if (abs*_moveFactor < 0.05) {
_bar.x = _x;
if (_moving) {
stage.removeEventListener(Event.ENTER_FRAME, _barMove);
_moving = false;
}
} else {
_bar.x += diff*_moveFactor;
}
}
// バーの強制移動
private function _barMoveJust():void {
_bar.x = _x = uint(_width*_value/_range);
if (_moving) {
stage.removeEventListener(Event.ENTER_FRAME, _barMove);
_moving = false;
}
}
/**
* バーを作成
*
* @param width バーの幅
* @param range バーの高さ
* @param argb バーのARGBカラー
*/
public static function createBar(width:uint, height:uint, argb:uint):SimpleButton {
var bmp:Bitmap;
bmp = new Bitmap(new BitmapData(width, height, true, argb));
bmp.x = - uint(width/2);
bmp.y = - uint(height/2);
return new SimpleButton(bmp, bmp, bmp, bmp);
}
/**
* レールを作成
*
* @param width バーの幅
* @param range バーの高さ
* @param argb バーのARGBカラー
*/
public static function createRail(width:uint, height:uint, argb:uint):Sprite {
var bmp:Bitmap, sprite:Sprite;
bmp = new Bitmap(new BitmapData(width, height, true, argb));
bmp.x = 0;
bmp.y = - uint(height/2);
sprite = new Sprite();
sprite.addChild(bmp);
return sprite;
}
}