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.

273 lines
7.1KB

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