Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
6.7KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Alienwah.cpp - "AlienWah" effect
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include <cmath>
  12. #include <rtosc/port-sugar.h>
  13. #include <rtosc/ports.h>
  14. #include "../Misc/Allocator.h"
  15. #include "Alienwah.h"
  16. using std::complex;
  17. #define rObject Alienwah
  18. #define rBegin [](const char *msg, rtosc::RtData &d) {
  19. #define rEnd }
  20. rtosc::Ports Alienwah::ports = {
  21. {"preset::i", rProp(parameter)
  22. rOptions(wah 1, wah 2, wah 3, wah 4)
  23. rDoc("Instrument Presets"), 0,
  24. rBegin;
  25. rObject *o = (rObject*)d.obj;
  26. if(rtosc_narguments(msg))
  27. o->setpreset(rtosc_argument(msg, 0).i);
  28. else
  29. d.reply(d.loc, "i", o->Ppreset);
  30. rEnd},
  31. //Pvolume/Ppanning are common
  32. rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
  33. rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
  34. rEffPar(PLFOtype, 4, rShort("shape"),
  35. rOptions(sine, triangle), "LFO Shape"),
  36. rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
  37. rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
  38. rEffPar(Pfeedback, 7, rShort("fb"), "Feedback"),
  39. rEffPar(Pdelay, 8, rLinear(1,100), rShort("delay"), "Delay"),
  40. rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"),
  41. rEffPar(Pphase, 10, rShort("phase"), "Phase"),
  42. };
  43. #undef rBegin
  44. #undef rEnd
  45. #undef rObject
  46. Alienwah::Alienwah(EffectParams pars)
  47. :Effect(pars),
  48. lfo(pars.srate, pars.bufsize),
  49. oldl(NULL),
  50. oldr(NULL)
  51. {
  52. setpreset(Ppreset);
  53. cleanup();
  54. oldclfol = complex<float>(fb, 0.0f);
  55. oldclfor = complex<float>(fb, 0.0f);
  56. }
  57. Alienwah::~Alienwah()
  58. {
  59. memory.devalloc(oldl);
  60. memory.devalloc(oldr);
  61. }
  62. //Apply the effect
  63. void Alienwah::out(const Stereo<float *> &smp)
  64. {
  65. float lfol, lfor; //Left/Right LFOs
  66. complex<float> clfol, clfor;
  67. /**\todo Rework, as optimization can be used when the new complex type is
  68. * utilized.
  69. * Before all calculations needed to be done with individual float,
  70. * but now they can be done together*/
  71. lfo.effectlfoout(&lfol, &lfor);
  72. lfol *= depth * PI * 2.0f;
  73. lfor *= depth * PI * 2.0f;
  74. clfol = complex<float>(cosf(lfol + phase) * fb, sinf(lfol + phase) * fb); //rework
  75. clfor = complex<float>(cosf(lfor + phase) * fb, sinf(lfor + phase) * fb); //rework
  76. for(int i = 0; i < buffersize; ++i) {
  77. float x = ((float) i) / buffersize_f;
  78. float x1 = 1.0f - x;
  79. //left
  80. complex<float> tmp = clfol * x + oldclfol * x1;
  81. complex<float> out = tmp * oldl[oldk];
  82. out += (1 - fabs(fb)) * smp.l[i] * pangainL;
  83. oldl[oldk] = out;
  84. float l = out.real() * 10.0f * (fb + 0.1f);
  85. //right
  86. tmp = clfor * x + oldclfor * x1;
  87. out = tmp * oldr[oldk];
  88. out += (1 - fabs(fb)) * smp.r[i] * pangainR;
  89. oldr[oldk] = out;
  90. float r = out.real() * 10.0f * (fb + 0.1f);
  91. if(++oldk >= Pdelay)
  92. oldk = 0;
  93. //LRcross
  94. efxoutl[i] = l * (1.0f - lrcross) + r * lrcross;
  95. efxoutr[i] = r * (1.0f - lrcross) + l * lrcross;
  96. }
  97. oldclfol = clfol;
  98. oldclfor = clfor;
  99. }
  100. //Cleanup the effect
  101. void Alienwah::cleanup(void)
  102. {
  103. for(int i = 0; i < Pdelay; ++i) {
  104. oldl[i] = complex<float>(0.0f, 0.0f);
  105. oldr[i] = complex<float>(0.0f, 0.0f);
  106. }
  107. oldk = 0;
  108. }
  109. //Parameter control
  110. void Alienwah::setdepth(unsigned char _Pdepth)
  111. {
  112. Pdepth = _Pdepth;
  113. depth = Pdepth / 127.0f;
  114. }
  115. void Alienwah::setfb(unsigned char _Pfb)
  116. {
  117. Pfb = _Pfb;
  118. fb = fabs((Pfb - 64.0f) / 64.1f);
  119. fb = sqrtf(fb);
  120. if(fb < 0.4f)
  121. fb = 0.4f;
  122. if(Pfb < 64)
  123. fb = -fb;
  124. }
  125. void Alienwah::setvolume(unsigned char _Pvolume)
  126. {
  127. Pvolume = _Pvolume;
  128. outvolume = Pvolume / 127.0f;
  129. if(insertion == 0)
  130. volume = 1.0f;
  131. else
  132. volume = outvolume;
  133. }
  134. void Alienwah::setphase(unsigned char _Pphase)
  135. {
  136. Pphase = _Pphase;
  137. phase = (Pphase - 64.0f) / 64.0f * PI;
  138. }
  139. void Alienwah::setdelay(unsigned char _Pdelay)
  140. {
  141. memory.devalloc(oldl);
  142. memory.devalloc(oldr);
  143. Pdelay = limit<int>(_Pdelay, 1, MAX_ALIENWAH_DELAY);
  144. oldl = memory.valloc<complex<float>>(Pdelay);
  145. oldr = memory.valloc<complex<float>>(Pdelay);
  146. cleanup();
  147. }
  148. void Alienwah::setpreset(unsigned char npreset)
  149. {
  150. const int PRESET_SIZE = 11;
  151. const int NUM_PRESETS = 4;
  152. unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
  153. //AlienWah1
  154. {127, 64, 70, 0, 0, 62, 60, 105, 25, 0, 64},
  155. //AlienWah2
  156. {127, 64, 73, 106, 0, 101, 60, 105, 17, 0, 64},
  157. //AlienWah3
  158. {127, 64, 63, 0, 1, 100, 112, 105, 31, 0, 42},
  159. //AlienWah4
  160. {93, 64, 25, 0, 1, 66, 101, 11, 47, 0, 86}
  161. };
  162. if(npreset >= NUM_PRESETS)
  163. npreset = NUM_PRESETS - 1;
  164. for(int n = 0; n < PRESET_SIZE; ++n)
  165. changepar(n, presets[npreset][n]);
  166. if(insertion == 0)
  167. changepar(0, presets[npreset][0] / 2); //lower the volume if this is system effect
  168. Ppreset = npreset;
  169. }
  170. void Alienwah::changepar(int npar, unsigned char value)
  171. {
  172. switch(npar) {
  173. case 0:
  174. setvolume(value);
  175. break;
  176. case 1:
  177. setpanning(value);
  178. break;
  179. case 2:
  180. lfo.Pfreq = value;
  181. lfo.updateparams();
  182. break;
  183. case 3:
  184. lfo.Prandomness = value;
  185. lfo.updateparams();
  186. break;
  187. case 4:
  188. lfo.PLFOtype = value;
  189. lfo.updateparams();
  190. break;
  191. case 5:
  192. lfo.Pstereo = value;
  193. lfo.updateparams();
  194. break;
  195. case 6:
  196. setdepth(value);
  197. break;
  198. case 7:
  199. setfb(value);
  200. break;
  201. case 8:
  202. setdelay(value);
  203. break;
  204. case 9:
  205. setlrcross(value);
  206. break;
  207. case 10:
  208. setphase(value);
  209. break;
  210. }
  211. }
  212. unsigned char Alienwah::getpar(int npar) const
  213. {
  214. switch(npar) {
  215. case 0: return Pvolume;
  216. case 1: return Ppanning;
  217. case 2: return lfo.Pfreq;
  218. case 3: return lfo.Prandomness;
  219. case 4: return lfo.PLFOtype;
  220. case 5: return lfo.Pstereo;
  221. case 6: return Pdepth;
  222. case 7: return Pfb;
  223. case 8: return Pdelay;
  224. case 9: return Plrcross;
  225. case 10: return Pphase;
  226. default: return 0;
  227. }
  228. }