PageRenderTime 24ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 1ms

/sfxr/Synth.hx

http://github.com/tong/sfxr
Haxe | 398 lines | 348 code | 40 blank | 10 comment | 71 complexity | b539da14d1509f814b205cdbb1574460 MD5 | raw file
  1package sfxr;
  2
  3import flash.events.SampleDataEvent;
  4import flash.media.Sound;
  5import flash.media.SoundChannel;
  6import flash.utils.ByteArray;
  7import flash.utils.Endian;
  8
  9class Synth {
 10	
 11	/**
 12		square: 0
 13		saw: 1
 14		sin: 2
 15		noise: 3
 16	*/
 17	public var waveType	: Int;
 18	/** Samples per second - only used for .wav export */
 19	public var sampleRate : UInt;
 20	/** Bits per sample - only used for .wav export */
 21	public var bitDepth : UInt;
 22	/** Overall volume of the sound (0 to 1) */
 23	public var masterVolume : Float;
 24	
 25	public var attackTime : Float;
 26	public var sustainTime : Float;
 27	public var sustainPunch : Float;
 28	public var decayTime : Float;
 29	
 30	public var startFrequency : Float;
 31	public var minFrequency : Float;
 32	
 33	public var slide : Float;
 34	public var deltaSlide : Float;
 35	
 36	public var vibratoDepth : Float;
 37	public var vibratoSpeed : Float;
 38	
 39	public var changeAmount : Float;
 40	public var changeSpeed : Float;
 41	
 42	public var squareDuty : Float;
 43	public var dutySweep : Float;
 44	
 45	public var repeatSpeed : Float;
 46	
 47	public var phaserOffset : Float;
 48	public var phaserSweep : Float;
 49	
 50	public var lpFilterCutoff : Float;
 51	public var lpFilterCutoffSweep : Float;
 52	public var lpFilterResonance : Float;
 53	
 54	public var hpFilterCutoff : Float;
 55	public var hpFilterCutoffSweep : Float;
 56	
 57	var _envelopeVolume : Float;
 58	var _envelopeStage : Int;
 59	var _envelopeTime : Float;
 60	var _envelopeLength : Float;
 61	var _envelopeLength0 : Float;
 62	var _envelopeLength1 : Float;
 63	var _envelopeLength2 : Float;
 64	var _envelopeOverLength0 : Float;
 65	var _envelopeOverLength1 : Float;
 66	var _envelopeOverLength2 : Float;
 67	var _envelopeFullLength : Float;
 68	
 69	var _phase : Float;
 70	var _pos : Float;
 71	var _period : Float;
 72	var _periodTemp : Float;
 73	var _maxPeriod : Float;
 74	
 75	var _slide : Float;
 76	var _deltaSlide : Float;
 77	
 78	var _vibratoPhase : Float;
 79	var _vibratoSpeed : Float;
 80	var _vibratoAmplitude : Float;
 81	
 82	var _changeAmount : Float;
 83	var _changeTime : Float;
 84	var _changeLimit : Float;
 85	
 86	var _squareDuty : Float;
 87	var _dutySweep : Float;
 88	
 89	var _repeatTime : Float;
 90	var _repeatLimit : Float;
 91	
 92	var _phaserOffset : Float;
 93	var _phaserDeltaOffset : Float;
 94	var _phaserInt : Int;
 95	var _phaserPos : Int;
 96	var _phaserBuffer : flash.Vector<Float>;
 97	
 98	var _lpFilterPos : Float;
 99	var _lpFilterOldPos : Float;
100	var _lpFilterDeltaPos : Float;
101	var _lpFilterCutoff : Float;
102	var _lpFilterDeltaCutoff : Float;
103	var _lpFilterDamping : Float;
104	
105	var _hpFilterPos : Float;
106	var _hpFilterCutoff : Float;
107	var _hpFilterDeltaCutoff : Float;
108	
109	var _noiseBuffer : flash.Vector<Float>;
110	var _superSample : Float;
111	var _sample : Float;
112	var _sampleCount : UInt;
113	var _bufferSample : Float;
114	
115	var sound : Sound;
116	var channel : SoundChannel;
117	
118	public function new( ?waveType : Int,
119						 sampleRate : UInt = 44100, bitDepth : UInt = 16,
120						 masterVolume : Float = 0.5 ) {
121		
122		this.waveType = ( waveType != null ) ? waveType : 0;
123		this.sampleRate = sampleRate;
124		this.bitDepth = bitDepth;
125		this.masterVolume = masterVolume;
126		
127		attackTime = sustainTime = sustainPunch = decayTime = 0;
128		startFrequency = minFrequency =
129		slide = deltaSlide =
130		vibratoDepth = vibratoSpeed =
131		changeAmount = changeSpeed =
132		squareDuty = dutySweep =
133		repeatSpeed =
134		phaserOffset = phaserSweep =
135		lpFilterCutoff = lpFilterCutoffSweep = lpFilterResonance =
136		hpFilterCutoff = hpFilterCutoffSweep = 0.0;
137	}
138	
139	public function play() {
140		stop();
141		reset( true );
142		if( sound == null ) {
143			sound = new Sound();
144			sound.addEventListener( SampleDataEvent.SAMPLE_DATA, onSampleData );
145		}
146		channel = sound.play();
147	}
148	
149	public function stop() {
150		if( channel != null )  {
151			channel.stop();
152			channel = null;
153		}
154	}
155	
156	public function validate() {
157		if( sampleRate != 22050 ) sampleRate = 44100;
158		if( bitDepth != 8 ) bitDepth = 16;
159		masterVolume = clamp1(masterVolume);
160		attackTime = clamp1(attackTime);
161		sustainTime = clamp1(sustainTime);
162		sustainPunch = clamp1(sustainPunch);
163		decayTime = clamp1(decayTime);
164		startFrequency = clamp1(startFrequency);
165		minFrequency = clamp1(minFrequency);
166		slide = clamp2(slide);
167		deltaSlide = clamp2(deltaSlide);
168		vibratoDepth = clamp1(vibratoDepth);
169		vibratoSpeed = clamp1(vibratoSpeed);
170		changeAmount = clamp2(changeAmount);
171		changeSpeed = clamp1(changeSpeed);
172		squareDuty = clamp1(squareDuty);
173		dutySweep = clamp2(dutySweep);
174		repeatSpeed = clamp1(repeatSpeed);
175		phaserOffset = clamp2(phaserOffset);
176		phaserSweep = clamp2(phaserSweep);
177		lpFilterCutoff = clamp1(lpFilterCutoff);
178		lpFilterCutoffSweep = clamp2(lpFilterCutoffSweep);
179		lpFilterResonance = clamp1(lpFilterResonance);
180		hpFilterCutoff = clamp1(hpFilterCutoff);
181		hpFilterCutoffSweep = clamp2(hpFilterCutoffSweep);
182	}
183	
184	public function clone() : Synth {
185		var out = new Synth();
186		out.copyFrom( this, false );		
187		return out;
188	}
189	
190	public function copyFrom( synth : Synth, shouldDeleteCache : Bool = true) {
191	//	if( shouldDeleteCache ) deleteCache();
192		waveType = 				synth.waveType;
193		attackTime =            synth.attackTime;
194		sustainTime =           synth.sustainTime;
195		sustainPunch =          synth.sustainPunch;
196		decayTime =             synth.decayTime;
197		startFrequency =        synth.startFrequency;
198		minFrequency =          synth.minFrequency;
199		slide =                 synth.slide;
200		deltaSlide =            synth.deltaSlide;
201		vibratoDepth =          synth.vibratoDepth;
202		vibratoSpeed =          synth.vibratoSpeed;
203		changeAmount =          synth.changeAmount;
204		changeSpeed =           synth.changeSpeed;
205		squareDuty =            synth.squareDuty;
206		dutySweep =             synth.dutySweep;
207		repeatSpeed =           synth.repeatSpeed;
208		phaserOffset =          synth.phaserOffset;
209		phaserSweep =           synth.phaserSweep;
210		lpFilterCutoff =        synth.lpFilterCutoff;
211		lpFilterCutoffSweep =   synth.lpFilterCutoffSweep;
212		lpFilterResonance =     synth.lpFilterResonance;
213		hpFilterCutoff =        synth.hpFilterCutoff;
214		hpFilterCutoffSweep =   synth.hpFilterCutoffSweep;
215		masterVolume = 			synth.masterVolume;
216		validate();
217	}                
218	
219	function onSampleData( e : SampleDataEvent ) {
220		synthWave( e.data, 3072, true );
221	}
222	
223	function synthWave( buffer : ByteArray, length : Int, waveData : Bool = false ) {
224		var finished = false;
225		_sampleCount = 0;
226		_bufferSample = 0.0;
227		for( i in 0...length ) {
228			if( finished )
229				return;
230			if( _repeatLimit != 0 ) {
231				if( ++_repeatTime >= _repeatLimit ) {
232					_repeatTime = 0;
233					reset( false );
234				}
235			}
236			if( _changeLimit != 0 ) {
237				if( ++_changeTime >= _changeLimit ) {
238					_changeLimit = 0;
239					_period *= _changeAmount;
240				}
241			}
242			_slide += _deltaSlide;
243			_period = _period * _slide;
244			if( _period > _maxPeriod ) {
245				_period = _maxPeriod;
246				if( minFrequency > 0.0 ) finished = true;
247			}
248			_periodTemp = _period;
249			if( _vibratoAmplitude > 0.0 ) {
250				_vibratoPhase += _vibratoSpeed;
251				_periodTemp = _period * ( 1.0 + Math.sin(_vibratoPhase) * _vibratoAmplitude );
252			}
253			_periodTemp = Std.int( _periodTemp );
254			if( _periodTemp < 8 ) _periodTemp = 8;
255			_squareDuty += _dutySweep;
256			if( _squareDuty < 0.0 ) _squareDuty = 0.0;
257			else if( _squareDuty > 0.5 ) _squareDuty = 0.5;
258			if( ++_envelopeTime > _envelopeLength ) {
259				_envelopeTime = 0;
260				switch( ++_envelopeStage ) {
261				case 1 : _envelopeLength = _envelopeLength1;
262				case 2 : _envelopeLength = _envelopeLength2;
263				}
264			}
265			switch( _envelopeStage ) {
266			case 0 : _envelopeVolume = _envelopeTime * _envelopeOverLength0;
267			case 1 : _envelopeVolume = 1.0 + (1.0 - _envelopeTime * _envelopeOverLength1) * 2.0 * sustainPunch;
268			case 2 : _envelopeVolume = 1.0 - _envelopeTime * _envelopeOverLength2;
269			case 3 : _envelopeVolume = 0.0; finished = true;
270			}
271			_phaserOffset += _phaserDeltaOffset;
272			_phaserInt = Std.int( _phaserOffset );
273			if( _phaserInt < 0 ) _phaserInt = -_phaserInt;
274			else if( _phaserInt > 1023 ) _phaserInt = 1023;
275			if( _hpFilterDeltaCutoff != 0.0 ) {
276				_hpFilterCutoff *- _hpFilterDeltaCutoff;
277				if( _hpFilterCutoff < 0.00001 ) _hpFilterCutoff = 0.00001;
278				else if( _hpFilterCutoff > 0.1 ) _hpFilterCutoff = 0.1;
279			}
280			_superSample = 0.0;
281			for( j in 0...8 ) {
282				_sample = 0.0;
283				_phase++;
284				if( _phase >= _periodTemp ) {
285					_phase = _phase % _periodTemp;
286					if( waveType == 3 ) { 
287						for( n in 0...32 ) {
288							 _noiseBuffer[n] = Math.random() * 2.0 - 1.0;
289						}
290					}
291				}
292				_pos = _phase / _periodTemp;
293				switch( waveType ) {
294				case 0 : _sample = (_pos < _squareDuty) ? 0.5 : -0.5;
295				case 1 : _sample = 1.0 - _pos * 2.0;
296				case 2 : _sample = Math.sin(_pos * Math.PI * 2.0);
297				case 3 : _sample = _noiseBuffer[Std.int(_phase * 32 / Std.int(_periodTemp))];
298				}
299				_lpFilterOldPos = _lpFilterPos;
300				_lpFilterCutoff *= _lpFilterDeltaCutoff;
301				if( _lpFilterCutoff < 0.0 ) _lpFilterCutoff = 0.0;
302				else if( _lpFilterCutoff > 0.1 ) _lpFilterCutoff = 0.1;
303				if( lpFilterCutoff != 1.0 ) {
304					_lpFilterDeltaPos += (_sample - _lpFilterPos) * _lpFilterCutoff * 4;
305					_lpFilterDeltaPos -= _lpFilterDeltaPos * _lpFilterDamping;
306				} else {
307					_lpFilterPos = _sample;
308					_lpFilterDeltaPos = 0.0;
309				}
310				_lpFilterPos += _lpFilterDeltaPos;
311				_hpFilterPos += _lpFilterPos - _lpFilterOldPos;
312				_hpFilterPos -= _hpFilterPos * _lpFilterCutoff;
313				_sample = _hpFilterPos;
314				_phaserBuffer[_phaserPos&1023] = _sample;
315				_sample += _phaserBuffer[(_phaserPos - _phaserInt + 1024) & 1023];
316				_phaserPos = (_phaserPos + 1) & 1023;
317				_superSample += _sample;
318			}
319			_superSample = masterVolume * masterVolume * _envelopeVolume * _superSample / 8.0;
320			if( _superSample > 1.0 ) _superSample = 1.0;
321			if( _superSample < -1.0 ) _superSample = -1.0;
322			if( waveData ) {
323				buffer.writeFloat(_superSample);
324				buffer.writeFloat(_superSample);
325			} else {
326				_bufferSample += _superSample;
327				_sampleCount++;
328				if( sampleRate == 44100 || _sampleCount == 2 ) {
329					_bufferSample /= _sampleCount;
330					_sampleCount = 0;
331					if( bitDepth == 16 ) buffer.writeShort(Std.int(32000.0 * _bufferSample));
332					else buffer.writeByte( Std.int( _bufferSample * 127 + 128 ) );
333						
334					_bufferSample = 0.0;
335				}
336			}
337		}
338	}
339	
340	function reset( total : Bool ) {
341		_period = 100.0 / ( startFrequency * startFrequency + 0.001 );
342		_maxPeriod = 100.0 / ( minFrequency * minFrequency + 0.001 );
343		_slide = 1.0 - slide * slide * slide * 0.01;
344		_deltaSlide = -deltaSlide * deltaSlide * deltaSlide * 0.000001;
345		_squareDuty = 0.5 - squareDuty * 0.5;
346		_dutySweep = -dutySweep * 0.00005;
347		if( changeAmount > 0.0 )  _changeAmount = 1.0 - changeAmount*changeAmount * 0.9;
348		else _changeAmount = 1.0 + changeAmount * changeAmount * 10.0;
349		_changeTime = 0;
350		_changeLimit = ( changeSpeed == 1.0 ) ? 0 : (1.0 - changeSpeed) * (1.0 - changeSpeed) * 20000 + 32;
351		if( total ) {
352			_phase = 0;
353			_lpFilterPos = _lpFilterDeltaPos = 0.0;
354			_lpFilterCutoff = lpFilterCutoff * lpFilterCutoff * lpFilterCutoff * 0.1;
355			_lpFilterDeltaCutoff = 1.0 + lpFilterCutoffSweep * 0.0001;
356			_lpFilterDamping = 5.0 / (1.0 + lpFilterResonance * lpFilterResonance * 20.0) * (0.01 + _lpFilterCutoff);
357			if( _lpFilterDamping > 0.8 ) _lpFilterDamping = 0.8;
358			_hpFilterPos = 0.0;
359			_hpFilterCutoff = hpFilterCutoff * hpFilterCutoff * 0.1;
360			_hpFilterDeltaCutoff = 1.0 + hpFilterCutoffSweep * 0.0003;
361			_vibratoPhase = 0.0;
362			_vibratoSpeed = vibratoSpeed * vibratoSpeed * 0.01;
363			_vibratoAmplitude = vibratoDepth * 0.5;
364			_envelopeVolume = 0.0;
365			_envelopeStage = 0;
366			_envelopeTime = 0;
367			_envelopeLength0 = attackTime * attackTime * 100000.0;
368			_envelopeLength1 = sustainTime * sustainTime * 100000.0;
369			_envelopeLength2 = decayTime * decayTime * 100000.0;
370			_envelopeLength = _envelopeLength0;
371			_envelopeFullLength = _envelopeLength0 + _envelopeLength1 + _envelopeLength2;
372			_envelopeOverLength0 = 1.0 / _envelopeLength0;
373			_envelopeOverLength1 = 1.0 / _envelopeLength1;
374			_envelopeOverLength2 = 1.0 / _envelopeLength2;
375			_phaserOffset = phaserOffset * phaserOffset * 1020.0;
376			if( phaserOffset < 0.0 ) _phaserOffset = -_phaserOffset;
377			_phaserDeltaOffset = phaserSweep * phaserSweep;
378			if( _phaserDeltaOffset < 0.0 ) _phaserDeltaOffset = -_phaserDeltaOffset;
379			_phaserPos = 0;
380			if( _phaserBuffer == null ) _phaserBuffer = new flash.Vector<Float>( 1024, true );
381			if( _noiseBuffer == null ) _noiseBuffer = new flash.Vector<Float>( 32, true );
382			for( i in 0...1024 ) _phaserBuffer[i] = 0.0;
383			for( i in 0...32 ) _noiseBuffer[i] = Math.random() * 2.0 - 1.0;
384			_repeatTime = 0;
385			if( repeatSpeed == 0.0 ) _repeatLimit = 0;
386			else _repeatLimit = Std.int((1.0-repeatSpeed) * (1.0-repeatSpeed) * 20000) + 32;
387		}
388	}
389	
390	inline function clamp1( v : Float ) : Float {
391		return (v > 1.0) ? 1.0 : ((v < 0.0) ? 0.0 : v);
392	}
393	
394	inline function clamp2( v : Float ) : Float {
395		return (v > 1.0) ? 1.0 : ((v < -1.0) ? -1.0 : v);
396	}
397	
398}