AudioProcessorPlayer setup and setProcessor()


#1

Howdy. I’ve been studying the Plugin Host project and have been able to create a project that lets me create windows for plugins very easily, which is great. It has a comboBox that I can select a plugin from, and that plugin pops up in a window. No assertions, no crashes, everything works great, which I am really surprised about lol.

As with the Plugin Host, I have added the midikeyboardComponent to the bottom of the window, and now i’m trying to get midi data from the MidiKeyboardComponent instance into the loaded audio plugin and out to the speakers. When i assign the loaded AudioPluginInstance to my class member AudioProcessPlayer, i get an EXC_BAD_ACCESS here in AudioProcessorPlayer::setProcessor(AudioProcessor* const processorToPlay) on line 66:

if (oldOne != nullptr)
            oldOne->releaseResources();

here’s how my class is set up:

private:
    AudioDeviceManager audioDeviceManager; //you need this so you can talk to the hardware!
    ScopedPointer<ApplicationProperties> appProperties; //you need this to easily store the known working plugins.
    KnownPluginList knownPluginList; //you need this so you can know which plugins exist on the system
    AudioPluginFormatManager pluginFormatManager; //you need this to know which formats of plugins you can use.
    AudioProcessorPlayer audioProcessorPlayer;

    ScopedPointer<ComboBox> pluginComboBox;
    ScopedPointer<TextButton> optionsButton;
    ScopedPointer<PluginListWindow> pluginListWindow;
    ScopedPointer<PluginWindow> pluginWindow;
    ScopedPointer<AudioPluginInstance> loadedPlugin;
    MidiKeyboardState midiKeyboardState;
    ScopedPointer<MidiKeyboardComponent> midiKeyboardComponent;

Here’s how my plugin is loaded when chosen from the list of Plugins in the comboBox:

void MainContentComponent::comboBoxChanged(juce::ComboBox *comboBoxThatHasChanged) {
   if( comboBoxThatHasChanged == pluginComboBox ) {
        if( comboBoxThatHasChanged->getSelectedId() > 0 ) {
            auto pluginDescription = knownPluginList.getType(comboBoxThatHasChanged->getSelectedId() - 1 );
            //create a DocumentWindow that holds our plugin's AudioProcessorEditor if it has one
            pluginFormatManager.createPluginInstanceAsync(*pluginDescription,
                                                          44100,
                                                          512,
                                                          [this](AudioPluginInstance* instance, const String& error)
            {
                this->createPluginWindowCallback(instance, error);
            }
                                                          );
        }
    }
}
void MainContentComponent::createPluginWindowCallback(juce::AudioPluginInstance* instance, const juce::String &error) {
    if( instance == nullptr ) {
        AlertWindow::showMessageBox(AlertWindow::WarningIcon, "Couldn't create Plugin", error);
    } else {
        //create a documentWindow
        if (pluginWindow != nullptr) { //Header file: ScopedPointer<PluginWindow> pluginWindow;
            pluginWindow = nullptr;
            loadedPlugin = nullptr;
        }
        loadedPlugin = instance; //Header file: ScopedPointer<AudioPluginInstance> loadedPlugin;
        pluginWindow = new PluginWindow(*this, instance->createEditorIfNeeded() );
        pluginWindow->toFront(true);
    }
}

As I said early, this works excellent/perfect.
When I add

        instance->enableAllBuses();

        audioProcessorPlayer.setProcessor(instance);
        audioProcessorPlayer.setDoublePrecisionProcessing( instance->supportsDoublePrecisionProcessing() );

after pluginWindow->toFront(true);, I get the EXC_BAD_ACCESS crash.

I’m initializing my audioDeviceManager as follows in the constructor:

audioDeviceManager.initialise(0, 2, nullptr, true);
audioDeviceManager.addMidiInputCallback(String(), this);
audioProcessorPlayer.setProcessor(nullptr);
audioDeviceManager.addAudioCallback(&audioProcessorPlayer);

What am I missing for setting the selected plugin as the AudioProcessor in the AudioProcessorPlayer?


#2

ok, I modified my code a bit to use AudioProcessorGraph instead, and now I can click on the MidiKeyboardComponent and the notes are passed to a loaded plugin. I’ve tested it with AUSampler from Apple. When i play on my midi controller as well as the on-screen MidiKeyboardComponent, i hear audio and see the keys lighting up! However, when I change plugins, it crashes. assigning anything to loadedPlugin when it already has an AudioPluginInstance assigned to it seems to be the culprit. I’m not sure what’s going on. Any ideas?

//MainContentComponent private members: 
ScopedPointer<AudioProcessorGraph> audioProcessorGraph;
    AudioProcessorGraph::Node* midiInputNode;
    AudioProcessorGraph::Node* audioOutputNode;
    AudioProcessorGraph::Node* pluginNode;
void MainContentComponent::createPluginWindowCallback(juce::AudioPluginInstance* instance, const juce::String &error) {
    if( instance == nullptr ) {
        AlertWindow::showMessageBox(AlertWindow::WarningIcon, "Couldn't create Plugin", error);
    } else {
        //create a documentWindow
        if (pluginWindow != nullptr) {
            pluginWindow = nullptr;
            audioProcessorPlayer.setProcessor(nullptr);
            audioProcessorGraph->clear();
            loadedPlugin = nullptr; // <-- this causes a crash
            audioProcessorGraph = nullptr;
        }

        loadedPlugin = instance; // <-- this also causes a crash if the loadedPlugin=nullptr above is commented out.
        pluginWindow = new PluginWindow(*this, instance->createEditorIfNeeded() );
        pluginWindow->toFront(true);
        instance->enableAllBuses();

        audioProcessorGraph = new AudioProcessorGraph();
        audioProcessorGraph->setPlayConfigDetails(2,
                                                  2,
                                                  audioDeviceManager.getCurrentAudioDevice()->getCurrentSampleRate(),
                                                  audioDeviceManager.getCurrentAudioDevice()->getDefaultBufferSize());

        midiInputNode = audioProcessorGraph->addNode( new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::IODeviceType::midiInputNode) );
        pluginNode = audioProcessorGraph->addNode(instance);
        audioOutputNode = audioProcessorGraph->addNode( new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::IODeviceType::audioOutputNode) );

        //connect midiInput to pluginNode
        DBG( "midi in to plugin: " + String(audioProcessorGraph->addConnection(midiInputNode->nodeId,
                                           AudioProcessorGraph::midiChannelIndex,
                                           pluginNode->nodeId,
                                           AudioProcessorGraph::midiChannelIndex)) );
        //connect pluginNode to audioOutNode;
        DBG( "plugin L to output L: " + String( audioProcessorGraph->addConnection(pluginNode->nodeId,
                                           0,   //left channel
                                           audioOutputNode->nodeId,
                                           0)) //left channel
            );
        DBG( "plugin R to output R: " + String( audioProcessorGraph->addConnection(pluginNode->nodeId,
                                           1,   //right channel
                                           audioOutputNode->nodeId,
                                           1))  //right channel
            );

        audioProcessorPlayer.setProcessor(audioProcessorGraph);
    }
}


#3

ah ha!

Node* AudioProcessorGraph::addNode ( AudioProcessor * newProcessor, uint32 nodeId = 0 )

Adds a node to the graph.

This creates a new node in the graph, for the specified processor. Once you have added a processor to the graph, the graph owns it and will delete it later when it is no longer needed.

crash fixed! I can change my plugins, and trigger them with both the external controller and the on-screen controller! And I hear the audio from them! And when I close the app or switch plugins, nothing crashes or leaks!! hurray!