Making a virtualMidiDevice

I am trying to modify the MidiRecordingDemo to use a very simplified midi note generator as input that just plays a note for 1 second, waits 1 second and plays it again.

class SimpleMidiIn : public Component,
public Timer
{
public:
//==============================================================
SimpleMidiIn ()
{
startTimer (1000);
}

void timerCallback() override
{
    if (noteIsOn)
    {
        turnNoteOff ();
    }
    else
    {
        turnNoteOn ();
    }
}

private:

int midiChannel = 10;
int midiNote = 47;
juce::uint8 velocity = (juce::uint8) 100;
bool noteIsOn = false;

void turnNoteOn ()
{
    auto message = juce::MidiMessage::noteOn (midiChannel, midiNote, velocity);
    noteIsOn = true;
}

void turnNoteOff ()
{
    auto message = juce::MidiMessage::noteOff (midiChannel, midiNote, velocity);
    noteIsOn = false;
}

};

I do not know how to register it as a virtualMidiDevice, or maybe I have totally missed the point. I am new to C++ so I am likely missing some key concepts, but are there any examples of something like this?

If you mean a virtual MIDI device that’d be available for any other app, be aware that you won’t be able to do that on Windows as this requires a kernel land driver. It’s fine on macOS and Linux IIRC.

Thanks for the tip. I am making an iOS app that takes audio input from the microphone and turns it into Midi. The app will be kind of a simplified multitrack DAW. I am probably biting off more than I can chew with this project, but that seems to be how I (unintentionally) do things.

You might want to look at the EngineInPluginDemo. It might be easiest to handle the audio callback yourself in your app, and then stuff midi messages in to the midi buffer and then pass that all to the engine.

Otherwise you may want to look at the HostedMidiInputDeviceInstance class on how to build a fake midi device that can be passed to the audio engine.

Thanks! I will check those out. Looks like I have misunderstood what a Virtual Midi Device is. :flushed:

If you are talking about the virtual midi ports in waveform tracktion_engine, they are for treating one physical midi input port as several. for example if you have two keyboards plugged into the same midi port, one on channel 1 and one on channel 2, you could make a virtual input for channel 1 and another for channel 2.

Not sure how much use they are anymore, most MIDI devices are USB now. I don’t think that many people use midi cables anymore with the pass thru port.

There are also virtual midi ports in macOS / (maybe iOS too) which let you communicate between apps via MIDI.

I mistakenly assumed that the VirtualMidiInputDevice class would allow me to pass midiMessages that I generate myself to a track, as opposed to a physical device. I have no good reason why I thought this… it wasn’t due to midi ports in waveform.

I now think that your suggestion of HostedMidiInputDeviceInstance may be what I was looking for. But I’m still trying to figure it out. I will poke around for a bit and try to come up with some more educated questions about how to do this.

Thanks for your help!

You can also try AudioTrack::injectLiveMidiMessage and that will send midi to a track.

That’s probably the easiest, the downside is it won’t be recorded into clips.

It’s used for the popup keyboard in waveform.

I just thought about this some more, what will work is:

    if (engine.getDeviceManager().getDefaultMidiInDevice() == nullptr)
        engine.getDeviceManager().createVirtualMidiDevice ("Virtual");

    if (auto input = engine.getDeviceManager().getDefaultMidiInDevice())
        input->handleIncomingMidiMessage (nullptr, mm);
1 Like

is there any way to make this virtual device be seen by the juce device manager? ie:

engine.getDeviceManager().createVirtualMidiDevice ("Virtual");

// would like the virtual device to appear in this list, currently it is not
 auto list = juce::MidiInput::getAvailableDevices();

I would like to be able to attach a midi callback to the virtual device:

auto list = juce::MidiInput::getAvailableDevices();
for (const auto& midiDevice : list)
{
    juceDeviceManager.setMidiInputDeviceEnabled(midiDevice.identifier, true);
    juceDeviceManager.addMidiInputDeviceCallback(midiDevice.identifier, this);
}

Edit: I ended up not needing a virtual midi device after all. Since im on Linux I have those built int midi through midi inputs and outputs and I ended up using that.

Sorry, this one must have slipped through the net.

It sounds like you got what you needed to do done now but for anyone else reading this in the future there isn’t a way to show the VirtualMidiDevices in the OS or JUCE MIDI input list, they’re just not that kind of object.

VirtualMidiDevice is probably not the best name for them, they’re more like “aggregate MIDI inputs” where you can create one, and assign multiple physical inputs to them in order to quickly get multiple MIDI inputs to a track and record them in one go.