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.

255 lines
7.9KB

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