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.

254 lines
6.5KB

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