//+------------------------------------------------------------------------- // // Copyright (c) 1998-2001 Microsoft Corporation // // File: dmtempl.cpp // //-------------------------------------------------------------------------- // DMTempl.cpp : Implementation of CDMTempl #include "DMTempl.h" #include #include "dmusici.h" #include "dmusicf.h" #include "..\dmstyle\iostru.h" #include "debug.h" #include "..\shared\Validate.h" void TemplateStruct::AddIntro(TList& PlayList, int nIntroLength) { TListItem *pCommand = new TListItem; 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 *pChord = PlayList.GetHead(); for (; pChord; pChord = pChord->GetNext()) { pChord->GetItemValue().m_nMeasure += (short)nIntroLength; } TListItem *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 *pCommand = new TListItem; 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 *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 *pCommand; TListItem *pScan = m_CommandList.GetHead(); for (; pScan; pScan = pScan->GetNext()) { if (m_nMeasures - nLength == pScan->GetItemValue().m_nMeasure) break; } pCommand = (pScan) ? pScan : new TListItem; 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* 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* pCommands = pTemplate->m_CommandList.GetHead(); for(; pCommands; pCommands = pCommands->GetNext()) { TemplateCommand& rCommand = pCommands->GetItemValue(); TListItem *pNew = new TListItem; 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 *pCommand, BOOL fIsCommand) { TListItem *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* pCommand = new TListItem; 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* pCommand = new TListItem; 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 *pCommand = pTemplate->m_CommandList.GetHead(); TListItem *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 *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 *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 *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(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(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* 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* 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* loadacommand( LPSTREAM pStream, DWORD dwSize ) { CommandExt command; TListItem* pCommand = new TListItem; 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* 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; }