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.

304 lines
12KB

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