1 module pixelperfectengine.audio.base.osc; 2 3 import pixelperfectengine.system.etc : clamp; 4 /** 5 * Implements an oscillator base. 6 */ 7 public abstract class Oscillator { 8 protected float _frequency; ///The current frequency of the oscillator 9 protected int _slmpFreq; ///Sampling frequency of the output 10 /** 11 * Returns the sampling frequency set in this oscillator. 12 */ 13 public int slmpFreq() @nogc @safe pure nothrow const { 14 return _slmpFreq; 15 } 16 /** 17 * Sets the sampling frequency of the oscillator. 18 * In devived classes, this might also change the internal state of the oscillator. 19 */ 20 public int slmpFreq(int val) @nogc @safe pure nothrow { 21 return _slmpFreq = val; 22 } 23 /** 24 * Returns the current output frequency of the oscillator. 25 */ 26 public float frequency() @nogc @safe pure nothrow const { 27 return _frequency; 28 } 29 /** 30 * Sets the new frequency of the oscillator. 31 * In devived classes, this might also change the internal state of the oscillator. 32 */ 33 public float frequency(float val) @nogc @safe pure nothrow { 34 return _frequency = val; 35 } 36 37 /** 38 * Generates an output based on the oscillator's internal states. 39 */ 40 public abstract void generate(float[] output) @nogc pure nothrow; 41 } 42 /** 43 * Generates a pulse signal. If set to 0.5, the output will be a perfect square wave. 44 */ 45 public class PulseGen : Oscillator { 46 protected float stepRate = 1; 47 protected float position = 0; 48 public float pulseWidth = 0.5; 49 public this(int _slmpFreq, float _frequency, float pulseWidth) { 50 this._slmpFreq = _slmpFreq; 51 frequency = _frequency; 52 this.pulseWidth = pulseWidth; 53 } 54 public override float frequency(float val) { 55 _frequency = val; 56 stepRate = (1 / _frequency) / _slmpFreq; 57 return _frequency; 58 } 59 public override int slmpFreq(int val) @nogc @safe pure nothrow { 60 _slmpFreq = val; 61 stepRate = (1 / _frequency) / _slmpFreq; 62 return _slmpFreq; 63 } 64 /** 65 * Generates an output based on the oscillator's internal states. 66 */ 67 public override void generate(float[] output) @nogc pure nothrow { 68 for (size_t i ; i < output.length ; i++) { 69 output[i] = position > pulseWidth ? -1 : 1; 70 position += stepRate; 71 position = position >= 1 ? 0 : position; 72 } 73 } 74 } 75 /** 76 * Generates a variable triangle signal. If shape is set to 0.5, a regular triangle wave will be generated. 0 and 1 77 * will generate regular saw waves. Any inbetween values generate asymmetric triangle waves. 78 */ 79 public class TriangleGen : Oscillator { 80 protected float stepRate = 1; 81 protected float position = 0; 82 protected float slopeUp = 2; 83 protected float slopeDown = -2; 84 protected float state = 0; 85 public float shape = 0.5; 86 public this(int _slmpFreq, float _frequency, float shape) { 87 this._slmpFreq = _slmpFreq; 88 frequency = _frequency; 89 this.shape = shape; 90 recalc(); 91 } 92 protected final void recalc() @nogc @safe pure nothrow { 93 stepRate = (1 / _frequency) / _slmpFreq; 94 slopeUp = stepRate * 2 * shape; 95 slopeDown = stepRate * -2 * (1 - shape); 96 } 97 public override float frequency(float val) { 98 _frequency = val; 99 stepRate = (1 / val) / _slmpFreq; 100 recalc(); 101 return _frequency; 102 } 103 public override void generate(float[] output) @nogc pure nothrow { 104 for (size_t i ; i < output.length ; i++) { 105 state += position > shape ? slopeDown : slopeUp; 106 clamp(state, -1, 1); 107 output[i] = state; 108 position += stepRate; 109 position = position >= 1 ? 0 : position; 110 } 111 } 112 }