/*
	FSinOsc - fixed frequency sine oscillator
	arguments :
		freq - frequency in cycles per second. Must be a scalar.
		mul - multiply by signal or scalar
		add - add to signal or scalar
		
	This unit generator uses a very fast algorithm for generating a sine
	wave at a fixed frequency.
*/

FSinOsc : UGen {	
	*ar { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0;
		^this.multiNew('audio', freq, iphase).madd(mul, add)
	}
	*kr { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0;
		^this.multiNew('control', freq, iphase).madd(mul, add)
	}
}


Klang : UGen {
	*ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0;
			^this.multiNewList(['audio', freqscale, 
						freqoffset, specificationsArrayRef] )
	}
	*new1 { arg rate, freqscale, freqoffset, arrayRef;
		var specs, freqs, amps, phases;
		# freqs, amps, phases = arrayRef.dereference;
		specs = [freqs, 
				amps ?? {Array.fill(freqs.size,1.0)}, 
				phases ?? {Array.fill(freqs.size,0.0)}
				].flop.flat;

		^super.new.rate_(rate).addToSynth.init([freqscale,freqoffset] ++ specs); 
	}
 	init { arg theInputs;
 		// store the inputs as an array
 		inputs = theInputs;
 	}
	argNamesInputsOffset { ^2 }
}

Klank : UGen {	
	*ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0;
			^this.multiNewList(['audio',  input, freqscale, 
						freqoffset, decayscale, specificationsArrayRef] )
	}
	*new1 { arg rate, input, freqscale, freqoffset, decayscale, arrayRef;
		var specs, freqs, amps, times;
		# freqs, amps, times = arrayRef.dereference;
		specs = [freqs, 
				amps ?? {Array.fill(freqs.size,1.0)}, 
				times ?? {Array.fill(freqs.size,1.0)}
				].flop.flat;

		^super.new.rate_(rate).addToSynth.init([input,freqscale,freqoffset,decayscale] ++ specs); 
	}
 	init { arg theInputs;
 		// store the inputs as an array
 		inputs = theInputs;
 	}
	argNamesInputsOffset { ^2 }
}

DynKlank : UGen {

	*ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0;
		var inputs = [specificationsArrayRef, input, freqscale, freqoffset, decayscale].flop;
		^inputs.collect { arg item; this.ar1(*item) }.unbubble
	}
	
	*ar1 { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0;
		var spec = specificationsArrayRef.value;
		^Ringz.ar(
				input,
				spec[0] ? #[440.0] * freqscale + freqoffset, 
				spec[2] ? #[1.0] * decayscale,
				spec[1] ? #[1.0]
		).sum
	}
}

DynKlang : UGen {
	
	*ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0;
		var inputs = [specificationsArrayRef, freqscale, freqoffset].flop;
		^inputs.collect { arg item; this.ar1(*item) }.unbubble
	}

	*ar1 { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0;
		var spec = specificationsArrayRef.value;
		^SinOsc.ar(
				spec[0] ? #[440.0] * freqscale + freqoffset, 
				spec[2] ? #[0.0],
				spec[1] ? #[1.0]
		).sum
	}
}

Blip : UGen {	
	*ar { arg freq=440.0, numharm = 200.0, mul = 1.0, add = 0.0;
		^this.multiNew('audio', freq, numharm).madd(mul, add)
	}
}

Saw : UGen {	
	*ar { arg freq=440.0, mul = 1.0, add = 0.0;
		^this.multiNew('audio', freq).madd(mul, add)
	}
}

Pulse : UGen {	
	*ar { arg freq=440.0, width = 0.5, mul = 1.0, add = 0.0;
		^this.multiNew('audio', freq, width).madd(mul, add)
	}
}
