handlePartialSysexMessage on Windows


#1

it took some digging to find out this wasn’t supported on windows since it isn’t mentioned in the comments or docs and the function name isn’t mentioned in the changelist. Are there plans to implement this on Windows?

In the the meantime, is there a reliable way to handle this via the existing handleIncomingMidiMessage? I suspect there’s more to it than just creating a buffer and filling it until I hit the terminator… to be sure the incoming packets are part of the same message?

Also as far as sending multi-packet sysex messages… haven’t looked into that much yet, but will I have similar problems there?

Any example code would be great, thx :slight_smile:


#2

Actually, it is as easy as you describe… As well as understanding the MIDI spec, ie. while 0xF7 is the normal termination of a sysex, any other Status byte will also end the sysex… And, if you have more than one midi port open, then you will need to use the MidiInput that comes into the callback to discern where it comes from… If no one else posts you some code, I’ll clean mine up for general consumption and post it… :slight_smile:


#3

JUCE is one of the very few APIs I’ve used where some thing really are easy :wink: or at least straight forward…

anyway, when I add my class to the MidiInput callback array like so:

I’m assuming my callback will only get called with the default device (even if it changes)… though I suppose when you have multiple devices checked in the device manager dialog, it’s not clear which one is the default… but I guess some hacky check like so can’t hurt:

[code]void MidiManager::handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message)
{
if (source->getName().compare(source->getDevices()[source->getDefaultDeviceIndex()]) != 0)
return;

//…
}[/code]

plus, I’m only accepting messages on one specified channel or sysex ID (specified in the header)… so the buffer thing seems to be working pretty well actually.

Haven’t gotten to the sending large sysex messages part yet… they could be upwards of a meg in my case… so if you have any code you could share for something like that, it would be much appreciated :slight_smile: I Haven’t looked at the internals of the MidiOuput class yet, but I’m guessing I can use some combination of calls to mimic the behavior of a decent midi program like midi-ox in terms of buffersize, delay between buffers, etc (?).

thanks :slight_smile:


#4

Here is a copy of the code I am using. Like you describe, I am only using a single midi input, so I don’t have to manage multiple streams. I don’t expect large sized sysex, so I use a small pre-allocated buffer. I haven’t looked at the underlying JUCE code, and I don’t recall reading anything in the docs, but I’m not sure you want to be allocating memory in the callback. So, you may need to pre-allocate a buffer large enough to handle the largest you expect… Oh, lastly, I modified the code when I pasted it here, to handle the case I didn’t have before (ie. any status message cancels the sysex)…

[code]void DK10EditorJuceComponent::handleIncomingMidiMessage( MidiInput source, const MidiMessage &message )
{
unsigned char
sysexData = (unsigned char*)message.getRawData();
int sysexDatalen = message.getRawDataSize();

receiveDk10Data( sysexDatalen, sysexData );

};

void DK10EditorJuceComponent::receiveDk10Data( int sysexBufferLen, unsigned char* sysexBuffer )
{
// if the data fits in the internal buffer
if( mSysexCurOffset + sysexBufferLen < kSysexBufferSize )
{
// if it the start of the msg, and it’s the start-of-sysex, or any byte after the start
if( ((mSysexCurOffset == 0) && (*sysexBuffer == 0xf0)) ||
(mSysexCurOffset != 0) )
{
memcpy( &mSysexBuffer[ mSysexCurOffset ], sysexBuffer, sysexBufferLen );
mSysexCurOffset += sysexBufferLen;

        // if this is a status byte, then this is the end of the sysex
        if( mSysexBuffer[ mSysexCurOffset - 1 ] & 0x80 != 0 )
        {
            // if this sysex ends in 0xF7, then it is a valid sysex
            if( mSysexBuffer[ mSysexCurOffset - 1 ] == 0xf7 )
            {
                mDk10Data.putSysexData( mSysexCurOffset, (unsigned char *)&mSysexBuffer[ 0 ] );
            }

            // reset the buffer
            mSysexCurOffset = 0;
        }

    }
    else
    {
        // ERROR
        // wrong data
        // reset the buffer
        mSysexCurOffset = 0;
    }

}
else
{
    // ERROR
    // too much data for the buffer
    // reset the buffer
    mSysexCurOffset = 0;
}

}
[/code]


#5

awesome, thanks! :slight_smile: Very similar to what I had except, um, better :wink: Are you using the MidiOutput class to send sysex messages as well? I suppose the same rules apply. Perhaps I’ll post my “MidiManager” class when it’s done.


#6

Actually, the sending is much easier, at least in my case, I just ask the data object for it’s sysex buffer, and then I send it.

void DK10EditorJuceComponent::sendDk10Data( void ) { // I should make sure there is an open midi port int sysexLen = 0; unsigned char* sysexData = mDk10Data.getSysexData( &sysexLen, false ); MidiMessage mySysEx = MidiMessage::createSysExMessage( sysexData, sysexLen ); mAudioDeviceManager->getDefaultMidiOutput()->sendMessageNow( mySysEx ); delete [] sysexData; } [/code]