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.

332 lines
9.8KB

  1. /*
  2. * ZamCompX2 Stereo compressor
  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 "ZamCompX2Plugin.hpp"
  18. START_NAMESPACE_DISTRHO
  19. // -----------------------------------------------------------------------
  20. ZamCompX2Plugin::ZamCompX2Plugin()
  21. : Plugin(paramCount, 1, 0) // 1 program, 0 states
  22. {
  23. // set default values
  24. d_setProgram(0);
  25. }
  26. // -----------------------------------------------------------------------
  27. // Init
  28. void ZamCompX2Plugin::d_initParameter(uint32_t index, Parameter& parameter)
  29. {
  30. switch (index)
  31. {
  32. case paramAttack:
  33. parameter.hints = PARAMETER_IS_AUTOMABLE;
  34. parameter.name = "Attack";
  35. parameter.symbol = "att";
  36. parameter.unit = "ms";
  37. parameter.ranges.def = 10.0f;
  38. parameter.ranges.min = 0.1f;
  39. parameter.ranges.max = 100.0f;
  40. break;
  41. case paramRelease:
  42. parameter.hints = PARAMETER_IS_AUTOMABLE;
  43. parameter.name = "Release";
  44. parameter.symbol = "rel";
  45. parameter.unit = "ms";
  46. parameter.ranges.def = 80.0f;
  47. parameter.ranges.min = 1.0f;
  48. parameter.ranges.max = 500.0f;
  49. break;
  50. case paramKnee:
  51. parameter.hints = PARAMETER_IS_AUTOMABLE;
  52. parameter.name = "Knee";
  53. parameter.symbol = "kn";
  54. parameter.unit = "dB";
  55. parameter.ranges.def = 0.0f;
  56. parameter.ranges.min = 0.0f;
  57. parameter.ranges.max = 9.0f;
  58. break;
  59. case paramRatio:
  60. parameter.hints = PARAMETER_IS_AUTOMABLE;
  61. parameter.name = "Ratio";
  62. parameter.symbol = "rat";
  63. parameter.unit = " ";
  64. parameter.ranges.def = 4.0f;
  65. parameter.ranges.min = 1.0f;
  66. parameter.ranges.max = 20.0f;
  67. break;
  68. case paramThresh:
  69. parameter.hints = PARAMETER_IS_AUTOMABLE;
  70. parameter.name = "Threshold";
  71. parameter.symbol = "thr";
  72. parameter.unit = "dB";
  73. parameter.ranges.def = 0.0f;
  74. parameter.ranges.min = -80.0f;
  75. parameter.ranges.max = 0.0f;
  76. break;
  77. case paramMakeup:
  78. parameter.hints = PARAMETER_IS_AUTOMABLE;
  79. parameter.name = "Makeup";
  80. parameter.symbol = "mak";
  81. parameter.unit = "dB";
  82. parameter.ranges.def = 0.0f;
  83. parameter.ranges.min = 0.0f;
  84. parameter.ranges.max = 30.0f;
  85. break;
  86. case paramGainRed:
  87. parameter.hints = PARAMETER_IS_OUTPUT;
  88. parameter.name = "Gain Reduction";
  89. parameter.symbol = "gr";
  90. parameter.unit = "dB";
  91. parameter.ranges.def = 0.0f;
  92. parameter.ranges.min = 0.0f;
  93. parameter.ranges.max = 20.0f;
  94. break;
  95. case paramStereo:
  96. parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_INTEGER;
  97. parameter.name = "Stereolink";
  98. parameter.symbol = "stereo";
  99. parameter.unit = " ";
  100. parameter.ranges.def = 1.0f;
  101. parameter.ranges.min = 0.0f;
  102. parameter.ranges.max = 2.0f;
  103. break;
  104. case paramOutputLevel:
  105. parameter.hints = PARAMETER_IS_OUTPUT;
  106. parameter.name = "Output Level";
  107. parameter.symbol = "outlevel";
  108. parameter.unit = "dB";
  109. parameter.ranges.def = -45.0f;
  110. parameter.ranges.min = -45.0f;
  111. parameter.ranges.max = 20.0f;
  112. break;
  113. }
  114. }
  115. void ZamCompX2Plugin::d_initProgramName(uint32_t index, d_string& programName)
  116. {
  117. if (index != 0)
  118. return;
  119. programName = "Default";
  120. }
  121. // -----------------------------------------------------------------------
  122. // Internal data
  123. float ZamCompX2Plugin::d_getParameterValue(uint32_t index) const
  124. {
  125. switch (index)
  126. {
  127. case paramAttack:
  128. return attack;
  129. break;
  130. case paramRelease:
  131. return release;
  132. break;
  133. case paramKnee:
  134. return knee;
  135. break;
  136. case paramRatio:
  137. return ratio;
  138. break;
  139. case paramThresh:
  140. return thresdb;
  141. break;
  142. case paramMakeup:
  143. return makeup;
  144. break;
  145. case paramGainRed:
  146. return gainred;
  147. break;
  148. case paramStereo:
  149. return stereolink;
  150. break;
  151. case paramOutputLevel:
  152. return outlevel;
  153. break;
  154. default:
  155. return 0.0f;
  156. }
  157. }
  158. void ZamCompX2Plugin::d_setParameterValue(uint32_t index, float value)
  159. {
  160. switch (index)
  161. {
  162. case paramAttack:
  163. attack = value;
  164. break;
  165. case paramRelease:
  166. release = value;
  167. break;
  168. case paramKnee:
  169. knee = value;
  170. break;
  171. case paramRatio:
  172. ratio = value;
  173. break;
  174. case paramThresh:
  175. thresdb = value;
  176. break;
  177. case paramMakeup:
  178. makeup = value;
  179. break;
  180. case paramGainRed:
  181. gainred = value;
  182. break;
  183. case paramStereo:
  184. stereolink = value;
  185. break;
  186. case paramOutputLevel:
  187. outlevel = value;
  188. break;
  189. }
  190. }
  191. void ZamCompX2Plugin::d_setProgram(uint32_t index)
  192. {
  193. if (index != 0)
  194. return;
  195. /* Default parameter values */
  196. attack = 10.0f;
  197. release = 80.0f;
  198. knee = 0.0f;
  199. ratio = 4.0f;
  200. thresdb = 0.0f;
  201. makeup = 0.0f;
  202. stereolink = 1.0f;
  203. /* reset filter values */
  204. d_activate();
  205. }
  206. // -----------------------------------------------------------------------
  207. // Process
  208. void ZamCompX2Plugin::d_activate()
  209. {
  210. gainred = 0.0f;
  211. outlevel = -45.0f;
  212. oldL_yl = oldL_y1 = oldR_yl = oldR_y1 = 0.f;
  213. }
  214. void ZamCompX2Plugin::d_run(const float** inputs, float** outputs, uint32_t frames)
  215. {
  216. float srate = d_getSampleRate();
  217. float width=(knee-0.99f)*6.f;
  218. float cdb=0.f;
  219. float attack_coeff = exp(-1000.f/(attack * srate));
  220. float release_coeff = exp(-1000.f/(release * srate));
  221. int stereo = (stereolink > 1.f) ? STEREOLINK_MAX : (stereolink > 0.f) ? STEREOLINK_AVERAGE : STEREOLINK_UNCOUPLED;
  222. float max = 0.f;
  223. float Lgain = 1.f;
  224. float Rgain = 1.f;
  225. float Lxg, Lxl, Lyg, Lyl, Ly1;
  226. float Rxg, Rxl, Ryg, Ryl, Ry1;
  227. uint32_t i;
  228. for (i = 0; i < frames; i++) {
  229. Lyg = Ryg = 0.f;
  230. Lxg = (inputs[0][i]==0.f) ? -160.f : to_dB(fabs(inputs[0][i]));
  231. Rxg = (inputs[1][i]==0.f) ? -160.f : to_dB(fabs(inputs[1][i]));
  232. Lxg = sanitize_denormal(Lxg);
  233. Rxg = sanitize_denormal(Rxg);
  234. if (2.f*(Lxg-thresdb)<-width) {
  235. Lyg = Lxg;
  236. } else if (2.f*fabs(Lxg-thresdb)<=width) {
  237. Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width);
  238. } else if (2.f*(Lxg-thresdb)>width) {
  239. Lyg = thresdb + (Lxg-thresdb)/ratio;
  240. }
  241. Lyg = sanitize_denormal(Lyg);
  242. if (2.f*(Rxg-thresdb)<-width) {
  243. Ryg = Rxg;
  244. } else if (2.f*fabs(Rxg-thresdb)<=width) {
  245. Ryg = Rxg + (1.f/ratio-1.f)*(Rxg-thresdb+width/2.f)*(Rxg-thresdb+width/2.f)/(2.f*width);
  246. } else if (2.f*(Rxg-thresdb)>width) {
  247. Ryg = thresdb + (Rxg-thresdb)/ratio;
  248. }
  249. Ryg = sanitize_denormal(Ryg);
  250. if (stereo == STEREOLINK_UNCOUPLED) {
  251. Lxl = Lxg - Lyg;
  252. Rxl = Rxg - Ryg;
  253. } else if (stereo == STEREOLINK_MAX) {
  254. Lxl = Rxl = fmaxf(Lxg - Lyg, Rxg - Ryg);
  255. } else {
  256. Lxl = Rxl = (Lxg - Lyg + Rxg - Ryg) / 2.f;
  257. }
  258. oldL_y1 = sanitize_denormal(oldL_y1);
  259. oldR_y1 = sanitize_denormal(oldR_y1);
  260. oldL_yl = sanitize_denormal(oldL_yl);
  261. oldR_yl = sanitize_denormal(oldR_yl);
  262. Ly1 = fmaxf(Lxl, release_coeff * oldL_y1+(1.f-release_coeff)*Lxl);
  263. Lyl = attack_coeff * oldL_yl+(1.f-attack_coeff)*Ly1;
  264. Ly1 = sanitize_denormal(Ly1);
  265. Lyl = sanitize_denormal(Lyl);
  266. cdb = -Lyl;
  267. Lgain = from_dB(cdb);
  268. gainred = Lyl;
  269. Ry1 = fmaxf(Rxl, release_coeff * oldR_y1+(1.f-release_coeff)*Rxl);
  270. Ryl = attack_coeff * oldR_yl+(1.f-attack_coeff)*Ry1;
  271. Ry1 = sanitize_denormal(Ry1);
  272. Ryl = sanitize_denormal(Ryl);
  273. cdb = -Ryl;
  274. Rgain = from_dB(cdb);
  275. outputs[0][i] = inputs[0][i];
  276. outputs[0][i] *= Lgain * from_dB(makeup);
  277. outputs[1][i] = inputs[1][i];
  278. outputs[1][i] *= Rgain * from_dB(makeup);
  279. max = (fabsf(outputs[0][i]) > max) ? fabsf(outputs[0][i]) : sanitize_denormal(max);
  280. max = (fabsf(outputs[1][i]) > max) ? fabsf(outputs[1][i]) : sanitize_denormal(max);
  281. oldL_yl = Lyl;
  282. oldR_yl = Ryl;
  283. oldL_y1 = Ly1;
  284. oldR_y1 = Ry1;
  285. }
  286. outlevel = (max == 0.f) ? -45.f : to_dB(max);
  287. }
  288. // -----------------------------------------------------------------------
  289. Plugin* createPlugin()
  290. {
  291. return new ZamCompX2Plugin();
  292. }
  293. // -----------------------------------------------------------------------
  294. END_NAMESPACE_DISTRHO