processBlock and midiOutput


#1

Howdy

In the processblock of the juce demo plugin, the audio Buffer can be edited directly and then it is output as I would expect.

I'm trying something similar with the midi buffer, but I can't seem to send any midi back out.

I'm generating my message and adding it to the buffer like this:

MidiMessage msg;
uint8 vel = 127;
msg = msg.noteOn(1, 22, vel);
midiMessages.addEvent(msg, midiMessages.getLastEventTime());

....but it's not working the way I would expect, like the audio buffer.

Am I doing this incorrectly, or do I need to explicitly pass these message to the midi out?

I should clarify I am testing this in the demo plugin host for simplicity.

Thanks for any pointers.


#2

Bit of an confused way of creating the message, but basically should work. You didn't say what's happening to the message afterwards or why you think it doesn't work.. Best way to test would be to connect it to a synth - are you doing that?


#3

Howdy Jules thanks for replying.

I am connecting it to a hardware device trying to turn on an LED.

If I send a note number and noteOn, the LED should light up...I have confirmed that the device functions properly by sending data from another program. One thought I had was maybe I was sending the note on and it was getting then reset each buffer, so maybe I'm just not seeing it. I'll try to hook up a better midi test right now with a software loopback.

Bit of an confused way of creating the message, but basically should work. You didn't say what's happening to the message afterwards or why you think it doesn't work.

Could you elaborate on what I am confused about? I was definitely confused with the uint thing...just putting in the integer value was triggering an error.

I was also confused about msg = msg.noteOn(...) - as I thought I could just do msg.noteOn(..) but that wasn't doing it either.

As for what is happening to the message after - I just add it to the buffer (I count the messages to make sure it is there)...if there is anything else I need to do with it, do enlighten me.

Thanks


#4

It's a static method!

midiMessages.addEvent (MidiMessage::noteOn (1, 22, vel), midiMessages.getLastEventTime());

Try it with a synth before assuming it's a fault in your processBlock. Most likely it's just not reaching the hardware device for some reason.

 


#5

Thanks Jules.

I set the midioutput of the demo plugin host to a MidiYoke channel, and tried to monitor the output via MidiOx....nothing.

I also loaded another midi generating plugin but couldn't get any midi out.

 

So I am trying a new host now and will report back.

Thanks


#6

I'm having a hard time finding a host that helps me debug the midi output of the plugin.

Ableton seems to treat it as an audio plugin (it does produce audio), which disables my options for midi output.

Is there a way to configure the plugin so that it only appears as a midi plugin? I'm wondering about in IntroJucer disabling the 'is a synth' box.

 

Any tips would be appreciated...I agree it seems that I'm just not getting communication with the device, but I can't figure out if it's my code or the plugin host. The code seems straightforward enough.

 

Thanks again.

edit: Changing the 'is a synth' box in introjucer did not make a difference...ableton still treats it as an audio plugin.


#7

Have you loaded your plugin into the vst inspector app that's in the vst sdk and checked if it reports "produces MIDI"?


#8

Howdy

That sounds like a good idea - but I'm not seeing an 'inspector' app in my sdk. First, are we talking about vst 2.4 or 3? I have found a test host in the vst3 sdk, and source for a 'minihost' in the 2.4 sdk.

 

I can't figure out how to load a plugin in the vst 3 app, and the 2.4 host will not compile, complaining with things like " Loaded 'C:\Windows\SysWOW64\user32.dll'. Cannot find or open the PDB file."

 

So if I'm missing something, please let me know. Otherwise I'll keep trying these two hosts.

THanks


#9

I was able to load the plugin via the vst2.4 sdk 'minihost' using the command line.

You have to specifically load the vst via the command line like 'minihost.exe *path-to-vst*'.

 

It does not show a 'produces midi' field - so how do I set that? It is set via the introjucer currently.

My plugin does show "Can do receiveVstEvents... yes
Can do receiveVstMidiEvent... yes
Can do midiProgramNames... don't know"

Diving back in now....thank yall.


#10

So using a VST midi monitor within the Juce vst host, I can see that my plugin is indeed producing Midi data.

However, this data is not going anywhere - not to a physical midi device or a virtual one which I then monitor with MidiOX. I have noticed that these beautiful red midi out ports in the software don't have anything to plug into.

 

Any ideas to get midi out of Plugin Host?

 

Thanks


#11

This depends really on the host implementation.

Some of them supports MIDI output from a VST plugin (Ableton Live, Cubase ...), some do not (FLStudio, Maschine ...).

 


#12

I can tell now that it does heavily rely on the host - and so my query is in particular regard to the Juce Demo Plugin Host.

 

Will the Juce demo host actually send midi out from a plugin?

Again, I can see the data with a midi monitor plugin, but I've nowhere to plug the midi out to and it just doesn't seem to go anywhere after that.

 

Sidenote: Ableton has a trick on their website where you use two midi channels, one to host the plugin and send midi internally, another to pick up this midi and then send back out.


#13

Well note the word "demo" in the juce demo host.. TBH I can't remember how the midi side of it works or whether it even supports midi i/o at all, but all the code is right there for you to look at or add to.


#14

Could you point me in the right direction?

I am trying the same thing with the StandaloneFilterWindow - I've got the options for midi output showing up, but still no midi out of the window. I'm assuming these will be related.

Would appreciate a point in the right direction (AudioDeviceManager?) to where I can find out how to manipulate the midi buffer at the end of leftover processblock

 

Thanks - I am digging in...checking out the sendBlockOfMessages stuff...


#15

I've got to admit at this point I'm pretty lost.

I tried looking at the demo host - but I really couldn't find a lot of code dealing with midi/audio processing except for going deeper into the juce modules. Since they are working there, I'm trying to stay more high level.
I did manage to create a graphical midi output node box, but it still didn't send midi anywhere.
(The demo host handle midi input just fine btw).

 

I've since moved on to trying to get some midi out using the standalonefilterwindow - I changed the default setting menu to show midi output as by default, it was hidden. Once again, I would expect it to just work per the documentation of processblock 'any data left in the buffer is assumed to be the midi output'.

 

What am I missing here? There has to be some disconnect where what you select as 'midi  output port' doesnt actually receive the code the plugin produces as midi output.

Thanks yall.


#16

I've decided instead of trying to dive deeper in the demo host, I'm going to attack this from standalone.

 

Am I correct that I need to add a callback to the device manager, and have that callback pull the midibuffer from my filter, then spit that out to a midi port? What's the best method for pulling the midibuffer?

 

If I'm incorrect there, then what should I be looking at? I've gone through the demo host, the Juce demo (midi i/o), and the standalone filter window, but I'm not finding anything that succesfully sends midi out...this makes me wonder if I'm really missing something or looking in the wrong place.

 

And to clarify - the plugin producing midi works fine - a host like ableton can pick it up and send it out. However I'd like to do this standalone  - and I can't find many examples of the kind of process I will need for this.

 

I have tested by sending a basic midi message

deviceManager->getDefaultMidiOutput()->sendMessageNow(MidiMessage::noteOn(1, 33, vel));

...and I can see that message, so I know the pathway is there. Still, I am unclear how to start pulling messages out of the plugin buffer.

 

Thanks as always.

 


#17

Maybe I'm overcomplicating....

Where would I look for some information on how to pull the MidiBuffer out of processblock - say in the standalonefilterwindow?

Per the audioProcessor documentaion..."Any messages left in the midi buffer when this method has finished are assumed to be the filter's midi output"...so how do I get at that buffer from outside the audioprocessor?

I know the plugin is generating midi data fine.

Thank yall.

 

ps. My solution right now is to just send the midioutput from within the plugin, I'd just prefer to leave the plugin code itself alone if possible.


Adding Midi Out to VST Host Demo
#18

Here's a how you can update the plugin host to handle midi out.

1. First you need to add some code to actually create the midi out connection so to say

In FilterGraph.cpp you add

addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiOutputFilter), 0.25f,  0.9f);

in InternalFilters.cpp you add

{
        AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);
        p.fillInPluginDescription (midiOutDesc);
}

and

    if (desc.name == midiOutDesc.name)
        return new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);

and

case midiInputFilter: return &midiInDesc;

in relevant places, I guess you'll see right away where to put these lines.

 

2. Some more updates

Add to the collection of privates of GraphEditorPanel.h

MidiOutput *midiOut;

 

Make GraphEditorPanel a ChangeListener i.e in GraphEditorPanel.h it should look like

class GraphEditorPanel : public Component, public ChangeListener


3. Add to GraphEditorPanel.cpp
 

void GraphDocumentComponent::changeListenerCallback (ChangeBroadcaster* source)
{
    if (source == deviceManager)
    {
        midiOut = deviceManager->getDefaultMidiOutput();

        if (midiOut)
            midiOut->startBackgroundThread();
        //else stop?

        graphPlayer.setMidiOutput(midiOut);
    }
}

and its declaration to GraphEditorPanel.h

 

4. Now add the line

changeListenerCallback (deviceManager);

somewhere in the constructor of GraphDocumentComponent. (GraphEditorPanel.h)

and put following at the to beginning of ~GraphDocumentComponent

if (midiOut)
 midiOut->stopBackgroundThread();

 

5. Finally you need to update two juce files. Add
 

MidiOutput *midiOutput;


to the private parts :) of juce_AudioProcessorPlayer.h
 

Add

void AudioProcessorPlayer::setMidiOutput(MidiOutput *newMidiOutput)
{
    if (midiOutput != newMidiOutput)
    {
        const ScopedLock sl (lock);
        
        midiOutput = newMidiOutput;
    }
}

to juce_AudioProcessorPlayer.cpp and corr declaration to juce_AudioProcessorPlayer.h

 

Now we've come to the part where midi output is actually taken from the AudioProcessorGraph.

In juce_AudioProcessorPlayer.cpp change

            if (!processor->isSuspended())
            {
                processor->processBlock (buffer, incomingMidi);
                return;
            }

to

            if (!processor->isSuspended())
            {
                processor->processBlock (buffer, incomingMidi);
        
                 MidiBuffer &midiBuffer ((dynamic_cast<AudioProcessorGraph *>(processor)) ->getCurrentMidiOutputBuffer());

         if (!midiBuffer.isEmpty() && midiOutput)
           midiOutput->sendBlockOfMessages(midiBuffer, Time::getMillisecondCounter(),   getCurrentProcessor()->getSampleRate());

                return;
            }

 

6. And last add following line to the publics of juce_AudioProcessorGraph.h


MidiBuffer& getCurrentMidiOutputBuffer() { return currentMidiOutputBuffer; }

After building and starting the plugin host you should now have a midiout. Draw a connection between midi input and midi output. If you have selected a midiout device in the audiosettings (e.g Microsft GS Wavetable Synth in windows) you should now here a piano when playing on the midikeyboard. See the attached pic.

If you're more into copy & paste programming you could instead of modifying the two juce files create a "midiout processor" by subclassing juce_AudioProcessor. But I leave that as an excersise for the reader...

 

Good luck!

 


#19

WOW! Thank you for that extensive breakdown. I did try an attempt at modifying the plugin host to do midiout, but I found a solution that worked for me so I moved on. I will have to revisit this now.

 

Thanks so much.


#20

Regarding this line....

MidiBuffer& getCurrentMidiOutputBuffer() { return currentMidiOutputBuffer; }

This is the sauce that I needed right here - and I'm not finding much about it in the documentation. 'CurrentMidiOutputBuffer' is exactly what I was looking for, but I guess I relied too heavily on the documentation and did not get into the code files enough.

Thanks again for the push.