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 8.6KB

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