bool attemptToWarmUp()

in pedalboard/ExternalPlugin.h [906:1004]


  bool attemptToWarmUp() {
    if (!pluginInstance || initializationTimeout <= 0)
      return false;

    auto endTime = juce::Time::currentTimeMillis() +
                   (long)(initializationTimeout * 1000.0);

    const int numInputChannels = pluginInstance->getMainBusNumInputChannels();
    const float sampleRate = 44100.0f;
    const int bufferSize = 2048;

    if (numInputChannels != 0) {
      // TODO: For effect plugins, do this check as well!
      return false;
    }

    // Set input and output busses/channels appropriately:
    int numOutputChannels =
        std::max(pluginInstance->getMainBusNumInputChannels(),
                 pluginInstance->getMainBusNumOutputChannels());
    setNumChannels(numOutputChannels);
    pluginInstance->setNonRealtime(true);
    pluginInstance->prepareToPlay(sampleRate, bufferSize);

    // Prepare an empty MIDI buffer to measure the background noise of the
    // plugin:
    juce::MidiBuffer emptyNoteBuffer;

    // Send in a MIDI buffer containing a single middle C at full velocity:
    auto noteOn = juce::MidiMessage::noteOn(
        /* channel */ 1, /* note number */ 60, /* velocity */ (juce::uint8)127);

    // And prepare an all-notes-off buffer:
    auto allNotesOff = juce::MidiMessage::allNotesOff(/* channel */ 1);

    if (juce::MessageManager::getInstance()->isThisTheMessageThread()) {
      for (int i = 0; i < 10; i++) {
        if (juce::Time::currentTimeMillis() >= endTime)
          return false;
        juce::MessageManager::getInstance()->runDispatchLoopUntil(1);
      }
    }

    juce::AudioBuffer<float> audioBuffer(numOutputChannels, bufferSize);
    audioBuffer.clear();

    pluginInstance->processBlock(audioBuffer, emptyNoteBuffer);
    auto noiseFloor = audioBuffer.getMagnitude(0, bufferSize);

    audioBuffer.clear();

    // Now pass in a middle C:
    // Note: we create a new MidiBuffer every time here, as unlike AudioBuffer,
    // the messages in a MidiBuffer get erased every time we call processBlock!
    {
      juce::MidiBuffer noteOnBuffer(noteOn);
      pluginInstance->processBlock(audioBuffer, noteOnBuffer);
    }

    // Then keep pumping the message thread until we get some louder output:
    bool magnitudeIncreased = false;
    while (true) {
      auto magnitudeWithNoteHeld = audioBuffer.getMagnitude(0, bufferSize);
      if (magnitudeWithNoteHeld > noiseFloor * 5) {
        magnitudeIncreased = true;
        break;
      }

      if (juce::MessageManager::getInstance()->isThisTheMessageThread()) {
        for (int i = 0; i < 10; i++) {
          juce::MessageManager::getInstance()->runDispatchLoopUntil(1);
        }
      }

      if (juce::Time::currentTimeMillis() >= endTime)
        break;

      audioBuffer.clear();
      {
        juce::MidiBuffer noteOnBuffer(noteOn);
        pluginInstance->processBlock(audioBuffer, noteOnBuffer);
      }

      if (juce::Time::currentTimeMillis() >= endTime)
        break;
    }

    // Send in an All Notes Off and then reset, just to make sure we clear any
    // note trails:
    audioBuffer.clear();
    {
      juce::MidiBuffer allNotesOffBuffer(allNotesOff);
      pluginInstance->processBlock(audioBuffer, allNotesOffBuffer);
    }
    pluginInstance->reset();
    pluginInstance->releaseResources();

    return magnitudeIncreased;
  }