in pedalboard/ExternalPlugin.h [709:815]
void reinstantiatePlugin() {
// JUCE only allows creating new plugin instances from the main
// thread, which we may not be on:
if (!juce::MessageManager::getInstance()->isThisTheMessageThread()) {
throw std::runtime_error(
"Plugin " + pathToPluginFile.toStdString() +
" must be reloaded on the main thread. Please pass `reset=False` " +
"if calling this plugin from a non-main thread.");
}
// If we have an existing plugin, save its state and reload its state
// later:
juce::MemoryBlock savedState;
std::map<int, float> currentParameters;
if (pluginInstance) {
pluginInstance->getStateInformation(savedState);
for (auto *parameter : pluginInstance->getParameters()) {
currentParameters[parameter->getParameterIndex()] =
parameter->getValue();
}
{
std::lock_guard<std::mutex> lock(EXTERNAL_PLUGIN_MUTEX);
// Delete the plugin instance itself:
pluginInstance.reset();
NUM_ACTIVE_EXTERNAL_PLUGINS--;
}
}
juce::String loadError;
{
std::lock_guard<std::mutex> lock(EXTERNAL_PLUGIN_MUTEX);
pluginInstance =
createPluginInstance(foundPluginDescription, ExternalLoadSampleRate,
ExternalLoadMaximumBlockSize, loadError);
if (!pluginInstance) {
throw pybind11::import_error("Unable to load plugin " +
pathToPluginFile.toStdString() + ": " +
loadError.toStdString());
}
pluginInstance->enableAllBuses();
auto mainInputBus = pluginInstance->getBus(true, 0);
auto mainOutputBus = pluginInstance->getBus(false, 0);
if (!mainOutputBus) {
auto exception = std::invalid_argument(
"Plugin '" + pluginInstance->getName().toStdString() +
"' does not produce audio output.");
pluginInstance.reset();
throw exception;
}
if (reloadType == ExternalPluginReloadType::Unknown) {
reloadType = detectReloadType();
if (reloadType == ExternalPluginReloadType::PersistsAudioOnReset) {
// Reload again, as we just passed audio into a plugin that
// we know doesn't reset itself cleanly!
pluginInstance = createPluginInstance(
foundPluginDescription, ExternalLoadSampleRate,
ExternalLoadMaximumBlockSize, loadError);
if (!pluginInstance) {
throw pybind11::import_error("Unable to load plugin " +
pathToPluginFile.toStdString() + ": " +
loadError.toStdString());
}
}
}
NUM_ACTIVE_EXTERNAL_PLUGINS++;
}
pluginInstance->setStateInformation(savedState.getData(),
savedState.getSize());
// Set all of the parameters twice: we may have meta-parameters that
// change the validity of other `setValue` calls. (i.e.: param1 can't be
// set until param2 is set.)
for (int i = 0; i < 2; i++) {
for (auto *parameter : pluginInstance->getParameters()) {
if (currentParameters.count(parameter->getParameterIndex()) > 0) {
parameter->setValue(
currentParameters[parameter->getParameterIndex()]);
}
}
}
if (lastSpec.numChannels != 0) {
const juce::dsp::ProcessSpec _lastSpec = lastSpec;
// Invalidate lastSpec to force us to update the plugin state:
lastSpec.numChannels = 0;
prepare(_lastSpec);
}
pluginInstance->reset();
// Try to warm up the plugin.
// Some plugins (mostly instrument plugins) may load resources on start;
// this call attempts to give them time to load those resources.
attemptToWarmUp();
}