MIDI Out events from a standalone plugin


#1

Hi all,

I’m working on a standalone plugin; I’ve made it using StandaloneFilterWindow, so I used the same processing code I wrote for a VST/AU plugin.
The plugin produces MIDI events; so in the StandaloneFilterWindow I have enabled the Midi Output selector. Then I use something like MIDI Yoke or LoopBe to route MIDI events to other apps, so I choose the proper MIDI stream from the Midi Output selector (for example MIDI Yoke).
I’m monitoring the MIDI events passing through MIDI Yoke, but no events are received.

It works good as audio-to-midi plugin in a host, but it does not work as standalone application.

Could someone help me?

Thanks in advance
Lele


#2

I think you need to handle the midi output yourself when working in standalone mode. MidiOutput::openDevice(int index) will return a midi output device that you can send notes to.


#3

StandaloneFilterWindow creates an AudioDeviceSelectorComponent (here I enabled the Midi Out selector), passing its AudioDeviceManager.
The AudioDeviceSelectorComponent already selects the default MidiOutput and assigns it to the AudioDeviceManager.

else if (comboBoxThatHasChanged == midiOutputSelector)
    {
        deviceManager.setDefaultMidiOutput (midiOutputSelector->getText());
    }

Now, the AudioDeviceManager adds an AudioProcessorPlayer as callback for audio and Midi Input:

deviceManager->addAudioCallback ( &player);
deviceManager->addMidiInputCallback (String::empty, &player);

But nothing related to Midi Output.

I found this post http://www.juce.com/viewtopic.php?t=1362&p=7476 dated Jan 08 2007, but I think that nothing has been done.

Is there any sample code that deals with Midi Out, for example a simple juce host that sends Midi Out to a Midi Out device?

Cheers
Lele


#4

Sorry, I don’t have any code for this, nor have I ever tried to do it myself. Perhaps I’m over simplifying this, but if you call AudioDeviceManager::getDefaultMidiOutput() after the midi device has been selected it will return the current MidiOutput object. Once you have this can’t you just call one of its send midi methods to output some midi notes?


#5

Hello,

Well, to open a MidiOut in stand alone app, you may not even need to go thru DeviceManager; it’s could just be a matter of

[code] StringArray midiOutNames;
midiOutNames = MidiOutput::getDevices();

ScopedPointer midiOut;
midiOut = MidiOutput::openDevice(midiOutNames.indexOf(name));
[/code]
then :

if (midiOut != nullptr) midiOut->sendMessageNow(midiMessage);
Works for me.

BTW : Did you made that standalone plugin to workaround the fact that plugin’s can’t output midi when inside a DAW by any chance ?

Salvator


#6

What do you mean by “fact that plugin’s can’t output midi when inside a DAW by any chance”. They certainly can as far as I’m aware? Just make sure you enable MIDI out in your AppConfig.h file.


#7

Salvador, thank you for your snippet, I’ll give it a try.

I’m building a standalone plugin because I need it :wink: ; as I stated in my first post:

As Rory said, I’ve just enabled the MIDI out in AppConfig.h file and returned “true” in producesMidi() method.

Lele


#8

It’s a complicated subject, MIDI OUT from a plugin to the Host is possible in the latest AU and VST (i have no idea bout AAX), it’s not available in some previous AU specifications.
You can always talk to MIDI devices directly but you must watch out for timing and threading, you should never produce MIDI events from within the Editor class (your GUI events will cause big delays in MIDI events),
you should produce MIDI events in a different thread or in the audio thread. You will never get correct time sync between your host and the external device, there is no way of knowing when to transmit MIDI events
to the external device from the Audio thread, it’s not possible because of latencies inside the host.

If you plan to send devices from your own classes on the UI thread, use the startBackgroundThread () method and send the vents using sendBlockOfMessages() method, all the threading stuff will be handled by JUCE.


#9

This is how I solved.

My AudioProcessor class is MyFilter; I’ve added two members:

AudioDeviceManager* devManager;
MidiOutput* midiOut;

At the beginning of processBlock():

	if(devManager) {
		midiOut = devManager->getDefaultMidiOutput();
		
		if( midiOut ) midiOut->startBackgroundThread();
	}

at the end of end of processBlock():


       if (midiOut != nullptr) {
		midiOut->sendBlockOfMessages(	
			midiMessages,
			Time::getMillisecondCounter(),
			this->getSampleRate()
		);	
	}

I created my own Standalone Window copying it from StandaloneFilterWindow and I’ve passed the DeviceManager to the filter:

    filter = (MyFilter*)createPluginFilterOfType (AudioProcessor::wrapperType_Standalone);
    filter->devManager = deviceManager;

I know, it is not the best way to do it, but it works as a charme.

Best
Lele


#10

i know this is an old post, but i'm trying to setup midi output in a standalone, and want to follow this advice.

Where should i put these lines of code?  

 

 


#11

When I wrote my example, I used JUCE 2; don’t know if there is something different with JUCE 4.
Anyway:

myfilter.h:

class MyFilter:AudioProcessor {
...
AudioDeviceManager* devManager;
MidiOutput* midiOut;
...
}

myfilter.cpp:

void MyFilter::processBlock(...){

if(devManager) {
		midiOut = devManager->getDefaultMidiOutput();
		if( midiOut ) midiOut->startBackgroundThread();
	}
...

if (midiOut != nullptr) {
	midiOut->sendBlockOfMessages(	
		midiMessages,
		Time::getMillisecondCounter(),
		this->getSampleRate()
	);
}

I’ve copied the entire juce_StandaloneFilterWindow.h in my source directory, renaming it to myStandaloneFilterWindow.h and renaming all occurrences of StandaloneFilterWindow to MyStandaloneFilterWindow.

myStandaloneFilterWindow.h:

...

JUCE_TRY
        {
// explicit cast to MyFilter*
            filter = (MyFilter*)createPluginFilterOfType (AudioProcessor::wrapperType_Standalone);
        }
JUCE_CATCH_ALL
...

deviceManager = new AudioDeviceManager();
deviceManager->addAudioCallback (&player);
deviceManager->addMidiInputCallback (String::empty, &player);
				
player.setProcessor (filter);
// added:
filter->devManager = deviceManager;

....

Hope it is clearer now.


#12

My standalone MIDI effect (no audio channels needed) unlike the plugin, doesn’t receive or send midi messages by default…
Is this has been taken care of in JUCE 5 or its something that we need to do it manually like the example above?