Adding a midi device to an AudioProcessorGraph

I have a simple VST host that connects my audio in to a vst which is then connected to my audio out.

    AudioProcessorGraph::AudioGraphIOProcessor* in;
in = new AudioProcessorGraph::AudioGraphIOProcessor(
    AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode);

AudioProcessorGraph::AudioGraphIOProcessor* out;
out = new AudioProcessorGraph::AudioGraphIOProcessor(
    AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);

AudioPluginInstance* plugin =
    pluginManager->createPluginInstance(*desc, 0, 0, error);

AudioProcessorGraph::Node* inNode = graph->addNode(in);
AudioProcessorGraph::Node* outNode = graph->addNode(out);
AudioProcessorGraph::Node* pluginNode = graph->addNode(plugin);

graph->addConnection(inNode->nodeId, 0, pluginNode->nodeId, 0);
graph->addConnection(pluginNode->nodeId, 0, outNode->nodeId, 0);

This works great for loading the plugin.

What I am puzzling over is how to add a midi device to my graph? I’d like to take the midi device and plug it into the midi input of my pluginNode, but nothing I’ve tried seems to work. Can someone help me out?

I can see my midi device via MidiInput::getDevices()), but I’m not sure how to connect it to my VST plugin.

I’ve tried adding a midi output like this:

AudioProcessorGraph::AudioGraphIOProcessor* midOuput = new AudioProcessorGraph::AudioGraphIOProcessor(
            AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);

add adding it to the graph like so

AudioProcessorGraph::Node* midiNode = graph->addNode(midiOutput);
graph->addConnection(midiNode->nodeId, AudioProcessorGraph::midiChannelIndex, pluginNode->nodeId, AudioProcessorGraph::midiChannelIndex);

But the result from that connection is always false and my vst plugin is not getting any midi input.

Do I need to open my midi device and put it on the graph in a particular way?

Check out this example where I modified the MultiSynth demo to use and AudioProcessorGraph:

It was for the now defunct MultiBus code… but the graph setup should show you how to hook up the MIDI

Rail

Rail-
Thank you so much for replying. I’m following most of the same steps that you have in your MultiOutSynth.cpp, but my vst still isn’t receiving midi input from a soft device that I created with JUCE as well.

Below is my application code.

I’m sure I’m missing something small, but I can’t seem to connect the dots yet.

Hi Erik,

I haven’t the time this week to read your code properly… but a quick glance makes me question if your objects’ lifetime scope is good… You appear to be passing around a lot of pointers – while I’d suggest using class members

For instance in a Standalone app I have which uses an AudioProcessorGraph I have some private members:

ScopedPointer<AudioProcessorGraph>              m_pMainGraph;

AudioProcessorGraph::AudioGraphIOProcessor*     m_ioProcOut;
AudioProcessorGraph::AudioGraphIOProcessor*     m_ioProcMidiIn;
AudioProcessorGraph::AudioGraphIOProcessor*     m_ioProcMidiOut;

AudioProcessorGraph::Node::Ptr                  m_ioProcOutNode;
AudioProcessorGraph::Node::Ptr                  m_ioProcMidiInNode;
AudioProcessorGraph::Node::Ptr                  m_ioProcMidiOutNode;

and in the MainComponent’s ctor in the init list I have:

m_pMainGraph                 (new AudioProcessorGraph()),

then in the ctor body (reduced to minimum for example):

m_pMainGraph->setPlayConfigDetails (2, 2, m_dSampleRate, m_iBufferSize);

m_ioProcOut         = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);
m_ioProcMidiIn      = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);
m_ioProcMidiOut     = new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);

m_ioProcOutNode     = m_pMainGraph->addNode (m_ioProcOut);
m_ioProcMidiInNode  = m_pMainGraph->addNode (m_ioProcMidiIn);
m_ioProcMidiOutNode = m_pMainGraph->addNode (m_ioProcMidiOut);

m_pSynthProc = new CSynthProcessor();  

m_pSynthProcNode = m_pMainGraph->addNode (m_pSynthProc);

jassert (m_pSynthProcNode != nullptr);

m_pMainGraph->addConnection (m_ioProcMidiInNode->nodeId, AudioProcessorGraph::midiChannelIndex, m_pSynthProcNode->nodeId, AudioProcessorGraph::midiChannelIndex);

You also appear to be using raw pointers instead of ReferenceCountedObjectPtr (for the Nodes).

Cheers,

Rail

2 Likes

Rail-
This is great feedback. I’m coming back to C++ after many years so I’m sure that a few things can be improved. I’ll take a look at how I’m passing around pointers.

I did figure out the issue I was having. I wasn’t properly setting up the device and player to accept midi input.

    device->initialiseWithDefaultDevices(3, 2);
    device->setMidiInputEnabled("my-midi", true);
    device->addMidiInputCallback("my-midi", player);

This seemed to do it.

Thank you again for your help!

Hi,
i have the exact same problem: I can play and hear output when playing in my VST plugin, but i don’t hear anything when playing on my hardware midi keyboard, but it is correctly connected in the graph to the plugin and i have also implemented the 3 lines of your last message.
Would you mind sharing your final VSTHost.cpp so that i can check what you added else in order that midi inputs are correctly handled?
Thank you very much!

I updated my gist to include the change I needed to make. Hope it helps.

Thank you Erik.
My problem was that i messed up with enabling midi in the AudioDeviceManager.
Now i’m also able to let midi sounds flow through a vst plugin :slight_smile:

Cheers
ricochet

I’m curious… Why are you not using ScopedPointers every time you use new in your gist? Where do all of your new instances of those classes get released/destructed?

I can tell from my side when adapting the source code from the Gist, that i am using ScopedPointers for all instances in my class - except for AudioPluginInstance, where the app crashed all the time when closing the app or the synth window.

JUCE should force you to pass a unique_ptr when you pass ownership of the memory. But this would break lots of code, so perhaps for a JUCE 6?
If you are using scoped pointers for all your instances, you may actually free the memory twice, as JUCE handles some objects passed as pointers.

Well, I mainly meant as class members. You aren’t using any members afaik. I’m not sure if those objects you’re new’ing are self-managing tho. @Rail_Jon_Rogut touched on the issue…