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

1132 lines
35 KiB
C++

//+-------------------------------------------------------------------------
//
// Copyright (c) 1998-2001 Microsoft Corporation
//
// File: dmtempl.cpp
//
//--------------------------------------------------------------------------
// DMTempl.cpp : Implementation of CDMTempl
#include "DMTempl.h"
#include <comdef.h>
#include "dmusici.h"
#include "dmusicf.h"
#include "..\dmstyle\iostru.h"
#include "debug.h"
#include "..\shared\Validate.h"
void TemplateStruct::AddIntro(TList<PlayChord>& PlayList, int nIntroLength)
{
TListItem<TemplateCommand> *pCommand = new TListItem<TemplateCommand>;
if (pCommand)
{
BOOL fMerge = FALSE;
TemplateCommand& rCommand = pCommand->GetItemValue();
rCommand.m_nMeasure = 0;
rCommand.m_dwChord = 0;
rCommand.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rCommand.m_Command.bGrooveLevel = 0;
rCommand.m_Command.bGrooveRange = 0;
rCommand.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
TListItem<PlayChord> *pChord = PlayList.GetHead();
for (; pChord; pChord = pChord->GetNext())
{
pChord->GetItemValue().m_nMeasure += (short)nIntroLength;
}
TListItem<TemplateCommand> *pScan = m_CommandList.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
TemplateCommand& rScan = pScan->GetItemValue();
if (rScan.m_nMeasure >= nIntroLength || !rScan.m_dwChord)
rScan.m_nMeasure += (short)nIntroLength;
else if (rScan.m_Command.bGrooveLevel != 0 || rScan.m_Command.bCommand == DMUS_COMMANDT_END)
{
rCommand.m_dwChord = rScan.m_dwChord;
rScan.m_dwChord = 0;
rScan.m_nMeasure += (short)nIntroLength;
}
else // merge with existing command
{
rScan.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rScan.m_Command.bGrooveLevel = 0;
rScan.m_Command.bGrooveRange = 0;
rScan.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
fMerge = TRUE;
}
}
m_nMeasures += (short)nIntroLength;
if (fMerge)
delete pCommand;
else
m_CommandList.AddHead(pCommand);
}
}
void TemplateStruct::AddIntro(bool f1Bar, int nLength)
{
TListItem<TemplateCommand> *pCommand = new TListItem<TemplateCommand>;
if (pCommand)
{
BOOL fMerge = FALSE;
TemplateCommand& rCommand = pCommand->GetItemValue();
rCommand.m_nMeasure = 0;
rCommand.m_dwChord = 0;
rCommand.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rCommand.m_Command.bGrooveLevel = 0;
rCommand.m_Command.bGrooveRange = 0;
rCommand.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
TListItem<TemplateCommand> *pScan = m_CommandList.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
TemplateCommand& rScan = pScan->GetItemValue();
if (rScan.m_nMeasure > 0 || !rScan.m_dwChord)
rScan.m_nMeasure += (short)nLength;
else if ( !f1Bar &&
(rScan.m_Command.bGrooveLevel != 0 ||
rScan.m_Command.bCommand != DMUS_COMMANDT_GROOVE) )
{
rCommand.m_dwChord = rScan.m_dwChord;
rScan.m_dwChord = 0;
rScan.m_nMeasure += (short)nLength;
}
else // merge with existing command
{
rScan.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rScan.m_Command.bGrooveLevel = 0;
rScan.m_Command.bGrooveRange = 0;
rScan.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
fMerge = TRUE;
}
}
if (!f1Bar) m_nMeasures += (short)nLength;
if (fMerge)
delete pCommand;
else
m_CommandList.AddHead(pCommand);
}
}
void TemplateStruct::AddEnd(int nLength)
{
TListItem<TemplateCommand> *pCommand;
TListItem<TemplateCommand> *pScan = m_CommandList.GetHead();
for (; pScan; pScan = pScan->GetNext())
{
if (m_nMeasures - nLength == pScan->GetItemValue().m_nMeasure) break;
}
pCommand = (pScan) ? pScan : new TListItem<TemplateCommand>;
if (pCommand)
{
TemplateCommand& rCommand = pCommand->GetItemValue();
rCommand.m_nMeasure = m_nMeasures - nLength;
if (!pScan || pScan->GetItemValue().m_nMeasure > 1) // otherwise keep the existing signpost
{
rCommand.m_dwChord = 0;
}
rCommand.m_Command.bCommand = DMUS_COMMANDT_END;
rCommand.m_Command.bGrooveLevel = 0;
rCommand.m_Command.bGrooveRange = 0;
rCommand.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
if (!pScan) m_CommandList.AddTail(pCommand);
}
}
void TemplateStruct::FillInGrooveLevels()
{
BYTE bLastGrooveLevel = 62;
TListItem<TemplateCommand>* pCommands = m_CommandList.GetHead();
for(; pCommands; pCommands = pCommands->GetNext())
{
TemplateCommand& rCommand = pCommands->GetItemValue();
if (rCommand.m_Command.bGrooveLevel == 0)
{
rCommand.m_Command.bGrooveLevel = bLastGrooveLevel;
}
else
{
bLastGrooveLevel = rCommand.m_Command.bGrooveLevel;
}
}
}
void TemplateStruct::IncorporateTemplate(
short nMeasure, TemplateStruct* pTemplate, short nDirection)
{
if (!pTemplate) return;
TListItem<TemplateCommand>* pCommands = pTemplate->m_CommandList.GetHead();
for(; pCommands; pCommands = pCommands->GetNext())
{
TemplateCommand& rCommand = pCommands->GetItemValue();
TListItem<TemplateCommand> *pNew = new TListItem<TemplateCommand>;
if (pNew)
{
TemplateCommand& rNew = pNew->GetItemValue();
rNew.m_nMeasure = rCommand.m_nMeasure + (short)nMeasure;
ChangeCommand(rNew.m_Command, rCommand.m_Command, nDirection);
rNew.m_dwChord = rCommand.m_dwChord;
m_CommandList.AddHead(pNew);
}
}
}
void TemplateStruct::InsertCommand(TListItem<TemplateCommand> *pCommand, BOOL fIsCommand)
{
TListItem<TemplateCommand> *pScan;
if( !pCommand )
{
return;
}
pCommand->SetNext(NULL);
TemplateCommand& rCommand = pCommand->GetItemValue();
pScan = m_CommandList.GetHead();
if (pScan)
{
for (; pScan; pScan = pScan->GetNext())
{
TemplateCommand& rScan = pScan->GetItemValue();
if (rScan.m_nMeasure == rCommand.m_nMeasure)
{
if (fIsCommand)
{
rScan.m_dwChord = 0;
rScan.m_Command.bCommand = rCommand.m_Command.bCommand;
rScan.m_Command.bGrooveLevel = rCommand.m_Command.bGrooveLevel;
rScan.m_Command.bGrooveRange = rCommand.m_Command.bGrooveRange;
rScan.m_Command.bRepeatMode = rCommand.m_Command.bRepeatMode;
}
else
{
rScan.m_dwChord = rCommand.m_dwChord;
rScan.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rScan.m_Command.bGrooveLevel = 0;
rScan.m_Command.bGrooveRange = 0;
rScan.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
}
delete pCommand;
return;
}
if (rScan.m_nMeasure > rCommand.m_nMeasure)
{
m_CommandList.InsertBefore(pScan, pCommand);
break;
}
}
}
if (!pScan)
{
m_CommandList.AddTail(pCommand);
}
}
void TemplateStruct::AddCommand(int nMeasure, DWORD dwCommand)
{
TListItem<TemplateCommand>* pCommand = new TListItem<TemplateCommand>;
if (pCommand)
{
TemplateCommand& rCommand = pCommand->GetItemValue();
rCommand.m_nMeasure = (short)nMeasure;
rCommand.m_Command.bGrooveRange = 0;
rCommand.m_Command.bRepeatMode = DMUS_PATTERNT_RANDOM;
switch (dwCommand)
{
case PF_FILL:
rCommand.m_Command.bCommand = DMUS_COMMANDT_FILL;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_INTRO:
rCommand.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_BREAK:
rCommand.m_Command.bCommand = DMUS_COMMANDT_BREAK;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_END:
rCommand.m_Command.bCommand = DMUS_COMMANDT_END;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_A:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 12;
break;
case PF_B:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 37;
break;
case PF_C:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 62;
break;
case PF_D:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 87;
break;
default: // default to a Groove C
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 62;
}
InsertCommand( pCommand, TRUE );
}
}
void TemplateStruct::AddChord(int nMeasure, DWORD dwChord)
{
TListItem<TemplateCommand>* pCommand = new TListItem<TemplateCommand>;
if (pCommand)
{
pCommand->GetItemValue().m_nMeasure = (short)nMeasure;
pCommand->GetItemValue().m_dwChord = dwChord;
InsertCommand( pCommand, FALSE );
}
}
int WeightedRand(int nRange)
/* This randomly chooses a number within nrange. However, it heavily
weights in favor of the first index, which has twice the chance
of the second index, which has twice the chance of the third...
*/
{
int nTotal = 0;
int index;
unsigned int nGuess;
if (nRange <= 0 || nRange > 15) return(0); // out of range.
for (index = 0;index < nRange; index++)
{
nTotal += (1 << index);
}
nGuess = rand() % nTotal;
nGuess++;
for (;nGuess;index--)
{
nGuess = nGuess >> 1;
}
return(index);
}
void TemplateStruct::CreateSignPosts()
{
// First, figure out how many different sign posts we should use.
// Should be the number of bits in measures minus two. Min is one.
// For example, 8 measures gets us 2 sign posts.
int nSPCount = -2;
int nCopy = m_nMeasures;
m_CommandList.RemoveAll();
while (nCopy)
{
nSPCount++;
nCopy = nCopy >> 1;
}
if (nSPCount < 1) nSPCount = 1;
if (nSPCount > 7) nSPCount = 7;
// Now, choose some signposts. We choose from the following set:
// 1, A, C, E, B, D, F. Randomly, but heavily weighted towards the start
// of the set.
static DWORD adwSource[7] = { DMUS_SIGNPOSTF_1, DMUS_SIGNPOSTF_A, DMUS_SIGNPOSTF_C, DMUS_SIGNPOSTF_E, DMUS_SIGNPOSTF_B, DMUS_SIGNPOSTF_D, DMUS_SIGNPOSTF_F };
DWORD adwChoice[7];
DWORD adwSign[7];
int anLength[7];
DWORD dwLastChord;
int index;
for (index = 0;index < 7;index++)
{
adwChoice[index] = adwSource[index];
adwSign[index] = 0;
if (rand() % 3) anLength[index] = 4;
else anLength[index] = 2;
}
if (rand() % 2) anLength[0] = 4;
for (index = 0;index < nSPCount;index++)
{
int nPosition;
int nScan = 0;
if (index) nPosition = WeightedRand(7 - index);
else nPosition = WeightedRand(3);
for (;nScan < 7;nScan++)
{
if (adwChoice[nScan])
{
if (!nPosition)
{
adwSign[index] = adwChoice[nScan];
if (rand() % 2) adwSign[index] |= DMUS_SIGNPOSTF_CADENCE;
adwChoice[nScan] = 0;
break;
}
nPosition--;
}
}
}
AddChord(0,dwLastChord = adwSign[0]);
int nLast = 0;
for (index = 0;index < m_nMeasures;)
{
DWORD dwCadence = 0;
DWORD dwChord;
index += anLength[nLast];
if (index >= (m_nMeasures - 1))
{
if (rand() % 3) AddChord(m_nMeasures - 1,DMUS_SIGNPOSTF_1 | dwCadence);
else AddChord(m_nMeasures - 1,adwSign[0] | dwCadence);
break;
}
dwChord = adwSign[nLast = WeightedRand(nSPCount)];
if (dwChord == dwLastChord)
{
dwChord = adwSign[nLast = WeightedRand(nSPCount)];
}
AddChord(index,dwChord | dwCadence);
dwLastChord = dwChord;
}
}
static void GrooveRange(TemplateStruct *pTemplate,int nStartm,int nEndm,
int nStartg,int nEndg,BOOL fRandom)
{
static BYTE abGrooveLevels[4] = { 12, 37, 62, 87 };
TListItem<TemplateCommand> *pCommand = pTemplate->m_CommandList.GetHead();
TListItem<TemplateCommand> *pLast = NULL;
int nRangem = nEndm - nStartm;
int nRangeg = nEndg - nStartg;
BYTE bLastGrooveLevel = 0;
int nLastGroove = -1;
int nLastMeasure = 0;
for (; pCommand; pCommand = pCommand->GetNext())
{
TemplateCommand& rCommand = pCommand->GetItemValue();
if (rCommand.m_Command.bCommand == DMUS_COMMANDT_GROOVE &&
rCommand.m_Command.bGrooveLevel > 0)
{
bLastGrooveLevel = rCommand.m_Command.bGrooveLevel;
nLastMeasure = rCommand.m_nMeasure;
}
if (rCommand.m_nMeasure >= nStartm)
{
if (rCommand.m_nMeasure >= nEndm) break;
int nGroove;
TListItem<TemplateCommand> *pNext = pCommand->GetNext();
if (pNext)
{
nGroove =
((pNext->GetItemValue().m_nMeasure + rCommand.m_nMeasure ) >> 1) - nStartm;
}
else
{
nGroove = rCommand.m_nMeasure - nStartm;
}
if (fRandom)
{
nGroove = rand() % 3;
nGroove += nLastGroove - 1;
if (nGroove > 3) nGroove = 2;
if (nGroove < 0) nGroove = 1;
}
else
{
nGroove *= nRangeg;
nGroove += (nRangem >> 1);
nGroove /= nRangem;
nGroove += nStartg;
}
if ((nGroove >= 0) && (nGroove < 4))
{
if (abGrooveLevels[nGroove] != bLastGrooveLevel)
{
if (nLastGroove >= 0)
{
if (nLastGroove > nGroove) nGroove = nLastGroove - 1;
else if (nLastGroove < nGroove) nGroove = nLastGroove + 1;
}
rCommand.m_Command.bGrooveLevel = abGrooveLevels[nGroove];
rCommand.m_Command.bGrooveRange = 0;
bLastGrooveLevel = abGrooveLevels[nGroove];
nLastMeasure = rCommand.m_nMeasure;
nLastGroove = nGroove;
}
else if (rCommand.m_nMeasure > (nLastMeasure + 6))
{
nGroove += ((rand() % 3) - 1);
if (nGroove < 0) nGroove += 2;
if (nGroove > 3) nGroove -= 2;
if (!nRangeg)
{
if ((nGroove < nLastGroove) && (nGroove <= nStartg))
{
if (rand() % 2) nGroove++;
}
}
if (abGrooveLevels[nGroove] != bLastGrooveLevel)
{
rCommand.m_Command.bGrooveLevel = abGrooveLevels[nGroove];
rCommand.m_Command.bGrooveRange = 0;
bLastGrooveLevel = abGrooveLevels[nGroove];
nLastMeasure = rCommand.m_nMeasure;
nLastGroove = nGroove;
}
}
}
}
}
}
void TemplateStruct::CreateEmbellishments(WORD shape, int nFillLength, int nBreakLength)
{
// Put fills in. Scan forward through the list, placing fills
// just prior to sign post changes. Each time, move forward a
// random count.
TListItem<TemplateCommand> *pCommand;
BYTE bLastGroove = 0;
BOOL fAddMore = FALSE;
int nStartg, nEndg;
switch (shape)
{
case DMUS_SHAPET_FALLING:
nStartg = 3;
nEndg = 0;
break;
case DMUS_SHAPET_LEVEL:
nStartg = 2;
nEndg = 2;
fAddMore = TRUE;
break;
case DMUS_SHAPET_LOOPABLE:
nStartg = 2;
nEndg = 2;
fAddMore = TRUE;
break;
case DMUS_SHAPET_LOUD:
nStartg = 3;
nEndg = 3;
fAddMore = TRUE;
break;
case DMUS_SHAPET_QUIET:
nStartg = 0;
nEndg = 1;
fAddMore = TRUE;
break;
case DMUS_SHAPET_PEAKING:
nStartg = 0;
nEndg = 3;
GrooveRange(this, 0, m_nMeasures >> 1, nStartg, nEndg, FALSE);
nStartg = 3;
nEndg = 0;
GrooveRange(this, m_nMeasures >> 1, m_nMeasures - 1, nStartg, nEndg, FALSE);
nStartg = 0;
nEndg = 0;
break;
case DMUS_SHAPET_RANDOM:
nStartg = 0;
nEndg = 0;
GrooveRange(this, 0, m_nMeasures - 1, nStartg, nEndg, TRUE);
break;
case DMUS_SHAPET_RISING:
nStartg = 0;
nEndg = 3;
break;
case DMUS_SHAPET_SONG:
default:
nStartg = 2;
nEndg = 2;
fAddMore = TRUE;
break;
}
if (nStartg || nEndg) GrooveRange(this, 0, m_nMeasures - 1, nStartg, nEndg, FALSE);
pCommand = m_CommandList.GetHead();
int nLastGrooveBar = 0;
for (; pCommand; pCommand = pCommand->GetNext())
{
TemplateCommand& rCommand = pCommand->GetItemValue();
if (rCommand.m_Command.bCommand == DMUS_COMMANDT_GROOVE)
{
BYTE bGrooveLevel = rCommand.m_Command.bGrooveLevel;
if (bGrooveLevel && (bGrooveLevel != bLastGroove))
{
if (rand() % 2)
{
if ( (rCommand.m_nMeasure >= nFillLength) &&
(rCommand.m_nMeasure - nFillLength > nLastGrooveBar) &&
(bGrooveLevel > 50 || bLastGroove > 75) )
{
AddCommand(rCommand.m_nMeasure - nFillLength, PF_FILL);
}
else
{
if ((rCommand.m_nMeasure >= nBreakLength) &&
(rCommand.m_nMeasure - nBreakLength > nLastGrooveBar) &&
(rand() % 3) )
{
AddCommand(rCommand.m_nMeasure - nBreakLength, PF_BREAK);
}
}
}
}
bLastGroove = bGrooveLevel;
if (rCommand.m_Command.bGrooveLevel) nLastGrooveBar = rCommand.m_nMeasure;
}
}
if (fAddMore)
{
int nLastMeasure = 0;
nLastGrooveBar = 0;
bLastGroove = 0;
pCommand = m_CommandList.GetHead();
for (; pCommand; pCommand = pCommand->GetNext())
{
TemplateCommand& rCommand = pCommand->GetItemValue();
TListItem<TemplateCommand> *pNext = pCommand->GetNext();
int nMeasure = rCommand.m_nMeasure;
if (rCommand.m_Command.bCommand != DMUS_COMMANDT_GROOVE)
{
nLastMeasure = nMeasure;
continue;
}
if (rCommand.m_Command.bCommand == DMUS_COMMANDT_GROOVE)
{
bLastGroove = rCommand.m_Command.bGrooveLevel;
}
if ( (nLastMeasure + nFillLength + nBreakLength + 4) < nMeasure )
{
if ((rand() % 3) == 0) // do something?
{ // perhaps a fill?
nLastMeasure = nMeasure;
if ((bLastGroove > 50) &&
(nMeasure >= nFillLength) &&
(nMeasure - nFillLength > nLastGrooveBar) &&
(rand() % 2))
{
AddCommand(nMeasure - nFillLength, PF_FILL);
}
else
{
if (pNext)
{
while (nMeasure + nBreakLength <= pNext->GetItemValue().m_nMeasure )
{
AddCommand(nMeasure, PF_BREAK);
nMeasure += nBreakLength;
if (rand() % 2) break;
}
}
}
}
}
if (bLastGroove) nLastGrooveBar = rCommand.m_nMeasure;
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CDMTempl
CDMTempl::CDMTempl( ) : m_cRef(1), m_pTemplateInfo(NULL), m_fCSInitialized(FALSE)
{
InterlockedIncrement(&g_cComponent);
// Do this first since it might throw an exception
//
::InitializeCriticalSection( &m_CriticalSection );
m_fCSInitialized = TRUE;
}
CDMTempl::~CDMTempl()
{
if (m_fCSInitialized)
{
CleanUp();
::DeleteCriticalSection( &m_CriticalSection );
}
InterlockedDecrement(&g_cComponent);
}
void CDMTempl::CleanUp()
{
if( m_pTemplateInfo != NULL )
{
delete m_pTemplateInfo;
m_pTemplateInfo = NULL;
}
}
STDMETHODIMP CDMTempl::QueryInterface(
const IID &iid,
void **ppv)
{
V_INAME(CDMTempl::QueryInterface);
V_PTRPTR_WRITE(ppv);
V_REFGUID(iid);
if (iid == IID_IUnknown || iid == IID_IDMTempl)
{
*ppv = static_cast<IDMTempl*>(this);
}
else if (iid == IID_IPersistStream)
{
*ppv = static_cast<IPersistStream*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CDMTempl::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CDMTempl::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT CDMTempl::SaveCommandList( IAARIFFStream* pRIFF, DMUS_TIMESIGNATURE& rTimeSig )
{
IStream* pStream;
MMCKINFO ck;
HRESULT hr;
DWORD cb;
DWORD dwSize;
DMUS_IO_COMMAND iCommand;
TListItem<TemplateCommand>* pCommand;
if (!m_pTemplateInfo) return E_FAIL;
pStream = pRIFF->GetStream();
if (!pStream) return E_FAIL;
hr = E_FAIL;
ck.ckid = FOURCC_COMMAND;
if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
{
dwSize = sizeof( DMUS_IO_COMMAND );
hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
if( FAILED( hr ) || cb != sizeof( dwSize ) )
{
pStream->Release();
return E_FAIL;
}
for( pCommand = m_pTemplateInfo->m_CommandList.GetHead(); pCommand != NULL ; pCommand = pCommand->GetNext() )
{
TemplateCommand& rCommand = pCommand->GetItemValue();
if (rCommand.m_Command.bGrooveLevel || rCommand.m_Command.bCommand)
{
memset( &iCommand, 0, sizeof( iCommand ) );
iCommand.mtTime = ClocksPerMeasure(rTimeSig) * rCommand.m_nMeasure;
iCommand.wMeasure = rCommand.m_nMeasure;
iCommand.bBeat = 0;
iCommand.bCommand = rCommand.m_Command.bCommand;
iCommand.bGrooveLevel = rCommand.m_Command.bGrooveLevel;
iCommand.bGrooveRange = rCommand.m_Command.bGrooveRange;
iCommand.bRepeatMode = rCommand.m_Command.bRepeatMode;
if( FAILED( pStream->Write( &iCommand, sizeof( iCommand ), &cb ) ) ||
cb != sizeof( iCommand ) )
{
break;
}
}
}
if( pCommand == NULL &&
pRIFF->Ascend( &ck, 0 ) == 0 )
{
hr = S_OK;
}
}
pStream->Release();
return hr;
}
HRESULT CDMTempl::SaveSignPostList( IAARIFFStream* pRIFF, DMUS_TIMESIGNATURE& TimeSig )
{
IStream* pStream;
MMCKINFO ck;
HRESULT hr;
DWORD cb;
DWORD dwSize;
DMUS_IO_SIGNPOST oSignPost;
TListItem<TemplateCommand>* pCommand;
;
if (!m_pTemplateInfo) return E_FAIL;
pStream = pRIFF->GetStream();
if (!pStream) return E_FAIL;
hr = E_FAIL;
ck.ckid = DMUS_FOURCC_SIGNPOST_TRACK_CHUNK;
if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
{
dwSize = sizeof( oSignPost );
hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb );
if( FAILED( hr ) || cb != sizeof( dwSize ) )
{
pStream->Release();
return E_FAIL;
}
for( pCommand = m_pTemplateInfo->m_CommandList.GetHead(); pCommand != NULL ; pCommand = pCommand->GetNext() )
{
TemplateCommand& rCommand = pCommand->GetItemValue();
memset( &oSignPost, 0, sizeof( oSignPost ) );
oSignPost.mtTime = ClocksPerMeasure(TimeSig) * rCommand.m_nMeasure;
oSignPost.wMeasure = rCommand.m_nMeasure;
oSignPost.dwChords = rCommand.m_dwChord;
if( FAILED( pStream->Write( &oSignPost, sizeof( oSignPost ), &cb ) ) ||
cb != sizeof( oSignPost ) )
{
break;
}
}
if( pCommand == NULL &&
pRIFF->Ascend( &ck, 0 ) == 0 )
{
hr = S_OK;
}
}
pStream->Release();
return hr;
}
HRESULT CDMTempl::Init(void* pTemplate)
{
CleanUp();
m_pTemplateInfo = (TemplateStruct*)pTemplate;
// fix groove levels in the command list
// m_pTemplateInfo->FillInGrooveLevels();
return S_OK;
}
HRESULT CDMTempl::CreateSegment(IDirectMusicSegment* pISegment)
{
if (!pISegment) return E_INVALIDARG;
if (!m_pTemplateInfo) return E_FAIL;
IDirectMusicTrack* pICommandTrack = NULL;
IDirectMusicTrack* pISignPostTrack = NULL;
IAARIFFStream* pCommandRIFF = NULL;
IStream* pICommandStream = NULL;
IPersistStream* pICommandTrackStream = NULL;
IPersistStream* pISignPostTrackStream = NULL;
IAARIFFStream* pSignPostRIFF = NULL;
IStream* pISignPostStream = NULL;
HRESULT hr = S_OK;
DMUS_TIMESIGNATURE TimeSig;
// Fill in the time sig event with default values (4/4, 16th note resolution)
TimeSig.mtTime = 0;
TimeSig.bBeatsPerMeasure = 4;
TimeSig.bBeat = 4;
TimeSig.wGridsPerBeat = 4;
// 1. Create Command and Sign Post Tracks.
hr = ::CoCreateInstance(
CLSID_DirectMusicCommandTrack,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicTrack,
(void**)&pICommandTrack
);
if (FAILED(hr)) goto ON_END;
hr = ::CoCreateInstance(
CLSID_DirectMusicSignPostTrack,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicTrack,
(void**)&pISignPostTrack
);
if (FAILED(hr)) goto ON_END;
// 2. Write the template's command list out to a stream.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pICommandStream);
if (S_OK != hr) goto ON_END;
AllocRIFFStream( pICommandStream, &pCommandRIFF);
if (!pCommandRIFF)
{
hr = E_FAIL;
goto ON_END;
}
SaveCommandList(pCommandRIFF, TimeSig);
// 3. Use the command list stream as input to the Command Track's Load method.
hr = pICommandTrack->QueryInterface(IID_IPersistStream, (void**)&pICommandTrackStream);
if(FAILED(hr)) goto ON_END;
StreamSeek(pICommandStream, 0, STREAM_SEEK_SET);
hr = pICommandTrackStream->Load(pICommandStream);
if(FAILED(hr)) goto ON_END;
// 4. Write the template's sign post list out to a stream.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pISignPostStream);
if(S_OK != hr) goto ON_END;
AllocRIFFStream( pISignPostStream, &pSignPostRIFF);
if (!pSignPostRIFF)
{
hr = E_FAIL;
goto ON_END;
}
SaveSignPostList(pSignPostRIFF, TimeSig);
// 5. Use the chord list stream as input to the Sign Post Track's Load method.
hr = pISignPostTrack->QueryInterface(IID_IPersistStream, (void**)&pISignPostTrackStream);
if(FAILED(hr)) goto ON_END;
StreamSeek(pISignPostStream, 0, STREAM_SEEK_SET);
hr = pISignPostTrackStream->Load(pISignPostStream);
if (FAILED(hr)) goto ON_END;
// 6. Create a Segment has been removed it is now passed in
// 7. Initialize the segment appropriately.
//pISegment->SetUserData(m_pTemplateInfo->m_nMeasures);
pISegment->SetLength(ClocksPerMeasure(TimeSig) * m_pTemplateInfo->m_nMeasures);
// 8. Insert the two Tracks into the Segment's Track list.
pISegment->InsertTrack(pICommandTrack, 1);
pISegment->InsertTrack(pISignPostTrack, 1);
// Note: the segment must release the track objects...
ON_END:
if (pICommandTrack) pICommandTrack->Release();
if (pISignPostTrack) pISignPostTrack->Release();
if (pCommandRIFF) pCommandRIFF->Release();
if (pICommandStream) pICommandStream->Release();
if (pICommandTrackStream) pICommandTrackStream->Release();
if (pISignPostTrackStream) pISignPostTrackStream->Release();
if (pSignPostRIFF) pSignPostRIFF->Release();
if (pISignPostStream) pISignPostStream->Release();
return hr;
}
HRESULT CDMTempl::GetClassID( LPCLSID pclsid )
{
if ( pclsid == NULL ) return E_INVALIDARG;
*pclsid = CLSID_DMTempl;
return S_OK;
}
HRESULT CDMTempl::IsDirty()
{
return ( m_fDirty ) ? S_OK : S_FALSE;
}
static TListItem<TemplateCommand>* loadacommand( LPSTREAM pStream, DWORD dwSize )
{
CommandExt command;
TListItem<TemplateCommand>* pCommand = new TListItem<TemplateCommand>;
if( pCommand == NULL )
{
StreamSeek( pStream, dwSize, STREAM_SEEK_CUR );
return NULL;
}
TemplateCommand& rCommand = pCommand->GetItemValue();
if( dwSize > sizeof(CommandExt) )
{
pStream->Read( &command, sizeof(CommandExt), NULL );
FixBytes( FBT_COMMANDEXT, &command );
StreamSeek( pStream, dwSize - sizeof(CommandExt), STREAM_SEEK_CUR );
}
else
{
pStream->Read( &command, dwSize, NULL );
FixBytes( FBT_COMMANDEXT, &command );
}
//rCommand.m_lTime = command->time;
rCommand.m_nMeasure = command.measure;
rCommand.m_Command.bGrooveRange = 0;
rCommand.m_Command.bRepeatMode = 0;
switch (command.command)
{
case PF_FILL:
rCommand.m_Command.bCommand = DMUS_COMMANDT_FILL;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_INTRO:
rCommand.m_Command.bCommand = DMUS_COMMANDT_INTRO;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_BREAK:
rCommand.m_Command.bCommand = DMUS_COMMANDT_BREAK;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_END:
rCommand.m_Command.bCommand = DMUS_COMMANDT_END;
rCommand.m_Command.bGrooveLevel = 0;
break;
case PF_A:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 12;
break;
case PF_B:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 37;
break;
case PF_C:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 62;
break;
case PF_D:
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 87;
break;
default: // default to a Groove with level 0 (interpretation: use previous groove level)
// This happens in the measure following an embellishment
rCommand.m_Command.bCommand = DMUS_COMMANDT_GROOVE;
rCommand.m_Command.bGrooveLevel = 0;
}
rCommand.m_dwChord = command.chord;
return pCommand;
}
HRESULT CDMTempl::LoadTemplate( LPSTREAM pStream, DWORD dwSize )
{
TListItem<TemplateCommand>* pCommand;
DWORD id = 0;
DWORD tsize = 0;
DWORD segsize = 0;
SCTtemplate* pTemplate;
long lSize = dwSize;
if ( pStream == NULL ) return E_INVALIDARG;
pTemplate = new SCTtemplate;
if( pTemplate == NULL )
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
return E_OUTOFMEMORY;
}
if (!GetMLong( pStream, tsize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
delete pTemplate;
return E_FAIL;
}
lSize -= 4;
if( tsize > sizeof(SCTtemplate) )
{
pStream->Read( pTemplate, sizeof(SCTtemplate), NULL );
FixBytes( FBT_SCTTEMPLATE, pTemplate );
StreamSeek( pStream, tsize - sizeof(SCTtemplate), STREAM_SEEK_CUR );
}
else
{
pStream->Read( pTemplate, tsize, NULL );
FixBytes( FBT_SCTTEMPLATE, pTemplate );
}
lSize -= tsize;
m_pTemplateInfo = new TemplateStruct;
if (!m_pTemplateInfo)
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
return E_OUTOFMEMORY;
}
m_pTemplateInfo->m_strName = pTemplate->achName;
m_pTemplateInfo->m_strType = pTemplate->achType;
m_pTemplateInfo->m_nMeasures = pTemplate->nMeasures;
delete pTemplate;
while( lSize > 0 )
{
pStream->Read( &id, 4, NULL );
if (!GetMLong( pStream, segsize ))
{
StreamSeek( pStream, lSize, STREAM_SEEK_CUR );
break;
}
lSize -= 8;
switch( id )
{
case mmioFOURCC( 'D', 'M', 'C', 's' ):
pCommand = loadacommand( pStream, segsize );
if( pCommand )
{
m_pTemplateInfo->m_CommandList.AddTail(pCommand);
}
break;
default:
StreamSeek( pStream, segsize, STREAM_SEEK_CUR );
break;
}
lSize -= segsize;
}
// fix groove levels in the command list
BYTE bLastGroove = 62;
pCommand = m_pTemplateInfo->m_CommandList.GetHead();
for (; pCommand; pCommand = pCommand->GetNext())
{
TemplateCommand& rCommand = pCommand->GetItemValue();
if (rCommand.m_Command.bGrooveLevel == 0)
{
rCommand.m_Command.bGrooveLevel = bLastGroove;
}
else bLastGroove = rCommand.m_Command.bGrooveLevel;
}
return S_OK;
}
// This loads a *single* template. I also need to handle files that contain
// *lists* of templates (but I can just load the first one in the list)
HRESULT CDMTempl::Load( LPSTREAM pStream )
{
FOURCC id;
DWORD dwSize;
HRESULT hr;
if ( pStream == NULL ) return E_INVALIDARG;
EnterCriticalSection( &m_CriticalSection );
CleanUp();
if( FAILED( pStream->Read( &id, sizeof( FOURCC ), NULL ) ) ||
!GetMLong( pStream, dwSize ) )
{
hr = E_FAIL;
goto end;
}
if( id != mmioFOURCC( 'L', 'P', 'T', 's' ) )
{
hr = E_FAIL;
goto end;
}
hr = LoadTemplate( pStream, dwSize );
end:
LeaveCriticalSection( &m_CriticalSection );
return hr;
}
HRESULT CDMTempl::Save( LPSTREAM pStream, BOOL fClearDirty )
{
return E_NOTIMPL;
}
HRESULT CDMTempl::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
{
return E_NOTIMPL;
}