Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1480 lines
49 KiB

//
// DMPers.cpp : Implementation of CDMPers
//
// Copyright (c) 1997-2001 Microsoft Corporation
//
// @doc EXTERNAL
//
#include "DMPers.h"
#include "dmusici.h"
#include "..\shared\validate.h"
#include "..\shared\dmscriptautguids.h"
#include "debug.h"
V_INAME(DMCompose)
/////////////////////////////////////////////////////////////////////////////
// ReadMBSfromWCS
void ReadMBSfromWCS( IStream* pIStream, DWORD dwSize, String& pstrText )
{
HRESULT hr = S_OK;
wchar_t* wstrText = NULL;
DWORD dwBytesRead;
pstrText = "";
wstrText = new wchar_t[dwSize];
if( wstrText == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
hr = pIStream->Read( wstrText, dwSize, &dwBytesRead );
if( FAILED( hr )
|| dwBytesRead != dwSize )
{
goto ON_ERR;
}
pstrText = wstrText;
ON_ERR:
if( wstrText )
delete [] wstrText;
}
/////////// Utility functions for chords //////////////////
static BYTE setchordbits( long lPattern )
{
LONG i;
short count = 0;
BYTE bBits = 0;
for( i=0L ; i<32L ; i++ )
{
if( lPattern & (1L << i) )
count++;
}
bBits |= CHORD_INVERT;
if( count > 3 )
bBits |= CHORD_FOUR;
if( lPattern & (15L << 18L) )
bBits |= CHORD_UPPER;
bBits &= ~CHORD_COUNT;
bBits |= count;
return bBits;
}
// returns TRUE if the chord pattern represents a multichord, FALSE otherwise
inline BOOL MultiChord(DWORD dwPattern)
{
BYTE bBits = setchordbits( dwPattern );
short nChordCount = bBits & CHORD_COUNT;
return !((bBits & CHORD_FOUR && nChordCount <= 4) ||
(!(bBits & CHORD_FOUR) && nChordCount <= 3));
}
/*
TListItem<DMExtendedChord*>* ConvertChord(
DWORD dwChordPattern, BYTE bChordRoot, DWORD dwScalePattern, BYTE bScaleRoot)
{
BYTE bBits = setchordbits( dwChordPattern );
short nChordCount = bBits & CHORD_COUNT;
// The root of the lower chord is the input chord's root,
// relative to the scale root.
bChordRoot -= bScaleRoot;
if (bChordRoot < 0) bChordRoot += 12;
if ((bBits & CHORD_FOUR && nChordCount <= 4) ||
(!(bBits & CHORD_FOUR) && nChordCount <= 3))
{
// single subchord with all info from input chord
TListItem<DMExtendedChord*>* pSubChord = new TListItem<DMExtendedChord*>;
if ( pSubChord == NULL ) return NULL;
DMExtendedChord* pNew = new DMExtendedChord;
if (!pNew)
{
delete pSubChord;
return NULL;
}
DMExtendedChord*& rSubChord = pSubChord->GetItemValue();
rSubChord = pNew;
rSubChord->m_dwChordPattern = dwChordPattern;
rSubChord->m_dwScalePattern = dwScalePattern;
rSubChord->m_dwInvertPattern = 0xffffff; // default: inversions everywhere
rSubChord->m_bRoot = bChordRoot;
rSubChord->m_bScaleRoot = bScaleRoot;
rSubChord->m_wCFlags = 0;
// A single subchord can be used as either a bass or standard chord
rSubChord->m_dwParts = (1 << SUBCHORD_BASS) | (1 << SUBCHORD_STANDARD_CHORD);
rSubChord->AddRef();
return pSubChord;
}
else
{
// two subchords both with scale and roots from input chord, and:
// 1st chord: chord pattern from lower n notes of input chord
// 2nd chord: chord pattern from upper n notes of input chord
DWORD dwLowerSubChord = 0L;
DWORD dwUpperSubChord = 0L;
BYTE bUpperRoot = bChordRoot;
DWORD dwPattern = dwChordPattern;
short nIgnoreHigh = (bBits & CHORD_FOUR) ? 4 : 3;
short nIgnoreLow = (bBits & CHORD_FOUR) ? nChordCount - 4 : nChordCount - 3;
short nLowestUpper = 0;
for (short nPos = 0, nCount = 0; nPos < 24; nPos++)
{
if (dwPattern & 1)
{
if (nCount < nIgnoreHigh)
{
dwLowerSubChord |= 1L << nPos;
}
if (nCount >= nIgnoreLow)
{
if (!nLowestUpper)
{
nLowestUpper = nPos;
bUpperRoot = (bUpperRoot + (BYTE) nLowestUpper);
}
dwUpperSubChord |= 1L << (nPos - nLowestUpper);
}
nCount++;
if (nCount >= nChordCount)
break;
}
dwPattern >>= 1L;
}
// now, create the two subchords.
TListItem<DMExtendedChord*>* pLowerSubChord = new TListItem<DMExtendedChord*>;
if ( pLowerSubChord == NULL ) return NULL;
DMExtendedChord* pLower = new DMExtendedChord;
if (!pLower)
{
delete pLowerSubChord;
return NULL;
}
DMExtendedChord*& rLowerSubChord = pLowerSubChord->GetItemValue();
rLowerSubChord = pLower;
rLowerSubChord->m_dwChordPattern = dwLowerSubChord;
rLowerSubChord->m_dwScalePattern = dwScalePattern;
rLowerSubChord->m_dwInvertPattern = 0xffffff; // default: inversions everywhere
rLowerSubChord->m_bRoot = bChordRoot;
rLowerSubChord->m_bScaleRoot = bScaleRoot;
rLowerSubChord->m_wCFlags = 0;
rLowerSubChord->m_dwParts = (1 << SUBCHORD_BASS); // the lower chord is the bass chord
TListItem<DMExtendedChord*>* pUpperSubChord = new TListItem<DMExtendedChord*>;
if ( pUpperSubChord == NULL ) return NULL;
DMExtendedChord* pUpper = new DMExtendedChord;
if (!pUpper)
{
delete pUpperSubChord;
return NULL;
}
DMExtendedChord*& rUpperSubChord = pUpperSubChord->GetItemValue();
rUpperSubChord = pUpper;
rUpperSubChord->m_dwChordPattern = dwUpperSubChord;
rUpperSubChord->m_dwScalePattern = dwScalePattern;
rUpperSubChord->m_dwInvertPattern = 0xffffff; // default: inversions everywhere
rUpperSubChord->m_bRoot = bUpperRoot % 24;
while (rUpperSubChord->m_bRoot < rLowerSubChord->m_bRoot)
rUpperSubChord->m_bRoot += 12;
rUpperSubChord->m_bScaleRoot = bScaleRoot;
rUpperSubChord->m_wCFlags = 0;
rUpperSubChord->m_dwParts = (1 << SUBCHORD_STANDARD_CHORD); // the upper chord is the standard chord
rLowerSubChord->AddRef();
rUpperSubChord->AddRef();
return pLowerSubChord->Cat(pUpperSubChord);
}
}
*/
/////////////////////////////////////////////////////////////////////////////
// CDMPers
CDMPers::CDMPers( ) : m_cRef(1), m_fCSInitialized(FALSE)
{
InterlockedIncrement(&g_cComponent);
// Do this first since it might throw an exception
//
::InitializeCriticalSection( &m_CriticalSection );
m_fCSInitialized = TRUE;
m_PersonalityInfo.m_fLoaded = false;
ZeroMemory(&m_PersonalityInfo.m_guid, sizeof(GUID));
}
CDMPers::~CDMPers()
{
if (m_fCSInitialized)
{
CleanUp();
::DeleteCriticalSection( &m_CriticalSection );
}
InterlockedDecrement(&g_cComponent);
}
void CDMPers::CleanUp()
{
m_PersonalityInfo.m_fLoaded = false;
ZeroMemory(&m_PersonalityInfo.m_guid, sizeof(GUID));
TListItem<DMChordEntry>* pEntry = m_PersonalityInfo.m_ChordMap.GetHead();
for(; pEntry; pEntry=pEntry->GetNext())
{
pEntry->GetItemValue().m_ChordData.Release();
}
m_PersonalityInfo.m_ChordMap.CleanUp();
for (short i = 0; i < 24; i++)
{
TListItem<DMChordData>* pData = m_PersonalityInfo.m_aChordPalette[i].GetHead();
for(; pData; pData=pData->GetNext())
{
pData->GetItemValue().Release();
}
m_PersonalityInfo.m_aChordPalette[i].CleanUp();
}
TListItem<DMSignPost>* pSignPost = m_PersonalityInfo.m_SignPostList.GetHead();
for (; pSignPost != NULL; pSignPost = pSignPost->GetNext())
{
DMSignPost& rSignPost = pSignPost->GetItemValue();
rSignPost.m_ChordData.Release();
rSignPost.m_aCadence[0].Release();
rSignPost.m_aCadence[1].Release();
}
m_PersonalityInfo.m_SignPostList.CleanUp();
}
STDMETHODIMP CDMPers::QueryInterface(
const IID &iid,
void **ppv)
{
V_INAME(CDMPers::QueryInterface);
V_PTRPTR_WRITE(ppv);
V_REFGUID(iid);
*ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IDirectMusicChordMap)
{
*ppv = static_cast<IDirectMusicChordMap*>(this);
}
else if (iid == IID_IPersistStream)
{
*ppv = static_cast<IPersistStream*>(this);
}
else if (iid == IID_IDirectMusicObject)
{
*ppv = static_cast<IDirectMusicObject*>(this);
}
else if (iid == IID_IDMPers)
{
*ppv = static_cast<IDMPers*>(this);
}
if (*ppv == NULL)
return E_NOINTERFACE;
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CDMPers::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CDMPers::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
m_cRef = 100; // artificial reference count to prevent reentrency due to COM aggregation
delete this;
return 0;
}
return m_cRef;
}
HRESULT CDMPers::GetPersonalityStruct(void** ppPersonality)
{
if (ppPersonality)
*ppPersonality = &m_PersonalityInfo;
return S_OK;
}
HRESULT CDMPers::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMPers::GetDescriptor);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
EnterCriticalSection( &m_CriticalSection );
ZeroMemory(pDesc, sizeof(DMUS_OBJECTDESC));
pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicChordMap;
if (m_PersonalityInfo.m_fLoaded)
{
pDesc->dwValidData |= DMUS_OBJ_LOADED;
}
if (m_PersonalityInfo.m_guid.Data1 || m_PersonalityInfo.m_guid.Data2)
{
pDesc->dwValidData |= DMUS_OBJ_OBJECT;
pDesc->guidObject = m_PersonalityInfo.m_guid;
}
if (m_PersonalityInfo.m_strName)
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
wcscpy(pDesc->wszName, m_PersonalityInfo.m_strName);
//MultiByteToWideChar( CP_ACP, 0, m_PersonalityInfo.m_strName, -1, pDesc->wszName, DMUS_MAX_NAME);
}
LeaveCriticalSection( &m_CriticalSection );
return S_OK;
}
HRESULT CDMPers::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMPers::SetDescriptor);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
HRESULT hr = E_INVALIDARG;
DWORD dw = 0;
EnterCriticalSection( &m_CriticalSection );
if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
{
if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
{
m_PersonalityInfo.m_guid = pDesc->guidObject;
dw |= DMUS_OBJ_OBJECT;
}
if( pDesc->dwValidData & DMUS_OBJ_NAME )
{
m_PersonalityInfo.m_strName = pDesc->wszName;
dw |= DMUS_OBJ_NAME;
}
if( pDesc->dwValidData & (~dw) )
{
Trace(2, "WARNING: SetDescriptor (chord map): Descriptor contains fields that were not set.\n");
hr = S_FALSE; // there were extra fields we didn't parse;
pDesc->dwValidData = dw;
}
else
{
hr = S_OK;
}
}
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
HRESULT CDMPers::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMPers::ParseDescriptor);
V_INTERFACE(pStream);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
IAARIFFStream* pIRiffStream;
MMCKINFO ckMain;
// Prsonality personality;
// DWORD dwSize;
// FOURCC id;
DWORD dwPos;
HRESULT hr = S_OK;
dwPos = StreamTell( pStream );
BOOL fFoundFormat = FALSE;
// Check for Direct Music format
hr = AllocRIFFStream( pStream, &pIRiffStream );
if( SUCCEEDED( hr ) )
{
ckMain.fccType = DMUS_FOURCC_CHORDMAP_FORM;
if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
{
hr = DM_ParseDescriptor( pIRiffStream, &ckMain, pDesc );
fFoundFormat = TRUE;
}
pIRiffStream->Release();
}
else
{
return hr;
}
if( !fFoundFormat )
{
/* Don't try to parse IMA 2.5 format
StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
if( FAILED( pStream->Read( &id, sizeof( FOURCC ), NULL ) ) ||
!GetMLong( pStream, dwSize ) )
{
*/
Trace(1, "ERROR: ParseDescriptor (chord map): File does not contain a valid chord map.\n");
return DMUS_E_CHUNKNOTFOUND;
/*
}
if( id != mmioFOURCC( 'R', 'E', 'P', 's' ) )
{
Trace(1, "ERROR: ParseDescriptor (chord map): File does not contain a valid chord map.\n");
return DMUS_E_CHUNKNOTFOUND;
}
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicChordMap;
GetMLong( pStream, dwSize );
if( SUCCEEDED( pStream->Read( &personality, min( sizeof(Prsonality), dwSize ), NULL ) ) )
{
MultiByteToWideChar( CP_ACP, 0, personality.name, -1, pDesc->wszName, DMUS_MAX_NAME);
if (pDesc->wszName[0])
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
}
}
*/
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IDirectMusicPersonality
/*
@method:(EXTERNAL) HRESULT | IDirectMusicPersonality | GetScale | Retrieves the scale
associated with the personality.
@rdesc Returns:
@flag S_OK | Success.
@flag E_POINTER | <p pdwScale> is not a valid pointer.
@comm The scale is defined by the bits in a DWORD, split into a scale pattern (lower 24 bits)
and a root (upper 8 bits) For the scale pattern, the low bit (0x0001) is the lowest note in the
scale, the next higher (0x0002) is a semitone higher, etc. for two octaves. The root is
represented as a number between 0 and 23, where 0 represents a low C, 1 represents the
C# above that, etc. for two octaves.
*/
HRESULT CDMPers::GetScale(
DWORD *pdwScale // @parm The scale value to be returned.
)
{
V_PTR_WRITE(pdwScale, sizeof(DWORD) );
*pdwScale = m_PersonalityInfo.m_dwScalePattern;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IPersist
HRESULT CDMPers::GetClassID( LPCLSID pclsid )
{
if ( pclsid == NULL ) return E_INVALIDARG;
*pclsid = CLSID_DirectMusicChordMap;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IPersistStream
HRESULT CDMPers::IsDirty()
{
return ( m_fDirty ) ? S_OK : S_FALSE;
}
HRESULT CDMPers::Save( LPSTREAM /*pStream*/, BOOL /*fClearDirty*/ )
{
return E_NOTIMPL;
}
HRESULT CDMPers::GetSizeMax( ULARGE_INTEGER FAR* /*pcbSize*/ )
{
return E_NOTIMPL;
}
HRESULT CDMPers::Load( LPSTREAM pStream )
{
//FOURCC id;
//DWORD dwSize;
DWORD dwPos;
IAARIFFStream* pIRiffStream;
MMCKINFO ckMain;
HRESULT hr = E_FAIL;
if ( pStream == NULL ) return E_INVALIDARG;
EnterCriticalSection( &m_CriticalSection );
CleanUp();
dwPos = StreamTell( pStream );
BOOL fFoundFormat = FALSE;
// Check for Direct Music format
if( SUCCEEDED( AllocRIFFStream( pStream, &pIRiffStream ) ) )
{
ckMain.fccType = DMUS_FOURCC_CHORDMAP_FORM;
if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
{
hr = DM_LoadPersonality( pIRiffStream, &ckMain );
fFoundFormat = TRUE;
}
pIRiffStream->Release();
}
if( !fFoundFormat )
{
/* Don't try to load IMA 2.5 format
StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
if( FAILED( pStream->Read( &id, sizeof( FOURCC ), NULL ) ) ||
!GetMLong( pStream, dwSize ) )
{
*/
Trace(1, "ERROR: Load (chord map): File does not contain a valid chord map.\n");
hr = DMUS_E_CHUNKNOTFOUND;
goto end;
/*
}
if( id != mmioFOURCC( 'R', 'E', 'P', 's' ) )
{
Trace(1, "ERROR: Load (chord map): File does not contain a valid chord map.\n");
hr = DMUS_E_CHUNKNOTFOUND;
goto end;
}
hr = LoadPersonality( pStream, dwSize );
*/
}
end:
if (SUCCEEDED(hr)) m_PersonalityInfo.m_fLoaded = true;
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
/*
static LPSINEPOST loadasignpost( LPSTREAM pStream, DWORD dwSize )
{
LPSINEPOST signpost;
signpost = new SinePost;
if( signpost == NULL )
{
StreamSeek( pStream, dwSize, STREAM_SEEK_CUR );
return NULL;
}
if( dwSize > sizeof(SinePost) )
{
pStream->Read( signpost, sizeof(SinePost), NULL );
FixBytes( FBT_SINEPOST, signpost );
StreamSeek( pStream, dwSize - sizeof(SinePost), STREAM_SEEK_CUR );
}
else
{
pStream->Read( signpost, dwSize, NULL );
FixBytes( FBT_SINEPOST, signpost );
}
signpost->pNext = 0;
signpost->chord.pNext = 0;
signpost->cadence[0].pNext = 0;
signpost->cadence[1].pNext = 0;
return signpost;
}
static LPNEXTCHRD loadnextchords( LPSTREAM pStream, DWORD dwSiz )
{
HRESULT hr = S_OK;
LPNEXTCHRD nextchordlist = NULL;
LPNEXTCHRD nextchord;
DWORD nodesize = 0;
long lSize = dwSiz;
if (!GetMLong( pStream, nodesize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
return NULL;
}
lSize -= 4;
while( lSize > 0 )
{
nextchord = new NextChrd;
if( nextchord == NULL )
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
if( nodesize > NEXTCHORD_SIZE )
{
hr = pStream->Read( &nextchord->dwflags, NEXTCHORD_SIZE, NULL );
FixBytes( FBT_NEXTCHRD, nextchord );
StreamSeek( pStream, nodesize - NEXTCHORD_SIZE, STREAM_SEEK_CUR );
}
else
{
pStream->Read( &nextchord->dwflags, nodesize, NULL );
FixBytes( FBT_NEXTCHRD, nextchord );
}
lSize -= nodesize;
if (SUCCEEDED(hr))
{
nextchord->pNext = 0;
nextchordlist = List_Cat( nextchordlist, nextchord );
}
else
{
delete nextchord;
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
}
return nextchordlist;
}
static LPCHRDENTRY loadachordentry( LPSTREAM pStream, DWORD dwSiz )
{
LPCHRDENTRY chordentry;
DWORD csize = 0;
DWORD segsize = 0;
DWORD id;
long lSize = dwSiz;
chordentry = new ChrdEntry;
if( chordentry == NULL )
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
return NULL;
}
if (!GetMLong( pStream, csize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
delete chordentry;
return NULL;
}
lSize -= 4;
if( csize > CHORDENTRY_SIZE )
{
pStream->Read( &chordentry->chord.time, CHORDENTRY_SIZE, NULL );
FixBytes( FBT_CHRDENTRY, chordentry );
StreamSeek( pStream, csize - CHORDENTRY_SIZE, STREAM_SEEK_CUR );
}
else
{
pStream->Read( &chordentry->chord.time, csize, NULL );
FixBytes( FBT_CHRDENTRY, chordentry );
}
lSize -= csize;
chordentry->pNext = 0;
chordentry->nextchordlist = 0;
chordentry->chord.pNext = 0;
while( lSize > 0 )
{
pStream->Read( &id, sizeof(id), NULL );
if (!GetMLong( pStream, segsize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
lSize -= 8;
switch( id )
{
case mmioFOURCC( 'L', 'X', 'N', 's' ):
chordentry->nextchordlist = loadnextchords( pStream, segsize );
break;
default:
StreamSeek( pStream, segsize, STREAM_SEEK_CUR );
break;
}
lSize -= segsize;
}
return chordentry;
}
void DMPersonalityStruct::ResolveConnections( LPPERSONALITY personality, short nCount )
{
LPCHRDENTRY entry;
LPNEXTCHRD nextchord;
if (nCount == 0)
{
return;
}
// nCount is the largest index, so the array needs to be one more than that
TListItem<DMChordEntry> **ChordMap = new TListItem<DMChordEntry> *[nCount + 1];
if (!ChordMap) return;
for( entry=personality->chordlist ; entry ; entry=entry->pNext )
{
TListItem<DMChordEntry>* pEntry = new TListItem<DMChordEntry>;
if (!pEntry)
{
delete [] ChordMap;
return;
}
DMChordEntry& rEntry = pEntry->GetItemValue();
rEntry.m_dwFlags = entry->dwflags;
rEntry.m_ChordData.m_strName = entry->chord.name;
rEntry.m_ChordData.m_pSubChords = ConvertChord(
entry->chord.pattern, entry->chord.root, entry->chord.scalepattern, 0);
m_ChordMap.AddHead(pEntry);
ChordMap[entry->nid] = pEntry;
nextchord = entry->nextchordlist;
for( ; nextchord ; nextchord=nextchord->pNext )
{
if( nextchord->nid )
{
TListItem<DMChordLink>* pLink = new TListItem<DMChordLink>;
if (!pLink)
{
delete [] ChordMap;
return;
}
DMChordLink& rLink = pLink->GetItemValue();
rLink.m_wWeight = nextchord->nweight;
rLink.m_wMinBeats = nextchord->nminbeats;
rLink.m_wMaxBeats = nextchord->nmaxbeats;
rLink.m_dwFlags = nextchord->dwflags;
rLink.m_nID = nextchord->nid;
rEntry.m_Links.AddHead(pLink);
}
}
}
for(TListItem<DMChordEntry>* pEntry=m_ChordMap.GetHead(); pEntry; pEntry=pEntry->GetNext())
{
TListItem<DMChordLink>* pLink = pEntry->GetItemValue().m_Links.GetHead();
for( ; pLink ; pLink = pLink->GetNext() )
{
DMChordLink& rLink = pLink->GetItemValue();
if( rLink.m_nID )
{
rLink.m_pChord = ChordMap[rLink.m_nID];
}
}
}
delete [] ChordMap;
}
HRESULT CDMPers::LoadPersonality( LPSTREAM pStream, DWORD dwSiz )
{
short i;
LPPERSONALITY personality;
LPCHRDENTRY chordentry;
LPSINEPOST signpost;
DWORD csize = 0;
DWORD segsize = 0;
FOURCC id;
short nCount = 0;
long lSize = dwSiz;
HRESULT hr = S_OK;
if ( pStream == NULL ) return E_INVALIDARG;
personality = new Prsonality;
if( personality == NULL )
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
return E_OUTOFMEMORY;
}
if (!GetMLong( pStream, csize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
delete personality;
return E_FAIL;
}
lSize -= 4;
if( csize > sizeof(Prsonality) )
{
pStream->Read( personality, sizeof(Prsonality), NULL );
FixBytes( FBT_PRSONALITY, personality );
StreamSeek( pStream, csize - sizeof(Prsonality), STREAM_SEEK_CUR );
}
else
{
pStream->Read( personality, csize, NULL );
FixBytes( FBT_PRSONALITY, personality );
}
lSize -= csize;
m_PersonalityInfo.m_strName = personality->name;
m_PersonalityInfo.m_dwScalePattern = personality->scalepattern;
personality->pNext = NULL;
personality->dwAA = 0;
personality->chordlist = NULL;
personality->signpostlist = NULL;
personality->playlist = 0;
personality->firstchord = NULL;
for( i=0 ; i<24 ; i++ )
{
TListItem<DMChordData>* pPaletteEntry = new TListItem<DMChordData>;
if (!pPaletteEntry)
{
hr = E_OUTOFMEMORY;
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
DMChordData& rChordData = pPaletteEntry->GetItemValue();
rChordData.m_strName = personality->chord[i].achName;
rChordData.m_pSubChords = ConvertChord(
personality->chord[i].lPattern, personality->chord[i].chRoot,
personality->chord[i].lScalePattern, 0);
m_PersonalityInfo.m_aChordPalette[i].AddTail(pPaletteEntry);
personality->chord[i].pNext = 0;
}
if (SUCCEEDED(hr))
{
while( lSize > 0 )
{
pStream->Read( &id, sizeof(id), NULL );
if (!GetMLong( pStream, segsize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
lSize -= 8;
switch( id )
{
case mmioFOURCC( 'N', 'E', 'C', 's' ):
chordentry = loadachordentry( pStream, segsize );
if( chordentry )
{
personality->chordlist = List_Cat( personality->chordlist, chordentry );
if (chordentry->nid > nCount)
nCount = chordentry->nid;
}
break;
case mmioFOURCC( 'P', 'N', 'S', 's' ):
signpost = loadasignpost( pStream, segsize );
if( signpost )
{
personality->signpostlist = List_Cat( personality->signpostlist, signpost );
TListItem<DMSignPost>* pSignPost = new TListItem<DMSignPost>;
if (!pSignPost)
{
hr = E_OUTOFMEMORY;
StreamSeek( pStream, segsize, STREAM_SEEK_CUR );
break;
}
DMSignPost& rSignPost = pSignPost->GetItemValue();
rSignPost.m_dwChords = signpost->chords;
rSignPost.m_dwFlags = signpost->flags;
rSignPost.m_dwTempFlags = signpost->tempflags;
rSignPost.m_ChordData.m_strName = signpost->chord.name;
rSignPost.m_ChordData.m_pSubChords = ConvertChord(
signpost->chord.pattern, signpost->chord.root,
signpost->chord.scalepattern, 0);
rSignPost.m_aCadence[0].m_strName = signpost->cadence[0].name;
rSignPost.m_aCadence[0].m_pSubChords = ConvertChord(
signpost->cadence[0].pattern, signpost->cadence[0].root,
signpost->cadence[0].scalepattern, 0);
rSignPost.m_aCadence[1].m_strName = signpost->cadence[1].name;
rSignPost.m_aCadence[1].m_pSubChords = ConvertChord(
signpost->cadence[1].pattern, signpost->cadence[1].root,
signpost->cadence[1].scalepattern, 0);
m_PersonalityInfo.m_SignPostList.AddTail(pSignPost);
}
break;
default:
StreamSeek( pStream, segsize, STREAM_SEEK_CUR );
break;
}
lSize -= segsize;
}
}
if (SUCCEEDED(hr))
{
m_PersonalityInfo.ResolveConnections( personality, nCount );
}
// free up all the old format data structures
LPCHRDENTRY pChord;
LPNEXTCHRD pNextChord;
LPNEXTCHRD pNextNextChord;
for( pChord = personality->chordlist ; pChord != NULL ; pChord = pChord->pNext )
{
for( pNextChord = pChord->nextchordlist ; pNextChord != NULL ; pNextChord = pNextNextChord )
{
pNextNextChord = pNextChord->pNext;
delete pNextChord;
}
}
List_Free( personality->chordlist );
List_Free( personality->signpostlist );
delete personality;
return hr;
}
*/
HRESULT CDMPers::DM_ParseDescriptor( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, LPDMUS_OBJECTDESC pDesc )
{
IStream* pIStream;
MMCKINFO ck;
DWORD dwByteCount;
DWORD dwSize;
DWORD dwPos;
HRESULT hr = S_OK;
short nCount = 0;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
dwPos = StreamTell( pIStream );
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicChordMap;
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_IOCHORDMAP_CHUNK:
{
DMUS_IO_CHORDMAP iPersonality;
dwSize = min( ck.cksize, sizeof( DMUS_IO_CHORDMAP ) );
hr = pIStream->Read( &iPersonality, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
Trace(1, "ERROR: ParseDescriptor (chord map): DMUS_FOURCC_IOCHORDMAP_CHUNK chunk does not contain a valid DMUS_IO_CHORDMAP.\n");
hr = DMUS_E_CHUNKNOTFOUND;
goto ON_END;
}
wcscpy(pDesc->wszName, iPersonality.wszLoadName);
if(pDesc->wszName[0])
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
pDesc->wszName[16] = 0;
}
break;
}
case DMUS_FOURCC_GUID_CHUNK:
dwSize = min( ck.cksize, sizeof( GUID ) );
hr = pIStream->Read( &pDesc->guidObject, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
Trace(1, "ERROR: ParseDescriptor (chord map): DMUS_FOURCC_GUID_CHUNK chunk does not contain a valid GUID.\n");
hr = DMUS_E_CHUNKNOTFOUND;
goto ON_END;
}
pDesc->dwValidData |= DMUS_OBJ_OBJECT;
break;
}
pIRiffStream->Ascend( &ck, 0 );
dwPos = StreamTell( pIStream );
}
ON_END:
pIStream->Release();
return hr;
}
HRESULT CDMPers::DM_LoadPersonality( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain )
{
IStream* pIStream;
MMCKINFO ck;
MMCKINFO ck1;
MMCKINFO ckList;
DWORD dwByteCount;
DWORD dwSize;
DWORD dwPos;
HRESULT hr = S_OK;
DMExtendedChord** apChordDB = NULL;
short nCount = 0;
short n;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
dwPos = StreamTell( pIStream );
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_IOCHORDMAP_CHUNK:
{
DMUS_IO_CHORDMAP iPersonality;
ZeroMemory(&iPersonality, sizeof(DMUS_IO_CHORDMAP));
iPersonality.dwScalePattern = 0xffffffff;
dwSize = min( ck.cksize, sizeof( DMUS_IO_CHORDMAP ) );
hr = pIStream->Read( &iPersonality, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_IOCHORDMAP_CHUNK chunk does not contain a valid DMUS_IO_CHORDMAP.\n");
if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
goto ON_END;
}
if( iPersonality.dwFlags & 0xffff0000 )
{
// the scale was not properly initialized
Trace(2, "WARNING: Load (chord map): The chord map's flags are not properly initialized; clearing flags.\n");
iPersonality.dwFlags = 0;
}
if( !(iPersonality.dwFlags & DMUS_CHORDMAPF_VERSION8) &&
iPersonality.dwScalePattern >> 24 )
{
// the scale was not properly initialized
Trace(1, "ERROR: Load (chord map): The chord map's scale is not properly initialized.\n");
hr = DMUS_E_NOT_INIT;
goto ON_END;
}
m_PersonalityInfo.m_strName = iPersonality.wszLoadName;
m_PersonalityInfo.m_dwScalePattern = iPersonality.dwScalePattern;
m_PersonalityInfo.m_dwChordMapFlags = iPersonality.dwFlags;
break;
}
case DMUS_FOURCC_GUID_CHUNK:
dwSize = min( ck.cksize, sizeof( GUID ) );
hr = pIStream->Read( &m_PersonalityInfo.m_guid, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_GUID_CHUNK chunk does not contain a valid GUID.\n");
if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
goto ON_END;
}
break;
case DMUS_FOURCC_SUBCHORD_CHUNK:
{
long lFileSize = ck.cksize;
WORD wSize;
DWORD cb;
hr = pIStream->Read( &wSize, sizeof( wSize ), &cb );
if (FAILED(hr) || cb != sizeof( wSize ) )
{
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_SUBCHORD_CHUNK chunk does not contain a valid size DWORD.\n");
if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
lFileSize -= cb;
TList<DMExtendedChord*> ChordList;
while (lFileSize > 0)
{
DMUS_IO_PERS_SUBCHORD iSubChord;
hr = pIStream->Read( &iSubChord, wSize, &cb );
if (FAILED(hr) || cb != wSize )
{
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_SUBCHORD_CHUNK chunk does not contain a valid DMUS_IO_PERS_SUBCHORD.\n");
if (SUCCEEDED(hr)) hr = DMUS_E_CANNOTREAD;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
// stuff the data into a subchord struct and add it to the chord list
// (in reverse order)
TListItem<DMExtendedChord*>* pChordItem = new TListItem<DMExtendedChord*>;
if (pChordItem)
{
DMExtendedChord*& rpChord = pChordItem->GetItemValue();
rpChord = new DMExtendedChord;
if (rpChord)
{
rpChord->m_dwChordPattern = iSubChord.dwChordPattern;
rpChord->m_dwScalePattern = iSubChord.dwScalePattern;
rpChord->m_dwInvertPattern = iSubChord.dwInvertPattern;
rpChord->m_bRoot = iSubChord.bChordRoot;
rpChord->m_bScaleRoot = iSubChord.bScaleRoot;
rpChord->m_wCFlags = iSubChord.wCFlags;
rpChord->m_dwParts = iSubChord.dwLevels;
nCount++;
ChordList.AddHead(pChordItem);
}
else
{
delete pChordItem;
pChordItem = NULL;
}
}
if (!pChordItem)
{
hr = E_OUTOFMEMORY;
goto ON_END;
}
lFileSize -= wSize;
}
if (lFileSize != 0 )
{
hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
// now that the chord list is complete, transfer the pointers into the
// chord db (back to front to reinstate original order)
apChordDB = new DMExtendedChord*[nCount];
if (apChordDB)
{
TListItem<DMExtendedChord*>* pScan = ChordList.GetHead();
for (n = nCount - 1; n >= 0; n--)
{
apChordDB[n] = pScan->GetItemValue();
pScan = pScan->GetNext();
}
}
else
{
hr = E_OUTOFMEMORY;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
break;
}
case FOURCC_LIST:
ck1 = ck;
ckList = ck;
switch( ck1.fccType )
{
case DMUS_FOURCC_CHORDPALETTE_LIST:
for( n = 0; pIRiffStream->Descend( &ck1, &ckList, 0 ) == 0 && n < 24; n++ )
{
if ( ck1.ckid == FOURCC_LIST && ck1.fccType == DMUS_FOURCC_CHORD_LIST )
{
TListItem<DMChordData>* pChordData = new TListItem<DMChordData>;
if (pChordData)
{
m_PersonalityInfo.m_aChordPalette[n].AddHead(pChordData);
hr = pChordData->GetItemValue().Read(pIRiffStream, &ck1, apChordDB);
}
}
pIRiffStream->Ascend( &ck1, 0 );
dwPos = StreamTell( pIStream );
}
break;
case DMUS_FOURCC_CHORDMAP_LIST:
{
short nMapMax = 0;
while ( pIRiffStream->Descend( &ck1, &ckList, 0 ) == 0 )
{
if ( ck1.ckid == FOURCC_LIST && ck1.fccType == DMUS_FOURCC_CHORDENTRY_LIST )
{
DM_LoadChordEntry(pIRiffStream, &ck1, apChordDB, nMapMax);
}
pIRiffStream->Ascend( &ck1, 0 );
dwPos = StreamTell( pIStream );
}
TListItem<DMChordEntry>** aChordArray = new TListItem<DMChordEntry>*[nMapMax + 1];
if (!aChordArray)
{
hr = E_OUTOFMEMORY;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
TListItem<DMChordEntry>* pScan = m_PersonalityInfo.m_ChordMap.GetHead();
for(; pScan; pScan = pScan->GetNext())
{
if (pScan->GetItemValue().m_nID < 0 || pScan->GetItemValue().m_nID > nMapMax)
{
// the connection id was not properly initialized
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_CHORDMAP_LIST chunk contains an improperly initialized connection ID.\n");
hr = DMUS_E_NOT_INIT;
pIRiffStream->Ascend( &ck, 0 );
delete [] aChordArray;
goto ON_END;
}
aChordArray[pScan->GetItemValue().m_nID] = pScan;
}
pScan = m_PersonalityInfo.m_ChordMap.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
TListItem<DMChordLink>* pLink = pScan->GetItemValue().m_Links.GetHead();
for (; pLink; pLink = pLink->GetNext())
{
DMChordLink& rLink = pLink->GetItemValue();
if (rLink.m_nID < 0 || rLink.m_nID > nMapMax)
{
// the connection id was not properly initialized
Trace(1, "ERROR: Load (chord map): DMUS_FOURCC_CHORDMAP_LIST chunk contains an improperly initialized connection ID.\n");
hr = DMUS_E_NOT_INIT;
pIRiffStream->Ascend( &ck, 0 );
delete [] aChordArray;
goto ON_END;
}
rLink.m_pChord = aChordArray[rLink.m_nID];
}
}
delete [] aChordArray;
break;
}
case DMUS_FOURCC_SIGNPOST_LIST:
while ( pIRiffStream->Descend( &ck1, &ckList, 0 ) == 0 )
{
if ( ck1.ckid == FOURCC_LIST && ck1.fccType == DMUS_FOURCC_SIGNPOSTITEM_LIST )
{
DM_LoadSignPost(pIRiffStream, &ck1, apChordDB);
}
pIRiffStream->Ascend( &ck1, 0 );
dwPos = StreamTell( pIStream );
}
break;
}
break;
}
pIRiffStream->Ascend( &ck, 0 );
dwPos = StreamTell( pIStream );
}
ON_END:
if (apChordDB) delete [] apChordDB;
pIStream->Release();
return hr;
}
HRESULT CDMPers::DM_LoadChordEntry(
IAARIFFStream* pIRiffStream, MMCKINFO* pckParent, DMExtendedChord** apChordDB, short& nMax )
{
HRESULT hr = S_OK;
if (!pIRiffStream || !pckParent) return E_INVALIDARG;
MMCKINFO ck;
IStream* pIStream = pIRiffStream->GetStream();
if(!pIStream) return E_FAIL;
WORD wConnectionID = 0;
TListItem<DMChordEntry>* pChordEntry = new TListItem<DMChordEntry>;
if (!pChordEntry) return E_OUTOFMEMORY;
DMChordEntry& rChordEntry = pChordEntry->GetItemValue();
rChordEntry.m_ChordData.m_strName = "";
m_PersonalityInfo.m_ChordMap.AddHead(pChordEntry);
while(pIRiffStream->Descend(&ck, pckParent, 0) == 0 && hr == S_OK)
{
switch(ck.ckid)
{
case DMUS_FOURCC_CHORDENTRY_CHUNK:
{
DMUS_IO_CHORDENTRY iChordEntry;
DWORD cb;
hr = pIStream->Read( &iChordEntry, sizeof(iChordEntry), &cb );
if (FAILED(hr) || cb != sizeof(iChordEntry) )
{
if (SUCCEEDED(hr)) hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
rChordEntry.m_dwFlags = iChordEntry.dwFlags;
rChordEntry.m_nID = iChordEntry.wConnectionID;
if (rChordEntry.m_nID > nMax) nMax = rChordEntry.m_nID;
}
break;
case FOURCC_LIST:
if (ck.fccType == DMUS_FOURCC_CHORD_LIST)
{
hr = rChordEntry.m_ChordData.Read(pIRiffStream, &ck, apChordDB);
}
break;
case DMUS_FOURCC_NEXTCHORDSEQ_CHUNK:
{
long lFileSize = ck.cksize;
WORD wSize;
DWORD cb;
hr = pIStream->Read( &wSize, sizeof( wSize ), &cb );
if (FAILED(hr) || cb != sizeof( wSize ) )
{
if (SUCCEEDED(hr)) hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
lFileSize -= cb;
while (lFileSize > 0)
{
DMUS_IO_NEXTCHORD iNextChord;
hr = pIStream->Read( &iNextChord, wSize, &cb );
if (FAILED(hr) || cb != wSize )
{
if (SUCCEEDED(hr)) hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
if (iNextChord.wConnectionID)
{
TListItem<DMChordLink>* pItem = new TListItem<DMChordLink>;
if (!pItem )
{
hr = E_OUTOFMEMORY;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
DMChordLink& rLink = pItem->GetItemValue();
rLink.m_dwFlags = iNextChord.dwFlags;
rLink.m_nID = iNextChord.wConnectionID;
rLink.m_wWeight = iNextChord.nWeight;
rLink.m_wMinBeats = iNextChord.wMinBeats;
rLink.m_wMaxBeats = iNextChord.wMaxBeats;
rChordEntry.m_Links.AddHead(pItem);
}
lFileSize -= wSize;
}
if (lFileSize != 0 )
{
hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
}
break;
}
pIRiffStream->Ascend(&ck, 0);
}
ON_END:
if (pIStream) pIStream->Release();
return hr;
}
HRESULT CDMPers::DM_LoadSignPost( IAARIFFStream* pIRiffStream, MMCKINFO* pckParent, DMExtendedChord** apChordDB )
{
HRESULT hr = S_OK;
if (!pIRiffStream || !pckParent) return E_INVALIDARG;
MMCKINFO ck;
IStream* pIStream = pIRiffStream->GetStream();
if(!pIStream) return E_FAIL;
TListItem<DMSignPost>* pSignPost = new TListItem<DMSignPost>;
if (!pSignPost) return E_OUTOFMEMORY;
DMSignPost& rSignPost = pSignPost->GetItemValue();
m_PersonalityInfo.m_SignPostList.AddTail(pSignPost);
while(pIRiffStream->Descend(&ck, pckParent, 0) == 0 && hr == S_OK)
{
switch(ck.ckid)
{
case DMUS_FOURCC_IOSIGNPOST_CHUNK:
{
DMUS_IO_PERS_SIGNPOST iSignPost;
DWORD cb;
hr = pIStream->Read( &iSignPost, sizeof(iSignPost), &cb );
if (FAILED(hr) || cb != sizeof(iSignPost) )
{
if (SUCCEEDED(hr)) hr = E_FAIL;
pIRiffStream->Ascend( &ck, 0 );
goto ON_END;
}
rSignPost.m_dwChords = iSignPost.dwChords;
rSignPost.m_dwFlags = iSignPost.dwFlags;
}
break;
case FOURCC_LIST:
switch(ck.fccType)
{
case DMUS_FOURCC_CHORD_LIST:
hr = rSignPost.m_ChordData.Read(pIRiffStream, &ck, apChordDB);
break;
case DMUS_FOURCC_CADENCE_LIST:
{
MMCKINFO ckCadence = ck;
MMCKINFO ck1 = ck;
for (short n = 0;
pIRiffStream->Descend(&ck1, &ckCadence, 0) == 0 && hr == S_OK && n < 2;
n++)
{
if (ck1.fccType == DMUS_FOURCC_CHORD_LIST)
{
short n2 = n;
if ( !(rSignPost.m_dwFlags & DMUS_SPOSTCADENCEF_1) &&
(rSignPost.m_dwFlags & DMUS_SPOSTCADENCEF_2) )
{
// if all we have is cadence 2, put it in location 1
n2 = 1;
}
hr = rSignPost.m_aCadence[n2].Read(pIRiffStream, &ck1, apChordDB);
}
pIRiffStream->Ascend(&ck1, 0);
}
}
break;
}
break;
}
pIRiffStream->Ascend(&ck, 0);
}
ON_END:
if (pIStream) pIStream->Release();
return hr;
}
HRESULT DMChordData::Read(
IAARIFFStream* pIRiffStream, MMCKINFO* pckParent, DMExtendedChord** apChordDB)
{
HRESULT hr1 = E_FAIL, hr2 = E_FAIL;
if (!pIRiffStream || !pckParent) return E_INVALIDARG;
if (!apChordDB) return E_POINTER;
MMCKINFO ck;
wchar_t wzName[12];
WORD awSubIds[4];
IStream* pIStream = pIRiffStream->GetStream();
if(!pIStream) return E_FAIL;
while(pIRiffStream->Descend(&ck, pckParent, 0) == 0)
{
TListItem<DMExtendedChord*>* pChord = NULL;
switch(ck.ckid)
{
case DMUS_FOURCC_CHORDNAME_CHUNK:
hr1 = pIStream->Read(wzName, sizeof(wzName), 0);
if (SUCCEEDED(hr1)) m_strName = wzName;
break;
case DMUS_FOURCC_SUBCHORDID_CHUNK:
hr2 = pIStream->Read(awSubIds, sizeof(awSubIds), 0);
// now use the ids to set up pointers to subchords
if (m_pSubChords) Release();
pChord = new TListItem<DMExtendedChord*>(apChordDB[awSubIds[3]]);
if (pChord)
{
pChord->GetItemValue()->AddRef();
for (short n = 2; n >= 0; n--)
{
TListItem<DMExtendedChord*>* pNew = new TListItem<DMExtendedChord*>(apChordDB[awSubIds[n]]);
if (pNew)
{
pNew->GetItemValue()->AddRef();
pNew->SetNext(pChord);
pChord = pNew;
}
}
}
m_pSubChords = pChord;
break;
}
pIRiffStream->Ascend(&ck, 0);
}
pIStream->Release();
return (hr1 == S_OK && hr2 == S_OK) ? S_OK : E_FAIL;
}