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.

311 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. ARAAudioSourceReader::ARAAudioSourceReader (ARAAudioSource* audioSource)
  21. : AudioFormatReader (nullptr, "ARAAudioSourceReader"),
  22. audioSourceBeingRead (audioSource)
  23. {
  24. jassert (audioSourceBeingRead != nullptr);
  25. bitsPerSample = 32;
  26. usesFloatingPointData = true;
  27. sampleRate = audioSourceBeingRead->getSampleRate();
  28. numChannels = (unsigned int) audioSourceBeingRead->getChannelCount();
  29. lengthInSamples = audioSourceBeingRead->getSampleCount();
  30. tmpPtrs.resize (numChannels);
  31. audioSourceBeingRead->addListener (this);
  32. if (audioSourceBeingRead->isSampleAccessEnabled())
  33. hostReader.reset (new ARA::PlugIn::HostAudioReader (audioSourceBeingRead));
  34. }
  35. ARAAudioSourceReader::~ARAAudioSourceReader()
  36. {
  37. invalidate();
  38. }
  39. void ARAAudioSourceReader::invalidate()
  40. {
  41. ScopedWriteLock scopedLock (lock);
  42. if (! isValid())
  43. return;
  44. hostReader.reset();
  45. audioSourceBeingRead->removeListener (this);
  46. audioSourceBeingRead = nullptr;
  47. }
  48. void ARAAudioSourceReader::willUpdateAudioSourceProperties (ARAAudioSource* audioSource,
  49. ARAAudioSource::PropertiesPtr newProperties)
  50. {
  51. if (audioSource->getSampleCount() != newProperties->sampleCount
  52. || ! exactlyEqual (audioSource->getSampleRate(), newProperties->sampleRate)
  53. || audioSource->getChannelCount() != newProperties->channelCount)
  54. {
  55. invalidate();
  56. }
  57. }
  58. void ARAAudioSourceReader::doUpdateAudioSourceContent ([[maybe_unused]] ARAAudioSource* audioSource,
  59. ARAContentUpdateScopes scopeFlags)
  60. {
  61. jassert (audioSourceBeingRead == audioSource);
  62. // Don't invalidate if the audio signal is unchanged
  63. if (scopeFlags.affectSamples())
  64. invalidate();
  65. }
  66. void ARAAudioSourceReader::willEnableAudioSourceSamplesAccess ([[maybe_unused]] ARAAudioSource* audioSource, bool enable)
  67. {
  68. jassert (audioSourceBeingRead == audioSource);
  69. // Invalidate our reader if sample access is disabled
  70. if (! enable)
  71. {
  72. ScopedWriteLock scopedLock (lock);
  73. hostReader.reset();
  74. }
  75. }
  76. void ARAAudioSourceReader::didEnableAudioSourceSamplesAccess ([[maybe_unused]] ARAAudioSource* audioSource, bool enable)
  77. {
  78. jassert (audioSourceBeingRead == audioSource);
  79. // Recreate our reader if sample access is enabled
  80. if (enable && isValid())
  81. {
  82. ScopedWriteLock scopedLock (lock);
  83. hostReader.reset (new ARA::PlugIn::HostAudioReader (audioSourceBeingRead));
  84. }
  85. }
  86. void ARAAudioSourceReader::willDestroyAudioSource ([[maybe_unused]] ARAAudioSource* audioSource)
  87. {
  88. jassert (audioSourceBeingRead == audioSource);
  89. invalidate();
  90. }
  91. bool ARAAudioSourceReader::readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
  92. int64 startSampleInFile, int numSamples)
  93. {
  94. const auto destSize = (bitsPerSample / 8) * (size_t) numSamples;
  95. const auto bufferOffset = (int) (bitsPerSample / 8) * startOffsetInDestBuffer;
  96. if (isValid())
  97. {
  98. const ScopedTryReadLock readLock (lock);
  99. if (readLock.isLocked() && hostReader != nullptr)
  100. {
  101. for (size_t i = 0; i < tmpPtrs.size(); ++i)
  102. {
  103. if ((i < (size_t) numDestChannels) && (destSamples[i] != nullptr))
  104. {
  105. tmpPtrs[i] = ((uint8_t*) destSamples[i]) + bufferOffset;
  106. }
  107. else
  108. {
  109. // We need to provide destination pointers for all channels in the ARA read call, even if
  110. // readSamples is not reading all of them. Hence we use this dummy buffer to pad the read
  111. // destination area.
  112. static thread_local std::vector<uint8_t> dummyBuffer;
  113. if (destSize > dummyBuffer.size())
  114. dummyBuffer.resize (destSize);
  115. tmpPtrs[i] = dummyBuffer.data();
  116. }
  117. }
  118. return hostReader->readAudioSamples (startSampleInFile, numSamples, tmpPtrs.data());
  119. }
  120. }
  121. for (int i = 0; i < numDestChannels; ++i)
  122. if (destSamples[i] != nullptr)
  123. zeromem (((uint8_t*) destSamples[i]) + bufferOffset, destSize);
  124. return false;
  125. }
  126. //==============================================================================
  127. ARAPlaybackRegionReader::ARAPlaybackRegionReader (ARAPlaybackRegion* playbackRegion)
  128. : ARAPlaybackRegionReader (playbackRegion->getAudioModification()->getAudioSource()->getSampleRate(),
  129. playbackRegion->getAudioModification()->getAudioSource()->getChannelCount(),
  130. { playbackRegion })
  131. {}
  132. ARAPlaybackRegionReader::ARAPlaybackRegionReader (double rate, int numChans,
  133. const std::vector<ARAPlaybackRegion*>& playbackRegions)
  134. : AudioFormatReader (nullptr, "ARAPlaybackRegionReader")
  135. {
  136. // We're only providing the minimal set of meaningful values, since the ARA renderer should only
  137. // look at the time position and the playing state, and read any related tempo or bar signature
  138. // information from the ARA model directly (MusicalContext).
  139. positionInfo.setIsPlaying (true);
  140. sampleRate = rate;
  141. numChannels = (unsigned int) numChans;
  142. bitsPerSample = 32;
  143. usesFloatingPointData = true;
  144. auto* documentController = (! playbackRegions.empty())
  145. ? playbackRegions.front()->getDocumentController<ARADocumentController>()
  146. : nullptr;
  147. playbackRenderer.reset (documentController ? static_cast<ARAPlaybackRenderer*> (documentController->doCreatePlaybackRenderer())
  148. : nullptr);
  149. if (playbackRenderer != nullptr)
  150. {
  151. double regionsStartTime = std::numeric_limits<double>::max();
  152. double regionsEndTime = std::numeric_limits<double>::lowest();
  153. for (const auto& playbackRegion : playbackRegions)
  154. {
  155. jassert (playbackRegion->getDocumentController() == documentController);
  156. auto playbackRegionTimeRange = playbackRegion->getTimeRange (ARAPlaybackRegion::IncludeHeadAndTail::yes);
  157. regionsStartTime = jmin (regionsStartTime, playbackRegionTimeRange.getStart());
  158. regionsEndTime = jmax (regionsEndTime, playbackRegionTimeRange.getEnd());
  159. playbackRenderer->addPlaybackRegion (ARA::PlugIn::toRef (playbackRegion));
  160. playbackRegion->addListener (this);
  161. }
  162. startInSamples = (int64) (regionsStartTime * sampleRate + 0.5);
  163. lengthInSamples = (int64) ((regionsEndTime - regionsStartTime) * sampleRate + 0.5);
  164. playbackRenderer->prepareToPlay (rate,
  165. maximumBlockSize,
  166. numChans,
  167. AudioProcessor::ProcessingPrecision::singlePrecision,
  168. ARARenderer::AlwaysNonRealtime::yes);
  169. }
  170. else
  171. {
  172. startInSamples = 0;
  173. lengthInSamples = 0;
  174. }
  175. }
  176. ARAPlaybackRegionReader::~ARAPlaybackRegionReader()
  177. {
  178. invalidate();
  179. }
  180. void ARAPlaybackRegionReader::invalidate()
  181. {
  182. ScopedWriteLock scopedWrite (lock);
  183. if (! isValid())
  184. return;
  185. for (auto& playbackRegion : playbackRenderer->getPlaybackRegions())
  186. playbackRegion->removeListener (this);
  187. playbackRenderer->releaseResources();
  188. playbackRenderer.reset();
  189. }
  190. bool ARAPlaybackRegionReader::readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
  191. int64 startSampleInFile, int numSamples)
  192. {
  193. bool success = false;
  194. bool needClearSamples = true;
  195. const ScopedTryReadLock readLock (lock);
  196. if (readLock.isLocked())
  197. {
  198. if (isValid())
  199. {
  200. success = true;
  201. needClearSamples = false;
  202. positionInfo.setTimeInSamples (startSampleInFile + startInSamples);
  203. while (numSamples > 0)
  204. {
  205. const int numSliceSamples = jmin (numSamples, maximumBlockSize);
  206. AudioBuffer<float> buffer ((float **) destSamples, numDestChannels, startOffsetInDestBuffer, numSliceSamples);
  207. positionInfo.setTimeInSeconds (static_cast<double> (*positionInfo.getTimeInSamples()) / sampleRate);
  208. success &= playbackRenderer->processBlock (buffer, AudioProcessor::Realtime::no, positionInfo);
  209. numSamples -= numSliceSamples;
  210. startOffsetInDestBuffer += numSliceSamples;
  211. positionInfo.setTimeInSamples (*positionInfo.getTimeInSamples() + numSliceSamples);
  212. }
  213. }
  214. }
  215. if (needClearSamples)
  216. for (int chan_i = 0; chan_i < numDestChannels; ++chan_i)
  217. FloatVectorOperations::clear ((float *) destSamples[chan_i], numSamples);
  218. return success;
  219. }
  220. void ARAPlaybackRegionReader::willUpdatePlaybackRegionProperties (ARAPlaybackRegion* playbackRegion, ARAPlaybackRegion::PropertiesPtr newProperties)
  221. {
  222. jassert (ARA::contains (playbackRenderer->getPlaybackRegions(), playbackRegion));
  223. if ((! exactlyEqual (playbackRegion->getStartInAudioModificationTime(), newProperties->startInModificationTime))
  224. || ! exactlyEqual (playbackRegion->getDurationInAudioModificationTime(), newProperties->durationInModificationTime)
  225. || ! exactlyEqual (playbackRegion->getStartInPlaybackTime(), newProperties->startInPlaybackTime)
  226. || ! exactlyEqual (playbackRegion->getDurationInPlaybackTime(), newProperties->durationInPlaybackTime)
  227. || (playbackRegion->isTimestretchEnabled() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationTimestretch) != 0))
  228. || (playbackRegion->isTimeStretchReflectingTempo() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationTimestretchReflectingTempo) != 0))
  229. || (playbackRegion->hasContentBasedFadeAtHead() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationContentBasedFadeAtHead) != 0))
  230. || (playbackRegion->hasContentBasedFadeAtTail() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationContentBasedFadeAtTail) != 0)))
  231. {
  232. invalidate();
  233. }
  234. }
  235. void ARAPlaybackRegionReader::didUpdatePlaybackRegionContent ([[maybe_unused]] ARAPlaybackRegion* playbackRegion,
  236. ARAContentUpdateScopes scopeFlags)
  237. {
  238. jassert (ARA::contains (playbackRenderer->getPlaybackRegions(), playbackRegion));
  239. // Invalidate if the audio signal is changed
  240. if (scopeFlags.affectSamples())
  241. invalidate();
  242. }
  243. void ARAPlaybackRegionReader::willDestroyPlaybackRegion ([[maybe_unused]] ARAPlaybackRegion* playbackRegion)
  244. {
  245. jassert (ARA::contains (playbackRenderer->getPlaybackRegions(), playbackRegion));
  246. invalidate();
  247. }
  248. } // namespace juce