This 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.



Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the following error values:



The dwFlags member (see DMUS_PMSG) must contain either DMUS_PMSGF_MUSICTIME or DMUS_PMSGF_REFTIME, depending on the time stamp in either 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 IDirectMusicGraph::StampPMsg method should be called on the message before SendPMsg is called. However, when sending a message directly to the main output tool, this step can be skipped. If you want the message to pass only through the performance graph, obtain the IDirectMusicGraph interface by calling IDirectMusicPerformance::QueryInterface. Otherwise, obtain it by calling IDirectMusicSegment::QueryInterface. Do not attempt to obtain the interface by calling IDirectMusicPerformance::GetGraph or IDirectMusicSegment::GetGraph; these methods return a pointer to the graph object, rather than to the implementation of the IDirectMusicGraph interface on the performance or segment.

Normally, the performance frees the message after it has been processed. For more information, see the Remarks for IDirectMusicPerformance::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 IDirectMusicPerformance
   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.
    if ( SUCCEEDED( pPerformance->AllocPMsg(
            sizeof(DMUS_SYSEX_PMSG) + m_dwSysExLength,
            (DMUS_PMSG**)&pSysEx )))
        // All fields are initialized to 0 from the 
        // AllocPMsg method.
        // Assume that m_pbSysExData is a pointer to an array 
        // containing data of length m_dwSysExLength.
        memcpy( pSysEx->abData, m_pbSysExData, m_dwSysExLength );
        pSysEx->dwSize = sizeof(DMUS_SYSEX_PMSG);
        pSysEx->dwLen = dwSysExLength;
        pSysEx->mtTime = mtTime;
        pSysEx->dwFlags = DMUS_PMSGF_MUSICTIME;
        pSysEx->dwType = DMUS_PMSGT_SYSEX;
        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(
            (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 );

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(IDirectMusicPerformance* pPerformance,
        MUSIC_TIME mtTime, DWORD dwTrackID) 
    // Allocate a Note PMessage.
    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;           // For DirectX 6.1, 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.
    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.
    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.
    // Fill in the fields specific to DMUS_NOTE_PMSG.
    pNote->wMusicValue = wMusicValue;
    hr = pPerformance->MusicToMIDI(
    if (FAILED(hr)) return hr;
    hr = pPerformance->TimeToRhythm(
    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;               // Do not 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 );

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


OS Versions: Windows CE .NET 4.0 and Windows CE .NET 4.1.
Header: Dmusici.h.
Link Library: Dmusic.lib.

See Also

Messages | DirectMusic Messages | DirectMusic Tools | IDirectMusicGraph | IDirectMusicGraph::StampPMsg | IDirectMusicPerformance::AllocPMsg | IDirectMusicPerformance::FreePMsg | IDirectMusicPerformance::GetGraph | IDirectMusicSegment::GetGraph | IDirectMusicTool::ProcessPMsg | DMUS_PMSG

 Last updated on Monday, April 12, 2004

© 1992-2002 Microsoft Corporation. All rights reserved.