In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

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;
    }
}