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.0KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Echo.cpp - Echo effect
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Copyright (C) 2009-2010 Mark McCurry
  6. Author: Nasca Octavian Paul
  7. Mark McCurry
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License
  10. as published by the Free Software Foundation; either version 2
  11. of the License, or (at your option) any later version.
  12. */
  13. #include <cmath>
  14. #include <rtosc/ports.h>
  15. #include <rtosc/port-sugar.h>
  16. #include "../Misc/Allocator.h"
  17. #include "Echo.h"
  18. #define MAX_DELAY 2
  19. namespace zyncarla {
  20. #define rObject Echo
  21. #define rBegin [](const char *msg, rtosc::RtData &d) {
  22. #define rEnd }
  23. rtosc::Ports Echo::ports = {
  24. {"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1,
  25. Panning Echo 2, Panning Echo 3, Feedback Echo)
  26. rProp(parameter)
  27. rDoc("Instrument Presets"), 0,
  28. rBegin;
  29. rObject *o = (rObject*)d.obj;
  30. if(rtosc_narguments(msg))
  31. o->setpreset(rtosc_argument(msg, 0).i);
  32. else
  33. d.reply(d.loc, "i", o->Ppreset);
  34. rEnd},
  35. rEffParVol(rDefault(67), rPresetsAt(6, 81, 81, 62)),
  36. rEffParPan(rPresetsAt(2, 75, 60, 60, 64, 60, 60, 64)),
  37. rEffPar(Pdelay, 2, rShort("delay"),
  38. rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28),
  39. "Length of Echo"),
  40. rEffPar(Plrdelay, 3, rShort("lr delay"),
  41. rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64),
  42. "Difference In Left/Right Delay"),
  43. rEffPar(Plrcross, 4, rShort("cross"),
  44. rPresetsAt(5, 0, 100, 127, 100), rDefault(30),
  45. "Left/Right Crossover"),
  46. rEffPar(Pfb, 5, rShort("feedback"),
  47. rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90),
  48. "Echo Feedback"),
  49. rEffPar(Phidamp, 6, rShort("damp"),
  50. rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55),
  51. "Dampen High Frequencies"),
  52. };
  53. #undef rBegin
  54. #undef rEnd
  55. #undef rObject
  56. Echo::Echo(EffectParams pars)
  57. :Effect(pars),
  58. Pvolume(50),
  59. Pdelay(60),
  60. Plrdelay(100),
  61. Pfb(40),
  62. Phidamp(60),
  63. delayTime(1),
  64. lrdelay(0),
  65. avgDelay(0),
  66. delay(memory.valloc<float>(MAX_DELAY * pars.srate),
  67. memory.valloc<float>(MAX_DELAY * pars.srate)),
  68. old(0.0f),
  69. pos(0),
  70. delta(1),
  71. ndelta(1)
  72. {
  73. initdelays();
  74. setpreset(Ppreset);
  75. }
  76. Echo::~Echo()
  77. {
  78. memory.devalloc(delay.l);
  79. memory.devalloc(delay.r);
  80. }
  81. //Cleanup the effect
  82. void Echo::cleanup(void)
  83. {
  84. memset(delay.l, 0, MAX_DELAY * samplerate * sizeof(float));
  85. memset(delay.r, 0, MAX_DELAY * samplerate * sizeof(float));
  86. old = Stereo<float>(0.0f);
  87. }
  88. inline int max(int a, int b)
  89. {
  90. return a > b ? a : b;
  91. }
  92. //Initialize the delays
  93. void Echo::initdelays(void)
  94. {
  95. cleanup();
  96. //number of seconds to delay left chan
  97. float dl = avgDelay - lrdelay;
  98. //number of seconds to delay right chan
  99. float dr = avgDelay + lrdelay;
  100. ndelta.l = max(1, (int) (dl * samplerate));
  101. ndelta.r = max(1, (int) (dr * samplerate));
  102. delta = ndelta;
  103. }
  104. //Effect output
  105. void Echo::out(const Stereo<float *> &input)
  106. {
  107. for(int i = 0; i < buffersize; ++i) {
  108. float ldl = delay.l[pos.l];
  109. float rdl = delay.r[pos.r];
  110. ldl = ldl * (1.0f - lrcross) + rdl * lrcross;
  111. rdl = rdl * (1.0f - lrcross) + ldl * lrcross;
  112. efxoutl[i] = ldl * 2.0f;
  113. efxoutr[i] = rdl * 2.0f;
  114. ldl = input.l[i] * pangainL - ldl * fb;
  115. rdl = input.r[i] * pangainR - rdl * fb;
  116. //LowPass Filter
  117. old.l = delay.l[(pos.l + delta.l) % (MAX_DELAY * samplerate)] =
  118. ldl * hidamp + old.l * (1.0f - hidamp);
  119. old.r = delay.r[(pos.r + delta.r) % (MAX_DELAY * samplerate)] =
  120. rdl * hidamp + old.r * (1.0f - hidamp);
  121. //increment
  122. ++pos.l; // += delta.l;
  123. ++pos.r; // += delta.r;
  124. //ensure that pos is still in bounds
  125. pos.l %= MAX_DELAY * samplerate;
  126. pos.r %= MAX_DELAY * samplerate;
  127. //adjust delay if needed
  128. delta.l = (15 * delta.l + ndelta.l) / 16;
  129. delta.r = (15 * delta.r + ndelta.r) / 16;
  130. }
  131. }
  132. //Parameter control
  133. void Echo::setvolume(unsigned char _Pvolume)
  134. {
  135. Pvolume = _Pvolume;
  136. if(insertion == 0) {
  137. if (Pvolume == 0) {
  138. outvolume = 0.0f;
  139. } else {
  140. outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f;
  141. }
  142. volume = 1.0f;
  143. }
  144. else
  145. volume = outvolume = Pvolume / 127.0f;
  146. if(Pvolume == 0)
  147. cleanup();
  148. }
  149. void Echo::setdelay(unsigned char _Pdelay)
  150. {
  151. Pdelay = _Pdelay;
  152. avgDelay = (Pdelay / 127.0f * 1.5f); //0 .. 1.5 sec
  153. initdelays();
  154. }
  155. void Echo::setlrdelay(unsigned char _Plrdelay)
  156. {
  157. float tmp;
  158. Plrdelay = _Plrdelay;
  159. tmp =
  160. (powf(2.0f, fabsf(Plrdelay - 64.0f) / 64.0f * 9.0f) - 1.0f) / 1000.0f;
  161. if(Plrdelay < 64.0f)
  162. tmp = -tmp;
  163. lrdelay = tmp;
  164. initdelays();
  165. }
  166. void Echo::setfb(unsigned char _Pfb)
  167. {
  168. Pfb = _Pfb;
  169. fb = Pfb / 128.0f;
  170. }
  171. void Echo::sethidamp(unsigned char _Phidamp)
  172. {
  173. Phidamp = _Phidamp;
  174. hidamp = 1.0f - Phidamp / 127.0f;
  175. }
  176. void Echo::setpreset(unsigned char npreset)
  177. {
  178. const int PRESET_SIZE = 7;
  179. const int NUM_PRESETS = 9;
  180. unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
  181. {67, 64, 35, 64, 30, 59, 0 }, //Echo 1
  182. {67, 64, 21, 64, 30, 59, 0 }, //Echo 2
  183. {67, 75, 60, 64, 30, 59, 10}, //Echo 3
  184. {67, 60, 44, 64, 30, 0, 0 }, //Simple Echo
  185. {67, 60, 102, 50, 30, 82, 48}, //Canyon
  186. {67, 64, 44, 17, 0, 82, 24}, //Panning Echo 1
  187. {81, 60, 46, 118, 100, 68, 18}, //Panning Echo 2
  188. {81, 60, 26, 100, 127, 67, 36}, //Panning Echo 3
  189. {62, 64, 28, 64, 100, 90, 55} //Feedback Echo
  190. };
  191. if(npreset >= NUM_PRESETS)
  192. npreset = NUM_PRESETS - 1;
  193. for(int n = 0; n < PRESET_SIZE; ++n)
  194. changepar(n, presets[npreset][n]);
  195. if(insertion)
  196. setvolume(presets[npreset][0] / 2); //lower the volume if this is insertion effect
  197. Ppreset = npreset;
  198. }
  199. void Echo::changepar(int npar, unsigned char value)
  200. {
  201. switch(npar) {
  202. case 0:
  203. setvolume(value);
  204. break;
  205. case 1:
  206. setpanning(value);
  207. break;
  208. case 2:
  209. setdelay(value);
  210. break;
  211. case 3:
  212. setlrdelay(value);
  213. break;
  214. case 4:
  215. setlrcross(value);
  216. break;
  217. case 5:
  218. setfb(value);
  219. break;
  220. case 6:
  221. sethidamp(value);
  222. break;
  223. }
  224. }
  225. unsigned char Echo::getpar(int npar) const
  226. {
  227. switch(npar) {
  228. case 0: return Pvolume;
  229. case 1: return Ppanning;
  230. case 2: return Pdelay;
  231. case 3: return Plrdelay;
  232. case 4: return Plrcross;
  233. case 5: return Pfb;
  234. case 6: return Phidamp;
  235. default: return 0; // in case of bogus parameter number
  236. }
  237. }
  238. }