From e688aaf7b22b6cf7c7504a634f9b5efba0861e67 Mon Sep 17 00:00:00 2001 From: Peter Sobot Date: Thu, 7 Mar 2024 16:13:13 -0500 Subject: [PATCH] Report current time in samples to plugins. --- pedalboard/ExternalPlugin.h | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/pedalboard/ExternalPlugin.h b/pedalboard/ExternalPlugin.h index dc98026e..79eac585 100644 --- a/pedalboard/ExternalPlugin.h +++ b/pedalboard/ExternalPlugin.h @@ -516,7 +516,7 @@ class AbstractExternalPlugin : public Plugin { }; template -class ExternalPlugin : public AbstractExternalPlugin { +class ExternalPlugin : public AbstractExternalPlugin, juce::AudioPlayHead { public: ExternalPlugin( std::string &_pathToPluginFile, @@ -630,6 +630,10 @@ class ExternalPlugin : public AbstractExternalPlugin { ~ExternalPlugin() { { std::lock_guard lock(EXTERNAL_PLUGIN_MUTEX); + if (pluginInstance) { + pluginInstance->setPlayHead(nullptr); + } + pluginInstance.reset(); NUM_ACTIVE_EXTERNAL_PLUGINS--; @@ -695,6 +699,9 @@ class ExternalPlugin : public AbstractExternalPlugin { { std::lock_guard lock(EXTERNAL_PLUGIN_MUTEX); // Delete the plugin instance itself: + if (pluginInstance) { + pluginInstance->setPlayHead(nullptr); + } pluginInstance.reset(); NUM_ACTIVE_EXTERNAL_PLUGINS--; } @@ -714,6 +721,7 @@ class ExternalPlugin : public AbstractExternalPlugin { loadError.toStdString()); } + pluginInstance->setPlayHead(this); pluginInstance->enableAllBuses(); auto mainInputBus = pluginInstance->getBus(true, 0); @@ -723,6 +731,9 @@ class ExternalPlugin : public AbstractExternalPlugin { auto exception = std::invalid_argument( "Plugin '" + pluginInstance->getName().toStdString() + "' does not produce audio output."); + if (pluginInstance) { + pluginInstance->setPlayHead(nullptr); + } pluginInstance.reset(); throw exception; } @@ -741,6 +752,7 @@ class ExternalPlugin : public AbstractExternalPlugin { pathToPluginFile.toStdString() + ": " + loadError.toStdString()); } + pluginInstance->setPlayHead(this); } } @@ -912,7 +924,10 @@ class ExternalPlugin : public AbstractExternalPlugin { juce::AudioBuffer audioBuffer(numOutputChannels, bufferSize); audioBuffer.clear(); + currentPositionInfo.isPlaying = true; pluginInstance->processBlock(audioBuffer, emptyNoteBuffer); + currentPositionInfo.isPlaying = false; + currentPositionInfo.timeInSamples += bufferSize; auto noiseFloor = audioBuffer.getMagnitude(0, bufferSize); audioBuffer.clear(); @@ -922,7 +937,10 @@ class ExternalPlugin : public AbstractExternalPlugin { // the messages in a MidiBuffer get erased every time we call processBlock! { juce::MidiBuffer noteOnBuffer(noteOn); + currentPositionInfo.isPlaying = true; pluginInstance->processBlock(audioBuffer, noteOnBuffer); + currentPositionInfo.isPlaying = false; + currentPositionInfo.timeInSamples += bufferSize; } // Then keep pumping the message thread until we get some louder output: @@ -945,8 +963,11 @@ class ExternalPlugin : public AbstractExternalPlugin { audioBuffer.clear(); { + currentPositionInfo.isPlaying = true; juce::MidiBuffer noteOnBuffer(noteOn); pluginInstance->processBlock(audioBuffer, noteOnBuffer); + currentPositionInfo.isPlaying = false; + currentPositionInfo.timeInSamples += bufferSize; } if (juce::Time::currentTimeMillis() >= endTime) @@ -958,8 +979,12 @@ class ExternalPlugin : public AbstractExternalPlugin { audioBuffer.clear(); { juce::MidiBuffer allNotesOffBuffer(allNotesOff); + currentPositionInfo.isPlaying = true; pluginInstance->processBlock(audioBuffer, allNotesOffBuffer); + currentPositionInfo.isPlaying = false; + currentPositionInfo.timeInSamples += bufferSize; } + currentPositionInfo.timeInSamples = 0; pluginInstance->reset(); pluginInstance->releaseResources(); @@ -1077,6 +1102,7 @@ class ExternalPlugin : public AbstractExternalPlugin { // Force prepare() to be called again later by invalidating lastSpec: lastSpec.maximumBlockSize = 0; samplesProvided = 0; + currentPositionInfo.timeInSamples = 0; } } @@ -1102,6 +1128,8 @@ class ExternalPlugin : public AbstractExternalPlugin { pluginInstance->setNonRealtime(true); pluginInstance->prepareToPlay(spec.sampleRate, spec.maximumBlockSize); + currentPositionInfo.timeInSamples = 0; + currentPositionInfo.isPlaying = false; lastSpec = spec; } @@ -1173,8 +1201,11 @@ class ExternalPlugin : public AbstractExternalPlugin { channelPointers.size(), outputBlock.getNumSamples()); + currentPositionInfo.isPlaying = true; pluginInstance->processBlock(audioBuffer, emptyMidiBuffer); + currentPositionInfo.isPlaying = false; samplesProvided += outputBlock.getNumSamples(); + currentPositionInfo.timeInSamples += outputBlock.getNumSamples(); // To compensate for any latency added by the plugin, // only tell Pedalboard to use the last _n_ samples. @@ -1269,7 +1300,10 @@ class ExternalPlugin : public AbstractExternalPlugin { juce::MidiBuffer midiChunk; midiChunk.addEvents(midiInputBuffer, i, chunkSampleCount, -i); + currentPositionInfo.isPlaying = true; pluginInstance->processBlock(audioChunk, midiChunk); + currentPositionInfo.isPlaying = false; + currentPositionInfo.timeInSamples += chunkSampleCount; } } @@ -1337,6 +1371,11 @@ class ExternalPlugin : public AbstractExternalPlugin { ExternalPluginReloadType reloadType = ExternalPluginReloadType::Unknown; juce::PluginDescription foundPluginDescription; + bool getCurrentPosition(CurrentPositionInfo &result) override { + result = currentPositionInfo; + return true; + } + private: std::unique_ptr createPluginInstance(const juce::PluginDescription &foundPluginDescription, @@ -1371,6 +1410,7 @@ class ExternalPlugin : public AbstractExternalPlugin { juce::String pathToPluginFile; juce::AudioPluginFormatManager pluginFormatManager; std::unique_ptr pluginInstance; + juce::AudioPlayHead::CurrentPositionInfo currentPositionInfo; long samplesProvided = 0; float initializationTimeout = DEFAULT_INITIALIZATION_TIMEOUT_SECONDS;