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.
1131 lines
36 KiB
1131 lines
36 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|