Beautifl - Flash Gallery

Thumbnail : 手書き波形でサウンド再生
手書き波形でサウンド再生
Hakuhin 2010-02-17 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

// -------------------------------------------------
//
// 手書き波形でサウンド再生
//
//
// -------------------------------------------------
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() {




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


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

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

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

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

// 周波数
var cycle:Number = 220;

// 入力サウンドバッファサイズ
var SOUND_BUFFER_SIZE:int = 200;

// 入力サウンドバッファ
var src:Object = {
	buffer:new Vector.<Number>(),	// バッファ
	pos:0				// 転送位置
}
var i:Number;
for(i=0;i<SOUND_BUFFER_SIZE;i++){
	src.buffer[i] = -Math.sin(i/SOUND_BUFFER_SIZE * Math.PI*2) * 0.5;
}


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

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

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

function Render():void{

	g = shape.graphics;
	g.clear();
	g.lineStyle (0, 0x0000FF, 0.2);	// 線のスタイル

	
	var i:int;
	var buf:Vector.<Number> = src.buffer;

	for(i=0;i<buf.length-2;i++){
		g.moveTo(i  ,buf[i  ] * 50 + 50);
		g.lineTo(i+1,buf[i+1] * 50 + 50);
	}
}
Render();


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

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

// スライダー数値作成
var tf_slider_v:TextField = new TextField();
tf_slider_v.x = 60;
tf_slider_v.y = 0;
tf_slider_v.width = 80;
tf_slider_v.height = 20;
tf_slider_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_v.defaultTextFormat = tf_slider_v_fmt;

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

// スライダー作成
var slider:SliderH = new SliderH(stage);
slider.x = 10;
slider.y = 30;
result.addChild(slider);
slider.setMinimum(55);
slider.setMaximum(440);

// スライダーが更新された
slider.setListener(function(v:Number):void{
	cycle = Math.floor(slider.value * 10) / 10;
	tf_slider_v.text = String(cycle);
});

slider.value = cycle;

// ボタン作成
var button_play:Button = new Button(stage);
button_play.x = 10;
button_play.y = 60;
button_play.setSize(80,20);
button_play.setLabel("再生開始");
result.addChild(button_play);

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

// ボタン作成
var button_stop:Button = new Button(stage);
button_stop.x = 100;
button_stop.y = 60;
button_stop.setSize(80,20);
button_stop.setLabel("停止");
result.addChild(button_stop);

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


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

	// リザルト位置
	result.y = h - 100 + 10;

	// スライダー
	slider.setSize(w - 20,10);
	
}
ResizeFunc(null);



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

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

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

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

	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 speed : Number = SOUND_BUFFER_SIZE / (44100 / cycle);
	
	var i:int;
	var buf:Vector.<Number> = src.buffer;

	for(i=0;i<sampling;i++){
		var data : Number = buf[Math.floor(wave.pos)];
		
		// 左右チャンネル
		out_buffer.writeFloat(data);
		out_buffer.writeFloat(data);

		wave.pos += speed;
		if(wave.pos > SOUND_BUFFER_SIZE - 1){
			wave.pos -= SOUND_BUFFER_SIZE - 1;
		}
	}

}


// サウンド開始
function SoundPlay():void{

	// 前回のサウンド停止
	SoundStop();
	
	// ソース用サウンドオブジェクト作成
	sound_obj = new Sound();

	// 新しいオーディオデータ要求時に呼び出されるイベント
	sound_obj.addEventListener(SampleDataEvent.SAMPLE_DATA, SampleDataFunc);

	// 再生開始
	channel = sound_obj.play();

}


// サウンド終了
function SoundStop():void{

	if(channel){
		channel.stop();
		channel = null;
	}
}


// マウス処理
var push:Boolean = false;
var mouse_pos_old:Point;	// 前回のマウス位置
var mouse_pos_new:Point;	// 今回のマウス位置

sprite.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent):void{
	push = true;
	mouse_pos_old = mouse_pos_new = new Point(shape.mouseX,shape.mouseY);
});
stage.addEventListener(MouseEvent.MOUSE_MOVE,function(e:MouseEvent):void{
	mouse_pos_old = mouse_pos_new;
	mouse_pos_new = new Point(shape.mouseX,shape.mouseY);
	if(push){
		MouseDrag(mouse_pos_old,mouse_pos_new);
	}
});
stage.addEventListener(MouseEvent.MOUSE_UP,function(e:MouseEvent):void{
	push = false;															 
});

function MouseDrag(p0:Point,p1:Point):void{
	
	var buf:Vector.<Number> = src.buffer;
	
	var pos0 : Point = new Point(p0.x,p0.y);
	var pos1 : Point = new Point(p1.x,p1.y);

	pos0.y = pos0.y / 50.0 - 1.0;
	pos1.y = pos1.y / 50.0 - 1.0;

	var d : Number;
	var min:Number;
	var max:Number;
	
	if(pos0.x < pos1.x){
		min = pos0.x;
		max = pos1.x;
	}else{
		min = pos1.x;
		max = pos0.x;
	}
	
	min = Math.floor(min + 0.5) + 0.5;
	max = Math.floor(max + 0.5) + 0.5;
	
	var i:Number;
	for(;min<max;min+=1.0){
		if(min < 0)						continue;
		if(min > SOUND_BUFFER_SIZE-1)	continue;
		
		var nx:Number = -(pos1.y - pos0.y);
		var ny:Number =  (pos1.x - pos0.x);
		d = -(nx * min -(pos0.x * nx + pos0.y * ny)) / (0 + ny);
		if(d < -1.0)	d = -1.0;
		if(d >  1.0)	d =  1.0;

		buf[Math.floor(min)] = d;
	}
	
	Render();
}



		}
    }
}








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;
	}

}