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

SoundVisualizer(5)

FP11.3で見るとうまく動かないっぽいのでFP11.2以下推奨
Get Adobe Flash player
by okoi 06 Jul 2012
/**
 * Copyright okoi ( http://wonderfl.net/user/okoi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/yEha
 */

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.StatusEvent;
    import flash.geom.Matrix;
    
    [SWF(width="465",height="465",frameRate="60")]
    
    /**
     * ...
     * @author okoi
     */
    public class Main extends Sprite
    {
        public static const WIDTH:int = 465;
        public static const HEIGHT:int = 465;
        
        private var _mp3player:SimpleMP3Player;
        private var _progressbar:ProgressBar;
        private var _visualizer:Visualizer3;
        
        public function Main():void
        {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            graphics.beginFill(0);
            var mat:Matrix = new Matrix();
            mat.createGradientBox(WIDTH, HEIGHT, Math.PI / 2);
            graphics.beginGradientFill("linear", [0, 0x333333, 0], [1, 1, 1], [0, 128, 255], mat);
            graphics.drawRect(0, 0, WIDTH, HEIGHT);
            graphics.endFill();
            
            _visualizer = new Visualizer3();
            addChild(_visualizer);
            
            _mp3player = new SimpleMP3Player(startLoad, completedLoad);
            _mp3player.x = WIDTH / 2;
            addChild(_mp3player);
            
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        
        }
                        
        private function startLoad():void
        {
            completedLoad();
            _progressbar = new ProgressBar();
            _progressbar.x = WIDTH / 2;
            _progressbar.y = HEIGHT / 2;
            addChild(_progressbar);
        }
        
        private function completedLoad():void
        {
            if (_progressbar)
            {
                removeChild(_progressbar);
                _progressbar = null;
            }
        }
        
        private function enterFrameHandler(e:Event):void
        {
            if (_mp3player.isPlaying())
            {
                _visualizer.update(_mp3player.spectrumData);
            }
        }
    
    }

}

import flash.system.Capabilities;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;

import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.media.SoundTransform;

import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.ProgressEvent;
import flash.net.FileReference;
import flash.net.FileFilter;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.utils.ByteArray;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;

/**
 * ...
 * @author okoi
 */
class Visualizer3 extends Sprite
{
    private static const SPECTRUM_NUM:int = 512;
    
    private var _back:BitmapData;
    private var _front:Sprite;
    
    private var _leftSpectrumFactorRecordList:Vector.<SpectrumFactorRecord>;
    private var _rightSpectrumFactorRecordList:Vector.<SpectrumFactorRecord>;
    
    private var _time:int;
    
    private static const ONESIDE_WAVELINE_COUNT:int = 8;
    private var _leftWaveList:Array /*WaveLine*/;
    private var _rightWaveList:Array /*WaveLine*/;
    
    private var _radius:Number = 0;
    
    private var _colorMatrixFilter:ColorMatrixFilter;
    private var _blurFilter:BlurFilter;
    
    public function Visualizer3()
    {
        var i:int;
        
        _back = new BitmapData(Main.WIDTH, Main.HEIGHT, true, 0);
        addChild(new Bitmap(_back));
        
        _front = new Sprite();
        
        _leftSpectrumFactorRecordList = new Vector.<SpectrumFactorRecord>(SPECTRUM_NUM / 2, true);
        _rightSpectrumFactorRecordList = new Vector.<SpectrumFactorRecord>(SPECTRUM_NUM / 2, true);
        for (i = 0; i < SPECTRUM_NUM / 2; i++)
        {
            _leftSpectrumFactorRecordList[i] = new SpectrumFactorRecord();
            _rightSpectrumFactorRecordList[i] = new SpectrumFactorRecord();
        }
        
        _time = 0;
        
        _leftWaveList = [];
        _rightWaveList = [];
        for (i = 0; i < ONESIDE_WAVELINE_COUNT; i++)
        {
            _leftWaveList.push(new WaveLine(120));
            _rightWaveList.push(new WaveLine(120));
        }
        
        _colorMatrixFilter = new ColorMatrixFilter([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0.99, 0]);
        _blurFilter = new BlurFilter(8, 8, 3);
    
    }
    
    public function update(spectrumData:SpectrumData):void
    {
        var i:int;
        var position:int = spectrumData.soundPosition;
        
        //--------------------------------------
        //    analyze
        //--------------------------------------
        var listSize:int = SPECTRUM_NUM / 2;
        var totalConsecutiveOverAverage:int = 0;
        var totalValue:Number = 0;
        
        for (i = 0; i < SPECTRUM_NUM; i++)
        {
            if (i < listSize)
            {
                _leftSpectrumFactorRecordList[i].addRecord(spectrumData.soundPosition, spectrumData.data[i]);
            }
            else
            {
                _rightSpectrumFactorRecordList[i - listSize].addRecord(spectrumData.soundPosition, spectrumData.data[i]);
            }
            
            totalValue += spectrumData.data[i];
        }
        
        _radius *= 0.5;
        _radius += totalValue;
        
        var wavePower:Number = 0;
        var wavePowerList:Array = new Array(ONESIDE_WAVELINE_COUNT);
        var rightWavePointList:Array = new Array(ONESIDE_WAVELINE_COUNT);
        for (i = 0; i < ONESIDE_WAVELINE_COUNT; i++)
        {
            wavePowerList[i] = 0;
            rightWavePointList[i] = 0;
        }
        var waveIndex:int = 0;
        
        listSize = _leftSpectrumFactorRecordList.length;
        for (i = 0; i < listSize; i++)
        {
            waveIndex = int(i / (listSize / ONESIDE_WAVELINE_COUNT));
            wavePowerList[waveIndex] += _leftSpectrumFactorRecordList[i].getLatestValue();
        }
        listSize = _rightSpectrumFactorRecordList.length;
        for (i = 0; i < listSize; i++)
        {
            waveIndex = int(i / (listSize / ONESIDE_WAVELINE_COUNT));
            rightWavePointList[waveIndex] += _rightSpectrumFactorRecordList[i].getLatestValue();
        }
        
        for (i = 0; i < ONESIDE_WAVELINE_COUNT; i++)
        {
            var angle:Number = ((360 / ONESIDE_WAVELINE_COUNT) * i + _time);
            var y:Number = Math.sin(angle * Math.PI / 180) * _radius;
            
            _leftWaveList[i].update(new Point(0, Main.HEIGHT / 2 + y), new Point(Main.WIDTH, Main.HEIGHT / 2 + y), wavePowerList[i], angle);
            _rightWaveList[i].update(new Point(Main.WIDTH, Main.HEIGHT / 2 - y), new Point(0, Main.HEIGHT / 2 - y), rightWavePointList[i], angle);
        }
        
        //--------------------------------------
        //    draw
        //--------------------------------------
        var g:Graphics = _front.graphics;
        
        g.clear();
        
        for (waveIndex = 0; waveIndex < ONESIDE_WAVELINE_COUNT; waveIndex++)
        {
            var wave:WaveLine = _leftWaveList[waveIndex];
            
            var points:Array /*Point*/ = wave.getDividePoints();
            g.lineStyle(0.5, 0xFFFFFF, wave.alpha);
            for (i = 0; i < points.length; i++)
            {
                
                if (i == 0)
                    g.moveTo(points[i].x, points[i].y);
                else
                    g.lineTo(points[i].x, points[i].y);
            }
            
            wave = _rightWaveList[waveIndex];
            points = wave.getDividePoints();
            g.lineStyle(0.5, 0xFFFFFF, wave.alpha);
            
            for (i = 0; i < points.length; i++)
            {
                
                if (i == 0)
                    g.moveTo(points[i].x, points[i].y);
                else
                    g.lineTo(points[i].x, points[i].y);
            }
        }
        
        _back.lock();
        _back.applyFilter(_back, _back.rect, new Point(), _colorMatrixFilter);
        
        _back.applyFilter(_back, _back.rect, new Point(), _blurFilter);
        _back.draw(_front, null, new ColorTransform(0, 0, 0, 0, 150, 150, 255, 70), "add");
        _back.unlock();
        
        _time++;
    }

}

/**
 *
 * @author okoi
 */
class WaveLine
{
    private var _length:Number = 0; //    start,end間の長さ
    
    private var _divideCount:int;
    private var _divideVec:Point; //    start-endを分割したときのベクトル
    private var _dividePoints:Array /*Point*/; //
    
    private var _powerVec:Point;
    
    private var _noise:BitmapData;
    private var _noiseOffset:Array /*Point*/;
    private var _noiseSeed:int;
    
    private var _alpha:Number = 0;
    
    //-------------------------------------------------
    //    getter / setter
    //-------------------------------------------------
    public function get alpha():Number
    {
        return _alpha;
    }
    
    public function WaveLine(divideCount:int)
    {
        var i:int;
        
        _divideCount = divideCount;
        
        _noise = new BitmapData(512, 10, true, 0);
        _noiseOffset = [new Point(), new Point()];
        _noiseSeed = int(Math.random() * 256);
    }
    
    public function getLength():Number
    {
        return _length;
    }
    
    public function getDividePoints():Array /*Point*/
    {
        return _dividePoints;
    }
    
    private function _updateNoise():void
    {
        _noiseOffset[0].x -= 3; //    最初のオクターブだけスクロール
        _noiseOffset[1].x += 0;
        
        _noise.perlinNoise(30, //    x 方向で使用する周波数(幅)
            0, //    y 方向で使用する周波数(高さ)
            1, //    重ねる回数 やりすぎると重い
            _noiseSeed, //    適当な整数
            true, //    補正があり、タイリング可能なノイズ生成を試みる(第09引数でスクロール時に効果的)
            false, //    フラクタルノイズの有無。falseの場合、炎や海の波のような視覚効果
            8, // (8 | 4 | 2 | 1),    //    ノイズ生成のチャンネル
            false, //    グレースケール化
            _noiseOffset //    第03引数で決めた各レイヤーをスクロールするためのPoint型の配列データ
            );
    
    }
    
    public function update(startPoint:Point, endPoint:Point, wavePower:Number, waveAngle:Number):void
    {
        var dx:Number = endPoint.x - startPoint.x;
        var dy:Number = endPoint.y - startPoint.y;
        
        //    ラインの長さ更新
        _length = Math.sqrt(dx * dx + dy * dy);
        
        //    分割した時のベクトル更新
        _divideVec = new Point(dx, dy);
        _divideVec.normalize(_length / _divideCount);
        
        var normal:Point = new Point(dx / _length, dy / _length);
        //x' = x * cosθ - y * sinθ
        //y' = x * sinθ + y * cosθ
        _powerVec = new Point(normal.x * 0 - normal.y * 1, normal.x * 1 + normal.y * 0); // 90度回転
        
        //    ノイズ更新
        _updateNoise();
        
        _dividePoints = [];
        var waveAngleSin:Number = -Math.sin(waveAngle * Math.PI / 180);
        for (var i:int = 0; i <= _divideCount; i++)
        {
            var sweep:Number = Math.sin(Math.PI * (i / _divideCount)) * waveAngleSin;
            
            var flick:Number = _noise.getPixel32((i * 1) % 512, 1);
            
            var a:Number = (((flick >> 24) & 0xff) - 128);
            var power:Number = a * sweep * wavePower * 0.1;
            
            var px:Number = startPoint.x + _divideVec.x * i + _powerVec.x * power;
            var py:Number = startPoint.y + _divideVec.y * i + _powerVec.y * power;
            
            _dividePoints.push(new Point(px, py));
        }
        
        //    アルファ値
        _alpha *= 0.05;
        _alpha += wavePower;
    }

}

/**
 * ...
 * @author okoi
 */
class SpectrumValueHistory
{
    private static const SIZE:int = 60; //    記録量
    private var _data:Vector.<Number>;
    private var _average:Number;
    private var _countConsecutiveOverAverage:int = 0;
    
    //-------------------------------------------
    //    getter / setter
    //-------------------------------------------
    public function get average():Number
    {
        return _average;
    }
    
    public function get countConsecutiveOverAverage():int
    {
        return _countConsecutiveOverAverage;
    }
    
    public function SpectrumValueHistory()
    {
        _data = new Vector.<Number>(SIZE, true);
        for (var i:int = 0; i < SIZE; i++)
            _data[i] = 0;
        
        _average = 0;
    }
    
    /**
     * 記録を追加する、古いデータは削除される
     * @param    value
     */
    public function add(value:Number):void
    {
        var i:int;
        
        for (i = SIZE - 1; i > 0; i--)
        {
            _data[i] = _data[i - 1];
        }
        _data[0] = value;
        
        //    平均値計算
        _average = 0;
        for (i = 0; i < SIZE; i++)
            _average += _data[i];
        _average = _average / SIZE;
        
        if (_data[0] > _average)
        {
            _countConsecutiveOverAverage += 1;
        }
        else
        {
            _countConsecutiveOverAverage = 0;
        }
    }
    
    /**
     * 最新の値を取得する
     */
    public function get latestValue():Number
    {
        return _data[0];
    }
    
    /**
     * 履歴の平均値を取得する
     */
    public function get averageValue():Number
    {
        var ret:Number = 0;
        for (var i:int = 0; i < SIZE; i++)
            ret += _data[i];
        return ret / SIZE;
    }
    
    /**
     * 履歴の前半と後半を比べて、急激に値が増加していたらtrueを返す
     * @return
     */
    public function isSteepUp():Boolean
    {
        var i:int;
        var first:Number = 0;
        var last:Number = 0;
        
        for (i = 0; i < SIZE / 2; i++)
        {
            first += _data[SIZE / 2 + i];
            last += _data[i];
        }
        first /= (SIZE / 2);
        last /= (SIZE / 2);
        
        return ((last / first) > 100);
    }
    
    /**
     * 最新の値が平均値以上かどうかを取得できる
     * @return
     */
    public function isLatestValueUpperAverage():Boolean
    {
        return (latestValue > averageValue);
    }

}

/**
 * ...
 * @author ...
 */
class SpectrumData
{
    private var _data:Array;
    private var _soundPosition:int;
    
    //------------------------------------------
    //    getter / setter
    //------------------------------------------
    public function get data():Array
    {
        return _data;
    }
    
    public function get soundPosition():int
    {
        return _soundPosition;
    }
    
    public function SpectrumData(data:Array, soundPosition:int)
    {
        _data = data;
        _soundPosition = soundPosition;
    }

}

/**
 * ...
 * @author ...
 */
class SpectrumFactorRecord
{
    private static const SIZE:int = 60;
    private var _record:Vector.<Number>;
    private var _average:Number;
    private var _latestSoundPosition:int;
    private var _countConsecutiveOverAverage:int = 0;
    
    //--------------------------------------------
    //    getter / setter
    //--------------------------------------------
    public function get average():Number
    {
        return _average;
    }
    
    public function get nowSoundPosition():int
    {
        return _latestSoundPosition;
    }
    
    public function get countConsecutiveOverAverage():int
    {
        return _countConsecutiveOverAverage;
    }
    
    //--------------------------------------------
    //--------------------------------------------
    
    public function SpectrumFactorRecord()
    {
        _record = new Vector.<Number>(SIZE, true);
        for (var i:int = 0; i < SIZE; i++)
            _record[i] = 0;
        
        _latestSoundPosition = 0;
    }
    
    /**
     * 記録を追加する、古いデータは削除される
     * @param    value
     */
    public function addRecord(soundPosition:int, value:Number):void
    {
        var i:int;
        
        for (i = SIZE - 1; i > 0; i--)
        {
            _record[i] = _record[i - 1];
        }
        _record[0] = value;
        
        _latestSoundPosition = soundPosition;
        
        //    平均値計算
        _average = 0;
        for (i = 0; i < SIZE; i++)
            _average += _record[i];
        _average = _average / SIZE;
        
        if (_record[0] > _average)
        {
            _countConsecutiveOverAverage += 1;
        }
        else
        {
            _countConsecutiveOverAverage = 0;
        }
    
    }
    
    /**
     * 最新の記録を取得
     * @return {Number}
     */
    public function getLatestValue():Number
    {
        return _record[0];
    }
    
    /**
     * 最新の値が平均値以上かどうかを取得できる
     * @return
     */
    public function isLatestValueUpperAverage():Boolean
    {
        return (getLatestValue() > _average);
    }

}

/**
 * ...
 * @author okoi
 */
class SimpleMP3Player extends Sprite
{
    public static const WIDTH:int = 450;
    public static const HEIGHT:int = 50;
    
    public static const ANM_NONE:int = 0;
    public static const ANM_FADEIN:int = 1;
    public static const ANM_FADEOUT:int = 2;
    
    private var _bytes:ByteArray;
    private var _fr:FileReference;
    private var _sound:Sound = null;
    private var _soundChannel:SoundChannel = null;
    private var _pausePosition:Number;
    
    private var _loadStartCallback:Function /*():void*/;
    private var _loadEndCallback:Function /*():void*/;
    
    private var _btn_play:Button;
    private var _flg_play:Boolean = false;
    
    private var _btn_load:Button;
    private var _flg_loading:Boolean;
    
    private var _titleBoard:TitleBoard;
    
    private var _animationId:int;
    private var _playerDisp:Boolean;
    
    private var _waveBuffer:Array;
    private var _fftBuffer:Array;
    
    private var _spectrumData:SpectrumData;
    
    //----------------------------------------------------
    //    getter / setter
    //----------------------------------------------------
    public function get waveBuffer():Array
    {
        return _waveBuffer;
    }
    
    public function get fftBuffer():Array
    {
        return _fftBuffer;
    }
    
    public function get spectrumData():SpectrumData
    {
        return _spectrumData;
    }
    
    public function SimpleMP3Player(loadstartcallback:Function, loadendcallback:Function)
    {
        _fr = new FileReference();
        _fr.addEventListener(Event.SELECT, FileSelectHandler);
        _fr.addEventListener(ProgressEvent.PROGRESS, ProgressHandler);
        _fr.addEventListener(Event.COMPLETE, FileLoadCompleteHandler);
        _fr.addEventListener(IOErrorEvent.IO_ERROR, FileLoadIOErrorHandler);
        _fr.addEventListener(SecurityErrorEvent.SECURITY_ERROR, FileLoadSecurityError);
        _flg_loading = false;
        
        _bytes = new ByteArray();
        
        _loadStartCallback = loadstartcallback;
        _loadEndCallback = loadendcallback;
        
        CreateUI();
        
        _animationId = ANM_NONE;
        setPlayerDisplay(true, false);
        
        _waveBuffer = GetSpectrumData(false);
        _fftBuffer = GetSpectrumData(true);
        
        this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }
    
    private function OpenFileSelectDialog():void
    {
        
        var filter:FileFilter = new FileFilter("mp3 file", "*.mp3");
        _fr.browse([filter]);
    }
    
    private function FileSelectHandler(e:Event):void
    {
        _fr.load();
        _flg_loading = true;
        _btn_play.Selectable(false);
        _titleBoard.SetTitle("");
        
        if (_loadStartCallback != null)
            _loadStartCallback();
    }
    
    private function ProgressHandler(e:ProgressEvent):void
    {
    
    }
    
    private function FileLoadCompleteHandler(e:Event):void
    {
        
        _flg_loading = false;
        _pausePosition = 0;
        
        _sound = new Sound();
        _sound.loadCompressedDataFromByteArray(_fr.data, _fr.data.length);
        
        SetTitleBoardText(_fr.name);
        
        resetSoundChannel();
        
        _btn_play.Selectable(true);
        
        _flg_play = true;
        onClickPlayButton();
        
        if (_loadEndCallback != null)
            _loadEndCallback();
    }
    
    private function FileLoadIOErrorHandler(e:IOErrorEvent):void
    {
        _flg_loading = false;
        _sound = null;
        changePlayButton(false);
        _btn_play.Selectable(false);
    }
    
    private function FileLoadSecurityError(e:SecurityErrorEvent):void
    {
        _flg_loading = false;
        _sound = null;
        changePlayButton(false);
        _btn_play.Selectable(false);
    }
    
    private function resetSoundChannel():void
    {
        if (_soundChannel != null)
        {
            _soundChannel.stop();
            _soundChannel.removeEventListener(Event.SOUND_COMPLETE, SoundCompleteHandler);
            _soundChannel = null;
        }
        _titleBoard.SetScrollFlag(false);
    }
    
    /**
     * サウンドの再生、再開を行う
     */
    private function play():void
    {
        if (_sound)
        {
            _soundChannel = _sound.play(_pausePosition);
            _soundChannel.addEventListener(Event.SOUND_COMPLETE, SoundCompleteHandler);
            _pausePosition = 0;
            _titleBoard.SetScrollFlag(true);
            
            var trans:SoundTransform = new SoundTransform(0.5);
            _soundChannel.soundTransform = trans;
        }
    }
    
    /**
     * サウンドの一時停止を行う
     */
    private function pause():void
    {
        if (_soundChannel)
        {
            _pausePosition = _soundChannel.position;
            resetSoundChannel();
        }
    }
    
    private function SoundCompleteHandler(e:Event):void
    {
        _pausePosition = 0;
        resetSoundChannel();
        play();
    }
    
    public function GetSpectrumData(FFTMode:Boolean = false):Array
    {
        var i:int;
        var buf:Array = new Array(512);
        
        if (!_soundChannel)
        {
            for (i = 0; i < 512; i++)
                buf[i] = 0;
            return buf;
        }
        
        SoundMixer.computeSpectrum(_bytes, FFTMode, 0);
        _bytes.position = 0;
        for (i = 0; i < 512; i++)
            buf[i] = _bytes.readFloat();
        return buf;
    }
    
    /**
     * 再生中かどうかを受け取る
     * @return
     */
    public function isPlaying():Boolean
    {
        return _flg_play;
    }
    
    public function enterFrameHandler(e:Event):void
    {
        
        _waveBuffer = GetSpectrumData(false);
        _fftBuffer = GetSpectrumData(true);
        var position:int = 0;
        if (_soundChannel != null)
        {
            position = _soundChannel.position;
        }
        _spectrumData = new SpectrumData(_fftBuffer, position);
        
        //    右クリックアニメーション
        if (_animationId == ANM_FADEIN)
        {
            this.alpha += 0.05;
            if (this.alpha >= 1)
                stopAnimation();
        }
        else if (_animationId == ANM_FADEOUT)
        {
            this.alpha -= 0.05;
            if (this.alpha <= 0)
                stopAnimation();
        }
    
    }
    
    //--------------------------------------------------------------------
    //
    //    アニメーション関連
    //
    //--------------------------------------------------------------------
    /**
     * プレイヤーの表示非表示状態を設定する
     * @param    flag
     */
    public function setPlayerDisplay(flag:Boolean, animation:Boolean = true):void
    {
        _playerDisp = flag;
        
        this.mouseEnabled = flag;
        this.mouseChildren = flag;
        
        if (animation)
            startAnimation((_playerDisp) ? ANM_FADEIN : ANM_FADEOUT);
        else
        {
            stopAnimation();
            if (_playerDisp)
                this.alpha = 1;
            else
                this.alpha = 0;
        }
    }
    
    /**
     *     プレイヤーの表示状態かどうかを受け取る
     *
     * @return
     */
    public function isPlayerDisplay():Boolean
    {
        return _playerDisp;
    }
    
    /**
     * アニメーションの再生を開始する
     * @param    animeId
     */
    public function startAnimation(animeId:int):void
    {
        if (_animationId != ANM_NONE)
            stopAnimation();
        
        _animationId = animeId;
    
    }
    
    /**
     * アニメーションの再生を終了する
     */
    public function stopAnimation():void
    {
        if (_animationId == ANM_FADEIN)
            this.alpha = 1;
        if (_animationId == ANM_FADEOUT)
            this.alpha = 0;
        
        _animationId = ANM_NONE;
    
    }
    
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    private function CreateUI():void
    {
        
        var g:Graphics;
        
        g = graphics;
        
        //    背景
        
        CreatePlayButton();
        CreateLoadButton();
        CreateTitleBoard();
    }
    
    private function CreatePlayButton():void
    {
        
        _btn_play = new Button(58, 18, "play", onClickPlayButton);
        _btn_play.x = -35;
        _btn_play.y = 20;
        _btn_play.Selectable(false);
        addChild(_btn_play);
    }
    
    /**
     * 再生ボタンが押された
     */
    private function onClickPlayButton():void
    {
        
        _flg_play = (_flg_play) ? false : true;
        changePlayButton(_flg_play);
        if (_flg_play)
        {
            play();
        }
        else
        {
            pause();
        }
    }
    
    private function changePlayButton(flg:Boolean):void
    {
        if (flg)
        {
            _btn_play.setLabelText("stop");
        }
        else
        {
            _btn_play.setLabelText("play");
        }
    }
    
    /**
     * 曲ロードボタンを作成
     */
    private function CreateLoadButton():void
    {
        _btn_load = new Button(58, 18, "load", onClickLoadButton);
        _btn_load.x = 35;
        _btn_load.y = 20;
        addChild(_btn_load);
    }
    
    /**
     * 曲ロードボタンが押された
     */
    private function onClickLoadButton():void
    {
        
        if (_flg_loading)
            return;
        
        OpenFileSelectDialog();
    }
    
    private function CreateTitleBoard():void
    {
        
        _titleBoard = new TitleBoard();
        _titleBoard.x = -TitleBoard.WIDTH / 2;
        _titleBoard.y = 40;
        addChild(_titleBoard);
    }
    
    private function SetTitleBoardText(text:String):void
    {
        _titleBoard.SetTitle(text);
    }

}

class TitleBoard extends Sprite
{
    
    public static const WIDTH:int = 300;
    public static const HEIGHT:int = 20;
    
    private var text:TextField;
    private var _mask:Shape;
    private var _flg_scroll:Boolean;
    
    public function TitleBoard()
    {
        
        this.alpha = 0.5;
        
        graphics.lineStyle(1, 0x474a4d);
        graphics.beginFill(0xc0c6c9);
        graphics.drawRect(0, 0, WIDTH, HEIGHT);
        graphics.endFill();
        
        var tf:TextFormat = new TextFormat();
        tf.font = "Arial";
        tf.size = 14;
        tf.color = 0xFFFFFF;
        tf.align = TextFormatAlign.CENTER;
        
        text = new TextField();
        text.autoSize = "left";
        text.selectable = false;
        text.defaultTextFormat = tf;
        text.x = WIDTH / 2;
        addChild(text);
        
        _mask = new Shape();
        _mask.graphics.beginFill(0);
        _mask.graphics.drawRect(0, 0, WIDTH, HEIGHT);
        _mask.graphics.endFill();
        this.mask = _mask;
        addChild(_mask);
        
        _flg_scroll = false;
        
        addEventListener(Event.ENTER_FRAME, EnterFrameHandler);
    }
    
    public function SetTitle(title:String):void
    {
        text.text = title;
        text.x = WIDTH / 2 - text.textWidth / 2;
    }
    
    private function EnterFrameHandler(e:Event):void
    {
        
        //if ( text.textWidth >= WIDTH ) {
        if (_flg_scroll)
        {
            text.x -= 1;
            if (text.x < -text.textWidth)
            {
                text.x = WIDTH;
            }
        }
    }
    
    public function SetScrollFlag(flg:Boolean):void
    {
        _flg_scroll = flg;
    }

}

/**
 * 汎用ボタンクラス
 * @author okoi
 */
class Button extends Sprite
{
    private var label:TextField;
    private var _onclick:Function /*():void*/ = null;
    private var _width:Number;
    private var _height:Number;
    private var _selectable:Boolean;
    
    public function Button(w:Number, h:Number, text:String, onclick:Function)
    {
        
        graphics.lineStyle(1, 0x474a4d);
        graphics.beginFill(0x2b2b2b);
        graphics.drawRect(-w / 2, -h / 2, w, h);
        graphics.endFill();
        
        _width = w;
        _height = h;
        
        var tf:TextFormat = new TextFormat();
        tf.font = "Arial";
        tf.size = 12;
        tf.color = 0xFFFFFF;
        tf.align = TextFormatAlign.CENTER;
        
        label = new TextField();
        label.mouseEnabled = false;
        label.autoSize = "center";
        label.multiline = false;
        label.defaultTextFormat = tf;
        label.selectable = false;
        label.text = text;
        label.x = -w / 2;
        label.y = -h / 2;
        label.width = w;
        label.height = h;
        addChild(label);
        
        this._onclick = onclick;
        
        this.buttonMode = true;
        this.addEventListener(MouseEvent.MOUSE_DOWN, MouseDownHandler);
    }
    
    private function MouseDownHandler(e:MouseEvent):void
    {
        
        this.removeEventListener(MouseEvent.MOUSE_DOWN, MouseDownHandler);
        
        this.addEventListener(MouseEvent.MOUSE_UP, MouseUpHandler);
        this.addEventListener(MouseEvent.ROLL_OUT, RollOutHandler);
        
        ChangeColor(true);
    }
    
    private function MouseUpHandler(e:MouseEvent):void
    {
        
        this.removeEventListener(MouseEvent.MOUSE_UP, MouseUpHandler);
        this.removeEventListener(MouseEvent.ROLL_OUT, RollOutHandler);
        
        this.addEventListener(MouseEvent.MOUSE_DOWN, MouseDownHandler);
        
        ChangeColor(false);
        if (_onclick != null)
        {
            _onclick();
        }
    }
    
    private function RollOutHandler(e:MouseEvent):void
    {
        
        this.removeEventListener(MouseEvent.MOUSE_UP, MouseUpHandler);
        this.removeEventListener(MouseEvent.ROLL_OUT, RollOutHandler);
        
        this.addEventListener(MouseEvent.MOUSE_DOWN, MouseDownHandler);
        
        ChangeColor(false);
    }
    
    private function ChangeColor(press:Boolean):void
    {
        graphics.clear();
        graphics.lineStyle(1, 0x474a4d);
        if (press)
        {
            graphics.beginFill(0x727171);
        }
        else
        {
            graphics.beginFill(0x2b2b2b);
        }
        graphics.drawRect(-_width / 2, -_height / 2, _width, _height);
        graphics.endFill();
    }
    
    public function setLabelText(text:String):void
    {
        label.text = text;
    }
    
    public function Selectable(flg:Boolean):void
    {
        _selectable = flg;
        
        this.mouseChildren = flg;
        this.mouseEnabled = flg;
        if (!flg)
        {
            ChangeColor(false);
            this.alpha = 0.5;
        }
        else
        {
            this.alpha = 1;
        }
    }

}

/**
 * ...
 * @author okoi
 */
class ProgressBar extends Sprite
{
    private var _mask:Shape;
    private var text:TextField;
    private var ct:int;
    
    private static const PARTICLE_LIFE:int = 60;
    private var particleList: /*Object*/Array;
    
    private var _rate:Number = 0;
    
    public function ProgressBar()
    {
        ct = 0;
        particleList = [];
        
        var format:TextFormat = new TextFormat();
        format.font = "Arial";
        format.bold = true;
        format.color = 0xFFFFFF;
        
        text = new TextField();
        text.defaultTextFormat = format;
        text.text = "LOADING";
        text.selectable = false;
        text.x = -text.textWidth / 2;
        text.y = -text.textHeight / 2;
        
        addChild(text);
        
        _mask = new Shape();
        _mask.graphics.beginFill(0);
        _mask.graphics.drawRect(-100, -25, 200, 50);
        _mask.graphics.endFill();
        this.mask = _mask;
        addChild(_mask);
        
        addEventListener(Event.ENTER_FRAME, EnterFrameHandler);
    }
    
    public function Destroy():void
    {
        removeEventListener(Event.ENTER_FRAME, EnterFrameHandler);
    }
    
    private function EnterFrameHandler(e:Event):void
    {
        
        var g:Graphics = graphics;
        g.clear();
        
        if (int(Math.random() * 10) == 0)
            AddParticle();
        
        for (var i:int = particleList.length - 1; i >= 0; i--)
        {
            g.lineStyle(2, 0xFFFFFF, 0.5 - (1 - particleList[i].life / PARTICLE_LIFE) * 0.5);
            particleList[i].y += particleList[i].vy;
            particleList[i].life -= 1;
            g.drawCircle(particleList[i].x, particleList[i].y, particleList[i].radius);
            
            if (particleList[i].life == 0)
            {
                particleList.splice(i, 1);
            }
        }
        
        if (ct % 4 == 0)
            text.alpha = 0;
        else
            text.alpha = 0.5;
        
        ct++;
    }
    
    private function AddParticle():void
    {
        var particle:Object = new Object();
        particle.x = Math.random() * 100 - 50;
        particle.y = 35;
        particle.radius = Math.random() * 5 + 5;
        particle.vy = (Math.random() * 1 + 0.5) * -1;
        particle.life = PARTICLE_LIFE;
        
        particleList.push(particle);
    }
    
    public function set rate(val:Number):void
    {
        _rate = val;
    }
}