Empty instance array in track's midiInputDevice

Hi,
I’m trying to get midi events to play live, on a audio track where an instrument plugin is loaded. Here’s some the code sending out the message:

void AudioEngine::playKick()
{
if (auto track = getOrInsertAudioTrackAt(edit, 0))
    {
        juce::MidiMessage mm = juce::MidiMessage::noteOn(1, 60, 1.f);
        track->getMidiInputDevice().handleIncomingMidiMessage(mm);
    }
}

No audio comes out. When stepping into handleIncomingMessage(), I can see that the midi message is left unused in the MidiInputDevice::sendMessageToInstances() method :

        for (auto i : instances)
        if (i->handleIncomingMidiMessage (message))
            messageUnused = false;

because the instances property is an empty array in the above snippet.

I’m obviously missing a point about midiInputDevices and instances. How do they relate to each other? How can I add instances to the midiInputDevice of an audio track?

Make sure Edit::playInStopEnabled is true. Input device instances on exist when the audio engine is running.

Here is a function that finds all the midi inputs, assigns them to consecutive tracks and arms them for recording:

    void createTracksAndAssignInputs()
    {
        auto& dm = engine.getDeviceManager();
        
        for (int i = 0; i < dm.getNumMidiInDevices(); i++)
        {
            if (auto mip = dm.getMidiInDevice (i))
            {
                mip->setEndToEndEnabled (true);
                mip->setEnabled (true);
            }
        }
        
        edit->getTransport().ensureContextAllocated();
        
        int trackNum = 0;
        for (auto instance : edit->getAllInputDevices())
        {
            if (instance->getInputDevice().getDeviceType() == te::InputDevice::physicalMidiDevice)
            {
                if (auto t = EngineHelpers::getOrInsertAudioTrackAt (*edit, trackNum))
                {
                    instance->setTargetTrack (*t, 0, true);
                    instance->setRecordingEnabled (*t, true);
                    
                    trackNum++;
                }
            }
        }
        
        edit->restartPlayback();
    }
2 Likes

The thing is that I’m trying to do it the other way around, that is, creating audio tracks, and then have one input device per track that I send midi events to.
I’m trying the following init code:

void AudioEngine::initTracks()
{
    edit.ensureNumberOfAudioTracks (numTracks);
    
    for (int i=0; i<numTracks; i++)
    {
        auto audioTrack = getOrInsertAudioTrackAt(edit, i);
        auto* MIDIdevice = &audioTrack->getMidiInputDevice();

        MIDIdevice->setEnabled(true);
        MIDIdevice->setEndToEndEnabled(true);
        
        edit.getTransport().ensureContextAllocated();
        
        auto playCtx { edit.getCurrentPlaybackContext() };

        if (playCtx)
        {
            if (!MIDIdevice->getDestinationTracks().contains(audioTrack))
            {
                deviceInstances.add(MIDIdevice->createInstance(*playCtx));
                deviceInstances.getLast()->setTargetTrack(*audioTrack, 0, true);
                deviceInstances.getLast()->setRecordingEnabled(*audioTrack, true);
            }
        }
    }
}

And then I send note a noteOn to the first audio track’s midi input device like so :

auto track = getOrInsertAudioTrackAt(edit, 0);
auto mm = juce::MidiMessage::noteOn(1, 60, 1.f);
track->getMidiInputDevice().handleIncomingMidiMessage(mm);

Now I do have some audio out, but it’s garbage, I’m not sure how to describe it otherwise. All that is connected on this track is an internal FourOscPlugin.

Can you spot what’s wrong in the code above?

AudioTrack::getMidiInputDevice() isn’t what you want. It’s returns the output of a track as a MIDI device that you can assign to other tracks. It’s so you can record the output of one track onto another track. It looks like you are assigning a tracks output to its own input, which is why it’s going crazy.

If you want virtual midi inputs you can assign to each track, use DeviceManager::createVirtualMidiDevice() Do that numTrack times.

Then do something like:

edit->getAllInputDevices()[0]->handleIncomingMidiMessage(mm);

1 Like