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.

256 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. bufferPos (0),
  24. sampsInBuffer (0),
  25. subSampleOffset (0),
  26. numChannels (numChannels_)
  27. {
  28. jassert (input != nullptr);
  29. zeromem (coefficients, sizeof (coefficients));
  30. }
  31. ResamplingAudioSource::~ResamplingAudioSource() {}
  32. void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample)
  33. {
  34. jassert (samplesInPerOutputSample > 0);
  35. const SpinLock::ScopedLockType sl (ratioLock);
  36. ratio = jmax (0.0, samplesInPerOutputSample);
  37. }
  38. void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
  39. double sampleRate)
  40. {
  41. const SpinLock::ScopedLockType sl (ratioLock);
  42. input->prepareToPlay (samplesPerBlockExpected, sampleRate);
  43. buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
  44. buffer.clear();
  45. sampsInBuffer = 0;
  46. bufferPos = 0;
  47. subSampleOffset = 0.0;
  48. filterStates.calloc ((size_t) numChannels);
  49. srcBuffers.calloc ((size_t) numChannels);
  50. destBuffers.calloc ((size_t) numChannels);
  51. createLowPass (ratio);
  52. resetFilters();
  53. }
  54. void ResamplingAudioSource::releaseResources()
  55. {
  56. input->releaseResources();
  57. buffer.setSize (numChannels, 0);
  58. }
  59. void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
  60. {
  61. double localRatio;
  62. {
  63. const SpinLock::ScopedLockType sl (ratioLock);
  64. localRatio = ratio;
  65. }
  66. if (lastRatio != localRatio)
  67. {
  68. createLowPass (localRatio);
  69. lastRatio = localRatio;
  70. }
  71. const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 2;
  72. int bufferSize = buffer.getNumSamples();
  73. if (bufferSize < sampsNeeded + 8)
  74. {
  75. bufferPos %= bufferSize;
  76. bufferSize = sampsNeeded + 32;
  77. buffer.setSize (buffer.getNumChannels(), bufferSize, true, true);
  78. }
  79. bufferPos %= bufferSize;
  80. int endOfBufferPos = bufferPos + sampsInBuffer;
  81. const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels());
  82. while (sampsNeeded > sampsInBuffer)
  83. {
  84. endOfBufferPos %= bufferSize;
  85. int numToDo = jmin (sampsNeeded - sampsInBuffer,
  86. bufferSize - endOfBufferPos);
  87. AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo);
  88. input->getNextAudioBlock (readInfo);
  89. if (localRatio > 1.0001)
  90. {
  91. // for down-sampling, pre-apply the filter..
  92. for (int i = channelsToProcess; --i >= 0;)
  93. applyFilter (buffer.getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]);
  94. }
  95. sampsInBuffer += numToDo;
  96. endOfBufferPos += numToDo;
  97. }
  98. for (int channel = 0; channel < channelsToProcess; ++channel)
  99. {
  100. destBuffers[channel] = info.buffer->getWritePointer (channel, info.startSample);
  101. srcBuffers[channel] = buffer.getReadPointer (channel);
  102. }
  103. int nextPos = (bufferPos + 1) % bufferSize;
  104. for (int m = info.numSamples; --m >= 0;)
  105. {
  106. const float alpha = (float) subSampleOffset;
  107. for (int channel = 0; channel < channelsToProcess; ++channel)
  108. *destBuffers[channel]++ = srcBuffers[channel][bufferPos]
  109. + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
  110. subSampleOffset += localRatio;
  111. jassert (sampsInBuffer > 0);
  112. while (subSampleOffset >= 1.0)
  113. {
  114. if (++bufferPos >= bufferSize)
  115. bufferPos = 0;
  116. --sampsInBuffer;
  117. nextPos = (bufferPos + 1) % bufferSize;
  118. subSampleOffset -= 1.0;
  119. }
  120. }
  121. if (localRatio < 0.9999)
  122. {
  123. // for up-sampling, apply the filter after transposing..
  124. for (int i = channelsToProcess; --i >= 0;)
  125. applyFilter (info.buffer->getWritePointer (i, info.startSample), info.numSamples, filterStates[i]);
  126. }
  127. else if (localRatio <= 1.0001 && info.numSamples > 0)
  128. {
  129. // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
  130. for (int i = channelsToProcess; --i >= 0;)
  131. {
  132. const float* const endOfBuffer = info.buffer->getReadPointer (i, info.startSample + info.numSamples - 1);
  133. FilterState& fs = filterStates[i];
  134. if (info.numSamples > 1)
  135. {
  136. fs.y2 = fs.x2 = *(endOfBuffer - 1);
  137. }
  138. else
  139. {
  140. fs.y2 = fs.y1;
  141. fs.x2 = fs.x1;
  142. }
  143. fs.y1 = fs.x1 = *endOfBuffer;
  144. }
  145. }
  146. jassert (sampsInBuffer >= 0);
  147. }
  148. void ResamplingAudioSource::createLowPass (const double frequencyRatio)
  149. {
  150. const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
  151. : 0.5 * frequencyRatio;
  152. const double n = 1.0 / std::tan (double_Pi * jmax (0.001, proportionalRate));
  153. const double nSquared = n * n;
  154. const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);
  155. setFilterCoefficients (c1,
  156. c1 * 2.0f,
  157. c1,
  158. 1.0,
  159. c1 * 2.0 * (1.0 - nSquared),
  160. c1 * (1.0 - std::sqrt (2.0) * n + nSquared));
  161. }
  162. void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6)
  163. {
  164. const double a = 1.0 / c4;
  165. c1 *= a;
  166. c2 *= a;
  167. c3 *= a;
  168. c5 *= a;
  169. c6 *= a;
  170. coefficients[0] = c1;
  171. coefficients[1] = c2;
  172. coefficients[2] = c3;
  173. coefficients[3] = c4;
  174. coefficients[4] = c5;
  175. coefficients[5] = c6;
  176. }
  177. void ResamplingAudioSource::resetFilters()
  178. {
  179. filterStates.clear ((size_t) numChannels);
  180. }
  181. void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
  182. {
  183. while (--num >= 0)
  184. {
  185. const double in = *samples;
  186. double out = coefficients[0] * in
  187. + coefficients[1] * fs.x1
  188. + coefficients[2] * fs.x2
  189. - coefficients[4] * fs.y1
  190. - coefficients[5] * fs.y2;
  191. #if JUCE_INTEL
  192. if (! (out < -1.0e-8 || out > 1.0e-8))
  193. out = 0;
  194. #endif
  195. fs.x2 = fs.x1;
  196. fs.x1 = in;
  197. fs.y2 = fs.y1;
  198. fs.y1 = out;
  199. *samples++ = (float) out;
  200. }
  201. }