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

[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やニコニコ動画が裏で流れていると失敗します
Get Adobe Flash player
by alumican_net 27 Aug 2009
/**
 * Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/t1m3
 */

/**
 * 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.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.module.SiOPMSamplerData;
	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
		{
			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 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);
			
			/*
			_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);
			g.beginFill(0x000000);
			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();
		}
	}
}