Frage

just started using RtMIDI in Xcode to prototype up some MIDI stuff. It's working fine but hit a stumbling block.

Using the example midiout.cpp without modifying anything:

  • If I send MIDI events to an already existing MIDI port, all events are sent ok.
  • If I send MIDI events to a created virtual port, all events except sysex events are sent.

Having a look in the library code, all MIDI events except sysex are sent (on OSX) using the os call MIDIReceived. Sysex events are sent using MIDISendSysex. This is as it should be.

Now, no errors are thrown, everything is being executed as it should, the MIDISendSysex call is not failing - just that no sysex events arrive at the destination. They just disappear into a black hole!

Anybody else come across this or have any help, suggestions, workarounds?

Thanks,

(Xcode 4.6.2, OSX 10.9.1, using MIDIMonitor & MIDIPipe to monitor the traffic on MIDI ports, both show same results of sysex events not arriving on virtual ports from midiout.cpp)

Ok, here's the sendMessage routing that's doing the actual sending:



    void MidiOutCore :: sendMessage( std::vector *message )
    {
    // ------------------------------------------------------------------------
      // We use the MIDISendSysex() function to asynchronously send sysex
      // messages.  Otherwise, we use a single CoreMidi MIDIPacket.
    // ------------------------------------------------------------------------
    // error handling code removed for brevity

      MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
      CoreMidiData *data = static_cast (apiData_);
      OSStatus result;

    // ------------------------------------------------------------------------
    // IF EVENT IS SYSEX
    // ------------------------------------------------------------------------

      if ( message->at(0) == 0xF0 ) {               // sysex start byte
        while ( sysexBuffer != 0 ) usleep( 1000 );  // sleep 1 ms

       sysexBuffer = new char[nBytes];

       // Copy data to buffer.
       for ( unsigned int i=0; iat(i);

       // build sysex request
       data->sysexreq.destination = data->destinationId;        // destinaiondId is valid endpointref
       data->sysexreq.data = (Byte *)sysexBuffer;
       data->sysexreq.bytesToSend = nBytes;
       data->sysexreq.complete = 0;
       data->sysexreq.completionProc = sysexCompletionProc;
       data->sysexreq.completionRefCon = &(data->sysexreq);

       // send the data
       // this works when we are connected to a 'real' MIDI port/device, but fails on a virtual port
       // destinationId is an endpointref and valid and id is good
       // tried to use data->endpoint (also an endpointref with id) but doesn't send either
       result = MIDISendSysex( &(data->sysexreq) );
       return;
      }

    // ------------------------------------------------------------------------
    // IF EVENT IS NOT SYSEX
    // ------------------------------------------------------------------------

      MIDIPacketList packetList;
      MIDIPacket *packet = MIDIPacketListInit( &packetList );
      packet = MIDIPacketListAdd( &packetList, sizeof(packetList), packet, timeStamp, nBytes, (const Byte *) &message->at( 0 ) );

      // Send to any destinations that may have connected to us.
      // this sends to virtual MIDI ports
      if ( data->endpoint ) {
        result = MIDIReceived( data->endpoint, &packetList );
        if ( result != noErr ) {
          errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
          RtMidi::error( RtError::WARNING, errorString_ );
        }
      }

      // And send to an explicit destination port if we're connected.
      // this sends to regular real MIDI devices we are connected to, not virtual ports
      if ( connected_ ) {
        result = MIDISend( data->port, data->destinationId, &packetList );
        if ( result != noErr ) {
          errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
          RtMidi::error( RtError::WARNING, errorString_ );
        }
      }

    }

War es hilfreich?

Lösung

Follow up note - this was a bug in RTMidi which should be fixed in the next version. It's related to the fact that in CoreMIDI, the MIDISendSysex() call does not send to virtual ports, it will work on real ports only.

I have updated my local copy of RTMIDI to handle sysex events using MIDIReceived() as recommended by this thread on the CoreAdio mailing list: http://lists.apple.com/archives/coreaudio-api/2006/Jan/msg00236.html

It now sends sysex to virtual ports and behaves as expected.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top