forked from: Generate Sound.

by tenasaku forked from Generate Sound. (diff: 42)
------------------------------------------------------------------------
振幅 amp の推移が不連続なのがポップ音の主原因のようですのでそこに手を入れました
変更点:
(1)	FREQS と sCount をコメントアウト
(2)	amp の推移が連続になるように変更 (どうもこれがカギらしい)
(3)	onSampleData の t の式で count だったところを i+e.position に変更 (count変数は不要に)
と思ったけど, やっぱり count 復活... 音価変更時に count = 0 にリセットする
(というのも position は 金輪際 リセットされず少々扱いにくいから)
(4)	count < REPAIR_LENGTH のあいだ, 直前のサンプル値の名残りとのブレンド処理
(音程変更時のポップノイズへの対処)
以上です
2010年4月7日 tenasaku
------------------------------------------------------------------------
♥0 | Line 122 | Modified 2010-04-07 18:33:58 | MIT License
play

ActionScript3 source code

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

// forked from onmyownlife's Generate Sound.
/*	------------------------------------------------------------------------
	振幅 amp の推移が不連続なのがポップ音の主原因のようですのでそこに手を入れました
	変更点:
	(1)	FREQS と sCount をコメントアウト
	(2)	amp の推移が連続になるように変更 (どうもこれがカギらしい)
	(3)	onSampleData の t の式で count だったところを i+e.position に変更 (count変数は不要に)
		と思ったけど, やっぱり count 復活... 音価変更時に count = 0 にリセットする
		(というのも position は 金輪際 リセットされず少々扱いにくいから)
	(4)	count < REPAIR_LENGTH のあいだ, 直前のサンプル値の名残りとのブレンド処理
		(音程変更時のポップノイズへの対処)
	以上です
	2010年4月7日 tenasaku
	------------------------------------------------------------------------
*/
package  
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.SampleDataEvent;
	import flash.filters.BlurFilter;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.utils.ByteArray;

	/**
	* ポップ音(ノイズ)が発生する原因を教えて。
	* 
	* @auther onmyownlife.com/
	*/
	public class Main extends Sprite
	{
		/** C,D,E,F,G,H,I */
//		private const FREQS:Array = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88];
		private const BASE_FREQ:Number = 44100;		
		private const AMP_DECAY:Number = 0.8;
		private var sound:Sound;		
		private var channel:SoundChannel;
		private var freq:Number = 200;
		private var amp:Number = .2;
		private var count:int = 0;
//		private var sCount:int = 0;
		private var centerY:Number;		
		private var numOfSample:Number = 8192 ;		
		private var freqDrunk:Drunk;
		private var lastValueLeft:Number = 0;
		private var lastValueRight:Number = 0;

		private var bt:Bitmap;
		private var btd:BitmapData;
		private var container:Sprite;
		
		public function Main(){
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			centerY = stage.stageHeight / 2;	
			
			btd = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x33000000);
			bt = new Bitmap(btd, "auto", true);
			bt.filters = [new BlurFilter(24,24)];
			addChild(bt);
			
			container = new Sprite();
			addChild(container);
			container.blendMode = "add";
			
			freqDrunk = new Drunk(20, 800, 100);
			freqDrunk.value = Math.random() * 50 + 20;

			sound = new Sound();
			sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
			channel = sound.play();
		}

		private function onSampleData(e:SampleDataEvent):void {
			const REPAIR_LENGTH:int = 441;
			btd.draw(this);
			bt.filters = [new BlurFilter(4, 4)];
			if (Math.random()<.15) {
				this.freq = freqDrunk.value;
				this.amp = Math.random() * .8 + .1;
				count = 0;
			}
			var amp0:Number = amp;
			var left:Number = 0;
			var right:Number = 0;
			container.graphics.clear();
			container.graphics.lineStyle(0, this.freq*256*256, 1);
			for (var i:uint = 0; i < numOfSample; i++) {
				amp = amp0*(1-i/numOfSample)+(i/numOfSample)*AMP_DECAY*amp0;
				var t:Number = (count++) * Math.PI * 2 * freq / BASE_FREQ;
				left = Math.sin(t) * amp;
				right = left;
				if (count<REPAIR_LENGTH) {
					left = left*(count/REPAIR_LENGTH)+lastValueLeft*(1-count/REPAIR_LENGTH);
					right = right*(count/REPAIR_LENGTH)+lastValueRight*(1-count/REPAIR_LENGTH);
				}
				e.data.writeFloat(left);
				e.data.writeFloat(right);
				if (i < 1000) {
					var val:Number = centerY + left * 100;
					if (i != 0) {
						container.graphics.lineTo(i / 1000 * stage.stageWidth, val );
					}else{
						container.graphics.moveTo(0, val);	
					}
				}
			}
			lastValueLeft = left;
			lastValueRight = right;
			amp = amp0*AMP_DECAY;
		}
	}
}

/**
 * Drunk Random Generator.
 */
class Drunk {
	public var range:Number = 2;
	public var maxValue:Number = 100;
	public var minValue:Number = 0;
	private var _value:Number;

	public function Drunk(minValue:Number = 0 , maxValue:Number = 100 , range:Number = 2){
		this.range = range;
		if (range < 0)range *= -1;
		if (range == 0)range = 2;
		this.maxValue = Math.max(minValue,maxValue);
		this.minValue = Math.min(minValue,maxValue);
		_value = Math.random() * (this.maxValue - this.minValue) + this.minValue;
	}
		
	public function get value():Number {
		var temp:Number = 0;
		var r:Number = Math.random() * range;
		r *= Math.random() > 0.5? -1:1;
		temp = _value + r;
		_value = temp;
		if (_value > maxValue) {
			_value = maxValue;
		}else if (_value < minValue) {
			_value = minValue;
		}
			
		return _value; 	
	}
		
	public function set value(val:Number):void {
		_value = val;
		if (_value > maxValue) {
			_value = maxValue;
		}else if (_value < minValue) {
			_value = minValue;
		}
	}
}