DirectX SDK |
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 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 can 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 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. DMUS_SYSEX_PMSG* pSysEx; 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( 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(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; // 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. 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; }
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