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.

438 lines
12KB

  1. /*
  2. * ZamEQ2 2 band parametric equaliser
  3. * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "ZamEQ2Plugin.hpp"
  18. START_NAMESPACE_DISTRHO
  19. // -----------------------------------------------------------------------
  20. ZamEQ2Plugin::ZamEQ2Plugin()
  21. : Plugin(paramCount, 1, 0) // 1 program, 0 states
  22. {
  23. // set default values
  24. d_setProgram(0);
  25. // reset
  26. d_deactivate();
  27. }
  28. ZamEQ2Plugin::~ZamEQ2Plugin()
  29. {
  30. }
  31. // -----------------------------------------------------------------------
  32. // Init
  33. void ZamEQ2Plugin::d_initParameter(uint32_t index, Parameter& parameter)
  34. {
  35. switch (index)
  36. {
  37. case paramGain1:
  38. parameter.hints = PARAMETER_IS_AUTOMABLE;
  39. parameter.name = "Boost/Cut 1";
  40. parameter.symbol = "boost1";
  41. parameter.unit = "dB";
  42. parameter.ranges.def = 0.0f;
  43. parameter.ranges.min = -50.0f;
  44. parameter.ranges.max = 20.0f;
  45. break;
  46. case paramQ1:
  47. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  48. parameter.name = "Bandwidth 1";
  49. parameter.symbol = "bw1";
  50. parameter.unit = " ";
  51. parameter.ranges.def = 2.0f;
  52. parameter.ranges.min = 0.1f;
  53. parameter.ranges.max = 6.0f;
  54. break;
  55. case paramFreq1:
  56. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  57. parameter.name = "Frequency 1";
  58. parameter.symbol = "f1";
  59. parameter.unit = "Hz";
  60. parameter.ranges.def = 500.0f;
  61. parameter.ranges.min = 20.0f;
  62. parameter.ranges.max = 14000.0f;
  63. break;
  64. case paramGain2:
  65. parameter.hints = PARAMETER_IS_AUTOMABLE;
  66. parameter.name = "Boost/Cut 2";
  67. parameter.symbol = "boost2";
  68. parameter.unit = "dB";
  69. parameter.ranges.def = 0.0f;
  70. parameter.ranges.min = -50.0f;
  71. parameter.ranges.max = 20.0f;
  72. break;
  73. case paramQ2:
  74. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  75. parameter.name = "Bandwidth 2";
  76. parameter.symbol = "bw2";
  77. parameter.unit = " ";
  78. parameter.ranges.def = 2.0f;
  79. parameter.ranges.min = 0.1f;
  80. parameter.ranges.max = 6.0f;
  81. break;
  82. case paramFreq2:
  83. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  84. parameter.name = "Frequency 2";
  85. parameter.symbol = "f2";
  86. parameter.unit = "Hz";
  87. parameter.ranges.def = 3000.0f;
  88. parameter.ranges.min = 20.0f;
  89. parameter.ranges.max = 14000.0f;
  90. break;
  91. case paramGainL:
  92. parameter.hints = PARAMETER_IS_AUTOMABLE;
  93. parameter.name = "Boost/Cut L";
  94. parameter.symbol = "boostl";
  95. parameter.unit = "dB";
  96. parameter.ranges.def = 0.0f;
  97. parameter.ranges.min = -50.0f;
  98. parameter.ranges.max = 20.0f;
  99. break;
  100. case paramFreqL:
  101. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  102. parameter.name = "Frequency L";
  103. parameter.symbol = "fl";
  104. parameter.unit = "Hz";
  105. parameter.ranges.def = 250.0f;
  106. parameter.ranges.min = 20.0f;
  107. parameter.ranges.max = 14000.0f;
  108. break;
  109. case paramGainH:
  110. parameter.hints = PARAMETER_IS_AUTOMABLE;
  111. parameter.name = "Boost/Cut H";
  112. parameter.symbol = "boosth";
  113. parameter.unit = "dB";
  114. parameter.ranges.def = 0.0f;
  115. parameter.ranges.min = -50.0f;
  116. parameter.ranges.max = 20.0f;
  117. break;
  118. case paramFreqH:
  119. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_LOGARITHMIC;
  120. parameter.name = "Frequency H";
  121. parameter.symbol = "fh";
  122. parameter.unit = "Hz";
  123. parameter.ranges.def = 8000.0f;
  124. parameter.ranges.min = 20.0f;
  125. parameter.ranges.max = 14000.0f;
  126. break;
  127. case paramMaster:
  128. parameter.hints = PARAMETER_IS_AUTOMABLE;
  129. parameter.name = "Master Gain";
  130. parameter.symbol = "master";
  131. parameter.unit = "dB";
  132. parameter.ranges.def = 0.0f;
  133. parameter.ranges.min = -12.0f;
  134. parameter.ranges.max = 12.0f;
  135. break;
  136. case paramTogglePeaks:
  137. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_BOOLEAN;
  138. parameter.name = "Peaks ON";
  139. parameter.symbol = "peaks";
  140. parameter.unit = " ";
  141. parameter.ranges.def = 0.0f;
  142. parameter.ranges.min = 0.0f;
  143. parameter.ranges.max = 1.0f;
  144. break;
  145. }
  146. }
  147. void ZamEQ2Plugin::d_initProgramName(uint32_t index, d_string& programName)
  148. {
  149. if (index != 0)
  150. return;
  151. programName = "Default";
  152. }
  153. // -----------------------------------------------------------------------
  154. // Internal data
  155. float ZamEQ2Plugin::d_getParameterValue(uint32_t index) const
  156. {
  157. switch (index)
  158. {
  159. case paramGain1:
  160. return gain1;
  161. break;
  162. case paramQ1:
  163. return q1;
  164. break;
  165. case paramFreq1:
  166. return freq1;
  167. break;
  168. case paramGain2:
  169. return gain2;
  170. break;
  171. case paramQ2:
  172. return q2;
  173. break;
  174. case paramFreq2:
  175. return freq2;
  176. break;
  177. case paramGainL:
  178. return gainl;
  179. break;
  180. case paramFreqL:
  181. return freql;
  182. break;
  183. case paramGainH:
  184. return gainh;
  185. break;
  186. case paramFreqH:
  187. return freqh;
  188. break;
  189. case paramMaster:
  190. return master;
  191. break;
  192. case paramTogglePeaks:
  193. return togglepeaks;
  194. break;
  195. default:
  196. return 0.0f;
  197. }
  198. }
  199. void ZamEQ2Plugin::d_setParameterValue(uint32_t index, float value)
  200. {
  201. switch (index)
  202. {
  203. case paramGain1:
  204. gain1 = value;
  205. break;
  206. case paramQ1:
  207. q1 = value;
  208. break;
  209. case paramFreq1:
  210. freq1 = value;
  211. break;
  212. case paramGain2:
  213. gain2 = value;
  214. break;
  215. case paramQ2:
  216. q2 = value;
  217. break;
  218. case paramFreq2:
  219. freq2 = value;
  220. break;
  221. case paramGainL:
  222. gainl = value;
  223. break;
  224. case paramFreqL:
  225. freql = value;
  226. break;
  227. case paramGainH:
  228. gainh = value;
  229. break;
  230. case paramFreqH:
  231. freqh = value;
  232. break;
  233. case paramMaster:
  234. master = value;
  235. break;
  236. case paramTogglePeaks:
  237. togglepeaks = value;
  238. break;
  239. }
  240. }
  241. void ZamEQ2Plugin::d_setProgram(uint32_t index)
  242. {
  243. if (index != 0)
  244. return;
  245. /* Default parameter values */
  246. gain1 = 0.0f;
  247. q1 = 1.0f;
  248. freq1 = 500.0f;
  249. gain2 = 0.0f;
  250. q2 = 1.0f;
  251. freq2 = 3000.0f;
  252. gainl = 0.0f;
  253. freql = 250.0f;
  254. gainh = 0.0f;
  255. freqh = 8000.0f;
  256. master = 0.f;
  257. togglepeaks = 0.f;
  258. /* Default variable values */
  259. /* reset filter values */
  260. d_activate();
  261. }
  262. // -----------------------------------------------------------------------
  263. // Process
  264. void ZamEQ2Plugin::d_activate()
  265. {
  266. int i;
  267. for (i = 0; i < MAX_FILT; ++i) {
  268. x1[0][i] = x2[0][i] = 0.f;
  269. y1[0][i] = y2[0][i] = 0.f;
  270. b0[0][i] = b1[0][i] = b2[0][i] = 0.f;
  271. a1[0][i] = a2[0][i] = 0.f;
  272. }
  273. }
  274. void ZamEQ2Plugin::d_deactivate()
  275. {
  276. // all values to zero
  277. }
  278. void ZamEQ2Plugin::lowshelf(int i, int ch, float srate, float fc, float g)
  279. {
  280. float k, v0;
  281. k = tanf(M_PI * fc / srate);
  282. v0 = powf(10., g / 20.);
  283. if (g < 0.f) {
  284. // LF cut
  285. float denom = v0 + sqrt(2. * v0)*k + k*k;
  286. b0[ch][i] = v0 * (1. + sqrt(2.)*k + k*k) / denom;
  287. b1[ch][i] = 2. * v0*(k*k - 1.) / denom;
  288. b2[ch][i] = v0 * (1. - sqrt(2.)*k + k*k) / denom;
  289. a1[ch][i] = 2. * (k*k - v0) / denom;
  290. a2[ch][i] = (v0 - sqrt(2. * v0)*k + k*k) / denom;
  291. } else {
  292. // LF boost
  293. float denom = 1. + sqrt(2.)*k + k*k;
  294. b0[ch][i] = (1. + sqrt(2. * v0)*k + v0*k*k) / denom;
  295. b1[ch][i] = 2. * (v0*k*k - 1.) / denom;
  296. b2[ch][i] = (1. - sqrt(2. * v0)*k + v0*k*k) / denom;
  297. a1[ch][i] = 2. * (k*k - 1.) / denom;
  298. a2[ch][i] = (1. - sqrt(2.)*k + k*k) / denom;
  299. }
  300. }
  301. void ZamEQ2Plugin::highshelf(int i, int ch, float srate, float fc, float g)
  302. {
  303. float k, v0;
  304. k = tanf(M_PI * fc / srate);
  305. v0 = powf(10., g / 20.);
  306. if (g < 0.f) {
  307. // HF cut
  308. float denom = 1. + sqrt(2. * v0)*k + v0*k*k;
  309. b0[ch][i] = v0*(1. + sqrt(2.)*k + k*k) / denom;
  310. b1[ch][i] = 2. * v0*(k*k - 1.) / denom;
  311. b2[ch][i] = v0*(1. - sqrt(2.)*k + k*k) / denom;
  312. a1[ch][i] = 2. * (v0*k*k - 1.) / denom;
  313. a2[ch][i] = (1. - sqrt(2. * v0)*k + v0*k*k) / denom;
  314. } else {
  315. // HF boost
  316. float denom = 1. + sqrt(2.)*k + k*k;
  317. b0[ch][i] = (v0 + sqrt(2. * v0)*k + k*k) / denom;
  318. b1[ch][i] = 2. * (k*k - v0) / denom;
  319. b2[ch][i] = (v0 - sqrt(2. * v0)*k + k*k) / denom;
  320. a1[ch][i] = 2. * (k*k - 1.) / denom;
  321. a2[ch][i] = (1. - sqrt(2.)*k + k*k) / denom;
  322. }
  323. }
  324. void ZamEQ2Plugin::peq(int i, int ch, float srate, float fc, float g, float bw)
  325. {
  326. float k, v0, q;
  327. k = tanf(M_PI * fc / srate);
  328. v0 = powf(10., g / 20.);
  329. q = powf(2., 1./bw)/(powf(2., bw) - 1.); //q from octave bw
  330. if (g < 0.f) {
  331. // cut
  332. float denom = 1. + k/(v0*q) + k*k;
  333. b0[ch][i] = (1. + k/q + k*k) / denom;
  334. b1[ch][i] = 2. * (k*k - 1.) / denom;
  335. b2[ch][i] = (1. - k/q + k*k) / denom;
  336. a1[ch][i] = b1[ch][i];
  337. a2[ch][i] = (1. - k/(v0*q) + k*k) / denom;
  338. } else {
  339. // boost
  340. float denom = 1. + k/q + k*k;
  341. b0[ch][i] = (1. + k*v0/q + k*k) / denom;
  342. b1[ch][i] = 2. * (k*k - 1.) / denom;
  343. b2[ch][i] = (1. - k*v0/q + k*k) / denom;
  344. a1[ch][i] = b1[ch][i];
  345. a2[ch][i] = (1. - k/q + k*k) / denom;
  346. }
  347. }
  348. float ZamEQ2Plugin::run_filter(int i, int ch, double in)
  349. {
  350. double out;
  351. in = sanitize_denormal(in);
  352. out = in * b0[ch][i] + x1[ch][i] * b1[ch][i]
  353. + x2[ch][i] * b2[ch][i]
  354. - y1[ch][i] * a1[ch][i]
  355. - y2[ch][i] * a2[ch][i] + 1e-20f;
  356. out = sanitize_denormal(out);
  357. x2[ch][i] = sanitize_denormal(x1[ch][i]);
  358. y2[ch][i] = sanitize_denormal(y1[ch][i]);
  359. x1[ch][i] = in;
  360. y1[ch][i] = out;
  361. return (float) out;
  362. }
  363. void ZamEQ2Plugin::d_run(float** inputs, float** outputs, uint32_t frames)
  364. {
  365. float srate = d_getSampleRate();
  366. lowshelf(0, 0, srate, freql, gainl);
  367. peq(1, 0, srate, freq1, gain1, q1);
  368. peq(2, 0, srate, freq2, gain2, q2);
  369. highshelf(3, 0, srate, freqh, gainh);
  370. for (uint32_t i = 0; i < frames; i++) {
  371. double tmp,tmpl, tmph;
  372. double in = inputs[0][i];
  373. in = sanitize_denormal(in);
  374. //lowshelf
  375. tmpl = (gainl == 0.f) ? in : run_filter(0, 0, in);
  376. //highshelf
  377. tmph = (gainh == 0.f) ? tmpl : run_filter(3, 0, tmpl);
  378. //parametric1
  379. tmp = (gain1 == 0.f) ? tmph : run_filter(1, 0, tmph);
  380. //parametric2
  381. tmpl = (gain2 == 0.f) ? tmp : run_filter(2, 0, tmp);
  382. outputs[0][i] = inputs[0][i];
  383. outputs[0][i] = (float) tmpl;
  384. outputs[0][i] *= from_dB(master);
  385. }
  386. }
  387. // -----------------------------------------------------------------------
  388. Plugin* createPlugin()
  389. {
  390. return new ZamEQ2Plugin();
  391. }
  392. // -----------------------------------------------------------------------
  393. END_NAMESPACE_DISTRHO