1 /** 2 * Copyright 2017 Cut Through Recordings 3 * License: MIT License 4 * Author(s): Ethan Reker 5 */ 6 module ddsp.effect.moddelay; 7 8 import ddsp.effect.effect; 9 import ddsp.osc.wtoscillator; 10 import ddsp.effect.digitaldelay; 11 import ddsp.util.memory; 12 13 import std.math; 14 15 import std.algorithm : max; 16 17 /// General purpose class for Modulated Delay effects. This class is used with 18 /// contraints on depth, offset, mix, and feedback to create other effects. (Flanger, Chorus, Tremolo, etc) 19 class ModDelay(T) : AudioEffect!T 20 { 21 public: 22 nothrow: 23 @nogc: 24 25 this() 26 { 27 lfo = calloc!(WTOscillator!T).init(); 28 delay = calloc!(DigitalDelay!T).init(); 29 } 30 31 override void setSampleRate(float sampleRate) 32 { 33 _sampleRate = sampleRate; 34 lfo.setSampleRate(sampleRate); 35 delay.setSampleRate(sampleRate); 36 } 37 38 float calcDelayOffset(float lfoValue) 39 { 40 float startDelay = _min_delay + _delay_offset; 41 float lfoOffset = _mod_depth * ((lfoValue + 1) / 2 * (_max_delay - _min_delay)) + _min_delay; 42 return max(lfoOffset + startDelay, 0); 43 } 44 45 /// Must be set before processing audio 46 void setDelayRange(float minDelay, float maxDelay) 47 { 48 _min_delay = minDelay; 49 _max_delay = maxDelay; 50 } 51 52 void setParams(float rate, float depth, float mix, float feedback, int offset, int modType = 0) 53 { 54 _mod_rate = rate; 55 _mod_depth = depth; 56 _delay_offset = offset; 57 _feedback = feedback; 58 _mix = mix; 59 60 //Frequency, sin, not bandlimited 61 lfo.setParams(rate, modType, true); 62 delay.setParams(0, feedback, mix); 63 } 64 65 override T getNextSample(const T input) 66 { 67 float fYn = 0.0; 68 float fYqn = 0.0; 69 lfo.doOscillate(&fYn, &fYqn); 70 71 float delaySamples = calcDelayOffset(fYn); 72 delay.setParams(delaySamples, _feedback, _mix); 73 74 float output = delay.getNextSample(input); 75 76 return output; 77 } 78 79 override void reset() 80 { 81 lfo.reset(); 82 delay.reset(); 83 } 84 private: 85 float _mod_rate; 86 float _mod_depth; 87 float _mix; 88 float _feedback; 89 float _delay_offset; 90 91 float _max_delay; 92 float _min_delay; 93 94 WTOscillator!T lfo; 95 DigitalDelay!T delay; 96 } 97 98 unittest 99 { 100 ModDelay!float modDelay = new ModDelay!float(); 101 } 102 103 class Flanger(T) : AudioEffect!T 104 { 105 public: 106 nothrow: 107 @nogc: 108 109 this() 110 { 111 _modDelay = calloc!(ModDelay!T).init(); 112 } 113 114 override void setSampleRate(float sampleRate) 115 { 116 _sampleRate = sampleRate; 117 _modDelay.setSampleRate(_sampleRate); 118 _modDelay.setDelayRange(0, 7); 119 } 120 121 void setParams(float modRate, float modDepth, int oscType = 0) 122 { 123 _modDelay.setParams(modRate, modDepth, 0.5, 0.5, 0, oscType); 124 } 125 126 override float getNextSample(const float input) 127 { 128 return _modDelay.getNextSample(input); 129 } 130 131 override void reset() 132 { 133 _modDelay.reset(); 134 } 135 136 private: 137 ModDelay!T _modDelay; 138 } 139 140 unittest 141 { 142 Flanger!float flanger = new Flanger!float(); 143 } 144 145 class Vibrato(T) : AudioEffect!T 146 { 147 public: 148 nothrow: 149 @nogc: 150 151 this() 152 { 153 _modDelay = calloc!(ModDelay!T).init(); 154 } 155 156 override void setSampleRate(float sampleRate) 157 { 158 _sampleRate = sampleRate; 159 _modDelay.setSampleRate(_sampleRate); 160 _modDelay.setDelayRange(0, 7); 161 } 162 163 void setParams(float modRate, float modDepth, int oscType = 0) 164 { 165 _modDelay.setParams(modRate, modDepth, 1.0, 0.0, 0, oscType); 166 } 167 168 override T getNextSample(const T input) 169 { 170 return _modDelay.getNextSample(input); 171 } 172 173 override void reset() 174 { 175 _modDelay.reset(); 176 } 177 178 private: 179 ModDelay!T _modDelay; 180 } 181 182 unittest 183 { 184 Vibrato!float vibrato = new Vibrato!float(); 185 } 186 187 class Chorus(T) : AudioEffect!T 188 { 189 public: 190 nothrow: 191 @nogc: 192 193 this() 194 { 195 _modDelay = calloc!(ModDelay!T).init(); 196 } 197 198 override void setSampleRate(float sampleRate) 199 { 200 _sampleRate = sampleRate; 201 _modDelay.setSampleRate(_sampleRate); 202 _modDelay.setDelayRange(5, 30); 203 } 204 205 void setParams(float modRate, float modDepth, int oscType = 0) 206 { 207 _modDelay.setParams(modRate, modDepth, 0.5, 0.0, 0, oscType); 208 } 209 210 override T getNextSample(const T input) 211 { 212 return _modDelay.getNextSample(input); 213 } 214 215 override void reset() 216 { 217 _modDelay.reset(); 218 } 219 220 private: 221 ModDelay!T _modDelay; 222 } 223 224 unittest 225 { 226 Chorus!float chorus = new Chorus!float(); 227 }