As promised, here are the instructions originally posted by oxxyyd on how to modify the plugin host to handle midi out, updated to JUCE version 5.4.4:
1 First you need to add some code to actually create the midi out connection so to say
In InternalPlugins.h you change
PluginDescription audioInDesc, audioOutDesc, midiInDesc;
to
PluginDescription audioInDesc, audioOutDesc, midiInDesc, midiOutDesc;
in InternalPlugins.cpp you add in the relevant places:
{
AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);
p.fillInPluginDescription (midiOutDesc);
}
and
if (name == midiOutDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);
and
midiOutDesc,
to the line that says
results.add (audioInDesc, audioOutDesc, midiInDesc,
(hint: search for midiInDesc and add the corresponding code for midiOutDesc).
In PluginGraph.cpp you add
addPlugin (internalFormat.midiOutDesc, { 0.25, 0.9 });
NOTE: at this point your code should be in a state that will compile and the MIDI Output node should appear in the plugin graph (but it doesn’t work yet).
2 Some more updates
Add to the collection of privates of GraphDocumentComponent in GraphEditorPanel.h
MidiOutput *midiOut;
Make GraphDocumentComponent a ChangeListener i.e in GraphEditorPanel.h it should look like
class GraphDocumentComponent : public Component,
public DragAndDropTarget,
public DragAndDropContainer,
public ChangeListener
and add the following line to the public part of the class declaration:
void changeListenerCallback(ChangeBroadcaster* source) override;
3 Add to GraphEditorPanel.cpp
void GraphDocumentComponent::changeListenerCallback(ChangeBroadcaster* source) {
if (source == &deviceManager) {
midiOut = deviceManager.getDefaultMidiOutput();
if (midiOut) {
midiOut->startBackgroundThread();
}
graphPlayer.setMidiOutput(midiOut);
}
}
4 Now add the line
changeListenerCallback(&deviceManager);
somewhere in the constructor of GraphDocumentComponent (GraphEditorPanel.cpp).
and put following at the to beginning of ~GraphDocumentComponent
if (midiOut)
midiOut->stopBackgroundThread();
and add to the method init(), after the line that begins with “keyState.addListener”, the line
deviceManager.addChangeListener(this);
5 Now we’ve come to the part where midi output is actually taken from the AudioProcessorGraph.
Modify the code below by adding the 7 lines after
// modification for MIDI output:
In juce_AudioProcessorPlayer.cpp:
if (! processor->isSuspended())
{
if (processor->isUsingDoublePrecision())
{
conversionBuffer.makeCopyOf (buffer, true);
processor->processBlock (conversionBuffer, incomingMidi);
buffer.makeCopyOf (conversionBuffer, true);
}
else
{
processor->processBlock (buffer, incomingMidi);
}
// modification for MIDI output:
AudioProcessorGraph* processorgraph=dynamic_cast<AudioProcessorGraph*>(processor);
if (processorgraph) {
MidiBuffer* midiBuffer (processorgraph->getCurrentMidiOutputBuffer());
if (midiBuffer && !midiBuffer->isEmpty() && midiOutput) {
midiOutput->sendBlockOfMessages(*midiBuffer, Time::getMillisecondCounter(), getCurrentProcessor()->getSampleRate());
}
}
return;
}
6 And last add following method declaration to the publics of juce_AudioProcessorGraph.h
// modification for MIDI output:
MidiBuffer* getCurrentMidiOutputBuffer();
and the corresponding implementation in juce_AudioProcessorGraph.cpp:
// modification for MIDI output:
MidiBuffer* AudioProcessorGraph::getCurrentMidiOutputBuffer() {
if (isUsingDoublePrecision()) {
if (renderSequenceDouble != nullptr) {
return &renderSequenceDouble->currentMidiOutputBuffer;
} else {
return nullptr;
}
} else {
if (renderSequenceFloat != nullptr) {
return &renderSequenceFloat->currentMidiOutputBuffer;
} else {
return nullptr;
}
}
}
After building and starting the plugin host you should now have a MIDI output. Draw a connection between midi input and midi output. If you have selected a midiout device in the audiosettings (e.g Microsft GS Wavetable Synth in windows) you should now here a piano when playing on the midikeyboard (or see the MIDI Out LED blink if you selected a physical MIDI interface).
Note from original instructions (which I would not necessarily recommend, especially if it involves copying and pasting a lot of JUCE library code, which then has to be maintained to keep track with the changes that are being made to JUCE), added here for the sake of completeness:
If you’re more into copy & paste programming you could instead of modifying the two [now three] juce files create a “midiout processor” by subclassing juce_AudioProcessor. But I leave that as an excersise for the reader…