MIDIRetrieveMessages

From EDM2
Jump to: navigation, search

Syntax

rc = MIDIRetrieveMessages( minstance, pBuffer,
                           pulBufferLength, ulFlag );

Parameters

MINSTANCE minstance (input)
The source instance number.
PVOID pBuffer (output)
Pointer to the buffer to be filled with the compound messages.
PULONG pulBufferLength (input/output)
Length of buffer in input (must be at least "sizeof(MESSAGE)" bytes long), number of bytes written on output.
ULONG ulFlag (input)
This parameter is not currently used and must be set to 0.

Returns

ULONG rc
The following values can be returned:
0 NO_ERROR Operation was successful.
7003 MIDIERR_INTERNAL_SYSTEM Error, Either the RTMIDI timer is not running, or the RTMIDI subsystem has become corrupt, and the application should terminate immediately, cleaning up as much as possible. In latter case, rebooting will most likely be necessary to restore RTMIDI to a functional state.
7007 MIDIERR_INVALID_FLAG Error, The ulFlag value is not set to 0.
7009 MIDIERR_INVALID_INSTANCE_NUMBER Error, The instance number is invalid.
7005 MIDIERR_INVALID_CLASS_NUMBER Error, The instance number refers to an instance that is not of the Application class.
7010 MIDIERR_INVALID_PARAMETER Error, Either of the pBuffer or pulBufferLength pointers is invalid.
7014 MIDIERR_NOT_ALLOWED Error, The function is not implemented on this version of RTMIDI.

Include Info

#include <mididll.h>

Usage Explanation

MIDIRetrieveMessages is used to receive the MIDI data that is sent to the Application node specified by minstance. Compound messages sent to the Application node are stored in a queue. When MIDIRetrieveMessages is called, and the queue is not empty, the contents of the queue are copied to the pBuffer and the call returns immediately. If the queue is empty, the thread blocks until the queue becomes non-empty.

Since it is possible (and even likely) that the thread calling MIDIRetrieveMessages will be blocked, it is strongly suggested that a thread be allocated specifically for this function.

On return, pBuffer will be filled with an array of compound messages. Since the call blocks until a message arrives, pBuffer will always have at least one compound message. The number of bytes copied will never exceed pulBufferLength, even if the queue holds more, and only whole compound messages will be copied. Therefore, it is suggested that pulBufferLength be equal to a multiple of sizeof(MESSAGE).

Relevant Structures

typedef struct {
   // inst # of the instance which generated the msg
   ULONG ulSourceInstance;
   // time the message is to be (or was) sent
   ULONG ulTime;
   ULONG ulTrack;
   union {
      ULONG ulMessage;
      struct {
         // The 1st byte of the message
         BYTE bStatus;
         // the rest of the message
         BYTE abData[3];
      } bytes;
      BYTE abData[4];
   } msg;
} MESSAGE, *PMESSAGE;

Gotchas

Currently, MIDIRetrieveMessages does not support receiving of SysEx messages. Any SysEx messages which are sent to an Application node are immediately discarded. This limitation will be removed in a future release of RTMIDI.

The Warp 4 GA version of RTMIDI has a bug where if a thread is blocked in MIDIRetrieveMessages, there is no way to unblock the thread prematurely. The work-around is to create a second Application node, use MIDIAddLink.html to create a link from it to the first Application node, and then use MIDISendMessages.html to send a message to the second Application node. The message will travel along the link to the first Application node, causing this node to unblock the MIDIRetrieveMessages call. The thread can then terminate itself.

This also means that if an Application node is deleted while a thread is block in a MIDIRetrieveMessages call to it, the thread will be permanently hung and there will be no way to terminate it.

Sample Code

#include <mididll.h>

MINSTANCE miHardwareNode;
MINSTANCE miApplicationNode;
ULONG ulApplicationClass;
volatile int fRecordMIDI = TRUE;
MESSAGE msg;
ULONG ulBufferSize;

  /* Assume that miHardwareNode has been set to the Hardware node   */
  /* from which we want to record MIDI data.  Also assume that      */
  /* ulApplicationClass has been set to the class number of the     */
  /* Application class.                                             */

  /* First, we create an Application node.  Then we link the        */
  /* Hardware node to it.  Then we enable the Hardware node for     */
  /* "send".  This will cause the hardware to start sending         */
  /* incoming MIDI data to the Application node.  Then we enter a   */
  /* loop of MIDIRetrieveMessages calls.  The loop terminates when  */
  /* some thread sets fRecordMIDI to false.                         */

  /* Our pBuffer is actually variable msg, so it can only hold a    */
  /* single compound message.  This means that we'll only be        */
  /* receiving one MIDI message at a time.  This is okay for low    */
  /* throughput, but for higher rates we'll need to be able to      */
  /* receive more than one at a time.                               */

       rc = MIDICreateInstance(ulApplicationClass,
                               "My Applictaion Node",
                               &miApplicationNode, 0);

       if (rc != 0)
       {
          /* Either not enough memory to create another node,       */
          /* or there already is an node called                     */
          /* "My Application Node".                                 */
       }

       rc = MIDIAddLink(miHardwareNode, miApplicationNode, 0, 0);

       if (rc != 0)
       {
          /* We got an error to take care of. */
       }

       rc = MIDIEnableInstance(miHardwareNode, MIDI_ENABLE_SEND);

       if (rc != 0)
       {
          /* We got an error to take care of. */
       }

       while (fRecordMIDI)
       {
          ulBufferSize = sizeof(msg);

          rc = MIDIRetrieveMessages(miApplicationNode,
                                    (PVOID) &msg,
                                    &ulBufferSize, 0);

          if (rc != 0)
          {
             /* We got an error to take care of. */
          }

          /* 'msg' now contains a new message.  Process it here, or   */
          /* dispatch it to another thread.  The longer this section  */
          /* takes execute, the lower your maximum throughput will    */
          /* be.                                                      */
       }

See Also

  • MIDISendMessages
  • SendSysexMessage