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.

262 lines
8.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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_,
  21. TimeSliceThread& backgroundThread_,
  22. const bool deleteSourceWhenDeleted,
  23. const int numberOfSamplesToBuffer_,
  24. const int numberOfChannels_)
  25. : source (source_, deleteSourceWhenDeleted),
  26. backgroundThread (backgroundThread_),
  27. numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)),
  28. numberOfChannels (numberOfChannels_),
  29. buffer (numberOfChannels_, 0),
  30. bufferValidStart (0),
  31. bufferValidEnd (0),
  32. nextPlayPos (0),
  33. wasSourceLooping (false)
  34. {
  35. jassert (source_ != nullptr);
  36. jassert (numberOfSamplesToBuffer_ > 1024); // not much point using this class if you're
  37. // not using a larger buffer..
  38. }
  39. BufferingAudioSource::~BufferingAudioSource()
  40. {
  41. releaseResources();
  42. }
  43. //==============================================================================
  44. void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate_)
  45. {
  46. source->prepareToPlay (samplesPerBlockExpected, sampleRate_);
  47. sampleRate = sampleRate_;
  48. buffer.setSize (numberOfChannels, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
  49. buffer.clear();
  50. bufferValidStart = 0;
  51. bufferValidEnd = 0;
  52. backgroundThread.addTimeSliceClient (this);
  53. while (bufferValidEnd - bufferValidStart < jmin (((int) sampleRate_) / 4,
  54. buffer.getNumSamples() / 2))
  55. {
  56. backgroundThread.addTimeSliceClient (this);
  57. Thread::sleep (5);
  58. }
  59. }
  60. void BufferingAudioSource::releaseResources()
  61. {
  62. backgroundThread.removeTimeSliceClient (this);
  63. buffer.setSize (numberOfChannels, 0);
  64. source->releaseResources();
  65. }
  66. void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
  67. {
  68. const ScopedLock sl (bufferStartPosLock);
  69. const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos);
  70. const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos);
  71. if (validStart == validEnd)
  72. {
  73. // total cache miss
  74. info.clearActiveBufferRegion();
  75. }
  76. else
  77. {
  78. if (validStart > 0)
  79. info.buffer->clear (info.startSample, validStart); // partial cache miss at start
  80. if (validEnd < info.numSamples)
  81. info.buffer->clear (info.startSample + validEnd,
  82. info.numSamples - validEnd); // partial cache miss at end
  83. if (validStart < validEnd)
  84. {
  85. for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;)
  86. {
  87. const int startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples());
  88. const int endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples());
  89. if (startBufferIndex < endBufferIndex)
  90. {
  91. info.buffer->copyFrom (chan, info.startSample + validStart,
  92. buffer,
  93. chan, startBufferIndex,
  94. validEnd - validStart);
  95. }
  96. else
  97. {
  98. const int initialSize = buffer.getNumSamples() - startBufferIndex;
  99. info.buffer->copyFrom (chan, info.startSample + validStart,
  100. buffer,
  101. chan, startBufferIndex,
  102. initialSize);
  103. info.buffer->copyFrom (chan, info.startSample + validStart + initialSize,
  104. buffer,
  105. chan, 0,
  106. (validEnd - validStart) - initialSize);
  107. }
  108. }
  109. }
  110. nextPlayPos += info.numSamples;
  111. if (source->isLooping() && nextPlayPos > 0)
  112. nextPlayPos %= source->getTotalLength();
  113. }
  114. }
  115. int64 BufferingAudioSource::getNextReadPosition() const
  116. {
  117. return (source->isLooping() && nextPlayPos > 0)
  118. ? nextPlayPos % source->getTotalLength()
  119. : nextPlayPos;
  120. }
  121. void BufferingAudioSource::setNextReadPosition (int64 newPosition)
  122. {
  123. const ScopedLock sl (bufferStartPosLock);
  124. nextPlayPos = newPosition;
  125. backgroundThread.addTimeSliceClient (this);
  126. }
  127. bool BufferingAudioSource::readNextBufferChunk()
  128. {
  129. int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
  130. {
  131. const ScopedLock sl (bufferStartPosLock);
  132. if (wasSourceLooping != isLooping())
  133. {
  134. wasSourceLooping = isLooping();
  135. bufferValidStart = 0;
  136. bufferValidEnd = 0;
  137. }
  138. newBVS = jmax ((int64) 0, nextPlayPos);
  139. newBVE = newBVS + buffer.getNumSamples() - 4;
  140. sectionToReadStart = 0;
  141. sectionToReadEnd = 0;
  142. const int maxChunkSize = 2048;
  143. if (newBVS < bufferValidStart || newBVS >= bufferValidEnd)
  144. {
  145. newBVE = jmin (newBVE, newBVS + maxChunkSize);
  146. sectionToReadStart = newBVS;
  147. sectionToReadEnd = newBVE;
  148. bufferValidStart = 0;
  149. bufferValidEnd = 0;
  150. }
  151. else if (std::abs ((int) (newBVS - bufferValidStart)) > 512
  152. || std::abs ((int) (newBVE - bufferValidEnd)) > 512)
  153. {
  154. newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);
  155. sectionToReadStart = bufferValidEnd;
  156. sectionToReadEnd = newBVE;
  157. bufferValidStart = newBVS;
  158. bufferValidEnd = jmin (bufferValidEnd, newBVE);
  159. }
  160. }
  161. if (sectionToReadStart != sectionToReadEnd)
  162. {
  163. const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples());
  164. const int bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples());
  165. if (bufferIndexStart < bufferIndexEnd)
  166. {
  167. readBufferSection (sectionToReadStart,
  168. (int) (sectionToReadEnd - sectionToReadStart),
  169. bufferIndexStart);
  170. }
  171. else
  172. {
  173. const int initialSize = buffer.getNumSamples() - bufferIndexStart;
  174. readBufferSection (sectionToReadStart,
  175. initialSize,
  176. bufferIndexStart);
  177. readBufferSection (sectionToReadStart + initialSize,
  178. (int) (sectionToReadEnd - sectionToReadStart) - initialSize,
  179. 0);
  180. }
  181. const ScopedLock sl2 (bufferStartPosLock);
  182. bufferValidStart = newBVS;
  183. bufferValidEnd = newBVE;
  184. return true;
  185. }
  186. else
  187. {
  188. return false;
  189. }
  190. }
  191. void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset)
  192. {
  193. if (source->getNextReadPosition() != start)
  194. source->setNextReadPosition (start);
  195. AudioSourceChannelInfo info;
  196. info.buffer = &buffer;
  197. info.startSample = bufferOffset;
  198. info.numSamples = length;
  199. source->getNextAudioBlock (info);
  200. }
  201. int BufferingAudioSource::useTimeSlice()
  202. {
  203. return readNextBufferChunk() ? 1 : 100;
  204. }
  205. END_JUCE_NAMESPACE