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.

315 lines
9.1KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Chorus.cpp - Chorus and Flange effects
  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/ports.h>
  13. #include <rtosc/port-sugar.h>
  14. #include "../Misc/Allocator.h"
  15. #include "Chorus.h"
  16. #include <iostream>
  17. using namespace std;
  18. namespace zyncarla {
  19. #define rObject Chorus
  20. #define rBegin [](const char *msg, rtosc::RtData &d) {
  21. #define rEnd }
  22. rtosc::Ports Chorus::ports = {
  23. {"preset::i", rProp(parameter)
  24. rOptions(Chorus1, Chorus2, Chorus3, Celeste1, Celeste2,
  25. Flange1, Flange2, Flange3, Flange4, Flange5)
  26. rDoc("Instrument Presets"), 0,
  27. rBegin;
  28. rObject *o = (rObject*)d.obj;
  29. if(rtosc_narguments(msg))
  30. o->setpreset(rtosc_argument(msg, 0).i);
  31. else
  32. d.reply(d.loc, "i", o->Ppreset);
  33. rEnd},
  34. //Pvolume/Ppanning are common
  35. rEffParVol(rDefault(64)),
  36. rEffParPan(),
  37. rEffPar(Pfreq, 2, rShort("freq"),
  38. rPresets(50, 45, 29, 26, 29, 57, 33, 53, 40, 55),
  39. "Effect Frequency"),
  40. rEffPar(Pfreqrnd, 3, rShort("rand"),
  41. rPreset(4, 117) rPreset(6, 34) rPreset(7, 34) rPreset(9, 105)
  42. rDefault(0), "Frequency Randomness"),
  43. rEffPar(PLFOtype, 4, rShort("shape"),
  44. rOptions(sine, tri),
  45. rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine)
  46. "LFO Shape"),
  47. rEffPar(PStereo, 5, rShort("stereo"),
  48. rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62), "Stereo Mode"),
  49. rEffPar(Pdepth, 6, rShort("depth"),
  50. rPresets(40, 56, 97, 115, 115, 23, 35, 35, 12), "LFO Depth"),
  51. rEffPar(Pdelay, 7, rShort("delay"),
  52. rPresets(85, 90, 95, 18, 9, 3, 3, 3, 19), "Delay"),
  53. rEffPar(Pfeedback,8, rShort("fb"),
  54. rPresets(64, 64, 90, 90, 31, 62, 109, 54, 97), "Feedback"),
  55. rEffPar(Plrcross, 9, rShort("l/r"), rPresets(119, 19, 127, 127, 127),
  56. rDefault(0), "Left/Right Crossover"),
  57. rEffParTF(Pflangemode, 10, rShort("flange"), rDefault(false),
  58. "Flange Mode"),
  59. rEffParTF(Poutsub, 11, rShort("sub"), rPreset(4, true), rPreset(7, true),
  60. rDefault(false), "Output Subtraction"),
  61. };
  62. #undef rBegin
  63. #undef rEnd
  64. #undef rObject
  65. Chorus::Chorus(EffectParams pars)
  66. :Effect(pars),
  67. lfo(pars.srate, pars.bufsize),
  68. maxdelay((int)(MAX_CHORUS_DELAY / 1000.0f * samplerate_f)),
  69. delaySample(memory.valloc<float>(maxdelay), memory.valloc<float>(maxdelay))
  70. {
  71. dlk = 0;
  72. drk = 0;
  73. setpreset(Ppreset);
  74. changepar(1, 64);
  75. lfo.effectlfoout(&lfol, &lfor);
  76. dl2 = getdelay(lfol);
  77. dr2 = getdelay(lfor);
  78. cleanup();
  79. }
  80. Chorus::~Chorus()
  81. {
  82. memory.devalloc(delaySample.l);
  83. memory.devalloc(delaySample.r);
  84. }
  85. //get the delay value in samples; xlfo is the current lfo value
  86. float Chorus::getdelay(float xlfo)
  87. {
  88. float result =
  89. (Pflangemode) ? 0 : (delay + xlfo * depth) * samplerate_f;
  90. //check if delay is too big (caused by bad setdelay() and setdepth()
  91. if((result + 0.5f) >= maxdelay) {
  92. cerr
  93. <<
  94. "WARNING: Chorus.cpp::getdelay(..) too big delay (see setdelay and setdepth funcs.)"
  95. << endl;
  96. result = maxdelay - 1.0f;
  97. }
  98. return result;
  99. }
  100. //Apply the effect
  101. void Chorus::out(const Stereo<float *> &input)
  102. {
  103. dl1 = dl2;
  104. dr1 = dr2;
  105. lfo.effectlfoout(&lfol, &lfor);
  106. dl2 = getdelay(lfol);
  107. dr2 = getdelay(lfor);
  108. for(int i = 0; i < buffersize; ++i) {
  109. float inL = input.l[i];
  110. float inR = input.r[i];
  111. //LRcross
  112. Stereo<float> tmpc(inL, inR);
  113. inL = tmpc.l * (1.0f - lrcross) + tmpc.r * lrcross;
  114. inR = tmpc.r * (1.0f - lrcross) + tmpc.l * lrcross;
  115. //Left channel
  116. //compute the delay in samples using linear interpolation between the lfo delays
  117. float mdel =
  118. (dl1 * (buffersize - i) + dl2 * i) / buffersize_f;
  119. if(++dlk >= maxdelay)
  120. dlk = 0;
  121. float tmp = dlk - mdel + maxdelay * 2.0f; //where should I get the sample from
  122. dlhi = (int) tmp;
  123. dlhi %= maxdelay;
  124. float dlhi2 = (dlhi - 1 + maxdelay) % maxdelay;
  125. float dllo = 1.0f + floorf(tmp) - tmp;
  126. efxoutl[i] = cinterpolate(delaySample.l, maxdelay, dlhi2) * dllo
  127. + cinterpolate(delaySample.l, maxdelay,
  128. dlhi) * (1.0f - dllo);
  129. delaySample.l[dlk] = inL + efxoutl[i] * fb;
  130. //Right channel
  131. //compute the delay in samples using linear interpolation between the lfo delays
  132. mdel = (dr1 * (buffersize - i) + dr2 * i) / buffersize_f;
  133. if(++drk >= maxdelay)
  134. drk = 0;
  135. tmp = drk * 1.0f - mdel + maxdelay * 2.0f; //where should I get the sample from
  136. dlhi = (int) tmp;
  137. dlhi %= maxdelay;
  138. dlhi2 = (dlhi - 1 + maxdelay) % maxdelay;
  139. dllo = 1.0f + floorf(tmp) - tmp;
  140. efxoutr[i] = cinterpolate(delaySample.r, maxdelay, dlhi2) * dllo
  141. + cinterpolate(delaySample.r, maxdelay,
  142. dlhi) * (1.0f - dllo);
  143. delaySample.r[dlk] = inR + efxoutr[i] * fb;
  144. }
  145. if(Poutsub)
  146. for(int i = 0; i < buffersize; ++i) {
  147. efxoutl[i] *= -1.0f;
  148. efxoutr[i] *= -1.0f;
  149. }
  150. for(int i = 0; i < buffersize; ++i) {
  151. efxoutl[i] *= pangainL;
  152. efxoutr[i] *= pangainR;
  153. }
  154. }
  155. //Cleanup the effect
  156. void Chorus::cleanup(void)
  157. {
  158. memset(delaySample.l, 0, maxdelay * sizeof(float));
  159. memset(delaySample.r, 0, maxdelay * sizeof(float));
  160. }
  161. //Parameter control
  162. void Chorus::setdepth(unsigned char _Pdepth)
  163. {
  164. Pdepth = _Pdepth;
  165. depth = (powf(8.0f, (Pdepth / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds
  166. }
  167. void Chorus::setdelay(unsigned char _Pdelay)
  168. {
  169. Pdelay = _Pdelay;
  170. delay = (powf(10.0f, (Pdelay / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds
  171. }
  172. void Chorus::setfb(unsigned char _Pfb)
  173. {
  174. Pfb = _Pfb;
  175. fb = (Pfb - 64.0f) / 64.1f;
  176. }
  177. void Chorus::setvolume(unsigned char _Pvolume)
  178. {
  179. Pvolume = _Pvolume;
  180. outvolume = Pvolume / 127.0f;
  181. volume = (!insertion) ? 1.0f : outvolume;
  182. }
  183. void Chorus::setpreset(unsigned char npreset)
  184. {
  185. const int PRESET_SIZE = 12;
  186. const int NUM_PRESETS = 10;
  187. unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
  188. //Chorus1
  189. {64, 64, 50, 0, 0, 90, 40, 85, 64, 119, 0, 0},
  190. //Chorus2
  191. {64, 64, 45, 0, 0, 98, 56, 90, 64, 19, 0, 0},
  192. //Chorus3
  193. {64, 64, 29, 0, 1, 42, 97, 95, 90, 127, 0, 0},
  194. //Celeste1
  195. {64, 64, 26, 0, 0, 42, 115, 18, 90, 127, 0, 0},
  196. //Celeste2
  197. {64, 64, 29, 117, 0, 50, 115, 9, 31, 127, 0, 1},
  198. //Flange1
  199. {64, 64, 57, 0, 0, 60, 23, 3, 62, 0, 0, 0},
  200. //Flange2
  201. {64, 64, 33, 34, 1, 40, 35, 3, 109, 0, 0, 0},
  202. //Flange3
  203. {64, 64, 53, 34, 1, 94, 35, 3, 54, 0, 0, 1},
  204. //Flange4
  205. {64, 64, 40, 0, 1, 62, 12, 19, 97, 0, 0, 0},
  206. //Flange5
  207. {64, 64, 55, 105, 0, 24, 39, 19, 17, 0, 0, 1}
  208. };
  209. if(npreset >= NUM_PRESETS)
  210. npreset = NUM_PRESETS - 1;
  211. for(int n = 0; n < PRESET_SIZE; ++n)
  212. changepar(n, presets[npreset][n]);
  213. Ppreset = npreset;
  214. }
  215. void Chorus::changepar(int npar, unsigned char value)
  216. {
  217. switch(npar) {
  218. case 0:
  219. setvolume(value);
  220. break;
  221. case 1:
  222. setpanning(value);
  223. break;
  224. case 2:
  225. lfo.Pfreq = value;
  226. lfo.updateparams();
  227. break;
  228. case 3:
  229. lfo.Prandomness = value;
  230. lfo.updateparams();
  231. break;
  232. case 4:
  233. lfo.PLFOtype = value;
  234. lfo.updateparams();
  235. break;
  236. case 5:
  237. lfo.Pstereo = value;
  238. lfo.updateparams();
  239. break;
  240. case 6:
  241. setdepth(value);
  242. break;
  243. case 7:
  244. setdelay(value);
  245. break;
  246. case 8:
  247. setfb(value);
  248. break;
  249. case 9:
  250. setlrcross(value);
  251. break;
  252. case 10:
  253. Pflangemode = (value > 1) ? 1 : value;
  254. break;
  255. case 11:
  256. Poutsub = (value > 1) ? 1 : value;
  257. break;
  258. }
  259. }
  260. unsigned char Chorus::getpar(int npar) const
  261. {
  262. switch(npar) {
  263. case 0: return Pvolume;
  264. case 1: return Ppanning;
  265. case 2: return lfo.Pfreq;
  266. case 3: return lfo.Prandomness;
  267. case 4: return lfo.PLFOtype;
  268. case 5: return lfo.Pstereo;
  269. case 6: return Pdepth;
  270. case 7: return Pdelay;
  271. case 8: return Pfb;
  272. case 9: return Plrcross;
  273. case 10: return Pflangemode;
  274. case 11: return Poutsub;
  275. default: return 0;
  276. }
  277. }
  278. }