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.

Resonance.cpp 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Resonance.cpp - Resonance
  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 <cstdlib>
  13. #include "Resonance.h"
  14. #include "../Misc/Util.h"
  15. #include <rtosc/ports.h>
  16. #include <rtosc/port-sugar.h>
  17. using namespace rtosc;
  18. namespace zyncarla {
  19. #define rObject Resonance
  20. #define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj
  21. #define rEnd }
  22. const rtosc::Ports Resonance::ports = {
  23. rSelf(Resonance),
  24. rPaste,
  25. rToggle(Penabled, rShort("enable"), rDefault(false),
  26. "resonance enable"),
  27. rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false),
  28. "Disable resonance filter on first harmonic"),
  29. rParams(Prespoints, N_RES_POINTS, rDefaultMissing,
  30. "Resonance data points"),
  31. rParamZyn(PmaxdB, rShort("max"), rDefault(20),
  32. "how many dB the signal may be amplified"),
  33. rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"),
  34. rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64),
  35. "The number of octaves..."),
  36. rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"),
  37. rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"),
  38. rAction(smooth, "Smooth out frequency response"),
  39. rAction(zero, "Reset frequency response"),
  40. //UI Value listeners
  41. {"centerfreq:", rDoc("Get center frequency") rMap(unit, Hz), NULL,
  42. [](const char *, RtData &d)
  43. {d.reply(d.loc, "f", ((rObject*)d.obj)->getcenterfreq());}},
  44. {"octavesfreq:", rDoc("Get center freq of graph"), NULL,
  45. [](const char *, RtData &d)
  46. {d.reply(d.loc, "f", ((rObject*)d.obj)->getoctavesfreq());}},
  47. {"respoints", 0, 0,
  48. rBegin;
  49. if(rtosc_narguments(msg)) {
  50. int i=0;
  51. auto itr = rtosc_itr_begin(msg);
  52. while(!rtosc_itr_end(itr) && i < N_RES_POINTS) {
  53. auto ival = rtosc_itr_next(&itr);
  54. if(ival.type == 'f')
  55. o.Prespoints[i++] = ival.val.f*127;
  56. }
  57. } else {
  58. rtosc_arg_t args[N_RES_POINTS];
  59. char types[N_RES_POINTS+1] = {0};
  60. for(int i=0; i<N_RES_POINTS; ++i) {
  61. args[i].f = o.Prespoints[i]/127.0;
  62. types[i] = 'f';
  63. }
  64. d.replyArray(d.loc, types, args);
  65. }
  66. rEnd},
  67. };
  68. #undef rBegin
  69. #undef rEnd
  70. Resonance::Resonance():Presets()
  71. {
  72. setpresettype("Presonance");
  73. defaults();
  74. }
  75. Resonance::~Resonance(void)
  76. {}
  77. void Resonance::defaults(void)
  78. {
  79. Penabled = 0;
  80. PmaxdB = 20;
  81. Pcenterfreq = 64; //1 kHz
  82. Poctavesfreq = 64;
  83. Pprotectthefundamental = 0;
  84. ctlcenter = 1.0f;
  85. ctlbw = 1.0f;
  86. for(int i = 0; i < N_RES_POINTS; ++i)
  87. Prespoints[i] = 64;
  88. }
  89. /*
  90. * Set a point of resonance function with a value
  91. */
  92. void Resonance::setpoint(int n, unsigned char p)
  93. {
  94. if((n < 0) || (n >= N_RES_POINTS))
  95. return;
  96. Prespoints[n] = p;
  97. }
  98. /*
  99. * Apply the resonance to FFT data
  100. */
  101. void Resonance::applyres(int n, fft_t *fftdata, float freq) const
  102. {
  103. if(Penabled == 0)
  104. return; //if the resonance is disabled
  105. const float l1 = logf(getfreqx(0.0f) * ctlcenter),
  106. l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
  107. //Provide an upper bound for resonance
  108. const float upper =
  109. limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, (float)INFINITY);
  110. for(int i = 1; i < n; ++i) {
  111. //compute where the n-th hamonics fits to the graph
  112. const float x = limit((logf(freq*i) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
  113. const float dx = x - floor(x);
  114. const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
  115. const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
  116. float y =
  117. ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx)
  118. - upper) / 127.0f;
  119. y = powf(10.0f, y * PmaxdB / 20.0f);
  120. if((Pprotectthefundamental != 0) && (i == 1))
  121. y = 1.0f;
  122. fftdata[i] *= y;
  123. }
  124. }
  125. /*
  126. * Gets the response at the frequency "freq"
  127. */
  128. //Requires
  129. // - resonance data
  130. // - max resonance
  131. // - mapping from resonance data to frequency
  132. float Resonance::getfreqresponse(float freq) const
  133. {
  134. const float l1 = logf(getfreqx(0.0f) * ctlcenter),
  135. l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
  136. //Provide an upper bound for resonance
  137. const float upper =
  138. limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, INFINITY);
  139. //compute where the n-th hamonics fits to the graph
  140. const float x = limit((logf(freq) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
  141. const float dx = x - floor(x);
  142. const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
  143. const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
  144. //Interpolate
  145. const float result =
  146. ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) - upper) / 127.0f;
  147. return powf(10.0f, result * PmaxdB / 20.0f);
  148. }
  149. /*
  150. * Smooth the resonance function
  151. */
  152. void Resonance::smooth(void)
  153. {
  154. float old = Prespoints[0];
  155. for(int i = 0; i < N_RES_POINTS; ++i) {
  156. old = old * 0.4f + Prespoints[i] * 0.6f;
  157. Prespoints[i] = (int) old;
  158. }
  159. old = Prespoints[N_RES_POINTS - 1];
  160. for(int i = N_RES_POINTS - 1; i > 0; i--) {
  161. old = old * 0.4f + Prespoints[i] * 0.6f;
  162. Prespoints[i] = (int) old + 1;
  163. if(Prespoints[i] > 127)
  164. Prespoints[i] = 127;
  165. }
  166. }
  167. /*
  168. * Randomize the resonance function
  169. */
  170. void Resonance::randomize(int type)
  171. {
  172. int r = (int)(RND * 127.0f);
  173. for(int i = 0; i < N_RES_POINTS; ++i) {
  174. Prespoints[i] = r;
  175. if((RND < 0.1f) && (type == 0))
  176. r = (int)(RND * 127.0f);
  177. if((RND < 0.3f) && (type == 1))
  178. r = (int)(RND * 127.0f);
  179. if(type == 2)
  180. r = (int)(RND * 127.0f);
  181. }
  182. smooth();
  183. }
  184. void Resonance::zero(void)
  185. {
  186. for(int i=0; i<N_RES_POINTS; ++i)
  187. setpoint(i,64);
  188. }
  189. /*
  190. * Interpolate the peaks
  191. */
  192. void Resonance::interpolatepeaks(int type)
  193. {
  194. int x1 = 0, y1 = Prespoints[0];
  195. for(int i = 1; i < N_RES_POINTS; ++i)
  196. if((Prespoints[i] != 64) || (i + 1 == N_RES_POINTS)) {
  197. int y2 = Prespoints[i];
  198. for(int k = 0; k < i - x1; ++k) {
  199. float x = (float) k / (i - x1);
  200. if(type == 0)
  201. x = (1 - cosf(x * PI)) * 0.5f;
  202. Prespoints[x1 + k] = (int)(y1 * (1.0f - x) + y2 * x);
  203. }
  204. x1 = i;
  205. y1 = y2;
  206. }
  207. }
  208. /*
  209. * Get the frequency from x, where x is [0..1]; x is the x coordinate
  210. */
  211. float Resonance::getfreqx(float x) const
  212. {
  213. const float octf = powf(2.0f, getoctavesfreq());
  214. return getcenterfreq() / sqrt(octf) * powf(octf, limit(x, 0.0f, 1.0f));
  215. }
  216. /*
  217. * Get the x coordinate from frequency (used by the UI)
  218. */
  219. float Resonance::getfreqpos(float freq) const
  220. {
  221. return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
  222. }
  223. /*
  224. * Get the center frequency of the resonance graph
  225. */
  226. float Resonance::getcenterfreq() const
  227. {
  228. return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
  229. }
  230. /*
  231. * Get the number of octave that the resonance functions applies to
  232. */
  233. float Resonance::getoctavesfreq() const
  234. {
  235. return 0.25f + 10.0f * Poctavesfreq / 127.0f;
  236. }
  237. void Resonance::sendcontroller(MidiControllers ctl, float par)
  238. {
  239. if(ctl == C_resonance_center)
  240. ctlcenter = par;
  241. else
  242. ctlbw = par;
  243. }
  244. #define COPY(y) this->y = r.y
  245. void Resonance::paste(Resonance &r)
  246. {
  247. COPY(Penabled);
  248. for(int i=0; i<N_RES_POINTS; ++i)
  249. this->Prespoints[i] = r.Prespoints[i];
  250. COPY(PmaxdB);
  251. COPY(Pcenterfreq);
  252. COPY(Poctavesfreq);
  253. COPY(Pprotectthefundamental);
  254. COPY(ctlcenter);
  255. COPY(ctlbw);
  256. }
  257. #undef COPY
  258. void Resonance::add2XML(XMLwrapper& xml)
  259. {
  260. xml.addparbool("enabled", Penabled);
  261. if((Penabled == 0) && (xml.minimal))
  262. return;
  263. xml.addpar("max_db", PmaxdB);
  264. xml.addpar("center_freq", Pcenterfreq);
  265. xml.addpar("octaves_freq", Poctavesfreq);
  266. xml.addparbool("protect_fundamental_frequency", Pprotectthefundamental);
  267. xml.addpar("resonance_points", N_RES_POINTS);
  268. for(int i = 0; i < N_RES_POINTS; ++i) {
  269. xml.beginbranch("RESPOINT", i);
  270. xml.addpar("val", Prespoints[i]);
  271. xml.endbranch();
  272. }
  273. }
  274. void Resonance::getfromXML(XMLwrapper& xml)
  275. {
  276. Penabled = xml.getparbool("enabled", Penabled);
  277. PmaxdB = xml.getpar127("max_db", PmaxdB);
  278. Pcenterfreq = xml.getpar127("center_freq", Pcenterfreq);
  279. Poctavesfreq = xml.getpar127("octaves_freq", Poctavesfreq);
  280. Pprotectthefundamental = xml.getparbool("protect_fundamental_frequency",
  281. Pprotectthefundamental);
  282. for(int i = 0; i < N_RES_POINTS; ++i) {
  283. if(xml.enterbranch("RESPOINT", i) == 0)
  284. continue;
  285. Prespoints[i] = xml.getpar127("val", Prespoints[i]);
  286. xml.exitbranch();
  287. }
  288. }
  289. }