The IDirectMusicPerformance::SendPMsg method sends a performance message. This method is called by tracks when they are played. It might also be called by a tool in order to inject new data into a performance.
HRESULT SendPMsg(
DMUS_PMSG* pPMSG
);
If the method succeeds, the return value is S_OK.
If it fails, the method may return one of the following error values:
DMUS_E_NO_MASTER_CLOCK |
DMUS_E_ALREADY_SENT |
E_INVALIDARG |
E_POINTER |
The dwFlags member (see DMUS_PMSG) must be set to either DMUS_PMSGF_MUSICTIME or DMUS_PMSGF_REFTIME, depending on the time stamp in either rtTime or mtTime. Also, the dwFlags member should be set to 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 is set to DMUS_PMSGF_REFTIME, it is assumed that this message is cued to go out now.
The IDirectMusicGraph::StampPMsg method should in most cases 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, you 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 will free the message after it has been processed. For more information, see the Remarks for IDirectMusicPerformance::FreePMsg.
The follow sample code shows how to allocate and send a sysex 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 we wanted the
// message to go through a segment graph, we 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 sysex data into it
DMUS_SYSEX_PMSG* pSysEx;
if ( SUCCEEDED( pPerformance->AllocPMsg(
sizeof(DMUS_SYSEX_PMSG) + m_dwSysExLength,
(DMUS_PMSG**)&pSysEx )))
{
// All fields are initialized to zero from the
// AllocPMsg method.
// Assume 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( 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 example shows a function that sends a note message associated with the track identified by dwTrackID. Note that 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.
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; // Will be 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/beat info
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;
// We'll use DMUS_PLAYMODE_PEDALPOINT as our 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 - 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;
}
Windows NT/2000: Requires Windows 2000.
Windows 95/98: Requires Windows 95 or later. Available as a redistributable for Windows 95.
Header: Declared in dmusici.h.
IDirectMusicTool::ProcessPMsg, Messages, DirectMusic Messages, DirectMusic Tools