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.

264 lines
8.0KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
  21. const bool deleteInputWhenDeleted,
  22. const int numChannels_)
  23. : input (inputSource, deleteInputWhenDeleted),
  24. ratio (1.0),
  25. lastRatio (1.0),
  26. buffer (numChannels_, 0),
  27. sampsInBuffer (0),
  28. numChannels (numChannels_)
  29. {
  30. jassert (input != nullptr);
  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 (numChannels);
  50. srcBuffers.calloc (numChannels);
  51. destBuffers.calloc (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;
  89. readInfo.buffer = &buffer;
  90. readInfo.numSamples = numToDo;
  91. readInfo.startSample = endOfBufferPos;
  92. input->getNextAudioBlock (readInfo);
  93. if (localRatio > 1.0001)
  94. {
  95. // for down-sampling, pre-apply the filter..
  96. for (int i = channelsToProcess; --i >= 0;)
  97. applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]);
  98. }
  99. sampsInBuffer += numToDo;
  100. endOfBufferPos += numToDo;
  101. }
  102. for (int channel = 0; channel < channelsToProcess; ++channel)
  103. {
  104. destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample);
  105. srcBuffers[channel] = buffer.getSampleData (channel, 0);
  106. }
  107. int nextPos = (bufferPos + 1) % bufferSize;
  108. for (int m = info.numSamples; --m >= 0;)
  109. {
  110. const float alpha = (float) subSampleOffset;
  111. const float invAlpha = 1.0f - alpha;
  112. for (int channel = 0; channel < channelsToProcess; ++channel)
  113. *destBuffers[channel]++ = srcBuffers[channel][bufferPos] * invAlpha + srcBuffers[channel][nextPos] * alpha;
  114. subSampleOffset += localRatio;
  115. jassert (sampsInBuffer > 0);
  116. while (subSampleOffset >= 1.0)
  117. {
  118. if (++bufferPos >= bufferSize)
  119. bufferPos = 0;
  120. --sampsInBuffer;
  121. nextPos = (bufferPos + 1) % bufferSize;
  122. subSampleOffset -= 1.0;
  123. }
  124. }
  125. if (localRatio < 0.9999)
  126. {
  127. // for up-sampling, apply the filter after transposing..
  128. for (int i = channelsToProcess; --i >= 0;)
  129. applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]);
  130. }
  131. else if (localRatio <= 1.0001)
  132. {
  133. // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
  134. for (int i = channelsToProcess; --i >= 0;)
  135. {
  136. const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1);
  137. FilterState& fs = filterStates[i];
  138. if (info.numSamples > 1)
  139. {
  140. fs.y2 = fs.x2 = *(endOfBuffer - 1);
  141. }
  142. else
  143. {
  144. fs.y2 = fs.y1;
  145. fs.x2 = fs.x1;
  146. }
  147. fs.y1 = fs.x1 = *endOfBuffer;
  148. }
  149. }
  150. jassert (sampsInBuffer >= 0);
  151. }
  152. void ResamplingAudioSource::createLowPass (const double frequencyRatio)
  153. {
  154. const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
  155. : 0.5 * frequencyRatio;
  156. const double n = 1.0 / std::tan (double_Pi * jmax (0.001, proportionalRate));
  157. const double nSquared = n * n;
  158. const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);
  159. setFilterCoefficients (c1,
  160. c1 * 2.0f,
  161. c1,
  162. 1.0,
  163. c1 * 2.0 * (1.0 - nSquared),
  164. c1 * (1.0 - std::sqrt (2.0) * n + nSquared));
  165. }
  166. void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6)
  167. {
  168. const double a = 1.0 / c4;
  169. c1 *= a;
  170. c2 *= a;
  171. c3 *= a;
  172. c5 *= a;
  173. c6 *= a;
  174. coefficients[0] = c1;
  175. coefficients[1] = c2;
  176. coefficients[2] = c3;
  177. coefficients[3] = c4;
  178. coefficients[4] = c5;
  179. coefficients[5] = c6;
  180. }
  181. void ResamplingAudioSource::resetFilters()
  182. {
  183. filterStates.clear (numChannels);
  184. }
  185. void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
  186. {
  187. while (--num >= 0)
  188. {
  189. const double in = *samples;
  190. double out = coefficients[0] * in
  191. + coefficients[1] * fs.x1
  192. + coefficients[2] * fs.x2
  193. - coefficients[4] * fs.y1
  194. - coefficients[5] * fs.y2;
  195. #if JUCE_INTEL
  196. if (! (out < -1.0e-8 || out > 1.0e-8))
  197. out = 0;
  198. #endif
  199. fs.x2 = fs.x1;
  200. fs.x1 = in;
  201. fs.y2 = fs.y1;
  202. fs.y1 = out;
  203. *samples++ = (float) out;
  204. }
  205. }
  206. END_JUCE_NAMESPACE