1 module pixelperfectengine.audio.base.osc;
2 
3 import pixelperfectengine.system.etc : clamp;
4 
5 /** 
6  * An oscillator that generates multiple waveform outputs from a single counter, and allows the mixing of them.
7  * Available waveforms:
8  * * sawtooth: The basic output of the counter.
9  * * triangle: Produced from the counter by using the top-bit of the counter to invert the next 16 bits.
10  * * pulse: Produced from the counter with a simple logic of testing the counter against the `pulseWidth` variable.
11  * * sawpulse: Sawtooth and pulse logically AND-ed together
12  * The amounts can be set to minus, this way the output will be inverted.
13  */
14 public struct MultiTapOsc {
15 	///The rate of which the oscillator operates at
16 	protected uint		rate;
17 	///Current state of the oscillator
18 	protected uint		counter;
19 	///Controls the pulse width of the oscillator
20 	public uint			pulseWidth;
21 	///Controls the amount of the sawtooth wave (minus means inverting)
22 	public short		sawAm;
23 	///Controls the amount of the triangle wave (minus means inverting)
24 	public short		triAm;
25 	///Controls the amount of the pulse wave (minus means inverting)
26 	public short		pulseAm;
27 	///Controls the amount of the sawpulse wave (minus means inverting)
28 	public short		sawPulseAm;
29 	/** 
30 	 * Returns the integer output of the oscillator.
31 	 */
32 	int outputI() @nogc @safe pure nothrow {
33 		const int pulseOut = (counter >= pulseWidth ? ushort.max : ushort.min);
34 		const int sawOut = (counter >> 16);
35 		const int triOut = (counter >> 15 ^ (sawOut & 0x80_00 ? ushort.max : ushort.min) & ushort.max);
36 		counter += rate;
37 		return (((pulseOut + short.min) * pulseAm)>>15) + (((sawOut + short.min) * pulseAm)>>15) + 
38 				(((triOut + short.min) * triAm)>>15) + ((((sawOut & pulseOut) + short.min) * sawPulseAm)>>15);
39 	}
40 	/** 
41 	 * Returns the floating point output of the oscillator
42 	 * Params:
43 	 *   bias = Offset of the output.
44 	 *   invDiv = Inverse divident to convert to a floating-point scale. Equals with 1/divident.
45 	 */
46 	double outputF(double bias, double invDiv) @nogc @safe pure nothrow {
47 		return (outputI() * invDiv) + bias;
48 	}
49 	/** 
50 	 * Sets the rate of the oscillator
51 	 * Params:
52 	 *   sampleRate = The current sampling frequency.
53 	 *   freq = The frequency to set the oscillator.
54 	 */
55 	void setRate(int sampleRate, double freq) @nogc @safe pure nothrow {
56 		double rateD = freq / (sampleRate / cast(double)(1<<16));
57 		rate = cast(uint)(cast(double)(1<<16) * rateD);
58 	}
59 	void reset() @nogc @safe pure nothrow {
60 		counter = 0;
61 	}
62 }