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

forked from: サウンドのサンプリング数落とし

-------------------------------------------------

サウンドのサンプリング数落とし

 ゲームボーイ風の音を出したいテストです。

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

// forked from Hakuhin's サウンドのサンプリング数落とし
// -------------------------------------------------
//
// サウンドのサンプリング数落とし
//
// ゲームボーイ風の音を出したいテストです。
//
// -------------------------------------------------
package {
    import flash.events.*;
    import flash.display.*;
    import flash.net.*;
    import flash.text.*;
    import flash.utils.*;
    import flash.system.*;
    import flash.geom.*;
    import flash.filters.*;
    import flash.ui.*;
    import flash.media.*;

    public class Main extends Sprite {
        public function Main() {


        
// -------------------------------------------------
// コンストラクタ
// -------------------------------------------------

// サウンドのファイルパス
var url:String = "http://actionscript.web.officelive.com/wonderfl/sound_001.mp3";

// フレームレート
stage.frameRate = 1000;

// 100%表示
stage.scaleMode = StageScaleMode.NO_SCALE;

// 左上
stage.align = StageAlign.TOP_LEFT;
stage.align = "TL";

// ステージサイズ
var w:uint;
var h:uint;

// 間引く平均数
var average:Number = 10;

// 量子化数
var quantize:Number = 128;

// グラフィック
var g:Graphics;

// 上画面
var sprite_up:Sprite = new Sprite();
g = sprite_up.graphics;
g.beginFill ( 0xF0F0F0 , 1.0 );
g.drawRoundRect ( 0 , 0 , 100 , 100 , 5 , 5 );
g.endFill();
g.lineStyle ( 0 , 0xFFFFFF , 1.0);
g.moveTo(  0,50);    g.lineTo(100,50);
addChild(sprite_up);
sprite_up.x = 10;
sprite_up.y = 10;

// 下画面
var sprite_down:Sprite = new Sprite();
g = sprite_down.graphics;
g.beginFill ( 0xF0F0F0 , 1.0 );
g.drawRoundRect ( 0 , 0 , 100 , 100 , 5 , 5 );
g.endFill();
g.lineStyle ( 0 , 0xFFFFFF , 1.0);
g.moveTo(  0,50);    g.lineTo(100,50);
addChild(sprite_down);
sprite_down.x = 10;

// 上画面描画領域
var shape_up:Shape = new Shape();
sprite_up.addChild(shape_up);

// 下画面描画領域
var shape_down:Shape = new Shape();
sprite_down.addChild(shape_down);

// 波形描画
addEventListener(Event.ENTER_FRAME,function(e:Event):void{
    if(!out_obj)                return;
    
    var stream:ByteArray = new ByteArray();
    src_obj.extract ( stream , 505 , wave.pos );

    var i:int;
    var pref:Number;
    var post:Number;
    var g:Graphics;
    var d:Number = quantize - 1.0;
    var num:Number;

    g = shape_up.graphics;
    g.clear();
    g.lineStyle ( 0 , 0x8080FF , 1.0);

    // 左(通常)
    for(i=0;i<500;i++){
        stream.position = 4 * 2 * ((i + 0) * 1);
        pref = stream.readFloat();
        stream.position = 4 * 2 * ((i + 1) * 1);
        post = stream.readFloat();
        
        g.moveTo((i+0)/5,pref * 50 + 50);
        g.lineTo((i+1)/5,pref * 50 + 50);
        g.lineTo((i+1)/5,post * 50 + 50);
    }

    g = shape_down.graphics;
    g.clear();
    g.lineStyle ( 0 , 0x8080FF , 1.0);

    // 右(通常)
    for(i=0;i<500;i++){
        stream.position = 4 * 2 * ((i + 0) * 1) + 4;
        pref = stream.readFloat();
        stream.position = 4 * 2 * ((i + 1) * 1) + 4;
        post = stream.readFloat();
        
        g.moveTo((i+0)/5,pref * 50 + 50);
        g.lineTo((i+1)/5,pref * 50 + 50);
        g.lineTo((i+1)/5,post * 50 + 50);
    }


    g = shape_up.graphics;
    g.lineStyle ( 0 , 0xFF8080 , 0.5);
    
    
    
    // 左(劣化後)
    pref = 0.0;
    for(i=0;i < 500;i+=average){
        num = 500 - i;
        if(num > average)    num = average;

        stream.position = (i + Math.floor(num * 0.5)) * 4 * 2;
        post = stream.readFloat();

        post = (post + 1) / 2;
        post = Math.floor(post * 0.9999999999999999*quantize) / d;
        post = post * 2 - 1;

        g.moveTo((i+0  )/5,pref * 50 + 50);
        g.lineTo((i+0  )/5,post * 50 + 50);
        g.lineTo((i+num)/5,post * 50 + 50);
        pref = post;
    }

    g = shape_down.graphics;
    g.lineStyle ( 0 , 0xFF8080 , 0.5);

    // 右(劣化後)
    pref = 0.0;
    for(i=0;i<500;i+=average){
        num = 500 - i;
        if(num > average)    num = average;

        stream.position = (i + Math.floor(num * 0.5)) * 4 * 2 + 4;
        post = stream.readFloat();

        post = (post + 1) / 2;
        post = Math.floor(post * 0.9999999999999999*quantize) / d;
        post = post * 2 - 1;

        g.moveTo((i+0  )/5,pref * 50 + 50);
        g.lineTo((i+0  )/5,post * 50 + 50);
        g.lineTo((i+num)/5,post * 50 + 50);
        pref = post;
    }
});

// リザルト作成
var result : Sprite = new Sprite();
addChild(result);
result.x = 0;

// スライダーコメント作成
var tf_slider_sampling_c:TextField = new TextField();
tf_slider_sampling_c.x = 10;
tf_slider_sampling_c.y = 0;
tf_slider_sampling_c.width = 300;
tf_slider_sampling_c.height = 20;
tf_slider_sampling_c.border = false;
tf_slider_sampling_c.text = "サンプリング数";
result.addChild(tf_slider_sampling_c);

// スライダー数値作成
var tf_slider_sampling_v:TextField = new TextField();
tf_slider_sampling_v.x = 100;
tf_slider_sampling_v.y = 0;
tf_slider_sampling_v.width = 40;
tf_slider_sampling_v.height = 20;
tf_slider_sampling_v.border = true;

// 書式
var tf_slider_v_fmt:TextFormat = new TextFormat();
tf_slider_v_fmt.font = "MS ゴシック";    // フォント名
tf_slider_v_fmt.align = TextFormatAlign.CENTER;    // 整列
tf_slider_sampling_v.defaultTextFormat = tf_slider_v_fmt;

// スライダー数値配置
tf_slider_sampling_v.text = "";
result.addChild(tf_slider_sampling_v);

// スライダー作成
var slider_sampling:SliderH = new SliderH(stage);
slider_sampling.x = 10;
slider_sampling.y = 22;
result.addChild(slider_sampling);
slider_sampling.setMinimum(200);
slider_sampling.setMaximum(1);

// スライダーが更新された
slider_sampling.setListener(function(v:Number):void{
    average = Math.floor(slider_sampling.value + 0.5);
    tf_slider_sampling_v.text = String(Math.floor(44100/average));
});

slider_sampling.value = average;




// スライダーコメント作成
var tf_slider_quantize_c:TextField = new TextField();
tf_slider_quantize_c.x = 10;
tf_slider_quantize_c.y = 40;
tf_slider_quantize_c.width = 300;
tf_slider_quantize_c.height = 20;
tf_slider_quantize_c.border = false;
tf_slider_quantize_c.text = "量子化数";
result.addChild(tf_slider_quantize_c);

// スライダー数値作成
var tf_slider_quantize_v:TextField = new TextField();
tf_slider_quantize_v.x = 100;
tf_slider_quantize_v.y = 40;
tf_slider_quantize_v.width = 40;
tf_slider_quantize_v.height = 20;
tf_slider_quantize_v.border = true;

// 書式
tf_slider_quantize_v.defaultTextFormat = tf_slider_v_fmt;

// スライダー数値配置
tf_slider_quantize_v.text = "";
result.addChild(tf_slider_quantize_v);

// スライダー作成
var slider_quantize:SliderH = new SliderH(stage);
slider_quantize.x = 10;
slider_quantize.y = 62;
result.addChild(slider_quantize);
slider_quantize.setMinimum(5);
slider_quantize.setMaximum(256);

// スライダーが更新された
slider_quantize.setListener(function(v:Number):void{
    quantize = Math.floor(slider_quantize.value + 0.5);
    tf_slider_quantize_v.text = String(quantize);
});

slider_quantize.value = quantize;




// ボタン作成
var button:Button = new Button(stage);
button.y = 90;
button.setSize(60,20);
button.setLabel("開く");
result.addChild(button);

// ボタンが押された
button.addEventListener(MouseEvent.CLICK,function(e:MouseEvent):void{
    load(text.text);
});

// テキストフィールド作成
var text:TextField = new TextField();
text.x = 10;
text.y = 90;
text.height = 20;
text.type = TextFieldType.INPUT;
text.border = true;

// 書式
var format:TextFormat = new TextFormat();
format.font = "MS ゴシック";    // フォント名
text.defaultTextFormat = format;

// テキスト表示
text.text = url;
result.addChild(text);

// リサイズ時に再配置
stage.addEventListener(Event.RESIZE,ResizeFunc);
function ResizeFunc(e:Event):void{
    w = stage.stageWidth;
    h = stage.stageHeight;
    
    // 上画面位置
    sprite_up.scaleX = (w - 10 - 10) / 100;
    sprite_up.scaleY = (h - 10 - 130 - 10) / 100 / 2;

    // 下画面位置
    sprite_down.y = 10 + (h - 10 - 120 - 10 - 0) / 2 + 10;
    sprite_down.scaleX = (w - 10 - 10) / 100;
    sprite_down.scaleY = (h - 10 - 130 - 10) / 100 / 2;
    
    // リザルト位置
    result.y = h - 130 + 10;

    // スライダー
    slider_sampling.setSize(w - 20,10);
    slider_quantize.setSize(w - 20,10);

    // テキストフィールド位置
    text.width = w - 10 - 10 - button.width - 10;
    
    // ボタン位置
    button.x = w - button.width - 10;
}
ResizeFunc(null);



// サウンドパラメータ
var sampling:uint = 2048;        // 1度に転送するサンプリング数
var loop:Boolean = true;        // ループあり
var loop_begin:uint = 0;        // ループ開始地点

// ソース用サウンドオブジェクト作成
var src_obj : Sound;

// 出力用サウンドオブジェクト
var out_obj:Sound = null;
var channel:SoundChannel = null;

// 波形用ワーク
var wave:Object = {
    pos : 0    // 再生位置
};

// サウンドデータ要求時に呼び出されるイベント
function SampleDataFunc(event:SampleDataEvent):void{

    var i:int;
    var j:int;
    
    // サウンドバッファの開始位置
    var po:int = 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 = sampling;
    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;
    }
    
    src_buffer.position = 0;

    var data_l:Number;
    var data_r:Number;
    var d:Number = quantize - 1.0;

    for(i=0;i < sampling;i+=average){
    
        var num:int = sampling - i;
        if(num > average)    num = average;

        src_buffer.position = (i + Math.floor(num * 0.5)) * 4 * 2;
        data_l = src_buffer.readFloat();
        data_r = src_buffer.readFloat();

        data_l = (data_l + 1) / 2;
        data_l = Math.floor(data_l * 0.9999999999999999*quantize) / d;
        data_l = data_l * 2 - 1;

        data_r = (data_r + 1) / 2;
        data_r = Math.floor(data_r * 0.9999999999999999*quantize) / d;
        data_r = data_r * 2 - 1;

        for(j=0;j<num;j++){
            // 左チャンネル
            out_buffer.writeFloat(data_l);
    
            // 右チャンネル
            out_buffer.writeFloat(data_r);
        }
    }

}

// リソース読み込み開始
load(url);

// -------------------------------------------------
// 読み込み
// -------------------------------------------------
function load(url:String):void{
    if(src_obj){
        src_obj = null;
    }
    
    if(out_obj){
        out_obj = null;
    }
    
    if(channel){
        channel.stop();
        channel = null;
    }
    
    // ソース用サウンドオブジェクト作成
    src_obj = new Sound();

    // ソース用サウンドオブジェクトの読み込みが完了
    src_obj.addEventListener (Event.COMPLETE,SoundCompleteFunc);
    function SoundCompleteFunc (event : Event):void {
    
        // 出力用サウンドオブジェクト作成
        out_obj = new Sound();
    
        // 新しいオーディオデータ要求時に呼び出されるイベント
        out_obj.addEventListener(SampleDataEvent.SAMPLE_DATA, SampleDataFunc);
    
        // 再生開始
        channel = out_obj.play();
    }

    // ソース用サウンドオブジェクト作成
    src_obj.load(new URLRequest(url));

}

        }
    }
}








import flash.events.*;
import flash.display.*;
import flash.net.*;
import flash.text.*;
import flash.utils.*;
import flash.system.*;
import flash.geom.*;
import flash.filters.*;
import flash.ui.*;
import flash.media.*;

// -------------------------------------------------
// ボタン
// -------------------------------------------------
internal class Button extends Sprite {

    private var _width:Number;
    private var _height:Number;
    
    private var _text:TextField;
    private var _background:Sprite;
    

    public function Button(stage:Stage) {
        var slider:Button = this;

        // 背景用スプライト作成
        _background = new Sprite();
        addChild(_background);

        // テキストフィールド
        _text = new TextField();
        addChild(_text);
    
        _text.x = 0;
        _text.y = 0;
        _text.selectable = false;

        // 書式
        var format:TextFormat = new TextFormat();
        format.align = TextFormatAlign.CENTER;    // 整列
        format.font = "MS ゴシック";    // フォント名
        format.size = 14;                // 文字のポイントサイズ
        format.color = 0x202020;        // 文字の色
        _text.defaultTextFormat = format;
    
        // マウスオーバーで少し明るく
        addEventListener(MouseEvent.MOUSE_OVER,function(e:MouseEvent):void{
            var color : ColorTransform = new ColorTransform(1,1,1,1,8,8,8,0);
            transform.colorTransform = color;
        });

        // マウスアウトで元に戻す
        addEventListener(MouseEvent.MOUSE_OUT,function(e:MouseEvent):void{
            var color : ColorTransform = new ColorTransform(1,1,1,1,0,0,0,0);
            transform.colorTransform = color;                                                           
        });

        // デフォルト値
        setSize(100,100);
        update();
    }
    // リサイズ
    public function setSize(w:Number,h:Number):void{
        // 背景リサイズ
        _width = w;
        _height = h;
        update();
    }
    // ラベルセット
    public function setLabel(str:String):void{
        _text.text = str;
        update();
    }
    // 描画更新
    private function update():void{
        // 背景描画
        var g:Graphics = _background.graphics;
        
        // 角丸矩形描画
        g.clear();
        g.lineStyle ( 0 , 0x808080 , 1.0,false,LineScaleMode.NONE,CapsStyle.ROUND,JointStyle.ROUND);
        g.beginFill ( 0xF0F0F0 , 1.0 );
        g.drawRoundRect ( 0 , 0 , _width , _height , 5 , 5 );
        g.endFill();
        
        // テキスト位置修正
        _text.width  = _width;
        _text.height = _height;
    }
}


// -------------------------------------------------
// 水平方向スライダー
// -------------------------------------------------
internal class SliderH extends Sprite {

    private var _value:Number;
    private var _minimum:Number;
    private var _maximum:Number;
    private var _width:Number;
    private var _height:Number;
    private var _width_bar:Number;
    private var _drag:Boolean;
    private var _listener:Function;
    
    private var _bar:Sprite;
    private var _background:Sprite;
    

    public function SliderH(stage:Stage) {
        var slider:SliderH = this;
        var g:Graphics;
        
        // 背景配置
        _background = new Sprite();
        addChild(_background);
        
        // バー配置
        _bar = new Sprite();
        addChild(_bar);
        _bar.x = 1;
        _bar.y = 1;
        
        // 背景描画
        g = _background.graphics;
        g.lineStyle ( 0 , 0xB0B0B0 , 1.0);
        g.beginFill ( 0xF0F0F0 , 1.0 );
        g.drawRect ( 0 , 0 , 100 , 100);
        g.endFill();
        
        // バー描画
        g = _bar.graphics;
        g.lineStyle ( 0 , 0x808080 , 1.0);
        g.beginFill ( 0xA0A0A0 , 1.0 );
        g.drawRect ( 0 , 0 , 100 , 100);
        g.endFill();

        // マウスイベント
        stage.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent):void{
            if(!_drag){
                if(slider.hitTestPoint ( e.stageX , e.stageY , false )){
                    if(e.buttonDown){
                        _drag = true;
                        
                        var color : ColorTransform = new ColorTransform(1,1,1,1,4,4,4,0);
                        transform.colorTransform = color;

                        DragEvent(e);
                    }
                }
            }
        });

        // マウスイベント
        stage.addEventListener(MouseEvent.MOUSE_MOVE,function(e:MouseEvent):void{
            if(_drag){
                if(!e.buttonDown){
                    _drag = false;

                    // マウスアウトで元に戻す
                    var color : ColorTransform = new ColorTransform(1,1,1,1,0,0,0,0);
                    transform.colorTransform = color;
                }
            }

            if(_drag)        DragEvent(e);
        });
        
        function DragEvent(e:MouseEvent):void{
            // ステージマウス座標をローカル座標系に落とし込む
            var p : Point = new Point(e.stageX,e.stageY);
            var m : Matrix = slider.transform.matrix;
            m.invert();
            p = m.transformPoint(p);

            // バーの位置更新
            _bar.x = p.x - _bar.width/2;
            if(_bar.x < 0)    _bar.x = 0;
            if(_bar.x > _width - _bar.width){
                _bar.x = _width - _bar.width;
            }
            
            // バーの位置からデフォルト値を決定
            var d:Number = (_bar.x) / (_width - _bar.width);
            d = (_maximum - _minimum) * d + _minimum;
            value = d;

            e.updateAfterEvent();        
        }

        // デフォルト値
        _value = 0.0;
        _minimum = 0.0;
        _maximum = 1.0;
        _drag = false;
        _listener = null;
        setSize(100,10);
        setSizeBar(20);
        update();
    }
    // 最小値セット
    public function setMinimum(v:Number):void{
        _minimum = v;
        update();
    }
    // 最大値セット
    public function setMaximum(v:Number):void{
        _maximum = v;
        update();
    }
    // 通常値取得
    public function get value():Number{
        return _value;
    }
    // 通常値セット
    public function set value(v:Number):void{
        _value = v;
        update();
        
        // 通知
        if(_listener != null)    _listener(_value);
    }
    // 更新通知
    public function setListener(func:Function):void{
        _listener = func;
    }
    // リサイズ
    public function setSize(w:Number,h:Number):void{
        // 背景リサイズ
        _width = w;
        _height = h;
        update();
    }
    // バーのリサイズ
    public function setSizeBar(w:Number):void{
        // 背景リサイズ
        _width_bar = w;
        update();
    }

    // 描画更新
    private function update():void{
        // リサイズ
        _background.scaleX = _width / 100;
        _background.scaleY = _height / 100;
        _bar.scaleX = (_width_bar - 2) / 100;
        _bar.scaleY = (_height - 2) / 100;
        
        // バーの位置
        var length : Number = _width - 2 - _bar.width;
        var d : Number = (_value - _minimum) / (_maximum - _minimum);
        _bar.x = length * d + 1;
    }

}