Microsoft DirectX 8.1 (C++)

IDirectMusicPerformance8::SendPMsg

The SendPMsg method sends a performance message. This method is called by tracks when they are played. It might also be called by a tool to inject new data into a performance.

Syntax

HRESULT SendPMsg(
  DMUS_PMSG* pPMSG
);

Parameters

pPMSG

Message allocated by IDirectMusicPerformance8::AllocPMsg.  This structure is of a type derived from DMUS_PMSG.

Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in the following table.

Return code
DMUS_E_NO_MASTER_CLOCK
DMUS_E_ALREADY_SENT
E_INVALIDARG
E_POINTER

Remarks

The dwFlags member (see DMUS_PMSG) must contain either DMUS_PMSGF_MUSICTIME or DMUS_PMSGF_REFTIME, depending on whether the time stamp is in rtTime or mtTime. The dwFlags member should also contain the appropriate delivery type—DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGF_TOOL_ATTIME, or DMUS_PMSGF_TOOL_IMMEDIATE—depending on the type of message. If none is selected, DMUS_PMSGF_TOOL_IMMEDIATE is used by default.

If the time of the message is set to 0 and the dwFlags member contains DMUS_PMSGF_REFTIME, it is assumed that this message is cued to go out immediately.

In most cases, the IDirectMusicGraph8::StampPMsg method should be called on the message before SendPMsg is called. If the message is not stamped, it is not delivered to any tools implemented by the application, and might not play on the correct performance channel. If you want the message to pass only through the performance toolgraph, obtain the IDirectMusicGraph8 interface by calling IDirectMusicPerformance8::QueryInterface. Otherwise, obtain it by calling IDirectMusicSegment8::QueryInterface. Do not attempt to obtain the interface by calling IDirectMusicPerformance8::GetGraph or IDirectMusicSegment8::GetGraph; these methods return a pointer to the graph object, rather than to the implementation of the IDirectMusicGraph8 interface on the performance or segment.

Normally, the performance frees the message after it has been processed. For more information, see the Remarks for IDirectMusicPerformance8::FreePMsg.

The follow code example shows how to allocate and send a system exclusive message and a tempo message.

// Assume that pPerformance is a valid IDirectMusicPerformance8
// pointer and that mtTime is an initialized MUSIC_TIME 
// variable.
 
IDirectMusicGraph* pGraph;
 
// Get the graph pointer from the performance. If you wanted the 
// message to go through a segment graph, you would 
// QueryInterface a segment object instead. 
 
if ( SUCCEEDED( pPerformance->QueryInterface( 
    IID_IDirectMusicGraph, (void**)&pGraph )))
{
  // Allocate a DMUS_SYSEX_PMSG of the appropriate size,
  // and read the system exclusive data into it.
 
  DMUS_SYSEX_PMSG* pSysEx;
 
  if ( SUCCEEDED( pPerformance->AllocPMsg( 
    sizeof(DMUS_SYSEX_PMSG) + m_dwSysExLength,
    (DMUS_PMSG**)&pSysEx )))
  {
    ZeroMemory(pSysEx, sizeof(DMUS_NOTE_PMSG));
    pSysEx->dwSize = sizeof(DMUS_SYSEX_PMSG);
    pSysEx->dwLen = dwSysExLength;
    pSysEx->mtTime = mtTime;
    pSysEx->dwFlags = DMUS_PMSGF_MUSICTIME;
    pSysEx->dwType = DMUS_PMSGT_SYSEX;
 
    // Assume that m_pbSysExData is a pointer to an array 
    // containing data of length m_dwSysExLength.
 
    memcpy( pSysEx->abData, m_pbSysExData, m_dwSysExLength );
 
    pGraph->StampPMsg( (DMUS_PMSG*)pSysEx );
    if (FAILED(pPerformance->SendPMsg( (DMUS_PMSG*)pSysEx )))
    {
    pPerformance->FreePMsg( (DMUS_PMSG*)pSysEx );
    }
  }
 
  // Change the tempo at time mtTime to 120 bpm.
 
  DMUS_TEMPO_PMSG* pTempo;
 
  if( SUCCEEDED( pPerformance->AllocPMsg(
    sizeof(DMUS_TEMPO_PMSG),
    (DMUS_PMSG**)&pTempo )))
  {
    pTempo->dwSize = sizeof(DMUS_TEMPO_PMSG);
    pTempo->dblTempo = 120;
    pTempo->mtTime = mtTime;
    pTempo->dwFlags = DMUS_PMSGF_MUSICTIME;
    pTempo->dwType = DMUS_PMSGT_TEMPO;
    pGraph->StampPMsg( (DMUS_PMSG*)pTempo );
    if (FAILED(pPerformance->SendPMsg( (DMUS_PMSG*)pTempo )))
    {
    pPerformance->FreePMsg( (DMUS_PMSG*)pTempo );
    }
  }
 
  pGraph->Release();
}

The next code example shows a function that sends a note message associated with the track identified by dwTrackID. The virtual track ID should be 0 if the message is not being generated from a DirectMusicTrack object.

HRESULT CreateNotePMsg(IDirectMusicPerformance8* pPerformance,
    MUSIC_TIME mtTime, DWORD dwTrackID) 
{
 
  // Allocate a Note PMessage.
  DMUS_NOTE_PMSG* pNote = NULL;
  HRESULT hr = pPerformance->AllocPMsg( sizeof(DMUS_NOTE_PMSG),
    (DMUS_PMSG**) &pNote);
  if (FAILED(hr)) return hr;
 
  pNote->dwSize = sizeof(DMUS_NOTE_PMSG); // Size of a Note Pmessage.
  pNote->rtTime = 0;        // Ignored.
  pNote->mtTime = mtTime;       // When to play the note.
  pNote->dwFlags = DMUS_PMSGF_MUSICTIME;  // Use the mtTime field.
  pNote->dwPChannel = 5;      // Play on PChannel 5.
  pNote->dwVirtualTrackID = dwTrackID;  // Track ID from parameter.
 
  // The following two fields should be set to NULL when a 
  // message is initially sent. They will be updated in
  // IDirectMusicGraph::StampPMsg.
  pNote->pTool = NULL; 
  pNote->pGraph = NULL;
  pNote->dwType = DMUS_PMSGT_NOTE; 
  pNote->dwVoiceID = 0;     // Always 0
  pNote->dwGroupID = 0xFFFFFFFF;  // All track groups
  pNote->punkUser = NULL;   // Always NULL
 
  // Get the current time signature from the performance
  // to compute measure and beat information.
  DMUS_TIMESIGNATURE TimeSig;
  MUSIC_TIME mtNext;
  hr = pPerformance->GetParam(GUID_TimeSignature, 0xFFFFFFFF, 
    0, mtTime, &mtNext, &TimeSig);
  if (FAILED(hr)) return hr;
 
  // Recompute TimeSig.mtTime to have the value expected 
  // by pPerformance->TimeToRhythm.
  TimeSig.mtTime += mtTime;
 
  // Get the current chord from the performance 
  // to create a note value.
  DMUS_CHORD_KEY Chord;
  hr = pPerformance->GetParam(GUID_ChordParam, 0xFFFFFFFF, 0, 
    mtTime, &mtNext, &Chord);
  if (FAILED(hr)) return hr;
 
  // Create a note with octave 5, chord tone 2 (fifth), scale 
  // offset 1 (=> sixth), and no accidentals.
  WORD wMusicValue = 0x5210;
 
  // Use DMUS_PLAYMODE_PEDALPOINT as your play mode
  // in pPerformance->MusicToMIDI.
  BYTE bPlayModeFlags = DMUS_PLAYMODE_PEDALPOINT;
 
  // Fill in the fields specific to DMUS_NOTE_PMSG.
  pNote->wMusicValue = wMusicValue; 
  hr = pPerformance->MusicToMIDI(
    wMusicValue,
    &Chord,
    bPlayModeFlags,
    0,
    &(pNote->bMidiValue));
  if (FAILED(hr)) return hr;
 
  hr = pPerformance->TimeToRhythm(
    TimeSig.mtTime,
    &TimeSig,
    &(pNote->wMeasure),
    &(pNote->bBeat),
    &(pNote->bGrid),
    &(pNote->nOffset));
  if (FAILED(hr)) return hr;
 
  pNote->mtDuration = DMUS_PPQ;   // Quarter note duration.
  pNote->bVelocity = 120;     // MIDI velocity (0 to 127).
  pNote->bFlags = DMUS_NOTEF_NOTEON;  // Always set to this value.
  pNote->bTimeRange = 250;    // Randomize start time a lot.
  pNote->bDurRange = 5;     // Randomize duration a little.
  pNote->bVelRange = 0;     // Don't randomize velocity.
  pNote->bPlayModeFlags = bPlayModeFlags; 
  pNote->bSubChordLevel = 0;    // Note uses subchord level 0.
  pNote->cTranspose = 0;      // No transposition.
 
  // Stamp the message with the performance graph.
  IDirectMusicGraph* pGraph;
  hr = pPerformance->QueryInterface( IID_IDirectMusicGraph,
    (void**)&pGraph );
  if (FAILED(hr)) return hr;
 
  pGraph->StampPMsg( (DMUS_PMSG*)pNote );
  pGraph->Release();

  // Finally, send the message.
  hr = pPerformance->SendPMsg( (DMUS_PMSG*)pNote);
  if (FAILED(hr))
  {
    pPerformance->FreePMsg( (DMUS_PMSG*)pNote);
    return hr;
  }
  return S_OK;
}

Requirements

  Header: Declared in dmusici.h.

See Also