Attempting to port from RtMidi to JUCE, but overwhelmed

I’ve been wanting to help my dad make a MIDI processor plugin for Logic Pro X, and I’ve found RtMidi to be a boon with MIDI interaction when I experimented with a simple program that, with the help of my dad at his mixer, I was able to automate the operation of a single mute. However, when it comes to JUCE, I’m utterly overwhelmed with what to do.

TL;DR: How would I go about translating this to JUCE?

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <RtMidi.h>
#include <vector>

void callback(double dtime, std::vector<uint8_t> *pMsg, void *data)
{
	std::cout << "Message: ";
	for (uint8_t &b : *pMsg)
		std::cout << std::hex << std::setw(2) << std::uppercase << static_cast<int>(b) << ' ';
	std::cout << '\n';
}

int main()
{
	RtMidiIn *midiIn = new RtMidiIn();
    RtMidiOut *midiOut = new RtMidiOut();
	int inports = midiIn->getPortCount();
    int outports = midiOut->getPortCount();
	std::vector<uint8_t> msg;
    
    std::cout << "API:" << midiIn->getApiDisplayName(midiIn->getCurrentApi()) << '\n';
	std::cout << "Inputs: " << inports << "\n\n";
    std::cout << "Outputs: " << outports << "\n\n";

	for (int i = 0; i < inports; i++)
		std::cout << "Input " << i << ": " << midiIn->getPortName(i) << '\n';
    std::cout << '\n';
    for (int i = 0; i < outports; i++)
        std::cout << "Output " << i << ": " << midiOut->getPortName(i) << '\n';
    std::cout << '\n';
	
    int port;
    std::cout << "Use port #: ";
    std::cin >> port;
	midiIn->openPort(port);
    midiOut->openPort(port);
	midiIn->setCallback(&callback);
	midiIn->ignoreTypes(false, false, false);

	std::cout << "\nReading MIDI input ... press 'q' and <enter> to quit.\n";
    char input = ' ';
    bool muteOn = false;
    while(input != 'q')
    {
        if (input == 'm')
        {
            uint8_t state = muteOn ? 2 : 3 ;
            std::vector<uint8_t> msg = { 178, 0, state };
            muteOn = state == 2 ? false : true;
            midiOut->sendMessage(&msg);
        }
        std::cin.get(input);
    }

	delete midiIn;
    delete midiOut;
	return 0;
}

Although I don’t know RtMidi, from your code I guess that this small command line application opens a midi interface of choice, prints out any incoming midi signal as hex and sends out this one mute signal when pressing the m key…

So what are you planing to do now with JUCE?

  • Build a command line program that does the same?
  • Build a standalone GUI app that does the same?
  • Build a plugin that does more or less the same?

Depending on what you plan, the “translation to JUCE” would look a bit different. E.g. all the management for setting up a midi in/out port will obviously not be needed with a plugin. The user interaction part would look quite different if you build a GUI instead of using command line in/out. So if you are a bit more specific, you might get some better answers.

It will be possible to write a similar simple command line tool with JUCE. If you plan on building something with a user interface, be prepared that it might get a little more complex.

For the meantime, have you had a look at the tutorials? https://docs.juce.com/master/tutorial_midi_message.html might get you started understanding the MidiMessage class which is used for a bit more sophisticated Midi message handling instead of the raw byte vector RtMidi seems to use, however this example doesn’t send or receive midi, it is just an example of how midi data is handled/manipulated with this class. Along with the GUI-centric tutorials, it could also help you getting started if you wanted to build some GUI based application.

Well my goal is to make an AU plugin that automates a D&R Cinemix brand mixer. I’m pretty sure I can set up GUI events no problem. It’s just that the processor class itself seemed like a headache at first glance. I will look at the tutorial, though. Skimming over it seems like it’ll be handy. Much appreciated.

When you generate an audio plugin project with the Projucer, it will generate the skeleton code for an AudioProcessor subclass and you may not even need to touch all the automatically generated methods. prepareToPlay and processBlock are the most important ones.