使用RtMIDI,MIDISendSysex不向虚拟端口发送任何事件

时间:2014-02-20 12:32:15

标签: c++ xcode macos midi

刚开始在Xcode中使用RtMIDI来制作一些MIDI内容。它工作正常,但遇到了绊脚石。

使用示例midiout.cpp而不修改任何内容:

  • 如果我将MIDI事件发送到现有的MIDI端口,则所有事件都会发送正常。
  • 如果我将MIDI事件发送到创建的虚拟端口,则会发送 sysex事件之外的所有事件。

查看库代码,除了sysex之外的所有MIDI事件都是使用os调用MIDIReceived发送的(在OSX上)。 Sysex事件使用MIDISendSysex发送。这是应该的。

现在,没有错误被抛出,一切正在按原样执行,MIDISendSysex调用没有失败 - 只是没有sysex事件到达目的地。他们只是消失在一个黑洞里!

是否有其他人遇到此问题或有任何帮助,建议,解决方法?

谢谢,

(Xcode 4.6.2,OSX 10.9.1,使用MIDIMonitor& MIDIPipe来监控MIDI端口上的流量,两者都显示未从midiout.cpp到达虚拟端口的sysex事件的相同结果)

好的,这是执行实际发送的sendMessage路由:



    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_ );
        }
      }

    }

1 个答案:

答案 0 :(得分:0)

跟进注释 - 这是RTMidi中的一个错误,应该在下一个版本中修复。这与以下事实有关:在CoreMIDI中,MIDISendSysex()调用不发送到虚拟端口,它只能在真实端口上工作。

我已根据CoreAdio邮件列表中此线程的建议,使用MIDIReceived()更新了RTMIDI的本地副本以处理sysex事件: http://lists.apple.com/archives/coreaudio-api/2006/Jan/msg00236.html

它现在将sysex发送到虚拟端口并按预期运行。