FF: [Prototyping] Resampled Spectrums with SiON Effector

by WLAD forked from [Prototyping] Resampled Spectrums with SiON Effector (diff: 20)
SoundMixer.computeSpectrum の第3引数 stretchFactor
による波形への影響を調べています

SiONライブラリの中からイコライザーをくっつけてみました
コードには試行錯誤の跡
なんかブツブツいっとるし、あとで直す

stretchFactor = 
0  1  2  3
4  5  6  7
8  9 10 11
12 13 14 15

インタラクションはステージ上クリックによるFFTModeの切り替えと、
マウス位置によるエフェクトのかかり具合

computeSpectrumメソッドを使っているため、
Youtubeやニコニコ動画が裏で流れていると失敗します
♥0 | Line 188 | Modified 2015-12-30 01:47:18 | MIT License
play

ActionScript3 source code

/**
 * Copyright WLAD ( http://wonderfl.net/user/WLAD )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/I0zj
 */

// forked from alumican_net's [Prototyping] Resampled Spectrums with SiON Effector
/**
 * SoundMixer.computeSpectrum の第3引数 stretchFactor
 * による波形への影響を調べています
 * 
 * SiONライブラリの中からイコライザーをくっつけてみました
 * コードには試行錯誤の跡
 * なんかブツブツいっとるし、あとで直す
 * 
 * stretchFactor = 
 *  0  1  2  3
 *  4  5  6  7
 *  8  9 10 11
 * 12 13 14 15
 * 
 * インタラクションはステージ上クリックによるFFTModeの切り替えと、
 * マウス位置によるエフェクトのかかり具合
 * 
 * computeSpectrumメソッドを使っているため、
 * Youtubeやニコニコ動画が裏で流れていると失敗します
 */
package 
{
    import flash.display.Graphics;
    import flash.display.GraphicsPathCommand;
    import flash.display.GraphicsPathWinding;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.system.Security;
    import flash.events.MouseEvent;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.media.SoundMixer;
    import flash.net.URLRequest;
    import flash.system.System;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.utils.ByteArray;
    import org.si.sion.utils.SiONUtil;
    
    import org.si.sion.SiONData;
    import org.si.sion.SiONDriver;
    import org.si.sion.effector.*;
    
    public 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:int;
        private var _soundBytesTotal:uint;
        
        private var _verts:Vector.<Vector.<Number>>;
        private var _waves:Vector.<Sprite>;
        
        private var _useFFTMode:Boolean;
        
        private var _field:TextField;
        
        //SiON
        //private var _driver:SiONDriver;
        //private var _track:SiOPMSamplerData;
        private var _effectors:Vector.<SiEffectBase>;
        
        private var _buffer:Vector.<Number>;
        private var _original:Vector.<Number>;
        
        
        
        //----------------------------------------
        //STAGE INSTANCES
        
        
        
        
        
        //----------------------------------------
        //METHODS
        
        /**
         * Constructor.
         */
        public function Effectable():void
        {
            this.graphics.beginFill(0);
            this.graphics.drawRect(0,0,W,H);
            
            init();
        }
        
        public function init():void
        {
            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.wordWrap = true;
            _field.defaultTextFormat = new TextFormat("MS GOTHIC, _ゴシック", 12);
            _field.selectable = false;
            _field.text = "loading sound...";
            
            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 var sound:Sound;
        
        private function _loadSound():void
        {
            Wonderfl.capture_delay(15);
            Security.loadPolicyFile("http://mutast.heteml.jp/crossdomain.xml");
            sound = new Sound();
            sound.load( new URLRequest("http://mutast.heteml.jp/works/music/music.mp3") );
            sound.addEventListener(Event.COMPLETE, _loadSoundCompleteHandler);
        }
        
        private function _loadSoundCompleteHandler(e:Event):void 
        {
            _soundBytes = new ByteArray();
            
            sound.removeEventListener(Event.COMPLETE, _loadSoundCompleteHandler);
            
            /*
            _driver = new SiONDriver(SOUND_BUFFER_LENGTH, 2, SOUND_SAMPLING_RATE, 0);
            _track  = _driver.setSamplerSound(0, sound, false, 2);
            _driver.play(_track, false);
            */
            
            _buffer = SiONUtil.extract(sound, null, 2, 1048576);
            
            _soundBytesTotal    = _buffer.length;
            _soundBytesPosition = 0;
            
            _original = new Vector.<Number>();
            _original = _original.concat(
                _buffer.slice(_buffer.length - SOUND_BUFFER_LENGTH * 2, _buffer.length),
                _buffer,
                _buffer.slice(0, SOUND_BUFFER_LENGTH * 2)
            );
            
            _soundBytesTotal    = _buffer.length;
            _soundBytesPosition = 0;
            
            _setEffectors();
            
            _dynamicSound = new Sound();
            _dynamicSound.addEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
            _dynamicSound.play();
            
            _useFFTMode = false;
            _stageMouseUpHandler();
            
            addEventListener(Event.ENTER_FRAME, _update);
            //stage.addEventListener(MouseEvent.MOUSE_MOVE, _stageMouseMoveHandler);
        }
        
        private function _setEffectors():void
        {
            _effectors = new Vector.<SiEffectBase>();
            
            var effectA:SiEffectEqualiser = new SiEffectEqualiser();
            effectA.initialize();
            effectA.prepareProcess();
            _effectors.push(effectA);
            
            var effectB:SiEffectStereoDelay = new SiEffectStereoDelay();
            effectB.initialize();
            effectB.prepareProcess();
            _effectors.push(effectB);
        }
        
        /*
        private function _stageMouseMoveHandler(e:MouseEvent):void 
        {
            _buffer = _original.concat();
            
            var x:Number =     mouseX / W;
            var y:Number = 1 - mouseY / H;
            
            var effectA:SiEffectEqualiser = _effectors[0] as SiEffectEqualiser;
            effectA.setParameters(x, x, 1 - x, 880 + 2000 * x, 5000 - 2000 * x);
            effectA.prepareProcess();
            effectA.process(2, _buffer, 0, _buffer.length / 2);
            
            var effectB:SiEffectStereoReverb = _effectors[1] as SiEffectStereoReverb;
            effectB.prepareProcess();
            effectB.process(2, _buffer, 0, _buffer.length / 2);
        }
        */
        
        private function _update(e:Event):void 
        {
            var n:uint = _waves.length;
            for (var i:uint = 0; i < n; ++i) _drawWave(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);
            var c:uint = ( (index+1) / 17 ) * 0x0000FF;
            c = c | ( (( (index+1) / 17 ) * 0x0000FF ) << 4 );
            c = c | ( (( (index+1) / 17 ) * 0x0000FF ) << 8 );
            g.beginFill( c );
            g.drawPath(commands, vertices, GraphicsPathWinding.EVEN_ODD);
            g.endFill();
        }
        
        private function _soundSampleDataHandler(e:SampleDataEvent):void 
        {
            var x:Number = mouseX / W;
            var y:Number = mouseY / H;
            
            _buffer = _original.slice(SOUND_BUFFER_LENGTH * 2 + _soundBytesPosition, _soundBytesPosition + SOUND_BUFFER_LENGTH * 4);
            
            var effectA:SiEffectEqualiser = _effectors[0] as SiEffectEqualiser;
            effectA.setParameters(1 - x, 1 - x, x, 880 + 1000 * y, 5000 - 3000 * y);
            effectA.prepareProcess();
            effectA.process(2, _buffer, 0, SOUND_BUFFER_LENGTH / 2);
            
            var p:uint = 0;
            for (var i:uint = 0; i < SOUND_BUFFER_LENGTH; ++i) 
            {
                e.data.writeFloat( _buffer[p++] );
                e.data.writeFloat( _buffer[p++] );
            }
            
            _soundBytesPosition += SOUND_BUFFER_LENGTH * 2;
            if (_soundBytesPosition + SOUND_BUFFER_LENGTH * 2 >= _soundBytesTotal) _soundBytesPosition -= _soundBytesTotal;
        }
        
        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();
        }
    }
}