/** * 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(); } } } [Prototyping] Resampled Spectrums with SiON Effector