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.
 
 
 
 
 
 

7376 lines
246 KiB

//
// DMStyle.cpp : Implementation of CDMStyle
//
// Copyright (c) 1997-2001 Microsoft Corporation
//
// @doc EXTERNAL
//
#include "DMStyle.h"
#include "score.h"
#include "..\dmband\dmbandp.h"
#include "..\shared\Validate.h"
#include <mmreg.h>
#include "dmsect.h"
#include "ptrntrk.h"
#include "StyleTrk.h"
#include "..\shared\dmscriptautguids.h"
V_INAME(DMStyle)
#define NBR_VARIATIONS 32
#define DX8_PART_SIZE 160
#define DX8_PARTREF_SIZE 28
DirectMusicTimeSig DefaultTimeSig(4, 4, 4);
static char achMappings[128] = {
0, //0 },
35, //1 },
36, //2 },
38, //3 },
40, //4 },
41, //5 },
45, //6 },
48, //7 },
42, //8 },
44, //9 },
46, //10 },
39, //11 },
37, //12 },
51, //13 },
49, //14 },
54, //15 },
56, //16 },
61, //17 },
60, //18 },
64, //19 },
63, //20 },
66, //21 },
65, //22 },
69, //23 },
70, //24 },
71, //25 },
72, //26 },
73, //27 },
75, //28 },
47, //29 },
50, //30 },
53, //31 },
57, //32 },
52, //33 },
74, //34 },
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 98,
87, //99 },
86, //100 },
85, //101 },
84, //102 },
83, //103 },
82, //104 },
81, //105 },
80, //106 },
79, //107 },
78, //108 },
77, //109 },
76, //110 },
68, //111 },
67, //112 },
62, //113 },
59, //114 },
58, //115 },
55, //116 },
43, //117 },
34, //118 },
33, //119 },
32, //120 },
31, //121 },
30, //122 },
29, //123 },
28, //124 },
27, //125 },
26, //126 },
25, //127 }
};
/////////////////////////////////////////////////////////////////////////////
// ReadMBSfromWCS
HRESULT ReadMBSfromWCS( IStream* pIStream, DWORD dwSize, String& pstrText )
{
HRESULT hr = S_OK;
wchar_t* wstrText = NULL;
DWORD dwBytesRead;
DWORD dwLength = dwSize / sizeof(WCHAR);
if (dwLength * sizeof(WCHAR) != dwSize)
{
// Funky size that will result in a small (less than sizeof(WCHAR)) overrun
// So adjust the length accordingly
dwLength++;
}
pstrText = "";
wstrText = new wchar_t[dwLength + 1]; // make sure we have room for a null terminator
if( wstrText == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
hr = pIStream->Read( wstrText, dwSize, &dwBytesRead );
wstrText[dwLength] = 0;
if( FAILED( hr ) || dwBytesRead != dwSize )
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
goto ON_ERR;
}
pstrText = wstrText;
ON_ERR:
if( wstrText )
{
delete [] wstrText;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// SaveMBStoWCS
HRESULT SaveMBStoWCS( IStream* pIStream, String* pstrText )
{
HRESULT hr = S_OK;
wchar_t* wstrText = NULL;
DWORD dwLength;
DWORD dwBytesWritten;
if( pstrText == NULL )
{
hr = E_FAIL;
goto ON_ERR;
}
dwLength = pstrText->GetLength() + 1;
wstrText = new wchar_t[dwLength];
if( wstrText == NULL )
{
hr = E_FAIL;
goto ON_ERR;
}
wcscpy(wstrText, *pstrText);
dwLength *= sizeof(wchar_t);
hr = pIStream->Write( wstrText, dwLength, &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != dwLength )
{
goto ON_ERR;
}
ON_ERR:
if( wstrText )
delete [] wstrText;
return hr;
}
DirectMusicPart::DirectMusicPart(DirectMusicTimeSig *pTimeSig) :
m_cRef(1),
m_wNumMeasures(1),
m_bPlayModeFlags(DMUS_PLAYMODE_NORMALCHORD),
m_bInvertLower(0),
m_bInvertUpper(127),
m_dwFlags(0)
{
memset(&m_guidPartID, 0, sizeof(GUID));
if (pTimeSig)
{
m_timeSig = *pTimeSig;
}
for( int i = 0 ; i < NBR_VARIATIONS ; i++ )
{
m_dwVariationChoices[i] = 0;
}
}
STDMETHODIMP_(ULONG) DirectMusicPart::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) DirectMusicPart::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
delete this;
return 0;
}
return m_cRef;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPart::DM_LoadPart
HRESULT DirectMusicPart::DM_LoadPart(
IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwByteCount;
long lSize;
DWORD dwStructSize;
WORD wExtra;
if( pStyle == NULL ) return E_INVALIDARG;
pIStream = pIRiffStream->GetStream();
if( pIStream == NULL ) return E_FAIL;
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_PART_CHUNK:
{
DMUS_IO_STYLEPART iDMStylePart;
memset(&iDMStylePart, 0, sizeof(iDMStylePart));
lSize = min( ck.cksize, sizeof( DMUS_IO_STYLEPART ) );
if (ck.cksize >= DX8_PART_SIZE) pStyle->m_dwFlags |= STYLEF_USING_DX8;
hr = pIStream->Read( &iDMStylePart, lSize, &dwByteCount );
if( FAILED( hr ) || (long)dwByteCount != lSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
if( pStyle->FindPartByGUID( iDMStylePart.guidPartID ) )
{
hr = S_FALSE; // Style already contains a Part with this GUID
goto ON_ERROR; // so we must bypass this Part
}
m_timeSig.m_bBeatsPerMeasure = iDMStylePart.timeSig.bBeatsPerMeasure;
m_timeSig.m_bBeat = iDMStylePart.timeSig.bBeat;
m_timeSig.m_wGridsPerBeat = iDMStylePart.timeSig.wGridsPerBeat;
m_wNumMeasures = iDMStylePart.wNbrMeasures;
m_bInvertUpper = iDMStylePart.bInvertUpper;
m_bInvertLower = iDMStylePart.bInvertLower;
m_bPlayModeFlags = iDMStylePart.bPlayModeFlags;
m_dwFlags = iDMStylePart.dwFlags;
memcpy( &m_guidPartID, &iDMStylePart.guidPartID, sizeof(GUID) );
memcpy( &m_dwVariationChoices, &iDMStylePart.dwVariationChoices, sizeof(m_dwVariationChoices) );
for( int i = 0 ; i < NBR_VARIATIONS ; i++ )
{
if( m_dwVariationChoices[i] == 0xFFFFFFFF )
{
m_dwVariationChoices[i] = 0x3FFFFFFF;
}
if (pStyle->UsingDX8() && m_dwVariationChoices[i] == 0x3FFFFFFF)
{
m_dwVariationChoices[i] = 0x7FFFFFFF;
}
}
break;
}
case DMUS_FOURCC_NOTE_CHUNK:
{
CDMStyleNote* pNote;
DMUS_IO_STYLENOTE iDMStyleNote;
memset(&iDMStyleNote, 0, sizeof(DMUS_IO_STYLENOTE));
lSize = ck.cksize;
// Read size of the note structure
hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
if( FAILED( hr )
|| dwByteCount != sizeof( dwStructSize ) )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwByteCount;
if( dwStructSize > sizeof( DMUS_IO_STYLENOTE ) )
{
wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLENOTE ) );
dwStructSize = sizeof( DMUS_IO_STYLENOTE );
}
else
{
wExtra = 0;
}
// now read in the notes
while( lSize > 0 )
{
hr = pIStream->Read( &iDMStyleNote, dwStructSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwStructSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwStructSize;
if( wExtra > 0 )
{
StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
// Create Direct Music Note (if note event is legal)
if (iDMStyleNote.mtGridStart >= 0)
{
pNote = new CDMStyleNote;
if( pNote )
{
pNote->m_nGridStart = (short)iDMStyleNote.mtGridStart;
pNote->m_dwVariation = iDMStyleNote.dwVariation;
pNote->m_mtDuration = iDMStyleNote.mtDuration;
pNote->m_nTimeOffset = iDMStyleNote.nTimeOffset;
pNote->m_wMusicValue = iDMStyleNote.wMusicValue;
pNote->m_bVelocity = iDMStyleNote.bVelocity;
pNote->m_bTimeRange = iDMStyleNote.bTimeRange;
pNote->m_bDurRange = iDMStyleNote.bDurRange;
pNote->m_bVelRange = iDMStyleNote.bVelRange;
pNote->m_bInversionId = iDMStyleNote.bInversionID;
pNote->m_bPlayModeFlags = iDMStyleNote.bPlayModeFlags;
pNote->m_bFlags = iDMStyleNote.bNoteFlags;
// Place note in Part's event list
EventList.AddHead( pNote );
}
}
}
break;
}
case DMUS_FOURCC_CURVE_CHUNK:
{
CDMStyleCurve* pCurve;
DMUS_IO_STYLECURVE iDMStyleCurve;
memset(&iDMStyleCurve, 0, sizeof(DMUS_IO_STYLECURVE));
lSize = ck.cksize;
// Read size of the curve structure
hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwByteCount;
if( dwStructSize > sizeof( DMUS_IO_STYLECURVE ) )
{
wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLECURVE ) );
dwStructSize = sizeof( DMUS_IO_STYLECURVE );
}
else
{
wExtra = 0;
}
// now read in the curves
while( lSize > 0 )
{
hr = pIStream->Read( &iDMStyleCurve, dwStructSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwStructSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwStructSize;
if( wExtra > 0 )
{
StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
// Create Direct Music Curve (if curve event is legal)
if (iDMStyleCurve.mtGridStart >= 0)
{
pCurve = new CDMStyleCurve;
if( pCurve )
{
pCurve->m_nGridStart = (short)iDMStyleCurve.mtGridStart;
pCurve->m_dwVariation = iDMStyleCurve.dwVariation;
pCurve->m_mtDuration = iDMStyleCurve.mtDuration;
pCurve->m_nTimeOffset = iDMStyleCurve.nTimeOffset;
pCurve->m_StartValue = iDMStyleCurve.nStartValue;
pCurve->m_EndValue = iDMStyleCurve.nEndValue;
pCurve->m_bEventType = iDMStyleCurve.bEventType;
pCurve->m_bCurveShape = iDMStyleCurve.bCurveShape;
pCurve->m_bCCData = iDMStyleCurve.bCCData;
pCurve->m_mtResetDuration = iDMStyleCurve.mtResetDuration;
pCurve->m_nResetValue = iDMStyleCurve.nResetValue;
pCurve->m_bFlags = iDMStyleCurve.bFlags;
// dx8 stuff
pCurve->m_wParamType = iDMStyleCurve.wParamType;
pCurve->m_wMergeIndex = iDMStyleCurve.wMergeIndex;
// Place curve in Part's event list
EventList.AddHead( pCurve );
}
}
}
break;
}
case DMUS_FOURCC_MARKER_CHUNK:
{
CDMStyleMarker* pMarker;
DMUS_IO_STYLEMARKER iDMStyleMarker;
memset(&iDMStyleMarker, 0, sizeof(DMUS_IO_STYLEMARKER));
lSize = ck.cksize;
// Read size of the marker structure
hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwByteCount;
if( dwStructSize > sizeof( DMUS_IO_STYLEMARKER ) )
{
wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLEMARKER ) );
dwStructSize = sizeof( DMUS_IO_STYLEMARKER );
}
else
{
wExtra = 0;
}
// now read in the markers
while( lSize > 0 )
{
hr = pIStream->Read( &iDMStyleMarker, dwStructSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwStructSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwStructSize;
if( wExtra > 0 )
{
StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
// Create Direct Music Marker (if marker event is legal)
if (iDMStyleMarker.mtGridStart >= 0)
{
pMarker = new CDMStyleMarker;
if( pMarker )
{
pMarker->m_nGridStart = (short)iDMStyleMarker.mtGridStart;
pMarker->m_dwVariation = iDMStyleMarker.dwVariation;
pMarker->m_nTimeOffset = 0; // ignore offsets
pMarker->m_wFlags = iDMStyleMarker.wMarkerFlags;
// Place marker in Part's event list
EventList.AddHead( pMarker );
}
}
}
break;
}
case DMUS_FOURCC_ANTICIPATION_CHUNK:
{
CDMStyleAnticipation* pAnticipation;
DMUS_IO_STYLE_ANTICIPATION iDMStyleAnticipation;
memset(&iDMStyleAnticipation, 0, sizeof(DMUS_IO_STYLE_ANTICIPATION));
lSize = ck.cksize;
// Read size of the anticipation structure
hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwByteCount;
if( dwStructSize > sizeof( DMUS_IO_STYLE_ANTICIPATION ) )
{
wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLE_ANTICIPATION ) );
dwStructSize = sizeof( DMUS_IO_STYLE_ANTICIPATION );
}
else
{
wExtra = 0;
}
// now read in the markers
while( lSize > 0 )
{
hr = pIStream->Read( &iDMStyleAnticipation, dwStructSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwStructSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwStructSize;
if( wExtra > 0 )
{
StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
// Create Direct Music Anticipation (if anticipation event is legal)
if (iDMStyleAnticipation.mtGridStart >= 0)
{
pAnticipation = new CDMStyleAnticipation;
if( pAnticipation )
{
pAnticipation->m_nGridStart = (short)iDMStyleAnticipation.mtGridStart;
pAnticipation->m_dwVariation = iDMStyleAnticipation.dwVariation;
pAnticipation->m_nTimeOffset = iDMStyleAnticipation.nTimeOffset;
pAnticipation->m_bTimeRange = iDMStyleAnticipation.bTimeRange;
// Place anticipation in Part's event list
EventList.AddHead( pAnticipation );
}
}
}
break;
}
case DMUS_FOURCC_RESOLUTION_CHUNK:
{
TListItem<DMUS_IO_STYLERESOLUTION>* pResolutionItem;
DMUS_IO_STYLERESOLUTION iDMStyleResolution;
memset(&iDMStyleResolution, 0, sizeof(DMUS_IO_STYLERESOLUTION));
lSize = ck.cksize;
// Read size of the resolution structure
hr = pIStream->Read( &dwStructSize, sizeof( dwStructSize ), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof( dwStructSize ) )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwByteCount;
if( dwStructSize > sizeof( DMUS_IO_STYLERESOLUTION ) )
{
wExtra = static_cast<WORD>( dwStructSize - sizeof( DMUS_IO_STYLERESOLUTION ) );
dwStructSize = sizeof( DMUS_IO_STYLERESOLUTION );
}
else
{
wExtra = 0;
}
// now read in the resolutions
while( lSize > 0 )
{
hr = pIStream->Read( &iDMStyleResolution, dwStructSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwStructSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
lSize -= dwStructSize;
if( wExtra > 0 )
{
StreamSeek( pIStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
// Create Direct Music resolution
pResolutionItem = new TListItem<DMUS_IO_STYLERESOLUTION>;
if( pResolutionItem )
{
pResolutionItem->GetItemValue() = iDMStyleResolution;
// Place marker in Part's resolution list
m_ResolutionList.AddHead( pResolutionItem );
}
}
break;
}
}
pIRiffStream->Ascend( &ck, 0 );
}
// Sort the Event List
EventList.MergeSort(m_timeSig);
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDMStyle
STDMETHODIMP CDMStyle::QueryInterface(
const IID &iid, // Interface to query for
void **ppv) // The requested interface will be returned here
{
V_INAME(CDMStyle::QueryInterface);
V_REFGUID(iid);
V_PTRPTR_WRITE(ppv);
*ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IDirectMusicStyle)
{
*ppv = static_cast<IDirectMusicStyle*>(this);
}
else if (iid == IID_IDirectMusicStyle8)
{
*ppv = static_cast<IDirectMusicStyle8*>(this);
m_StyleInfo.m_dwFlags |= STYLEF_USING_DX8;
}
else if (iid == IID_IDirectMusicStyle8P)
{
*ppv = static_cast<IDirectMusicStyle8P*>(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_IDMStyle)
{
*ppv = static_cast<IDMStyle*>(this);
}
if (*ppv == NULL)
return E_NOINTERFACE;
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CDMStyle::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CDMStyle::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 CDMStyle::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMStyle::GetDescriptor);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
ZeroMemory(pDesc, sizeof(DMUS_OBJECTDESC));
pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicStyle;
if (m_StyleInfo.m_fLoaded)
{
pDesc->dwValidData |= DMUS_OBJ_LOADED;
}
if (m_StyleInfo.m_guid.Data1 || m_StyleInfo.m_guid.Data2)
{
pDesc->dwValidData |= DMUS_OBJ_OBJECT;
pDesc->guidObject = m_StyleInfo.m_guid;
}
if (m_StyleInfo.m_strCategory)
{
pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
wcsncpy(pDesc->wszCategory, m_StyleInfo.m_strCategory, DMUS_MAX_CATEGORY);
pDesc->wszCategory[DMUS_MAX_CATEGORY - 1] = 0;
}
if (m_StyleInfo.m_strName)
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
wcsncpy(pDesc->wszName, m_StyleInfo.m_strName, DMUS_MAX_NAME);
pDesc->wszName[DMUS_MAX_NAME - 1] = 0;
}
if (m_StyleInfo.m_dwVersionMS || m_StyleInfo.m_dwVersionLS)
{
pDesc->dwValidData |= DMUS_OBJ_VERSION;
pDesc->vVersion.dwVersionMS = m_StyleInfo.m_dwVersionMS;
pDesc->vVersion.dwVersionLS = m_StyleInfo.m_dwVersionLS;
}
return S_OK;
}
HRESULT CDMStyle::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMStyle::SetDescriptor);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
HRESULT hr = E_INVALIDARG;
DWORD dw = 0;
if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
{
if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
{
m_StyleInfo.m_guid = pDesc->guidObject;
dw |= DMUS_OBJ_OBJECT;
}
if( pDesc->dwValidData & DMUS_OBJ_NAME )
{
WCHAR wszTempName[DMUS_MAX_NAME];
memcpy(wszTempName, pDesc->wszName, sizeof(WCHAR)*DMUS_MAX_NAME);
wszTempName[DMUS_MAX_NAME - 1] = 0;
m_StyleInfo.m_strName = wszTempName;
dw |= DMUS_OBJ_NAME;
}
if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
{
WCHAR wszTempCategory[DMUS_MAX_CATEGORY];
memcpy(wszTempCategory, pDesc->wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY);
wszTempCategory[DMUS_MAX_CATEGORY - 1] = 0;
m_StyleInfo.m_strCategory = wszTempCategory;
dw |= DMUS_OBJ_CATEGORY;
}
if ( pDesc->dwValidData & DMUS_OBJ_VERSION )
{
m_StyleInfo.m_dwVersionMS = pDesc->vVersion.dwVersionMS;
m_StyleInfo.m_dwVersionLS = pDesc->vVersion.dwVersionLS;
dw |= DMUS_OBJ_VERSION;
}
if( pDesc->dwValidData & (~dw) )
{
hr = S_FALSE; // there were extra fields we didn't parse;
pDesc->dwValidData = dw;
}
else
{
hr = S_OK;
}
}
return hr;
}
HRESULT CDMStyle::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CDMStyle::ParseDescriptor);
V_INTERFACE(pStream);
V_PTR_WRITE(pDesc, DMUS_OBJECTDESC);
IAARIFFStream* pRIFF;
MMCKINFO ckMain;
MMCKINFO ck;
ioStyle iStyle;
DWORD cb;
DWORD cSize;
HRESULT hr = S_OK;
DWORD dwPos;
BOOL fFoundFormat = FALSE;
dwPos = StreamTell( pStream );
// Check for Direct Music format
hr = AllocRIFFStream( pStream, &pRIFF );
if( SUCCEEDED( hr ) )
{
ckMain.fccType = DMUS_FOURCC_STYLE_FORM;
if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
{
hr = DM_ParseDescriptor( pRIFF, &ckMain, pDesc );
fFoundFormat = TRUE;
}
pRIFF->Release();
pRIFF = NULL;
}
else
{
return hr;
}
// Check for IMA 2.5 format
if( fFoundFormat )
{
hr = S_OK;
}
else
{
StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
hr = AllocRIFFStream( pStream, &pRIFF );
if( SUCCEEDED( hr ) )
{
ckMain.fccType = FOURCC_STYLE_FORM;
if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDRIFF ) != 0 )
{
pRIFF->Release();
return DMUS_E_CHUNKNOTFOUND;
}
ck.ckid = FOURCC_STYLE;
if( pRIFF->Descend( &ck, &ckMain, MMIO_FINDCHUNK ) != 0 )
{
pRIFF->Release();
return DMUS_E_CHUNKNOTFOUND;
}
cSize = min( ck.cksize, sizeof( iStyle ) );
hr = pStream->Read( &iStyle, cSize, &cb );
FixBytes( FBT_IOSTYLE, &iStyle );
if( FAILED( hr ) || cb != cSize )
{
pRIFF->Release();
return DMUS_E_CHUNKNOTFOUND;
}
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicStyle;
wcsncpy(pDesc->wszName, iStyle.wstrName, DMUS_MAX_NAME);
if(pDesc->wszName[0])
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
pDesc->wszName[16] = 0;
}
wcsncpy(pDesc->wszCategory, iStyle.wstrCategory, DMUS_MAX_CATEGORY);
if(pDesc->wszCategory[0])
{
pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
pDesc->wszCategory[16] = 0;
}
if(iStyle.guid.Data1 || iStyle.guid.Data2 || iStyle.guid.Data3)
{
pDesc->guidObject = iStyle.guid;
pDesc->dwValidData |= DMUS_OBJ_OBJECT;
}
pRIFF->Release();
}
else
{
return hr;
}
}
return hr;
}
// Note: this needs to be called from inside a critical section.
HRESULT CDMStyle::CreateMotifSegment(CDirectMusicPattern* pPattern, IUnknown * * ppSegment,
DWORD dwRepeats)
{
HRESULT hr = S_OK;
//1. Create a Motif track.
IDirectMusicTrack* pIMotifTrack = NULL;
hr = ::CoCreateInstance(
CLSID_DirectMusicMotifTrack,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicTrack,
(void**)&pIMotifTrack
);
if (SUCCEEDED(hr))
{
// 2. Set the Track's Motif
DirectMusicTimeSig& TimeSig =
pPattern->m_timeSig.m_bBeat == 0 ? m_StyleInfo.m_TimeSignature : pPattern->m_timeSig;
TListItem<DirectMusicPartRef>* pPartRef = pPattern->m_PartRefList.GetHead();
for(; pPartRef != NULL; pPartRef = pPartRef->GetNext())
{
DirectMusicPart* pPart = pPartRef->GetItemValue().m_pDMPart;
DirectMusicTimeSig& TS =
pPart->m_timeSig.m_bBeat == 0 ? TimeSig : pPart->m_timeSig;
pPart->EventList.MergeSort(TS);
}
IMotifTrack* pIMT;
hr = pIMotifTrack->QueryInterface(IID_IMotifTrack, (void**)&pIMT);
if (SUCCEEDED(hr))
{
IDirectMusicStyle* pIDMS = NULL;
hr = ((IDMStyle*)this)->QueryInterface(IID_IDirectMusicStyle, (void**)&pIDMS);
hr = pIMT->SetTrack(pIDMS, pPattern);
pIDMS->Release();
DWORD dwLength;
dwLength = pPattern->m_wNumMeasures * TimeSig.ClocksPerMeasure();
// 3. Create a secondary segment for the motif.
IDirectMusicSegment *pISegment;
hr = ::CoCreateInstance(
CLSID_DirectMusicSegment,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicSegment,
(void**)&pISegment
);
if (SUCCEEDED(hr) )
{
// 4. Initialize the segment appropriately.
pISegment->SetLength(dwLength);
if (pPattern->m_fSettings)
{
pISegment->SetRepeats(pPattern->m_dwRepeats);
pISegment->SetDefaultResolution(pPattern->m_dwResolution);
pISegment->SetStartPoint(pPattern->m_mtPlayStart);
pISegment->SetLoopPoints(pPattern->m_mtLoopStart, pPattern->m_mtLoopEnd);
}
else
{
pISegment->SetRepeats(dwRepeats);
pISegment->SetDefaultResolution(DMUS_SEGF_BEAT);
}
pISegment->InsertTrack(pIMotifTrack, 1);
// create and insert a band track, if the motif references a band
if (pPattern->m_pMotifBand)
{
IDirectMusicTrack* pBandTrack = NULL;
hr = ::CoCreateInstance(
CLSID_DirectMusicBandTrack,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicTrack,
(void**)&pBandTrack
);
if (SUCCEEDED(hr))
{
DMUS_BAND_PARAM DMBandParam;
DMBandParam.mtTimePhysical = -64;
DMBandParam.pBand = pPattern->m_pMotifBand;
hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam);
if (SUCCEEDED(hr))
{
pISegment->InsertTrack(pBandTrack, 1);
}
pBandTrack->Release(); // Release the AddRef from InsertTrack
}
}
// Note: the segment must release the track objects...
if (SUCCEEDED(hr))
{
IUnknown *pUnknown;
hr = pISegment->QueryInterface(IID_IUnknown, (void**)&pUnknown);
if (SUCCEEDED(hr))
{
*ppSegment = pUnknown;
pISegment->Release();
}
}
}
pIMT->Release();
}
pIMotifTrack->Release();
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_SaveSinglePattern
HRESULT CDirectMusicPattern::DM_SaveSinglePattern( IAARIFFStream* pIRiffStream )
{
TList<DirectMusicPart*> PartList;
TListItem<DirectMusicPartRef>* pPartRefItem;
TListItem<DirectMusicPart*>* pPartItem;
DirectMusicPart* pPart;
HRESULT hr = S_OK;
IStream* pIStream;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
// Save Pattern chunk
hr = DM_SavePatternChunk( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}
// Save Pattern rhythm
hr = DM_SavePatternRhythm( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}
/*// Save Pattern switch points
hr = DM_SavePatternSwitchPoints( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}*/
// Save Pattern info
hr = DM_SavePatternInfoList( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}
// Build list of Parts
pPartRefItem = m_PartRefList.GetHead();
for( ; pPartRefItem; pPartRefItem = pPartRefItem->GetNext() )
{
DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
if( rPartRef.m_pDMPart == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
for (pPartItem = PartList.GetHead(); pPartItem; pPartItem = pPartItem->GetNext())
{
if (pPartItem->GetItemValue() == rPartRef.m_pDMPart)
break;
}
if( pPartItem == NULL )
{
pPartItem = new TListItem<DirectMusicPart*>(rPartRef.m_pDMPart);
if (pPartItem)
{
PartList.AddTail( pPartItem );
}
}
}
// Save Parts
pPartItem = PartList.GetHead();
for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
{
pPart = pPartItem->GetItemValue();
hr = pPart->DM_SavePart( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}
}
// Save Part References
pPartRefItem = m_PartRefList.GetHead();
for( ; pPartRefItem; pPartRefItem = pPartRefItem->GetNext() )
{
DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
hr = rPartRef.DM_SavePartRef( pIRiffStream );
if( FAILED ( hr ) )
{
goto ON_ERROR;
}
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_SavePatternRhythm
HRESULT CDirectMusicPattern::DM_SavePatternRhythm( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr = S_OK;
MMCKINFO ck;
DWORD dwBytesWritten;
int i;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Rhythm chunk header
ck.ckid = DMUS_FOURCC_RHYTHM_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save the RhythmMap for each measure
for( i = 0 ; i < m_wNumMeasures ; i++ )
{
// Write Rhythm chunk data
hr = pIStream->Write( &m_pRhythmMap[i], sizeof(DWORD), &dwBytesWritten);
if( FAILED( hr ) || dwBytesWritten != sizeof(DWORD) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_SavePatternSwitchPoints
/*
HRESULT CDirectMusicPattern::DM_SavePatternSwitchPoints( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
int i;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Pattern Switch Point chunk header
ck.ckid = DMUS_FOURCC_SWITCH_POINT_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save the Switch Points for each measure
for( i = 0 ; i < m_wNumMeasures ; i++ )
{
// Write Switch Point chunk data
hr = pIStream->Write( &m_pSwitchPoints[i], sizeof(DWORD), &dwBytesWritten);
if( FAILED( hr ) || dwBytesWritten != sizeof(DWORD) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
*/
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_SavePatternInfoList
HRESULT CDirectMusicPattern::DM_SavePatternInfoList( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ckMain;
MMCKINFO ck;
if( m_strName.IsEmpty() )
{
return S_OK;
}
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write UNFO LIST header
ckMain.fccType = DMUS_FOURCC_UNFO_LIST;
if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Pattern name
if( !m_strName.IsEmpty() )
{
ck.ckid = DMUS_FOURCC_UNAM_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
hr = SaveMBStoWCS( pIStream, &m_strName );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
if( pIRiffStream->Ascend(&ckMain, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_SavePatternChunk
HRESULT CDirectMusicPattern::DM_SavePatternChunk( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
DMUS_IO_PATTERN oDMPattern;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Pattern chunk header
ck.ckid = DMUS_FOURCC_PATTERN_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Prepare DMUS_IO_PATTERN
memset( &oDMPattern, 0, sizeof(DMUS_IO_PATTERN) );
oDMPattern.timeSig.bBeatsPerMeasure = m_timeSig.m_bBeatsPerMeasure;
oDMPattern.timeSig.bBeat = m_timeSig.m_bBeat;
oDMPattern.timeSig.wGridsPerBeat = m_timeSig.m_wGridsPerBeat;
oDMPattern.bGrooveBottom = m_bGrooveBottom;
oDMPattern.bGrooveTop = m_bGrooveTop;
oDMPattern.bDestGrooveBottom = m_bDestGrooveBottom;
oDMPattern.bDestGrooveTop = m_bDestGrooveTop;
oDMPattern.wEmbellishment = m_wEmbellishment;
oDMPattern.wNbrMeasures = m_wNumMeasures;
oDMPattern.dwFlags = m_dwFlags;
// Write Pattern chunk data
hr = pIStream->Write( &oDMPattern, sizeof(DMUS_IO_PATTERN), &dwBytesWritten);
if( FAILED( hr )
|| dwBytesWritten != sizeof(DMUS_IO_PATTERN) )
{
hr = E_FAIL;
goto ON_ERROR;
}
if( pIRiffStream->Ascend( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
HRESULT CDirectMusicPattern::Save( IStream* pIStream )
{
if( pIStream == NULL )
{
return E_INVALIDARG;
}
IAARIFFStream* pIRiffStream;
MMCKINFO ckMain;
HRESULT hr = E_FAIL;
// Single Pattern (Direct Music format)
if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
{
ckMain.fccType = DMUS_FOURCC_PATTERN_LIST;
if( pIRiffStream->CreateChunk( &ckMain, MMIO_CREATERIFF ) == 0
&& SUCCEEDED( DM_SaveSinglePattern( pIRiffStream ) )
&& pIRiffStream->Ascend( &ckMain, 0 ) == 0 )
{
hr = S_OK;
}
pIRiffStream->Release();
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPartRef::DM_SavePartRef
HRESULT DirectMusicPartRef::DM_SavePartRef( IAARIFFStream* pIRiffStream )
{
IStream* pIStream = NULL;
HRESULT hr;
MMCKINFO ckMain;
MMCKINFO ck;
DWORD dwBytesWritten;
DMUS_IO_PARTREF oDMPartRef;
if ( m_pDMPart == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write PartRef list header
ckMain.fccType = DMUS_FOURCC_PARTREF_LIST;
if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write PartRef chunk header
ck.ckid = DMUS_FOURCC_PARTREF_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Prepare DMUS_IO_PARTREF structure
memset( &oDMPartRef, 0, sizeof(DMUS_IO_PARTREF) );
oDMPartRef.dwPChannel = m_dwLogicalPartID;
oDMPartRef.wLogicalPartID = (WORD) m_dwLogicalPartID;
oDMPartRef.bVariationLockID = m_bVariationLockID;
oDMPartRef.bSubChordLevel = m_bSubChordLevel;
oDMPartRef.bPriority = m_bPriority;
memcpy( &oDMPartRef.guidPartID, &m_pDMPart->m_guidPartID, sizeof(GUID) );
// Write PartRef chunk data
hr = pIStream->Write( &oDMPartRef, sizeof(DMUS_IO_PARTREF), &dwBytesWritten);
if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_PARTREF) )
{
hr = E_FAIL;
goto ON_ERROR;
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
if( pIRiffStream->Ascend( &ckMain, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
if (pIStream) pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPart::DM_SavePart
HRESULT DirectMusicPart::DM_SavePart( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ckMain;
MMCKINFO ck;
DWORD dwBytesWritten;
DMUS_IO_STYLEPART oDMStylePart;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Part list header
ckMain.fccType = DMUS_FOURCC_PART_LIST;
if( pIRiffStream->CreateChunk(&ckMain, MMIO_CREATELIST) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Part chunk header
ck.ckid = DMUS_FOURCC_PART_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Prepare DMUS_IO_STYLEPART structure
memset( &oDMStylePart, 0, sizeof(DMUS_IO_STYLEPART) );
oDMStylePart.timeSig.bBeatsPerMeasure = m_timeSig.m_bBeatsPerMeasure;
oDMStylePart.timeSig.bBeat = m_timeSig.m_bBeat;
oDMStylePart.timeSig.wGridsPerBeat = m_timeSig.m_wGridsPerBeat;
oDMStylePart.wNbrMeasures = m_wNumMeasures;
oDMStylePart.bInvertUpper = m_bInvertUpper;
oDMStylePart.bInvertLower = m_bInvertLower;
oDMStylePart.bPlayModeFlags = m_bPlayModeFlags;
oDMStylePart.dwFlags = m_dwFlags;
memcpy( &oDMStylePart.guidPartID, &m_guidPartID, sizeof(GUID) );
memcpy( &oDMStylePart.dwVariationChoices, &m_dwVariationChoices, sizeof(m_dwVariationChoices) );
// Write Part chunk data
hr = pIStream->Write( &oDMStylePart, sizeof(DMUS_IO_STYLEPART), &dwBytesWritten);
if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLEPART) )
{
hr = E_FAIL;
goto ON_ERROR;
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
CDirectMusicEventItem* pEvent;
// Save Part note list (when applicable)
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_NOTE )
{
hr = DM_SaveNoteList( pIRiffStream );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
break;
}
pEvent = pEvent->GetNext();
}
// Save Part curve list (when applicable)
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_CURVE )
{
hr = DM_SaveCurveList( pIRiffStream );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
break;
}
pEvent = pEvent->GetNext();
}
// Save Part marker list (when applicable)
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_MARKER )
{
hr = DM_SaveMarkerList( pIRiffStream );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
break;
}
pEvent = pEvent->GetNext();
}
// Save Part anticipation list (when applicable)
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION )
{
hr = DM_SaveAnticipationList( pIRiffStream );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
break;
}
pEvent = pEvent->GetNext();
}
// save resolution list (when applicable)
if (m_ResolutionList.GetHead())
{
hr = DM_SaveResolutionList(pIRiffStream);
if( FAILED( hr ) )
{
goto ON_ERROR;
}
}
if( pIRiffStream->Ascend( &ckMain, 0 ) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPart::DM_SaveNoteList
HRESULT DirectMusicPart::DM_SaveNoteList( IAARIFFStream* pIRiffStream )
{
CDirectMusicEventItem* pEvent;
CDMStyleNote* pNote;
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
WORD dwSize;
DMUS_IO_STYLENOTE oDMStyleNote;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Write Note chunk header
ck.ckid = DMUS_FOURCC_NOTE_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
{
hr = E_FAIL;
goto ON_ERROR;
}
// Save size of DMUS_IO_STYLENOTE structure
dwSize = sizeof(DMUS_IO_STYLENOTE);
hr = pIStream->Write( &dwSize, sizeof(DWORD), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(DWORD) )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save all of the notes
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_NOTE )
{
pNote = (CDMStyleNote*)pEvent;
// Prepare DMUS_IO_STYLENOTE structure
memset( &oDMStyleNote, 0, sizeof(DMUS_IO_STYLENOTE) );
oDMStyleNote.mtGridStart = pNote->m_nGridStart;
oDMStyleNote.dwVariation = pNote->m_dwVariation;
oDMStyleNote.nTimeOffset = pNote->m_nTimeOffset;
oDMStyleNote.mtDuration = pNote->m_mtDuration;
oDMStyleNote.wMusicValue = pNote->m_wMusicValue;
oDMStyleNote.bVelocity = pNote->m_bVelocity;
oDMStyleNote.bTimeRange = pNote->m_bTimeRange;
oDMStyleNote.bDurRange = pNote->m_bDurRange;
oDMStyleNote.bVelRange = pNote->m_bVelRange;
oDMStyleNote.bInversionID = pNote->m_bInversionId;
oDMStyleNote.bPlayModeFlags = pNote->m_bPlayModeFlags;
oDMStyleNote.bNoteFlags = pNote->m_bFlags;
// Write DMUS_IO_STYLENOTE structure
hr = pIStream->Write( &oDMStyleNote, sizeof(DMUS_IO_STYLENOTE), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(DMUS_IO_STYLENOTE) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
pEvent = pEvent->GetNext();
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPart::DM_SaveCurveList
HRESULT DirectMusicPart::DM_SaveCurveList( IAARIFFStream* pIRiffStream )
{
CDirectMusicEventItem* pEvent;
CDMStyleCurve* pCurve;
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
WORD dwSize;
DMUS_IO_STYLECURVE oDMStyleCurve;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
ck.ckid = DMUS_FOURCC_CURVE_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
{
hr = E_FAIL;
goto ON_ERROR;
}
// Save size of DMUS_IO_STYLECURVE structure
dwSize = sizeof(DMUS_IO_STYLECURVE);
hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(dwSize) )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save all of the curves
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_CURVE )
{
pCurve = (CDMStyleCurve*)pEvent;
// Prepare DMUS_IO_STYLECURVE structure
memset( &oDMStyleCurve, 0, sizeof(DMUS_IO_STYLECURVE) );
oDMStyleCurve.mtGridStart = pCurve->m_nGridStart;
oDMStyleCurve.dwVariation = pCurve->m_dwVariation;
oDMStyleCurve.nTimeOffset = pCurve->m_nTimeOffset;
oDMStyleCurve.mtDuration = pCurve->m_mtDuration;
oDMStyleCurve.nStartValue = pCurve->m_StartValue;
oDMStyleCurve.nEndValue = pCurve->m_EndValue;
oDMStyleCurve.bEventType = pCurve->m_bEventType;
oDMStyleCurve.bCurveShape = pCurve->m_bCurveShape;
oDMStyleCurve.bCCData = pCurve->m_bCCData;
oDMStyleCurve.mtResetDuration = pCurve->m_mtResetDuration;
oDMStyleCurve.nResetValue = pCurve->m_nResetValue;
oDMStyleCurve.bFlags = pCurve->m_bFlags;
// dx8 stuff
oDMStyleCurve.wParamType = pCurve->m_wParamType;
oDMStyleCurve.wMergeIndex = pCurve->m_wMergeIndex;
// Write DMUS_IO_STYLECURVE structure
hr = pIStream->Write( &oDMStyleCurve, sizeof(DMUS_IO_STYLECURVE), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(DMUS_IO_STYLECURVE) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
pEvent = pEvent->GetNext();
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPart::DM_SaveMarkerList
HRESULT DirectMusicPart::DM_SaveMarkerList( IAARIFFStream* pIRiffStream )
{
CDirectMusicEventItem* pEvent;
CDMStyleMarker* pMarker;
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
WORD dwSize;
DMUS_IO_STYLEMARKER oDMStyleMarker;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
ck.ckid = DMUS_FOURCC_MARKER_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
{
hr = E_FAIL;
goto ON_ERROR;
}
// Save size of DMUS_IO_STYLEMARKER structure
dwSize = sizeof(DMUS_IO_STYLEMARKER);
hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(dwSize) )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save all of the markers
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_MARKER )
{
pMarker = (CDMStyleMarker*)pEvent;
// Prepare DMUS_IO_STYLEMARKER structure
memset( &oDMStyleMarker, 0, sizeof(DMUS_IO_STYLEMARKER) );
oDMStyleMarker.mtGridStart = pMarker->m_nGridStart;
oDMStyleMarker.dwVariation = pMarker->m_dwVariation;
oDMStyleMarker.wMarkerFlags = pMarker->m_wFlags;
// Write DMUS_IO_STYLEMARKER structure
hr = pIStream->Write( &oDMStyleMarker, sizeof(DMUS_IO_STYLEMARKER), &dwBytesWritten );
if( FAILED( hr )
|| dwBytesWritten != sizeof(DMUS_IO_STYLEMARKER) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
pEvent = pEvent->GetNext();
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPart::DM_SaveAnticipationList
HRESULT DirectMusicPart::DM_SaveAnticipationList( IAARIFFStream* pIRiffStream )
{
CDirectMusicEventItem* pEvent;
CDMStyleAnticipation* pAnticipation;
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
WORD dwSize;
DMUS_IO_STYLE_ANTICIPATION oDMStyleAnticipation;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
ck.ckid = DMUS_FOURCC_ANTICIPATION_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
{
hr = E_FAIL;
goto ON_ERROR;
}
// Save size of DMUS_IO_STYLE_ANTICIPATION structure
dwSize = sizeof(DMUS_IO_STYLE_ANTICIPATION);
hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
if( FAILED( hr ) || dwBytesWritten != sizeof(dwSize) )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save all of the anticipations
pEvent = EventList.GetHead();
while( pEvent )
{
if( pEvent->m_dwEventTag == DMUS_EVENT_ANTICIPATION )
{
pAnticipation = (CDMStyleAnticipation*)pEvent;
// Prepare DMUS_IO_STYLE_ANTICIPATION structure
memset( &oDMStyleAnticipation, 0, sizeof(DMUS_IO_STYLE_ANTICIPATION) );
oDMStyleAnticipation.mtGridStart = pAnticipation->m_nGridStart;
oDMStyleAnticipation.dwVariation = pAnticipation->m_dwVariation;
oDMStyleAnticipation.nTimeOffset = pAnticipation->m_nTimeOffset;
oDMStyleAnticipation.bTimeRange = pAnticipation->m_bTimeRange;
// Write DMUS_IO_STYLE_ANTICIPATION structure
hr = pIStream->Write( &oDMStyleAnticipation, sizeof(DMUS_IO_STYLE_ANTICIPATION), &dwBytesWritten );
if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLE_ANTICIPATION) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
pEvent = pEvent->GetNext();
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPart::DM_SaveResolutionList
HRESULT DirectMusicPart::DM_SaveResolutionList( IAARIFFStream* pIRiffStream )
{
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwBytesWritten;
WORD dwSize;
DMUS_IO_STYLERESOLUTION oDMStyleResolution;
TListItem<DMUS_IO_STYLERESOLUTION>* pScan = m_ResolutionList.GetHead();
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
ck.ckid = DMUS_FOURCC_RESOLUTION_CHUNK;
if( pIRiffStream->CreateChunk( &ck, 0 ) != 0)
{
hr = E_FAIL;
goto ON_ERROR;
}
// Save size of DMUS_IO_STYLERESOLUTION structure
dwSize = sizeof(DMUS_IO_STYLERESOLUTION);
hr = pIStream->Write( &dwSize, sizeof(dwSize), &dwBytesWritten );
if( FAILED( hr ) || dwBytesWritten != sizeof(dwSize) )
{
hr = E_FAIL;
goto ON_ERROR;
}
// Now save all of the resolutions
for(; pScan; pScan = pScan->GetNext() )
{
// Prepare DMUS_IO_STYLERESOLUTION structure
oDMStyleResolution = pScan->GetItemValue();
// Write DMUS_IO_STYLERESOLUTION structure
hr = pIStream->Write( &oDMStyleResolution, sizeof(DMUS_IO_STYLERESOLUTION), &dwBytesWritten );
if( FAILED( hr ) || dwBytesWritten != sizeof(DMUS_IO_STYLERESOLUTION) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
if( pIRiffStream->Ascend(&ck, 0) != 0 )
{
hr = E_FAIL;
goto ON_ERROR;
}
ON_ERROR:
pIStream->Release();
return hr;
}
HRESULT CDMStyle::GetPatternStream(WCHAR* wszName, DWORD dwPatternType, IStream** ppStream)
{
V_PTRPTR_WRITE(ppStream);
TListItem<CDirectMusicPattern*>* pPattern = NULL;
switch (dwPatternType)
{
case DMUS_STYLET_PATTERN:
pPattern = m_StyleInfo.m_PatternList.GetHead();
break;
case DMUS_STYLET_MOTIF:
pPattern = m_StyleInfo.m_MotifList.GetHead();
break;
// case for melody fragments...
}
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
if (pPattern->GetItemValue()->m_strName == wszName)
break;
}
if (pPattern != NULL)
{
// Create a stream
IStream *pIPatternStream;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pIPatternStream);
if (SUCCEEDED(hr))
{
// Persist the pattern to the stream
pPattern->GetItemValue()->Save(pIPatternStream);
// Return the stream
*ppStream = pIPatternStream;
}
return hr;
}
else
{
return S_FALSE;
}
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetMotif | Creates a segment containing
the named motif.
@rdesc Returns one of the following:
@flag S_OK | Success.
@flag S_FALSE | No motif with the given name.
@flag E_POINTER | <p ppSegment> is not a valid address.
@comm Searches the Style's list of motifs for one whose name matches <p wszName>. If one
is found, a segment is created containing a Motif track. The track references the Style as
its associated style and the motif as its pattern.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::GetMotif(
WCHAR* pwszName, // @parm The name of the motif to be retrieved.
IDirectMusicSegment** ppSegment // @parm A segment containing the named motif.
)
{
V_PTR_READ(pwszName,1);
V_PTRPTR_WRITE(ppSegment);
String str = pwszName;
EnterCriticalSection( &m_CriticalSection );
TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_MotifList.GetHead();
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
if (pPattern->GetItemValue()->m_strName == str)
break;
}
if (pPattern != NULL)
{
// AddRef the style
((IDirectMusicStyle*)this)->AddRef();
// create a segment containing a motif track
IUnknown* pIUSegment;
// make a motif with the given number of repeats
CreateMotifSegment(pPattern->GetItemValue(), &pIUSegment, 0);
HRESULT hr = pIUSegment->QueryInterface(IID_IDirectMusicSegment, (void**)ppSegment);
pIUSegment->Release();
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
else
{
LeaveCriticalSection( &m_CriticalSection );
return S_FALSE;
}
}
HRESULT STDMETHODCALLTYPE CDMStyle::EnumPartGuid(
DWORD dwIndex, WCHAR* wszName, DWORD dwPatternType, GUID& rGuid)
{
HRESULT hr = S_OK;
TListItem<CDirectMusicPattern*>* pPattern = NULL;
switch (dwPatternType)
{
case DMUS_STYLET_PATTERN:
pPattern = m_StyleInfo.m_PatternList.GetHead();
break;
case DMUS_STYLET_MOTIF:
pPattern = m_StyleInfo.m_MotifList.GetHead();
break;
// case for melody fragments...
}
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
if (pPattern->GetItemValue()->m_strName == wszName)
break;
}
if (pPattern != NULL)
{
TListItem<DirectMusicPartRef>* pPartRef = pPattern->GetItemValue()->m_PartRefList.GetHead();
for (DWORD dw = 0; dw < dwIndex; dw++)
{
if (pPartRef) pPartRef = pPartRef->GetNext();
}
if (pPartRef)
{
rGuid = pPartRef->GetItemValue().m_pDMPart->m_guidPartID;
hr = S_OK;
}
else
{
hr = S_FALSE;
}
}
else
{
hr = DMUS_E_NOT_FOUND;
}
return hr;
}
// NOTE: assumes wszName is preallocated to MAX_PATH
HRESULT STDMETHODCALLTYPE CDMStyle::EnumPattern(
DWORD dwIndex,
DWORD dwPatternType,
WCHAR *wszName
)
{
HRESULT hr = E_INVALIDARG;
switch (dwPatternType)
{
case DMUS_STYLET_PATTERN:
hr = EnumRegularPattern(dwIndex, wszName);
break;
case DMUS_STYLET_MOTIF:
hr = EnumMotif(dwIndex, wszName);
break;
// case for melody fragments...
}
return hr;
}
HRESULT STDMETHODCALLTYPE CDMStyle::EnumRegularPattern(
DWORD dwIndex,
WCHAR *wszName
)
{
V_PTR_WRITE(wszName, 1);
TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
for (DWORD dw = 0; pPattern != NULL; pPattern = pPattern->GetNext(), dw++)
{
if (dw == dwIndex)
break;
}
HRESULT hr = S_OK;
if (pPattern != NULL)
{
if (pPattern->GetItemValue()->m_strName.GetLength() < MAX_PATH)
{
wcscpy(wszName, pPattern->GetItemValue()->m_strName);
hr = S_OK;
}
else
{
for (int i = 0; i < (MAX_PATH - 1); i++)
{
wszName[i] = pPattern->GetItemValue()->m_strName[i];
}
wszName[MAX_PATH - 1] = L'\0';
hr = DMUS_S_STRING_TRUNCATED;
}
}
else
{
hr = S_FALSE;
}
return hr;
}
// enum the list of start times common to all patterns referenced by the associated type, level, and range.
// (i.e. if more than one such pattern, skip start times not comon to all)
// return S_FALSE when no start times remain.
HRESULT STDMETHODCALLTYPE CDMStyle::EnumStartTime(DWORD dwIndex, DMUS_COMMAND_PARAM* pCommand, MUSIC_TIME* pmtStartTime)
{
int nRange = (int)pCommand->bGrooveRange / 2;
int nLow = (int)pCommand->bGrooveLevel - nRange;
if (nLow < 0) nLow = 0;
int nHigh = (int)pCommand->bGrooveLevel + nRange;
if (nHigh > 100) nHigh = 100;
TList<CDirectMusicPattern*> MatchList;
int nMatchCount = 0;
TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
if (!pPattern) return S_FALSE;
TListItem<MUSIC_TIME>** apStartTimes = NULL;
HRESULT hr = S_OK;
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
CDirectMusicPattern*& rpPattern = pPattern->GetItemValue();
if (rpPattern->m_bGrooveBottom <= (BYTE)nHigh &&
rpPattern->m_bGrooveTop >= (BYTE)nLow)
{
if ( (pCommand->bCommand == DMUS_COMMANDT_FILL &&
rpPattern->m_wEmbellishment == EMB_FILL) ||
(pCommand->bCommand == DMUS_COMMANDT_INTRO &&
rpPattern->m_wEmbellishment == EMB_INTRO) ||
(pCommand->bCommand == DMUS_COMMANDT_BREAK &&
rpPattern->m_wEmbellishment == EMB_BREAK) ||
(pCommand->bCommand == DMUS_COMMANDT_END &&
rpPattern->m_wEmbellishment == EMB_END) ||
(pCommand->bCommand == DMUS_COMMANDT_GROOVE &&
rpPattern->m_wEmbellishment == EMB_NORMAL) ||
(rpPattern->m_wEmbellishment & EMB_USER_DEFINED &&
(rpPattern->m_wEmbellishment >> 8) == (WORD)pCommand->bCommand) )
{
if (rpPattern && rpPattern->m_StartTimeList.GetHead())
{
TListItem<CDirectMusicPattern*>* pNewPattern;
pNewPattern = new TListItem<CDirectMusicPattern*>(rpPattern);
if (!pNewPattern)
{
hr = E_OUTOFMEMORY;
break;
}
MatchList.AddHead(pNewPattern);
nMatchCount++;
}
}
}
}
if (S_OK == hr)
{
if (nMatchCount)
{
apStartTimes = new TListItem<MUSIC_TIME>*[nMatchCount];
if (!apStartTimes) hr = E_OUTOFMEMORY;
}
else hr = S_FALSE;
}
if (S_OK == hr)
{
MUSIC_TIME mtMin = 0, mtMax = 0;
TListItem<CDirectMusicPattern*>* pMatch = MatchList.GetHead();
// initialize the array of start time pointers
for (int i = 0; pMatch; pMatch = pMatch->GetNext(), i++)
{
apStartTimes[i] = pMatch->GetItemValue()->m_StartTimeList.GetHead();
}
for (DWORD dw = 0; S_OK == hr && dw <= dwIndex; dw++)
{
// get the min and max times for the first item in each list
mtMin = mtMax = apStartTimes[0]->GetItemValue();
for (int i = 0; i < nMatchCount; i++)
{
if (apStartTimes[i]->GetItemValue() < mtMin)
{
mtMin = apStartTimes[i]->GetItemValue();
}
if (apStartTimes[i]->GetItemValue() > mtMax)
{
mtMax = apStartTimes[i]->GetItemValue();
}
}
// sync up all the start times by making sure max == min.
// set hr to S_FALSE if any lists run out.
while (S_OK == hr && mtMax != mtMin)
{
// We'll only be changing values less than max, so the
// new min will be not greater than that.
MUSIC_TIME mtNewMin = mtMax;
for (i = 0; i < nMatchCount; i++)
{
if (apStartTimes[i]->GetItemValue() < mtMax)
{
apStartTimes[i] = apStartTimes[i]->GetNext();
if (!apStartTimes[i])
{
hr = S_FALSE;
break;
}
if (apStartTimes[i]->GetItemValue() < mtNewMin)
{
mtNewMin = apStartTimes[i]->GetItemValue();
}
if (apStartTimes[i]->GetItemValue() > mtMax)
{
mtMax = apStartTimes[i]->GetItemValue();
}
}
}
// mtTempMin is the new min, since every instance of the
// old min was less than max and therefore changed.
mtMin = mtNewMin;
}
if (S_OK != hr) break;
// if we're going to loop again, increment all the start time pointers.
if (dw < dwIndex)
{
for (i = 0; i < nMatchCount; i++)
{
apStartTimes[i] = apStartTimes[i]->GetNext();
// set hr to S_FALSE if any lists run out.
if (!apStartTimes[i])
{
hr = S_FALSE;
break;
}
}
}
}
// if hr is S_OK, max should equal min, so return one of them.
if (S_OK == hr) *pmtStartTime = mtMax;
delete [] apStartTimes;
}
return hr;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumMotif | Retrieves the name of the
motif indexed by <p dwIndex>.
@rdesc Returns one of the following
@flag S_OK | Success
@flag S_FALSE | No motif at the given location
@flag DMUS_S_STRING_TRUNCATED | The length of the motif name is not less than MAX_PATH
@flag E_POINTER | <p pwszName> is not a valid address
@comm Searches the Style's list of motifs for the one at the location given by <p dwIndex>.
If there is such a motif, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
it is truncated. This assumes that <p pwszName>
has been pre-allocated to have a length of at least MAX_PATH.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::EnumMotif(
DWORD dwIndex, // @parm An index into the Style's motif list (0-based).
WCHAR *pwszName // @parm The motif name to be returned.
)
{
V_BUFPTR_WRITE(pwszName,MAX_PATH);
TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_MotifList.GetHead();
for (DWORD dw = 0; pPattern != NULL; pPattern = pPattern->GetNext(), dw++)
{
if (dw == dwIndex)
break;
}
HRESULT hr = S_OK;
if (pPattern != NULL)
{
if (pPattern->GetItemValue()->m_strName.GetLength() < MAX_PATH)
{
wcscpy(pwszName, pPattern->GetItemValue()->m_strName);
hr = S_OK;
}
else
{
for (int i = 0; i < (MAX_PATH - 1); i++)
{
pwszName[i] = pPattern->GetItemValue()->m_strName[i];
}
pwszName[MAX_PATH - 1] = L'\0';
hr = DMUS_S_STRING_TRUNCATED;
}
}
else
{
hr = S_FALSE;
}
return hr;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetChordMap | Retrieves the named ChordMap.
@rdesc Returns one of the following:
@flag S_OK | Success.
@flag S_FALSE | No ChordMap with the given name.
@flag E_POINTER | ppChordMap not a valid pointer
@comm Searches the Style's list of personalities for one whose name matches <p wszName>. If one
is found, it is returned.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::GetChordMap(
WCHAR* pwszName, // @parm The name of the ChordMap to be retrieved.
IDirectMusicChordMap** ppChordMap // @parm The named ChordMap.
)
{
V_PTR_READ(pwszName,1);
V_PTRPTR_WRITE(ppChordMap);
String str1 = pwszName;
TListItem<IDirectMusicChordMap*>* pPersItem = m_StyleInfo.m_PersList.GetHead();
IDirectMusicChordMap *pPers = NULL;
for (; pPersItem != NULL; pPersItem = pPersItem->GetNext())
{
HRESULT hr = S_OK;
String str2;
pPers = pPersItem->GetItemValue();
IDirectMusicObject *pIObject = NULL;
DMUS_OBJECTDESC Desc; // Descriptor.
if (SUCCEEDED(hr = pPers->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
{
if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
{
if (Desc.dwValidData & DMUS_OBJ_NAME)
{
str2 = Desc.wszName;
if (str1 == str2)
{
pIObject->Release();
break;
}
}
else hr = E_FAIL;
}
pIObject->Release();
}
if (!SUCCEEDED(hr))
{
return hr;
}
}
if (pPersItem != NULL)
{
// AddRef the ChordMap
pPers->AddRef();
// Return it.
*ppChordMap = pPers;
return S_OK;
}
else
{
return S_FALSE;
}
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumChordMap | Retrieves the name of the
ChordMap indexed by <p dwIndex>.
@rdesc Returns one of the following
@flag S_OK | Success
@flag S_FALSE | No ChordMap at the given location
@flag DMUS_S_STRING_TRUNCATED | The length of the ChordMap name is not less than MAX_PATH
@flag E_POINTER | <p pwszName> is not a valid address
@flag DMUS_E_TYPE_UNSUPPORTED | The ChordMap's descriptor doesn't support DMUS_OBJ_NAME
@comm Searches the Style's list of chord maps for the one at the location given by <p dwIndex>.
If there is such a ChordMap, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
it is truncated. This assumes that <p pwszName>
has been pre-allocated to have a length of at least MAX_PATH.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::EnumChordMap(
DWORD dwIndex, // @parm An index into the Style's ChordMap list (0-based).
WCHAR *pwszName // @parm The ChordMap name to be returned.
)
{
V_BUFPTR_WRITE(pwszName,MAX_PATH);
TListItem<IDirectMusicChordMap*>* pPers = m_StyleInfo.m_PersList.GetHead();
for (DWORD dw = 0; pPers != NULL; pPers = pPers->GetNext(), dw++)
{
if (dw == dwIndex)
break;
}
if (pPers != NULL)
{
HRESULT hr = S_OK;
IDirectMusicChordMap* pChordMap = pPers->GetItemValue();
IDirectMusicObject *pIObject = NULL;
DMUS_OBJECTDESC Desc; // Descriptor.
if (SUCCEEDED(hr = pChordMap->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
{
if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
{
if (Desc.dwValidData & DMUS_OBJ_NAME)
{
if (wcslen(Desc.wszName) < MAX_PATH)
{
wcscpy(pwszName, Desc.wszName);
}
else
{
for (int i = 0; i < (MAX_PATH - 1); i++)
{
pwszName[i] = Desc.wszName[i];
}
pwszName[MAX_PATH - 1] = L'\0';
hr = DMUS_S_STRING_TRUNCATED;
}
}
else
{
hr = DMUS_E_TYPE_UNSUPPORTED;
}
}
pIObject->Release();
}
return hr;
}
else
{
return S_FALSE;
}
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetDefaultChordMap | Gets the style's
default ChordMap.
@rdesc Returns one of the following
@flag S_OK | Success.
@flag E_POINTER | <p ppChordMap> not a valid pointer.
@flag S_FALSE | Style does not have a default ChordMap.
@comm Returns the Style's default ChordMap in <p ppChordMap>.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::GetDefaultChordMap(
IDirectMusicChordMap **ppChordMap // @parm The ChordMap to be returned.
)
{
V_PTRPTR_WRITE(ppChordMap);
if(m_StyleInfo.m_pDefaultPers == NULL)
{
return S_FALSE;
}
*ppChordMap = m_StyleInfo.m_pDefaultPers;
(*ppChordMap)->AddRef();
return S_OK;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetBand | Retrieves the named band.
@rdesc Returns one of the following
@flag S_OK | Success
@flag E_POINTER | ppBand not a valid pointer
@flag S_FALSE | No band with the given name
@comm Searches the Style's list of bands for one whose name matches <p pwszName>. If one
is found, it is returned in <p ppBand>.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::GetBand(
WCHAR *pwszName, // @parm The name of the band to be retrieved.
IDirectMusicBand **ppBand // @parm The named band.
)
{
V_PTR_READ(pwszName,1);
V_PTRPTR_WRITE(ppBand);
String str1 = pwszName;
TListItem<IDirectMusicBand*>* pBandItem = m_StyleInfo.m_BandList.GetHead();
IDirectMusicBand *pBand = NULL;
for (; pBandItem != NULL; pBandItem = pBandItem->GetNext())
{
HRESULT hr = S_OK;
String str2;
pBand = pBandItem->GetItemValue();
IDirectMusicObject *pIObject = NULL;
DMUS_OBJECTDESC Desc; // Descriptor.
Desc.dwSize = sizeof(Desc);
if (SUCCEEDED(hr = pBand->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
{
if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
{
if (Desc.dwValidData & DMUS_OBJ_NAME)
{
str2 = Desc.wszName;
if (str1 == str2)
{
pIObject->Release();
break;
}
}
else hr = E_FAIL;
}
pIObject->Release();
}
if (!SUCCEEDED(hr))
{
return hr;
}
}
if (pBandItem != NULL)
{
// AddRef the band
pBand->AddRef();
// Return it.
*ppBand = pBand;
return S_OK;
}
else
{
return S_FALSE;
}
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | EnumBand | Retrieves the name of the
band indexed by <p dwIndex>.
@rdesc Returns one of the following
@flag S_OK | Success
@flag S_FALSE | No band at the given location
@flag DMUS_S_STRING_TRUNCATED | The length of the band name is not less than MAX_PATH
@flag E_POINTER | <p pwszName> is not a valid address
@flag DMUS_E_TYPE_UNSUPPORTED | The band's descriptor doesn't support DMUS_OBJ_NAME
@comm Searches the Style's list of bands for the one at the location given by <p dwIndex>.
If there is such a band, its name is returned in <p pwszName>; if it is not less than MAX_PATH,
it is truncated. This assumes that <p pwszName>
has been pre-allocated to have a length of at least MAX_PATH.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::EnumBand(
DWORD dwIndex, // @parm An index into the Style's band list (0-based).
WCHAR *pwszName// @parm The band name to be returned.
)
{
V_BUFPTR_WRITE(pwszName,MAX_PATH);
TListItem<IDirectMusicBand*>* pBandItem = m_StyleInfo.m_BandList.GetHead();
for (DWORD dw = 0; pBandItem != NULL; pBandItem = pBandItem->GetNext(), dw++)
{
if (dw == dwIndex)
break;
}
if (pBandItem != NULL)
{
HRESULT hr = S_OK;
IDirectMusicBand* pBand = pBandItem->GetItemValue();
IDirectMusicObject *pIObject = NULL;
DMUS_OBJECTDESC Desc; // Descriptor.
Desc.dwSize = sizeof(Desc);
if (SUCCEEDED(hr = pBand->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
{
if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
{
if (Desc.dwValidData & DMUS_OBJ_NAME)
{
if (wcslen(Desc.wszName) < MAX_PATH)
{
wcscpy(pwszName, Desc.wszName);
}
else
{
for (int i = 0; i < (MAX_PATH - 1); i++)
{
pwszName[i] = Desc.wszName[i];
}
pwszName[MAX_PATH - 1] = L'\0';
hr = DMUS_S_STRING_TRUNCATED;
}
}
else
{
hr = DMUS_E_TYPE_UNSUPPORTED;
}
}
pIObject->Release();
}
return hr;
}
else
{
return S_FALSE;
}
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetDefaultBand | Gets the style's default band
@rdesc Returns one of the following
@flag S_OK | Success
@flag E_POINTER | ppBand not a valid pointer
@flag S_FALSE | Style does not have a default band
@comm Returns the Style's default band in <p ppBand>.
*/
HRESULT STDMETHODCALLTYPE CDMStyle::GetDefaultBand(
IDirectMusicBand **ppBand // @parm The band to be returned.
)
{
V_PTRPTR_WRITE(ppBand);
if(m_StyleInfo.m_pDefaultBand == NULL)
{
return S_FALSE;
}
*ppBand = m_StyleInfo.m_pDefaultBand;
(*ppBand)->AddRef();
return S_OK;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetTimeSignature | Retrieves the Style's
time signature.
@rdesc Returns one of the following
@flag S_OK | Success
@flag E_POINTER | <p pTimeSig> is not a valid address
@comm Fills in a <t DMUS_TIMESIGNATURE> structure with data from the Style's time signature.
*/
HRESULT CDMStyle::GetTimeSignature(
DMUS_TIMESIGNATURE* pTimeSig // @parm A pre-allocated <t DMUS_TIMESIGNATURE> structure.
)
{
V_PTR_WRITE(pTimeSig, sizeof(DMUS_TIMESIGNATURE) );
pTimeSig->mtTime = 0;
pTimeSig->wGridsPerBeat = m_StyleInfo.m_TimeSignature.m_wGridsPerBeat;
pTimeSig->bBeatsPerMeasure = m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure;
pTimeSig->bBeat = m_StyleInfo.m_TimeSignature.m_bBeat;
return S_OK;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetEmbellishmentLength | Finds the shortest
and longest lengths for patterns of the specified embellishment type and groove level.
@rdesc Returns one of the following
@flag S_OK | Success
@flag S_FALSE | There are no patterns of the specified type and groove level
@flag E_POINTER | Either <p pdwMin> or <p pdwMax> is not a valid address
@comm Finds all patterns in the Style with embellishment type given by <p bType> and groove
range that includes <p bLevel>. The length of the longest such pattern is returned in
<p pdwMax>, and the length of the shortest pattern is returned in <p pdwMin>.
Note that <p bLevel> is ignored for non-groove embellishments.
*/
HRESULT CDMStyle::GetEmbellishmentLength(
DWORD dwType, // @parm An embellishment type.
DWORD dwLevel, // @parm A groove level (1 - 100).
DWORD* pdwMin, // @parm Length of the shortest pattern of the specified type
// and groove level.
DWORD* pdwMax // @parm Length of the longest pattern of the specified type
// and groove level.
)
{
V_PTR_WRITE(pdwMin, sizeof(DWORD) );
V_PTR_WRITE(pdwMax, sizeof(DWORD) );
TListItem<CDirectMusicPattern*>* pPattern = m_StyleInfo.m_PatternList.GetHead();
*pdwMin = *pdwMax = 0;
if (!pPattern) return S_FALSE;
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
CDirectMusicPattern*& rpPattern = pPattern->GetItemValue();
switch (dwType)
{
// need to use == rather than & for all of these because of user-defined embellishments
case DMUS_COMMANDT_FILL:
if (rpPattern->m_wEmbellishment == EMB_FILL)
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
break;
case DMUS_COMMANDT_INTRO:
if (rpPattern->m_wEmbellishment == EMB_INTRO)
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
break;
case DMUS_COMMANDT_BREAK:
if (rpPattern->m_wEmbellishment == EMB_BREAK)
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
break;
case DMUS_COMMANDT_END:
if (rpPattern->m_wEmbellishment == EMB_END)
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
break;
case DMUS_COMMANDT_GROOVE: // need to use == rather than & since EMB_NORMAL == 0
if ((rpPattern->m_wEmbellishment == EMB_NORMAL) &&
rpPattern->m_bGrooveBottom <= (BYTE)dwLevel &&
rpPattern->m_bGrooveTop >= (BYTE)dwLevel)
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
break;
default: // check for user-defined embellishment
if ( (rpPattern->m_wEmbellishment & EMB_USER_DEFINED) &&
(rpPattern->m_wEmbellishment >> 8) == (WORD)dwType )
{
if (rpPattern->m_wNumMeasures > *pdwMax)
*pdwMax = rpPattern->m_wNumMeasures;
if (rpPattern->m_wNumMeasures < *pdwMin || *pdwMin == 0)
*pdwMin = rpPattern->m_wNumMeasures;
}
}
}
if (!*pdwMin || !*pdwMax) return S_FALSE;
return S_OK;
}
/*
@method:(EXTERNAL) HRESULT | IDirectMusicStyle | GetTempo | Retrieves the recommended tempo
of the style.
@rdesc Returns one of the following
@flag S_OK | Success
@flag E_POINTER | <p pTempo> is not a valid pointer
*/
HRESULT CDMStyle::GetTempo
(
double* pTempo // @parm The recommended tempo of the style.
)
{
V_PTR_WRITE(pTempo, sizeof(double) );
*pTempo = m_StyleInfo.m_dblTempo;
return S_OK;
}
CDirectMusicEventItem* CDirectMusicEventItem::MergeSort(DirectMusicTimeSig& TimeSig)
{
if (m_pNext != NULL)
{
CDirectMusicEventItem *pList1, *pList2;
Divide(pList1, pList2);
return pList1->MergeSort(TimeSig)->Merge(pList2->MergeSort(TimeSig), TimeSig);
}
return this;
}
void CDirectMusicEventItem::Divide(CDirectMusicEventItem*& pHead1, CDirectMusicEventItem*& pHead2)
{
CDirectMusicEventItem *pCurrent = this, *pTail1 = NULL, *pTail2 = NULL;
do
{
pHead1 = pCurrent;
pCurrent = (CDirectMusicEventItem *)pCurrent->m_pNext;
pHead1->m_pNext = pTail1;
pTail1 = pHead1;
if (pCurrent != NULL)
{
pHead2 = pCurrent;
pCurrent = (CDirectMusicEventItem *)pCurrent->m_pNext;
pHead2->m_pNext = pTail2;
pTail2 = pHead2;
}
} while (pCurrent != NULL);
}
CDirectMusicEventItem* CDirectMusicEventItem::Merge(CDirectMusicEventItem* pOtherList, DirectMusicTimeSig& TimeSig)
{
if (!pOtherList) return this;
CDirectMusicEventItem
*pThisList = this, *pResultHead = NULL, *pResultTail = NULL, *pMergeItem = NULL;
while (pThisList && pOtherList)
{
if (pThisList->m_nGridStart < pOtherList->m_nGridStart ||
// Markers need to precede other events occuring at the same time
((pThisList->m_dwEventTag == DMUS_EVENT_MARKER) &&
(pThisList->m_nGridStart) == (pOtherList->m_nGridStart)) ||
// Within a grid, sort by time offset
((pThisList->m_nGridStart) == (pOtherList->m_nGridStart) &&
(pThisList->m_nTimeOffset < pOtherList->m_nTimeOffset)) )
{
pMergeItem = pThisList;
pThisList = pThisList->GetNext();
}
else
{
pMergeItem = pOtherList;
pOtherList = pOtherList->GetNext();
}
pMergeItem->SetNext(NULL);
if (!pResultTail)
{
pResultHead = pResultTail = pMergeItem;
}
else
{
pResultTail->SetNext(pMergeItem);
pResultTail = pMergeItem;
}
}
if (pThisList) pResultTail->SetNext(pThisList);
else pResultTail->SetNext(pOtherList);
return pResultHead;
}
CDirectMusicEventItem* CDirectMusicEventItem::ReviseEvent(short nGrid,
short nOffset,
DWORD* pdwVariation,
DWORD* pdwID,
WORD* pwMusic,
BYTE* pbPlaymode,
BYTE* pbFlags)
{
CDirectMusicEventItem* pEvent = NULL;
switch (m_dwEventTag)
{
case DMUS_EVENT_NOTE:
pEvent = ((CDMStyleNote*)this)->ReviseEvent(nGrid, nOffset, pdwVariation, pdwID, pwMusic, pbPlaymode, pbFlags);
break;
case DMUS_EVENT_CURVE:
pEvent = ((CDMStyleCurve*)this)->ReviseEvent(nGrid, nOffset);
break;
case DMUS_EVENT_MARKER:
pEvent = ((CDMStyleMarker*)this)->ReviseEvent(nGrid);
break;
case DMUS_EVENT_ANTICIPATION:
pEvent = ((CDMStyleAnticipation*)this)->ReviseEvent(nGrid);
break;
}
return pEvent;
}
CDirectMusicEventItem* CDMStyleNote::ReviseEvent(short nGrid,
short nOffset,
DWORD* pdwVariation,
DWORD* pdwID,
WORD* pwMusic,
BYTE* pbPlaymode,
BYTE* pbFlags)
{
CDMStyleNote* pNoteEvent = new CDMStyleNote;
if (pNoteEvent)
{
pNoteEvent->m_nGridStart = nGrid;
pNoteEvent->m_nTimeOffset = nOffset;
pNoteEvent->m_dwVariation = pdwVariation ? *pdwVariation : m_dwVariation;
pNoteEvent->m_dwEventTag = m_dwEventTag;
pNoteEvent->m_mtDuration = m_mtDuration;
pNoteEvent->m_bVelocity = m_bVelocity;
pNoteEvent->m_bTimeRange = m_bTimeRange;
pNoteEvent->m_bDurRange = m_bDurRange;
pNoteEvent->m_bVelRange = m_bVelRange;
pNoteEvent->m_bInversionId = m_bInversionId;
pNoteEvent->m_bPlayModeFlags = pbPlaymode ? *pbPlaymode : m_bPlayModeFlags;
pNoteEvent->m_wMusicValue = pwMusic ? *pwMusic : m_wMusicValue;
pNoteEvent->m_dwFragmentID = pdwID ? *pdwID : m_dwFragmentID;
pNoteEvent->m_bFlags = pbFlags ? *pbFlags : 0;
}
return pNoteEvent;
}
CDirectMusicEventItem* CDMStyleCurve::ReviseEvent(short nGrid, short nOffset)
{
CDMStyleCurve* pCurveEvent = new CDMStyleCurve;
if (pCurveEvent)
{
pCurveEvent->m_nGridStart = nGrid;
pCurveEvent->m_nTimeOffset = nOffset;
pCurveEvent->m_dwVariation = 0xffffffff;
pCurveEvent->m_dwEventTag = m_dwEventTag;
pCurveEvent->m_mtDuration = m_mtDuration;
pCurveEvent->m_mtResetDuration = m_mtResetDuration;
pCurveEvent->m_StartValue = m_StartValue;
pCurveEvent->m_EndValue = m_EndValue;
pCurveEvent->m_nResetValue = m_nResetValue;
pCurveEvent->m_bEventType = m_bEventType;
pCurveEvent->m_bCurveShape = m_bCurveShape;
pCurveEvent->m_bCCData = m_bCCData;
pCurveEvent->m_bFlags = m_bFlags;
pCurveEvent->m_wParamType = m_wParamType;
pCurveEvent->m_wMergeIndex = m_wMergeIndex;
}
return pCurveEvent;
}
CDirectMusicEventItem* CDMStyleMarker::ReviseEvent(short nGrid)
{
CDMStyleMarker* pMarkerEvent = new CDMStyleMarker;
if (pMarkerEvent)
{
pMarkerEvent->m_nGridStart = nGrid;
pMarkerEvent->m_nTimeOffset = 0;
pMarkerEvent->m_dwVariation = 0xffffffff;
pMarkerEvent->m_dwEventTag = m_dwEventTag;
pMarkerEvent->m_wFlags = m_wFlags;
}
return pMarkerEvent;
}
CDirectMusicEventItem* CDMStyleAnticipation::ReviseEvent(short nGrid)
{
CDMStyleAnticipation* pAnticipationEvent = new CDMStyleAnticipation;
if (pAnticipationEvent)
{
pAnticipationEvent->m_nGridStart = nGrid;
pAnticipationEvent->m_nTimeOffset = m_nTimeOffset;
pAnticipationEvent->m_dwVariation = 0xffffffff;
pAnticipationEvent->m_dwEventTag = m_dwEventTag;
pAnticipationEvent->m_bTimeRange = m_bTimeRange;
}
return pAnticipationEvent;
}
CDirectMusicEventList::~CDirectMusicEventList()
{
CDirectMusicEventItem *pEvent;
while (pEvent = RemoveHead())
{
delete pEvent;
}
}
void CDirectMusicEventList::MergeSort(DirectMusicTimeSig& TimeSig)
{
if (m_pHead != NULL && m_pHead->GetNext() != NULL)
m_pHead = ((CDirectMusicEventItem *)m_pHead)->MergeSort(TimeSig);
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern constructor
CDirectMusicPattern::CDirectMusicPattern( DirectMusicTimeSig* pTimeSig, BOOL fMotif ) :
m_wNumMeasures(1),
m_cRef(1),
m_wID(0),
m_bGrooveBottom(1),
m_bGrooveTop(100),
m_bDestGrooveBottom(1),
m_bDestGrooveTop(100),
m_pRhythmMap(NULL),
// m_pSwitchPoints(NULL),
m_fSettings(FALSE),
m_dwRepeats(0),
m_mtPlayStart(0),
m_mtLoopStart(0),
m_mtLoopEnd(-1),
m_dwResolution(0),
m_pMotifBand(NULL),
m_dwFlags(0)
{
if ( pTimeSig != NULL )
{
m_timeSig = *pTimeSig;
}
// Set defaults
if( fMotif )
{
m_wEmbellishment = EMB_MOTIF;
}
else
{
m_wEmbellishment = EMB_NORMAL;
}
}
CDirectMusicPattern* CDirectMusicPattern::Clone(MUSIC_TIME mtStart, MUSIC_TIME mtEnd, BOOL fMotif)
{
HRESULT hr = S_OK;
CDirectMusicPattern* pNewPattern = new CDirectMusicPattern(&m_timeSig, fMotif);
if (pNewPattern)
{
WORD wMeasureStart = (WORD)m_timeSig.ClocksToMeasure(mtStart);
WORD wMeasureEnd = (WORD)m_timeSig.ClocksToMeasure(mtEnd);
pNewPattern->m_wNumMeasures = wMeasureEnd - wMeasureStart;
pNewPattern->m_cRef = m_cRef;
pNewPattern->m_wID = m_wID;
pNewPattern->m_bGrooveBottom = m_bGrooveBottom;
pNewPattern->m_bGrooveTop = m_bGrooveTop;
pNewPattern->m_bDestGrooveBottom = m_bDestGrooveBottom;
pNewPattern->m_bDestGrooveTop = m_bDestGrooveTop;
pNewPattern->m_fSettings = m_fSettings;
pNewPattern->m_dwRepeats = m_dwRepeats;
pNewPattern->m_strName = m_strName;
pNewPattern->m_dwResolution = m_dwResolution;
pNewPattern->m_dwFlags = m_dwFlags;
if (m_mtPlayStart <= mtStart)
{
pNewPattern->m_mtPlayStart = 0;
}
else
{
pNewPattern->m_mtPlayStart = m_mtPlayStart - mtStart;
}
if (m_mtLoopStart <= mtStart)
{
pNewPattern->m_mtLoopStart = 0;
}
else
{
pNewPattern->m_mtLoopStart = m_mtLoopStart - mtStart;
}
if (m_mtLoopEnd >= (mtEnd - mtStart))
{
pNewPattern->m_mtLoopEnd = mtEnd - mtStart;
}
else if (m_mtLoopEnd < 0)
{
pNewPattern->m_mtLoopEnd = -1;
}
else
{
pNewPattern->m_mtLoopEnd = m_mtLoopEnd - mtStart;
}
pNewPattern->m_pRhythmMap = new DWORD[pNewPattern->m_wNumMeasures];
if (!pNewPattern->m_pRhythmMap)
{
hr = E_FAIL;
goto ON_END;
}
for (int i = 0; i < pNewPattern->m_wNumMeasures; i++)
{
pNewPattern->m_pRhythmMap[i] = m_pRhythmMap[i + wMeasureStart];
}
if (m_pMotifBand)
{
pNewPattern->m_pMotifBand = m_pMotifBand;
pNewPattern->m_pMotifBand->AddRef();
}
TListItem<DirectMusicPartRef>* pPartRefItem = m_PartRefList.GetHead();
int nParts = m_PartRefList.GetCount();
for (i = 0; pPartRefItem && i < nParts; pPartRefItem = pPartRefItem->GetNext(), i++)
{
DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
DirectMusicPart* pPart = rPartRef.m_pDMPart;
if (!pPart)
{
hr = E_FAIL;
goto ON_END;
}
TListItem<DirectMusicPartRef>* pNew = pNewPattern->CreatePart(rPartRef, pPart->m_bPlayModeFlags, pNewPattern->m_wNumMeasures);
if (!pNew)
{
hr = E_FAIL;
goto ON_END;
}
DirectMusicPartRef& rNew = pNew->GetItemValue();
// Now that I've got the new part, I need to add events to its event list based
// on mtStart and mtEnd
CDirectMusicEventItem* pEvent = pPart->EventList.GetHead();
MUSIC_TIME mtClocksInGrid = m_timeSig.ClocksPerGrid();
for (; pEvent; pEvent = pEvent->GetNext())
{
MUSIC_TIME mtEvent = m_timeSig.GridToClocks(pEvent->m_nGridStart);
if (mtEvent >= mtStart && mtEvent < mtEnd)
{
short nNewGrid = (short) ((mtEvent - mtStart) / mtClocksInGrid);
short nNewOffset = (short) (pEvent->m_nTimeOffset + (mtEvent - mtStart) % mtClocksInGrid);
CDirectMusicEventItem* pNewEvent = pEvent->ReviseEvent(nNewGrid, nNewOffset);
if (!pNewEvent)
{
hr = E_FAIL;
goto ON_END;
}
rNew.m_pDMPart->EventList.AddHead(pNewEvent);
}
}
rNew.m_pDMPart->EventList.MergeSort(m_timeSig);
}
}
ON_END:
if (FAILED(hr))
{
if (pNewPattern)
{
delete pNewPattern;
pNewPattern = NULL;
}
}
return pNewPattern;
}
HRESULT CDirectMusicPattern::LoadCurveList( LPSTREAM pStream, LPMMCKINFO pck, short nClickTime)
{
HRESULT hr = S_OK;
DWORD cb;
WORD wCurveSize;
WORD wCurveExtra;
WORD wSubSize;
WORD wSubExtra;
long lSize;
ioSubCurve iSubCurve;
ioCurve iCurve;
WORD wCount;
CDirectMusicEventItem* pCurve = NULL;
lSize = pck->cksize;
// read size of the curve structure
hr = pStream->Read( &wCurveSize, sizeof( wCurveSize ), &cb );
FixBytes( FBT_SHORT, &wCurveSize );
if( FAILED( hr ) || cb != sizeof( wCurveSize ) )
{
hr = E_FAIL;
goto ON_ERR;
}
lSize -= cb;
if( wCurveSize > sizeof( ioCurve ) )
{
wCurveExtra = static_cast<WORD>( wCurveSize - sizeof( ioCurve ) );
wCurveSize = sizeof( ioCurve );
}
else
{
wCurveExtra = 0;
}
// read size of the subcurve structure
hr = pStream->Read( &wSubSize, sizeof( wSubSize ), &cb );
FixBytes( FBT_SHORT, &wSubSize );
if( FAILED( hr ) || cb != sizeof( wSubSize ) )
{
hr = E_FAIL;
goto ON_ERR;
}
lSize -= cb;
if( wSubSize > sizeof( ioSubCurve ) )
{
wSubExtra = static_cast<WORD>( wSubSize - sizeof( ioSubCurve ) );
wSubSize = sizeof( ioSubCurve );
}
else
{
wSubExtra = 0;
}
// now read in the curve
while( lSize > 0 )
{
hr = pStream->Read( &iCurve, wCurveSize, &cb );
FixBytes( FBT_IOCURVE, &iCurve );
if( FAILED( hr ) || cb != wCurveSize )
{
hr = E_FAIL;
goto ON_ERR;
}
lSize -= cb;
if( wCurveExtra > 0 )
{
StreamSeek( pStream, wCurveExtra, STREAM_SEEK_CUR );
lSize -= wCurveExtra;
}
pCurve = new CDMStyleCurve;
if( pCurve == NULL )
{
hr = E_FAIL;
goto ON_ERR;
}
pCurve->m_dwVariation = iCurve.wVariation;
pCurve->m_nGridStart = nClickTime;
((CDMStyleCurve*)pCurve)->m_bEventType = iCurve.bEventType;
((CDMStyleCurve*)pCurve)->m_bCCData = iCurve.bCCData;
DirectMusicPart* pPart = FindPart(iCurve.bVoiceID);
// read subcurve count
hr = pStream->Read( &wCount, sizeof( wCount ), &cb );
FixBytes( FBT_SHORT, &wCount );
if( FAILED( hr ) || cb != sizeof( wCount ) )
{
hr = E_FAIL;
delete pCurve;
goto ON_ERR;
}
lSize -= cb;
for( ; wCount > 0 ; --wCount )
{
// read subcurves
hr = pStream->Read( &iSubCurve, wSubSize, &cb );
FixBytes( FBT_IOSUBCURVE, &iSubCurve );
if( FAILED( hr ) || cb != wSubSize )
{
hr = E_FAIL;
delete pCurve;
goto ON_ERR;
}
lSize -= wSubSize;
if( wSubExtra > 0 )
{
StreamSeek( pStream, wSubExtra, STREAM_SEEK_CUR );
lSize -= wSubExtra;
}
((CDMStyleCurve*)pCurve)->m_bCurveShape = iSubCurve.bCurveType; // shape
if (iSubCurve.nMaxTime < iSubCurve.nMinTime)
{
short n = iSubCurve.nMaxTime;
iSubCurve.nMaxTime = iSubCurve.nMinTime;
iSubCurve.nMinTime = n;
}
if (iSubCurve.nMaxValue < iSubCurve.nMinValue)
{
short n = iSubCurve.nMaxValue;
iSubCurve.nMaxValue = iSubCurve.nMinValue;
iSubCurve.nMinValue = n;
iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
}
if( iSubCurve.fFlipped & CURVE_FLIPTIME )
{
switch( ((CDMStyleCurve*)pCurve)->m_bCurveShape )
{
case DMUS_CURVES_LINEAR:
if( iSubCurve.fFlipped & CURVE_FLIPVALUE )
{
iSubCurve.fFlipped = 0;
}
else
{
iSubCurve.fFlipped = CURVE_FLIPVALUE;
}
break;
case DMUS_CURVES_INSTANT:
iSubCurve.nMinTime = iSubCurve.nMaxTime;
iSubCurve.nMaxTime = iSubCurve.nMinTime + 1;
break;
case DMUS_CURVES_EXP:
((CDMStyleCurve*)pCurve)->m_bCurveShape = DMUS_CURVES_LOG;
iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
// log is the horiz flipped version of vertical flipped exp
break;
case DMUS_CURVES_LOG:
((CDMStyleCurve*)pCurve)->m_bCurveShape = DMUS_CURVES_EXP;
iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
// exp is the horiz flipped version of vertical flipped log
break;
case DMUS_CURVES_SINE:
iSubCurve.fFlipped ^= CURVE_FLIPVALUE; // toggle fFlipped
// because horiz. and vert. flip are the same for sine wave
break;
default:
assert( 0 );
break;
}
}
if( iSubCurve.fFlipped & CURVE_FLIPVALUE )
{
((CDMStyleCurve*)pCurve)->m_StartValue = iSubCurve.nMaxValue;
((CDMStyleCurve*)pCurve)->m_EndValue = iSubCurve.nMinValue;
}
else
{
((CDMStyleCurve*)pCurve)->m_StartValue = iSubCurve.nMinValue;
((CDMStyleCurve*)pCurve)->m_EndValue = iSubCurve.nMaxValue;
}
pCurve->m_nTimeOffset = ConvertTime(iSubCurve.nMinTime);
((CDMStyleCurve*)pCurve)->m_mtDuration = iSubCurve.nMaxTime - iSubCurve.nMinTime;
((CDMStyleCurve*)pCurve)->m_mtResetDuration = 0;
((CDMStyleCurve*)pCurve)->m_nResetValue = 0;
((CDMStyleCurve*)pCurve)->m_bFlags = 0;
if (pPart != NULL)
{
pPart->EventList.AddHead(pCurve);
}
else
{
delete pCurve;
}
pCurve = new CDMStyleCurve;
if( pCurve == NULL )
{
hr = E_FAIL;
goto ON_ERR;
}
pCurve->m_dwVariation = iCurve.wVariation;
pCurve->m_nGridStart = nClickTime;
((CDMStyleCurve*)pCurve)->m_bEventType = iCurve.bEventType;
((CDMStyleCurve*)pCurve)->m_bCCData = iCurve.bCCData;
}
// the loop generates an extra one, and if we don't enter the loop, we never used
// the first one we generated.
delete pCurve;
}
ON_ERR:
return hr;
}
HRESULT CDirectMusicPattern::LoadNoteList( LPSTREAM pStream, LPMMCKINFO pck, short nClickTime)
{
HRESULT hr = S_OK;;
ioNote iNote;
DWORD cb;
WORD wNoteSize;
WORD wExtra;
long lSize;
CDirectMusicEventItem* pNote = NULL;
lSize = pck->cksize;
// read size of the note structure
hr = pStream->Read( &wNoteSize, sizeof( wNoteSize ), &cb );
FixBytes( FBT_SHORT, &wNoteSize );
if( FAILED( hr ) || cb != sizeof( wNoteSize ) )
{
hr = E_FAIL;
goto ON_ERR;
}
lSize -= cb;
if( wNoteSize > sizeof( ioNote ) )
{
wExtra = static_cast<WORD>( wNoteSize - sizeof( ioNote ) );
wNoteSize = sizeof( ioNote );
}
else
{
wExtra = 0;
}
// now read in the notes
while( lSize > 0 )
{
iNote.bPlayMode = 0;
hr = pStream->Read( &iNote, wNoteSize, &cb );
FixBytes( FBT_IONOTE, &iNote );
if( FAILED( hr ) || cb != wNoteSize )
{
hr = E_FAIL;
goto ON_ERR;
}
lSize -= wNoteSize;
if( wExtra > 0 )
{
StreamSeek( pStream, wExtra, STREAM_SEEK_CUR );
lSize -= wExtra;
}
pNote = new CDMStyleNote;
if( pNote != NULL )
{
pNote->m_nGridStart = nClickTime;
pNote->m_nTimeOffset = ConvertTime(iNote.nTime);
pNote->m_dwVariation = iNote.wVariation;
((CDMStyleNote*)pNote)->m_bVelocity = iNote.bVelocity;
((CDMStyleNote*)pNote)->m_mtDuration = ConvertTime(iNote.nDuration);
((CDMStyleNote*)pNote)->m_bTimeRange = iNote.bTimeRange;
((CDMStyleNote*)pNote)->m_bDurRange = iNote.bDurRange;
((CDMStyleNote*)pNote)->m_bVelRange = iNote.bVelRange;
((CDMStyleNote*)pNote)->m_bInversionId = 0; // not in IMA2.5
((CDMStyleNote*)pNote)->m_bFlags = 0; // not in IMA2.5
// Make sure SuperJAM! play mode is valid
if ( !(iNote.bPlayMode & 0x80) )
{
iNote.bPlayMode = CHTYPE_NONE;
}
// Strip 0x80 before checking SuperJAM! play mode
switch (iNote.bPlayMode & 0x0F)
{
case CHTYPE_NOTINITIALIZED:
case CHTYPE_NONE:
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_NONE;
break;
case CHTYPE_DRUM:
case CHTYPE_FIXED:
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
break;
case CHTYPE_UPPER:
case CHTYPE_BASS:
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_NORMALCHORD;
break;
case CHTYPE_SCALEONLY:
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_PEDALPOINT;
break;
case CHTYPE_BASSMELODIC:
case CHTYPE_UPPERMELODIC:
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_SCALE_INTERVALS | DMUS_PLAYMODE_CHORD_ROOT;
break;
default:
// should never get here...
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
}
//}
DirectMusicPart* pPart = FindPart(iNote.bVoiceID);
if (pPart != NULL)
{
pPart->EventList.AddHead(pNote);
}
else
{
assert(0);
}
// Determine playmode of note
BYTE bNotePlayModeFlags;
if( ((CDMStyleNote*)pNote)->m_bPlayModeFlags == DMUS_PLAYMODE_NONE )
{
bNotePlayModeFlags = pPart->m_bPlayModeFlags;
}
else
{
bNotePlayModeFlags = ((CDMStyleNote*)pNote)->m_bPlayModeFlags;
}
// if ScaleValue is non-zero and the note isn't a pedalpoint, it's purpleized.
if( iNote.bScaleValue != 0
&& bNotePlayModeFlags != DMUS_PLAYMODE_PEDALPOINT )
{
((CDMStyleNote*)pNote)->m_bPlayModeFlags = DMUS_PLAYMODE_PURPLEIZED;
}
// if the note is a drum event, use the (mapped) MIDI value;
if( iNote.bVoiceID == 5 ) // it's a drum part
{
if (iNote.bValue < 128 && achMappings[iNote.bValue] < 128)
((CDMStyleNote*)pNote)->m_wMusicValue = achMappings[iNote.bValue];
else
{
((CDMStyleNote*)pNote)->m_wMusicValue = 0;
}
}
// otherwise, if it's fixed, use the unmapped Midi value
else if( bNotePlayModeFlags == DMUS_PLAYMODE_FIXED )
{
((CDMStyleNote*)pNote)->m_wMusicValue = iNote.bValue;
}
// otherwise, use MusicValue
else
{
((CDMStyleNote*)pNote)->m_wMusicValue = iNote.nMusicValue;
}
}
}
ON_ERR:
return hr;
}
HRESULT CDirectMusicPattern::LoadEvents( IAARIFFStream* pRIFF, MMCKINFO* pckMain )
{
ioClick iClick;
HRESULT hr = S_OK;
LPSTREAM pStream;
MMCKINFO ck;
DWORD cSize;
DWORD cb;
BOOL fClickLoaded = FALSE;
pStream = pRIFF->GetStream();
if ( pStream == NULL ) return E_FAIL;
short nClickTime = 0;
while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case FOURCC_CLICK:
fClickLoaded = TRUE;
cSize = min( ck.cksize, sizeof( iClick ) );
hr = pStream->Read( &iClick, cSize, &cb );
FixBytes( FBT_IOCLICK, &iClick );
if( FAILED( hr ) || cb != cSize )
{
hr = E_FAIL;
goto ON_ERR;
}
nClickTime = iClick.lTime;
break;
case FOURCC_NOTE:
if (fClickLoaded)
LoadNoteList( pStream, &ck, nClickTime);
else
{
hr = E_FAIL;
goto ON_ERR;
}
break;
case FOURCC_CURVE:
if (fClickLoaded)
LoadCurveList( pStream, &ck, nClickTime);
else
{
hr = E_FAIL;
goto ON_ERR;
}
break;
}
pRIFF->Ascend( &ck, 0 );
}
ON_ERR:
pStream->Release();
return hr;
}
void CDirectMusicPattern::CleanUp()
{
if (m_pRhythmMap != NULL)
{
delete [] m_pRhythmMap;
m_pRhythmMap = NULL;
}
/* if (m_pSwitchPoints != NULL)
{
delete [] m_pSwitchPoints;
m_pSwitchPoints = NULL;
}*/
if (m_pMotifBand)
{
m_pMotifBand->Release();
m_pMotifBand = NULL;
}
m_PartRefList.CleanUp();
}
STDMETHODIMP_(ULONG) CDirectMusicPattern::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CDirectMusicPattern::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
delete this;
return 0;
}
return m_cRef;
}
DirectMusicPart* CDirectMusicPattern::FindPart(BYTE bVoiceID)
{
TListItem<DirectMusicPartRef> *li;
for(li = m_PartRefList.GetHead(); li != NULL; li = li->GetNext())
{
if (VOICEID_TO_CHANNEL(bVoiceID + 1) == li->GetItemValue().m_dwLogicalPartID)
return li->GetItemValue().m_pDMPart;
}
return NULL;
}
TListItem<DirectMusicPartRef>* CDirectMusicPattern::FindPartRefByPChannel(DWORD dwPChannel)
{
TListItem<DirectMusicPartRef> *li;
for(li = m_PartRefList.GetHead(); li != NULL; li = li->GetNext())
{
if (dwPChannel == li->GetItemValue().m_dwLogicalPartID)
return li;
}
return NULL;
}
TListItem<DirectMusicPartRef>* CDirectMusicPattern::CreatePart( DirectMusicPartRef& rPartRef, BYTE bPlaymode, WORD wMeasures )
{
TListItem<DirectMusicPartRef>* pNewPartRef = FindPartRefByPChannel(rPartRef.m_dwLogicalPartID);
if (pNewPartRef)
{
DirectMusicPartRef& rNewPartRef = pNewPartRef->GetItemValue();
DirectMusicPart* pFoundPart = rNewPartRef.m_pDMPart;
DirectMusicPart* pOtherPart = rPartRef.m_pDMPart;
if (pFoundPart && pOtherPart)
{
if (pOtherPart->m_bInvertUpper > pFoundPart->m_bInvertUpper)
{
pFoundPart->m_bInvertUpper = pOtherPart->m_bInvertUpper;
}
if (pOtherPart->m_bInvertLower < pFoundPart->m_bInvertLower)
{
pFoundPart->m_bInvertLower = pOtherPart->m_bInvertLower;
}
pFoundPart->m_dwFlags |= pOtherPart->m_dwFlags;
}
}
else
{
pNewPartRef = new TListItem<DirectMusicPartRef>;
if( pNewPartRef )
{
DirectMusicPart* pPart = new DirectMusicPart;
if( !pPart )
{
delete pNewPartRef;
pNewPartRef = NULL;
}
else
{
DirectMusicPartRef& rNewPartRef = pNewPartRef->GetItemValue();
// initialize the new part...
DirectMusicPart* pOtherPart = rPartRef.m_pDMPart;
if (pPart && pOtherPart)
{
pPart->m_guidPartID = pOtherPart->m_guidPartID;
pPart->m_timeSig = m_timeSig;
for (int i = 0; i < 32; i++) // activate all variations
{
pPart->m_dwVariationChoices[i] = 0x7fffffff;
}
pPart->m_bPlayModeFlags = bPlaymode;
pPart->m_bInvertUpper = pOtherPart->m_bInvertUpper;
pPart->m_bInvertLower = pOtherPart->m_bInvertLower;
pPart->m_dwFlags = pOtherPart->m_dwFlags;
pPart->m_wNumMeasures = wMeasures;
}
// initialize the new part ref...
rNewPartRef.m_pDMPart = pPart;
rNewPartRef.m_dwLogicalPartID = rPartRef.m_dwLogicalPartID;
rNewPartRef.m_bVariationLockID = rPartRef.m_bVariationLockID;
rNewPartRef.m_bSubChordLevel = rPartRef.m_bSubChordLevel;
rNewPartRef.m_bPriority = rPartRef.m_bPriority;
rNewPartRef.m_bRandomVariation = rPartRef.m_bRandomVariation;
m_PartRefList.AddTail(pNewPartRef);
}
}
}
return pNewPartRef;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DM_LoadPattern
HRESULT CDirectMusicPattern::DM_LoadPattern(
IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
{
TListItem<DirectMusicPartRef>* pPartRefItem = NULL;
DirectMusicPart* pPart;
IStream* pIStream;
HRESULT hr = S_OK;
DWORD dwByteCount;
DWORD dwSize;
MMCKINFO ck;
MMCKINFO ckList;
int i;
if ( pStyle == NULL ) return E_INVALIDARG;
if ( pIRiffStream == NULL ) return E_INVALIDARG;
if ( pckMain == NULL ) return E_INVALIDARG;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
// Load the Pattern
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_PATTERN_CHUNK:
{
DMUS_IO_PATTERN iDMPattern;
memset(&iDMPattern, 0, sizeof(iDMPattern));
dwSize = min( ck.cksize, sizeof( DMUS_IO_PATTERN ) );
hr = pIStream->Read( &iDMPattern, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
m_bGrooveBottom = iDMPattern.bGrooveBottom;
m_bGrooveTop = iDMPattern.bGrooveTop;
m_wEmbellishment = iDMPattern.wEmbellishment;
m_bDestGrooveBottom = iDMPattern.bDestGrooveBottom;
m_bDestGrooveTop = iDMPattern.bDestGrooveTop;
m_dwFlags = iDMPattern.dwFlags;
m_timeSig.m_bBeatsPerMeasure = iDMPattern.timeSig.bBeatsPerMeasure;
m_timeSig.m_bBeat = iDMPattern.timeSig.bBeat;
m_timeSig.m_wGridsPerBeat = iDMPattern.timeSig.wGridsPerBeat;
m_wNumMeasures = iDMPattern.wNbrMeasures;
break;
}
case DMUS_FOURCC_RHYTHM_CHUNK:
if( m_pRhythmMap )
{
delete [] m_pRhythmMap;
m_pRhythmMap = NULL;
}
m_pRhythmMap = new DWORD[m_wNumMeasures];
if( m_pRhythmMap == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERROR;
}
for( i = 0 ; i < m_wNumMeasures ; i++ )
{
hr = pIStream->Read( &m_pRhythmMap[i], sizeof(DWORD), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof(DWORD) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
break;
/* case DMUS_FOURCC_SWITCH_POINT_CHUNK:
if( m_pSwitchPoints )
{
delete [] m_pSwitchPoints;
m_pSwitchPoints = NULL;
}
m_pSwitchPoints = new DWORD[m_wNumMeasures];
if( m_pSwitchPoints == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERROR;
}
for( i = 0 ; i < m_wNumMeasures ; i++ )
{
hr = pIStream->Read( &m_pSwitchPoints[i], sizeof(DWORD), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof(DWORD) )
{
hr = E_FAIL;
goto ON_ERROR;
}
}
break;
*/
case DMUS_FOURCC_MOTIFSETTINGS_CHUNK:
{
DMUS_IO_MOTIFSETTINGS ioMotifSettings;
hr = pIStream->Read( &ioMotifSettings, sizeof(DMUS_IO_MOTIFSETTINGS), &dwByteCount );
if( FAILED( hr ) || dwByteCount != sizeof(DMUS_IO_MOTIFSETTINGS) )
{
hr = E_FAIL;
goto ON_ERROR;
}
m_fSettings = TRUE;
m_dwRepeats = ioMotifSettings.dwRepeats;
m_mtPlayStart = ioMotifSettings.mtPlayStart;
m_mtLoopStart = ioMotifSettings.mtLoopStart;
m_mtLoopEnd = ioMotifSettings.mtLoopEnd;
m_dwResolution = ioMotifSettings.dwResolution;
break;
}
case FOURCC_RIFF:
switch( ck.fccType )
{
case DMUS_FOURCC_BAND_FORM:
{
// load band associated with the motif
if (m_pMotifBand)
{
m_pMotifBand->Release();
m_pMotifBand = NULL;
}
// Create a band
hr = CoCreateInstance(CLSID_DirectMusicBand,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicBand,
(void**)&m_pMotifBand);
if(SUCCEEDED(hr))
{
// Seek back to begining of Riff chunk
// This is the amount read by Descend when descending into a FOURCC_RIFF chunk
// Get current position
LARGE_INTEGER li;
ULARGE_INTEGER ul;
li.HighPart = 0;
li.LowPart = 0;
hr = pIStream->Seek(li,
STREAM_SEEK_CUR,
&ul);
if(SUCCEEDED(hr))
{
li.HighPart = 0;
// This is always a valid operation
li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
hr = pIStream->Seek(li,
STREAM_SEEK_SET,
&ul);
}
}
if(SUCCEEDED(hr))
{
// Load band
IPersistStream* pIPersistStream;
hr = m_pMotifBand->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
if(SUCCEEDED(hr))
{
hr = pIPersistStream->Load(pIStream);
pIPersistStream->Release();
}
}
if(FAILED(hr))
{
if (m_pMotifBand)
{
m_pMotifBand->Release();
m_pMotifBand = NULL;
}
goto ON_ERROR;
}
break;
}
}
break;
case FOURCC_LIST:
switch( ck.fccType )
{
case DMUS_FOURCC_UNFO_LIST:
while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
{
switch( ckList.ckid )
{
case RIFFINFO_INAM:
case DMUS_FOURCC_UNAM_CHUNK:
{
DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
hr = ReadMBSfromWCS( pIStream, dwLength, m_strName );
if (FAILED(hr))
{
goto ON_ERROR;
}
break;
}
}
pIRiffStream->Ascend( &ckList, 0 );
}
break;
case DMUS_FOURCC_PART_LIST: // only in GUID_SinglePattern format
pPart = pStyle->AllocPart();
if( pPart == NULL )
{
hr = E_OUTOFMEMORY ;
goto ON_ERROR;
}
hr = pPart->DM_LoadPart( pIRiffStream, &ck, pStyle );
if( FAILED( hr ) )
{
pStyle->DeletePart( pPart );
goto ON_ERROR;
}
if( hr == S_FALSE )
{
// Bypass this Part because Style already contains a Part
// whose GUID matches pPart->m_guidPartID
pStyle->DeletePart( pPart );
}
else // merge the part's marker events
{
pPart->MergeMarkerEvents(pStyle, this);
}
break;
case DMUS_FOURCC_PARTREF_LIST:
hr = AllocPartRef(pPartRefItem);
if ( FAILED(hr) )
{
goto ON_ERROR;
}
hr = pPartRefItem->GetItemValue().DM_LoadPartRef( pIRiffStream, &ck, pStyle );
if ( FAILED( hr ) )
{
DeletePartRef( pPartRefItem );
goto ON_ERROR;
}
break;
}
break;
}
pIRiffStream->Ascend( &ck, 0 );
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern additional functions
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::AllocPartRef
HRESULT CDirectMusicPattern::AllocPartRef(TListItem<DirectMusicPartRef>*& rpPartRefItem)
{
rpPartRefItem = new TListItem<DirectMusicPartRef>;
if (rpPartRefItem)
{
// Add PartRef to Pattern's list of Parts
m_PartRefList.AddTail( rpPartRefItem );
return S_OK;
}
return E_OUTOFMEMORY;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPattern::DeletePartRef
void CDirectMusicPattern::DeletePartRef(TListItem<DirectMusicPartRef>* pPartRefItem)
{
// add stuff later...
}
HRESULT CDirectMusicPattern::LoadPattern(IAARIFFStream* pRIFF,
MMCKINFO* pckMain,
TList<DirectMusicPart*> &partList,
DMStyleStruct& rStyleStruct
)
{
int i;
int j;
ioPattern iPattern;
LPSTREAM pStream;
HRESULT hr = S_OK;
MMCKINFO ck;
DWORD cb;
DWORD cSize;
WORD wKludge;
DWORD dwRhythm = 1; // make it a whole note pattern by default
pStream = pRIFF->GetStream();
if ( pStream == NULL ) return E_FAIL;
while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case FOURCC_PATTERN:
cSize = min( ck.cksize, sizeof( iPattern ) );
hr = pStream->Read( &iPattern, cSize, &cb );
FixBytes( FBT_IOPATTERN, &iPattern );
if( FAILED( hr ) || cb != cSize )
{
hr = E_FAIL;
goto ON_ERR;
}
m_strName = iPattern.wstrName;
m_timeSig.m_bBeatsPerMeasure = static_cast<BYTE>( iPattern.dwLength / static_cast<long>( iPattern.wClocksPerBeat ) / iPattern.wMeasures );
m_timeSig.m_bBeat = static_cast<BYTE>(iPattern.wBeat);
m_timeSig.m_wGridsPerBeat = iPattern.wClocksPerBeat / iPattern.wClocksPerClick;
m_wNumMeasures = iPattern.wMeasures;
// Bottom of groove range is 1 if either level A or no levels were specified;
// 26 if level B is the lowest level specified, etc.
if ( iPattern.fFlags & PF_A || !(iPattern.fFlags & (PF_A | PF_B | PF_C | PF_D)) )
m_bGrooveBottom = 1;
else if (iPattern.fFlags & PF_B) m_bGrooveBottom = 26;
else if (iPattern.fFlags & PF_C) m_bGrooveBottom = 51;
else m_bGrooveBottom = 76;
// Top of groove range is 100 if either level D or no levels were specified;
// 75 if level C is the highest level specified, etc.
if ( iPattern.fFlags & PF_D || !(iPattern.fFlags & (PF_A | PF_B | PF_C | PF_D)) )
m_bGrooveTop = 100;
else if (iPattern.fFlags & PF_C) m_bGrooveTop = 75;
else if (iPattern.fFlags & PF_B) m_bGrooveTop = 50;
else m_bGrooveTop = 25;
m_wEmbellishment = EMB_NORMAL;
if (iPattern.fFlags & PF_FILL) m_wEmbellishment |= EMB_FILL;
if (iPattern.fFlags & PF_INTRO) m_wEmbellishment |= EMB_INTRO;
if (iPattern.fFlags & PF_END) m_wEmbellishment |= EMB_END;
if (iPattern.fFlags & PF_BREAK) m_wEmbellishment |= EMB_BREAK;
if (iPattern.fFlags & PF_MOTIF) m_wEmbellishment |= EMB_MOTIF;
m_pRhythmMap = new DWORD[iPattern.wMeasures];
if( m_pRhythmMap == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
if (iPattern.fFlags & PF_WHOLE) dwRhythm = 1; // bit 1 set
if (iPattern.fFlags & PF_HALF) dwRhythm = 5; // bits 1 and 3
if (iPattern.fFlags & PF_QUARTER) dwRhythm = 15; // bits 1-4
for (i = 0; i < iPattern.wMeasures; ++i)
{
m_pRhythmMap[i] = dwRhythm;
}
for( i = 0 ; i < 16 ; ++i ) // loop over Parts
{
TListItem<DirectMusicPart*> *pPartItem = new TListItem<DirectMusicPart*>;
if( pPartItem == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
DirectMusicPart*& pPart = pPartItem->GetItemValue();
pPart = new DirectMusicPart;
if( pPart == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
pPart->m_wNumMeasures = m_wNumMeasures;
TListItem<DirectMusicPartRef> *pPartRefItem = new TListItem<DirectMusicPartRef>;
if( pPartRefItem == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
DirectMusicPartRef& rPartRef = pPartRefItem->GetItemValue();
rPartRef.m_pDMPart = pPart;
rPartRef.m_pDMPart->AddRef();
rPartRef.m_dwLogicalPartID = VOICEID_TO_CHANNEL(i + 1);
AdjoinPChannel(rStyleStruct.m_PChannelList, rPartRef.m_dwLogicalPartID);
rPartRef.m_bVariationLockID = 0; // 0 means no locking between parts...
rPartRef.m_bRandomVariation = DMUS_VARIATIONT_RANDOM; // (default in 2.5)
if( iPattern.wInvert & (1 << i) )
{
pPart->m_bInvertLower = iPattern.abInvertLower[i];
pPart->m_bInvertUpper = iPattern.abInvertUpper[i];
}
else
{
pPart->m_bInvertLower = 0;
pPart->m_bInvertUpper = 127;
}
if (iPattern.achChordChoice[i] == CHTYPE_UPPER ||
iPattern.achChordChoice[i] == CHTYPE_UPPERMELODIC)
{
rPartRef.m_bSubChordLevel = SUBCHORD_STANDARD_CHORD;
}
else
{
rPartRef.m_bSubChordLevel = SUBCHORD_BASS;
}
switch (iPattern.achChordChoice[i])
{
case CHTYPE_DRUM:
case CHTYPE_FIXED:
pPart->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
break;
case CHTYPE_UPPER:
case CHTYPE_BASS:
pPart->m_bPlayModeFlags = DMUS_PLAYMODE_NORMALCHORD;
break;
case CHTYPE_SCALEONLY:
pPart->m_bPlayModeFlags = DMUS_PLAYMODE_PEDALPOINT;
break;
case CHTYPE_BASSMELODIC:
case CHTYPE_UPPERMELODIC:
pPart->m_bPlayModeFlags = DMUS_PLAYMODE_SCALE_INTERVALS | DMUS_PLAYMODE_CHORD_ROOT;
break;
default:
// should never get here...
pPart->m_bPlayModeFlags = DMUS_PLAYMODE_FIXED;
}
// if none of the variations have the ->I or ->V flag set, set it in all variations
wKludge = VF_TO1 | VF_TO5;
for (j = 16; j < 32; j++) pPart->m_dwVariationChoices[j] = 0;
for( j = 0 ; j < 16 ; ++j )
{
pPart->m_dwVariationChoices[j] = iPattern.awVarFlags[i][j];
if( ( pPart->m_dwVariationChoices[j] & VF_TO1 ) != 0 )
{
wKludge &= ~VF_TO1;
}
if( ( pPart->m_dwVariationChoices[j] & VF_TO5 ) != 0 )
{
wKludge &= ~VF_TO5;
}
}
if( wKludge != 0 )
{
for( j = 0 ; j < 16 ; ++j )
{
pPart->m_dwVariationChoices[j] |= wKludge;
}
}
partList.AddTail(pPartItem);
m_PartRefList.AddTail(pPartRefItem);
}
break;
case FOURCC_LIST:
switch( ck.fccType )
{
case FOURCC_CLICK_LIST:
LoadEvents(pRIFF, &ck);
break;
}
break;
}
pRIFF->Ascend( &ck, 0 );
}
ON_ERR:
pStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDirectMusicPartRef::DM_LoadPartRef
HRESULT DirectMusicPartRef::DM_LoadPartRef(
IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, DMStyleStruct* pStyle )
{
DirectMusicPart* pPart;
IStream* pIStream;
HRESULT hr;
MMCKINFO ck;
DWORD dwByteCount;
DWORD dwSize;
if ( pStyle == NULL ) return E_INVALIDARG;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_PARTREF_CHUNK:
{
DMUS_IO_PARTREF iDMPartRef;
dwSize = min( ck.cksize, sizeof( DMUS_IO_PARTREF ) );
hr = pIStream->Read( &iDMPartRef, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
m_bRandomVariation = iDMPartRef.bRandomVariation;
if (dwSize < DX8_PARTREF_SIZE)
{
m_dwLogicalPartID = iDMPartRef.wLogicalPartID;
}
else
{
m_dwLogicalPartID = iDMPartRef.dwPChannel;
}
AdjoinPChannel(pStyle->m_PChannelList, m_dwLogicalPartID);
m_bVariationLockID = iDMPartRef.bVariationLockID;
m_bSubChordLevel = iDMPartRef.bSubChordLevel;
m_bPriority = iDMPartRef.bPriority;
pPart = pStyle->FindPartByGUID( iDMPartRef.guidPartID );
if( pPart == NULL )
{
hr = E_FAIL;
goto ON_ERROR;
}
SetPart( pPart );
break;
}
}
pIRiffStream->Ascend( &ck, 0 );
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DirectMusicPartRef::SetPart
void DirectMusicPartRef::SetPart( DirectMusicPart* pPart )
{
if( m_pDMPart == pPart )
{
return;
}
if( m_pDMPart )
{
m_pDMPart->Release();
}
if( pPart )
{
m_pDMPart = pPart;
m_pDMPart->AddRef();
}
}
CDMStyle::CDMStyle() : m_cRef(1), m_fCSInitialized(FALSE)
{
InterlockedIncrement(&g_cComponent);
::InitializeCriticalSection( &m_CriticalSection );
m_fCSInitialized = TRUE;
m_StyleInfo.m_fLoaded = false;
m_StyleInfo.m_dwFlags = 0;
m_StyleInfo.m_pDefaultBand = NULL;
m_StyleInfo.m_pDefaultPers = NULL;
}
CDMStyle::~CDMStyle()
{
if (m_fCSInitialized)
{
// Don't need to clean up if critical section failed.
// DON'T MOVE THIS - it will fault in low memory conditions
//
CleanUp();
::DeleteCriticalSection( &m_CriticalSection );
}
InterlockedDecrement(&g_cComponent);
}
HRESULT CDMStyle::GetStyleInfo(void **pData)
{
*pData = (void *) &m_StyleInfo;
return S_OK;
}
HRESULT CDMStyle::IsDX8()
{
return m_StyleInfo.UsingDX8() ? S_OK : S_FALSE;
}
HRESULT CDMStyle::CritSec(bool fEnter)
{
HRESULT hr = S_OK;
if (m_fCSInitialized)
{
if (fEnter)
{
EnterCriticalSection(&m_CriticalSection);
}
else
{
LeaveCriticalSection(&m_CriticalSection);
}
}
else
{
hr = E_FAIL;
}
return hr;
}
/* IPersist methods */
HRESULT CDMStyle::GetClassID( LPCLSID pclsid )
{
//assert ( pclsid != NULL );
*pclsid = CLSID_DirectMusicStyle;
return S_OK;
}
HRESULT CDMStyle::IsDirty()
{
return ( m_fDirty ) ? S_OK : S_FALSE;
}
HRESULT CDMStyle::Save( LPSTREAM pStream, BOOL /*fClearDirty*/ )
{
return E_NOTIMPL;
}
HRESULT CDMStyle::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ )
{
return E_NOTIMPL;
}
HRESULT CDMStyle::Load( LPSTREAM pIStream )
{
DWORD dwPos;
IAARIFFStream* pIRiffStream;
MMCKINFO ckMain;
HRESULT hr = E_FAIL;
if( pIStream == NULL )
{
return E_INVALIDARG;
}
EnterCriticalSection( &m_CriticalSection );
CleanUp();
dwPos = StreamTell( pIStream );
BOOL fFoundFormat = FALSE;
// Check for Direct Music format
if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
{
ckMain.fccType = DMUS_FOURCC_STYLE_FORM;
if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
{
hr = DM_LoadStyle( pIRiffStream, &ckMain );
fFoundFormat = TRUE;
}
pIRiffStream->Release();
pIRiffStream = NULL;
}
// Check for IMA 2.5 format
if( !fFoundFormat )
{
StreamSeek( pIStream, dwPos, STREAM_SEEK_SET );
if( SUCCEEDED( AllocRIFFStream( pIStream, &pIRiffStream ) ) )
{
ckMain.fccType = FOURCC_STYLE_FORM;
if( pIRiffStream->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 )
{
hr = IMA25_LoadStyle( pIRiffStream, &ckMain );
fFoundFormat = TRUE;
}
pIRiffStream->Release();
}
}
if (SUCCEEDED(hr)) m_StyleInfo.m_fLoaded = true;
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
void CDMStyle::CleanUp()
{
EnterCriticalSection(&m_CriticalSection);
m_StyleInfo.m_fLoaded = false;
TListItem<IDirectMusicBand*>* pBandListItem = (m_StyleInfo.m_BandList).GetHead();
for (; pBandListItem; pBandListItem = pBandListItem->GetNext())
{
IDirectMusicBand* pBand = pBandListItem->GetItemValue();
if(pBand)
{
pBand->Release();
}
}
m_StyleInfo.m_BandList.CleanUp();
TListItem<IDirectMusicChordMap*>* pPersListItem = (m_StyleInfo.m_PersList).GetHead();
for (; pPersListItem; pPersListItem = pPersListItem->GetNext())
{
IDirectMusicChordMap* pPers = pPersListItem->GetItemValue();
if(pPers)
{
pPers->Release();
}
}
m_StyleInfo.m_PersList.CleanUp();
TListItem<DirectMusicPart*>* pPartListItem = (m_StyleInfo.m_PartList).GetHead();
for (int count = 0; pPartListItem; pPartListItem = pPartListItem->GetNext(),count++)
{
DirectMusicPart* pPart = pPartListItem->GetItemValue();
if(pPart)
{
if (pPart->Release() == 0)
{
pPartListItem->GetItemValue() = NULL;
}
}
}
m_StyleInfo.m_PartList.CleanUp();
TListItem<CDirectMusicPattern*>* pPatternListItem = (m_StyleInfo.m_PatternList).GetHead();
for (; pPatternListItem; pPatternListItem = pPatternListItem->GetNext())
{
CDirectMusicPattern* pPattern = pPatternListItem->GetItemValue();
if(pPattern)
{
if (pPattern->Release() == 0)
{
pPatternListItem->GetItemValue() = NULL;
}
}
}
m_StyleInfo.m_PatternList.CleanUp();
pPatternListItem = (m_StyleInfo.m_MotifList).GetHead();
for (; pPatternListItem; pPatternListItem = pPatternListItem->GetNext())
{
CDirectMusicPattern* pPattern = pPatternListItem->GetItemValue();
if(pPattern)
{
pPattern->Release();
}
}
m_StyleInfo.m_MotifList.CleanUp();
m_StyleInfo.m_PChannelList.CleanUp();
LeaveCriticalSection(&m_CriticalSection);
}
HRESULT CDMStyle::IMA25_LoadPersonalityReference( IStream* pStream, MMCKINFO* pck )
{
ioPersonalityRef ref;
DWORD dwSize;
WORD wStructSize;
String strFileName;
HRESULT hr = S_OK;
HRESULT hrChordMap = E_FAIL;
if ( pStream == NULL ) return E_POINTER;
dwSize = pck->cksize;
pStream->Read( &wStructSize, sizeof( wStructSize ), NULL );
FixBytes( FBT_SHORT, &wStructSize );
dwSize -= sizeof( wStructSize );
if( wStructSize > sizeof(ref) )
{
hr = pStream->Read( &ref, sizeof(ref), NULL );
FixBytes( FBT_IOPERSONALITYREF, &ref );
StreamSeek( pStream, wStructSize - sizeof(ref), STREAM_SEEK_CUR );
}
else
{
hr = pStream->Read( &ref, wStructSize, NULL );
FixBytes( FBT_IOPERSONALITYREF, &ref );
}
if (!SUCCEEDED(hr)) return hr;
dwSize -= wStructSize;
// loader stuff here...
DMUS_OBJECTDESC ObjectDescript;
ZeroMemory(&ObjectDescript, sizeof(DMUS_OBJECTDESC));
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
ObjectDescript.guidClass = CLSID_DirectMusicChordMap;
wcscpy(ObjectDescript.wszName, ref.wstrName);
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_NAME;
IDirectMusicLoader* pLoader;
IDirectMusicGetLoader *pIGetLoader;
hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader );
if (!SUCCEEDED(hr)) return hr;
hr = pIGetLoader->GetLoader(&pLoader);
pIGetLoader->Release();
if (!SUCCEEDED(hr)) return hr;
IDirectMusicObject* pObject = NULL;
// Ignore this result (except for purposes of incorporating it into the style):
// success or failure of loading individual ChordMap references should have no
// bearing on the success or failure of loading the style.
hrChordMap = pLoader->GetObject(&ObjectDescript, IID_IDirectMusicObject, (void**)&pObject);
if (!SUCCEEDED(hrChordMap))
{
hr = strFileName.ReadWCS( pStream, dwSize );
if (SUCCEEDED(hr))
{
strFileName += ".per";
wcscpy(ObjectDescript.wszFileName, strFileName);
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
hrChordMap = pLoader->GetObject(&ObjectDescript, IID_IDirectMusicObject, (void**)&pObject);
}
}
pLoader->Release();
if (SUCCEEDED(hrChordMap))
{
IDirectMusicChordMap* pPers;
hr = pObject->QueryInterface(IID_IDirectMusicChordMap, (void**)&pPers);
pObject->Release();
if (SUCCEEDED(hr))
{
hr = IncorporatePersonality(pPers, ref.wstrName, ref.fDefault);
}
}
return hr;
}
HRESULT CDMStyle::IncorporatePersonality( IDirectMusicChordMap* pPers, String strName, BOOL fDefault )
{
EnterCriticalSection( &m_CriticalSection );
TListItem<IDirectMusicChordMap*>* pScan = m_StyleInfo.m_PersList.GetHead();
for( ; pScan != NULL ; pScan = pScan->GetNext() )
{
HRESULT hr = S_OK;
String str2;
IDirectMusicObject *pIObject = NULL;
DMUS_OBJECTDESC Desc; // Descriptor.
if (SUCCEEDED(hr = pScan->GetItemValue()->QueryInterface(IID_IDirectMusicObject,(void **) &pIObject)))
{
if (SUCCEEDED(hr = pIObject->GetDescriptor(&Desc)))
{
if (Desc.dwValidData & DMUS_OBJ_NAME)
{
str2 = Desc.wszName;
if (strName == str2)
{
pPers->Release();
break;
}
}
else hr = E_FAIL;
}
pIObject->Release();
}
if (!SUCCEEDED(hr))
{
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
}
if( pScan == NULL )
{
TListItem<IDirectMusicChordMap*>* pNew = NULL;
pNew = new TListItem<IDirectMusicChordMap*>(pPers);
if (pNew)
{
m_StyleInfo.m_PersList.AddHead(pNew);
if (fDefault)
{
if (m_StyleInfo.m_pDefaultPers) m_StyleInfo.m_pDefaultPers->Release();
m_StyleInfo.m_pDefaultPers = pPers;
}
}
}
LeaveCriticalSection( &m_CriticalSection );
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CDMStyle::DM_ParseDescriptor
HRESULT CDMStyle::DM_ParseDescriptor( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain, LPDMUS_OBJECTDESC pDesc )
{
IStream* pIStream;
MMCKINFO ck;
MMCKINFO ckList;
DWORD dwByteCount;
DWORD dwSize;
DWORD dwPos;
HRESULT hr = S_OK;
String str;
pIStream = pIRiffStream->GetStream();
if ( pIStream == NULL ) return E_FAIL;
dwPos = StreamTell( pIStream );
pDesc->dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicStyle;
while( pIRiffStream->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case DMUS_FOURCC_GUID_CHUNK:
dwSize = min( ck.cksize, sizeof( GUID ) );
hr = pIStream->Read( &pDesc->guidObject, dwSize, &dwByteCount );
if( FAILED( hr ) || dwByteCount != dwSize )
{
hr = DMUS_E_CHUNKNOTFOUND;
goto ON_ERROR;
}
else
{
pDesc->dwValidData |= DMUS_OBJ_OBJECT;
}
break;
case DMUS_FOURCC_VERSION_CHUNK:
{
dwSize = min( ck.cksize, sizeof( DMUS_IO_VERSION ) );
hr = pIStream->Read( &pDesc->vVersion, dwSize, &dwByteCount );
if( FAILED( hr )|| dwByteCount != dwSize )
{
hr = DMUS_E_CHUNKNOTFOUND;
goto ON_ERROR;
}
else
{
pDesc->dwValidData |= DMUS_OBJ_VERSION;
}
break;
}
case FOURCC_LIST:
switch( ck.fccType )
{
case DMUS_FOURCC_UNFO_LIST:
while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
{
switch( ckList.ckid )
{
case RIFFINFO_INAM:
case DMUS_FOURCC_UNAM_CHUNK:
{
DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
hr = ReadMBSfromWCS( pIStream, dwLength, str );
if (FAILED(hr))
{
goto ON_ERROR;
}
wcscpy(pDesc->wszName, str);
if(pDesc->wszName[0])
{
pDesc->dwValidData |= DMUS_OBJ_NAME;
pDesc->wszName[16] = 0;
}
break;
}
case DMUS_FOURCC_CATEGORY_CHUNK:
{
DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_CATEGORY - 1)));
hr = ReadMBSfromWCS( pIStream, dwLength, str );
if (FAILED(hr))
{
goto ON_ERROR;
}
wcscpy(pDesc->wszCategory, str);
if(pDesc->wszCategory[0])
{
pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
pDesc->wszCategory[16] = 0;
}
break;
}
}
pIRiffStream->Ascend( &ckList, 0 );
}
break;
}
break;
}
pIRiffStream->Ascend( &ck, 0 );
dwPos = StreamTell( pIStream );
}
ON_ERROR:
pIStream->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CDMStyle::DM_LoadStyle
HRESULT CDMStyle::DM_LoadStyle( IAARIFFStream* pIRiffStream, MMCKINFO* pckMain )
{
DirectMusicPart* pPart;
IStream* pIStream;
MMCKINFO ck;
MMCKINFO ckList;
DWORD dwByteCount;
DWORD dwSize;
DWORD dwPos;
HRESULT hr = S_OK;
HRESULT hrBand = S_OK;
BOOL fFoundDefault = FALSE;
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_STYLE_CHUNK:
{
DMUS_IO_STYLE iDMStyle;
dwSize = min( ck.cksize, sizeof( DMUS_IO_STYLE ) );
hr = pIStream->Read( &iDMStyle, dwSize, &dwByteCount );
if( FAILED( hr )
|| dwByteCount != dwSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure = iDMStyle.timeSig.bBeatsPerMeasure;
m_StyleInfo.m_TimeSignature.m_bBeat = iDMStyle.timeSig.bBeat;
m_StyleInfo.m_TimeSignature.m_wGridsPerBeat = iDMStyle.timeSig.wGridsPerBeat;
m_StyleInfo.m_dblTempo = iDMStyle.dblTempo;
break;
}
case DMUS_FOURCC_GUID_CHUNK:
dwSize = min( ck.cksize, sizeof( GUID ) );
hr = pIStream->Read( &m_StyleInfo.m_guid, dwSize, &dwByteCount );
if( FAILED( hr )
|| dwByteCount != dwSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
break;
case DMUS_FOURCC_VERSION_CHUNK:
{
DMUS_IO_VERSION iDMStyleVersion;
dwSize = min( ck.cksize, sizeof( DMUS_IO_VERSION ) );
hr = pIStream->Read( &iDMStyleVersion, dwSize, &dwByteCount );
if( FAILED( hr )
|| dwByteCount != dwSize )
{
hr = E_FAIL;
goto ON_ERROR;
}
m_StyleInfo.m_dwVersionMS = iDMStyleVersion.dwVersionMS;
m_StyleInfo.m_dwVersionLS = iDMStyleVersion.dwVersionLS;
break;
}
case FOURCC_LIST:
switch( ck.fccType )
{
case DMUS_FOURCC_STYLE_PERS_REF_LIST:
{
hr = DM_LoadPersonalityReference( pIRiffStream, &ck );
if( FAILED( hr ) )
{
goto ON_ERROR;
}
break;
}
case DMUS_FOURCC_UNFO_LIST:
while( pIRiffStream->Descend( &ckList, &ck, 0 ) == 0 )
{
switch( ckList.ckid )
{
case RIFFINFO_INAM:
case DMUS_FOURCC_UNAM_CHUNK:
{
DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_NAME - 1)));
hr = ReadMBSfromWCS( pIStream, dwLength, m_StyleInfo.m_strName );
if (FAILED(hr))
{
goto ON_ERROR;
}
break;
}
case DMUS_FOURCC_CATEGORY_CHUNK:
{
DWORD dwLength = min(ckList.cksize, (DWORD)(sizeof(WCHAR)*(DMUS_MAX_CATEGORY - 1)));
hr = ReadMBSfromWCS( pIStream, dwLength, m_StyleInfo.m_strCategory );
if (FAILED(hr))
{
goto ON_ERROR;
}
break;
}
}
pIRiffStream->Ascend( &ckList, 0 );
}
break;
case DMUS_FOURCC_PART_LIST:
pPart = m_StyleInfo.AllocPart();
if( pPart == NULL )
{
hr = E_OUTOFMEMORY ;
goto ON_ERROR;
}
hr = pPart->DM_LoadPart( pIRiffStream, &ck, &m_StyleInfo );
if( FAILED( hr ) )
{
m_StyleInfo.DeletePart( pPart );
goto ON_ERROR;
}
if( hr == S_FALSE )
{
// This should not happen when loading a Style!
Trace(0, "LOAD CONFLICT: Two parts with the same Guid.\n");
assert( 0 );
// Bypass this Part because Style already contains a Part
// whose GUID matches pPart->m_guidPartID
m_StyleInfo.DeletePart( pPart );
}
break;
case DMUS_FOURCC_PATTERN_LIST:
StreamSeek( pIStream, dwPos, STREAM_SEEK_SET );
CDirectMusicPattern* pPattern =
new CDirectMusicPattern( &m_StyleInfo.m_TimeSignature, FALSE );
if( pPattern == NULL )
{
hr = E_OUTOFMEMORY ;
goto ON_ERROR;
}
ckList.fccType = DMUS_FOURCC_PATTERN_LIST;
if( pIRiffStream->Descend( &ckList, NULL, MMIO_FINDLIST ) != 0 )
{
hr = E_FAIL;
pPattern->Release();
goto ON_ERROR;
}
hr = pPattern->DM_LoadPattern( pIRiffStream, &ckList, &m_StyleInfo );
pIRiffStream->Ascend( &ckList, 0 );
if( FAILED( hr ) )
{
pPattern->Release();
goto ON_ERROR;
}
TListItem<CDirectMusicPattern*>* pPatternItem =
new TListItem<CDirectMusicPattern*>(pPattern);
if( pPatternItem == NULL )
{
hr = E_OUTOFMEMORY ;
goto ON_ERROR;
}
if( pPattern->m_wEmbellishment & EMB_MOTIF )
{
m_StyleInfo.m_MotifList.AddTail( pPatternItem );
}
else
{
m_StyleInfo.m_PatternList.AddTail( pPatternItem );
}
break;
}
break;
case FOURCC_RIFF:
switch( ck.fccType )
{
case FOURCC_BAND_FORM:
case DMUS_FOURCC_BAND_FORM:
{
TListItem<IDirectMusicBand*>* pBandListItem = new TListItem<IDirectMusicBand*>;
if(pBandListItem)
{
pBandListItem->GetItemValue() = NULL;
// Create a band
hr = CoCreateInstance(CLSID_DirectMusicBand,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicBand,
(void**)&(pBandListItem->GetItemValue()));
}
else
{
hr = E_OUTOFMEMORY;
}
if(SUCCEEDED(hr))
{
// Seek back to begining of Riff chunk
// This is the amount read by Descend when descending into a FOURCC_RIFF chunk
// Get current position
LARGE_INTEGER li;
ULARGE_INTEGER ul;
li.HighPart = 0;
li.LowPart = 0;
hr = pIStream->Seek(li,
STREAM_SEEK_CUR,
&ul);
if(SUCCEEDED(hr))
{
li.HighPart = 0;
// This is always a valid operation
li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
hr = pIStream->Seek(li,
STREAM_SEEK_SET,
&ul);
}
}
if(SUCCEEDED(hr))
{
// Load band
IPersistStream* pIPersistStream;
hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
if (hr != S_OK)
{
hrBand = hr;
}
if(SUCCEEDED(hr))
{
hr = pIPersistStream->Load(pIStream);
pIPersistStream->Release();
DWORD dwFlags = 0;
if(SUCCEEDED(hr))
{
IDirectMusicBandPrivate *pIDMBandP = NULL;
hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pIDMBandP);
if(SUCCEEDED(hr))
{
hr = pIDMBandP->GetFlags(&dwFlags);
if(SUCCEEDED(hr))
{
if( (ck.fccType == FOURCC_BAND_FORM && (dwFlags & DMUSB_DEFAULT)) ||
(ck.fccType == DMUS_FOURCC_BAND_FORM && !fFoundDefault) )
{
// We have a default band
m_StyleInfo.m_pDefaultBand = pBandListItem->GetItemValue();
fFoundDefault = TRUE;
}
}
pIDMBandP->Release();
}
}
}
}
if(FAILED(hr))
{
if(pBandListItem)
{
IDirectMusicBand* pBand = pBandListItem->GetItemValue();
if(pBand)
{
pBand->Release();
}
delete pBandListItem;
}
goto ON_ERROR;
}
EnterCriticalSection(&m_CriticalSection);
(m_StyleInfo.m_BandList).AddHead(pBandListItem);
LeaveCriticalSection(&m_CriticalSection);
}
break;
}
break;
}
pIRiffStream->Ascend( &ck, 0 );
dwPos = StreamTell( pIStream );
}
ON_ERROR:
// Merge the marker event start times in each of the patterns
TListItem<CDirectMusicPattern*>* pPattern;
pPattern = m_StyleInfo.m_PatternList.GetHead();
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
pPattern->GetItemValue()->MergeMarkerEvents(&m_StyleInfo);
}
pPattern = m_StyleInfo.m_MotifList.GetHead();
for (; pPattern != NULL; pPattern = pPattern->GetNext())
{
pPattern->GetItemValue()->MergeMarkerEvents(&m_StyleInfo);
}
pIStream->Release();
if (hr == S_OK && hrBand != S_OK)
{
hr = hrBand;
}
return hr;
}
HRESULT CDMStyle::DM_LoadPersonalityReference( IAARIFFStream* pIRiffStream, MMCKINFO* pckParent)
{
BOOL fDefaultPers = TRUE;
HRESULT hr = S_OK;
if (!pIRiffStream || !pckParent) return E_INVALIDARG;
MMCKINFO ck;
IStream* pIStream = pIRiffStream->GetStream();
if(!pIStream) return E_FAIL;
while (pIRiffStream->Descend( &ck, pckParent, 0 ) == 0)
{
switch (ck.ckid)
{
case FOURCC_LIST:
if (ck.fccType == DMUS_FOURCC_REF_LIST)
{
// Ignore this result: success or failure of loading individual
// ChordMap references should have no bearing on the success or
// failure of loading the style.
//hr = LoadReference(pIStream, pIRiffStream, ck, fDefaultPers);
LoadReference(pIStream, pIRiffStream, ck, fDefaultPers);
fDefaultPers = FALSE;
}
break;
}
pIRiffStream->Ascend( &ck, 0 );
}
pIStream->Release();
return hr;
}
//////////////////////////////////////////////////////////////////////
// CDMStyle::LoadReference
HRESULT CDMStyle::LoadReference(IStream *pStream,
IAARIFFStream *pIRiffStream,
MMCKINFO& ckParent,
BOOL fDefault)
{
if (!pStream || !pIRiffStream) return E_INVALIDARG;
IDirectMusicChordMap* pChordMap;
IDirectMusicLoader* pLoader = NULL;
IDirectMusicGetLoader *pIGetLoader;
HRESULT hr = pStream->QueryInterface( IID_IDirectMusicGetLoader,(void **) &pIGetLoader );
if (FAILED(hr)) return hr;
hr = pIGetLoader->GetLoader(&pLoader);
pIGetLoader->Release();
if (FAILED(hr)) return hr;
DMUS_OBJECTDESC desc;
ZeroMemory(&desc, sizeof(desc));
DWORD cbRead;
MMCKINFO ckNext;
ckNext.ckid = 0;
ckNext.fccType = 0;
DWORD dwSize = 0;
while( pIRiffStream->Descend( &ckNext, &ckParent, 0 ) == 0 )
{
switch(ckNext.ckid)
{
case DMUS_FOURCC_REF_CHUNK:
DMUS_IO_REFERENCE ioDMRef;
hr = pStream->Read(&ioDMRef, sizeof(DMUS_IO_REFERENCE), &cbRead);
if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_REFERENCE))
{
desc.guidClass = ioDMRef.guidClassID;
desc.dwValidData |= ioDMRef.dwValidData;
desc.dwValidData |= DMUS_OBJ_CLASS;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_GUID_CHUNK:
hr = pStream->Read(&(desc.guidObject), sizeof(GUID), &cbRead);
if(SUCCEEDED(hr) && cbRead == sizeof(GUID))
{
desc.dwValidData |= DMUS_OBJ_OBJECT;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_DATE_CHUNK:
hr = pStream->Read(&(desc.ftDate), sizeof(FILETIME), &cbRead);
if(SUCCEEDED(hr) && cbRead == sizeof(FILETIME))
{
desc.dwValidData |= DMUS_OBJ_DATE;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_NAME_CHUNK:
dwSize = min(sizeof(desc.wszName), ckNext.cksize);
hr = pStream->Read(desc.wszName, dwSize, &cbRead);
if(SUCCEEDED(hr) && cbRead == dwSize)
{
desc.wszName[DMUS_MAX_NAME - 1] = L'\0';
desc.dwValidData |= DMUS_OBJ_NAME;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_FILE_CHUNK:
dwSize = min(sizeof(desc.wszFileName), ckNext.cksize);
hr = pStream->Read(desc.wszFileName, dwSize, &cbRead);
if(SUCCEEDED(hr) && cbRead == dwSize)
{
desc.wszFileName[DMUS_MAX_FILENAME - 1] = L'\0';
desc.dwValidData |= DMUS_OBJ_FILENAME;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_CATEGORY_CHUNK:
dwSize = min(sizeof(desc.wszCategory), ckNext.cksize);
hr = pStream->Read(desc.wszCategory, dwSize, &cbRead);
if(SUCCEEDED(hr) && cbRead == dwSize)
{
desc.wszCategory[DMUS_MAX_CATEGORY - 1] = L'\0';
desc.dwValidData |= DMUS_OBJ_CATEGORY;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
case DMUS_FOURCC_VERSION_CHUNK:
DMUS_IO_VERSION ioDMObjVer;
hr = pStream->Read(&ioDMObjVer, sizeof(DMUS_IO_VERSION), &cbRead);
if(SUCCEEDED(hr) && cbRead == sizeof(DMUS_IO_VERSION))
{
desc.vVersion.dwVersionMS = ioDMObjVer.dwVersionMS;
desc.vVersion.dwVersionLS = ioDMObjVer.dwVersionLS;
desc.dwValidData |= DMUS_OBJ_VERSION;
}
else if(SUCCEEDED(hr))
{
hr = E_FAIL;
}
break;
default:
break;
}
if(SUCCEEDED(hr) && pIRiffStream->Ascend(&ckNext, 0) == 0)
{
ckNext.ckid = 0;
ckNext.fccType = 0;
}
else if (SUCCEEDED(hr)) hr = E_FAIL;
}
if (!(desc.dwValidData & DMUS_OBJ_NAME) )
{
hr = E_FAIL;
}
if(SUCCEEDED(hr))
{
desc.dwSize = sizeof(DMUS_OBJECTDESC);
hr = pLoader->GetObject(&desc,IID_IDirectMusicChordMap, (void**)&pChordMap);
if (SUCCEEDED(hr))
{
hr = IncorporatePersonality(pChordMap, desc.wszName, fDefault);
}
}
if (pLoader)
{
pLoader->Release();
}
return hr;
}
HRESULT CDMStyle::IMA25_LoadStyle( IAARIFFStream* pRIFF, MMCKINFO* pckMain )
{
HRESULT hr = S_OK;
HRESULT hrBand = S_OK;
MMCKINFO ck;
DWORD cb;
DWORD cSize;
LPSTREAM pStream;
ioStyle iStyle; // in iostructs.h
BOOL fReadStyle = FALSE;
pStream = pRIFF->GetStream();
while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 )
{
switch( ck.ckid )
{
case FOURCC_STYLE:
fReadStyle = TRUE;
cSize = min( ck.cksize, sizeof( iStyle ) );
hr = pStream->Read( &iStyle, cSize, &cb );
FixBytes( FBT_IOSTYLE, &iStyle );
if( FAILED( hr ) || cb != cSize )
{
hr = E_FAIL;
goto ON_ERR;
}
m_StyleInfo.m_dwVersionMS = m_StyleInfo.m_dwVersionLS = 0; // no version info in IMA 2.5
m_StyleInfo.m_strName = iStyle.wstrName;
m_StyleInfo.m_TimeSignature.m_bBeatsPerMeasure = (BYTE) iStyle.wBPM;
m_StyleInfo.m_TimeSignature.m_bBeat = (BYTE) iStyle.wBeat;
m_StyleInfo.m_TimeSignature.m_wGridsPerBeat = iStyle.wClocksPerBeat / iStyle.wClocksPerClick;
m_StyleInfo.m_dblTempo = iStyle.wTempo;
m_StyleInfo.m_strCategory = iStyle.wstrCategory;
memcpy( &m_StyleInfo.m_guid, &iStyle.guid, sizeof( m_StyleInfo.m_guid ) );
break;
// find ChordMap reference
case FOURCC_PERSONALITYREF:
hr = IMA25_LoadPersonalityReference( pStream, &ck );
if( FAILED( hr ) )
{
goto ON_ERR;
}
break;
case FOURCC_RIFF:
switch( ck.fccType )
{
case FOURCC_BAND_FORM:
{
TListItem<IDirectMusicBand*>* pBandListItem = new TListItem<IDirectMusicBand*>;
if(pBandListItem)
{
pBandListItem->GetItemValue() = NULL;
// Create a band
hr = CoCreateInstance(CLSID_DirectMusicBand,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicBand,
(void**)&(pBandListItem->GetItemValue()));
}
else
{
hr = E_OUTOFMEMORY;
}
if(SUCCEEDED(hr))
{
// Seek back to begining of Riff chunk
// This is the amount read by Descend when descending into a FOURCC_RIFF chunk
// Get current position
LARGE_INTEGER li;
ULARGE_INTEGER ul;
li.HighPart = 0;
li.LowPart = 0;
hr = pStream->Seek(li,
STREAM_SEEK_CUR,
&ul);
if(SUCCEEDED(hr))
{
li.HighPart = 0;
// This is always a valid operation
li.LowPart = ul.LowPart - (2 * sizeof(FOURCC) + sizeof(DWORD));
hr = pStream->Seek(li,
STREAM_SEEK_SET,
&ul);
}
}
if(SUCCEEDED(hr))
{
// Load band
IPersistStream* pIPersistStream;
hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
if(SUCCEEDED(hr))
{
hr = pIPersistStream->Load(pStream);
if (hr != S_OK)
{
hrBand = hr;
}
pIPersistStream->Release();
DWORD dwFlags = 0;
IDirectMusicBandPrivate *pIDMBandP = NULL;
hr = (pBandListItem->GetItemValue())->QueryInterface(IID_IDirectMusicBandPrivate, (void **)&pIDMBandP);
if(SUCCEEDED(hr))
{
hr = pIDMBandP->GetFlags(&dwFlags);
if(SUCCEEDED(hr))
{
if(dwFlags & DMUSB_DEFAULT)
{
// We have a default band
m_StyleInfo.m_pDefaultBand = pBandListItem->GetItemValue();
}
}
pIDMBandP->Release();
}
}
}
if(FAILED(hr))
{
if(pBandListItem)
{
IDirectMusicBand* pBand = pBandListItem->GetItemValue();
if(pBand)
{
pBand->Release();
}
delete pBandListItem;
}
goto ON_ERR;
}
EnterCriticalSection(&m_CriticalSection);
(m_StyleInfo.m_BandList).AddHead(pBandListItem);
LeaveCriticalSection(&m_CriticalSection);
}
break;
// find first pattern
case FOURCC_PATTERN_FORM:
if( fReadStyle )
{
TListItem<CDirectMusicPattern*>* pOldPattern = new TListItem<CDirectMusicPattern*>;
if( pOldPattern == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
CDirectMusicPattern*& rpOldPattern = pOldPattern->GetItemValue();
rpOldPattern = new CDirectMusicPattern;
if( rpOldPattern == NULL )
{
hr = E_OUTOFMEMORY;
goto ON_ERR;
}
hr = rpOldPattern->LoadPattern( pRIFF, &ck, m_StyleInfo.m_PartList, m_StyleInfo);
if( FAILED( hr ) )
{
hr = E_FAIL;
goto ON_ERR;
}
if( ( rpOldPattern->m_wEmbellishment & EMB_MOTIF ) != 0 )
{
EnterCriticalSection( &m_CriticalSection );
m_StyleInfo.m_MotifList.AddTail(pOldPattern);
LeaveCriticalSection( &m_CriticalSection );
}
else
{
EnterCriticalSection( &m_CriticalSection );
m_StyleInfo.m_PatternList.AddTail(pOldPattern);
LeaveCriticalSection( &m_CriticalSection );
}
}
break;
}
break;
}
pRIFF->Ascend( &ck, 0 );
}
ON_ERR:
pStream->Release();
// sort here
TListItem<DirectMusicPart*>* pPartItem = m_StyleInfo.m_PartList.GetHead();
for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
{
pPartItem->GetItemValue()->EventList.MergeSort(m_StyleInfo.m_TimeSignature);
}
if (hr == S_OK && hrBand != S_OK)
{
hr = hrBand;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// DMStyleStruct::FindPartByGUID
DirectMusicPart* DMStyleStruct::FindPartByGUID( GUID guidPartID )
{
DirectMusicPart* pThePart = NULL;
DirectMusicPart* pPart;
TListItem<DirectMusicPart*>* pScan = m_PartList.GetHead();
for (; pScan; pScan = pScan->GetNext() )
{
pPart = pScan->GetItemValue();
if( ::IsEqualGUID( pPart->m_guidPartID, guidPartID ) )
{
pThePart = pPart;
break;
}
}
return pThePart;
}
/////////////////////////////////////////////////////////////////////////////
// DMStyleStruct::AllocPart
DirectMusicPart* DMStyleStruct::AllocPart( )
{
DirectMusicPart* pPart = new DirectMusicPart(&m_TimeSignature);
if (pPart)
{
TListItem<DirectMusicPart*>* pPartItem = new TListItem<DirectMusicPart*>(pPart);
if( pPartItem)
{
// Add Part to Style's list of Parts
m_PartList.AddTail( pPartItem );
}
else
{
delete pPart;
pPart = NULL;
}
}
return pPart;
}
/////////////////////////////////////////////////////////////////////////////
// DMStyleStruct::DeletePart
void DMStyleStruct::DeletePart( DirectMusicPart* pPart )
{
TListItem<DirectMusicPart*>* pPartItem = m_PartList.GetHead();
TListItem<DirectMusicPart*>* pPrevious = NULL;
for ( ; pPartItem; pPartItem = pPartItem->GetNext() )
{
DirectMusicPart* pScan = pPartItem->GetItemValue();
if (pPart == pScan)
{
pScan->Release();
if (pPrevious)
{
pPrevious->SetNext(pPartItem->GetNext());
}
else
{
m_PartList.RemoveHead();
}
pPartItem->SetNext(NULL);
delete pPartItem;
break;
}
pPrevious = pPartItem;
}
}
HRESULT DMStyleStruct::GetCommand(
MUSIC_TIME mtTime,
MUSIC_TIME mtOffset,
IDirectMusicPerformance* pPerformance,
IDirectMusicSegment* pSegment,
DWORD dwGroupID,
DMUS_COMMAND_PARAM_2* pCommand,
BYTE& rbActualCommand)
{
HRESULT hr = S_OK;
if (!pPerformance && !pSegment) return E_INVALIDARG;
if (pPerformance)
{
hr = pPerformance->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtTime + mtOffset,
NULL, ((void*) pCommand));
}
else
{
hr = pSegment->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtTime,
NULL, ((void*) pCommand));
}
if (FAILED(hr)) return hr;
// Look at the command's mtTime to see how far in the past it occurred. If a measure
// or more, keep the groove level but make the command a regular groove.
MUSIC_TIME mtMeasureTime = (MUSIC_TIME) m_TimeSignature.ClocksPerMeasure();
//TraceI(0, "Now: %d Offset: %d Command: %x, Groove Level: %d, Command time: %d Measure time: %d\n",
// mtTime, mtOffset, pCommand->bCommand, pCommand->bGrooveLevel, pCommand->mtTime, mtMeasureTime);
rbActualCommand = pCommand->bCommand;
if (pCommand->mtTime + mtMeasureTime <= 0 ||
(pCommand->mtTime + mtMeasureTime < mtMeasureTime &&
(mtMeasureTime + pCommand->mtTime) % mtMeasureTime) )
{
pCommand->bCommand = DMUS_COMMANDT_GROOVE;
}
return hr;
}
struct TaggedCommands
{
TaggedCommands()
{
m_pCommands = NULL;
m_pRhythms = NULL;
m_mtTag = 0;
}
HRESULT Init(MUSIC_TIME mtTag, int nSize, int nGlobalGroove)
{
HRESULT hr = S_OK;
m_mtTag = mtTag;
m_pCommands = new DMUS_COMMAND_PARAM_2 [nSize];
m_pRhythms = new DWORD [nSize];
if (!m_pCommands || !m_pRhythms)
{
Cleanup();
hr = E_OUTOFMEMORY;
}
else
{
int nGroove = 62 + nGlobalGroove;
if (nGroove > 100) nGroove = 100;
if (nGroove < 1) nGroove = 1;
m_pCommands[0].bGrooveLevel = (BYTE)nGroove;
m_pCommands[0].bGrooveLevel = 62;
m_pCommands[0].bGrooveRange = 0;
m_pCommands[0].bCommand = DMUS_COMMANDT_GROOVE;
m_pCommands[0].bRepeatMode = DMUS_PATTERNT_RANDOM;
m_pRhythms[0] = 0;
}
return hr;
}
void Cleanup()
{
if (m_pCommands) delete [] m_pCommands;
if (m_pRhythms) delete [] m_pRhythms;
}
~TaggedCommands()
{
Cleanup();
}
MUSIC_TIME m_mtTag;
DMUS_COMMAND_PARAM_2* m_pCommands;
DWORD* m_pRhythms;
};
TListItem<TaggedCommands>* FindTaggedCommands(MUSIC_TIME mtTag, TList<TaggedCommands>& rCommands)
{
TListItem<TaggedCommands>* pScan = rCommands.GetHead();
for(; pScan; pScan = pScan->GetNext())
{
if (pScan->GetItemValue().m_mtTag == mtTag) return pScan;
}
return NULL;
}
CDirectMusicPattern* DMStyleStruct::SelectPattern(bool fNewMode,
DMUS_COMMAND_PARAM_2* pCommands,
StyleTrackState* StyleTrackState,
PatternDispatcher& rDispatcher)
{
if (rDispatcher.IsEmpty()) return NULL;
if (!UsingDX8() || !StyleTrackState)
{
return rDispatcher.RandomSelect();
}
CDirectMusicPattern* pResult = NULL;
TListItem<CDirectMusicPattern*>* pNew = NULL;
TListItem<CDirectMusicPattern*>* pScan = NULL;
int nIndex = 0;
if (pCommands)
{
switch (pCommands[0].bRepeatMode)
{
case DMUS_PATTERNT_RANDOM:
pResult = rDispatcher.RandomSelect();
break;
case DMUS_PATTERNT_REPEAT:
pResult = (!fNewMode && S_OK == rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex))
? StyleTrackState->m_pPattern : rDispatcher.RandomSelect();
break;
case DMUS_PATTERNT_SEQUENTIAL:
case DMUS_PATTERNT_RANDOM_START:
if (fNewMode)
{
if (pCommands[0].bRepeatMode == DMUS_PATTERNT_SEQUENTIAL)
{
pResult = rDispatcher.GetItem(0);
}
else
{
pResult = rDispatcher.RandomSelect();
}
}
else
{
HRESULT hr = rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex);
if (hr == S_OK && rDispatcher.GetItem(nIndex + 1))
{
pResult = rDispatcher.GetItem(nIndex + 1);
}
else
{
pResult = rDispatcher.GetItem(0);
}
}
break;
case DMUS_PATTERNT_NO_REPEAT:
if (!fNewMode)
{
HRESULT hr = rDispatcher.FindPattern(StyleTrackState->m_pPattern, nIndex);
if (hr == S_OK)
{
rDispatcher.SetTag(nIndex, REMOVED);
}
}
pResult = rDispatcher.RandomSelect();
break;
case DMUS_PATTERNT_RANDOM_ROW:
if (fNewMode)
{
StyleTrackState->m_PlayedPatterns.CleanUp();
}
pScan = StyleTrackState->m_PlayedPatterns.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
HRESULT hr = rDispatcher.FindPattern(pScan->GetItemValue(), nIndex);
if (hr == S_OK)
{
rDispatcher.SetTag(nIndex, RANDOM_ROW);
}
}
if (rDispatcher.IsEmpty()) // start over, but avoid the one just played
{
rDispatcher.RestorePatterns(RANDOM_ROW);
pScan = StyleTrackState->m_PlayedPatterns.GetHead();
if (pScan)
{
HRESULT hr = rDispatcher.FindPattern(pScan->GetItemValue(), nIndex);
if (hr == S_OK)
{
rDispatcher.SetTag(nIndex, RANDOM_ROW);
}
}
StyleTrackState->m_PlayedPatterns.CleanUp();
}
pResult = rDispatcher.RandomSelect();
if (pResult)
{
pNew = new TListItem<CDirectMusicPattern*>(pResult);
if (pNew)
{
StyleTrackState->m_PlayedPatterns.AddHead(pNew);
}
}
break;
default:
pResult = rDispatcher.RandomSelect();
break;
}
}
return pResult;
}
HRESULT DMStyleStruct::GetPattern(
bool fNewMode,
MUSIC_TIME mtNow,
MUSIC_TIME mtOffset,
StyleTrackState* pStyleTrackState,
IDirectMusicPerformance* pPerformance,
IDirectMusicSegment* pSegment,
CDirectMusicPattern*& rpTargetPattern,
MUSIC_TIME& rmtMeasureTime,
MUSIC_TIME& rmtNextCommand)
{
if (!pSegment && !pPerformance) return E_INVALIDARG;
static aMatchType[5] =
{MATCH_COMMAND_AND_RHYTHM, MATCH_COMMAND_FULL, MATCH_COMMAND_PARTIAL, MATCH_EMBELLISHMENT, MATCH_GROOVE_LEVEL};
HRESULT hr = S_OK;
MUSIC_TIME mtNextStyleTime = pStyleTrackState ? pStyleTrackState->m_mtNextStyleTime : 0;
DMUS_RHYTHM_PARAM ChordRhythm;
TList<TaggedCommands> Commands;
int nLongestPattern = 0;
int nPatternLength = 1;
DWORD dwGroupID = pStyleTrackState ? pStyleTrackState->m_dwGroupID : 0xffffffff;
TListItem<CDirectMusicPattern*> *pPatternItem = m_PatternList.GetHead();
for (; pPatternItem != NULL; pPatternItem = pPatternItem->GetNext())
{
CDirectMusicPattern*& rpPattern = pPatternItem->GetItemValue();
if (rpPattern->m_wNumMeasures > nLongestPattern)
nLongestPattern = rpPattern->m_wNumMeasures;
}
if (nLongestPattern <= 0) return E_POINTER;
char chGroove;
if (!pPerformance ||
!SUCCEEDED(pPerformance->GetGlobalParam((GUID)GUID_PerfMasterGrooveLevel, &chGroove, 1)))
{
chGroove = 0;
}
DMUS_COMMAND_PARAM_2 CommandParam;
// this call to GetParam is for rmtNextCommand only (?)
HRESULT hrCommand = E_FAIL;
if (pPerformance)
{
hrCommand = pPerformance->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtNow + mtOffset,
&rmtNextCommand, ((void*) &CommandParam));
}
else
{
hrCommand = pSegment->GetParam(GUID_CommandParam2, dwGroupID, DMUS_SEG_ANYTRACK, mtNow,
&rmtNextCommand, ((void*) &CommandParam));
}
if (DMUS_E_TRACK_NOT_FOUND == hrCommand || rmtNextCommand <= 0) // Happens if the performance can't find a segment with a command track
{
if (mtNextStyleTime) rmtNextCommand = mtNextStyleTime;
else if (pStyleTrackState && pStyleTrackState->m_pSegState)
{
MUSIC_TIME mtLength = 0;
IDirectMusicSegment* pTmpSegment = NULL;
if (SUCCEEDED(pStyleTrackState->m_pSegState->GetSegment(&pTmpSegment)))
{
hr = pTmpSegment->GetLength(&mtLength);
pTmpSegment->Release();
// GetLength may return DMUS_S_GARBAGE_COLLECTED which FAILED will not catch
if(hr != S_OK)
{
mtLength = 0x7FFFFFFF;
}
}
rmtNextCommand = mtLength - mtNow;
}
else rmtNextCommand = 0;
}
MUSIC_TIME mtStyleDifference = mtNextStyleTime ? mtNextStyleTime - mtNow : 0;
if ( mtStyleDifference > 0 && (!rmtNextCommand || mtStyleDifference < rmtNextCommand) )
{
rmtNextCommand = mtStyleDifference;
}
if (pStyleTrackState)
{
if (FAILED(hrCommand) || pStyleTrackState->m_CommandData.bRepeatMode != CommandParam.bRepeatMode)
{
fNewMode = true;
}
pStyleTrackState->m_CommandData = CommandParam;
pStyleTrackState->m_CommandData.bGrooveLevel += chGroove;
}
TListItem<TaggedCommands>* pTaggedCommands = NULL;
PatternDispatcher Dispatcher(m_PatternList, rmtNextCommand, mtNow, mtOffset, pStyleTrackState, pPerformance, this);
// find a pattern matching the chord rhythm and command
for (int nMatch = 0; nMatch < 5; nMatch++, Dispatcher.RestoreAllPatterns())
{
if (nMatch > 2 && !UsingDX8()) break; // only do these for dx8
// while more pattern lengths:
do
{
// divide current list into those with the longest patterns and eveything else
Dispatcher.ResetMeasures();
Dispatcher.Scan(FIND_LONGEST_PATTERN);
Dispatcher.Filter(COLLECT_LONGEST_PATTERN);
// while more time signatures:
do
{
int nLength = 0;
DirectMusicTimeSig TimeSig;
// divide list into those with "longest" time sigs and everything else
Dispatcher.ResetTimeSig();
Dispatcher.Scan(FIND_LONGEST_TIMESIG);
Dispatcher.Filter(COLLECT_LONGEST_TIMESIG);
// fill up pCommands and pRhythms (also get mtMeasureTime, based on time sig)
CDirectMusicPattern* pFirstPattern = Dispatcher.GetItem(0);
MUSIC_TIME mtMeasureTime = 0;
if (pFirstPattern)
{
TimeSig = pFirstPattern->TimeSignature(this);
nLength = pFirstPattern->m_wNumMeasures;
}
else
{
TimeSig = m_TimeSignature;
}
mtMeasureTime = TimeSig.ClocksPerMeasure();
Dispatcher.SetMeasureTime(mtMeasureTime);
IDirectMusicStyle* pThisStyle = NULL;
MUSIC_TIME mtNextStyle = 0;
if (SUCCEEDED(pPerformance->GetParam(GUID_IDirectMusicStyle, dwGroupID, DMUS_SEG_ANYTRACK, mtNow + mtOffset,
&mtNextStyle, (void*) &pThisStyle)))
{
if (mtNextStyle && mtMeasureTime)
{
nPatternLength = (mtNextStyle / mtMeasureTime);
if (!nPatternLength) nPatternLength = 1;
}
if (nPatternLength > nLongestPattern) nPatternLength = nLongestPattern;
pThisStyle->Release();
}
Dispatcher.SetPatternLength(nPatternLength);
pTaggedCommands = FindTaggedCommands(mtMeasureTime, Commands);
if (!pTaggedCommands)
{
pTaggedCommands = new TListItem<TaggedCommands>;
if (!pTaggedCommands) return E_OUTOFMEMORY;
TaggedCommands& rCommands = pTaggedCommands->GetItemValue();
hr = rCommands.Init(mtMeasureTime, nPatternLength, chGroove);
if (FAILED(hr)) return hr;
Commands.AddHead(pTaggedCommands);
if (SUCCEEDED(hrCommand))
{
HRESULT hrChord = S_OK;
// get chord rhythm for next measure(s)
// get command for next measure(s)
ChordRhythm.TimeSig = TimeSig;
for (short i = 0; i < nPatternLength; i++)
{
BYTE bActualCommand;
if (S_OK != GetCommand(mtNow + (i * mtMeasureTime),
mtOffset, pPerformance, pSegment, dwGroupID, &CommandParam,
bActualCommand))
{
break;
}
rCommands.m_pCommands[i] = CommandParam;
short nGroove = CommandParam.bGrooveLevel + chGroove;
if (nGroove > 100) nGroove = 100;
if (nGroove < 1) nGroove = 1;
rCommands.m_pCommands[i].bGrooveLevel = (BYTE)nGroove;
if (pPerformance)
{
hrChord = pPerformance->GetParam(GUID_RhythmParam, dwGroupID, DMUS_SEG_ANYTRACK, (mtNow + (i * mtMeasureTime) + mtOffset),
NULL, (void*) &ChordRhythm);
}
else
{
hrChord = pSegment->GetParam(GUID_RhythmParam, dwGroupID, DMUS_SEG_ANYTRACK, (mtNow + (i * mtMeasureTime)),
NULL, (void*) &ChordRhythm);
}
if (SUCCEEDED(hrChord))
{
rCommands.m_pRhythms[i] = ChordRhythm.dwRhythmPattern;
}
else
{
rCommands.m_pRhythms[i] = 0;
}
TraceI(3, "NOW: %d, i: %d, Groove level: %d, command: %d, rhythm: %x\n",
mtNow + (i * mtMeasureTime), i, rCommands.m_pCommands[i].bGrooveLevel,
rCommands.m_pCommands[i].bCommand, rCommands.m_pRhythms[i]);
}
}
}
TaggedCommands& rCommands = pTaggedCommands->GetItemValue();
Dispatcher.SetCommands(rCommands.m_pCommands, rCommands.m_pRhythms);
// filter best matches, using aMatchType[nMatch]
// (MATCH_COMMAND_AND_RHYTHM also needs to filter with MATCH_RHYTHM_BITS)
// break on match
if (aMatchType[nMatch] == MATCH_COMMAND_AND_RHYTHM)
{
Dispatcher.ResetRhythms();
}
Dispatcher.Filter(aMatchType[nMatch]);
if (!Dispatcher.IsEmpty())
{
if (aMatchType[nMatch] == MATCH_COMMAND_AND_RHYTHM)
{
Dispatcher.Filter(MATCH_RHYTHM_BITS);
if (!Dispatcher.IsEmpty()) break;
Dispatcher.RestorePatterns(MATCH_RHYTHM_BITS);
}
else break;
}
Dispatcher.ReplacePatterns(COLLECT_LONGEST_TIMESIG, REMOVED);
TraceI(2, "Failed Match: %d (%d, %d/%d)\n",
nMatch, nLength, TimeSig.m_bBeatsPerMeasure, TimeSig.m_bBeat);
} while (!Dispatcher.IsEmpty());
if (!Dispatcher.IsEmpty()) break;
Dispatcher.ReplacePatterns(COLLECT_LONGEST_PATTERN, REMOVED);
} while (!Dispatcher.IsEmpty());
if (!Dispatcher.IsEmpty()) break;
}
if (!Dispatcher.IsEmpty())
{
//TraceI(2, "Filtering Destinations...\n");
Dispatcher.Filter(MATCH_NEXT_COMMAND);
if (Dispatcher.IsEmpty())
{
Dispatcher.RestorePatterns(MATCH_NEXT_COMMAND);
}
rpTargetPattern = SelectPattern(fNewMode, pTaggedCommands->GetItemValue().m_pCommands, pStyleTrackState, Dispatcher);
}
// if all searches failed, select the first pattern
if (!rpTargetPattern)
{
TraceI(1, "ALL SEARCHES FAILED\n");
TListItem<CDirectMusicPattern*> *pPattern = m_PatternList.GetHead();
if (pPattern) // if this is NULL, something's wrong
{
rpTargetPattern = pPattern->GetItemValue();
}
}
if (rpTargetPattern) // if pTargetPattern is NULL, something's really wrong
{
rmtMeasureTime = rpTargetPattern->TimeSignature(this).ClocksPerMeasure();
if (pStyleTrackState)
{
hr = pStyleTrackState->InitPattern(rpTargetPattern, mtNow);
}
TraceI(2, "Pattern: %S (%d, %d/%d) [%d]\n",
//TraceI(0, "Pattern: %S (%d, %d/%d) [%d]\n",
(const WCHAR *)rpTargetPattern->m_strName, rpTargetPattern->m_wNumMeasures,
rpTargetPattern->TimeSignature(this).m_bBeatsPerMeasure,
rpTargetPattern->TimeSignature(this).m_bBeat, mtNow);
}
else hr = E_POINTER;
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// AdjoinPChannel
HRESULT AdjoinPChannel(TList<DWORD>& rPChannelList, DWORD dwPChannel)
{
TListItem<DWORD>* pScan = rPChannelList.GetHead();
for (; pScan; pScan = pScan->GetNext() )
{
DWORD rdwPChannel = pScan->GetItemValue();
if( dwPChannel == rdwPChannel )
{
return S_OK;
}
}
TListItem<DWORD>* pNew = new TListItem<DWORD>(dwPChannel);
if (!pNew) return E_OUTOFMEMORY;
rPChannelList.AddHead(pNew);
return S_OK;
}
static inline BOOL InversionPoint(char chNote, DWORD dwInvertPattern)
{
if (chNote < 0 || chNote >= 24) return FALSE;
return (dwInvertPattern >> chNote) & 1;
}
static BYTE NotePosition(char chMidiValue, BYTE bRoot)
{
chMidiValue -= bRoot;
while (chMidiValue < 0) chMidiValue += 12;
while (chMidiValue > 23) chMidiValue -= 12;
return (BYTE)chMidiValue;
}
static char InversionAmountLow(
BYTE bMidiValue,
BYTE bLower,
DWORD dwInvertPattern,
BYTE bRoot)
{
char chResult = 0;
TraceI(3, "InversionAmountLow: MidiValue: %d, Lower: %d, Pattern: %X, Root: %d\n",
bMidiValue, bLower, dwInvertPattern, bRoot);
char chDifference = (char) (bLower - bMidiValue);
char chPosition = NotePosition(bMidiValue, bRoot);
while (chDifference > 23) chDifference -= 24;
TraceI(3, "Position: %d Difference: %d\n", chPosition, chDifference);
// Right now I'm checking both endpoints. Is this what I want?
for (char i = chPosition; chDifference >= 0; (i = (i < 23) ? i + 1 : 0), chDifference--)
{
if (InversionPoint(i, dwInvertPattern)) break;
}
if (chDifference >= 0)
{
while (bLower > bMidiValue + chResult)
{
chResult += 12;
}
}
TraceI(3, "Result: %d\n", chResult);
return chResult;
}
static char InversionAmountHigh(
BYTE bMidiValue,
BYTE bUpper,
DWORD dwInvertPattern,
BYTE bRoot)
{
char chResult = 0;
TraceI(3, "InversionAmountHigh: MidiValue: %d, Upper: %d, Pattern: %X, Root: %d\n",
bMidiValue, bUpper, dwInvertPattern, bRoot);
char chDifference = (char) (bMidiValue - bUpper);
char chPosition = NotePosition(bMidiValue, bRoot);
while (chDifference > 23) chDifference -= 24;
TraceI(3, "Position: %d Difference: %d\n", chPosition, chDifference);
// Right now I'm checking both endpoints. Is this what I want?
for (char i = chPosition; chDifference >= 0; (i = (i > 0) ? i - 1 : 23), chDifference--)
{
if (InversionPoint(i, dwInvertPattern)) break;
}
if (chDifference >= 0)
{
while ((char)bMidiValue + chResult > (char)bUpper)
{
chResult -= 12;
}
}
TraceI(3, "Result: %d\n", chResult);
return chResult;
}
static char InversionAmount(
BYTE bMidiValue,
BYTE bLower,
BYTE bUpper,
DWORD dwInvertPattern,
BYTE bRoot)
{
char chResult = 0;
if (bMidiValue <= 0 || bMidiValue > 127) return 0;
if (dwInvertPattern & 0xff000000)
{
while (bMidiValue + chResult < bLower) chResult += 12;
while (bMidiValue + chResult > bUpper) chResult -= 12;
return chResult;
}
TraceI(4, "InversionAmount: MidiValue: %d, Lower: %d, Upper: %d, Pattern: %X, Root: %d\n",
bMidiValue, bLower, bUpper, dwInvertPattern, bRoot);
if (bLower <= bMidiValue && bMidiValue <= bUpper) return 0;
if (bMidiValue < bLower)
{
chResult = InversionAmountLow(bMidiValue, bLower, dwInvertPattern, bRoot);
}
else
{
chResult = InversionAmountHigh(bMidiValue, bUpper, dwInvertPattern, bRoot);
}
return chResult;
}
HRESULT DirectMusicPartRef::ConvertMusicValue(CDMStyleNote* pNoteEvent,
DMUS_CHORD_PARAM& rCurrentChord,
BYTE bPlayModeFlags,
BOOL fPlayAsIs,
InversionGroup aInversionGroups[],
IDirectMusicPerformance* pPerformance,
BYTE& rbMidiValue,
short& rnMidiOffset)
{
bool fReleasePerformance = false;
if (!pPerformance)
{
fReleasePerformance = true;
if( FAILED( CoCreateInstance( CLSID_DirectMusicPerformance,
NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance,
(void**)&pPerformance )))
{
return E_FAIL;
}
}
// music value is computed using the current chord info and the playmode flags
// musicvalue is a MIDI note value (0-127)
WORD wMV = pNoteEvent->m_wMusicValue;
short nMidiOffset = 0;
if (bPlayModeFlags != DMUS_PLAYMODE_FIXED)
{
DMSubChord rSubChord;
DWORD dwLevel = 1 << m_bSubChordLevel;
DWORD dwIndex;
for (dwIndex = 0; dwIndex < rCurrentChord.bSubChordCount; dwIndex++)
{
if (dwLevel & rCurrentChord.SubChordList[dwIndex].dwLevels)
{
rSubChord = rCurrentChord.SubChordList[dwIndex];
break;
}
}
if (dwIndex == rCurrentChord.bSubChordCount)
{
rSubChord = rCurrentChord.SubChordList[0];
dwIndex = 0;
}
DMUS_CHORD_KEY ChordAndKey;
ZeroMemory(&ChordAndKey, sizeof(DMUS_CHORD_KEY));
ChordAndKey.dwScale = rCurrentChord.dwScale;
ChordAndKey.bSubChordCount = rCurrentChord.bSubChordCount;
ChordAndKey.bKey = rCurrentChord.bKey;
ChordAndKey.bFlags = 0;
ChordAndKey.SubChordList[dwIndex].bChordRoot = rSubChord.m_bChordRoot;
ChordAndKey.SubChordList[dwIndex].bScaleRoot = rSubChord.m_bScaleRoot;
ChordAndKey.SubChordList[dwIndex].dwChordPattern = rSubChord.m_dwChordPattern;
ChordAndKey.SubChordList[dwIndex].dwLevels = rSubChord.m_dwLevels;
ChordAndKey.SubChordList[dwIndex].dwScalePattern = rSubChord.m_dwScalePattern;
BYTE bChordRoot = 0;
HRESULT hrChordRoot = pPerformance->MusicToMIDI(
(pNoteEvent->m_wMusicValue & 0xf000),
&ChordAndKey,
bPlayModeFlags,
m_bSubChordLevel,
&bChordRoot);
if (bPlayModeFlags == DMUS_PLAYMODE_CHORD_ROOT) // fixed to chord
{
wMV += (rSubChord.m_bChordRoot % 24);
}
else if (bPlayModeFlags == DMUS_PLAYMODE_SCALE_ROOT) // fixed to scale
{
wMV += rCurrentChord.bKey;
}
else
{
BYTE bMIDIVal;
HRESULT hrTest = pPerformance->MusicToMIDI(
pNoteEvent->m_wMusicValue,
&ChordAndKey,
bPlayModeFlags,
m_bSubChordLevel,
&bMIDIVal);
if (hrTest == S_OK)
{
wMV = bMIDIVal;
}
else
{
wMV = 0;
}
}
if (wMV && !fPlayAsIs )
{
if (pNoteEvent->m_bInversionId == 0)
{
nMidiOffset = InversionAmount((BYTE)wMV,
m_pDMPart->m_bInvertLower,
m_pDMPart->m_bInvertUpper,
rSubChord.m_dwInversionPoints,
bChordRoot);
}
else // handle inversion groups
{
short nIndex = FindGroup(aInversionGroups, pNoteEvent->m_bInversionId);
if (nIndex >= 0) // invert according to the existing group
{
nMidiOffset = aInversionGroups[nIndex].m_nOffset;
aInversionGroups[nIndex].m_wCount--;
if (aInversionGroups[nIndex].m_wCount == 0)
aInversionGroups[nIndex].m_wGroupID = 0;
}
else // create a new inversion group
{
// 1. find out how many events have this group id for a count
WORD wCount = 1; // for this event...
CDirectMusicEventItem* pScan = pNoteEvent->GetNext();
for (; pScan; pScan = pScan->GetNext())
{
if (pScan->m_dwEventTag == DMUS_EVENT_NOTE)
{
CDMStyleNote* pScanEvent = (CDMStyleNote*)pScan;
if (pScanEvent->m_bInversionId == pNoteEvent->m_bInversionId)
wCount++;
}
}
// 2. call InversionAmount for an offset
short nOffset = InversionAmount((BYTE)wMV,
m_pDMPart->m_bInvertLower,
m_pDMPart->m_bInvertUpper,
rSubChord.m_dwInversionPoints,
bChordRoot);
// 3. call AddGroup with the id, count, and offset
short nIndex2 = AddGroup(aInversionGroups, pNoteEvent->m_bInversionId, wCount, nOffset);
// 4. If the add was successful, do the inversion.
if (nIndex2 >= 0)
{
nMidiOffset = aInversionGroups[nIndex2].m_nOffset;
aInversionGroups[nIndex2].m_wCount--;
if (aInversionGroups[nIndex2].m_wCount == 0)
aInversionGroups[nIndex2].m_wGroupID = 0;
}
}
}
}
}
wMV += nMidiOffset;
while (wMV < 0) wMV += 12;
while (wMV > 127) wMV -= 12;
// NOT IMPLEMENTED: Don't play notes with low priority when the device
// runs out of notes
rbMidiValue = (BYTE) wMV;
rnMidiOffset = nMidiOffset;
if (fReleasePerformance) pPerformance->Release();
return S_OK;
}
HRESULT DirectMusicPartRef::ConvertMIDIValue(BYTE bMIDI,
DMUS_CHORD_PARAM& rCurrentChord,
BYTE bPlayModeFlags,
IDirectMusicPerformance* pPerformance,
WORD& rwMusicValue)
{
HRESULT hr = S_OK;
bool fReleasePerformance = false;
if (!pPerformance)
{
fReleasePerformance = true;
if( FAILED( CoCreateInstance( CLSID_DirectMusicPerformance,
NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance,
(void**)&pPerformance )))
{
return E_FAIL;
}
}
if (bPlayModeFlags != DMUS_PLAYMODE_FIXED)
{
DMSubChord rSubChord;
DWORD dwLevel = 1 << m_bSubChordLevel;
DWORD dwIndex;
for (dwIndex = 0; dwIndex < rCurrentChord.bSubChordCount; dwIndex++)
{
if (dwLevel & rCurrentChord.SubChordList[dwIndex].dwLevels)
{
rSubChord = rCurrentChord.SubChordList[dwIndex];
break;
}
}
if (dwIndex == rCurrentChord.bSubChordCount)
{
rSubChord = rCurrentChord.SubChordList[0];
dwIndex = 0;
}
DMUS_CHORD_KEY ChordAndKey;
ZeroMemory(&ChordAndKey, sizeof(DMUS_CHORD_KEY));
ChordAndKey.dwScale = rCurrentChord.dwScale;
ChordAndKey.bSubChordCount = rCurrentChord.bSubChordCount;
ChordAndKey.bKey = rCurrentChord.bKey;
ChordAndKey.bFlags = 0;
ChordAndKey.SubChordList[dwIndex].bChordRoot = rSubChord.m_bChordRoot;
ChordAndKey.SubChordList[dwIndex].bScaleRoot = rSubChord.m_bScaleRoot;
ChordAndKey.SubChordList[dwIndex].dwChordPattern = rSubChord.m_dwChordPattern;
ChordAndKey.SubChordList[dwIndex].dwLevels = rSubChord.m_dwLevels;
ChordAndKey.SubChordList[dwIndex].dwScalePattern = rSubChord.m_dwScalePattern;
hr = pPerformance->MIDIToMusic(
bMIDI,
&ChordAndKey,
bPlayModeFlags,
m_bSubChordLevel,
&rwMusicValue);
}
if (fReleasePerformance) pPerformance->Release();
return hr;
}
short FindGroup(InversionGroup aGroup[], WORD wID)
{
for (short n = 0; n < INVERSIONGROUPLIMIT; n++)
if (wID == aGroup[n].m_wGroupID)
return n;
return -1;
}
short AddGroup(InversionGroup aGroup[], WORD wID, WORD wCount, short nOffset)
{
for (short n = 0; n < INVERSIONGROUPLIMIT; n++)
{
if (aGroup[n].m_wGroupID == 0)
{
aGroup[n].m_wGroupID = wID;
aGroup[n].m_wCount = wCount;
aGroup[n].m_nOffset = nOffset;
return n;
}
}
return -1;
}
inline DWORD CleanupScale(DWORD dwPattern)
// Force scale to be exactly two octaves
{
dwPattern &= 0x0FFF; // Clear upper octave.
dwPattern |= (dwPattern << 12); // Copy lower octave to top.
return dwPattern;
}
inline BYTE RelativeRoot(char chChordRoot, char chScaleRoot)
{
// is there any reason this should be > 12?
while (chScaleRoot > chChordRoot) chChordRoot += 12;
BYTE bResult = chChordRoot - chScaleRoot;
return bResult % 12;
}
// returns 1 - 7 for scale positions I - VII and 0 if chord isn't in scale
BYTE ScalePosition(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
{
DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
if (dwRootBit & dwScalePattern)
{
BYTE bResult = 0;
while (dwRootBit > 0)
{
if (dwRootBit & dwScalePattern)
bResult++;
dwRootBit >>= 1;
}
return bResult;
}
else return 0;
}
// returns 1 - 7 for scale positions #I - #VII, 0 if not a sharp position
BYTE ScalePositionSharp(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
{
DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
// now shift to see if this is sharp from the next position down
if (dwRootBit == 1) dwRootBit <<= 11;
else dwRootBit >>= 1;
if (dwRootBit & dwScalePattern)
{
BYTE bResult = 0;
while (dwRootBit > 0)
{
if (dwRootBit & dwScalePattern)
bResult++;
dwRootBit >>= 1;
}
return bResult;
}
else return 0;
}
// returns 1 - 7 for scale positions bI - bVII, 0 if not a flat position
BYTE ScalePositionFlat(DMSubChord& rSubChord, BYTE bKey, DWORD dwScale)
{
DWORD dwScalePattern = dwScale ? CleanupScale(dwScale) : DEFAULT_SCALE_PATTERN;
DWORD dwRootBit = (DWORD) (1 << RelativeRoot(rSubChord.m_bChordRoot, bKey));
// now shift to see if this is flat from the next position up
if (dwRootBit == (1 << 11)) dwRootBit = 1;
else dwRootBit <<= 1;
if (dwRootBit & dwScalePattern)
{
BYTE bResult = 0;
while (dwRootBit > 0)
{
if (dwRootBit & dwScalePattern)
bResult++;
dwRootBit >>= 1;
}
return bResult;
}
else return 0;
}
bool IsSimple(DMUS_CHORD_PARAM& Chord)
{
if (Chord.bSubChordCount <= 1)
{
return true;
}
else
{
bool fResult = true;
for (int n = 1; n < Chord.bSubChordCount; n++)
{
if ( (Chord.SubChordList[n].dwChordPattern != Chord.SubChordList[0].dwChordPattern) ||
(Chord.SubChordList[n].dwScalePattern != Chord.SubChordList[0].dwScalePattern) ||
(Chord.SubChordList[n].bChordRoot != Chord.SubChordList[0].bChordRoot) ||
(Chord.SubChordList[n].bScaleRoot != Chord.SubChordList[0].bScaleRoot) )
{
fResult = false;
break;
}
}
return fResult;
}
}
bool IsSimple(DMUS_CHORD_PARAM& Chord, int& rCount, int& rSixSeven)
{
// Combine all the notes from all chord patterns into one pattern
DWORD dwMOAPatterns = 0;
int nBaseRoot = Chord.SubChordList[0].bChordRoot;
for (int n = 0; n < Chord.bSubChordCount; n++)
{
int nShift = (int)Chord.SubChordList[n].bChordRoot - nBaseRoot;
while (nShift < 0) nShift += 12;
dwMOAPatterns |= (Chord.SubChordList[n].dwChordPattern << nShift);
}
// Fold both octaves of the pattern together
DWORD dwHighOctave = (dwMOAPatterns & 0xfff000) >> 12;
dwMOAPatterns = (dwMOAPatterns & 0xfff) | dwHighOctave;
// count the total notes
rCount = 0;
rSixSeven = 0;
for (n = 0; n < 12; n++)
{
if (dwMOAPatterns & (1 << n))
{
rCount++;
if (n > 7) rSixSeven++;
}
}
return rCount <= 4;
}
DWORD CDirectMusicPattern::IMA25MoawFlags(MUSIC_TIME mtTime,
MUSIC_TIME mtNextChord,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord)
{
DWORD dwMoawFlags = 0;
DMSubChord rSubChord = rCurrentChord.SubChordList[0];
// set one of bits 0-7 based on chord root and scale root of current chord
DWORD dwPosition = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
if (dwPosition)
dwMoawFlags |= 1 << (dwPosition - 1); // bit 0 for scale position I, etc.
else
dwMoawFlags |= VF_ACCIDENTAL;
// set bits based on tonality of 1st subchord of current chord
if ((rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN)
dwMoawFlags |= VF_MAJOR;
else if ((rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
dwMoawFlags |= VF_MINOR;
else
dwMoawFlags |= VF_ALL;
// set bits if the root of the next chord is I or V
MUSIC_TIME mtPatternLength = 0;
mtPatternLength = m_timeSig.ClocksPerMeasure() * m_wNumMeasures;
if (rNextChord.bSubChordCount > 0)
{
DMSubChord SC = rNextChord.SubChordList[0];
int nNextRoot = ScalePosition(SC, rCurrentChord.bKey, rCurrentChord.dwScale);
int nThisRoot = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
if (mtPatternLength + mtTime < mtNextChord)
{
nNextRoot = nThisRoot;
}
switch (nNextRoot)
{
case 1: // Next chord is a I
dwMoawFlags |= VF_TO1;
break;
case 5: // Next chord is a 5
dwMoawFlags |= VF_TO5;
break;
}
}
// Set bits for simple and complex chords
if ( IsSimple(rCurrentChord) )
dwMoawFlags |= VF_SIMPLE;
else
dwMoawFlags |= VF_COMPLEX;
return dwMoawFlags;
}
void CDirectMusicPattern::DMusMoawFlags(MUSIC_TIME mtTime,
MUSIC_TIME mtNextChord,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord,
bool fIsDX8,
DWORD& dwNaturals,
DWORD& dwSharps,
DWORD& dwFlats)
{
dwNaturals = dwSharps = dwFlats = 0;
DMSubChord rSubChord = rCurrentChord.SubChordList[0];
// dwScalePosition holds the scale position of the chord.
DWORD dwScalePosition = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
// dwSharpPosition holds the sharped scale position of the chord.
DWORD dwSharpPosition = ScalePositionSharp(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
// dwFlatPosition holds the flatted scale position of the chord.
DWORD dwFlatPosition = ScalePositionFlat(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
// set bits for scale tone, sharp, and flat
if (dwScalePosition)
{
dwNaturals |= DMUS_VARIATIONF_ROOT_SCALE;
// shift bits based on tonality of 1st subchord of current chord
if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
{
dwNaturals |= 1 << (dwScalePosition - 1);
}
else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
{
dwNaturals |= 1 << (dwScalePosition + 6);
}
else
{
dwNaturals |= 1 << (dwScalePosition + 13);
}
dwSharps = dwFlats = dwNaturals;
dwSharpPosition = dwFlatPosition = dwScalePosition;
}
else
{
if (dwSharpPosition)
{
dwSharps |= DMUS_VARIATIONF_ROOT_SHARP;
// shift bits based on tonality of 1st subchord of current chord
if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
{
dwSharps |= 1 << (dwSharpPosition - 1);
}
else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
{
dwSharps |= 1 << (dwSharpPosition + 6);
}
else
{
dwSharps |= 1 << (dwSharpPosition + 13);
}
}
if (dwFlatPosition)
{
dwFlats |= DMUS_VARIATIONF_ROOT_FLAT;
// shift bits based on tonality of 1st subchord of current chord
if ( (rSubChord.m_dwChordPattern & MAJOR_PATTERN) == MAJOR_PATTERN )
{
dwFlats |= 1 << (dwFlatPosition - 1);
}
else if ( (rSubChord.m_dwChordPattern & MINOR_PATTERN) == MINOR_PATTERN)
{
dwFlats |= 1 << (dwFlatPosition + 6);
}
else
{
dwFlats |= 1 << (dwFlatPosition + 13);
}
}
}
// set bits if the root of the next chord is I or V (and it's different from the current chord)
MUSIC_TIME mtPatternLength = 0;
mtPatternLength = m_timeSig.ClocksPerMeasure() * m_wNumMeasures;
if (rNextChord.bSubChordCount > 0)
{
DMSubChord SC = rNextChord.SubChordList[0];
int nNextRoot = ScalePosition(SC, rCurrentChord.bKey, rCurrentChord.dwScale);
int nThisRoot = ScalePosition(rSubChord, rCurrentChord.bKey, rCurrentChord.dwScale);
if (mtPatternLength + mtTime < mtNextChord)
{
nNextRoot = nThisRoot;
}
/* This is easy enough to add if it's desired --- but not having it allows a bit more control
//Don't require anything but the ->Other flag to be set when staying on the same chord
if (fIsDX8 && nNextRoot == nThisRoot)
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_OTHER;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_OTHER;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_OTHER;
}
*/
switch (nNextRoot)
{
case 1: // Next chord is a I
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_TO1;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_TO1;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_TO1;
break;
case 5: // Next chord is a V
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_TO5;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_TO5;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_TO5;
break;
default: // Next chord is neither I nor V
if (fIsDX8)
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_DEST_OTHER;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_DEST_OTHER;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_DEST_OTHER;
}
break;
}
}
// Set bits for simple and complex chords
int nCount = 0;
int nSixSeven = 0;
if ( IsSimple(rCurrentChord, nCount, nSixSeven) )
{
if (nCount <= 3)
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_TRIAD;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_TRIAD;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_TRIAD;
}
else if (nCount == 4)
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_6AND7;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_6AND7;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_6AND7;
}
else
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_COMPLEX;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_COMPLEX;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_COMPLEX;
}
}
else
{
if (dwScalePosition) dwNaturals |= DMUS_VARIATIONF_TYPE_COMPLEX;
if (dwSharpPosition) dwSharps |= DMUS_VARIATIONF_TYPE_COMPLEX;
if (dwFlatPosition) dwFlats |= DMUS_VARIATIONF_TYPE_COMPLEX;
}
}
HRESULT CDirectMusicPattern::ComputeVariations(DWORD dwFlags,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord,
BYTE abVariationGroups[],
DWORD adwVariationMask[],
DWORD adwRemoveVariations[],
BYTE abVariation[],
MUSIC_TIME mtTime,
MUSIC_TIME mtNextChord,
PatternTrackState* pState)
{
HRESULT hr = S_OK;
// First, initialize the array of variation groups.
for (short i = 0; i < MAX_VARIATION_LOCKS; i++)
{
abVariationGroups[i] = 0xFF;
}
// Now, compute the variations for each part.
TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
for (i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
{
hr = ComputeVariation(
pPartRef->GetItemValue(),
i,
dwFlags,
rCurrentChord,
rNextChord,
abVariationGroups,
adwVariationMask,
adwRemoveVariations,
abVariation,
mtTime,
mtNextChord,
pState);
if (FAILED(hr))
{
break;
}
}
return hr;
}
HRESULT CDirectMusicPattern::ComputeVariationGroup(DirectMusicPartRef& rPartRef,
int nPartIndex,
DWORD dwFlags,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord,
BYTE abVariationGroups[],
DWORD adwVariationMask[],
DWORD adwRemoveVariations[],
BYTE abVariation[],
MUSIC_TIME mtTime,
MUSIC_TIME mtNextChord,
PatternTrackState* pState)
{
HRESULT hr = S_OK;
BYTE bLockID = rPartRef.m_bVariationLockID;
bool fChangedVariation = (dwFlags & COMPUTE_VARIATIONSF_CHANGED) ? true : false;
// If this part is locked, get a new variation for all parts locked to it;
// otherwise, just get a new variation for this part.
if (bLockID)
{
if (!fChangedVariation)
{
// First, initialize the variation group for this variation.
abVariationGroups[bLockID - 1] = 0xFF;
// Now, compute the variations for each part locked to this one.
TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
for (int i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
{
DirectMusicPartRef& rPartRefScan = pPartRef->GetItemValue();
if ( (bLockID == rPartRefScan.m_bVariationLockID) )
{
hr = ComputeVariation(
rPartRefScan,
i,
dwFlags,
rCurrentChord,
rNextChord,
abVariationGroups,
adwVariationMask,
adwRemoveVariations,
abVariation,
mtTime,
mtNextChord,
pState);
if (FAILED(hr))
{
break;
}
}
}
}
}
else
{
hr = ComputeVariation(
rPartRef,
nPartIndex,
dwFlags,
rCurrentChord,
rNextChord,
abVariationGroups,
adwVariationMask,
adwRemoveVariations,
abVariation,
mtTime,
mtNextChord,
pState);
}
return hr;
}
HRESULT CDirectMusicPattern::ComputeVariation(DirectMusicPartRef& rPartRef,
int nPartIndex,
DWORD dwFlags,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord,
BYTE abVariationGroups[],
DWORD adwVariationMask[],
DWORD adwRemoveVariations[],
BYTE abVariation[],
MUSIC_TIME mtTime,
MUSIC_TIME mtNextChord,
PatternTrackState* pState)
{
int i = nPartIndex;
bool fUseMask = (dwFlags & COMPUTE_VARIATIONSF_USE_MASK) ? true : false;
bool fNewPattern = (dwFlags & COMPUTE_VARIATIONSF_NEW_PATTERN) ? true : false;
bool fChordAlign = (dwFlags & COMPUTE_VARIATIONSF_CHORD_ALIGN) ? true : false;
bool fMarker = (dwFlags & COMPUTE_VARIATIONSF_MARKER) ? true : false;
bool fStart = (dwFlags & COMPUTE_VARIATIONSF_START) ? true : false;
bool fIsDX8 = (dwFlags & COMPUTE_VARIATIONSF_DX8) ? true : false;
bool fChord = false;
if (pState && (mtTime == pState->m_mtCurrentChordTime || mtTime == pState->m_mtNextChordTime))
{
fChord = true;
}
DWORD dwMarkerFlags = DMUS_MARKERF_START;
DWORD dwDMusNaturals, dwDMusSharps, dwDMusFlats;
DMusMoawFlags(mtTime, mtNextChord, rCurrentChord, rNextChord, fIsDX8, dwDMusNaturals, dwDMusSharps, dwDMusFlats);
DWORD dwIMA25MoawFlags = IMA25MoawFlags(mtTime, mtNextChord, rCurrentChord, rNextChord);
TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
DWORD dwNaturalFlags, dwSharpFlags, dwFlatFlags;
/*// First, initialize the array of variation groups
for (short i = 0; i < MAX_VARIATION_LOCKS; i++)
{
abVariationGroups[i] = 0xFF;
}*/
//for (i = 0; pPartRef != NULL; pPartRef = pPartRef->GetNext(), i++)
{
// if (pguidPart &&
// pPartRef->GetItemValue().m_pDMPart &&
// *pguidPart != pPartRef->GetItemValue().m_pDMPart->m_guidPartID)
// {
// continue; // the way this was, it wiped out variation locking
// }
DWORD dwVariationChoices = 0xffffffff;
if (fUseMask)
{
dwVariationChoices = adwVariationMask[i];
}
// DirectMusicPartRef& rPartRef = pPartRef->GetItemValue();
BYTE bLockID = rPartRef.m_bVariationLockID;
DirectMusicPart* pPart = rPartRef.m_pDMPart;
MUSIC_TIME mtPartOffset = (pState) ? pState->PartOffset(i) : 0;
MUSIC_TIME mtNowRelative = (mtTime >= mtPartOffset) ? mtTime - mtPartOffset : 0;
MUSIC_TIME mtClosestTime = 0;
// Find a variation whose moaw field matches dwMoawFlags.
// Variation locking: If a part ref has a variation lock id that has already been
// recorded, use the recorded variation. Otherwise, find a variation and, if the
// part ref has a variation lock id, record the variation.
if (bLockID && abVariationGroups[bLockID - 1] != 0xFF)
{
abVariation[i] = abVariationGroups[bLockID - 1];
adwVariationMask[i] = abVariationGroups[bLockID - 1];
}
else
{
// First, collect all matches.
// Also, find the time of the matching variation closest to but not preceding mtTime.
BYTE bMode = 0;
DWORD dwMatches = 0;
DWORD dwCompleteMatches = 0;
short nMatchCount = 0;
DWORD dwEnabled = 0;
short nEnabledCount = 0;
bool fGotClosest = false;
for (short nV = 0; nV < 32; nV++)
{
DWORD dwVariation = 1 << nV;
if (dwVariation & dwVariationChoices)
{
if ( (pPart->m_dwVariationChoices[nV] & 0x5FFFFFFF) != 0) // enabled
{
nEnabledCount++;
dwEnabled |= dwVariation;
}
if (pPart->m_dwVariationChoices[nV] & DMUS_VARIATIONF_DMUS_MODE)
{
dwNaturalFlags = dwDMusNaturals;
dwSharpFlags = dwDMusSharps;
dwFlatFlags = dwDMusFlats;
}
else
{
dwNaturalFlags = dwSharpFlags = dwFlatFlags = dwIMA25MoawFlags;
}
if ( (dwNaturalFlags && (pPart->m_dwVariationChoices[nV] & dwNaturalFlags) == dwNaturalFlags) ||
(dwSharpFlags && (pPart->m_dwVariationChoices[nV] & dwSharpFlags) == dwSharpFlags) ||
(dwFlatFlags && (pPart->m_dwVariationChoices[nV] & dwFlatFlags) == dwFlatFlags) )
{
nMatchCount++;
dwMatches |= dwVariation;
if ((fStart || fMarker) && pPart && (pPart->m_dwFlags & DMUS_PARTF_USE_MARKERS))
{
MUSIC_TIME mtTemp = 0;
if (SUCCEEDED(pPart->GetClosestTime(nV, mtNowRelative, dwMarkerFlags, fChord, mtTemp)))
{
if (!fGotClosest || mtTemp < mtClosestTime)
{
mtClosestTime = mtTemp;
fGotClosest = true;
}
}
}
}
}
}
dwCompleteMatches = dwMatches;
DWORD dwTemp = dwMatches;
bMode = rPartRef.m_bRandomVariation;
if ( bMode == DMUS_VARIATIONT_RANDOM_ROW )
{
dwTemp &= ~adwRemoveVariations[i];
if (!dwTemp)
{
// start counting all over, but don't repeat this one
adwRemoveVariations[i] = 0;
dwTemp = dwMatches;
bMode = DMUS_VARIATIONT_NO_REPEAT;
}
}
if ( bMode == DMUS_VARIATIONT_NO_REPEAT && abVariation[i] != 0xff )
{
dwTemp &= ~(1 << abVariation[i]);
}
if (dwTemp != dwMatches)
{
if (dwTemp) // otherwise, keep what we had
{
for (int j = 0; j < 32; j++)
{
if ( ((1 << j) & dwMatches) && !((1 << j) & dwTemp) )
{
nMatchCount--;
}
}
dwMatches = dwTemp;
}
}
if (nMatchCount == 0)
{
if (nEnabledCount)
{
// if there are any enabled variations, choose from among them
nMatchCount = nEnabledCount;
dwMatches = dwEnabled;
}
else
{
// otherwise, choose any variation from among the first 16
// (for compatability with SuperJam)
nMatchCount = 16;
dwMatches = 0xffffffff;
}
}
adwVariationMask[i] = dwMatches;
// If we're starting at or past a marker, or we're at a marker,
// and the part is using markers, filter out all
// variations except those with start markers closest to but not preceding mtNow.
if ( ((fStart && mtTime >= mtClosestTime) || fMarker) &&
pPart && (pPart->m_dwFlags & DMUS_PARTF_USE_MARKERS) )
{
DWORD dwMatchTemp = dwMatches;
short nCountTemp = nMatchCount;
for (nV = 0; nV < 32; nV++)
{
if (dwMatches & (1 << nV))
{
if ( !pPart->IsMarkerAtTime(nV, mtClosestTime, dwMarkerFlags, fChord) )
{
dwMatches &= ~(1 << nV);
nMatchCount--;
}
}
}
// Fall back to the original matches
if (!dwMatches)
{
dwMatches = dwMatchTemp;
nMatchCount = nCountTemp;
}
}
// Next, select a match.
// Only select a match if either we're just starting a new pattern,
// we're at a chord-aligned marker,
// or the current variation isn't a match.
// If this part aligns variations to chords, only get a new variation
// if we're just starting a new pattern,
// or we're at a chord-aligned marker AND the current variation isn't a match.
TraceI(3, "Matches: %x\n", dwMatches);
bool fAlignPartToChord = (pPart->m_dwFlags & DMUS_PARTF_ALIGN_CHORDS) ? true : false;
bool fMatch = ((1 << abVariation[i]) & dwCompleteMatches) ? true : false;
bool fFirstRandomInOrder = false;
if ( fNewPattern ||
(!fAlignPartToChord && (fChordAlign || !fMatch)) ||
(fAlignPartToChord && fChordAlign && !fMatch) )
{
//TraceI(0, "Time: %d, New Pattern: %d Chord Align: %d Variation: %d Matches: %x\n",
// mtTime, fNewPattern, fChordAlign, abVariation[i], dwCompleteMatches);
switch (rPartRef.m_bRandomVariation)
{
case DMUS_VARIATIONT_RANDOM_ROW:
case DMUS_VARIATIONT_NO_REPEAT:
case DMUS_VARIATIONT_RANDOM:
{
short nChoice = 0;
if (pState)
{
nChoice = (short)pState->RandomVariation(mtTime, nMatchCount);
}
else
{
nChoice = (short) (rand() % nMatchCount);
}
short nCount = 0;
for (nV = 0; nV < 32; nV++)
{
if ((1 << nV) & dwMatches)
{
if (nChoice == nCount)
break;
nCount++;
}
}
abVariation[i] = (BYTE) nV;
if (rPartRef.m_bRandomVariation == DMUS_VARIATIONT_RANDOM_ROW)
{
adwRemoveVariations[i] |= (1 << abVariation[i]);
}
TraceI(3, "New variation: %d at time %d\n", nV, mtTime);
break;
}
case DMUS_VARIATIONT_RANDOM_START:
// Choose an initial value
if (abVariation[i] == 0xff)
{
fFirstRandomInOrder = true;
int nStart = 0;
if (pState)
{
nStart = (BYTE)pState->RandomVariation(mtTime, nMatchCount);
}
else
{
nStart = (BYTE) (rand() % nMatchCount);
}
int nCount = 0;
for (nV = 0; nV < 32; nV++)
{
if ((1 << nV) & dwMatches)
{
if (nStart == nCount)
break;
nCount++;
}
}
abVariation[i] = (BYTE) nV;
}
// Now, go directly to the sequential case (no break)
case DMUS_VARIATIONT_SEQUENTIAL:
{
if (!fFirstRandomInOrder)
{
do
{
abVariation[i]++;
}
while (!((1 << ((nV + abVariation[i]) % 32)) & dwMatches));
abVariation[i] %= 32;
}
TraceI(3, "New variation: %d at time %d\n", abVariation[i], mtTime);
break;
}
}
// If this is a locked variation, it's the first in its group, so record it.
if (bLockID)
{
abVariationGroups[bLockID - 1] = abVariation[i];
}
}
}
}
return S_OK;
}
// Returns:
// Total number of bits in the pattern if all bits in the rhythm match the pattern.
// 0 otherwise.
void CDirectMusicPattern::MatchRhythm(DWORD pRhythms[], short nPatternLength,
short& nBits)
{
nBits = 0;
for (int i = 0; i < nPatternLength; i++)
{
if (i >= m_wNumMeasures)
{
return;
}
if ((pRhythms[i] & m_pRhythmMap[i]) == pRhythms[i])
{
for (int n = 0; n < 32; n++)
{
nBits += (short) (m_pRhythmMap[i] >> n) & 1;
}
}
else
{
nBits = 0;
return;
}
}
}
BOOL CDirectMusicPattern::MatchCommand(DMUS_COMMAND_PARAM_2 pCommands[], short nLength)
{
short nPatternLength = (m_wNumMeasures < nLength) ? m_wNumMeasures : nLength;
if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
for (int i = 0; i < nPatternLength; i++)
{
if ( (i > 0) &&
(pCommands[i].bCommand == DMUS_COMMANDT_GROOVE) &&
(pCommands[i].bGrooveLevel == pCommands[0].bGrooveLevel) )
{
continue;
}
if (!MatchEmbellishment(pCommands[i])) return FALSE;
if (!MatchGrooveLevel(pCommands[i])) return FALSE;
}
return TRUE;
}
BOOL CDirectMusicPattern::MatchGrooveLevel(DMUS_COMMAND_PARAM_2& rCommand)
{
if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
// Lower the upper range and raise the lower range by half of the total range each
BYTE bMiddle = rCommand.bGrooveRange / 2;
BYTE bUpper = (rCommand.bGrooveLevel < bMiddle) ? 1 : rCommand.bGrooveLevel - bMiddle;
BYTE bLower = (rCommand.bGrooveLevel + bMiddle > 100) ? 100 : rCommand.bGrooveLevel + bMiddle;
TraceI(3, "Range: %d Upper: %d Lower: %d\n", bMiddle, bUpper, bLower);
return (bLower >= m_bGrooveBottom && bUpper <= m_bGrooveTop);
}
BOOL CDirectMusicPattern::MatchEmbellishment(DMUS_COMMAND_PARAM_2& rCommand)
{
if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
if ((m_wEmbellishment & EMB_USER_DEFINED)) // handle user-defined embellishments
{
if ((BYTE)(m_wEmbellishment >> 8) != rCommand.bCommand) return FALSE;
}
else
{
switch (rCommand.bCommand)
{
case DMUS_COMMANDT_GROOVE:
if ((m_wEmbellishment & EMB_NORMAL) != m_wEmbellishment) return FALSE;
break;
case DMUS_COMMANDT_FILL:
if (!(m_wEmbellishment & EMB_FILL)) return FALSE;
break;
case DMUS_COMMANDT_INTRO:
if (!(m_wEmbellishment & EMB_INTRO)) return FALSE;
break;
case DMUS_COMMANDT_BREAK:
if (!(m_wEmbellishment & EMB_BREAK)) return FALSE;
break;
case DMUS_COMMANDT_END:
if (!(m_wEmbellishment & EMB_END)) return FALSE;
break;
default: return FALSE;
}
}
return TRUE;
}
BOOL CDirectMusicPattern::MatchNextCommand(DMUS_COMMAND_PARAM_2& rNextCommand)
{
TraceI(3, "Next Command: %x (%d) Embellishment: %x [%d %d] <%d %d>\n", rNextCommand.bCommand, rNextCommand.bGrooveLevel,
m_wEmbellishment, m_bGrooveBottom, m_bGrooveTop, m_bDestGrooveBottom, m_bDestGrooveTop);
if ((m_wEmbellishment & EMB_MOTIF) == EMB_MOTIF) return FALSE; // discard all motifs
if (!m_bDestGrooveBottom || !m_bDestGrooveTop) // handle legacy
{
return TRUE;
}
// Lower the upper range and raise the lower range by half of the total range each
BYTE bMiddle = rNextCommand.bGrooveRange / 2;
BYTE bUpper = (rNextCommand.bGrooveLevel < bMiddle) ? 1 : rNextCommand.bGrooveLevel - bMiddle;
BYTE bLower = (rNextCommand.bGrooveLevel + bMiddle > 100) ? 100 : rNextCommand.bGrooveLevel + bMiddle;
TraceI(3, "Range: %d Upper: %d Lower: %d\n", bMiddle, bUpper, bLower);
return (bLower >= m_bDestGrooveBottom && bUpper <= m_bDestGrooveTop);
}
HRESULT CDirectMusicPattern::MergeMarkerEvents( DMStyleStruct* pStyle )
{
TListItem<DirectMusicPartRef>* pPartRef = m_PartRefList.GetHead();
for (; pPartRef; pPartRef = pPartRef->GetNext())
{
pPartRef->GetItemValue().m_pDMPart->MergeMarkerEvents(pStyle, this);
}
return S_OK;
}
bool Greater(MUSIC_TIME& mt1, MUSIC_TIME& mt2)
{
return mt1 > mt2;
}
bool Greater(Marker& m1, Marker& m2)
{
return m1.mtTime > m2.mtTime;
}
template <class T>
HRESULT InsertInOrder(TList<T>& List, T tValue)
{
TListItem<T>* pNew = new TListItem<T>(tValue);
if (!pNew) return E_OUTOFMEMORY;
TListItem<T>* pScan = List.GetHead();
TListItem<T>* pPrevious = NULL;
for (; pScan; pScan = pScan->GetNext())
{
if (Greater(pScan->GetItemValue(), tValue))
{
break;
}
pPrevious = pScan;
}
if (!pPrevious)
{
List.AddHead(pNew);
}
else
{
pPrevious->SetNext(pNew);
pNew->SetNext(pScan);
}
return S_OK;
}
HRESULT DirectMusicPart::MergeMarkerEvents( DMStyleStruct* pStyle, CDirectMusicPattern* pPattern )
{
DirectMusicTimeSig& TimeSig = TimeSignature(pStyle, pPattern);
CDirectMusicEventItem* pEvent;
for (pEvent = EventList.GetHead(); pEvent; pEvent = pEvent->GetNext())
{
if (pEvent->m_dwEventTag == DMUS_EVENT_MARKER)
{
CDMStyleMarker* pMarker = (CDMStyleMarker*)pEvent;
if (pMarker->m_wFlags & DMUS_MARKERF_START)
{
MUSIC_TIME mtTime =
(MUSIC_TIME)(TimeSig.GridToClocks(pMarker->m_nGridStart) + pMarker->m_nTimeOffset);
// Put this in all the appropriate variation lists
for (int i = 0; i < 32; i++)
{
if (pMarker->m_dwVariation & (1 << i))
{
Marker M;
M.mtTime = mtTime;
M.wFlags = pMarker->m_wFlags;
InsertInOrder(m_StartTimes[i], M);
}
}
InsertInOrder(pPattern->m_StartTimeList, mtTime);
}
}
}
return S_OK;
}
HRESULT DirectMusicPart::GetClosestTime(int nVariation, MUSIC_TIME mtTime, DWORD dwFlags, bool fChord, MUSIC_TIME& rmtResult)
{
HRESULT hr = E_FAIL;
rmtResult = 0;
if (nVariation < 32 && nVariation >= 0)
{
TListItem<Marker>* pMarker = m_StartTimes[nVariation].GetHead();
for (; pMarker; pMarker = pMarker->GetNext())
{
if ( pMarker->GetItemValue().mtTime >= mtTime &&
(pMarker->GetItemValue().wFlags & dwFlags) == dwFlags &&
(fChord || !(pMarker->GetItemValue().wFlags & DMUS_MARKERF_CHORD_ALIGN)) )
{
rmtResult = pMarker->GetItemValue().mtTime;
hr = S_OK;
break;
}
}
}
return hr;
}
bool DirectMusicPart::IsMarkerAtTime(int nVariation, MUSIC_TIME mtTime, DWORD dwFlags, bool fChord)
{
bool fResult = false;
if (nVariation < 32 && nVariation >= 0)
{
TListItem<Marker>* pMarker = m_StartTimes[nVariation].GetHead();
for (; pMarker; pMarker = pMarker->GetNext())
{
if ( pMarker->GetItemValue().mtTime == mtTime &&
(pMarker->GetItemValue().wFlags & dwFlags) == dwFlags &&
(fChord || !(pMarker->GetItemValue().wFlags & DMUS_MARKERF_CHORD_ALIGN)) )
{
fResult = true;
break;
}
}
}
return fResult;
}
DirectMusicTimeSig& CDirectMusicPattern::TimeSignature( DMStyleStruct* pStyle )
{
if (m_timeSig.m_bBeat != 0)
{
return m_timeSig;
}
else if (pStyle)
{
return pStyle->TimeSignature();
}
else
{
return ::DefaultTimeSig;
}
}
DirectMusicTimeSig& DirectMusicPart::TimeSignature( DMStyleStruct* pStyle, CDirectMusicPattern* pPattern )
{
if (m_timeSig.m_bBeat != 0)
{
return m_timeSig;
}
else if (pPattern)
{
return pPattern->TimeSignature(pStyle);
}
else
{
return ::DefaultTimeSig;
}
}