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.)
{
buffer.clear();
midiMessages.clear();
MidiBuffer generatedMidi;
int time;
MidiMessage m;
int8 ccTempVal;
int8 myVal = (int8)CC00Val;
if (myVal != ccTempVal)
{
m = MidiMessage::controllerEvent(2, 1, myVal);
generatedMidi.addEvent(m, midiMessages.getLastEventTime());
}
else generatedMidi.clear();
ccTempVal = myVal;
midiMessages.swapWith (generatedMidi);
}
This is what I saw in another post and they recommended this:
So I can keep the code but move the ccTempVal out.
Is it maybe wise then, since I need to check 30-40 variables that I make an array and then put the checking loop and the sending in the processBlock?
Last part I put in as a test and it gives errors. So how do I add my event to the processBlock? I just have spent 5 hours Googling and I have found absolutely nothing…
It’s quite involved because you would need to manipulate the MIDI buffer from the GUI thread. I don’t remember at the moment if I’ve done any, even passably good, code for that myself.
You could in principle create a new MIDI buffer elsewhere and in “some manner” pass it into the audio thread to be used in the processBlock call and switch/merge it with the processBlock MIDI buffer…
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:
std::unique_ptr<MidiOutput> midiOutput;
// prepareToPlay:
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!):
if (midiOutput)
midiOutput->sendMessageNow(MidiMessage::controllerEvent(1, 23, 23));
I’m also working on a MIDI editor that needs to send to a physical MIDI out and I think having a lot of the same problems. Do you think you could post your working process block?