1 /* aw.cpp
2
3 AlienWah $Revision: 1.11 $
4 LADSPA plugin implementation:
5 Paul Thompson <set@pobox.com> (C) Dec 1, 2001
6 Initial test values:
7 freq: 0.6
8 startphase: 0
9 feedback: 0.5
10 delay: 20
11 */
12
13 #define MAX_DELAY 50
14
15 /* (original sine.cpp sample plugin)
16 Free software by Richard W.E. Furse. Do with as you will. No
17 warranty.
18 */
19
20
21 /* Original effect and demo program:
22 Alien-Wah by Nasca Octavian Paul from Tg. Mures, Romania
23 e-mail: <paulnasca@email.ro> or <paulnasca@yahoo.com>.
24
25 Copyright (C) 2001 Nasca Octavian Paul
26
27 This program is free software; you can redistribute it and/or
28 modify it under the terms of the GNU General Public License as
29 published by the Free Software Foundation; either version 2 of
30 the License, or (at your option) any later version.
31
32 This program is distributed in the hope that it will be
33 useful, but WITHOUT ANY WARRANTY; without even the implied
34 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
35 See the GNU General Public License for more details.
36
37 You should have received a copy of the GNU General Public
38 License along with this program; if not, write to the Free
39 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
40 02111 USA
41
42 The algorithm was found by me by mistake(I was looking for
43 something else); I c alled this effect "Alien Wah" because sounds
44 a bit like wahwah, but more strange . The ideea of this effect
45 is very simple: It is a feedback delay who uses comple x numbers.
46 If x[] represents the input and y[] is the output, so a simple
47 feedback delay l ooks like this: y[n]=y[n-delay]*fb+x[n]*(1-fb)
48 'fb' is a real number between 0 and 1. If you change the fb with
49 a complex number who has the MODULUS smaller than 1, it will look
50 like this.
51
52 fb=R*(cos(alpha)+i*sin(alpha)); i^2=-1; R<1;
53 y[n]=y[n-delay]*R*(cos(alpha)+i*sin(alpha))+x[n]*(1-R);
54
55 alpha is the phase of the number and is controlled by the
56 LFO(Low Frequency Osc illator). If the 'delay' parameter is low,
57 the effect sounds more like wah-wah, but if it is big, the effect
58 will sound very interesting. The input x[n] has the real part of
59 the samples from the wavefile and the imagi nary part is zero.
60 The output of this effect is the real part of y[n].
61 */
62
63 /*****************************************************************************/
64
65 #include <cmath>
66 #include <complex>
67 #include <cstdlib>
68 #include <cstring>
69 #include <cstdio>
70
71 /*****************************************************************************/
72
73 #include "ladspa.h"
74
75 /*****************************************************************************/
76
77 /* The port numbers for the plugin: */
78
79 #define AW_FREQ 0
80 #define AW_STARTPHASE 1
81 #define AW_FEEDBACK 2
82 #define AW_DELAY 3
83 #define AW_INPUT1 4
84 #define AW_OUTPUT1 5
85 #define AW_INPUT2 6
86 #define AW_OUTPUT2 7
87
88 #define AW_NUMPORTS 8
89
90 /*****************************************************************************/
91 /* Make number of samples represented by 'delay' proportional to
92 * the sample rate, such that delay=1 is 1 sample buffer at
93 * 44100hz
94 */
95 #define NORM (1.0 / 44100.0)
96 #define PI (3.141592653589)
97 /*****************************************************************************/
98
99 class AW {
100 private:
101
102 // should this be a constant?
103 #define LFO_SKIPSAMPLES 25
104
105 // TODO promote all floats to double, even tho ladspa is floaty?
106 /* Ports */
107 LADSPA_Data lfreq;
108 LADSPA_Data lstartphase;
109 LADSPA_Data lfeedback;
110 LADSPA_Data ldelay;
111 LADSPA_Data * i_buf;
112 LADSPA_Data * o_buf;
113 LADSPA_Data * i_buf2;
114 LADSPA_Data * o_buf2;
115
116 /* State */
117 bool inited;
118 unsigned long samplerate;
119 unsigned long t; //??
120 unsigned long t2; //??
121 unsigned long k; // index for delaybuf
122 unsigned long k2; // index for delaybuf2
123 std::complex<float> * delaybuf;
124 std::complex<float> * delaybuf2;
125 std::complex<float> c; //??
126 std::complex<float> c2; //??
127 float freq;
128 float startphase;
129 float feedback;
130 unsigned int delay;
131
132 /*
133 * class constructor
134 */
AW(const long lSampleRate)135 AW(const long lSampleRate) :
136 inited(false),
137 samplerate(lSampleRate),
138 t(0), t2(0),
139 k(0), k2(0),
140 c(std::complex<float>(0,0)),
141 c2(std::complex<float>(0,0)) {
142 }
143
144 friend LADSPA_Handle instantiateAW(const LADSPA_Descriptor *,
145 unsigned long SampleRate);
146 friend void connectPortToAW(LADSPA_Handle instance, unsigned long port,
147 LADSPA_Data * datalocation);
148 friend void activateAW(void * pvHandle);
149 friend void runAW_Mono(LADSPA_Handle instance, unsigned long samplecount);
150 friend void runAW_Stereo(LADSPA_Handle instance, unsigned long samplecount);
151 friend void cleanupAW(void *pvHandle);
152
153 /*
154 * Munge some things based upon the settings passed. Set
155 * initial state.
156 */
initState(int chans)157 void initState(int chans) {
158 inited = true;
159 freq = (float)lfreq;
160 feedback = ((float)lfeedback)/4 + 0.74; // whyfor?
161 if (feedback>0.999) feedback=0.999;
162 if (ldelay < 0) ldelay = 1;
163 // swh I think this is wrong delay = (unsigned int) (ldelay * samplerate * NORM);
164 delay = (unsigned int) ldelay;
165 printf("delay %d\n", delay);
166 if (delay < 1) delay = 1;
167 if (delay > MAX_DELAY) delay = MAX_DELAY;
168 delaybuf = new std::complex<float>[delay];
169 if (chans == 2) {
170 delaybuf2 = new std::complex<float>[MAX_DELAY+1];
171 }
172 for (unsigned int i =0; i<delay; ++i) {
173 delaybuf[i] = std::complex<float>(0,0);
174 }
175 }
176
177 };
178
179
180 /*
181 * simply calls the constructor
182 */
instantiateAW(const LADSPA_Descriptor *,unsigned long SampleRate)183 LADSPA_Handle instantiateAW(const LADSPA_Descriptor *,
184 unsigned long SampleRate)
185 {
186 return new AW(SampleRate);
187 }
188
189 /*
190 * get all the pointers to our ports data
191 */
connectPortToAW(LADSPA_Handle instance,unsigned long port,LADSPA_Data * datalocation)192 void connectPortToAW(LADSPA_Handle instance, unsigned long port,
193 LADSPA_Data * datalocation)
194 {
195 switch (port) {
196 case AW_FREQ:
197 ((AW *)instance)->lfreq = *datalocation;
198 break;
199 case AW_STARTPHASE:
200 ((AW *)instance)->lstartphase = *datalocation;
201 break;
202 case AW_FEEDBACK:
203 ((AW *)instance)->lfeedback = *datalocation;
204 break;
205 case AW_DELAY:
206 ((AW *)instance)->ldelay = *datalocation;
207 break;
208 case AW_INPUT1:
209 ((AW *)instance)->i_buf = datalocation;
210 case AW_OUTPUT1:
211 ((AW*)instance)->o_buf = datalocation;
212 case AW_INPUT2:
213 ((AW *)instance)->i_buf2 = datalocation;
214 case AW_OUTPUT2:
215 ((AW*)instance)->o_buf2 = datalocation;
216 }
217 }
218
219 /*
220 * connect_port may be called before of after here, so we
221 * cannot rely upon port data for initialization
222 */
activateAW(void * pvHandle)223 void activateAW(void * pvHandle)
224 {
225 }
226
227 /*
228 * Mono effect
229 * Do the effect. 'i_buf' is transformed into 'o_buf'
230 */
runAW_Mono(LADSPA_Handle instance,unsigned long samplecount)231 void runAW_Mono(LADSPA_Handle instance, unsigned long samplecount)
232 {
233 AW * me = (AW *)instance;
234 float lfo;
235 std::complex<float> outc;
236 float lfoskip = me->freq * 2 * PI / me->samplerate;
237
238 if (! me->inited) me->initState(1);
239
240 for(unsigned int i=0; i<samplecount; ++i) {
241 if ((me->t++ % LFO_SKIPSAMPLES) == 0) {
242 lfo = 1 + cos(me->t * lfoskip + me->startphase);
243 me->c = std::complex<float>(cos(lfo) * me->feedback,
244 sin(lfo) * me->feedback);
245 }
246 outc = me->c * me->delaybuf[me->k] + (1 - me->feedback) *
247 me->i_buf[i];
248 me->delaybuf[me->k] = outc;
249 if (++(me->k) >= me->delay) me->k=0;
250 me->o_buf[i] = real(outc)*3;
251 }
252 }
253
254 /*
255 * Stereo effect?
256 */
runAW_Stereo(LADSPA_Handle instance,unsigned long samplecount)257 void runAW_Stereo(LADSPA_Handle instance, unsigned long samplecount)
258 {
259 AW * me = (AW *)instance;
260 float lfo;
261 std::complex<float> outc;
262 float lfoskip = me->freq * 2 * PI / me->samplerate;
263
264 if (! me->inited) me->initState(2);
265
266 for(unsigned int i=0; i<samplecount; ++i) {
267 if ((me->t++ % LFO_SKIPSAMPLES) == 0) {
268 lfo = 1 + cos(me->t * lfoskip + me->startphase);
269 me->c = std::complex<float>(cos(lfo) * me->feedback,
270 sin(lfo) * me->feedback);
271 }
272 outc = me->c * me->delaybuf[me->k] + (1 - me->feedback) *
273 me->i_buf[i];
274 me->delaybuf[me->k] = outc;
275 if (++(me->k) >= me->delay) me->k=0;
276 me->o_buf[i] = real(outc)*3;
277 }
278
279 for(unsigned int i=0; i<samplecount; ++i) {
280 if ((me->t2++ % LFO_SKIPSAMPLES) == 0) {
281 lfo = 1 + cos(me->t2 * lfoskip);
282 me->c2 = std::complex<float>(cos(lfo) * me->feedback,
283 sin(lfo) * me->feedback);
284 }
285 outc = me->c2 * me->delaybuf2[me->k2] + (1 - me->feedback) *
286 me->i_buf2[i];
287 me->delaybuf2[me->k2] = outc;
288 if (++(me->k2) >= me->delay) me->k2=0;
289 me->o_buf2[i] = real(outc)*3;
290 }
291 }
292
cleanupAW(void * pvHandle)293 void cleanupAW(void *pvHandle)
294 {
295 delete (AW *)pvHandle;
296 }
297
298 /*****************************************************************************/
299
300 typedef char * char_ptr;
301
302 LADSPA_Descriptor * desc[2] = { NULL, NULL };
303
304 /*****************************************************************************/
305
306 /* Global object used handle startup initialisation and shut down
307 tidying. Performs the function of the _init() and _fini() calls in
308 the C modules. */
309 class StartupShutdownHandler {
310 public:
311
StartupShutdownHandler()312 StartupShutdownHandler() {
313
314 char ** pnames = NULL;
315 LADSPA_PortDescriptor * portdesc = NULL;
316 LADSPA_PortRangeHint * rangehints = NULL;
317
318 for (long plug = 0; plug < 2; plug++) {
319
320 desc[plug] = new LADSPA_Descriptor;
321 if (desc[plug] == NULL)
322 break;
323
324 /* generic */
325 desc[plug]->UniqueID
326 = 1561 + plug;
327 desc[plug]->Properties
328 = LADSPA_PROPERTY_HARD_RT_CAPABLE;
329 desc[plug]->Maker
330 = strdup("Plugin: Paul<set@pobox.com> Effect: Nasca O. Paul<paulnasca@yahoo.com>");
331 desc[plug]->Copyright
332 = strdup("GPL");
333 desc[plug]->instantiate
334 = instantiateAW;
335 desc[plug]->connect_port
336 = connectPortToAW;
337 desc[plug]->activate
338 = activateAW;
339 desc[plug]->run_adding
340 = NULL;
341 desc[plug]->set_run_adding_gain
342 = NULL;
343 desc[plug]->deactivate
344 = NULL;
345 desc[plug]->cleanup
346 = cleanupAW;
347
348 /* specific */
349 switch (plug) {
350 case 0: /* Mono */
351 desc[plug]->Label
352 = strdup("alienwah_mono");
353 desc[plug]->Name
354 = strdup("AlienWah for mono");
355 desc[plug]->run
356 = runAW_Mono;
357 desc[plug]->PortCount
358 = 6;
359 portdesc
360 = new LADSPA_PortDescriptor[AW_NUMPORTS];
361 desc[plug]->PortDescriptors
362 = (const LADSPA_PortDescriptor *)portdesc;
363 portdesc[AW_FREQ]
364 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
365 portdesc[AW_STARTPHASE]
366 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
367 portdesc[AW_FEEDBACK]
368 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
369 portdesc[AW_DELAY]
370 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
371 portdesc[AW_INPUT1]
372 = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
373 portdesc[AW_OUTPUT1]
374 = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
375 pnames
376 = new char_ptr[AW_NUMPORTS];
377 desc[plug]->PortNames
378 = (const char **)pnames;
379 pnames[AW_FREQ]
380 = strdup("Frequency (Hz)");
381 pnames[AW_STARTPHASE]
382 = strdup("Initial phase for stereo (radians)");
383 pnames[AW_FEEDBACK]
384 = strdup("Feedback");
385 pnames[AW_DELAY]
386 = strdup("Delay (samples)");
387 pnames[AW_INPUT1]
388 = strdup("Input");
389 pnames[AW_OUTPUT1]
390 = strdup("Output");
391
392 /* range hints */
393 rangehints
394 = new LADSPA_PortRangeHint[AW_NUMPORTS];
395 desc[plug]->PortRangeHints
396 = (const LADSPA_PortRangeHint *)rangehints;
397
398 rangehints[AW_FREQ].HintDescriptor
399 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_SAMPLE_RATE;
400 rangehints[AW_FREQ].LowerBound
401 = 0;
402
403 rangehints[AW_STARTPHASE].HintDescriptor = 0;
404
405 rangehints[AW_FEEDBACK].HintDescriptor
406 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
407 rangehints[AW_FEEDBACK].LowerBound
408 = 0;
409 rangehints[AW_FEEDBACK].UpperBound
410 = 1.0;
411
412 rangehints[AW_DELAY].HintDescriptor
413 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE |
414 LADSPA_HINT_INTEGER;
415 rangehints[AW_DELAY].LowerBound
416 = 5;
417 rangehints[AW_DELAY].UpperBound
418 = 50;
419
420 rangehints[AW_INPUT1].HintDescriptor = 0;
421 rangehints[AW_INPUT2].HintDescriptor = 0;
422 break;
423
424 case 1: /* Stereo */
425 desc[plug]->Label
426 = strdup("alienwah_stereo");
427 desc[plug]->Name
428 = strdup("AlienWah for stereo");
429 desc[plug]->run
430 = runAW_Stereo;
431
432 desc[plug]->PortCount
433 = 8;
434 portdesc
435 = new LADSPA_PortDescriptor[AW_NUMPORTS];
436 desc[plug]->PortDescriptors
437 = (const LADSPA_PortDescriptor *)portdesc;
438 portdesc[AW_FREQ]
439 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
440 portdesc[AW_STARTPHASE]
441 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
442 portdesc[AW_FEEDBACK]
443 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
444 portdesc[AW_DELAY]
445 = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
446 portdesc[AW_INPUT2]
447 = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
448 portdesc[AW_OUTPUT2]
449 = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
450 portdesc[AW_INPUT1]
451 = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
452 portdesc[AW_OUTPUT1]
453 = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
454 pnames
455 = new char_ptr[AW_NUMPORTS];
456 desc[plug]->PortNames
457 = (const char **)pnames;
458 pnames[AW_FREQ]
459 = strdup("Frequency (Hz)");
460 pnames[AW_STARTPHASE]
461 = strdup("Initial phase for stereo (radians)");
462 pnames[AW_FEEDBACK]
463 = strdup("Feedback");
464 pnames[AW_DELAY]
465 = strdup("Delay (samples)");
466 pnames[AW_INPUT1]
467 = strdup("Input1");
468 pnames[AW_OUTPUT1]
469 = strdup("Output1");
470 pnames[AW_INPUT2]
471 = strdup("Input2");
472 pnames[AW_OUTPUT2]
473 = strdup("Output2");
474
475 /* range hints */
476 rangehints
477 = new LADSPA_PortRangeHint[AW_NUMPORTS];
478 desc[plug]->PortRangeHints
479 = (const LADSPA_PortRangeHint *)rangehints;
480
481 rangehints[AW_FREQ].HintDescriptor
482 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_SAMPLE_RATE;
483 rangehints[AW_FREQ].LowerBound
484 = 0;
485
486 rangehints[AW_STARTPHASE].HintDescriptor
487 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
488 rangehints[AW_STARTPHASE].LowerBound
489 = 0;
490 rangehints[AW_STARTPHASE].LowerBound
491 = PI * 2.0;
492
493 rangehints[AW_FEEDBACK].HintDescriptor
494 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
495 rangehints[AW_FEEDBACK].LowerBound
496 = 0;
497 rangehints[AW_FEEDBACK].UpperBound
498 = 2.0;
499
500 rangehints[AW_DELAY].HintDescriptor
501 = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE |
502 LADSPA_HINT_INTEGER;
503 rangehints[AW_DELAY].LowerBound
504 = 5;
505 rangehints[AW_DELAY].UpperBound
506 = 50;
507
508 rangehints[AW_INPUT1].HintDescriptor = 0;
509 rangehints[AW_INPUT2].HintDescriptor = 0;
510 rangehints[AW_OUTPUT1].HintDescriptor = 0;
511 rangehints[AW_OUTPUT2].HintDescriptor = 0;
512 break;
513 }
514
515 }
516 }
517
deleteDescriptor(LADSPA_Descriptor * psDescriptor)518 void deleteDescriptor(LADSPA_Descriptor * psDescriptor) {
519 unsigned long lIndex;
520 if (psDescriptor) {
521 delete [] psDescriptor->Label;
522 delete [] psDescriptor->Name;
523 delete [] psDescriptor->Maker;
524 delete [] psDescriptor->Copyright;
525 delete [] psDescriptor->PortDescriptors;
526 for (lIndex = 0; lIndex < psDescriptor->PortCount; lIndex++)
527 delete [] psDescriptor->PortNames[lIndex];
528 delete [] psDescriptor->PortNames;
529 delete [] psDescriptor->PortRangeHints;
530 delete psDescriptor;
531 }
532 }
533
~StartupShutdownHandler()534 ~StartupShutdownHandler() {
535 deleteDescriptor(desc[0]);
536 deleteDescriptor(desc[1]);
537 }
538
539 } g_oShutdownStartupHandler;
540
541 /*****************************************************************************/
542
543 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)544 ladspa_descriptor(unsigned long Index) {
545 if (Index < 2)
546 return desc[Index];
547 else
548 return NULL;
549 }
550
551 /*****************************************************************************/
552
553 /* EOF */
554