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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 <math.h>
  18. #include <stdlib.h>
  19. #include "Resonance.h"
  20. Resonance::Resonance():Presets()
  21. {
  22. setpresettype("Presonance");
  23. defaults();
  24. }
  25. Resonance::~Resonance()
  26. {}
  27. void Resonance::defaults()
  28. {
  29. Penabled = 0;
  30. PmaxdB = 20;
  31. Pcenterfreq = 64; //1 kHz
  32. Poctavesfreq = 64;
  33. Pprotectthefundamental = 0;
  34. ctlcenter = 1.0f;
  35. ctlbw = 1.0f;
  36. for(int i = 0; i < N_RES_POINTS; ++i)
  37. Prespoints[i] = 64;
  38. }
  39. /*
  40. * Set a point of resonance function with a value
  41. */
  42. void Resonance::setpoint(int n, unsigned char p)
  43. {
  44. if((n < 0) || (n >= N_RES_POINTS))
  45. return;
  46. Prespoints[n] = p;
  47. }
  48. /*
  49. * Apply the resonance to FFT data
  50. */
  51. void Resonance::applyres(int n, fft_t *fftdata, float freq)
  52. {
  53. if(Penabled == 0)
  54. return; //if the resonance is disabled
  55. float sum = 0.0f,
  56. l1 = logf(getfreqx(0.0f) * ctlcenter),
  57. l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
  58. for(int i = 0; i < N_RES_POINTS; ++i)
  59. if(sum < Prespoints[i])
  60. sum = Prespoints[i];
  61. if(sum < 1.0f)
  62. sum = 1.0f;
  63. for(int i = 1; i < n; ++i) {
  64. float x = (logf(freq * i) - l1) / l2; //compute where the n-th hamonics fits to the graph
  65. if(x < 0.0f)
  66. x = 0.0f;
  67. x *= N_RES_POINTS;
  68. float dx = x - floor(x);
  69. x = floor(x);
  70. int kx1 = (int)x;
  71. if(kx1 >= N_RES_POINTS)
  72. kx1 = N_RES_POINTS - 1;
  73. int kx2 = kx1 + 1;
  74. if(kx2 >= N_RES_POINTS)
  75. kx2 = N_RES_POINTS - 1;
  76. float y =
  77. (Prespoints[kx1]
  78. * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 127.0f;
  79. y = powf(10.0f, y * PmaxdB / 20.0f);
  80. if((Pprotectthefundamental != 0) && (i == 1))
  81. y = 1.0f;
  82. fftdata[i] *= y;
  83. }
  84. }
  85. /*
  86. * Gets the response at the frequency "freq"
  87. */
  88. float Resonance::getfreqresponse(float freq)
  89. {
  90. float l1 = logf(getfreqx(0.0f) * ctlcenter),
  91. l2 = logf(2.0f) * getoctavesfreq() * ctlbw, sum = 0.0f;
  92. for(int i = 0; i < N_RES_POINTS; ++i)
  93. if(sum < Prespoints[i])
  94. sum = Prespoints[i];
  95. if(sum < 1.0f)
  96. sum = 1.0f;
  97. float x = (logf(freq) - l1) / l2; //compute where the n-th hamonics fits to the graph
  98. if(x < 0.0f)
  99. x = 0.0f;
  100. x *= N_RES_POINTS;
  101. float dx = x - floor(x);
  102. x = floor(x);
  103. int kx1 = (int)x;
  104. if(kx1 >= N_RES_POINTS)
  105. kx1 = N_RES_POINTS - 1;
  106. int kx2 = kx1 + 1;
  107. if(kx2 >= N_RES_POINTS)
  108. kx2 = N_RES_POINTS - 1;
  109. float result =
  110. (Prespoints[kx1]
  111. * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 127.0f;
  112. result = powf(10.0f, result * PmaxdB / 20.0f);
  113. return result;
  114. }
  115. /*
  116. * Smooth the resonance function
  117. */
  118. void Resonance::smooth()
  119. {
  120. float old = Prespoints[0];
  121. for(int i = 0; i < N_RES_POINTS; ++i) {
  122. old = old * 0.4f + Prespoints[i] * 0.6f;
  123. Prespoints[i] = (int) old;
  124. }
  125. old = Prespoints[N_RES_POINTS - 1];
  126. for(int i = N_RES_POINTS - 1; i > 0; i--) {
  127. old = old * 0.4f + Prespoints[i] * 0.6f;
  128. Prespoints[i] = (int) old + 1;
  129. if(Prespoints[i] > 127)
  130. Prespoints[i] = 127;
  131. }
  132. }
  133. /*
  134. * Randomize the resonance function
  135. */
  136. void Resonance::randomize(int type)
  137. {
  138. int r = (int)(RND * 127.0f);
  139. for(int i = 0; i < N_RES_POINTS; ++i) {
  140. Prespoints[i] = r;
  141. if((RND < 0.1f) && (type == 0))
  142. r = (int)(RND * 127.0f);
  143. if((RND < 0.3f) && (type == 1))
  144. r = (int)(RND * 127.0f);
  145. if(type == 2)
  146. r = (int)(RND * 127.0f);
  147. }
  148. smooth();
  149. }
  150. /*
  151. * Interpolate the peaks
  152. */
  153. void Resonance::interpolatepeaks(int type)
  154. {
  155. int x1 = 0, y1 = Prespoints[0];
  156. for(int i = 1; i < N_RES_POINTS; ++i)
  157. if((Prespoints[i] != 64) || (i + 1 == N_RES_POINTS)) {
  158. int y2 = Prespoints[i];
  159. for(int k = 0; k < i - x1; ++k) {
  160. float x = (float) k / (i - x1);
  161. if(type == 0)
  162. x = (1 - cosf(x * PI)) * 0.5f;
  163. Prespoints[x1 + k] = (int)(y1 * (1.0f - x) + y2 * x);
  164. }
  165. x1 = i;
  166. y1 = y2;
  167. }
  168. }
  169. /*
  170. * Get the frequency from x, where x is [0..1]; x is the x coordinate
  171. */
  172. float Resonance::getfreqx(float x)
  173. {
  174. if(x > 1.0f)
  175. x = 1.0f;
  176. float octf = powf(2.0f, getoctavesfreq());
  177. return getcenterfreq() / sqrt(octf) * powf(octf, x);
  178. }
  179. /*
  180. * Get the x coordinate from frequency (used by the UI)
  181. */
  182. float Resonance::getfreqpos(float freq)
  183. {
  184. return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
  185. }
  186. /*
  187. * Get the center frequency of the resonance graph
  188. */
  189. float Resonance::getcenterfreq()
  190. {
  191. return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
  192. }
  193. /*
  194. * Get the number of octave that the resonance functions applies to
  195. */
  196. float Resonance::getoctavesfreq()
  197. {
  198. return 0.25f + 10.0f * Poctavesfreq / 127.0f;
  199. }
  200. void Resonance::sendcontroller(MidiControllers ctl, float par)
  201. {
  202. if(ctl == C_resonance_center)
  203. ctlcenter = par;
  204. else
  205. ctlbw = par;
  206. }
  207. void Resonance::add2XML(XMLwrapper *xml)
  208. {
  209. xml->addparbool("enabled", Penabled);
  210. if((Penabled == 0) && (xml->minimal))
  211. return;
  212. xml->addpar("max_db", PmaxdB);
  213. xml->addpar("center_freq", Pcenterfreq);
  214. xml->addpar("octaves_freq", Poctavesfreq);
  215. xml->addparbool("protect_fundamental_frequency", Pprotectthefundamental);
  216. xml->addpar("resonance_points", N_RES_POINTS);
  217. for(int i = 0; i < N_RES_POINTS; ++i) {
  218. xml->beginbranch("RESPOINT", i);
  219. xml->addpar("val", Prespoints[i]);
  220. xml->endbranch();
  221. }
  222. }
  223. void Resonance::getfromXML(XMLwrapper *xml)
  224. {
  225. Penabled = xml->getparbool("enabled", Penabled);
  226. PmaxdB = xml->getpar127("max_db", PmaxdB);
  227. Pcenterfreq = xml->getpar127("center_freq", Pcenterfreq);
  228. Poctavesfreq = xml->getpar127("octaves_freq", Poctavesfreq);
  229. Pprotectthefundamental = xml->getparbool("protect_fundamental_frequency",
  230. Pprotectthefundamental);
  231. for(int i = 0; i < N_RES_POINTS; ++i) {
  232. if(xml->enterbranch("RESPOINT", i) == 0)
  233. continue;
  234. Prespoints[i] = xml->getpar127("val", Prespoints[i]);
  235. xml->exitbranch();
  236. }
  237. }