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

forked from: Simple spectrum analyzer (SiON FFT module + FP10.1 microphone)

Mashed:
forked
and
http://wonderfl.net/c/wpbB
/**
 * Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/qGdx
 */

/**
 * SoundMixer.computeSpectrum の第3引数 stretchFactor
 * による波形への影響を調べています
 * 
 * stretchFactor = 
 *  0  1  2  3
 *  4  5  6  7
 *  8  9 10 11
 * 12 13 14 15
 * 
 * インタラクションはステージ上クリックによるFFTModeの切り替えのみ
 * 
 * computeSpectrumメソッドを使っているため、
 * Youtubeやニコニコ動画が裏で流れていると失敗します
 */

package 
{
    import flash.display.Sprite
    
    public class EffectableClient extends Sprite
    {
        public function EffectableClient() 
        {
            addChild(new Effectable)
        }
    }
}
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.GraphicsPathCommand;
    import flash.display.GraphicsPathWinding;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.media.SoundMixer;
    import flash.net.URLRequest;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.utils.ByteArray;
    import org.si.utils.FFT;
    import frocessing.color.ColorLerp;
    
    class Effectable extends Sprite
    {
        //----------------------------------------
        //CLASS CONSTANT
        
        private const SOUND_SAMPLING_RATE:Number = 44.1;
        private const SOUND_BUFFER_LENGTH:Number = 2048;
        
        private const W:uint = 465;
        private const H:uint = 465;
        
        private const PI:Number  = Math.PI;
        private const PI2:Number = PI * 2;
        
        
        
        
        
        //----------------------------------------
        //VARIABLES
        
        private var _spectrums:Vector.<Number>;
        
        private var _dynamicSound:Sound;
        
        private var _soundBytes:ByteArray;
        private var _soundBytesPosition:uint;
        private var _soundBytesTotal:uint;
        
        private var _verts:Vector.<Vector.<Number>>;
        private var _waves:Vector.<Sprite>;
        
        private var _useFFTMode:Boolean=true;
        
        private var _field:TextField;
        
        private var voicePrint:BitmapData = new BitmapData(465, 256, false, 0);
        
        
        
        
        //----------------------------------------
        //STAGE INSTANCES
        
        
        
        
        
        //----------------------------------------
        //METHODS
        
        /**
         * Constructor.
         */
        public function Effectable():void
        {
            if (stage) 
            {
                init(null);
            }
            else
            {
                addEventListener(Event.ADDED_TO_STAGE, init);
            }
        }
        
        private function init(e:Event):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            _initFFT();
            addChild(new Bitmap(voicePrint)).y = 100;
            var n:uint = 16;
            var d:uint = Math.sqrt(n);
            _waves = new Vector.<Sprite>(n, true);
            _verts = new Vector.<Vector.<Number>>(n, true);
            for (var i:uint = 0; i < n; ++i) 
            {
                var wave:Sprite = addChild( new Sprite() ) as Sprite;
                wave.x = int(i % d) * (W / d) + W / d / 2;
                wave.y = int(i / d) * (H / d) + H / d / 2;
                _waves[i] = wave;
                
                _verts[i] = new Vector.<Number>(256, true);
                for (var j:uint = 0; j < 256; ++j) _verts[i][j] = 0;
            }
            
            _spectrums = new Vector.<Number>(512, true);
            
            _field = addChild( new TextField() ) as TextField;
            _field.x = 2;
            _field.y = 2;
            _field.width  = W;
            _field.height = H;
            _field.defaultTextFormat = new TextFormat("MS GOTHIC, _ゴシック", 12);
            _field.selectable = false;
            _field.text = "loading sound...";
            _field.visible = false;
            //stage.addEventListener(MouseEvent.MOUSE_UP, _stageMouseUpHandler);
            
            _loadSound();
        }
        
        private function _stageMouseUpHandler(e:MouseEvent = null):void 
        {
            _useFFTMode = !_useFFTMode;
            _field.text = (_useFFTMode) ? "fft (click stage to change fft mode)" :
                                          "raw (click stage to change fft mode)" ;
        }
        
        private function _loadSound():void
        {
        //    var base:String = "assets/";
            var base:String = "http://lab.alumican.net/wonderfl/effectable/";
            
            var sound:Sound = new Sound();
        //    sound.load( new URLRequest(base + "bit158-2.mp3") );
            sound.load( new URLRequest(base + "bit184-1.mp3") );
        //    sound.load( new URLRequest(base + "bit187-1.mp3") );
            sound.addEventListener(Event.COMPLETE, _loadSoundCompleteHandler);
        }
        
        private function _loadSoundCompleteHandler(e:Event):void 
        {
            _soundBytes = new ByteArray();
            
            var sound:Sound = e.currentTarget as Sound;
            sound.removeEventListener(Event.COMPLETE, _loadSoundCompleteHandler);
            sound.extract(_soundBytes, sound.length * SOUND_SAMPLING_RATE * 8);
            
            _soundBytesTotal    = _soundBytes.length;
            _soundBytesPosition = 0;
            
            _dynamicSound = new Sound();
            _dynamicSound.addEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
            _dynamicSound.play();
            
            _useFFTMode = false;
            _stageMouseUpHandler();
            
            addEventListener(Event.ENTER_FRAME, _update);
        }
        
        private function _update(e:Event):void 
        {
            var n:uint = _waves.length;
            for (var i:uint = 0; i < n; ++i) _getSpectrums(i);
        }
        
        private function _drawWave(index:uint):void
        {
            _getSpectrums(index);
            
            var verts:Vector.<Number> = _verts[index];
            
            var commands:Vector.<int>    = new Vector.<int>();
            var vertices:Vector.<Number> = new Vector.<Number>();
            var angle:Number  = 0;
            var radius:Number = 20;
            var n:uint = _spectrums.length / 2;
            for (var i:uint = 0; i < n; ++i) 
            {
                verts[i] += ( (_useFFTMode ? Math.sqrt(_spectrums[i]) : _spectrums[i]) * radius - verts[i]) *  0.3;
                
                var r:Number = radius + verts[i];
                
                angle = i * PI2 / n;
                var x:Number = r * Math.cos(angle);
                var y:Number = r * Math.sin(angle);
                vertices.push(x, y);
                commands.push(GraphicsPathCommand.LINE_TO);
            }
            commands[0] = GraphicsPathCommand.MOVE_TO;
            commands.push(GraphicsPathCommand.LINE_TO);
            vertices.push(vertices[0], vertices[1]);
            
            var g:Graphics = _waves[index].graphics;
            g.clear();
            g.lineStyle(0, 0x000000, 0);
            g.beginFill(0x000000);
            g.drawPath(commands, vertices, GraphicsPathWinding.EVEN_ODD);
            g.endFill();
        }
        
        private function _soundSampleDataHandler(e:SampleDataEvent):void 
        {
            for (var i:uint = 0; i < SOUND_BUFFER_LENGTH; ++i) 
            {
                _soundBytesPosition += 8;
                if      (_soundBytesPosition > _soundBytesTotal - 8) _soundBytesPosition -= _soundBytesTotal;
                else if (_soundBytesPosition <  7                  ) _soundBytesPosition += _soundBytesTotal;
                _soundBytes.position = _soundBytesPosition;
                e.data.writeFloat( _soundBytes.readFloat() / 2 );
                e.data.writeFloat( _soundBytes.readFloat() / 2 );
            }
            for (e.data.position=0; e.data.bytesAvailable>0;) {
                _execFFT(e.data);
                _updateImage();
            }        }
        
        private function _getSpectrums(stretchFactor:uint = 0):void
        {
            var bytes:ByteArray = new ByteArray();
            SoundMixer.computeSpectrum(bytes, _useFFTMode, stretchFactor);
            for (var i:uint = 0; i < 512; ++i) _spectrums[i] = bytes.readFloat();
        }
        
        
        private function _updateImage() : void {
            voicePrint.scroll(-4, 0);
            for (var i:int=0; i < 256; i++) {
                voicePrint.setPixel(461, 255-i, grad[frm[3][i]]);
                voicePrint.setPixel(462, 255-i, grad[frm[2][i]]);
                voicePrint.setPixel(463, 255-i, grad[frm[1][i]]);
                voicePrint.setPixel(464, 255-i, grad[frm[0][i]]);
            }
        }
        
        private var src:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(4);
        private var dst:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(4);
        private var amp:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(4);
        private var frm:Vector.<Vector.<int>> = new Vector.<Vector.<int>>(4);
        private var hamm:Vector.<Number> = new Vector.<Number>(2048);
        private var fft:FFT = new FFT(2048);
        private var grad:Array, scale:Number;
        private function _initFFT() : void {
            var i:int;
            for (i=0; i<4; i++) {
                src[i] = new Vector.<Number>(2048);
                dst[i] = new Vector.<Number>(2048);
                amp[i] = new Vector.<Number>(1024);
                frm[i] = new Vector.<int>(256);
            }
            for (i=0; i<2048; i++) hamm[i]=0.54-Math.cos(i*0.00306796)*0.46;
            ColorLerp.mode = "hsv";
            grad = ColorLerp.gradient(0x000040, 0xff0000, 256);
            scale = 25;
        }
        private function _execFFT(data:ByteArray) : void {
            var index:int, i:int, j:int, n:Number, 
                f:Vector.<int>, a:Vector.<Number>,
                s0:Vector.<Number> = src[0],
                s1:Vector.<Number> = src[1],
                s2:Vector.<Number> = src[2],
                s3:Vector.<Number> = src[3];
            for (index=3; index>=0; --index) {
                for (i=0; i<512; i++) {
                    n = data.readFloat();
                    j = i;     s0[j] = n * hamm[j];
                    j += 512;  s1[j] = n * hamm[j];
                    j += 512;  s2[j] = n * hamm[j];
                    j += 512;  s3[j] = n * hamm[j];
                }
                a = amp[index];
                f = frm[index];
                fft.setData(s3).calcDCT().getMagnitude(a)
                for (i=0; i<256; i++) { // from 86Hz to 5.6kHz
                    n = Math.log(a[i+4]*scale);
                    f[i] = int(((n<0) ? 0 : (n>1) ? 1 : n) * 255);
                }
                s3 = s2;
                s2 = s1;
                s1 = s0;
                s0 = src[index];
            }
        }
    }