1 /*
2 Copyright 2008-2011 David Robillard <http://drobilla.net>
3 Copyright 1999-2000 Paul Kellett (Maxim Digital Audio)
4
5 This is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 This software is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this software. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "mdaDetune.h"
20
21 #include <cmath>
22 #include <cstdio>
23 #include <cstring>
24
createEffectInstance(audioMasterCallback audioMaster)25 AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
26 {
27 return new mdaDetune(audioMaster);
28 }
29
getProductString(char * text)30 bool mdaDetune::getProductString(char* text) { strcpy(text, "mda Detune"); return true; }
getVendorString(char * text)31 bool mdaDetune::getVendorString(char* text) { strcpy(text, "mda"); return true; }
getEffectName(char * name)32 bool mdaDetune::getEffectName(char* name) { strcpy(name, "Detune"); return true; }
33
mdaDetune(audioMasterCallback audioMaster)34 mdaDetune::mdaDetune(audioMasterCallback audioMaster): AudioEffectX(audioMaster, NPROGS, NPARAMS)
35 {
36 setNumInputs(2);
37 setNumOutputs(2);
38 setUniqueID("mdaDetune"); ///identify mdaDetune-in here
39 DECLARE_LVZ_DEPRECATED(canMono) ();
40 canProcessReplacing();
41
42 programs[0].param[0] = 0.20f; //fine
43 programs[0].param[1] = 0.90f; //mix
44 programs[0].param[2] = 0.50f; //output
45 programs[0].param[3] = 0.50f; //chunksize
46 strcpy(programs[0].name, "Stereo Detune");
47 programs[1].param[0] = 0.20f;
48 programs[1].param[1] = 0.90f;
49 programs[1].param[2] = 0.50f;
50 programs[1].param[3] = 0.50f;
51 strcpy(programs[1].name,"Symphonic");
52 programs[2].param[0] = 0.8f;
53 programs[2].param[1] = 0.7f;
54 programs[2].param[2] = 0.50f;
55 programs[2].param[3] = 0.50f;
56 strcpy(programs[2].name,"Out Of Tune");
57
58 ///initialise...
59 curProgram=0;
60 suspend();
61
62 semi = 3.0f * 0.20f * 0.20f * 0.20f;
63 dpos2 = (float)pow(1.0594631f, semi);
64 dpos1 = 1.0f / dpos2;
65 wet = 1.0f;
66 dry = wet - wet * 0.90f * 0.90f;
67 wet = (wet + wet - wet * 0.90f) * 0.90f;
68 }
69
suspend()70 void mdaDetune::suspend() ///clear any buffers...
71 {
72 memset(buf, 0, sizeof (buf));
73 memset(win, 0, sizeof (win));
74 pos0 = 0; pos1 = pos2 = 0.0f;
75
76 //recalculate crossfade window
77 buflen = 1 << (8 + (int32_t)(4.9f * programs[curProgram].param[3]));
78 if (buflen > BUFMAX) buflen = BUFMAX;
79 bufres = 1000.0f * (float)buflen / getSampleRate();
80
81 int32_t i; //hanning half-overlap-and-add
82 double p=0.0, dp=6.28318530718/buflen;
83 for(i=0;i<buflen;i++) { win[i] = (float)(0.5 - 0.5 * cos(p)); p+=dp; }
84 }
85
86
setProgram(int32_t program)87 void mdaDetune::setProgram(int32_t program)
88 {
89 if ((unsigned int)program < NPROGS)
90 {
91 curProgram = program;
92
93 // update
94 float * param = programs[curProgram].param;
95 semi = 3.0f * param[0] * param[0] * param[0];
96 dpos2 = (float)pow(1.0594631f, semi);
97 dpos1 = 1.0f / dpos2;
98
99 wet = (float)pow(10.0f, 2.0f * param[2] - 1.0f);
100 dry = wet - wet * param[1] * param[1];
101 wet = (wet + wet - wet * param[1]) * param[1];
102
103 int32_t tmp = 1 << (8 + (int32_t)(4.9f * param[3]));
104
105 if(tmp!=buflen) //recalculate crossfade window
106 {
107 buflen = tmp;
108 if (buflen > BUFMAX) buflen = BUFMAX;
109 bufres = 1000.0f * (float)buflen / getSampleRate();
110
111 int32_t i; //hanning half-overlap-and-add
112 double p=0.0, dp=6.28318530718/buflen;
113 for(i=0;i<buflen;i++) { win[i] = (float)(0.5 - 0.5 * cos(p)); p+=dp; }
114 }
115 }
116 }
117
118
setParameter(int32_t which,float value)119 void mdaDetune::setParameter(int32_t which, float value)
120 {
121 float * param = programs[curProgram].param;
122 param[which] = value;
123
124 switch(which)
125 {
126 case 0:
127 semi = 3.0f * param[0] * param[0] * param[0];
128 dpos2 = (float)pow(1.0594631f, semi);
129 dpos1 = 1.0f / dpos2;
130 break;
131 case 1:
132 case 2:
133 wet = (float)pow(10.0f, 2.0f * param[2] - 1.0f);
134 dry = wet - wet * param[1] * param[1];
135 wet = (wet + wet - wet * param[1]) * param[1];
136 break;
137 case 3:
138 {
139 int32_t tmp = 1 << (8 + (int32_t)(4.9f * param[3]));
140
141 if(tmp!=buflen) //recalculate crossfade window
142 {
143 buflen = tmp;
144 if (buflen > BUFMAX) buflen = BUFMAX;
145 bufres = 1000.0f * (float)buflen / getSampleRate();
146
147 int32_t i; //hanning half-overlap-and-add
148 double p=0.0, dp=6.28318530718/buflen;
149 for(i=0;i<buflen;i++) { win[i] = (float)(0.5 - 0.5 * cos(p)); p+=dp; }
150 }
151 break;
152 }
153 default:
154 break;
155 }
156 }
157
158
getParameter(int32_t which)159 float mdaDetune::getParameter(int32_t which) { return programs[curProgram].param[which]; }
setProgramName(char * name)160 void mdaDetune::setProgramName(char *name) { strcpy(programs[curProgram].name, name); }
getProgramName(char * name)161 void mdaDetune::getProgramName(char *name) { strcpy(name, programs[curProgram].name); }
getProgramNameIndexed(int32_t category,int32_t which,char * name)162 bool mdaDetune::getProgramNameIndexed (int32_t category, int32_t which, char* name)
163 {
164 if ((unsigned int)which < NPROGS)
165 {
166 strcpy(name, programs[which].name);
167 return true;
168 }
169 return false;
170 }
171
172
getParameterName(int32_t which,char * label)173 void mdaDetune::getParameterName(int32_t which, char *label)
174 {
175 switch(which)
176 {
177 case 0: strcpy(label, "Detune"); break;
178 case 1: strcpy(label, "Mix"); break;
179 case 2: strcpy(label, "Output"); break;
180 default: strcpy(label, "Latency");
181 }
182 }
183
184
getParameterDisplay(int32_t which,char * text)185 void mdaDetune::getParameterDisplay(int32_t which, char *text)
186 {
187 char string[16];
188
189 switch(which)
190 {
191 case 1: sprintf(string, "%.0f", 99.0f * programs[curProgram].param[which]); break;
192 case 2: sprintf(string, "%.1f", 40.0f * programs[curProgram].param[which] - 20.0f); break;
193 case 3: sprintf(string, "%.1f", bufres); break;
194 default: sprintf(string, "%.1f", 100.0f * semi);
195 }
196 string[8] = 0;
197 strcpy(text, (char *)string);
198 }
199
200
getParameterLabel(int32_t which,char * label)201 void mdaDetune::getParameterLabel(int32_t which, char *label)
202 {
203 switch(which)
204 {
205 case 0: strcpy(label, "cents"); break;
206 case 1: strcpy(label, "%"); break;
207 case 2: strcpy(label, "dB"); break;
208 default: strcpy(label, "ms");
209 }
210 }
211
212
process(float ** inputs,float ** outputs,int32_t sampleFrames)213 void mdaDetune::process(float **inputs, float **outputs, int32_t sampleFrames)
214 {
215 float *in1 = inputs[0];
216 float *in2 = inputs[1];
217 float *out1 = outputs[0];
218 float *out2 = outputs[1];
219 float a, b, c, d;
220 float x, w=wet, y=dry, p1=pos1, p1f, d1=dpos1;
221 float p2=pos2, d2=dpos2;
222 int32_t p0=pos0, p1i, p2i;
223 int32_t l=buflen-1, lh=buflen>>1;
224 float lf = (float)buflen;
225
226 --in1;
227 --in2;
228 --out1;
229 --out2;
230 while(--sampleFrames >= 0)
231 {
232 a = *++in1;
233 b = *++in2;
234 c = out1[1];
235 d = out2[1];
236
237 c += y * a;
238 d += y * b;
239
240 --p0 &= l;
241 *(buf + p0) = w * (a + b); //input
242
243 p1 -= d1;
244 if(p1<0.0f) p1 += lf; //output
245 p1i = (int32_t)p1;
246 p1f = p1 - (float)p1i;
247 a = *(buf + p1i);
248 ++p1i &= l;
249 a += p1f * (*(buf + p1i) - a); //linear interpolation
250
251 p2i = (p1i + lh) & l; //180-degree ouptut
252 b = *(buf + p2i);
253 ++p2i &= l;
254 b += p1f * (*(buf + p2i) - b); //linear interpolation
255
256 p2i = (p1i - p0) & l; //crossfade window
257 x = *(win + p2i);
258 //++p2i &= l;
259 //x += p1f * (*(win + p2i) - x); //linear interpolation (doesn't do much)
260 c += b + x * (a - b);
261
262 p2 -= d2; //repeat for downwards shift - can't see a more efficient way?
263 if(p2<0.0f) p2 += lf; //output
264 p1i = (int32_t)p2;
265 p1f = p2 - (float)p1i;
266 a = *(buf + p1i);
267 ++p1i &= l;
268 a += p1f * (*(buf + p1i) - a); //linear interpolation
269
270 p2i = (p1i + lh) & l; //180-degree ouptut
271 b = *(buf + p2i);
272 ++p2i &= l;
273 b += p1f * (*(buf + p2i) - b); //linear interpolation
274
275 p2i = (p1i - p0) & l; //crossfade window
276 x = *(win + p2i);
277 //++p2i &= l;
278 //x += p1f * (*(win + p2i) - x); //linear interpolation (doesn't do much)
279 d += b + x * (a - b);
280
281 *++out1 = c;
282 *++out2 = d;
283 }
284 pos0=p0; pos1=p1; pos2=p2;
285 }
286
287
processReplacing(float ** inputs,float ** outputs,int32_t sampleFrames)288 void mdaDetune::processReplacing(float **inputs, float **outputs, int32_t sampleFrames)
289 {
290 float *in1 = inputs[0];
291 float *in2 = inputs[1];
292 float *out1 = outputs[0];
293 float *out2 = outputs[1];
294 float a, b, c, d;
295 float x, w=wet, y=dry, p1=pos1, p1f, d1=dpos1;
296 float p2=pos2, d2=dpos2;
297 int32_t p0=pos0, p1i, p2i;
298 int32_t l=buflen-1, lh=buflen>>1;
299 float lf = (float)buflen;
300
301 --in1;
302 --in2;
303 --out1;
304 --out2;
305 while(--sampleFrames >= 0) //had to disable optimization /Og in MSVC++5!
306 {
307 a = *++in1;
308 b = *++in2;
309
310 c = y * a;
311 d = y * b;
312
313 --p0 &= l;
314 *(buf + p0) = w * (a + b); //input
315
316 p1 -= d1;
317 if(p1<0.0f) p1 += lf; //output
318 p1i = (int32_t)p1;
319 p1f = p1 - (float)p1i;
320 a = *(buf + p1i);
321 ++p1i &= l;
322 a += p1f * (*(buf + p1i) - a); //linear interpolation
323
324 p2i = (p1i + lh) & l; //180-degree ouptut
325 b = *(buf + p2i);
326 ++p2i &= l;
327 b += p1f * (*(buf + p2i) - b); //linear interpolation
328
329 p2i = (p1i - p0) & l; //crossfade
330 x = *(win + p2i);
331 //++p2i &= l;
332 //x += p1f * (*(win + p2i) - x); //linear interpolation (doesn't do much)
333 c += b + x * (a - b);
334
335 p2 -= d2; //repeat for downwards shift - can't see a more efficient way?
336 if(p2<0.0f) p2 += lf; //output
337 p1i = (int32_t)p2;
338 p1f = p2 - (float)p1i;
339 a = *(buf + p1i);
340 ++p1i &= l;
341 a += p1f * (*(buf + p1i) - a); //linear interpolation
342
343 p2i = (p1i + lh) & l; //180-degree ouptut
344 b = *(buf + p2i);
345 ++p2i &= l;
346 b += p1f * (*(buf + p2i) - b); //linear interpolation
347
348 p2i = (p1i - p0) & l; //crossfade
349 x = *(win + p2i);
350 //++p2i &= l;
351 //x += p1f * (*(win + p2i) - x); //linear interpolation (doesn't do much)
352 d += b + x * (a - b);
353
354 *++out1 = c;
355 *++out2 = d;
356 }
357 pos0=p0; pos1=p1; pos2=p2;
358 }
359