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.

460 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. return ((int) (in - originalIn) + wrap) % wrap;
  216. }
  217. template <typename InterpolatorType>
  218. static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio,
  219. const float* in, float* out, int numOut,
  220. int available, int wrap, float gain) noexcept
  221. {
  222. if (actualRatio == 1.0)
  223. {
  224. if (available >= numOut)
  225. {
  226. FloatVectorOperations::addWithMultiply (out, in, gain, numOut);
  227. pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap);
  228. }
  229. else
  230. {
  231. FloatVectorOperations::addWithMultiply (out, in, gain, available);
  232. pushInterpolationSamples (lastInputSamples, in, available, available, wrap);
  233. if (wrap > 0)
  234. {
  235. FloatVectorOperations::addWithMultiply (out, in - wrap, gain, numOut - available);
  236. pushInterpolationSamples (lastInputSamples, in - wrap, numOut - available, available, wrap);
  237. }
  238. else
  239. {
  240. for (int i = 0; i < numOut-available; ++i)
  241. pushInterpolationSample (lastInputSamples, 0.0);
  242. }
  243. }
  244. return numOut;
  245. }
  246. auto originalIn = in;
  247. auto pos = subSamplePos;
  248. bool exceeded = false;
  249. if (actualRatio < 1.0)
  250. {
  251. for (int i = numOut; --i >= 0;)
  252. {
  253. if (pos >= 1.0)
  254. {
  255. if (exceeded)
  256. {
  257. pushInterpolationSample (lastInputSamples, 0.0);
  258. }
  259. else
  260. {
  261. pushInterpolationSample (lastInputSamples, *in++);
  262. if (--available <= 0)
  263. {
  264. if (wrap > 0)
  265. {
  266. in -= wrap;
  267. available += wrap;
  268. }
  269. else
  270. {
  271. exceeded = true;
  272. }
  273. }
  274. }
  275. pos -= 1.0;
  276. }
  277. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  278. pos += actualRatio;
  279. }
  280. }
  281. else
  282. {
  283. for (int i = numOut; --i >= 0;)
  284. {
  285. while (pos < actualRatio)
  286. {
  287. if (exceeded)
  288. {
  289. pushInterpolationSample (lastInputSamples, 0.0);
  290. }
  291. else
  292. {
  293. pushInterpolationSample (lastInputSamples, *in++);
  294. if (--available <= 0)
  295. {
  296. if (wrap > 0)
  297. {
  298. in -= wrap;
  299. available += wrap;
  300. }
  301. else
  302. {
  303. exceeded = true;
  304. }
  305. }
  306. }
  307. pos += 1.0;
  308. }
  309. pos -= actualRatio;
  310. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos));
  311. }
  312. }
  313. subSamplePos = pos;
  314. return ((int) (in - originalIn) + wrap) % wrap;
  315. }
  316. template <typename InterpolatorType>
  317. static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio,
  318. const float* in, float* out, int numOut, float gain) noexcept
  319. {
  320. auto pos = subSamplePos;
  321. if (actualRatio == 1.0 && pos == 1.0)
  322. {
  323. FloatVectorOperations::addWithMultiply (out, in, gain, numOut);
  324. pushInterpolationSamples (lastInputSamples, in, numOut);
  325. return numOut;
  326. }
  327. int numUsed = 0;
  328. while (numOut > 0)
  329. {
  330. while (pos >= 1.0)
  331. {
  332. pushInterpolationSample (lastInputSamples, in[numUsed++]);
  333. pos -= 1.0;
  334. }
  335. *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos);
  336. pos += actualRatio;
  337. --numOut;
  338. }
  339. subSamplePos = pos;
  340. return numUsed;
  341. }
  342. }
  343. //==============================================================================
  344. template <int k>
  345. struct LagrangeResampleHelper
  346. {
  347. static forcedinline void calc (float& a, float b) noexcept { a *= b * (1.0f / k); }
  348. };
  349. template<>
  350. struct LagrangeResampleHelper<0>
  351. {
  352. static forcedinline void calc (float&, float) noexcept {}
  353. };
  354. struct LagrangeAlgorithm
  355. {
  356. static forcedinline float valueAtOffset (const float* inputs, float offset) noexcept
  357. {
  358. return calcCoefficient<0> (inputs[4], offset)
  359. + calcCoefficient<1> (inputs[3], offset)
  360. + calcCoefficient<2> (inputs[2], offset)
  361. + calcCoefficient<3> (inputs[1], offset)
  362. + calcCoefficient<4> (inputs[0], offset);
  363. }
  364. template <int k>
  365. static forcedinline float calcCoefficient (float input, float offset) noexcept
  366. {
  367. LagrangeResampleHelper<0 - k>::calc (input, -2.0f - offset);
  368. LagrangeResampleHelper<1 - k>::calc (input, -1.0f - offset);
  369. LagrangeResampleHelper<2 - k>::calc (input, 0.0f - offset);
  370. LagrangeResampleHelper<3 - k>::calc (input, 1.0f - offset);
  371. LagrangeResampleHelper<4 - k>::calc (input, 2.0f - offset);
  372. return input;
  373. }
  374. };
  375. LagrangeInterpolator::LagrangeInterpolator() noexcept { reset(); }
  376. LagrangeInterpolator::~LagrangeInterpolator() noexcept {}
  377. void LagrangeInterpolator::reset() noexcept
  378. {
  379. subSamplePos = 1.0;
  380. for (auto& s : lastInputSamples)
  381. s = 0;
  382. }
  383. int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut, int available, int wrap) noexcept
  384. {
  385. return interpolate<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap);
  386. }
  387. int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut) noexcept
  388. {
  389. return interpolate<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut);
  390. }
  391. int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, int available, int wrap, float gain) noexcept
  392. {
  393. return interpolateAdding<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap, gain);
  394. }
  395. int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, float gain) noexcept
  396. {
  397. return interpolateAdding<LagrangeAlgorithm> (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, gain);
  398. }
  399. } // namespace juce