The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

468 lines
15KB

  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. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. namespace
  20. {
  21. static forcedinline void pushInterpolationSample (float* lastInputSamples, float newValue) noexcept
  22. {
  23. lastInputSamples[4] = lastInputSamples[3];
  24. lastInputSamples[3] = lastInputSamples[2];
  25. lastInputSamples[2] = lastInputSamples[1];
  26. lastInputSamples[1] = lastInputSamples[0];
  27. lastInputSamples[0] = newValue;
  28. }
  29. static forcedinline void pushInterpolationSamples (float* lastInputSamples, const float* input, int numOut) noexcept
  30. {
  31. if (numOut >= 5)
  32. {
  33. for (int i = 0; i < 5; ++i)
  34. lastInputSamples[i] = input[--numOut];
  35. }
  36. else
  37. {
  38. for (int i = 0; i < numOut; ++i)
  39. pushInterpolationSample (lastInputSamples, input[i]);
  40. }
  41. }
  42. static forcedinline void pushInterpolationSamples (float* lastInputSamples, const float* input,
  43. int numOut, int available, int wrapAround) noexcept
  44. {
  45. if (numOut >= 5)
  46. {
  47. if (available >= 5)
  48. {
  49. for (int i = 0; i < 5; ++i)
  50. lastInputSamples[i] = input[--numOut];
  51. }
  52. else
  53. {
  54. for (int i = 0; i < available; ++i)
  55. lastInputSamples[i] = input[--numOut];
  56. if (wrapAround > 0)
  57. {
  58. numOut -= wrapAround;
  59. for (int i = available; i < 5; ++i)
  60. lastInputSamples[i] = input[--numOut];
  61. }
  62. else
  63. {
  64. for (int i = available; i < 5; ++i)
  65. lastInputSamples[i] = 0.0f;
  66. }
  67. }
  68. }
  69. else
  70. {
  71. if (numOut > available)
  72. {
  73. for (int i = 0; i < available; ++i)
  74. pushInterpolationSample (lastInputSamples, input[i]);
  75. if (wrapAround > 0)
  76. {
  77. for (int i = 0; i < numOut - available; ++i)
  78. pushInterpolationSample (lastInputSamples, input[i + available - wrapAround]);
  79. }
  80. else
  81. {
  82. for (int i = 0; i < numOut - available; ++i)
  83. pushInterpolationSample (lastInputSamples, 0);
  84. }
  85. }
  86. else
  87. {
  88. for (int i = 0; i < numOut; ++i)
  89. pushInterpolationSample (lastInputSamples, input[i]);
  90. }
  91. }
  92. }
  93. template <typename InterpolatorType>
  94. static int interpolate (float* lastInputSamples, double& subSamplePos, double actualRatio,
  95. const float* in, float* out, int numOut) noexcept
  96. {
  97. auto pos = subSamplePos;
  98. if (actualRatio == 1.0 && pos == 1.0)
  99. {
  100. memcpy (out, in, (size_t) numOut * sizeof (float));
  101. pushInterpolationSamples (lastInputSamples, in, numOut);
  102. return numOut;
  103. }
  104. int numUsed = 0;
  105. while (numOut > 0)
  106. {
  107. while (pos >= 1.0)
  108. {
  109. pushInterpolationSample (lastInputSamples, in[numUsed++]);
  110. pos -= 1.0;
  111. }
  112. *out++ = InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  113. pos += actualRatio;
  114. --numOut;
  115. }
  116. subSamplePos = pos;
  117. return numUsed;
  118. }
  119. template <typename InterpolatorType>
  120. static int interpolate (float* lastInputSamples, double& subSamplePos, double actualRatio,
  121. const float* in, float* out, int numOut, int available, int wrap) noexcept
  122. {
  123. if (actualRatio == 1.0)
  124. {
  125. if (available >= numOut)
  126. {
  127. memcpy (out, in, (size_t) numOut * sizeof (float));
  128. pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap);
  129. }
  130. else
  131. {
  132. memcpy (out, in, (size_t) available * sizeof (float));
  133. pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap);
  134. if (wrap > 0)
  135. {
  136. memcpy (out + available, in + available - wrap, (size_t) (numOut - available) * sizeof (float));
  137. pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap);
  138. }
  139. else
  140. {
  141. for (int i = 0; i < numOut - available; ++i)
  142. pushInterpolationSample (lastInputSamples, 0);
  143. }
  144. }
  145. return numOut;
  146. }
  147. auto originalIn = in;
  148. auto pos = subSamplePos;
  149. bool exceeded = false;
  150. if (actualRatio < 1.0)
  151. {
  152. for (int i = numOut; --i >= 0;)
  153. {
  154. if (pos >= 1.0)
  155. {
  156. if (exceeded)
  157. {
  158. pushInterpolationSample (lastInputSamples, 0);
  159. }
  160. else
  161. {
  162. pushInterpolationSample (lastInputSamples, *in++);
  163. if (--available <= 0)
  164. {
  165. if (wrap > 0)
  166. {
  167. in -= wrap;
  168. available += wrap;
  169. }
  170. else
  171. {
  172. exceeded = true;
  173. }
  174. }
  175. }
  176. pos -= 1.0;
  177. }
  178. *out++ = InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  179. pos += actualRatio;
  180. }
  181. }
  182. else
  183. {
  184. for (int i = numOut; --i >= 0;)
  185. {
  186. while (pos < actualRatio)
  187. {
  188. if (exceeded)
  189. {
  190. pushInterpolationSample (lastInputSamples, 0);
  191. }
  192. else
  193. {
  194. pushInterpolationSample (lastInputSamples, *in++);
  195. if (--available <= 0)
  196. {
  197. if (wrap > 0)
  198. {
  199. in -= wrap;
  200. available += wrap;
  201. }
  202. else
  203. {
  204. exceeded = true;
  205. }
  206. }
  207. }
  208. pos += 1.0;
  209. }
  210. pos -= actualRatio;
  211. *out++ = InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos));
  212. }
  213. }
  214. subSamplePos = pos;
  215. if (wrap == 0)
  216. return (int) (in - originalIn);
  217. return ((int) (in - originalIn) + wrap) % wrap;
  218. }
  219. template <typename InterpolatorType>
  220. static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio,
  221. const float* in, float* out, int numOut,
  222. int available, int wrap, float gain) noexcept
  223. {
  224. if (actualRatio == 1.0)
  225. {
  226. if (available >= numOut)
  227. {
  228. FloatVectorOperations::addWithMultiply (out, in, gain, numOut);
  229. pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap);
  230. }
  231. else
  232. {
  233. FloatVectorOperations::addWithMultiply (out, in, gain, available);
  234. pushInterpolationSamples (lastInputSamples, in, available, available, wrap);
  235. if (wrap > 0)
  236. {
  237. FloatVectorOperations::addWithMultiply (out, in - wrap, gain, numOut - available);
  238. pushInterpolationSamples (lastInputSamples, in - wrap, numOut - available, available, wrap);
  239. }
  240. else
  241. {
  242. for (int i = 0; i < numOut-available; ++i)
  243. pushInterpolationSample (lastInputSamples, 0.0);
  244. }
  245. }
  246. return numOut;
  247. }
  248. auto originalIn = in;
  249. auto pos = subSamplePos;
  250. bool exceeded = false;
  251. if (actualRatio < 1.0)
  252. {
  253. for (int i = numOut; --i >= 0;)
  254. {
  255. if (pos >= 1.0)
  256. {
  257. if (exceeded)
  258. {
  259. pushInterpolationSample (lastInputSamples, 0.0);
  260. }
  261. else
  262. {
  263. pushInterpolationSample (lastInputSamples, *in++);
  264. if (--available <= 0)
  265. {
  266. if (wrap > 0)
  267. {
  268. in -= wrap;
  269. available += wrap;
  270. }
  271. else
  272. {
  273. exceeded = true;
  274. }
  275. }
  276. }
  277. pos -= 1.0;
  278. }
  279. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  280. pos += actualRatio;
  281. }
  282. }
  283. else
  284. {
  285. for (int i = numOut; --i >= 0;)
  286. {
  287. while (pos < actualRatio)
  288. {
  289. if (exceeded)
  290. {
  291. pushInterpolationSample (lastInputSamples, 0.0);
  292. }
  293. else
  294. {
  295. pushInterpolationSample (lastInputSamples, *in++);
  296. if (--available <= 0)
  297. {
  298. if (wrap > 0)
  299. {
  300. in -= wrap;
  301. available += wrap;
  302. }
  303. else
  304. {
  305. exceeded = true;
  306. }
  307. }
  308. }
  309. pos += 1.0;
  310. }
  311. pos -= actualRatio;
  312. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos));
  313. }
  314. }
  315. subSamplePos = pos;
  316. if (wrap == 0)
  317. return (int) (in - originalIn);
  318. return ((int) (in - originalIn) + wrap) % wrap;
  319. }
  320. template <typename InterpolatorType>
  321. static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio,
  322. const float* in, float* out, int numOut, float gain) noexcept
  323. {
  324. auto pos = subSamplePos;
  325. if (actualRatio == 1.0 && pos == 1.0)
  326. {
  327. FloatVectorOperations::addWithMultiply (out, in, gain, numOut);
  328. pushInterpolationSamples (lastInputSamples, in, numOut);
  329. return numOut;
  330. }
  331. int numUsed = 0;
  332. while (numOut > 0)
  333. {
  334. while (pos >= 1.0)
  335. {
  336. pushInterpolationSample (lastInputSamples, in[numUsed++]);
  337. pos -= 1.0;
  338. }
  339. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  340. pos += actualRatio;
  341. --numOut;
  342. }
  343. subSamplePos = pos;
  344. return numUsed;
  345. }
  346. }
  347. //==============================================================================
  348. template <int k>
  349. struct LagrangeResampleHelper
  350. {
  351. static forcedinline void calc (float& a, float b) noexcept { a *= b * (1.0f / k); }
  352. };
  353. template<>
  354. struct LagrangeResampleHelper<0>
  355. {
  356. static forcedinline void calc (float&, float) noexcept {}
  357. };
  358. struct LagrangeAlgorithm
  359. {
  360. static forcedinline float valueAtOffset (const float* inputs, float offset) noexcept
  361. {
  362. return calcCoefficient<0> (inputs[4], offset)
  363. + calcCoefficient<1> (inputs[3], offset)
  364. + calcCoefficient<2> (inputs[2], offset)
  365. + calcCoefficient<3> (inputs[1], offset)
  366. + calcCoefficient<4> (inputs[0], offset);
  367. }
  368. template <int k>
  369. static forcedinline float calcCoefficient (float input, float offset) noexcept
  370. {
  371. LagrangeResampleHelper<0 - k>::calc (input, -2.0f - offset);
  372. LagrangeResampleHelper<1 - k>::calc (input, -1.0f - offset);
  373. LagrangeResampleHelper<2 - k>::calc (input, 0.0f - offset);
  374. LagrangeResampleHelper<3 - k>::calc (input, 1.0f - offset);
  375. LagrangeResampleHelper<4 - k>::calc (input, 2.0f - offset);
  376. return input;
  377. }
  378. };
  379. LagrangeInterpolator::LagrangeInterpolator() noexcept { reset(); }
  380. LagrangeInterpolator::~LagrangeInterpolator() noexcept {}
  381. void LagrangeInterpolator::reset() noexcept
  382. {
  383. subSamplePos = 1.0;
  384. for (auto& s : lastInputSamples)
  385. s = 0;
  386. }
  387. int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut, int available, int wrap) noexcept
  388. {
  389. return interpolate<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap);
  390. }
  391. int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut) noexcept
  392. {
  393. return interpolate<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut);
  394. }
  395. int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, int available, int wrap, float gain) noexcept
  396. {
  397. return interpolateAdding<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap, gain);
  398. }
  399. int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, float gain) noexcept
  400. {
  401. return interpolateAdding<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, gain);
  402. }
  403. } // namespace juce