forked from: [Prototyping] Microphone Study #03 リング変調

by windy forked from [Prototyping] Microphone Study #03 リング変調 (diff: 1)
リング変調でボイスチェンジャーもどき

@author Yukiya Okuda
♥0 | Line 145 | Modified 2011-04-12 22:36:03 | MIT License
play

ActionScript3 source code

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

// forked from alumican_net's [Prototyping] Microphone Study #03 リング変調
package
{
    import com.bit101.components.CheckBox;
    import com.bit101.components.HUISlider;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.SampleDataEvent;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Microphone;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    
    /**
     * リング変調でボイスチェンジャーもどき
     * 
     * @author Yukiya Okuda
     */
    public class Main extends Sprite
    {
        //----------------------------------------
        //CLASS CONSTANTS
        
        private const ZEROS:Point = new Point();
        
        
        
        
        //----------------------------------------
        //VARIABLES
        
        /**
         * マイクロフォン
         */
        private var _mic:Microphone;
        
        /**
         * 録音用
         */
        private var _records:Vector.<Number>;
        
        /**
         * 再生用
         */
        private var _sound:Sound;
        private var _soundChannel:SoundChannel;
        
        /**
         * 録音、再生ヘッダ
         */
        private var _position:int;
        
        /**
         * 描画用
         */
        private var _canvas:BitmapData;
        private var _slit:BitmapData;
        private var _over:Sprite;
        
        /**
         * リング変調用
         */
        private var _sample:int;
        private var _power:Number;
        private var _freq1:Number;
        private var _freq2:Number;
        private var _useDual:Boolean;
        
        
        
        //----------------------------------------
        //STAGE INSTANCES
        
        
        
        
        
        //----------------------------------------
        //METHODS
        
        /**
         * コンストラクタ
         */
        public function Main():void
        {
            Wonderfl.disable_capture();
            
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.quality = StageQuality.LOW;
            
            _mic = Microphone.getMicrophone();
            _mic.rate = 44;
            _mic.setSilenceLevel(0);
            _mic.setUseEchoSuppression(true);
            
            _sound = new Sound();
            
            _canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xffffff);
            _slit = new BitmapData(1, stage.stageHeight, false, 0xffffff);
            addChild( new Bitmap(_canvas) );
            
            _over = addChild( new Sprite() ) as Sprite;
            _over.graphics.beginFill(0x0);
            _over.graphics.drawRect(0, 0, 100, 100);
            _over.graphics.endFill();
            _over.blendMode = BlendMode.INVERT;
            
            var freq1Slider:HUISlider = new HUISlider(this, 10, 10, "FREQUENCY 1", function(e:Event):void
            {
                _freq1 = int( e.currentTarget.value );
            });
            freq1Slider.minimum = 100;
            freq1Slider.maximum = 500;
            freq1Slider.value   = _freq1 = 300;
            
            var freq2Slider:HUISlider = new HUISlider(this, 10, 30, "FREQUENCY 2", function(e:Event):void
            {
                _freq2 = int( e.currentTarget.value );
            });
            freq2Slider.minimum = 500;
            freq2Slider.maximum = 900;
            freq2Slider.value   = _freq2 = 700;
            
            var checkbox:CheckBox = new CheckBox(this, 200, 15, "USE ONLY FREQUENCY 1", function(e:Event):void
            {
                _useDual = !Boolean( e.currentTarget.selected );
            });
            _useDual = !(checkbox.selected = false);
            
            _startRecord();
        }
        
        /**
         * 録音開始
         */
        private function _startRecord():void
        {
            trace("_startRecord");
            
            _over.width = 0;
            
            _position = 0;
            _records = new Vector.<Number>(44100 * 5);
            _mic.addEventListener(SampleDataEvent.SAMPLE_DATA, _micSampleDataHandler);
        }
        
        private function _micSampleDataHandler(e:SampleDataEvent):void
        {
            var sw:int = stage.stageWidth;
            var sh:int = stage.stageHeight;
            
            var datas:ByteArray = e.data;
            
            while (datas.bytesAvailable)
            {
                var data:Number = _records[_position] = datas.readFloat();
                
                if (_position % 3 == 0)
                {
                    var x:Number = _position / _records.length * sw;
                    var y:Number = sh * 0.5 - data * 1000;
                    _canvas.copyPixels(_slit, _slit.rect, new Point(x + 1, 0));
                    _canvas.setPixel(x, y, 0x0);
                }
                
                if (++_position == _records.length)
                {
                    _mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, _micSampleDataHandler);
                    _startSound();
                    return;
                }
            }
        }
        
        /**
         * 再生開始
         */
        private function _startSound():void
        {
            trace("_startSound");
            
            //リング変調
            _power = 6;
            _sample = 0;
            
            _position = 0;
            _sound.addEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
            _soundChannel = _sound.play();
        }
        
        private function _soundSampleDataHandler(e:SampleDataEvent):void
        {
            _over.width = stage.stageWidth * (_position / _records.length);
            _over.height = stage.stageHeight;
            
            for (var i:int = 0; i < 2048; ++i)
            {
                var data:Number = _records[_position];
                
                var mod:Number = (_sample / 44100) * (2.0 * Math.PI);
                if (_useDual)
                {
                    data *= _power * Math.cos(_freq1 * mod) * Math.cos(_freq2 * mod);
                }
                else
                {
                    data *= _power * Math.cos(_freq1 * mod);
                }
                if (++_sample == 44100) _sample = 0;
                
                e.data.writeFloat(data);
                e.data.writeFloat(data);
                
                if (++_position == _records.length)
                {
                    _sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
                    _startRecord();
                    return;
                }
            }
        }
    }
}