Juce VST3 plugin - MIDI SYS EX output issue


#1

Hi this is my first topic on a forum, please excuse any bloomers

The problem is when I use MidiMessage::createSysExMessage() to send a SYS EX message, nothing is sent
If it try MIDI output using MidiMessage::noteOn() it works fine !
I have debugged into the code and can see the createSysExMessage constructs the SYS_EX packet Ok

the SYS EX MIDI output using MidiMessage::MidiMessage() was previously working but mysteriously stopped some weeks ago when I was not looking ! (several weeks ago I updated from 3.1.1 to Juce 3.2.0 but I cannot tell if this had any relation to when the fault occurred.)

1) can you spot what I am doing wrong ?

2) can you point me to an example of MIDI sysex output ?

3) I would prefer to use MidiMessage::MidiMessage() to send raw MIDI data (which was previously working)

I have been trying to get this going for 4 days now and it's starting to drive me potty
Please can you help me.

I have written in C for several years and wrote my first MIDI sequencer in 1983
but this is my first C++ project and I am using the excellent Juce framework 3.2.0 for the first time

My PC AMD w 16Gb RAM, I am using savihost3x64_1v42 http://www.hermannseib.com/english/savihost.htm to host my VST3 x64 plugin
It is receiving MIDI commands from the USB device and The Juce keyboard works Ok outputting notes to my USB MIDI device


//-----------------------------------------------------------------
// This is served every Audio block (few 100 us) for PlugInProcessor

void GgPuAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
  const int numSamples = buffer.getNumSamples();
  keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
 
  processGuitarMidiBuffer(midiMessages);         // Pass any incoming midi messages to Guitar neck display & Replace MIDI Output messages
}
//---------------------------------------------------------------------------
void processGuitarMidiBuffer (MidiBuffer& midiMessages)
{
  MidiMessage midiMess;
 
  MidiBuffer::Iterator iIter (midiMessages);
  MidiBuffer processedMidi;
  MidiMessage message (0xf4, 0.0); // I do not know why this is req'd
  int time = 0;
  //------------------------------------------------
  // MIDI Input
  while (iIter.getNextEvent (message, time))
  {
    processMidiRxEvent (message, time);       // Service all MIDI Rx Input events
  }
  //--------------------------------------------------------------------------------------
  // MIDI Outut - message to test MIDI output SYS EX send
 
  byte *pMessTest;
  pMessTest = new byte[16];           // test buffer
  *(pMessTest + 0) = MIDI_SYS_EX;     // 0xF0 (will be prepended by createSysExMessage)
  *(pMessTest + 1) = 0x1A;
  *(pMessTest + 2) = 0x2A;
  *(pMessTest + 5) = MIDI_SYS_EX_END; // 0x7F (will be appended by createSysExMessage)
// Referenced by MidiEventList::toMidiBuffer().
//-----------------------------------------
// The data passed to createSysExMessage() in is wrapped with header and tail bytes of 0xf0 and 0xf7. OK
// midiMess = MidiMessage::MidiMessage(pMessTest, 4, 0.0f);     // This test does not send any MIDI message
  midiMess = MidiMessage::createSysExMessage(pMessTest + 1, 2); // This test does not send any MIDI message
//-----------------------------------------
// midiMess = MidiMessage::noteOn(5, 127, 1.0f); // this sends MIDI message OK to host
//-----------------------------------------
  processedMidi.addEvent (midiMess, time); 
}
//---------------------------------------------------------------------------

 


#2

Hello,

​You add an event to the function local variable processedMidi, but you don't use it anywhere.

Hope this helps!


#3

Also, all that code creating that array should be written like this:

const char data[] = { 0x1a, 0x2a };
midiMess = MidiMessage::createSysExMessage (data, numElementsInArray (data));

The function already adds the sysex header + footer bytes for you, and it looks like you're creating and leaking a heap array for no reason, as well as leaving bits of it uninitialised. If you're unfamiliar with how C++ heap/stack variables work, you'd probably benefit from spending some time learning about that.


#4

 

Thanks for the response,  the code I submitted was a test, my real code did clean the heap and swap the MIDI out buffers 

So I have simplified it, I hope this makes more sense.


The code here does not send any MIDI output as it should do, can you explain ?
 

//------------------------------------------------
// This is served every Audio block (few 100 us) for PlugInProcessor
void GgPuAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
  const int numSamples = buffer.getNumSamples();
  keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
 
  processGuitarMidiBuffer(midiMessages);
}
//------------------------------------------------
void processGuitarMidiBuffer (MidiBuffer& midiMessages)
{
  MidiMessage midiMess;
 
  MidiBuffer::Iterator iIter (midiMessages);
  MidiBuffer processedMidi;
  MidiMessage message (0xf4, 0.0);
  int time = 0;
  //------------------------------------------------
  // MIDI Input
  while (iIter.getNextEvent (message, time))
  {
    processMidiRxEvent (message, time); // Service all MIDI Rx = OK
  }
  //------------------------------------------------
  // MIDI Output
 
  const char data[] = { 0x1a, 0x2a };  // TEST SYS EX data
  midiMess = MidiMessage::createSysExMessage (data, numElementsInArray (data));
  processedMidi.addEvent (midiMess, time); 
  midiMessages.swapWith (processedMidi);
}
//------------------------------------------------

#5

That looks OK, but looking at the VST3 code, sysex does seem to be implemented as far as I can tell, and we're not aware of problems with it.

I'm OOTO today but you might want to debug into the MidiEventList::toEventList() function to see if your data gets as far as being sent?


#6

Hi Jules

Thanks for respondin so quickly

I debug into MidiEventList::toEventList() and midiBuffer has correct SYS EX data ie F0, 1A, 2A, F7

msg.isSysEx() - OK

e.type = 2

e.data.bytes = 0x1A

e.data.size = 2

e.data type = 0

e.sampleOffset = 0

I think this is as expected, but I put a break in the USB MIDI device, no SYS_EX is received

When I change the line:

 midiMess = createSysExMessage(.....) to  midiMess = MidiMessage::noteOn(5, 127, 1.0f); then it sends a note as expected

also when I presss a key on your piano keybaord that is sent Ok

 


#7

TBH it sounds like it's your host that's not sending the message onwards.


#8


Ha .... Yes it looks like my debug VST Host is only sending MIDI Note info, will update when I have found the root cause.........
 


#9

createSysExMessage() x64 is broken, x32 is OK

I am now using Reaper 5.0.1  as a VST host  (I was using savihost3x64 as VST host)

So this is not my VST host problem, as when I compile using the introJucer x32 option, the MIDI sys ex works OK, my test is F0, 1A, 2A, 3A, 4A, 7F

When I change introJucer to x64, createSysExMessage () sends rubbish ie. 0xDD, 7B, 00, DD, 00, DD, 00 (all the rest of my VST works fine including MIDI Note send)

I have tries various other MidiMessage:: events

Working Ok in x64 = noteOn, aftertouchChange

Not working in x64 = controllerEvent, channelPressureChange, createSysExMessage, MidiMessage


#10

None of juce's sysex handling is 32- or 64-bit specific, I'd suspect it's either your host that's behaving differently, or maybe your own code is messing up memory in a way that just happens to survive by sheer luck in 32 bit mode.