// // 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* 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* pSubChord = new TListItem; 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* pLowerSubChord = new TListItem; 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* pUpperSubChord = new TListItem; 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* 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* pData = m_PersonalityInfo.m_aChordPalette[i].GetHead(); for(; pData; pData=pData->GetNext()) { pData->GetItemValue().Release(); } m_PersonalityInfo.m_aChordPalette[i].CleanUp(); } TListItem* 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(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast(this); } else if (iid == IID_IDirectMusicObject) { *ppv = static_cast(this); } else if (iid == IID_IDMPers) { *ppv = static_cast(this); } if (*ppv == NULL) return E_NOINTERFACE; reinterpret_cast(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 |

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 **ChordMap = new TListItem *[nCount + 1]; if (!ChordMap) return; for( entry=personality->chordlist ; entry ; entry=entry->pNext ) { TListItem* pEntry = new TListItem; 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* pLink = new TListItem; 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* pEntry=m_ChordMap.GetHead(); pEntry; pEntry=pEntry->GetNext()) { TListItem* 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* pPaletteEntry = new TListItem; 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* pSignPost = new TListItem; 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 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* pChordItem = new TListItem; 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* 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* pChordData = new TListItem; 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** aChordArray = new TListItem*[nMapMax + 1]; if (!aChordArray) { hr = E_OUTOFMEMORY; pIRiffStream->Ascend( &ck, 0 ); goto ON_END; } TListItem* 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* 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* pChordEntry = new TListItem; 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* pItem = new TListItem; 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* pSignPost = new TListItem; 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* 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(apChordDB[awSubIds[3]]); if (pChord) { pChord->GetItemValue()->AddRef(); for (short n = 2; n >= 0; n--) { TListItem* pNew = new TListItem(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; }