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.

441 lines
14KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.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 3 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 LICENSE file.
  16. */
  17. #include <cstdio>
  18. #include <cstring>
  19. // fix blendish build, missing symbol in debug mode
  20. #ifdef DEBUG
  21. extern "C" {
  22. float bnd_clamp(float v, float mn, float mx) {
  23. return (v > mx)?mx:(v < mn)?mn:v;
  24. }
  25. }
  26. #endif
  27. // fix bogaudio build, another missing symbol
  28. #ifdef DEBUG
  29. namespace bogaudio {
  30. struct FollowerBase {
  31. static float efGainMaxDecibelsDebug;
  32. };
  33. float FollowerBase::efGainMaxDecibelsDebug = 12.0f;
  34. }
  35. #endif
  36. // Compile those nice implementation-in-header little libraries
  37. #define NANOSVG_IMPLEMENTATION
  38. #define NANOSVG_ALL_COLOR_KEYWORDS
  39. #undef nsvgParseFromFile
  40. #include <nanosvg.h>
  41. // Custom Cardinal filtering
  42. static const struct {
  43. const char* const filename;
  44. const char* shapes[4];
  45. } pathsToFilterOut[] = {
  46. {
  47. "/Core/AudioInterface.svg",
  48. {"path39377","path39381","path39383","path39379"}
  49. },
  50. {
  51. "/Core/AudioInterface2.svg",
  52. {"path18733","path18737","path18731","path18735"}
  53. },
  54. {
  55. "/Core/AudioInterface16.svg",
  56. {"path40283","path40287","path40289","path40285"}
  57. },
  58. {
  59. "/Core/CV-CC.svg",
  60. {"path12881","path12885","path12887","path12883"}
  61. },
  62. {
  63. "/Core/CV-Gate.svg",
  64. {"path13127","path13131","path13133","path13129"}
  65. },
  66. {
  67. "/Core/CV-MIDI.svg",
  68. {"path12747","path12751","path12753","path12749"}
  69. },
  70. {
  71. "/Core/MIDI-CC.svg",
  72. {"path9740","path9744","path9746","path9742"}
  73. },
  74. {
  75. "/Core/MIDI-CV.svg",
  76. {"path11803","path11807","path11809","path11805"}
  77. },
  78. {
  79. "/Core/MIDI-Gate.svg",
  80. {"path11634","path11638","path11640","path11636"}
  81. },
  82. {
  83. "/Core/MIDI-Map.svg",
  84. {"path21209","path21213","path21215","path21211"}
  85. },
  86. {
  87. "/Core/Notes.svg",
  88. {"path6935","path6939","path6941","path6937"}
  89. },
  90. {
  91. "/Fundamental/8vert.svg",
  92. {"path69642","path69646","path69640","path69644"}
  93. },
  94. {
  95. "/Fundamental/ADSR.svg",
  96. {"path33693","path33697","path33699","path33695"}
  97. },
  98. {
  99. "/Fundamental/Delay.svg",
  100. {"path25369","path25373","path25375","path25371"}
  101. },
  102. {
  103. "/Fundamental/LFO-1.svg",
  104. {"path35889","path35893","path35895","path35891"}
  105. },
  106. {
  107. "/Fundamental/LFO-2.svg",
  108. {"path36131","path36135","path36137","path36133"}
  109. },
  110. {
  111. "/Fundamental/Merge.svg",
  112. {"path29991","path29995","path29989","path29993"}
  113. },
  114. {
  115. "/Fundamental/MidSide.svg",
  116. {"path44181","path44185","path44179","path44183"}
  117. },
  118. {
  119. "/Fundamental/Mutes.svg",
  120. {"path21613","path21617","path21611","path21615"}
  121. },
  122. {
  123. "/Fundamental/Noise.svg",
  124. {"path105594","path105598","path105592","path105596"}
  125. },
  126. {
  127. "/Fundamental/Octave.svg",
  128. {"path38471","path38475","path38469","path38473"}
  129. },
  130. {
  131. "/Fundamental/Pulses.svg",
  132. {"path46241","path46245","path46239","path46243"}
  133. },
  134. {
  135. "/Fundamental/Quantizer.svg",
  136. {"path38549","path38553","path38547","path38551"}
  137. },
  138. {
  139. "/Fundamental/Random.svg",
  140. {"path89732","path89736","path89730","path89734"}
  141. },
  142. {
  143. "/Fundamental/SEQ3.svg",
  144. {"path35687","path35691","path35693","path35689"}
  145. },
  146. {
  147. "/Fundamental/Scope.svg",
  148. {"path33887","path33891","path33893","path33889"}
  149. },
  150. {
  151. "/Fundamental/Split.svg",
  152. {"path29999","path30003","path29997","path30001"}
  153. },
  154. {
  155. "/Fundamental/Sum.svg",
  156. {"path10913","path10917","path10911","path10915"}
  157. },
  158. {
  159. "/Fundamental/Unity.svg",
  160. {"path21219","path21223","path21217","path21221"}
  161. },
  162. {
  163. "/Fundamental/VCF.svg",
  164. {"path25239","path25243","path25245","path25241"}
  165. },
  166. {
  167. "/Fundamental/VCMixer.svg",
  168. {"path125839","path125843","path125845","path125841"}
  169. },
  170. {
  171. "/Fundamental/VCO-1.svg",
  172. {"path33533","path33537","path33539","path33535"}
  173. },
  174. {
  175. "/Fundamental/VCO-2.svg",
  176. {"path37557","path37561","path37563","path37559"}
  177. },
  178. {
  179. "/Fundamental/Viz.svg",
  180. {"path41769","path41773","path41767","path41771"}
  181. },
  182. };
  183. static const struct {
  184. const char* const filename;
  185. const char* shapeIdsToIgnore[5];
  186. const int shapeNumberToIgnore;
  187. } svgFilesToInvert[] = {
  188. { "/AnimatedCircuits/FoldingLight.svg", {}, -1 },
  189. { "/AudibleInstruments/Blinds.svg", {}, -1 },
  190. { "/AudibleInstruments/Braids.svg", {}, -1 },
  191. { "/AudibleInstruments/Branches.svg", {}, -1 },
  192. { "/AudibleInstruments/Clouds.svg", {}, -1 },
  193. { "/AudibleInstruments/Elements.svg", {}, -1 },
  194. { "/AudibleInstruments/Frames.svg", {}, -1 },
  195. { "/AudibleInstruments/Kinks.svg", {}, -1 },
  196. { "/AudibleInstruments/Links.svg", {}, -1 },
  197. { "/AudibleInstruments/Marbles.svg", {}, -1 },
  198. { "/AudibleInstruments/Peaks.svg", {}, -1 },
  199. { "/AudibleInstruments/Plaits.svg", {}, -1 },
  200. { "/AudibleInstruments/Rings.svg", {}, -1 },
  201. { "/AudibleInstruments/Ripples.svg", {}, -1 },
  202. { "/AudibleInstruments/Shades.svg", {}, -1 },
  203. { "/AudibleInstruments/Sheep.svg", {}, -1 },
  204. { "/AudibleInstruments/Shelves.svg", {}, -1 },
  205. { "/AudibleInstruments/Stages.svg", {}, -1 },
  206. { "/AudibleInstruments/Streams.svg", {}, -1 },
  207. { "/AudibleInstruments/Tides.svg", {}, -1 },
  208. { "/AudibleInstruments/Tides2.svg", {}, -1 },
  209. { "/AudibleInstruments/Veils.svg", {}, -1 },
  210. { "/AudibleInstruments/Warps.svg", {}, -1 },
  211. { "/Bidoo/ACNE.svg", {}, -1 },
  212. { "/Bidoo/ANTN.svg", {}, -1 },
  213. { "/Bidoo/BAFIS.svg", {}, -1 },
  214. { "/Bidoo/BAR.svg", {"rect833"}, -1 },
  215. { "/Bidoo/BISTROT.svg", {}, -1 },
  216. { "/Bidoo/BORDL.svg", {"rect959-3-0-7-5","rect959-3-0-7","rect959-3-0","rect959-3"}, -1 },
  217. { "/Bidoo/CANARD.svg", {"rect959-3-7"}, -1 },
  218. { "/Bidoo/CHUTE.svg", {}, -1 },
  219. { "/Bidoo/DFUZE.svg", {}, -1 },
  220. { "/Bidoo/DIKTAT.svg", {"rect843","rect843-0","rect843-0-8"}, -1 },
  221. { "/Bidoo/DTROY.svg", {"rect959-3"}, -1 },
  222. { "/Bidoo/DUKE.svg", {}, -1 },
  223. { "/Bidoo/EMILE.svg", {}, -1 },
  224. { "/Bidoo/FLAME.svg", {}, -1 },
  225. { "/Bidoo/FORK.svg", {}, -1 },
  226. { "/Bidoo/FREIN.svg", {}, -1 },
  227. { "/Bidoo/HCTIP.svg", {}, -1 },
  228. { "/Bidoo/HUITRE.svg", {}, -1 },
  229. { "/Bidoo/LATE.svg", {}, -1 },
  230. { "/Bidoo/LIMBO.svg", {}, -1 },
  231. { "/Bidoo/LIMONADE.svg", {"rect839","rect839-6"}, -1 },
  232. { "/Bidoo/LOURDE.svg", {}, -1 },
  233. { "/Bidoo/MAGMA.svg", {}, -1 },
  234. { "/Bidoo/MINIBAR.svg", {"rect833"}, -1 },
  235. { "/Bidoo/MOIRE.svg", {"rect843","rect843-7"}, -1 },
  236. { "/Bidoo/MS.svg", {}, -1 },
  237. { "/Bidoo/MU.svg", {"rect864"}, -1 },
  238. { "/Bidoo/OAI.svg", {}, -1 },
  239. { "/Bidoo/OUAIVE.svg", {"rect959-3-7"}, -1 },
  240. { "/Bidoo/PERCO.svg", {}, -1 },
  241. { "/Bidoo/PILOT.svg", {"rect843-6-4-5","rect843","rect843-4","rect843-6-4","rect843-6-7"}, -1 },
  242. { "/Bidoo/POUPRE.svg", {}, -1 },
  243. { "/Bidoo/RABBIT.svg", {}, -1 },
  244. { "/Bidoo/REI.svg", {}, -1 },
  245. { "/Bidoo/SIGMA.svg", {}, -1 },
  246. { "/Bidoo/TIARE.svg", {}, -1 },
  247. { "/Bidoo/TOCANTE.svg", {"rect843"}, -1 },
  248. { "/Bidoo/VOID.svg", {}, -1 },
  249. { "/Bidoo/ZINC.svg", {}, -1 },
  250. { "/Bidoo/ZOUMAI.svg", {}, -1 },
  251. { "/cf/ALGEBRA.svg", {}, -1 },
  252. { "/cf/BUFFER.svg", {}, -1 },
  253. { "/cf/CHOKE.svg", {}, -1 },
  254. { "/cf/CUBE.svg", {}, -1 },
  255. { "/cf/CUTS.svg", {}, -1 },
  256. { "/cf/DISTO.svg", {}, -1 },
  257. { "/cf/EACH.svg", {}, -1 },
  258. { "/cf/FOUR.svg", {}, -1 },
  259. { "/cf/FUNKTION.svg", {}, -1 },
  260. { "/cf/L3DS3Q.svg", {}, 3 },
  261. { "/cf/LABEL.svg", {}, -1 },
  262. { "/cf/LEDS.svg", {}, -1 },
  263. { "/cf/LEDSEQ.svg", {}, 3 },
  264. { "/cf/MASTER.svg", {}, -1 },
  265. { "/cf/METRO.svg", {}, -1 },
  266. { "/cf/MONO.svg", {}, -1 },
  267. { "/cf/PATCH.svg", {}, -1 },
  268. { "/cf/PEAK.svg", {}, -1 },
  269. { "/cf/PLAY.svg", {}, -1 },
  270. { "/cf/PLAYER.svg", {}, -1 },
  271. { "/cf/SLIDERSEQ.svg", {}, -1 },
  272. { "/cf/STEPS.svg", {}, -1 },
  273. { "/cf/STEREO.svg", {}, -1 },
  274. { "/cf/SUB.svg", {}, -1 },
  275. { "/cf/trSEQ.svg", {}, -1 },
  276. { "/cf/VARIABLE.svg", {}, -1 },
  277. { "/DrumKit/Baronial.svg", {}, -1 },
  278. { "/DrumKit/BD9.svg", {}, -1 },
  279. { "/DrumKit/ClosedHH.svg", {}, -1 },
  280. { "/DrumKit/CR78.svg", {}, -1 },
  281. { "/DrumKit/DMX.svg", {}, -1 },
  282. { "/DrumKit/Gnome.svg", {}, -1 },
  283. { "/DrumKit/Marionette.svg", {}, -1 },
  284. { "/DrumKit/OpenHH.svg", {}, -1 },
  285. { "/DrumKit/SBD.svg", {}, -1 },
  286. { "/DrumKit/Sequencer.svg", {}, -1 },
  287. { "/DrumKit/Snare.svg", {}, -1 },
  288. { "/DrumKit/Tomi.svg", {}, -1 },
  289. { "/Fundamental/SequentialSwitch1.svg", {}, -1 },
  290. { "/Fundamental/SequentialSwitch2.svg", {}, -1 },
  291. { "/Fundamental/VCA-1.svg", {}, -1 },
  292. { "/Fundamental/VCA.svg", {}, -1 },
  293. };
  294. static void removeShape(NSVGimage* const handle, const char* const id)
  295. {
  296. for (NSVGshape *shape = handle->shapes, *old = nullptr; shape != nullptr; old = shape, shape = shape->next)
  297. {
  298. if (std::strcmp(shape->id, id) != 0)
  299. continue;
  300. if (old != nullptr)
  301. old->next = shape->next;
  302. else
  303. handle->shapes = shape->next;
  304. nsvg__deletePaths(shape->paths);
  305. free(shape);
  306. break;
  307. }
  308. }
  309. static bool invertPaint(NSVGpaint& paint, const char* const svgFileToInvert = nullptr)
  310. {
  311. // Special case for DrumKit background grandient
  312. if (paint.type == NSVG_PAINT_LINEAR_GRADIENT && svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0)
  313. {
  314. paint.type = NSVG_PAINT_COLOR;
  315. paint.color = 0xff000000;
  316. return true;
  317. }
  318. if (paint.type != NSVG_PAINT_COLOR)
  319. return false;
  320. // Special case for Bidoo red color
  321. if (paint.color == 0xff001fcd && svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/Bidoo/", 7) == 0)
  322. {
  323. paint.color = 0xcf8b94c4;
  324. return true;
  325. }
  326. switch (paint.color)
  327. {
  328. // scopes or other special things (do nothing)
  329. case 0x40ffffff:
  330. case 0xff004200:
  331. case 0xff2b281e:
  332. case 0xff2d2827:
  333. case 0xff303030:
  334. case 0xff362c23:
  335. case 0xff40352c:
  336. return false;
  337. // pure black (convert to not quite pure white)
  338. case 0xff000000:
  339. paint.color = 0xffd0d0d0;
  340. return true;
  341. // all others (direct invert)
  342. default:
  343. paint.color = (paint.color & 0xff000000)
  344. | (0xff0000 - (paint.color & 0xff0000))
  345. | (0xff00 - (paint.color & 0xff00))
  346. | (0xff - (paint.color & 0xff));
  347. return true;
  348. }
  349. }
  350. extern "C" {
  351. NSVGimage* nsvgParseFromFileCardinal(const char* filename, const char* units, float dpi);
  352. }
  353. NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* const units, const float dpi)
  354. {
  355. if (NSVGimage* const handle = nsvgParseFromFile(filename, units, dpi))
  356. {
  357. for (size_t i = 0; i < sizeof(pathsToFilterOut)/sizeof(pathsToFilterOut[0]); ++i)
  358. {
  359. const char* const pathToFilterOut = pathsToFilterOut[i].filename;
  360. const size_t filenamelen = std::strlen(filename);
  361. const size_t filterlen = std::strlen(pathToFilterOut);
  362. if (filenamelen < filterlen)
  363. continue;
  364. if (std::strncmp(filename + (filenamelen-filterlen), pathToFilterOut, filterlen) != 0)
  365. continue;
  366. puts("Removing CC-ND deadlock from file...");
  367. removeShape(handle, pathsToFilterOut[i].shapes[0]);
  368. removeShape(handle, pathsToFilterOut[i].shapes[1]);
  369. removeShape(handle, pathsToFilterOut[i].shapes[2]);
  370. removeShape(handle, pathsToFilterOut[i].shapes[3]);
  371. for (NSVGshape* shape = handle->shapes; shape != nullptr; shape = shape->next)
  372. {
  373. invertPaint(shape->fill);
  374. invertPaint(shape->stroke);
  375. }
  376. return handle;
  377. }
  378. for (size_t i = 0; i < sizeof(svgFilesToInvert)/sizeof(svgFilesToInvert[0]); ++i)
  379. {
  380. const char* const svgFileToInvert = svgFilesToInvert[i].filename;
  381. const size_t filenamelen = std::strlen(filename);
  382. const size_t filterlen = std::strlen(svgFileToInvert);
  383. if (filenamelen < filterlen)
  384. continue;
  385. if (std::strncmp(filename + (filenamelen-filterlen), svgFileToInvert, filterlen) != 0)
  386. continue;
  387. const char* const* const shapeIdsToIgnore = svgFilesToInvert[i].shapeIdsToIgnore;
  388. const int shapeNumberToIgnore = svgFilesToInvert[i].shapeNumberToIgnore;
  389. int shapeCounter = 0;
  390. for (NSVGshape* shape = handle->shapes; shape != nullptr; shape = shape->next, ++shapeCounter)
  391. {
  392. if (shapeNumberToIgnore == shapeCounter)
  393. continue;
  394. bool ignore = false;
  395. for (size_t j = 0; j < 5 && shapeIdsToIgnore[j] != nullptr; ++j)
  396. {
  397. if (std::strcmp(shape->id, shapeIdsToIgnore[j]) == 0)
  398. {
  399. ignore = true;
  400. break;
  401. }
  402. }
  403. if (ignore)
  404. continue;
  405. if (invertPaint(shape->fill, svgFileToInvert))
  406. invertPaint(shape->stroke, svgFileToInvert);
  407. }
  408. return handle;
  409. }
  410. return handle;
  411. }
  412. return nullptr;
  413. }