void reinstantiatePlugin()

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();
  }