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 }