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.

298 lines
9.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. ImageConvolutionKernel::ImageConvolutionKernel (const int size_)
  22. : values ((size_t) (size_ * size_)),
  23. size (size_)
  24. {
  25. clear();
  26. }
  27. ImageConvolutionKernel::~ImageConvolutionKernel()
  28. {
  29. }
  30. //==============================================================================
  31. float ImageConvolutionKernel::getKernelValue (const int x, const int y) const noexcept
  32. {
  33. if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
  34. return values [x + y * size];
  35. jassertfalse;
  36. return 0;
  37. }
  38. void ImageConvolutionKernel::setKernelValue (const int x, const int y, const float value) noexcept
  39. {
  40. if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
  41. {
  42. values [x + y * size] = value;
  43. }
  44. else
  45. {
  46. jassertfalse;
  47. }
  48. }
  49. void ImageConvolutionKernel::clear()
  50. {
  51. for (int i = size * size; --i >= 0;)
  52. values[i] = 0;
  53. }
  54. void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum)
  55. {
  56. double currentTotal = 0.0;
  57. for (int i = size * size; --i >= 0;)
  58. currentTotal += values[i];
  59. rescaleAllValues ((float) (desiredTotalSum / currentTotal));
  60. }
  61. void ImageConvolutionKernel::rescaleAllValues (const float multiplier)
  62. {
  63. for (int i = size * size; --i >= 0;)
  64. values[i] *= multiplier;
  65. }
  66. //==============================================================================
  67. void ImageConvolutionKernel::createGaussianBlur (const float radius)
  68. {
  69. const double radiusFactor = -1.0 / (radius * radius * 2);
  70. const int centre = size >> 1;
  71. for (int y = size; --y >= 0;)
  72. {
  73. for (int x = size; --x >= 0;)
  74. {
  75. const int cx = x - centre;
  76. const int cy = y - centre;
  77. values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy));
  78. }
  79. }
  80. setOverallSum (1.0f);
  81. }
  82. //==============================================================================
  83. void ImageConvolutionKernel::applyToImage (Image& destImage,
  84. const Image& sourceImage,
  85. const Rectangle<int>& destinationArea) const
  86. {
  87. if (sourceImage == destImage)
  88. {
  89. destImage.duplicateIfShared();
  90. }
  91. else
  92. {
  93. if (sourceImage.getWidth() != destImage.getWidth()
  94. || sourceImage.getHeight() != destImage.getHeight()
  95. || sourceImage.getFormat() != destImage.getFormat())
  96. {
  97. jassertfalse;
  98. return;
  99. }
  100. }
  101. const Rectangle<int> area (destinationArea.getIntersection (destImage.getBounds()));
  102. if (area.isEmpty())
  103. return;
  104. const int right = area.getRight();
  105. const int bottom = area.getBottom();
  106. const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(),
  107. Image::BitmapData::writeOnly);
  108. uint8* line = destData.data;
  109. const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly);
  110. if (destData.pixelStride == 4)
  111. {
  112. for (int y = area.getY(); y < bottom; ++y)
  113. {
  114. uint8* dest = line;
  115. line += destData.lineStride;
  116. for (int x = area.getX(); x < right; ++x)
  117. {
  118. float c1 = 0;
  119. float c2 = 0;
  120. float c3 = 0;
  121. float c4 = 0;
  122. for (int yy = 0; yy < size; ++yy)
  123. {
  124. const int sy = y + yy - (size >> 1);
  125. if (sy >= srcData.height)
  126. break;
  127. if (sy >= 0)
  128. {
  129. int sx = x - (size >> 1);
  130. const uint8* src = srcData.getPixelPointer (sx, sy);
  131. for (int xx = 0; xx < size; ++xx)
  132. {
  133. if (sx >= srcData.width)
  134. break;
  135. if (sx >= 0)
  136. {
  137. const float kernelMult = values [xx + yy * size];
  138. c1 += kernelMult * *src++;
  139. c2 += kernelMult * *src++;
  140. c3 += kernelMult * *src++;
  141. c4 += kernelMult * *src++;
  142. }
  143. else
  144. {
  145. src += 4;
  146. }
  147. ++sx;
  148. }
  149. }
  150. }
  151. *dest++ = (uint8) jmin (0xff, roundToInt (c1));
  152. *dest++ = (uint8) jmin (0xff, roundToInt (c2));
  153. *dest++ = (uint8) jmin (0xff, roundToInt (c3));
  154. *dest++ = (uint8) jmin (0xff, roundToInt (c4));
  155. }
  156. }
  157. }
  158. else if (destData.pixelStride == 3)
  159. {
  160. for (int y = area.getY(); y < bottom; ++y)
  161. {
  162. uint8* dest = line;
  163. line += destData.lineStride;
  164. for (int x = area.getX(); x < right; ++x)
  165. {
  166. float c1 = 0;
  167. float c2 = 0;
  168. float c3 = 0;
  169. for (int yy = 0; yy < size; ++yy)
  170. {
  171. const int sy = y + yy - (size >> 1);
  172. if (sy >= srcData.height)
  173. break;
  174. if (sy >= 0)
  175. {
  176. int sx = x - (size >> 1);
  177. const uint8* src = srcData.getPixelPointer (sx, sy);
  178. for (int xx = 0; xx < size; ++xx)
  179. {
  180. if (sx >= srcData.width)
  181. break;
  182. if (sx >= 0)
  183. {
  184. const float kernelMult = values [xx + yy * size];
  185. c1 += kernelMult * *src++;
  186. c2 += kernelMult * *src++;
  187. c3 += kernelMult * *src++;
  188. }
  189. else
  190. {
  191. src += 3;
  192. }
  193. ++sx;
  194. }
  195. }
  196. }
  197. *dest++ = (uint8) roundToInt (c1);
  198. *dest++ = (uint8) roundToInt (c2);
  199. *dest++ = (uint8) roundToInt (c3);
  200. }
  201. }
  202. }
  203. else if (destData.pixelStride == 1)
  204. {
  205. for (int y = area.getY(); y < bottom; ++y)
  206. {
  207. uint8* dest = line;
  208. line += destData.lineStride;
  209. for (int x = area.getX(); x < right; ++x)
  210. {
  211. float c1 = 0;
  212. for (int yy = 0; yy < size; ++yy)
  213. {
  214. const int sy = y + yy - (size >> 1);
  215. if (sy >= srcData.height)
  216. break;
  217. if (sy >= 0)
  218. {
  219. int sx = x - (size >> 1);
  220. const uint8* src = srcData.getPixelPointer (sx, sy);
  221. for (int xx = 0; xx < size; ++xx)
  222. {
  223. if (sx >= srcData.width)
  224. break;
  225. if (sx >= 0)
  226. {
  227. const float kernelMult = values [xx + yy * size];
  228. c1 += kernelMult * *src++;
  229. }
  230. else
  231. {
  232. src += 3;
  233. }
  234. ++sx;
  235. }
  236. }
  237. }
  238. *dest++ = (uint8) roundToInt (c1);
  239. }
  240. }
  241. }
  242. }
  243. } // namespace juce