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.

443 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. namespace ColourHelpers
  16. {
  17. static uint8 floatToUInt8 (const float n) noexcept
  18. {
  19. return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : static_cast<uint8> (n * 255.996f));
  20. }
  21. //==============================================================================
  22. struct HSB
  23. {
  24. HSB (Colour col) noexcept
  25. {
  26. const int r = col.getRed();
  27. const int g = col.getGreen();
  28. const int b = col.getBlue();
  29. const int hi = jmax (r, g, b);
  30. const int lo = jmin (r, g, b);
  31. if (hi != 0)
  32. {
  33. saturation = (hi - lo) / (float) hi;
  34. if (saturation > 0)
  35. {
  36. const float invDiff = 1.0f / (hi - lo);
  37. const float red = (hi - r) * invDiff;
  38. const float green = (hi - g) * invDiff;
  39. const float blue = (hi - b) * invDiff;
  40. if (r == hi)
  41. hue = blue - green;
  42. else if (g == hi)
  43. hue = 2.0f + red - blue;
  44. else
  45. hue = 4.0f + green - red;
  46. hue *= 1.0f / 6.0f;
  47. if (hue < 0)
  48. ++hue;
  49. }
  50. else
  51. {
  52. hue = 0;
  53. }
  54. }
  55. else
  56. {
  57. saturation = hue = 0;
  58. }
  59. brightness = hi / 255.0f;
  60. }
  61. Colour toColour (Colour original) const noexcept
  62. {
  63. return Colour (hue, saturation, brightness, original.getAlpha());
  64. }
  65. static PixelARGB toRGB (float h, float s, float v, const uint8 alpha) noexcept
  66. {
  67. v = jlimit (0.0f, 255.0f, v * 255.0f);
  68. const uint8 intV = (uint8) roundToInt (v);
  69. if (s <= 0)
  70. return PixelARGB (alpha, intV, intV, intV);
  71. s = jmin (1.0f, s);
  72. h = (h - std::floor (h)) * 6.0f + 0.00001f; // need a small adjustment to compensate for rounding errors
  73. const float f = h - std::floor (h);
  74. const uint8 x = (uint8) roundToInt (v * (1.0f - s));
  75. if (h < 1.0f) return PixelARGB (alpha, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x);
  76. if (h < 2.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - s * f)), intV, x);
  77. if (h < 3.0f) return PixelARGB (alpha, x, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))));
  78. if (h < 4.0f) return PixelARGB (alpha, x, (uint8) roundToInt (v * (1.0f - s * f)), intV);
  79. if (h < 5.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x, intV);
  80. return PixelARGB (alpha, intV, x, (uint8) roundToInt (v * (1.0f - s * f)));
  81. }
  82. float hue, saturation, brightness;
  83. };
  84. //==============================================================================
  85. struct YIQ
  86. {
  87. YIQ (Colour c) noexcept
  88. {
  89. const float r = c.getFloatRed();
  90. const float g = c.getFloatGreen();
  91. const float b = c.getFloatBlue();
  92. y = 0.2999f * r + 0.5870f * g + 0.1140f * b;
  93. i = 0.5957f * r - 0.2744f * g - 0.3212f * b;
  94. q = 0.2114f * r - 0.5225f * g - 0.3113f * b;
  95. alpha = c.getFloatAlpha();
  96. }
  97. Colour toColour() const noexcept
  98. {
  99. return Colour::fromFloatRGBA (y + 0.9563f * i + 0.6210f * q,
  100. y - 0.2721f * i - 0.6474f * q,
  101. y - 1.1070f * i + 1.7046f * q,
  102. alpha);
  103. }
  104. float y, i, q, alpha;
  105. };
  106. }
  107. //==============================================================================
  108. bool Colour::operator== (const Colour& other) const noexcept { return argb.getNativeARGB() == other.argb.getNativeARGB(); }
  109. bool Colour::operator!= (const Colour& other) const noexcept { return argb.getNativeARGB() != other.argb.getNativeARGB(); }
  110. //==============================================================================
  111. Colour::Colour (const uint32 col) noexcept
  112. : argb (static_cast<uint8> ((col >> 24) & 0xff),
  113. static_cast<uint8> ((col >> 16) & 0xff),
  114. static_cast<uint8> ((col >> 8) & 0xff),
  115. static_cast<uint8> (col & 0xff))
  116. {
  117. }
  118. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue) noexcept
  119. {
  120. argb.setARGB (0xff, red, green, blue);
  121. }
  122. Colour Colour::fromRGB (const uint8 red, const uint8 green, const uint8 blue) noexcept
  123. {
  124. return Colour (red, green, blue);
  125. }
  126. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept
  127. {
  128. argb.setARGB (alpha, red, green, blue);
  129. }
  130. Colour Colour::fromRGBA (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept
  131. {
  132. return Colour (red, green, blue, alpha);
  133. }
  134. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const float alpha) noexcept
  135. {
  136. argb.setARGB (ColourHelpers::floatToUInt8 (alpha), red, green, blue);
  137. }
  138. Colour Colour::fromFloatRGBA (const float red, const float green, const float blue, const float alpha) noexcept
  139. {
  140. return Colour (ColourHelpers::floatToUInt8 (red),
  141. ColourHelpers::floatToUInt8 (green),
  142. ColourHelpers::floatToUInt8 (blue), alpha);
  143. }
  144. Colour::Colour (const float hue, const float saturation, const float brightness, const float alpha) noexcept
  145. : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, ColourHelpers::floatToUInt8 (alpha)))
  146. {
  147. }
  148. Colour Colour::fromHSV (const float hue, const float saturation, const float brightness, const float alpha) noexcept
  149. {
  150. return Colour (hue, saturation, brightness, alpha);
  151. }
  152. Colour::Colour (const float hue, const float saturation, const float brightness, const uint8 alpha) noexcept
  153. : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, alpha))
  154. {
  155. }
  156. Colour::Colour (PixelARGB argb_) noexcept
  157. : argb (argb_)
  158. {
  159. }
  160. Colour::Colour (PixelRGB rgb) noexcept
  161. : argb (Colour (rgb.getInARGBMaskOrder()).argb)
  162. {
  163. }
  164. Colour::Colour (PixelAlpha alpha) noexcept
  165. : argb (Colour (alpha.getInARGBMaskOrder()).argb)
  166. {
  167. }
  168. //==============================================================================
  169. const PixelARGB Colour::getPixelARGB() const noexcept
  170. {
  171. PixelARGB p (argb);
  172. p.premultiply();
  173. return p;
  174. }
  175. uint32 Colour::getARGB() const noexcept
  176. {
  177. return argb.getInARGBMaskOrder();
  178. }
  179. //==============================================================================
  180. bool Colour::isTransparent() const noexcept
  181. {
  182. return getAlpha() == 0;
  183. }
  184. bool Colour::isOpaque() const noexcept
  185. {
  186. return getAlpha() == 0xff;
  187. }
  188. Colour Colour::withAlpha (const uint8 newAlpha) const noexcept
  189. {
  190. PixelARGB newCol (argb);
  191. newCol.setAlpha (newAlpha);
  192. return Colour (newCol);
  193. }
  194. Colour Colour::withAlpha (const float newAlpha) const noexcept
  195. {
  196. jassert (newAlpha >= 0 && newAlpha <= 1.0f);
  197. PixelARGB newCol (argb);
  198. newCol.setAlpha (ColourHelpers::floatToUInt8 (newAlpha));
  199. return Colour (newCol);
  200. }
  201. Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept
  202. {
  203. jassert (alphaMultiplier >= 0);
  204. PixelARGB newCol (argb);
  205. newCol.setAlpha ((uint8) jmin (0xff, roundToInt (alphaMultiplier * newCol.getAlpha())));
  206. return Colour (newCol);
  207. }
  208. //==============================================================================
  209. Colour Colour::overlaidWith (Colour src) const noexcept
  210. {
  211. const int destAlpha = getAlpha();
  212. if (destAlpha <= 0)
  213. return src;
  214. const int invA = 0xff - (int) src.getAlpha();
  215. const int resA = 0xff - (((0xff - destAlpha) * invA) >> 8);
  216. if (resA <= 0)
  217. return *this;
  218. const int da = (invA * destAlpha) / resA;
  219. return Colour ((uint8) (src.getRed() + ((((int) getRed() - src.getRed()) * da) >> 8)),
  220. (uint8) (src.getGreen() + ((((int) getGreen() - src.getGreen()) * da) >> 8)),
  221. (uint8) (src.getBlue() + ((((int) getBlue() - src.getBlue()) * da) >> 8)),
  222. (uint8) resA);
  223. }
  224. Colour Colour::interpolatedWith (Colour other, float proportionOfOther) const noexcept
  225. {
  226. if (proportionOfOther <= 0)
  227. return *this;
  228. if (proportionOfOther >= 1.0f)
  229. return other;
  230. PixelARGB c1 (getPixelARGB());
  231. const PixelARGB c2 (other.getPixelARGB());
  232. c1.tween (c2, (uint32) roundToInt (proportionOfOther * 255.0f));
  233. c1.unpremultiply();
  234. return Colour (c1);
  235. }
  236. //==============================================================================
  237. float Colour::getFloatRed() const noexcept { return getRed() / 255.0f; }
  238. float Colour::getFloatGreen() const noexcept { return getGreen() / 255.0f; }
  239. float Colour::getFloatBlue() const noexcept { return getBlue() / 255.0f; }
  240. float Colour::getFloatAlpha() const noexcept { return getAlpha() / 255.0f; }
  241. //==============================================================================
  242. void Colour::getHSB (float& h, float& s, float& v) const noexcept
  243. {
  244. const ColourHelpers::HSB hsb (*this);
  245. h = hsb.hue;
  246. s = hsb.saturation;
  247. v = hsb.brightness;
  248. }
  249. float Colour::getHue() const noexcept { return ColourHelpers::HSB (*this).hue; }
  250. float Colour::getSaturation() const noexcept { return ColourHelpers::HSB (*this).saturation; }
  251. float Colour::getBrightness() const noexcept { return ColourHelpers::HSB (*this).brightness; }
  252. Colour Colour::withHue (float h) const noexcept { ColourHelpers::HSB hsb (*this); hsb.hue = h; return hsb.toColour (*this); }
  253. Colour Colour::withSaturation (float s) const noexcept { ColourHelpers::HSB hsb (*this); hsb.saturation = s; return hsb.toColour (*this); }
  254. Colour Colour::withBrightness (float v) const noexcept { ColourHelpers::HSB hsb (*this); hsb.brightness = v; return hsb.toColour (*this); }
  255. float Colour::getPerceivedBrightness() const noexcept
  256. {
  257. return std::sqrt (0.241f * square (getFloatRed())
  258. + 0.691f * square (getFloatGreen())
  259. + 0.068f * square (getFloatBlue()));
  260. }
  261. //==============================================================================
  262. Colour Colour::withRotatedHue (const float amountToRotate) const noexcept
  263. {
  264. ColourHelpers::HSB hsb (*this);
  265. hsb.hue += amountToRotate;
  266. return hsb.toColour (*this);
  267. }
  268. Colour Colour::withMultipliedSaturation (const float amount) const noexcept
  269. {
  270. ColourHelpers::HSB hsb (*this);
  271. hsb.saturation = jmin (1.0f, hsb.saturation * amount);
  272. return hsb.toColour (*this);
  273. }
  274. Colour Colour::withMultipliedBrightness (const float amount) const noexcept
  275. {
  276. ColourHelpers::HSB hsb (*this);
  277. hsb.brightness = jmin (1.0f, hsb.brightness * amount);
  278. return hsb.toColour (*this);
  279. }
  280. //==============================================================================
  281. Colour Colour::brighter (float amount) const noexcept
  282. {
  283. amount = 1.0f / (1.0f + amount);
  284. return Colour ((uint8) (255 - (amount * (255 - getRed()))),
  285. (uint8) (255 - (amount * (255 - getGreen()))),
  286. (uint8) (255 - (amount * (255 - getBlue()))),
  287. getAlpha());
  288. }
  289. Colour Colour::darker (float amount) const noexcept
  290. {
  291. amount = 1.0f / (1.0f + amount);
  292. return Colour ((uint8) (amount * getRed()),
  293. (uint8) (amount * getGreen()),
  294. (uint8) (amount * getBlue()),
  295. getAlpha());
  296. }
  297. //==============================================================================
  298. Colour Colour::greyLevel (const float brightness) noexcept
  299. {
  300. const uint8 level = ColourHelpers::floatToUInt8 (brightness);
  301. return Colour (level, level, level);
  302. }
  303. //==============================================================================
  304. Colour Colour::contrasting (const float amount) const noexcept
  305. {
  306. return overlaidWith ((getPerceivedBrightness() >= 0.5f
  307. ? Colours::black
  308. : Colours::white).withAlpha (amount));
  309. }
  310. Colour Colour::contrasting (Colour target, float minContrast) const noexcept
  311. {
  312. const ColourHelpers::YIQ bg (*this);
  313. ColourHelpers::YIQ fg (target);
  314. if (std::abs (bg.y - fg.y) >= minContrast)
  315. return target;
  316. const float y1 = jmax (0.0f, bg.y - minContrast);
  317. const float y2 = jmin (1.0f, bg.y + minContrast);
  318. fg.y = (std::abs (y1 - bg.y) > std::abs (y2 - bg.y)) ? y1 : y2;
  319. return fg.toColour();
  320. }
  321. Colour Colour::contrasting (Colour colour1,
  322. Colour colour2) noexcept
  323. {
  324. const float b1 = colour1.getPerceivedBrightness();
  325. const float b2 = colour2.getPerceivedBrightness();
  326. float best = 0.0f;
  327. float bestDist = 0.0f;
  328. for (float i = 0.0f; i < 1.0f; i += 0.02f)
  329. {
  330. const float d1 = std::abs (i - b1);
  331. const float d2 = std::abs (i - b2);
  332. const float dist = jmin (d1, d2, 1.0f - d1, 1.0f - d2);
  333. if (dist > bestDist)
  334. {
  335. best = i;
  336. bestDist = dist;
  337. }
  338. }
  339. return colour1.overlaidWith (colour2.withMultipliedAlpha (0.5f))
  340. .withBrightness (best);
  341. }
  342. //==============================================================================
  343. String Colour::toString() const
  344. {
  345. return String::toHexString ((int) argb.getInARGBMaskOrder());
  346. }
  347. Colour Colour::fromString (StringRef encodedColourString)
  348. {
  349. return Colour ((uint32) CharacterFunctions::HexParser<int>::parse (encodedColourString.text));
  350. }
  351. String Colour::toDisplayString (const bool includeAlphaValue) const
  352. {
  353. return String::toHexString ((int) (argb.getInARGBMaskOrder() & (includeAlphaValue ? 0xffffffff : 0xffffff)))
  354. .paddedLeft ('0', includeAlphaValue ? 8 : 6)
  355. .toUpperCase();
  356. }
  357. } // namespace juce