windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmcompos/perstrk.cpp
2020-09-26 16:20:57 +08:00

820 lines
24 KiB
C++

//+-------------------------------------------------------------------------
//
// 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<StampedPersonality>* pScan = rTrack.m_PersonalityList.GetHead();
TListItem<StampedPersonality>* 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<StampedPersonality>* pNew = new TListItem<StampedPersonality>;
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<StampedPersonality>* pNew = new TListItem<StampedPersonality>;
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<IDirectMusicTrack*>(this);
}
else if (iid == IID_IPersistStream)
{
*ppv = static_cast<IPersistStream*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(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<StampedPersonality>* 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<StampedPersonality>* pPersItem = m_PersonalityList.GetHead();
TListItem<StampedPersonality>* pPrevious = NULL;
TListItem<StampedPersonality>* pNew = new TListItem<StampedPersonality>;
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<StampedPersonality>* pNew = new TListItem<StampedPersonality>;
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<StampedPersonality>* pScan = pOtherTrack->m_PersonalityList.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
StampedPersonality& rScan = pScan->GetItemValue();
TListItem<StampedPersonality>* pNew = new TListItem<StampedPersonality>;
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;
}