mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
ARAPluginDemo: Fix thread race when PlaybackRegion is modified during playback
This commit is contained in:
parent
043182faa6
commit
0f402bb81f
1 changed files with 48 additions and 8 deletions
|
|
@ -296,11 +296,18 @@ private:
|
||||||
std::unique_ptr<AudioFormatReader> reader;
|
std::unique_ptr<AudioFormatReader> reader;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ProcessingLockInterface
|
||||||
|
{
|
||||||
|
virtual ~ProcessingLockInterface() = default;
|
||||||
|
virtual ScopedTryReadLock getProcessingLock() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
class PlaybackRenderer : public ARAPlaybackRenderer
|
class PlaybackRenderer : public ARAPlaybackRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ARAPlaybackRenderer::ARAPlaybackRenderer;
|
PlaybackRenderer (ARA::PlugIn::DocumentController* dc, ProcessingLockInterface& lockInterfaceIn)
|
||||||
|
: ARAPlaybackRenderer (dc), lockInterface (lockInterfaceIn) {}
|
||||||
|
|
||||||
void prepareToPlay (double sampleRateIn,
|
void prepareToPlay (double sampleRateIn,
|
||||||
int maximumSamplesPerBlockIn,
|
int maximumSamplesPerBlockIn,
|
||||||
|
|
@ -351,6 +358,11 @@ public:
|
||||||
AudioProcessor::Realtime realtime,
|
AudioProcessor::Realtime realtime,
|
||||||
const AudioPlayHead::PositionInfo& positionInfo) noexcept override
|
const AudioPlayHead::PositionInfo& positionInfo) noexcept override
|
||||||
{
|
{
|
||||||
|
const auto lock = lockInterface.getProcessingLock();
|
||||||
|
|
||||||
|
if (! lock.isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
const auto numSamples = buffer.getNumSamples();
|
const auto numSamples = buffer.getNumSamples();
|
||||||
jassert (numSamples <= maximumSamplesPerBlock);
|
jassert (numSamples <= maximumSamplesPerBlock);
|
||||||
jassert (numChannels == buffer.getNumChannels());
|
jassert (numChannels == buffer.getNumChannels());
|
||||||
|
|
@ -458,8 +470,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
// We're subclassing here only to provide a proper default c'tor for our shared resource
|
ProcessingLockInterface& lockInterface;
|
||||||
|
|
||||||
SharedResourcePointer<SharedTimeSliceThread> sharedTimesliceThread;
|
SharedResourcePointer<SharedTimeSliceThread> sharedTimesliceThread;
|
||||||
std::map<ARAAudioSource*, PossiblyBufferedReader> audioSourceReaders;
|
std::map<ARAAudioSource*, PossiblyBufferedReader> audioSourceReaders;
|
||||||
bool useBufferedAudioSourceReader = true;
|
bool useBufferedAudioSourceReader = true;
|
||||||
|
|
@ -473,8 +484,12 @@ class EditorRenderer : public ARAEditorRenderer,
|
||||||
private ARARegionSequence::Listener
|
private ARARegionSequence::Listener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EditorRenderer (ARA::PlugIn::DocumentController* documentController, const PreviewState* previewStateIn)
|
EditorRenderer (ARA::PlugIn::DocumentController* documentController,
|
||||||
: ARAEditorRenderer (documentController), previewState (previewStateIn), previewBuffer()
|
const PreviewState* previewStateIn,
|
||||||
|
ProcessingLockInterface& lockInterfaceIn)
|
||||||
|
: ARAEditorRenderer (documentController),
|
||||||
|
lockInterface (lockInterfaceIn),
|
||||||
|
previewState (previewStateIn)
|
||||||
{
|
{
|
||||||
jassert (previewState != nullptr);
|
jassert (previewState != nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -549,6 +564,11 @@ public:
|
||||||
{
|
{
|
||||||
ignoreUnused (realtime);
|
ignoreUnused (realtime);
|
||||||
|
|
||||||
|
const auto lock = lockInterface.getProcessingLock();
|
||||||
|
|
||||||
|
if (! lock.isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
return asyncConfigCallback.withLock ([&] (bool locked)
|
return asyncConfigCallback.withLock ([&] (bool locked)
|
||||||
{
|
{
|
||||||
if (! locked)
|
if (! locked)
|
||||||
|
|
@ -661,6 +681,7 @@ private:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessingLockInterface& lockInterface;
|
||||||
const PreviewState* previewState = nullptr;
|
const PreviewState* previewState = nullptr;
|
||||||
AsyncConfigurationCallback asyncConfigCallback { [this] { configure(); } };
|
AsyncConfigurationCallback asyncConfigCallback { [this] { configure(); } };
|
||||||
double lastPreviewTime = 0.0;
|
double lastPreviewTime = 0.0;
|
||||||
|
|
@ -678,7 +699,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControllerSpecialisation
|
class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControllerSpecialisation,
|
||||||
|
private ProcessingLockInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ARADocumentControllerSpecialisation::ARADocumentControllerSpecialisation;
|
using ARADocumentControllerSpecialisation::ARADocumentControllerSpecialisation;
|
||||||
|
|
@ -686,6 +708,16 @@ public:
|
||||||
PreviewState previewState;
|
PreviewState previewState;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void willBeginEditing (ARADocument*) override
|
||||||
|
{
|
||||||
|
processBlockLock.enterWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
void didEndEditing (ARADocument*) override
|
||||||
|
{
|
||||||
|
processBlockLock.exitWrite();
|
||||||
|
}
|
||||||
|
|
||||||
ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource,
|
ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource,
|
||||||
ARA::ARAAudioModificationHostRef hostRef,
|
ARA::ARAAudioModificationHostRef hostRef,
|
||||||
const ARAAudioModification* optionalModificationToClone) noexcept override
|
const ARAAudioModification* optionalModificationToClone) noexcept override
|
||||||
|
|
@ -697,12 +729,12 @@ protected:
|
||||||
|
|
||||||
ARAPlaybackRenderer* doCreatePlaybackRenderer() noexcept override
|
ARAPlaybackRenderer* doCreatePlaybackRenderer() noexcept override
|
||||||
{
|
{
|
||||||
return new PlaybackRenderer (getDocumentController());
|
return new PlaybackRenderer (getDocumentController(), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRenderer* doCreateEditorRenderer() noexcept override
|
EditorRenderer* doCreateEditorRenderer() noexcept override
|
||||||
{
|
{
|
||||||
return new EditorRenderer (getDocumentController(), &previewState);
|
return new EditorRenderer (getDocumentController(), &previewState, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doRestoreObjectsFromStream (ARAInputStream& input,
|
bool doRestoreObjectsFromStream (ARAInputStream& input,
|
||||||
|
|
@ -779,6 +811,14 @@ protected:
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScopedTryReadLock getProcessingLock() override
|
||||||
|
{
|
||||||
|
return ScopedTryReadLock { processBlockLock };
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriteLock processBlockLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayHeadState
|
struct PlayHeadState
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue