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.

juce_ResamplingAudioSource.cpp 7.8KB

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