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