If you are doing a plugin that is supposed to output MIDI internally within a host into the following plugins in the processing chain, MidiOutput is not going to work. (It’s meant for outputting into MIDI hardware.)
I do need my plugin to select a MIDI out port because I want to use it in Ableton. I am building an external synth editor so I need to send to a physical MIDI out.
Right now Ableton thinks it is a synth and I can not route the MIDI coming out of the plugin because it thinks it is audio.
Do you have any idea if that is possible?
Everything works fine in GUI mode, but getting it to work in plugin mode is a real pain.
I checked it CTRLR and it is possible to be a plugin AND select the midi out, so why do people discourage that usage?
It might be “good enough” for CC-data in live mode, but the problem is, that the execution time of the processBlock() is independent of the playback time.
The event from the MidiInput may occur as soon as it arrives at the port in a dedicated thread. In a host it would get now a timestamp, that correlates to the playback time (including the sample within the block).
A plugin doesn’t have that information. And due to latency compensation of a following plugin, it might already process samples of the future, or in case of an offline bounce, there is everything happening virtually at the same time (a milli second becomes suddenly a nano second).
The next problem is, that your processBlock happens at discrete time points. Usually you would pick up a the midi events that happened at the beginning of a processBlock(), but since you don’t have the sample offset, all events can only happen at block starts, which can be up to 24 ms if running with 512 samples blocks (can be even longer).
If that was a constant latency, it might still sound not too bad, but since it is a jitter moving the notes into a non-musical grid, a performance would suffer quite severely.
First of all, in the latest JUCE (develop and master) openDevice() returns a unique_ptr, so you cannot assign it directly to a raw pointer (best to update your JUCE).
You are responsible for the destruction of the device you just opened (that’s the memory leaks you are warned about, apart from being best practice, if you run your plugin a while longer, there will be no memory left).
Second, you need to open your device outside the processBlock and keep it as member variable. Best to do it in prepareToPlay and check, if it is already open, since prepareToPlay can be called multiple times.
And last but not least, you have to check, if sendMidiMessageNow is realtime safe, i.e. it must not block, not use any OS resources and not allocate memory.
If it is not realtime safe, you need to implement a FIFO, where you can safely put midi messages, that are picked up from a non realtime task and be sent out.
Some snippets without having checked the above:
// member variable:
if (midiOutput.get() == nullptr)
midiOutput = MidiOutput::openDevice (MidiOutput::getDefaultDevice().identifier);
// with your old version in prepareToPlay rather:
if (midiOutput.get() == nullptr)
midiOutput.reset (MidiOutput::openDevice (0));
// processBlock (please check, if that is realtime safe, no guarantee!):
midiOutput->sendMessageNow(MidiMessage::controllerEvent(1, 23, 23));