1481 lines
49 KiB
C++
1481 lines
49 KiB
C++
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
|