//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) 1998-1999 Microsoft Corporation // // File: perstrk.cpp // //-------------------------------------------------------------------------- // 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) // PersTrk.cpp : Implementation of CPersonalityTrack #include "DMPers.h" #include "PersTrk.h" #include "dmusicc.h" #include "..\shared\Validate.h" ///////////////////////////////////////////////////////////////////////////// // CPersonalityTrack CPersonalityTrack::CPersonalityTrack() : m_bRequiresSave(0), m_cRef(1), m_fCSInitialized(FALSE) { InterlockedIncrement(&g_cComponent); // Do this first since it might throw an exception // ::InitializeCriticalSection( &m_CriticalSection ); m_fCSInitialized = TRUE; } CPersonalityTrack::CPersonalityTrack(const CPersonalityTrack& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd) : m_bRequiresSave(0), m_cRef(1), m_fCSInitialized(FALSE) { InterlockedIncrement(&g_cComponent); // Do this first since it might throw an exception // ::InitializeCriticalSection( &m_CriticalSection ); m_fCSInitialized = TRUE; TListItem* pScan = rTrack.m_PersonalityList.GetHead(); TListItem* pPrevious = NULL; for(; pScan; pScan = pScan->GetNext()) { StampedPersonality& rScan = pScan->GetItemValue(); if (rScan.m_mtTime < mtStart) { pPrevious = pScan; } else if (rScan.m_mtTime < mtEnd) { if (rScan.m_mtTime == mtStart) { pPrevious = NULL; } TListItem* pNew = new TListItem; if (pNew) { StampedPersonality& rNew = pNew->GetItemValue(); rNew.m_mtTime = rScan.m_mtTime - mtStart; rNew.m_pPersonality = rScan.m_pPersonality; if (rNew.m_pPersonality) rNew.m_pPersonality->AddRef(); m_PersonalityList.AddTail(pNew); } } else break; } if (pPrevious) { TListItem* pNew = new TListItem; if (pNew) { StampedPersonality& rNew = pNew->GetItemValue(); rNew.m_mtTime = 0; rNew.m_pPersonality = pPrevious->GetItemValue().m_pPersonality; if (rNew.m_pPersonality) rNew.m_pPersonality->AddRef(); m_PersonalityList.AddHead(pNew); } } } CPersonalityTrack::~CPersonalityTrack() { if (m_fCSInitialized) { ::DeleteCriticalSection( &m_CriticalSection ); } InterlockedDecrement(&g_cComponent); } STDMETHODIMP CPersonalityTrack::QueryInterface( const IID &iid, void **ppv) { V_INAME(CPersonalityTrack::QueryInterface); V_PTRPTR_WRITE(ppv); V_REFGUID(iid); if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack || iid == IID_IDirectMusicTrack8) { *ppv = static_cast(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(this)->AddRef(); return S_OK; } STDMETHODIMP_(ULONG) CPersonalityTrack::AddRef() { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CPersonalityTrack::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; } return m_cRef; } HRESULT CPersonalityTrack::Init( /*[in]*/ IDirectMusicSegment* pSegment ) { return S_OK; } HRESULT CPersonalityTrack::InitPlay( /*[in]*/ IDirectMusicSegmentState* pSegmentState, /*[in]*/ IDirectMusicPerformance* pPerformance, /*[out]*/ void** ppStateData, /*[in]*/ DWORD dwTrackID, /*[in]*/ DWORD dwFlags ) { return S_OK; } HRESULT CPersonalityTrack::EndPlay( /*[in]*/ void* pStateData ) { return S_OK; } HRESULT CPersonalityTrack::Play( /*[in]*/ void* pStateData, /*[in]*/ MUSIC_TIME mtStart, /*[in]*/ MUSIC_TIME mtEnd, /*[in]*/ MUSIC_TIME mtOffset, DWORD dwFlags, IDirectMusicPerformance* pPerf, IDirectMusicSegmentState* pSegState, DWORD dwVirtualID ) { return S_OK; } HRESULT CPersonalityTrack::GetPriority( /*[out]*/ DWORD* pPriority ) { return E_NOTIMPL; } HRESULT CPersonalityTrack::GetParam( REFGUID rCommandGuid, MUSIC_TIME mtTime, MUSIC_TIME* pmtNext, void* pData ) { V_INAME(CPersonalityTrack::GetParam); V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME); V_REFGUID(rCommandGuid); if( NULL == pData ) { Trace(1, "ERROR: GetParam (chord map track): pParam is NULL.\n"); return E_POINTER; } HRESULT hr; EnterCriticalSection(&m_CriticalSection); if (rCommandGuid == GUID_IDirectMusicChordMap) { TListItem* pScan = m_PersonalityList.GetHead(); if (pScan) { IDirectMusicChordMap* pPersonality = pScan->GetItemValue().m_pPersonality; for(pScan = pScan->GetNext(); pScan; pScan = pScan->GetNext()) { StampedPersonality& rScan = pScan->GetItemValue(); if (mtTime < rScan.m_mtTime && rScan.m_pPersonality) break; // ignore if NULL if (rScan.m_pPersonality) pPersonality = rScan.m_pPersonality; // skip if NULL } if (pPersonality) { pPersonality->AddRef(); *(IDirectMusicChordMap**)pData = pPersonality; if (pmtNext) { *pmtNext = (pScan != NULL) ? pScan->GetItemValue().m_mtTime - mtTime : 0; } hr = S_OK; } else { Trace(1, "ERROR: GetParam (chord map track): Chord map list item is empty.\n"); hr = E_POINTER; } } else { Trace(1, "ERROR: GetParam (chord map track): Chord map track is empty.\n"); hr = DMUS_E_NOT_FOUND; } } else { Trace(1, "ERROR: GetParam (chord map track): Attempt to get an unsupported parameter.\n"); hr = DMUS_E_GET_UNSUPPORTED; } LeaveCriticalSection(&m_CriticalSection); return hr; } HRESULT CPersonalityTrack::SetParam( REFGUID rCommandGuid, MUSIC_TIME mtTime, void __RPC_FAR *pData) { V_INAME(CPersonalityTrack::SetParam); V_REFGUID(rCommandGuid); HRESULT hr; if (!pData) { Trace(1, "ERROR: SetParam (chord map track): pParam is NULL.\n"); return E_POINTER; } EnterCriticalSection( &m_CriticalSection ); if (rCommandGuid == GUID_IDirectMusicChordMap) { IDirectMusicChordMap* pPers = (IDirectMusicChordMap*)pData; TListItem* pPersItem = m_PersonalityList.GetHead(); TListItem* pPrevious = NULL; TListItem* pNew = new TListItem; if (!pNew) { hr = E_OUTOFMEMORY; } else { pNew->GetItemValue().m_mtTime = mtTime; pNew->GetItemValue().m_pPersonality = pPers; if (pPers) pPers->AddRef(); for(; pPersItem != NULL; pPersItem = pPersItem->GetNext()) { if (pPersItem->GetItemValue().m_mtTime >= mtTime) break; pPrevious = pPersItem; } if (pPrevious) { pPrevious->SetNext(pNew); pNew->SetNext(pPersItem); } else // pPersItem is current head of list { m_PersonalityList.AddHead(pNew); } if (pPersItem && pPersItem->GetItemValue().m_mtTime == mtTime) { // remove it if (pPersItem->GetItemValue().m_pPersonality) { pPersItem->GetItemValue().m_pPersonality->Release(); } pPersItem->GetItemValue().m_pPersonality = NULL; pNew->SetNext(pPersItem->GetNext()); pPersItem->SetNext(NULL); delete pPersItem; } hr = S_OK; } } else { Trace(1, "ERROR: SetParam (chord map track): Attempt to set an unsupported parameter.\n"); hr = DMUS_E_SET_UNSUPPORTED; } LeaveCriticalSection( &m_CriticalSection ); return hr; } // IPersist methods HRESULT CPersonalityTrack::GetClassID( LPCLSID pClassID ) { V_INAME(CPersonalityTrack::GetClassID); V_PTR_WRITE(pClassID, CLSID); *pClassID = CLSID_DirectMusicChordMapTrack; return S_OK; } // IDirectMusicCommon Methods HRESULT CPersonalityTrack::GetName( /*[out]*/ BSTR* pbstrName ) { return E_NOTIMPL; } HRESULT CPersonalityTrack::IsParamSupported( /*[in]*/ REFGUID rGuid ) { V_INAME(CPersonalityTrack::IsParamSupported); V_REFGUID(rGuid); if (rGuid == GUID_IDirectMusicChordMap) return S_OK; else { Trace(2, "WARNING: IsParamSupported (chord map track): The parameter is not supported.\n"); return DMUS_E_TYPE_UNSUPPORTED; } } // IPersistStream methods HRESULT CPersonalityTrack::IsDirty() { return m_bRequiresSave ? S_OK : S_FALSE; } HRESULT CPersonalityTrack::Save( LPSTREAM pStream, BOOL fClearDirty ) { return E_NOTIMPL; } HRESULT CPersonalityTrack::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ ) { return E_NOTIMPL; } BOOL Less(StampedPersonality& SP1, StampedPersonality& SP2) { return SP1.m_mtTime < SP2.m_mtTime; } HRESULT CPersonalityTrack::Load(LPSTREAM pStream ) { V_INAME(CPersonalityTrack::Load); V_INTERFACE(pStream); IAARIFFStream* pIRiffStream; //MMCKINFO ckMain; MMCKINFO ck; HRESULT hr = E_FAIL; if ( pStream == NULL ) return E_INVALIDARG; EnterCriticalSection( &m_CriticalSection ); if (m_PersonalityList.GetHead()) { delete m_PersonalityList.GetHead(); m_PersonalityList.RemoveAll(); } if( SUCCEEDED( AllocRIFFStream( pStream, &pIRiffStream ) ) ) { if (pIRiffStream->Descend( &ck, NULL, 0 ) == 0) { if (ck.ckid == FOURCC_LIST && ck.fccType == DMUS_FOURCC_PERS_TRACK_LIST) { hr = LoadPersRefList(pIRiffStream, &ck); } pIRiffStream->Ascend( &ck, 0 ); } pIRiffStream->Release(); } m_PersonalityList.MergeSort(Less); LeaveCriticalSection( &m_CriticalSection ); return hr; } HRESULT CPersonalityTrack::LoadPersRefList( IAARIFFStream* pIRiffStream, MMCKINFO* pckParent ) { HRESULT hr = S_OK; if (!pIRiffStream || !pckParent) return E_INVALIDARG; MMCKINFO ck; while ( pIRiffStream->Descend( &ck, pckParent, 0 ) == 0 ) { if ( ck.ckid == FOURCC_LIST && ck.fccType == DMUS_FOURCC_PERS_REF_LIST ) { hr = LoadPersRef(pIRiffStream, &ck); pIRiffStream->Ascend( &ck, 0 ); } pIRiffStream->Ascend( &ck, 0 ); } return hr; } HRESULT CPersonalityTrack::LoadPersRef( IAARIFFStream* pIRiffStream, MMCKINFO* pckParent ) { HRESULT hr = S_OK; if (!pIRiffStream || !pckParent) return E_INVALIDARG; MMCKINFO ck; IStream* pIStream = pIRiffStream->GetStream(); if(!pIStream) return E_FAIL; IDirectMusicChordMap* pPersonality = NULL; TListItem* pNew = new TListItem; if (!pNew) return E_OUTOFMEMORY; StampedPersonality& rNew = pNew->GetItemValue(); while (pIRiffStream->Descend( &ck, pckParent, 0 ) == 0) { switch (ck.ckid) { case DMUS_FOURCC_TIME_STAMP_CHUNK: { DWORD dwTime; DWORD cb; hr = pIStream->Read( &dwTime, sizeof( dwTime ), &cb ); if (FAILED(hr) || cb != sizeof( dwTime ) ) { if (SUCCEEDED(hr)) hr = E_FAIL; pIRiffStream->Ascend( &ck, 0 ); goto ON_END; } rNew.m_mtTime = dwTime; } break; case FOURCC_LIST: if (ck.fccType == DMUS_FOURCC_REF_LIST) { hr = LoadReference(pIStream, pIRiffStream, ck, &pPersonality); if (SUCCEEDED(hr)) { rNew.m_pPersonality = pPersonality; } } break; } pIRiffStream->Ascend( &ck, 0 ); } if (SUCCEEDED(hr)) { m_PersonalityList.AddTail(pNew); } else { delete pNew; } ON_END: pIStream->Release(); return hr; } ////////////////////////////////////////////////////////////////////// // CPersonalityTrack::LoadReference HRESULT CPersonalityTrack::LoadReference(IStream *pStream, IAARIFFStream *pIRiffStream, MMCKINFO& ckParent, IDirectMusicChordMap** ppPersonality) { if (!pStream || !pIRiffStream || !ppPersonality) return E_INVALIDARG; IDirectMusicLoader* pLoader = NULL; IDirectMusicGetLoader *pIGetLoader; HRESULT hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader ); if (FAILED(hr)) return hr; hr = pIGetLoader->GetLoader(&pLoader); pIGetLoader->Release(); if (FAILED(hr)) return hr; DMUS_OBJECTDESC desc; ZeroMemory(&desc, sizeof(desc)); DWORD cbRead; MMCKINFO ckNext; ckNext.ckid = 0; ckNext.fccType = 0; DWORD dwSize = 0; while( pIRiffStream->Descend( &ckNext, &ckParent, 0 ) == 0 ) { switch(ckNext.ckid) { case DMUS_FOURCC_REF_CHUNK: DMUS_IO_REFERENCE ioDMRef; hr = pStream->Read(&ioDMRef, sizeof(DMUS_IO_REFERENCE), &cbRead); if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_REFERENCE)) { desc.guidClass = ioDMRef.guidClassID; desc.dwValidData |= ioDMRef.dwValidData; desc.dwValidData |= DMUS_OBJ_CLASS; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_GUID_CHUNK: hr = pStream->Read(&(desc.guidObject), sizeof(GUID), &cbRead); if(SUCCEEDED(hr) && cbRead == sizeof(GUID)) { desc.dwValidData |= DMUS_OBJ_OBJECT; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_DATE_CHUNK: hr = pStream->Read(&(desc.ftDate), sizeof(FILETIME), &cbRead); if(SUCCEEDED(hr) && cbRead == sizeof(FILETIME)) { desc.dwValidData |= DMUS_OBJ_DATE; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_NAME_CHUNK: dwSize = min(sizeof(desc.wszName), ckNext.cksize); hr = pStream->Read(desc.wszName, dwSize, &cbRead); if(SUCCEEDED(hr) && cbRead == dwSize) { desc.wszName[DMUS_MAX_NAME - 1] = L'\0'; desc.dwValidData |= DMUS_OBJ_NAME; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_FILE_CHUNK: dwSize = min(sizeof(desc.wszFileName), ckNext.cksize); hr = pStream->Read(desc.wszFileName, dwSize, &cbRead); if(SUCCEEDED(hr) && cbRead == dwSize) { desc.wszFileName[DMUS_MAX_FILENAME - 1] = L'\0'; desc.dwValidData |= DMUS_OBJ_FILENAME; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_CATEGORY_CHUNK: dwSize = min(sizeof(desc.wszCategory), ckNext.cksize); hr = pStream->Read(desc.wszCategory, dwSize, &cbRead); if(SUCCEEDED(hr) && cbRead == dwSize) { desc.wszCategory[DMUS_MAX_CATEGORY - 1] = L'\0'; desc.dwValidData |= DMUS_OBJ_CATEGORY; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; case DMUS_FOURCC_VERSION_CHUNK: DMUS_IO_VERSION ioDMObjVer; hr = pStream->Read(&ioDMObjVer, sizeof(DMUS_IO_VERSION), &cbRead); if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_VERSION)) { desc.vVersion.dwVersionMS = ioDMObjVer.dwVersionMS; desc.vVersion.dwVersionLS = ioDMObjVer.dwVersionLS; desc.dwValidData |= DMUS_OBJ_VERSION; } else if(SUCCEEDED(hr)) { hr = E_FAIL; } break; default: break; } if(SUCCEEDED(hr) && pIRiffStream->Ascend(&ckNext, 0) == 0) { ckNext.ckid = 0; ckNext.fccType = 0; } else if (SUCCEEDED(hr)) hr = E_FAIL; } if(SUCCEEDED(hr)) { desc.dwSize = sizeof(DMUS_OBJECTDESC); hr = pLoader->GetObject(&desc, IID_IDirectMusicChordMap, (void**)ppPersonality); } if (pLoader) { pLoader->Release(); } return hr; } HRESULT STDMETHODCALLTYPE CPersonalityTrack::AddNotificationType( /* [in] */ REFGUID rGuidNotify) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CPersonalityTrack::RemoveNotificationType( /* [in] */ REFGUID rGuidNotify) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CPersonalityTrack::Clone( MUSIC_TIME mtStart, MUSIC_TIME mtEnd, IDirectMusicTrack** ppTrack) { V_INAME(CPersonalityTrack::Clone); V_PTRPTR_WRITE(ppTrack); HRESULT hr = S_OK; if(mtStart < 0 ) { Trace(1, "ERROR: Clone (chord map track): Invalid start time.\n"); return E_INVALIDARG; } if(mtStart > mtEnd) { Trace(1, "ERROR: Clone (chord map track): Invalid end time.\n"); return E_INVALIDARG; } EnterCriticalSection( &m_CriticalSection ); CPersonalityTrack *pDM; try { pDM = new CPersonalityTrack(*this, mtStart, mtEnd); } catch( ... ) { pDM = NULL; } if (pDM == NULL) { LeaveCriticalSection( &m_CriticalSection ); return E_OUTOFMEMORY; } hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack); pDM->Release(); LeaveCriticalSection( &m_CriticalSection ); return hr; } // IDirectMusicTrack8 Methods // For consistency with other track types STDMETHODIMP CPersonalityTrack::GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime, REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags) { HRESULT hr; MUSIC_TIME mtNext; hr = GetParam(rguidType,(MUSIC_TIME) rtTime, &mtNext, pParam); if (prtNext) { *prtNext = mtNext; } return hr; } // For consistency with other track types STDMETHODIMP CPersonalityTrack::SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime, void* pParam, void * pStateData, DWORD dwFlags) { return SetParam(rguidType, (MUSIC_TIME) rtTime , pParam); } // For consistency with other track types STDMETHODIMP CPersonalityTrack::PlayEx(void* pStateData,REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset, DWORD dwFlags,IDirectMusicPerformance* pPerf, IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID) { V_INAME(IDirectMusicTrack::PlayEx); V_INTERFACE(pPerf); V_INTERFACE(pSegSt); HRESULT hr; EnterCriticalSection(&m_CriticalSection); hr = Play(pStateData, (MUSIC_TIME)rtStart, (MUSIC_TIME)rtEnd, (MUSIC_TIME)rtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); LeaveCriticalSection(&m_CriticalSection); return hr; } STDMETHODIMP CPersonalityTrack::Compose( IUnknown* pContext, DWORD dwTrackGroup, IDirectMusicTrack** ppResultTrack) { return E_NOTIMPL; } STDMETHODIMP CPersonalityTrack::Join( IDirectMusicTrack* pNewTrack, MUSIC_TIME mtJoin, IUnknown* pContext, DWORD dwTrackGroup, IDirectMusicTrack** ppResultTrack) { V_INAME(IDirectMusicTrack::Join); V_INTERFACE(pNewTrack); V_INTERFACE_OPT(pContext); V_PTRPTR_WRITE_OPT(ppResultTrack); HRESULT hr = S_OK; EnterCriticalSection(&m_CriticalSection); if (ppResultTrack) { hr = Clone(0, mtJoin, ppResultTrack); if (SUCCEEDED(hr)) { hr = ((CPersonalityTrack*)*ppResultTrack)->JoinInternal(pNewTrack, mtJoin, dwTrackGroup); } } else { hr = JoinInternal(pNewTrack, mtJoin, dwTrackGroup); } LeaveCriticalSection(&m_CriticalSection); return hr; } HRESULT CPersonalityTrack::JoinInternal( IDirectMusicTrack* pNewTrack, MUSIC_TIME mtJoin, DWORD dwTrackGroup) { HRESULT hr = S_OK; CPersonalityTrack* pOtherTrack = (CPersonalityTrack*)pNewTrack; TListItem* pScan = pOtherTrack->m_PersonalityList.GetHead(); for (; pScan; pScan = pScan->GetNext()) { StampedPersonality& rScan = pScan->GetItemValue(); TListItem* pNew = new TListItem; if (pNew) { StampedPersonality& rNew = pNew->GetItemValue(); rNew.m_mtTime = rScan.m_mtTime + mtJoin; rNew.m_pPersonality = rScan.m_pPersonality; if (rNew.m_pPersonality) rNew.m_pPersonality->AddRef(); m_PersonalityList.AddTail(pNew); } else { hr = E_OUTOFMEMORY; break; } } return hr; }