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

音操作、スロー再生とか

http://hakuhin.jp/as3/sound.html
を参考に、音の扱いについて学びました。

各スライダで速度を調整できます。
またFileRefarenceで手持ちの音声に差し替えらるようにしました。

録音した音声をボイスチェンジャー風に加工したりするアプリにすると楽しそう。
でも、音程を操るにはさらに、難しいみたい。すごく重くてアプリかは無理っぽい

参考リンク
・http://marubayashi.net/diary/2010/03/cat-voice-keyboard.html
・http://iq12.com/old_blog/2009/08/25/real-  time-pitch-shifting/
Get Adobe Flash player
by otherone 15 Jan 2015
/**
 * Copyright otherone ( http://wonderfl.net/user/otherone )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5a8N
 */

package
{
    import com.bit101.components.PushButton;
    import com.bit101.components.Slider;
    import com.bit101.components.Text;
    import flash.display.SimpleButton;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.MouseEvent;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.media.SoundLoaderContext;
    import flash.net.URLRequest;
    import flash.text.TextField;
    import flash.utils.ByteArray;
    import flash.net.FileReference;
    import flash.display.Loader;
    
    /**
     * ...
     * @author nekome
     */

    public class Main extends Sprite
    {
        //*******************************************************
        private var traceTxt:TextField;
        private var src_obj:Sound;
        private var sound_loader_context:SoundLoaderContext;
        private var url:URLRequest;
        private var _fr:FileReference;
        private var _loader:Loader;
        // パラメータ
        private var sampling:uint = 2048; // 1 度に転送するサンプリング数
        private var sound_speed:Number = 1.0; // 再生速度        
        private var loop:Boolean = true; // ループあり
        private var loop_begin:Number = 0; // ループ開始地点        
        private var sound_speed_amp:Number = 0.0; // 再生速度の振幅
        private var sound_speed_phase_speed:Number = 0.0; // 再生速度の振幅の位相変化量(0 ~ 360)        
        //private var src_obj:Sound; // = new MySound(); // ソース用サウンドオブジェクト        
        private var out_obj:Sound = null; // 出力用サウンドオブジェクト        
        private var channel:Object = null;
        private var phase:Number = 0; // 再生速度振幅の位相を変化
        // 波形用ワーク
        private var wave:Object = { pos: 0 };
        private var sli_speed:Slider,sli_seek:Slider,sli_amp:Slider,sli_phase:Slider;
        private var tf_speed:Text,tf_phase:Text,tf_amp:Text;

        public function Main():void
        {            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void

        {

            removeEventListener(Event.ADDED_TO_STAGE, init);

            // entry point
            traceTxt = new TextField();
            addChild(traceTxt);
            traceTxt.x = 10, traceTxt.y = 10, traceTxt.width = stage.stageWidth - 20, traceTxt.height = stage.stageHeight - 20;

            url = new URLRequest("http://www.voice-pro.jp/announce2/sample/business/sibuya-bz01.mp3");
            src_obj = new Sound(url,new SoundLoaderContext(1000,true));
            src_obj.addEventListener(IOErrorEvent.IO_ERROR, SoundIOErrorFunc), src_obj.addEventListener(Event.COMPLETE, SoundCompleteFunc);
            addEventListener(Event.ENTER_FRAME, update);
            
            _fr= new FileReference();
            _fr.addEventListener(Event.SELECT, onSelect);
        }
        
        private function SoundIOErrorFunc(event:IOErrorEvent):void{traceTxt.text=("ファイル入出力のエラー");}
        private function SoundCompleteFunc(e:Event):void
        {            
            var play_b:PushButton = new PushButton(stage,100,300,"Play",fnPlay);// 再生ボタン
            var stop_b:PushButton = new PushButton(stage, 200, 300, "Stop", fnStop);// 停止ボタン
            var file_b:PushButton = new PushButton(stage, 300, 300, "File", fnFileSelect);// 停止ボタン
            sli_speed = new Slider("horizontal", stage, 50, 150, SliderSpeedSetFunc);//スピード
            sli_amp = new Slider("horizontal", stage, 50, 200, SliderAmpSetFunc);
            sli_phase=new Slider("horizontal",stage,50,250,SliderPhaseSetFunc);
            sli_speed.width = sli_amp.width = sli_phase.width = 300;            
            tf_speed = new Text(stage, 350, 150,"speed : "+sound_speed);
            tf_amp = new Text(stage, 350, 200, "phase : " + sound_speed_phase_speed);
            tf_phase = new Text(stage, 350, 250,"amp : "+sound_speed_amp);
            
            
            sli_speed.maximum = 100,sli_amp.maximum = 0.5,sli_phase.maximum = 90;
            sli_speed.value = 50;
            sli_speed.height = sli_amp.height = sli_phase.height = tf_speed.height = tf_phase.height = tf_amp.height = 20;
            tf_speed.width = tf_phase.width = tf_amp.width = 100;            
        }
        
        
        private function fnFileSelect(e:MouseEvent):void
        {
            _fr.browse();
        }

        private function onSelect(e:Event):void
        {
            _fr.addEventListener(Event.COMPLETE, compHandler);
            _fr.load();
        }

        private function compHandler(e:Event):void
        {
            _loader = new Loader();
            src_obj=new Sound();
            soundNull();
            src_obj.loadCompressedDataFromByteArray(e.target.data, e.target.data.length);
        }                
        
        
        private function SliderSpeedSetFunc(e:Event):void
        {
            var d:Number = sli_speed.value
            if (d >= 50) sound_speed = 1.0 + ((d - 50) / 50) * 2.0;
            else sound_speed = 1.0 / (1.0 + (1.0 - (d / 50)) * 2.0);
            tf_speed.text = String("speed : "+Math.floor(sound_speed * 100) / 100);
        }

        private function SliderPhaseSetFunc(e:Event):void
        {
            sound_speed_phase_speed = sli_phase.value;
            tf_phase.text = String("phase : "+Math.floor(sound_speed_phase_speed * 100) / 100);
        }

        private function SliderAmpSetFunc(e:Event):void
        {
            sound_speed_amp = sli_amp.value;
            tf_amp.text = String("amp : "+Math.floor(sound_speed_amp * 100) / 100);
        }

        

        private function fnPlay(e:MouseEvent):void
        {
            if (out_obj) return;
            out_obj = new Sound();
            // サウンドデータ要求時に呼び出されるイベント    
            out_obj.addEventListener(SampleDataEvent.SAMPLE_DATA, SampleDataFunc);
            channel = out_obj.play();
        }

        private function fnStop(e:MouseEvent):void { soundNull(); }
        private function soundNull():void
        {
            if (channel)channel.stop(), out_obj = null, channel = null;
        }

        // サウンドデータ要求
        private function SampleDataFunc(event:SampleDataEvent):void
        {
            var i:uint;            

            // 再生速度
            var speed:Number = sound_speed;            

            // 再生速度振幅分を加算
            speed += Math.sin(phase * Math.PI / 180) * sound_speed_amp;            

            // 速度制限
            if (speed < 0.1)speed = 0.1;
            if (speed > 10)speed = 10;            

            // 表示用
            //traceTxt.text = String(Math.floor(speed * 100) / 100);
            
            // サウンドバッファの開始位置
            var pos:Number = wave.pos - Math.floor(wave.pos);

            // ソース用と出力用のバッファ
            var src_buffer:ByteArray = new ByteArray();
            var out_buffer:ByteArray = event.data;
            
            // 開始直後のノイズ対策
            if (event.position == 0)
            {
                for (i = 0; i < 4096; i++)
                {
                    // 左チャンネル
                    out_buffer.writeFloat(0.0);
                    // 右チャンネル
                    out_buffer.writeFloat(0.0);
                }
                return;
            }

            // ソースから取得するサンプリング数
            var copy_sampling:uint = Math.ceil(sampling * speed);            
            if (!copy_sampling)copy_sampling = 1;            
            // サウンドデータを取得
            var get_sampling:uint = src_obj.extract(src_buffer, copy_sampling, wave.pos);
            // サウンドバッファが埋まるまでループを繰り返す
            while (true)
            {
                wave.pos += get_sampling;
                copy_sampling -= get_sampling;
                if (copy_sampling <= 0)break;                
                if (!loop)
                {
                    // ループしないなら空白で埋める
                    for (i = 0; i < copy_sampling; i++)
                    {
                        src_buffer.writeFloat(0);        
                        src_buffer.writeFloat(0);    
                    }
                    break;
                }
                // ループ開始位置をセット
                wave.pos = loop_begin;
                // サウンドデータを再取得
                get_sampling = src_obj.extract(src_buffer, copy_sampling, wave.pos);
                // エラー
                if (!get_sampling)return;
            }
            
            // 再生速度に合わせてサウンドデータをコピー
            var data:Number;
            
            for (i = 0; i < sampling; i++)
            {
                src_buffer.position = Math.floor(pos) * 4 * 2;
                pos += speed;

                // 左チャンネル
                data = src_buffer.readFloat();
                out_buffer.writeFloat(data);
             
                // 右チャンネル
                data = src_buffer.readFloat();
                out_buffer.writeFloat(data);        
           }        
        }

        private function GetDigitalTime(time:Number):String
        {
            var mil:* = Math.floor(time);
            var sec:* = Math.floor(mil / 1000);
            var min:* = Math.floor(sec / 60);
            if (min > 99)    min = 99;
            sec %= 60;
            mil %= 1000;
            if (min < 10) min = "0" + min;
            if (sec < 10) sec = "0" + sec;
            var z:* = "";
            if (mil < 100) z += "0";
            if (mil < 10)  z += "0";
            mil = z + mil;
            return min + ":" + sec + ":" + mil;
        }


        private function update(e:Event):void
        {
            if (channel != null)
            {
                //channel.position%src_obj.length;
                //traceTxt.text = GetDigitalTime(channel.position%src_obj.length)+" / "+GetDigitalTime(src_obj.length);
             }
            phase += sound_speed_phase_speed;
        }

    }
}