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