[Noob question] Outputting MIDI from plugin


#1

Hey all, JUCE noob here - and C++ noob in general (Although I’m quite experienced in Java)

Basically, I’m trying to make a plugin for personal use which can be configured so on bar X, it will output a program change message to the DAW it’s running in.

I’ve got the actual timing part* done so I know which bar I’m on - what I’m struggling with is the outputting of the MIDI message. After a couple of hours of googling everything seems quite over complicated for what I’m doing, things like arpeggiators which need specific timing or stuff for writing fully-blown DAWs. My PC messages don’t need any specific timing and in fact should send as quickly as possible once the bar is reached.

So, my question is what’s the most simple way to output a MIDI message - and (I think this is where I’m having issues) how do I specify which device it should be sent to? I know on Mac you have various different devices and from my understanding I need to send it to an IAC driver in order to pass it on to the host. (What about in Windows though - I’m writing for OSX primarily but it’d be nice if I can support windows for anyone else who may want it)

I’ve tried various things but it doesn’t seem to be working. To test I’m loading it into a clean MainStage (which is what I’ll be using the final plugin in), with three patches. Sending a PC with values 1-3 into Mainstage will select those patches, but running my little AU doesn’t do anything. Also MidiMonitor shows no MIDI being passed on any device/channel, so I’m relatively confident the issue lies somewhere in my MIDI output. processBlock Code is below, and is a sort of amalgamation of stuff I’ve found from google and the tutorial code from the MIDI volume slider. (Sorry if it’s super messy/any bad practices - like I said I’m new to C++ in general but trying to learn!)

void BeatNotesAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    playHead = this->getPlayHead();
    playHead->getCurrentPosition(currentPositionInfo);

bpm = currentPositionInfo.bpm;
ppq = currentPositionInfo.ppqPosition;

midiMessages.clear();

int pcId = -1;

if (ppq >= 4.0 && ppq <= 5.0) {
    //send PC 002
    pcId = 2;
}
if (ppq >= 8 && ppq <= 9.0) {
    //send PC 003
    pcId = 3;
}

buffer.clear();

MidiBuffer processedMidi;
int time;
MidiMessage m;

for(MidiBuffer::Iterator i (midiMessages); i.getNextEvent(m, time);)
{
    if (pcId >= 0) {
        m = MidiMessage::programChange(1, pcId);
        pcId = -1;
    }
    processedMidi.addEvent(m, time);
}

midiMessages.swapWith(processedMidi);
}

Any help would be great :smiley:

*I’m currently getting timing info in the form of PPQ, which from what I can see is a double and every full integer = 1 beat, so the math should be pretty easy to actually figure out the bars. However, currently I’ve got my plugin GUI trying to display the current PPQ value, but it’s only updating when I click on or click off the window instead of updating in real time. For bonus points how would I get my GUI to update roughly in real time?


#2

What about skipping midiMessages.clear() before iterating it?


#3

I go for the bonus points :wink:
Best approach is to derive your ProcessorEditor from Timer and write a void Timer::timerCallback() where you constatntly call repaint().
This is because the midi messages run on theaudio thread and you don’t want to call painting directly from there, because it may block the playback (or even worse the recording).
To not waste too many painting time add a flag or better a counter, which you increment on each message arriving, so the timerCallback can check with a member variable if painting is necessary.

And best thing would be to make the counter in an atomic, because you are reading from two different threads.
Eventually confusing, so I better give some code:

void ProcessorEditor::timerCallback() override
{
    const int mc = processor.getMidiCounter();
    if (lastMidi != mc) {
        repaint();
        lastMidi = mc;
    }
}

in the processor:

int getMidiCounter() const {
    return midiCounter.get();
}
private:
    Atomic<int> midiCounter;

and simply increment midiCounter whenever something changed what you want to update.
and don’t forget to call startTimerHz (50); in the editor’s constructor.

For the actual midi question, there are several catches about whit methods to use, so just my rough thoughts:
When you use the MidiBuffer in processBlock, it is meant to be routed inside your DAW. But every DAW is different, so e.g.in ProTools a plugin that accepts midi input will add a selection of any midi outputs any plugins in the project will offer. In cubase I couldn’t find that option, there I think it is only passed from one plugin to the next…
Unfortunately I don’t know how it looks in MainStage though. Maybe somebody else has some insights about that.

So if you want to communicate with other softwares or connected hardware, you use MidiInput and MidiOutput
But remeber that you are then outside the DAWs timing context. So this is better suitable for AudioApplications instead of plugins. You can mix it, but better use the DAWs routing options.


#4

@oxxyyd - That made no difference unfortunately

@daniel - Wow, thanks for all the help! Took me a bit of tinkering (as I said, C++ newbie and things are quite different to Java which often has me screaming WHY ARE YOU LIKE THIS at my screen) - but I eventually got the refresh thing working so that can now be crossed off the list :slight_smile:

Regarding what you said about the main MIDI issue - MainStage does indeed have routing options. My current system is using what they call an “External Instrument”, which you can assign both midi out and midi in on (as in into the external instrument, and out from). I do have it set up so the external instrument (IE, my plugin, which is a MIDI FX plugin) is outputting to my “To MainStage IAC” driver.
For sanity’s sake, I set up a quick PureData script which listens to the MainStage clock and after 4 bars, sends a PC message back in on that same driver, and that works just fine (PD is what I was originally using, but it’s a real pain to have to load individual scripts, which is why I’m making this in plugin form where I can just save presets).

MIDI monitor shows the output from PureData too, but not from my plugin, so I’m pretty confident it’s a bug with my code and not just MainStage ignoring the message. I’ll keep trying to figure it out but is there any other ideas? I really need to keep it in plugin form else the whole endeavour is pretty pointless.

–EDIT–

Alright, with a lot of diving around the web, I’ve discovered that although Audio Units support MIDI output, Logic does not (Which is weird as both are made by Apple). The closest you get in Logic is the aforementioned Midi FX, which can output MIDI but only within the channel strip (IE, it’s designed for sending MIDI data to an attached softsynth or similar - not for program changes etc).
There’s no info either way on MainStage, but as it’s derivitive of Logic I assume it’s the same situation.

HOWEVER, you mentioned before the Midi output thing. I’m gonna start tinkering now but I’m sure you can tell me well before I’m done;
would it be possible to use Midi Output to send MIDI to a device which would be specified within my plugin, and therefore my plugin would output straight to that device (ie, the IAC driver) without sending MIDI into the DAW? That way I can just have a midi input from the IAC driver which would read that data and accept it just as if it was sent from PureData… I’ll tinker a bit :stuck_out_tongue:

EDIT 2:
It’s actually super easy and I got it working! Oddly, all you need to do is create a new midi out device. You don’t even have to use it or anything - it just needs to exist.

That’s the easy part of my plugin done I guess… now I have to do the GUI and let people configure it. D:
Thanks for the help + pushing in the right direction