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.

258 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
  18. const bool deleteInputWhenDeleted,
  19. const int numChannels_)
  20. : input (inputSource, deleteInputWhenDeleted),
  21. ratio (1.0),
  22. lastRatio (1.0),
  23. buffer (numChannels_, 0),
  24. bufferPos (0),
  25. sampsInBuffer (0),
  26. subSampleOffset (0),
  27. numChannels (numChannels_)
  28. {
  29. jassert (input != nullptr);
  30. zeromem (coefficients, sizeof (coefficients));
  31. }
  32. ResamplingAudioSource::~ResamplingAudioSource() {}
  33. void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample)
  34. {
  35. jassert (samplesInPerOutputSample > 0);
  36. const SpinLock::ScopedLockType sl (ratioLock);
  37. ratio = jmax (0.0, samplesInPerOutputSample);
  38. }
  39. void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
  40. double sampleRate)
  41. {
  42. const SpinLock::ScopedLockType sl (ratioLock);
  43. input->prepareToPlay (samplesPerBlockExpected, sampleRate);
  44. buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
  45. buffer.clear();
  46. sampsInBuffer = 0;
  47. bufferPos = 0;
  48. subSampleOffset = 0.0;
  49. filterStates.calloc ((size_t) numChannels);
  50. srcBuffers.calloc ((size_t) numChannels);
  51. destBuffers.calloc ((size_t) numChannels);
  52. createLowPass (ratio);
  53. resetFilters();
  54. }
  55. void ResamplingAudioSource::releaseResources()
  56. {
  57. input->releaseResources();
  58. buffer.setSize (numChannels, 0);
  59. }
  60. void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
  61. {
  62. double localRatio;
  63. {
  64. const SpinLock::ScopedLockType sl (ratioLock);
  65. localRatio = ratio;
  66. }
  67. if (lastRatio != localRatio)
  68. {
  69. createLowPass (localRatio);
  70. lastRatio = localRatio;
  71. }
  72. const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 2;
  73. int bufferSize = buffer.getNumSamples();
  74. if (bufferSize < sampsNeeded + 8)
  75. {
  76. bufferPos %= bufferSize;
  77. bufferSize = sampsNeeded + 32;
  78. buffer.setSize (buffer.getNumChannels(), bufferSize, true, true);
  79. }
  80. bufferPos %= bufferSize;
  81. int endOfBufferPos = bufferPos + sampsInBuffer;
  82. const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels());
  83. while (sampsNeeded > sampsInBuffer)
  84. {
  85. endOfBufferPos %= bufferSize;
  86. int numToDo = jmin (sampsNeeded - sampsInBuffer,
  87. bufferSize - endOfBufferPos);
  88. AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo);
  89. input->getNextAudioBlock (readInfo);
  90. if (localRatio > 1.0001)
  91. {
  92. // for down-sampling, pre-apply the filter..
  93. for (int i = channelsToProcess; --i >= 0;)
  94. applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]);
  95. }
  96. sampsInBuffer += numToDo;
  97. endOfBufferPos += numToDo;
  98. }
  99. for (int channel = 0; channel < channelsToProcess; ++channel)
  100. {
  101. destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample);
  102. srcBuffers[channel] = buffer.getSampleData (channel, 0);
  103. }
  104. int nextPos = (bufferPos + 1) % bufferSize;
  105. for (int m = info.numSamples; --m >= 0;)
  106. {
  107. const float alpha = (float) subSampleOffset;
  108. for (int channel = 0; channel < channelsToProcess; ++channel)
  109. *destBuffers[channel]++ = srcBuffers[channel][bufferPos]
  110. + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
  111. subSampleOffset += localRatio;
  112. jassert (sampsInBuffer > 0);
  113. while (subSampleOffset >= 1.0)
  114. {
  115. if (++bufferPos >= bufferSize)
  116. bufferPos = 0;
  117. --sampsInBuffer;
  118. nextPos = (bufferPos + 1) % bufferSize;
  119. subSampleOffset -= 1.0;
  120. }
  121. }
  122. if (localRatio < 0.9999)
  123. {
  124. // for up-sampling, apply the filter after transposing..
  125. for (int i = channelsToProcess; --i >= 0;)
  126. applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]);
  127. }
  128. else if (localRatio <= 1.0001 && info.numSamples > 0)
  129. {
  130. // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
  131. for (int i = channelsToProcess; --i >= 0;)
  132. {
  133. const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1);
  134. FilterState& fs = filterStates[i];
  135. if (info.numSamples > 1)
  136. {
  137. fs.y2 = fs.x2 = *(endOfBuffer - 1);
  138. }
  139. else
  140. {
  141. fs.y2 = fs.y1;
  142. fs.x2 = fs.x1;
  143. }
  144. fs.y1 = fs.x1 = *endOfBuffer;
  145. }
  146. }
  147. jassert (sampsInBuffer >= 0);
  148. }
  149. void ResamplingAudioSource::createLowPass (const double frequencyRatio)
  150. {
  151. const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
  152. : 0.5 * frequencyRatio;
  153. const double n = 1.0 / std::tan (double_Pi * jmax (0.001, proportionalRate));
  154. const double nSquared = n * n;
  155. const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);
  156. setFilterCoefficients (c1,
  157. c1 * 2.0f,
  158. c1,
  159. 1.0,
  160. c1 * 2.0 * (1.0 - nSquared),
  161. c1 * (1.0 - std::sqrt (2.0) * n + nSquared));
  162. }
  163. void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6)
  164. {
  165. const double a = 1.0 / c4;
  166. c1 *= a;
  167. c2 *= a;
  168. c3 *= a;
  169. c5 *= a;
  170. c6 *= a;
  171. coefficients[0] = c1;
  172. coefficients[1] = c2;
  173. coefficients[2] = c3;
  174. coefficients[3] = c4;
  175. coefficients[4] = c5;
  176. coefficients[5] = c6;
  177. }
  178. void ResamplingAudioSource::resetFilters()
  179. {
  180. filterStates.clear ((size_t) numChannels);
  181. }
  182. void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
  183. {
  184. while (--num >= 0)
  185. {
  186. const double in = *samples;
  187. double out = coefficients[0] * in
  188. + coefficients[1] * fs.x1
  189. + coefficients[2] * fs.x2
  190. - coefficients[4] * fs.y1
  191. - coefficients[5] * fs.y2;
  192. #if JUCE_INTEL
  193. if (! (out < -1.0e-8 || out > 1.0e-8))
  194. out = 0;
  195. #endif
  196. fs.x2 = fs.x1;
  197. fs.x1 = in;
  198. fs.y2 = fs.y1;
  199. fs.y1 = out;
  200. *samples++ = (float) out;
  201. }
  202. }