代码之家  ›  专栏  ›  技术社区  ›  beely

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

  •  1
  • beely  · 技术社区  · 10 年前

    刚刚开始在Xcode中使用RtMIDI来制作一些MIDI素材的原型。它运行良好,但遇到了障碍。

    在不修改任何内容的情况下使用示例midiout.cpp:

    • 如果我将MIDI事件发送到已经存在的MIDI端口,则所有事件都发送正常。
    • 如果我将MIDI事件发送到创建的虚拟端口,则所有事件 除了 发送sysex事件。

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

    现在,没有抛出错误,一切都在按应有的方式执行,MIDISendSysex调用没有失败-只是没有sysex事件到达目标。他们消失在一个黑洞里!

    还有人遇到这个问题或有任何帮助、建议或变通办法吗?

    谢谢

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

    好的,这是实际发送的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 回复  |  直到 10 年前
        1
  •  1
  •   beely    10 年前

    后续说明-这是RTMidi中的一个bug,应该在下一个版本中修复。这与以下事实有关:在CoreMDI中,MIDISendSysex()调用不会发送到虚拟端口,它只能在实际端口上工作。

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

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