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