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

【解説】 Sound Star

Get Adobe Flash player
by yd_niku 20 Jul 2010
/**
 * Copyright yd_niku ( http://wonderfl.net/user/yd_niku )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/zmMI
 */

package  
{
    public class soundSpectrum extends F5MovieClip2DBmp
    {
        public function setup():void{
            size( 465, 465 );
            //背景の描画
            background( 0 );
            //HSVカラーモードセット
            colorMode( HSV, 1 );
            
            stage.addEventListener(MouseEvent.CLICK, FFTswitcher);
            
            Wonderfl.capture_delay( 15 );
            
            //パーティクル用の入れ物を準備
            _particles = new Vector.<Star>();//Starクラスしか入らない配列
            
            //音開始
            playSound("http://www.takasumi-nagai.com/soundfiles/sound001.mp3");
        }
        
        private var _angleY:Number = 0;
        private var _angleC:Number = 0;
        public function draw():void{
            
            //色相環0-360°変化させる
            _angleC++;
            $color.hsv(_angleC%360,1,0.2+(_angleC%240)/240*0.8);
            
            //半透明(0.9)で全画面塗る=前の描画がちょっと残る
            beginFill($color.value,0.9); 
            drawRect(0,0,465,465);
            endFill();
            
            //全体の放射角を回転させ(0-360) 三角関数で向き(x, y)を決定
            _angleY+=6;
            var aX:Number  = Math.cos(_angleY/180*Math.PI);
            var aY:Number  = Math.sin(_angleY/180*Math.PI);
            
            // 音の解析データをバイナリに転写
            var bytes:ByteArray = new ByteArray();
            SoundMixer.computeSpectrum(bytes, FFTswitch, 0);
            /*
            bytesには左右チャンネル各256諧調でサンプリングされます。
            
            これをbytes.readFloat();で1bytesずつ読みだして行きます。(Array.shift的なメソッドで順繰りに読みだせる。)
            rfには FFTがONで 0-1, FFTがOFFで-1 - 1の範囲で各周波数帯域の出力が読みだされます。(FFTだと1.414まで行くかも?)
            ちなみにFFTは高速フーリエ変換の略で、要するにEQみたいに波を周波数帯域別に分解してくれる変換関数。
            FFTじゃない場合は並べると合成された波の形になります。see:http://wonderfl.net/c/dllp
             * bytesイメージ = [ 左 0------------256 右 0-------------256 ]
            
            この値が音のデータとなりますので、これをもとに絵を作っていきます。
            今回の場合はパーティクルというデータにいったん変換して、それを計算結果を描画に利用してます
            音量レベルに応じてパーティクルの勢い(初速:p.vx/p.vy)と質量(p.mass)きめて生成し、あとは勢いがなくなるまで加速度運動します。
            
            また512バンドすべてをパーティクルにすると大変な数になるので
            36バンドに一個、かつ各ユニット(36バンド)の合算したレベルが2より大きければパーティクル1個生成します。
            つまりそのフレームの発音の音域がひろければたくさんパーティクルが跳びます。
            
            このループではパーティクル(Star)クラスの生成と初期値の設定のみ行います。
            */
            
            // DEF_CNTバンドごとにlevをリセットするためのcntをそれぞれリセット
            const DEF_CNT:Number = 36;
            var cnt:Number = DEF_CNT;
            var lev:Number = 0;
            
            var i:uint, j:uint;
            for (i = 0; i < 2; i++){//左右
                for (j = 0; j < 256; j++){//各256バンド
                    var rf:Number = bytes.readFloat();
                    
                    /**
                    * ★ようはこの rfの値を 大きさや色などの ビジュアルに対応させることでビジュアライザができます。
                    */
                    
                    if (cnt-->0) lev += rf;//cntが0でなければ合算し続ける
                    else {
                        if( lev > 2 ) {
                            var p:Star = new Star();
                            //放出の勢い
                            var r:Number = random(lev,0.2);
                            p.x = 232;
                            p.y = 232;
                            //質量
                            p.mass = lev/5;
                            //初速
                            p.vx = lev/3+aX*r;//重いほど勢いがある
                            p.vy = Math.random()*lev/6+aY*r/2;//重いほどい勢いがあるがランダム
                            //配列に格納。
                            _particles.push(p);
                        }
                        //リセットして次のバンドへ。
                        cnt = DEF_CNT; lev = 0; 
                    }
                }
            }
            
            /*
            次に今保持してるパーティクルを演算して描画します。
            パーティクルは枚フレームp.lifeを減らしていき 特定の時間が過ぎると削除されます。(減衰効果)
            
            すべてのパーティクルの位置を更新して、結果を描画していきます。
            */
            for(var k:int=_particles.length-1; k>=0; k-- ){
                var s:Star = _particles[k];
                if(s.life<=0) {
                    //減衰仕切ったら配列から削除
                    _particles.splice(i,1);
                    continue;//このセクションは飛ばして次のパーティクルへ
                }
           /**
            * パーティクルの更新
            */
                // 速度を反映
                // s.yに重力(+0.5)と、lifeをもとにしたサイン波で微妙な揺らぎを加えてます
                s.x += s.vx;
                s.y += s.vy + Math.sin((s.life%360)/180*Math.PI)+0.5;
                s.life--;
                
           /**
            * 円を描画
            */
                // red, green, blue, alphaで描画する線の色と濃さを指定して円を書きます
                // 円は質量に応じて最大半径が大きくなります。(ランダムでチラチラさせてますが)
                stroke(0,0,1,(s.life-80)/80);
                drawCircle( s.x, s.y, 3*s.mass*Math.random() );
                
           /**
            * 円と同じ位置に星を描画
            */
                // 線の設定をキャンセル
                noStroke();
                //塗りの色と濃さ(ls.ifeによる)指定
                beginFill(0xFFFFFF,(s.life-80)/80);
                // 星の外周の半径と5角形の一遍の角度をあらかじめ計算
                var sradius:Number = random(6,0.1)*s.mass, ssradius:Number, partAngle:Number = Math.PI*2/10;
                // 星の角度
                var offset:Number = random(Math.PI);
                
                // 星の各頂点を計算するようの変数
                var ssx:Number, ssy:Number;
                //各頂点の描画
                for(var t:int=0; t<10;++t){
                    ssradius = (t%2==0?0.35:1)*sradius;//内円と外円の半径を交互に決定
                    ssx = s.x+Math.sin(partAngle*t+offset)*ssradius;
                    ssy = s.y+Math.cos(partAngle*t+offset)*ssradius;
                    if(t==0) moveTo( ssx, ssy );
                    lineTo( ssx, ssy ); 
                }
                endFill();//星の描画おわり
            }
        }
    
        private function playSound(sndUrl:String):void
        {
            snd = new Sound();
            var context:SoundLoaderContext = new SoundLoaderContext(10,true);
            var req:URLRequest = new URLRequest(sndUrl);
            snd.load(req, context);
            var sndChannel:SoundChannel=new SoundChannel();
            sndChannel = snd.play(0, 5);
            
        }
        
        private function FFTswitcher(e:MouseEvent):void 
        {
            if (FFTswitch) { FFTswitch = false; } else { FFTswitch = true;}
        }
            
        private var _particles:Vector.<Star>;
        private var snd:Sound;
        private var FFTswitch:Boolean = false;
        private var $color:ColorHSV = new ColorHSV();
        //private var fil:Array = [];
    }
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.*;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.media.SoundLoaderContext;
    import flash.media.SoundMixer;
    import flash.net.URLRequest;
    import flash.utils.ByteArray;
    
    //import flash.filters.BlurFilter;
    import frocessing.display.F5MovieClip2DBmp;
    import frocessing.color.*;
    [SWF(width=465,height=465,backgroundColor=0x0)]
}
class Star{
    public var x:Number = 0;
    public var y:Number = 0;
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var life:Number = 240;
    public var mass:Number = 1;
}