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.

254 lines
7.7KB

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