|
|
// Copyright (c) 1998-1999 Microsoft Corporation
// READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
//
// We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
// sources).
//
// The one place we use exceptions is around construction of objects that call
// InitializeCriticalSection. We guarantee that it is safe to use in this case with
// the restriction given by not using -GX (automatic objects in the call chain between
// throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
// size because of the unwind code.
//
// Any other use of exceptions must follow these restrictions or -GX must be turned on.
//
// READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
#pragma warning(disable:4530)
// TimeSigTrk.cpp : Implementation of CTimeSigTrack
#include "dmime.h"
#include "TSigTrk.h"
#include "dmusici.h"
#include "dmusicf.h"
#include "debug.h"
#include "..\shared\dmstrm.h"
#include "..\shared\Validate.h"
#include "debug.h"
#define ASSERT assert
CTimeSigItem::CTimeSigItem()
{ m_TimeSig.lTime = 0; m_TimeSig.bBeatsPerMeasure = 0; m_TimeSig.bBeat = 0; m_TimeSig.wGridsPerBeat = 0; }
/////////////////////////////////////////////////////////////////////////////
// CTimeSigTrack
void CTimeSigTrack::Construct() { InterlockedIncrement(&g_cComponent);
m_cRef = 1; m_fCSInitialized = FALSE; InitializeCriticalSection(&m_CrSec); m_fCSInitialized = TRUE; m_dwValidate = 0; m_fNotificationMeasureBeat = FALSE; }
CTimeSigTrack::CTimeSigTrack() { Construct(); m_fActive = TRUE; m_fStateSetBySetParam = FALSE; }
CTimeSigTrack::CTimeSigTrack( CTimeSigTrack *pSourceTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd) { Construct(); m_fActive = pSourceTrack->m_fActive; m_fStateSetBySetParam = pSourceTrack->m_fStateSetBySetParam; // Clone the time signature list.
CTimeSigItem* pScan = pSourceTrack->m_TSigEventList.GetHead(); CTimeSigItem* pPrevious = NULL; for(; pScan; pScan = pScan->GetNext()) { if (pScan->m_TimeSig.lTime < mtStart) { pPrevious = pScan; } else if (pScan->m_TimeSig.lTime < mtEnd) { if (pScan->m_TimeSig.lTime == mtStart) { pPrevious = NULL; } CTimeSigItem* pNew = new CTimeSigItem; if (pNew) { pNew->m_TimeSig = pScan->m_TimeSig; pNew->m_TimeSig.lTime = pScan->m_TimeSig.lTime - mtStart; m_TSigEventList.AddHead(pNew); // instead of AddTail, which is n^2. We reverse below.
} } else break; } m_TSigEventList.Reverse(); // Now, put list in order.
// Then, install the time signature that precedes the clone.
if (pPrevious) { CTimeSigItem* pNew = new CTimeSigItem; if (pNew) { pNew->m_TimeSig = pPrevious->m_TimeSig; pNew->m_TimeSig.lTime = 0; m_TSigEventList.AddHead(pNew); } } }
void CTimeSigTrack::Clear()
{ CTimeSigItem* pItem; while( pItem = m_TSigEventList.RemoveHead() ) { delete pItem; } }
CTimeSigTrack::~CTimeSigTrack() { Clear(); if (m_fCSInitialized) { DeleteCriticalSection(&m_CrSec); } InterlockedDecrement(&g_cComponent); }
// @method:(EXTERNAL) HRESULT | IDirectMusicTimeSigTrack | QueryInterface | Standard QueryInterface implementation for <i IDirectMusicTimeSigTrack>
//
// @parm const IID & | iid | Interface to query for
// @parm void ** | ppv | The requested interface will be returned here
//
// @rdesc Returns one of the following:
//
// @flag S_OK | If the interface is supported and was returned
// @flag E_NOINTERFACE | If the object does not support the given interface.
//
// @mfunc:(INTERNAL)
//
//
STDMETHODIMP CTimeSigTrack::QueryInterface( const IID &iid, // @parm Interface to query for
void **ppv) // @parm The requested interface will be returned here
{ V_INAME(CTimeSigTrack::QueryInterface); V_PTRPTR_WRITE(ppv); V_REFGUID(iid);
if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack) { *ppv = static_cast<IDirectMusicTrack*>(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast<IPersistStream*>(this); } else { *ppv = NULL; Trace(4,"Warning: Request to query unknown interface on Time Signature Track\n"); return E_NOINTERFACE; }
reinterpret_cast<IUnknown*>(this)->AddRef(); return S_OK; }
// @method:(EXTERNAL) HRESULT | IDirectMusicTimeSigTrack | AddRef | Standard AddRef implementation for <i IDirectMusicTimeSigTrack>
//
// @rdesc Returns the new reference count for this object.
//
// @mfunc:(INTERNAL)
//
//
STDMETHODIMP_(ULONG) CTimeSigTrack::AddRef() { return InterlockedIncrement(&m_cRef); }
// @method:(EXTERNAL) HRESULT | IDirectMusicTimeSigTrack | Release | Standard Release implementation for <i IDirectMusicTimeSigTrack>
//
// @rdesc Returns the new reference count for this object.
//
// @mfunc:(INTERNAL)
//
//
STDMETHODIMP_(ULONG) CTimeSigTrack::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; }
return m_cRef; }
/////////////////////////////////////////////////////////////////////////////
// IPersist
HRESULT CTimeSigTrack::GetClassID( CLSID* pClassID ) { V_INAME(CTimeSigTrack::GetClassID); V_PTR_WRITE(pClassID, CLSID); *pClassID = CLSID_DirectMusicTimeSigTrack; return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// IPersistStream functions
HRESULT CTimeSigTrack::IsDirty() { return S_FALSE; }
/*
@method HRESULT | ITimeSigTrack | Load | Call this with an IStream filled with DMUS_IO_TIMESIGNATURE_ITEM's, sorted in time order. @parm IStream* | pIStream | A stream of DMUS_IO_TIMESIGNATURE_ITEM's, sorted in time order. The seek pointer should be set to the first event. The stream should only contain TimeSig events and nothing more. @rvalue E_INVALIDARG | If pIStream == NULL @rvalue S_OK @comm The <p pIStream> will be AddRef'd inside this function and held until the TimeSigTrack is released. */
HRESULT CTimeSigTrack::Load( IStream* pIStream ) { V_INAME(CTimeSigTrack::Load); V_INTERFACE(pIStream);
CRiffParser Parser(pIStream); EnterCriticalSection(&m_CrSec); m_dwValidate++; // used to validate state data that's out there
RIFFIO ckMain;
HRESULT hr = S_OK;
Parser.EnterList(&ckMain); if (Parser.NextChunk(&hr)) { if (ckMain.ckid == DMUS_FOURCC_TIMESIG_CHUNK) { hr = LoadTimeSigList(&Parser,ckMain.cksize); } else if ((ckMain.ckid == FOURCC_LIST) && (ckMain.fccType == DMUS_FOURCC_TIMESIGTRACK_LIST)) { Clear(); RIFFIO ckNext; // Descends into the children chunks.
Parser.EnterList(&ckNext); while (Parser.NextChunk(&hr)) { switch(ckNext.ckid) { case DMUS_FOURCC_TIMESIG_CHUNK : hr = LoadTimeSigList(&Parser,ckNext.cksize); break; } } Parser.LeaveList(); } else { Trace(1,"Error: Failure reading bad data in time signature track.\n"); hr = DMUS_E_CHUNKNOTFOUND; } }
LeaveCriticalSection(&m_CrSec); return hr; }
HRESULT CTimeSigTrack::LoadTimeSigList( CRiffParser *pParser, long lChunkSize ) { HRESULT hr;
// copy contents of the stream into the list.
DWORD dwSubSize; // read in the size of the data structures
hr = pParser->Read( &dwSubSize, sizeof(DWORD)); if (SUCCEEDED(hr)) { lChunkSize -= sizeof(DWORD);
DWORD dwRead, dwSeek; if( dwSubSize > sizeof(DMUS_IO_TIMESIGNATURE_ITEM) ) { dwRead = sizeof(DMUS_IO_TIMESIGNATURE_ITEM); dwSeek = dwSubSize - dwRead; } else { dwRead = dwSubSize; dwSeek = 0; } if( 0 == dwRead ) { Trace(1,"Error: Failure reading time signature track.\n"); hr = DMUS_E_CANNOTREAD; } else { while( lChunkSize > 0 ) { CTimeSigItem *pNew = new CTimeSigItem; if (pNew) { if( FAILED( pParser->Read( &pNew->m_TimeSig, dwRead ))) { delete pNew; hr = DMUS_E_CANNOTREAD; break; } // make sure this time sig is OK
if (!pNew->m_TimeSig.bBeatsPerMeasure) { Trace(1, "Warning: invalid content: DMUS_IO_TIMESIGNATURE_ITEM.bBeatsPerMeasure\n"); pNew->m_TimeSig.bBeatsPerMeasure = 4; } if (!pNew->m_TimeSig.bBeat) { Trace(1, "Warning: invalid content: DMUS_IO_TIMESIGNATURE_ITEM.bBeat\n"); pNew->m_TimeSig.bBeat = 4; } if (!pNew->m_TimeSig.wGridsPerBeat) { Trace(1, "Warning: invalid content: DMUS_IO_TIMESIGNATURE_ITEM.wGridsPerBeat\n"); pNew->m_TimeSig.wGridsPerBeat = 4; } m_TSigEventList.AddHead(pNew); lChunkSize -= dwRead; if( dwSeek ) { if( FAILED( pParser->Skip(dwSeek))) { hr = DMUS_E_CANNOTSEEK; break; } lChunkSize -= dwSeek; } } } m_TSigEventList.Reverse(); // If there is no time signature at the start, make a copy of the
// first time signature and stick it there. This resolves a bug in 6.1
// where notification messages and GetParam() were inconsistent
// in their behavior under this circumstance. This ensures they behave
// the same.
CTimeSigItem *pTop = m_TSigEventList.GetHead(); if (pTop && (pTop->m_TimeSig.lTime > 0)) { CTimeSigItem *pCopy = new CTimeSigItem; if (pCopy) { *pCopy = *pTop; pCopy->m_TimeSig.lTime = 0; m_TSigEventList.AddHead(pCopy); } } } } return hr; }
HRESULT CTimeSigTrack::Save( IStream* pIStream, BOOL fClearDirty ) { return E_NOTIMPL; }
HRESULT CTimeSigTrack::GetSizeMax( ULARGE_INTEGER FAR* pcbSize ) { return E_NOTIMPL; }
// IDirectMusicTrack
HRESULT STDMETHODCALLTYPE CTimeSigTrack::IsParamSupported( /* [in] */ REFGUID rguid) { V_INAME(CTimeSigTrack::IsParamSupported); V_REFGUID(rguid);
if (m_fStateSetBySetParam) { if( m_fActive ) { if( rguid == GUID_DisableTimeSig ) return S_OK; if( rguid == GUID_TimeSignature ) return S_OK; if( rguid == GUID_EnableTimeSig ) return DMUS_E_TYPE_DISABLED; } else { if( rguid == GUID_EnableTimeSig ) return S_OK; if( rguid == GUID_DisableTimeSig ) return DMUS_E_TYPE_DISABLED; if( rguid == GUID_TimeSignature ) return DMUS_E_TYPE_DISABLED; } } else { if(( rguid == GUID_DisableTimeSig ) || ( rguid == GUID_TimeSignature ) || ( rguid == GUID_EnableTimeSig )) return S_OK; } return DMUS_E_TYPE_UNSUPPORTED; }
//////////////////////////////////////////////////////////////////////
// IDirectMusicTrack::Init
HRESULT CTimeSigTrack::Init( /* [in] */ IDirectMusicSegment *pSegment) { return S_OK; }
HRESULT CTimeSigTrack::InitPlay( /* [in] */ IDirectMusicSegmentState *pSegmentState, /* [in] */ IDirectMusicPerformance *pPerformance, /* [out] */ void **ppStateData, /* [in] */ DWORD dwTrackID, /* [in] */ DWORD dwFlags) { V_INAME(IDirectMusicTrack::InitPlay); V_PTRPTR_WRITE(ppStateData); V_INTERFACE(pSegmentState); V_INTERFACE(pPerformance);
EnterCriticalSection(&m_CrSec); CTimeSigStateData* pStateData; pStateData = new CTimeSigStateData; if( NULL == pStateData ) return E_OUTOFMEMORY; *ppStateData = pStateData; if (m_fStateSetBySetParam) { pStateData->m_fActive = m_fActive; } else { pStateData->m_fActive = !(dwFlags & (DMUS_SEGF_CONTROL | DMUS_SEGF_SECONDARY)); } pStateData->m_dwVirtualTrackID = dwTrackID; pStateData->m_pPerformance = pPerformance; // weak reference, no addref.
pStateData->m_pSegState = pSegmentState; // weak reference, no addref.
pStateData->m_pCurrentTSig = m_TSigEventList.GetHead(); pStateData->m_dwValidate = m_dwValidate; LeaveCriticalSection(&m_CrSec); return S_OK; }
HRESULT CTimeSigTrack::EndPlay( /* [in] */ void *pStateData) { ASSERT( pStateData ); if( pStateData ) { V_INAME(CTimeSigTrack::EndPlay); V_BUFPTR_WRITE(pStateData, sizeof(CTimeSigStateData)); CTimeSigStateData* pSD = (CTimeSigStateData*)pStateData; delete pSD; } return S_OK; }
HRESULT CTimeSigTrack::Play( /* [in] */ void *pStateData, /* [in] */ MUSIC_TIME mtStart, /* [in] */ MUSIC_TIME mtEnd, /* [in] */ MUSIC_TIME mtOffset, DWORD dwFlags, IDirectMusicPerformance* pPerf, IDirectMusicSegmentState* pSegSt, DWORD dwVirtualID ) { V_INAME(IDirectMusicTrack::Play); V_BUFPTR_WRITE( pStateData, sizeof(CTimeSigStateData)); V_INTERFACE(pPerf); V_INTERFACE(pSegSt);
EnterCriticalSection(&m_CrSec); HRESULT hr = S_OK; IDirectMusicGraph* pGraph = NULL; DMUS_TIMESIG_PMSG* pTimeSig; CTimeSigStateData* pSD = (CTimeSigStateData*)pStateData; MUSIC_TIME mtNotification = mtStart; BOOL fSeek = (dwFlags & DMUS_TRACKF_SEEK) ? TRUE : FALSE;
// if mtStart is 0 and dwFlags contains DMUS_TRACKF_START, we want to be sure to
// send out any negative time events. So, we'll set mtStart to -768.
if( (mtStart == 0) && ( dwFlags & DMUS_TRACKF_START )) { mtStart = -768; }
if( pSD->m_dwValidate != m_dwValidate ) { pSD->m_dwValidate = m_dwValidate; pSD->m_pCurrentTSig = NULL; } // if the previous end time isn't the same as the current start time,
// we need to seek to the right position.
if( fSeek || ( pSD->m_mtPrevEnd != mtStart )) { if( dwFlags & (DMUS_TRACKF_START | DMUS_TRACKF_LOOP) ) { Seek( pStateData, mtStart, TRUE ); } else { Seek( pStateData, mtStart, FALSE ); } } pSD->m_mtPrevEnd = mtEnd;
if( NULL == pSD->m_pCurrentTSig ) { pSD->m_pCurrentTSig = m_TSigEventList.GetHead(); }
if( FAILED( pSD->m_pSegState->QueryInterface( IID_IDirectMusicGraph, (void**)&pGraph ))) { pGraph = NULL; }
for( ; pSD->m_pCurrentTSig; pSD->m_pCurrentTSig = pSD->m_pCurrentTSig->GetNext() ) { DMUS_IO_TIMESIGNATURE_ITEM *pItem = &pSD->m_pCurrentTSig->m_TimeSig; if( pItem->lTime >= mtEnd ) { break; } if( (pItem->lTime < mtStart) && !fSeek ) { break; } if( pSD->m_fActive && !(dwFlags & DMUS_TRACKF_PLAY_OFF) && SUCCEEDED( pSD->m_pPerformance->AllocPMsg( sizeof(DMUS_TIMESIG_PMSG), (DMUS_PMSG**)&pTimeSig ))) { if( pItem->lTime < mtStart ) { // this only happens in the case where we've puposefully seeked
// and need to time stamp this event with the start time
pTimeSig->mtTime = mtStart + mtOffset; } else { pTimeSig->mtTime = pItem->lTime + mtOffset; } pTimeSig->bBeatsPerMeasure = pItem->bBeatsPerMeasure; pTimeSig->bBeat = pItem->bBeat; pTimeSig->wGridsPerBeat = pItem->wGridsPerBeat; pTimeSig->dwFlags |= DMUS_PMSGF_MUSICTIME; pTimeSig->dwVirtualTrackID = pSD->m_dwVirtualTrackID; pTimeSig->dwType = DMUS_PMSGT_TIMESIG; pTimeSig->dwGroupID = 0xffffffff;
if( pGraph ) { pGraph->StampPMsg( (DMUS_PMSG*)pTimeSig ); } TraceI(3, "TimeSigtrk: TimeSig event\n"); if(FAILED(pSD->m_pPerformance->SendPMsg( (DMUS_PMSG*)pTimeSig ))) { pSD->m_pPerformance->FreePMsg( (DMUS_PMSG*)pTimeSig ); } } if( pSD->m_fActive && m_fNotificationMeasureBeat && !(dwFlags & DMUS_TRACKF_NOTIFY_OFF)) { // create beat and measure notifications for up to this time
if (mtNotification < pItem->lTime) { mtNotification = NotificationMeasureBeat( mtNotification, pItem->lTime, pSD, mtOffset ); } } // set the state data to the new beat and beats per measure, and time
pSD->m_bBeat = pItem->bBeat; pSD->m_bBeatsPerMeasure = pItem->bBeatsPerMeasure; pSD->m_mtTimeSig = pItem->lTime; } if( pSD->m_fActive && m_fNotificationMeasureBeat && ( mtNotification < mtEnd ) && !(dwFlags & DMUS_TRACKF_NOTIFY_OFF)) { NotificationMeasureBeat( mtNotification, mtEnd, pSD, mtOffset ); } if( pGraph ) { pGraph->Release(); }
LeaveCriticalSection(&m_CrSec); return hr; }
// seeks to the time sig. just before mtTime.
HRESULT CTimeSigTrack::Seek( /* [in] */ void *pStateData, /* [in] */ MUSIC_TIME mtTime, BOOL fGetPrevious) { CTimeSigStateData* pSD = (CTimeSigStateData*)pStateData;
if( m_TSigEventList.IsEmpty() ) { return S_FALSE; } if( NULL == pSD->m_pCurrentTSig ) { pSD->m_pCurrentTSig = m_TSigEventList.GetHead(); } // if the current event's time is on or past mtTime, we need to rewind to the beginning
if( pSD->m_pCurrentTSig->m_TimeSig.lTime >= mtTime ) { pSD->m_pCurrentTSig = m_TSigEventList.GetHead(); } // now start seeking until we find an event with time on or past mtTime
CTimeSigItem* pTSig; for( pTSig = pSD->m_pCurrentTSig; pTSig ; pTSig = pTSig->GetNext() ) { if( pTSig->m_TimeSig.lTime >= mtTime ) { break; } pSD->m_pCurrentTSig = pTSig; } if( !fGetPrevious && pSD->m_pCurrentTSig ) { pSD->m_pCurrentTSig = pSD->m_pCurrentTSig->GetNext(); } return S_OK; }
HRESULT CTimeSigTrack::GetParam( REFGUID rguid, MUSIC_TIME mtTime, MUSIC_TIME* pmtNext, void *pData) { V_INAME(CTimeSigTrack::GetParam); V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME); V_REFGUID(rguid);
HRESULT hr = DMUS_E_GET_UNSUPPORTED; EnterCriticalSection(&m_CrSec); if( NULL == pData ) { hr = E_POINTER; } else if( GUID_TimeSignature == rguid ) { if( !m_fActive ) { hr = DMUS_E_TYPE_DISABLED; } else { DMUS_TIMESIGNATURE* pTSigData = (DMUS_TIMESIGNATURE*)pData; CTimeSigItem* pScan = m_TSigEventList.GetHead(); CTimeSigItem* pPrevious = pScan; if (pScan) { for (; pScan; pScan = pScan->GetNext()) { if (pScan->m_TimeSig.lTime > mtTime) { break; } pPrevious = pScan; } pTSigData->mtTime = pPrevious->m_TimeSig.lTime - mtTime; pTSigData->bBeatsPerMeasure = pPrevious->m_TimeSig.bBeatsPerMeasure; pTSigData->bBeat = pPrevious->m_TimeSig.bBeat; pTSigData->wGridsPerBeat = pPrevious->m_TimeSig.wGridsPerBeat; if (pmtNext) { *pmtNext = 0; } if (pScan) { if (pmtNext) { *pmtNext = pScan->m_TimeSig.lTime - mtTime; } } hr = S_OK; } else { hr = DMUS_E_NOT_FOUND; } } } LeaveCriticalSection(&m_CrSec); return hr; }
HRESULT CTimeSigTrack::SetParam( REFGUID rguid, MUSIC_TIME mtTime, void *pData) { V_INAME(CTimeSigTrack::SetParam); V_REFGUID(rguid);
HRESULT hr = DMUS_E_SET_UNSUPPORTED;
if( rguid == GUID_EnableTimeSig ) { if (m_fStateSetBySetParam && m_fActive) { // Already been enabled.
hr = DMUS_E_TYPE_DISABLED; } else { m_fStateSetBySetParam = TRUE; m_fActive = TRUE; hr = S_OK; } } else if( rguid == GUID_DisableTimeSig ) { if (m_fStateSetBySetParam && !m_fActive) { // Already been disabled.
hr = DMUS_E_TYPE_DISABLED; } else { m_fStateSetBySetParam = TRUE; m_fActive = FALSE; hr = S_OK; } } return hr; }
HRESULT STDMETHODCALLTYPE CTimeSigTrack::AddNotificationType( /* [in] */ REFGUID rguidNotification) { V_INAME(IDirectMusicTrack::AddNotificationType); V_REFGUID(rguidNotification);
HRESULT hr = S_FALSE;
if( rguidNotification == GUID_NOTIFICATION_MEASUREANDBEAT ) { m_fNotificationMeasureBeat = TRUE; hr = S_OK; } return hr; }
HRESULT STDMETHODCALLTYPE CTimeSigTrack::RemoveNotificationType( /* [in] */ REFGUID rguidNotification) { V_INAME(IDirectMusicTrack::RemoveNotificationType); V_REFGUID(rguidNotification);
HRESULT hr = S_FALSE;
if( rguidNotification == GUID_NOTIFICATION_MEASUREANDBEAT ) { m_fNotificationMeasureBeat = FALSE; hr = S_OK; } return hr; }
// send measure and beat notifications
MUSIC_TIME CTimeSigTrack::NotificationMeasureBeat( MUSIC_TIME mtStart, MUSIC_TIME mtEnd, CTimeSigStateData* pSD, MUSIC_TIME mtOffset ) { DMUS_NOTIFICATION_PMSG* pEvent = NULL; MUSIC_TIME mtTime; DWORD dwMeasure; BYTE bCurrentBeat;
if( pSD->m_mtTimeSig >= mtEnd ) return mtStart;
if( pSD->m_mtTimeSig > mtStart ) { mtStart = pSD->m_mtTimeSig; }
// now actually generate the beat events.
// Generate events that are on beat boundaries, from mtStart to mtEnd
long lQuantize = ( DMUS_PPQ * 4 ) / pSD->m_bBeat;
mtTime = mtStart - pSD->m_mtTimeSig; if( mtTime ) // 0 stays 0
{ // quantize to next boundary
mtTime = ((( mtTime - 1 ) / lQuantize ) + 1 ) * lQuantize; } mtStart += mtTime - ( mtStart - pSD->m_mtTimeSig ); bCurrentBeat = (BYTE)(( ( mtStart - pSD->m_mtTimeSig ) / lQuantize ) % pSD->m_bBeatsPerMeasure); dwMeasure = mtStart / (pSD->m_bBeatsPerMeasure * lQuantize ); while( mtStart < mtEnd ) { if( SUCCEEDED( pSD->m_pPerformance->AllocPMsg( sizeof(DMUS_NOTIFICATION_PMSG), (DMUS_PMSG**)&pEvent ))) { pEvent->dwType = DMUS_PMSGT_NOTIFICATION; pEvent->mtTime = mtStart + mtOffset; pEvent->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_ATTIME; pEvent->dwPChannel = 0; pSD->m_pSegState->QueryInterface(IID_IUnknown, (void**)&pEvent->punkUser);
pEvent->dwNotificationOption = DMUS_NOTIFICATION_MEASUREBEAT; pEvent->dwField1 = bCurrentBeat; pEvent->dwField2 = dwMeasure; pEvent->guidNotificationType = GUID_NOTIFICATION_MEASUREANDBEAT; pEvent->dwGroupID = 0xffffffff;
IDirectMusicGraph* pGraph; if( SUCCEEDED( pSD->m_pSegState->QueryInterface( IID_IDirectMusicGraph, (void**)&pGraph ))) { pGraph->StampPMsg((DMUS_PMSG*) pEvent ); pGraph->Release(); } if(FAILED(pSD->m_pPerformance->SendPMsg((DMUS_PMSG*) pEvent ))) { pSD->m_pPerformance->FreePMsg( (DMUS_PMSG*)pEvent ); } } bCurrentBeat++; if( bCurrentBeat >= pSD->m_bBeatsPerMeasure ) { bCurrentBeat = 0; dwMeasure += 1; } mtStart += lQuantize; } return mtEnd; }
HRESULT STDMETHODCALLTYPE CTimeSigTrack::Clone( MUSIC_TIME mtStart, MUSIC_TIME mtEnd, IDirectMusicTrack** ppTrack) { V_INAME(IDirectMusicTrack::Clone); V_PTRPTR_WRITE(ppTrack);
HRESULT hr = S_OK;
if((mtStart < 0 ) ||(mtStart > mtEnd)) { Trace(1,"Error: Clone failed on time signature track because of invalid start or end time.\n"); return E_INVALIDARG; }
EnterCriticalSection(&m_CrSec); CTimeSigTrack *pDM; try { pDM = new CTimeSigTrack(this, mtStart, mtEnd); } catch( ... ) { pDM = NULL; }
LeaveCriticalSection(&m_CrSec); if (pDM == NULL) { return E_OUTOFMEMORY; }
hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack); pDM->Release();
return hr; }
|