|
|
//+-------------------------------------------------------------------------
//
// Copyright (c) 1998-2001 Microsoft Corporation
//
// File: dmsect.cpp
//
//--------------------------------------------------------------------------
// DMSection.cpp : Implementation of CDMSection
#include "DMSect.h"
#include "DMStyle.h"
#include <initguid.h>
#include "debug.h"
#include "..\dmloader\ima.h"
#include "..\shared\Validate.h"
HRESULT CDMSection::GetDescriptor(LPDMUS_OBJECTDESC pDesc) { return S_OK; }
HRESULT CDMSection::SetDescriptor(LPDMUS_OBJECTDESC pDesc) { return S_OK; }
HRESULT CDMSection::ParseDescriptor(LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) { return S_OK; }
STDMETHODIMP CDMSection::QueryInterface( const IID &iid, void **ppv) { V_INAME(CDMSection::QueryInterface); V_REFGUID(iid); V_PTRPTR_WRITE(ppv);
if (iid == IID_IUnknown || iid == IID_IDMSection) { *ppv = static_cast<IDMSection*>(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast<IPersistStream*>(this); } else if (iid == IID_IDirectMusicObject) { *ppv = static_cast<IDirectMusicObject*>(this); } else { *ppv = NULL; return E_NOINTERFACE; }
reinterpret_cast<IUnknown*>(this)->AddRef(); return S_OK; }
STDMETHODIMP_(ULONG) CDMSection::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CDMSection::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; }
return m_cRef; }
/////////////////////////////////////////////////////////////////////////////
// CDMSection
STDMETHODIMP CDMSection::GetStyle(IUnknown * * ppStyle) { HRESULT hr; if (m_pStyle) { IUnknown* pIU = NULL; hr = m_pStyle->QueryInterface(IID_IUnknown, (void**)&pIU); if (SUCCEEDED(hr)) { *ppStyle = pIU; pIU->Release(); hr = S_OK; } } else hr = E_FAIL; return hr; }
STDMETHODIMP CDMSection::CreateSegment(IDirectMusicSegment* pISegment) { HRESULT hr = S_OK; IDirectMusicTrack* pIStyleTrack = NULL; IDirectMusicTrack* pICommandTrack = NULL; IDirectMusicTrack* pIChordTrack = NULL; IDirectMusicTrack* pBandTrack = NULL; IDirectMusicTrack* pDMTrack = NULL; IAARIFFStream* pCommandRIFF = NULL; IAARIFFStream* pChordRIFF = NULL; IStream* pICommandStream = NULL; IStream* pIChordStream = NULL; IPersistStream* pICommandTrackStream = NULL; IPersistStream* pIChordTrackStream = NULL; IStyleTrack* pS = NULL; IUnknown* pU = NULL; DMUS_BAND_PARAM DMBandParam;
// 1. Create Style, Command, and Chord Tracks.
hr = ::CoCreateInstance( CLSID_DirectMusicStyleTrack, NULL, CLSCTX_INPROC, IID_IDirectMusicTrack, (void**)&pIStyleTrack ); if (FAILED(hr)) goto ON_END; hr = ::CoCreateInstance( CLSID_DirectMusicCommandTrack, NULL, CLSCTX_INPROC, IID_IDirectMusicTrack, (void**)&pICommandTrack ); if (FAILED(hr)) goto ON_END; hr = ::CoCreateInstance( CLSID_DirectMusicChordTrack, NULL, CLSCTX_INPROC, IID_IDirectMusicTrack, (void**)&pIChordTrack ); if (FAILED(hr)) goto ON_END; hr = ::CoCreateInstance( CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC, IID_IDirectMusicTrack, (void**)&pBandTrack ); if (FAILED(hr)) goto ON_END;
// 2/3. Use the section's style create a style track.
hr = m_pStyle->QueryInterface(IID_IUnknown, (void**)&pU); if (FAILED(hr)) goto ON_END; hr = pIStyleTrack->QueryInterface(IID_IStyleTrack, (void**)&pS); if (FAILED(hr)) goto ON_END; pS->SetTrack(pU); m_pStyle->AddRef(); // Whenever I create a track from a style, I need to addref the style
// 4. Write the section's command list out to a stream.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pICommandStream); if (FAILED(hr)) goto ON_END; hr = AllocRIFFStream( pICommandStream, &pCommandRIFF); if (FAILED(hr)) goto ON_END; SaveCommandList(pCommandRIFF); // 5. Write the section's chord list out to a stream.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pIChordStream); if (S_OK != hr) goto ON_END; hr = AllocRIFFStream( pIChordStream, &pChordRIFF); if (FAILED(hr)) goto ON_END; SaveChordList(pChordRIFF); // 6. 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; // 7a. Use the chord list stream as input to the Chord Track's Load method.
hr = pIChordTrack->QueryInterface(IID_IPersistStream, (void**)&pIChordTrackStream); if (FAILED(hr)) goto ON_END; StreamSeek(pIChordStream, 0, STREAM_SEEK_SET); hr = pIChordTrackStream->Load(pIChordStream); if(FAILED(hr)) goto ON_END; // 7b. Load band into band track
DMBandParam.mtTimePhysical = -64; DMBandParam.pBand = m_pIDMBand; hr = pBandTrack->SetParam(GUID_BandParam, 0, (void*)&DMBandParam); if (FAILED(hr)) goto ON_END;
// 8. Create a Segment has been removed it is now passed in
// 9. Initialize the segment appropriately.
pISegment->SetRepeats(m_wRepeats); pISegment->SetDefaultResolution((DWORD)m_wClocksPerBeat); pISegment->SetLength(m_dwClockLength); // need the length of the section!
/////////////////////////////////////////////////////////////////
DMUS_TEMPO_PARAM tempo; tempo.mtTime = 0; // ConvertTime( dwTime );
tempo.dblTempo = (double) m_wTempo; // ((double)dw) / 64;
/////////////////////////////////////////////////////////////////
hr = S_OK; // Create a Tempo Track in which to store the tempo events
if( SUCCEEDED( CoCreateInstance( CLSID_DirectMusicTempoTrack, NULL, CLSCTX_INPROC, IID_IDirectMusicTrack, (void**)&pDMTrack ))) { GUID Guid = GUID_TempoParam; if ( SUCCEEDED(pDMTrack->SetParam(Guid, 0, &tempo))) { pISegment->InsertTrack( pDMTrack, 1 ); } } // 10. Insert the three Tracks into the Segment's Track list.
pISegment->InsertTrack(pBandTrack, 1); pISegment->InsertTrack(pIStyleTrack, 1); pISegment->InsertTrack(pICommandTrack, 1); pISegment->InsertTrack(pIChordTrack, 1);
// Note: the segment must release the track objects...
ON_END: if (pDMTrack) pDMTrack->Release(); if (pIChordStream) pIChordStream->Release(); if (pIChordTrackStream) pIChordTrackStream->Release(); if (pICommandStream) pICommandStream->Release(); if (pICommandTrackStream) pICommandTrackStream->Release(); if (pCommandRIFF) pCommandRIFF->Release(); if (pChordRIFF) pChordRIFF->Release(); if (pS) pS->Release(); if (pU) pU->Release(); if (pIStyleTrack) pIStyleTrack->Release(); if (pICommandTrack) pICommandTrack->Release(); if (pIChordTrack) pIChordTrack->Release(); if (pBandTrack) pBandTrack->Release(); return hr; }
CDMSection::CDMSection() : m_pStyle(NULL), m_pIDMBand(NULL), m_cRef(1) { InterlockedIncrement(&g_cComponent); }
CDMSection::~CDMSection() { CleanUp(); InterlockedDecrement(&g_cComponent); }
void CDMSection::CleanUp( BOOL fStop) { if(m_pIDMBand) { m_pIDMBand->Release(); }
// let whoever used the section release the style.
if (m_pStyle) { m_pStyle->Release(); } }
static BYTE setchordbits( long lPattern ) { LONG i; short count = 0; BYTE bBits = 0;
for( i=0L ; i<32L ; i++ ) { if( lPattern & (1L << i) ) count++; } bBits |= CHORD_INVERT; if( count > 3 ) bBits |= CHORD_FOUR; if( lPattern & (15L << 18L) ) bBits |= CHORD_UPPER; bBits &= ~CHORD_COUNT; bBits |= count; return bBits; }
HRESULT CDMSection::LoadChordList( LPSTREAM pStream, LPMMCKINFO pck, TList<DMChord>& ChordList ) { HRESULT hr = S_OK; DWORD cb; long lSize; TListItem<DMChord>* pChord; ioChordSelection iChordSelection; WORD wSizeChord;
lSize = pck->cksize; // load size of chord structure
hr = pStream->Read( &wSizeChord, sizeof( wSizeChord ), &cb ); if( FAILED( hr ) || cb != sizeof( wSizeChord ) ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_SHORT, &wSizeChord ); lSize -= cb; while( lSize > 0 ) { pChord = new TListItem<DMChord>; if( pChord == NULL ) { hr = E_OUTOFMEMORY; goto ON_ERR; } if( wSizeChord > sizeof( ioChordSelection ) ) { hr = pStream->Read( &iChordSelection, sizeof( ioChordSelection ), &cb ); if( FAILED( hr ) || cb != sizeof( ioChordSelection ) ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_IOCHORDSELECTION, &iChordSelection ); StreamSeek( pStream, wSizeChord - sizeof( ioChordSelection ), STREAM_SEEK_CUR ); } else { hr = pStream->Read( &iChordSelection, wSizeChord, &cb ); if( FAILED( hr ) || cb != wSizeChord ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_IOCHORDSELECTION, &iChordSelection ); } lSize -= wSizeChord;
// WideCharToMultiByte( CP_ACP, 0, iChordSelection.wstrName, -1, pChord->name, sizeof( pChord->name ), NULL, NULL );
DMChord& rChord = pChord->GetItemValue(); rChord.m_bKey = m_bRoot; rChord.m_dwScale = DEFAULT_SCALE_PATTERN; rChord.m_strName = iChordSelection.wstrName; rChord.m_bBeat = iChordSelection.bBeat; rChord.m_wMeasure = iChordSelection.wMeasure; rChord.m_mtTime = m_wClocksPerMeasure * rChord.m_wMeasure + m_wClocksPerBeat * rChord.m_bBeat; // If chordpattern contains <= n notes (for an n-note chord)
// create a single subchord
// Else
// create 2 subchords, with the 1st having the lower n notes and the
// 2nd having the upper n notes (assumes there are <= 2n notes)
BYTE bBits = setchordbits( iChordSelection.aChord[0].lChordPattern ); short nChordCount = bBits & CHORD_COUNT; // The root of the lower chord is the input chord's root,
// relative to the scale (section) root.
BYTE bChordRoot = iChordSelection.aChord[0].bRoot; // (bBits & CHORD_UPPER) ? (iChordSelection.aChord[0].bRoot - 12) : iChordSelection.aChord[0].bRoot;
bChordRoot -= m_bRoot; if (bChordRoot < 0) bChordRoot += 12; if ((bBits & CHORD_FOUR && nChordCount <= 4) || (!(bBits & CHORD_FOUR) && nChordCount <= 3)) { // single subchord with all info from input chord
TListItem<DMSubChord>* pSubChord = new TListItem<DMSubChord>; if( pSubChord == NULL ) { hr = E_OUTOFMEMORY; goto ON_ERR; } DMSubChord& rSubChord = pSubChord->GetItemValue(); if (iChordSelection.aChord[0].lChordPattern) { rSubChord.m_dwChordPattern = iChordSelection.aChord[0].lChordPattern; } else { } rSubChord.m_dwScalePattern = iChordSelection.aChord[0].lScalePattern; rSubChord.m_dwInversionPoints = 0xffffff; // default: inversions everywhere
rSubChord.m_dwLevels = (1 << SUBCHORD_BASS) | (1 << SUBCHORD_STANDARD_CHORD); rSubChord.m_bChordRoot = bChordRoot; rSubChord.m_bScaleRoot = m_bRoot; // scale root is root of the section
rChord.m_SubChordList.AddTail(pSubChord); } else { // two subchords both with scale and roots from input chord, and:
// 1st chord: chord pattern from lower n notes of input chord
// 2nd chord: chord pattern from upper n notes of input chord
DWORD dwLowerSubChord = 0L; DWORD dwUpperSubChord = 0L; BYTE bUpperRoot = bChordRoot; DWORD dwChordPattern = iChordSelection.aChord[0].lChordPattern; short nIgnoreHigh = (bBits & CHORD_FOUR) ? 4 : 3; short nIgnoreLow = (bBits & CHORD_FOUR) ? nChordCount - 4 : nChordCount - 3; short nLowestUpper = 0; for (short nPos = 0, nCount = 0; nPos < 24; nPos++) { if (dwChordPattern & 1) { if (nCount < nIgnoreHigh) { dwLowerSubChord |= 1L << nPos; } if (nCount >= nIgnoreLow) { if (!nLowestUpper) { nLowestUpper = nPos; bUpperRoot = (bUpperRoot + (BYTE) nLowestUpper); } dwUpperSubChord |= 1L << (nPos - nLowestUpper); } nCount++; if (nCount >= nChordCount) break; } dwChordPattern >>= 1L; } // now, create the two subchords.
TListItem<DMSubChord>* pLowerSubChord = new TListItem<DMSubChord>; if( pLowerSubChord == NULL ) { hr = E_OUTOFMEMORY; goto ON_ERR; } DMSubChord& rLowerSubChord = pLowerSubChord->GetItemValue(); rLowerSubChord.m_dwChordPattern = dwLowerSubChord; rLowerSubChord.m_dwScalePattern = iChordSelection.aChord[0].lScalePattern; rLowerSubChord.m_dwInversionPoints = 0xffffff; // default: inversions everywhere
rLowerSubChord.m_dwLevels = (1 << SUBCHORD_BASS); rLowerSubChord.m_bChordRoot = bChordRoot; rLowerSubChord.m_bScaleRoot = m_bRoot; // scale root is root of the section
rChord.m_SubChordList.AddTail(pLowerSubChord); TListItem<DMSubChord>* pUpperSubChord = new TListItem<DMSubChord>; if( pUpperSubChord == NULL ) { hr = E_OUTOFMEMORY; goto ON_ERR; } DMSubChord& rUpperSubChord = pUpperSubChord->GetItemValue(); rUpperSubChord.m_dwChordPattern = dwUpperSubChord; rUpperSubChord.m_dwScalePattern = iChordSelection.aChord[0].lScalePattern; rUpperSubChord.m_dwInversionPoints = 0xffffff; // default: inversions everywhere
rUpperSubChord.m_dwLevels = (1 << SUBCHORD_STANDARD_CHORD); rUpperSubChord.m_bChordRoot = bUpperRoot % 24; while (rUpperSubChord.m_bChordRoot < rLowerSubChord.m_bChordRoot) rUpperSubChord.m_bChordRoot += 12; rUpperSubChord.m_bScaleRoot = m_bRoot; // scale root is root of the section
rChord.m_SubChordList.AddTail(pUpperSubChord); }
ChordList.AddTail(pChord); } ON_ERR: return hr; }
HRESULT CDMSection::LoadCommandList( LPSTREAM pStream, LPMMCKINFO pck, TList<DMCommand>& CommandList ) { HRESULT hr = S_OK; DWORD cb; long lSize; TListItem<DMCommand>* pCommand; ioCommand iCommand; WORD wSizeCommand;
lSize = pck->cksize; // load size of command structure
hr = pStream->Read( &wSizeCommand, sizeof( wSizeCommand ), &cb ); if( FAILED( hr ) || cb != sizeof( wSizeCommand ) ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_SHORT, &wSizeCommand ); lSize -= cb; while( lSize > 0 ) { pCommand = new TListItem<DMCommand>; if( pCommand == NULL ) { hr = E_OUTOFMEMORY; goto ON_ERR; } if( wSizeCommand > sizeof( ioCommand ) ) { hr = pStream->Read( &iCommand, sizeof( ioCommand ), &cb ); if( FAILED( hr ) || cb != sizeof( ioCommand ) ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_IOCOMMAND, &iCommand ); StreamSeek( pStream, wSizeCommand - sizeof( ioCommand ), STREAM_SEEK_CUR ); } else { hr = pStream->Read( &iCommand, wSizeCommand, &cb ); if( FAILED( hr ) || cb != wSizeCommand ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_IOCOMMAND, &iCommand ); } lSize -= wSizeCommand;
DMCommand& rCommand = pCommand->GetItemValue(); ////////////////////////////////////////////////////////////////////
// Change this from absolute time to measures and beats!
////////////////////////////////////////////////////////////////////
// To convert clock time to measures and beats:
// 1. Use clocksPerMeasure to find the measure
// 2. Use clocksPerBeat to find the beat
// DWORD dwClocks = rCommand.m_dwTime - m_dwTime;
rCommand.m_wMeasure = (WORD) (ConvertTime(iCommand.lTime) / m_wClocksPerMeasure); // assumes 1st measure is 0
rCommand.m_bBeat = (BYTE) ((ConvertTime(iCommand.lTime) % m_wClocksPerMeasure) / m_wClocksPerBeat); // ditto
rCommand.m_mtTime = ConvertTime(iCommand.lTime); /////////////////////////////////////////////////////////////////////
switch (iCommand.dwCommand & PF_RIFF) { case PF_INTRO: rCommand.m_bCommand = DMUS_COMMANDT_INTRO; break; case PF_END: rCommand.m_bCommand = DMUS_COMMANDT_END; break; case PF_BREAK: rCommand.m_bCommand = DMUS_COMMANDT_BREAK; break; case PF_FILL: rCommand.m_bCommand = DMUS_COMMANDT_FILL; break; default: rCommand.m_bCommand = DMUS_COMMANDT_GROOVE; } switch (iCommand.dwCommand & PF_GROOVE) { case PF_A: rCommand.m_bGrooveLevel = 12; break; case PF_B: rCommand.m_bGrooveLevel = 37; break; case PF_C: rCommand.m_bGrooveLevel = 62; break; case PF_D: rCommand.m_bGrooveLevel = 87; break; default: rCommand.m_bGrooveLevel = 0; } rCommand.m_bGrooveRange = 0; rCommand.m_bRepeatMode = DMUS_PATTERNT_RANDOM;
CommandList.AddTail(pCommand); } ON_ERR: return hr; }
HRESULT CDMSection::LoadStyleReference( LPSTREAM pStream, MMCKINFO* pck) { HRESULT hr; DWORD cb; DWORD cSize; //char szName[40];
wchar_t wstrName[40]; //IAALoader* pLoader;
cSize = min( pck->cksize, sizeof( wstrName ) ); hr = pStream->Read( wstrName, cSize, &cb ); if( FAILED( hr ) || cb != cSize ) { return E_FAIL; } m_strStyleName = wstrName; DMUS_OBJECTDESC ObjectDescript; ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC); ObjectDescript.guidClass = CLSID_DirectMusicStyle; wcscpy(ObjectDescript.wszName, wstrName); ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_NAME; IDirectMusicLoader* pLoader; IDirectMusicGetLoader *pIGetLoader; // <==============
hr = pStream->QueryInterface( IID_IDirectMusicGetLoader, (void **) &pIGetLoader );// <========
if (SUCCEEDED(hr)) { hr = pIGetLoader->GetLoader(&pLoader); // <========
if (SUCCEEDED(hr)) // <========
{ // <========
hr = pLoader->GetObject(&ObjectDescript, IID_IDirectMusicStyle, (void**)&m_pStyle); pLoader->Release(); } // <========
pIGetLoader->Release(); // <========
} return hr; }
HRESULT CDMSection::LoadSection( IAARIFFStream* pRIFF, MMCKINFO* pckMain ) { HRESULT hr = S_OK; HRESULT hrBand = S_OK; ioSection iSection; MMCKINFO ck; DWORD cb; DWORD cSize; IStream* pStream; BOOL fLoadedSection = FALSE;
pStream = pRIFF->GetStream(); while( pRIFF->Descend( &ck, pckMain, 0 ) == 0 ) { switch( ck.ckid ) { case FOURCC_SECTION: cSize = min( ck.cksize, sizeof( iSection ) ); hr = pStream->Read( &iSection, cSize, &cb ); if( FAILED( hr ) || cb != cSize ) { hr = E_FAIL; goto ON_ERR; } FixBytes( FBT_IOSECTION, &iSection );
m_strName = iSection.wstrName; m_dwTime = iSection.lTime; m_wTempo = iSection.wTempo; // wRepeats refers to repeats after the first play.
m_wRepeats = iSection.wRepeats; m_wMeasureLength = iSection.wMeasureLength; m_wClocksPerMeasure = ConvertTime(iSection.wClocksPerMeasure); m_wClocksPerBeat = ConvertTime(iSection.wClocksPerBeat); m_wTempoFract = iSection.wTempoFract; m_dwFlags = iSection.dwFlags; m_bRoot = (char)( iSection.chKey & ~KEY_FLAT ); m_dwClockLength = (long)m_wMeasureLength * (long)m_wClocksPerMeasure;
fLoadedSection = TRUE; break; case FOURCC_STYLEREF: if( fLoadedSection ) { hr = LoadStyleReference( pStream, &ck ); if (hr != S_OK) { hrBand = hr; } if( FAILED( hr ) ) { goto ON_ERR; } } break;
case FOURCC_RIFF: switch(ck.fccType) { case FOURCC_BAND_FORM: { // Create a band
hr = CoCreateInstance(CLSID_DirectMusicBand, NULL, CLSCTX_INPROC, IID_IDirectMusicBand, (void**)&m_pIDMBand);
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 = m_pIDMBand->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
if(SUCCEEDED(hr)) { hr = pIPersistStream->Load(pStream); if (hr != S_OK) { hrBand = hr; } pIPersistStream->Release(); } }
if(FAILED(hr)) { goto ON_ERR; } } break; } break;
case FOURCC_CHORD: if( fLoadedSection ) { hr = LoadChordList( pStream, &ck, m_ChordList ); if( FAILED( hr ) ) { goto ON_ERR; } } break; case FOURCC_COMMAND: if( fLoadedSection ) { hr = LoadCommandList( pStream, &ck, m_CommandList ); if( FAILED( hr ) ) { goto ON_ERR; } } break; } pRIFF->Ascend( &ck, 0 ); }
ON_ERR: if( FAILED( hr ) ) {
if(m_pIDMBand != NULL) { if(m_pIDMBand) { m_pIDMBand->Release(); } m_pIDMBand = NULL; }
} pStream->Release( ); if (hr == S_OK && hrBand != S_OK) { hr = hrBand; } return hr; }
HRESULT CDMSection::Load( LPSTREAM pStream ) // Pointer to a stream that contains the
// Section information to load.
{ DWORD dwPos; IAARIFFStream* pRIFF; MMCKINFO ckMain; HRESULT hr;
if ( pStream == NULL ) return E_INVALIDARG; hr = E_FAIL; CleanUp( FALSE );
dwPos = StreamTell( pStream );
StreamSeek( pStream, dwPos, STREAM_SEEK_SET );
if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) ) { ckMain.fccType = FOURCC_SECTION_FORM; if( pRIFF->Descend( &ckMain, NULL, MMIO_FINDRIFF ) == 0 ) { hr = LoadSection( pRIFF, &ckMain ); pRIFF->Ascend( &ckMain, 0 ); } pRIFF->Release( ); } return hr; }
DMChord::DMChord(DMUS_CHORD_PARAM& DMC) { m_strName = DMC.wszName; m_wMeasure = DMC.wMeasure; m_bBeat = DMC.bBeat; m_bKey = DMC.bKey; m_dwScale = DMC.dwScale; m_fSilent = (DMC.bFlags & DMUS_CHORDKEYF_SILENT) ? true : false; for (BYTE n = 0; n < DMC.bSubChordCount; n++) { TListItem<DMSubChord>* pSub = new TListItem<DMSubChord>(DMC.SubChordList[n]); if (pSub) { m_SubChordList.AddTail(pSub); } } }
DMChord::DMChord(DMChord& DMC) { m_strName = DMC.m_strName; m_wMeasure = DMC.m_wMeasure; m_bBeat = DMC.m_bBeat; m_bKey = DMC.m_bKey; m_dwScale = DMC.m_dwScale; m_fSilent = DMC.m_fSilent; TListItem<DMSubChord>* pScan = DMC.m_SubChordList.GetHead(); for (; pScan != NULL; pScan = pScan->GetNext()) { TListItem<DMSubChord>* pSub = new TListItem<DMSubChord>(pScan->GetItemValue()); if (pSub) { m_SubChordList.AddTail(pSub); } } }
DMChord& DMChord::operator=(const DMChord& DMC) { if (this != &DMC) { m_strName = DMC.m_strName; m_wMeasure = DMC.m_wMeasure; m_bBeat = DMC.m_bBeat; m_bKey = DMC.m_bKey; m_dwScale = DMC.m_dwScale; m_fSilent = DMC.m_fSilent; m_SubChordList.CleanUp(); TListItem<DMSubChord>* pScan = DMC.m_SubChordList.GetHead(); for (; pScan != NULL; pScan = pScan->GetNext()) { TListItem<DMSubChord>* pSub = new TListItem<DMSubChord>(pScan->GetItemValue()); if (pSub) { m_SubChordList.AddTail(pSub); } } } return *this; }
DMChord::operator DMUS_CHORD_PARAM() { DMUS_CHORD_PARAM result; wcscpy(result.wszName, m_strName); result.wMeasure = m_wMeasure; result.bBeat = m_bBeat; result.bKey = m_bKey; result.dwScale = m_dwScale; result.bFlags = 0; if (m_fSilent) result.bFlags |= DMUS_CHORDKEYF_SILENT; BYTE n = 0; TListItem<DMSubChord>* pSub = m_SubChordList.GetHead(); for (; pSub != NULL; pSub = pSub->GetNext(), n++) { result.SubChordList[n] = pSub->GetItemValue(); } result.bSubChordCount = n; return result; }
HRESULT DMChord::Save( IAARIFFStream* pRIFF ) { IStream* pStream; MMCKINFO ck; DWORD cb; DMUS_IO_CHORD iChord; DMUS_IO_SUBCHORD iSubChord; DWORD dwSize; HRESULT hr = E_FAIL;
pStream = pRIFF->GetStream(); ck.ckid = mmioFOURCC('c', 'r', 'd', 'b'); if( pRIFF->CreateChunk( &ck, 0 ) == 0 ) { memset( &iChord, 0, sizeof( iChord ) ); m_strName = iChord.wszName; //MultiByteToWideChar( CP_ACP, 0, m_strName, -1, iChord.wszName, sizeof( iChord.wszName ) / sizeof( wchar_t ) );
iChord.mtTime = m_mtTime; iChord.wMeasure = m_wMeasure; iChord.bBeat = m_bBeat; iChord.bFlags = 0; if (m_fSilent) iChord.bFlags |= DMUS_CHORDKEYF_SILENT; dwSize = sizeof( iChord ); hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb ); if( SUCCEEDED(hr) && SUCCEEDED( pStream->Write( &iChord, sizeof( iChord), &cb ) ) && cb == sizeof( iChord) ) // &&
//pRIFF->Ascend( &ck, 0 ) == 0 )
{ //ck.ckid = mmioFOURCC('s', 'u', 'b', 'c');
//if( pRIFF->CreateChunk( &ck, 0 ) == 0 )
{ DWORD dwCount = (WORD) m_SubChordList.GetCount(); hr = pStream->Write( &dwCount, sizeof( dwCount ), &cb ); if( FAILED( hr ) || cb != sizeof( dwSize ) ) { pStream->Release(); return E_FAIL; } dwSize = sizeof( iSubChord ); hr = pStream->Write( &dwSize, sizeof( dwSize ), &cb ); if( FAILED( hr ) || cb != sizeof( dwSize ) ) { pStream->Release(); return E_FAIL; } for (TListItem<DMSubChord>* pSub = m_SubChordList.GetHead(); pSub != NULL; pSub = pSub->GetNext()) { DMSubChord& rSubChord = pSub->GetItemValue(); memset( &iSubChord, 0, sizeof( iSubChord ) ); iSubChord.dwChordPattern = rSubChord.m_dwChordPattern; iSubChord.dwScalePattern = rSubChord.m_dwScalePattern; iSubChord.dwInversionPoints = rSubChord.m_dwInversionPoints; iSubChord.dwLevels = rSubChord.m_dwLevels; iSubChord.bChordRoot = rSubChord.m_bChordRoot; iSubChord.bScaleRoot = rSubChord.m_bScaleRoot; if( FAILED( pStream->Write( &iSubChord, sizeof( iSubChord ), &cb ) ) || cb != sizeof( iSubChord ) ) { break; } } // ascend from chord body chunk
if( pSub == NULL && pRIFF->Ascend( &ck, 0 ) != 0 ) { hr = S_OK; } } } } pStream->Release(); return hr; }
HRESULT CDMSection::SaveChordList( IAARIFFStream* pRIFF ) { IStream* pStream; //LPSECT pSection;
MMCKINFO ck; MMCKINFO ckHeader; HRESULT hr; DWORD cb; //WORD wSize;
TListItem<DMChord>* pChord; //int i;
pStream = pRIFF->GetStream(); //pSection = (LPSECT)m_pSection->lpDLL1;
ck.fccType = DMUS_FOURCC_CHORDTRACK_LIST; hr = pRIFF->CreateChunk(&ck, MMIO_CREATELIST); if (SUCCEEDED(hr)) { // wSize = sizeof( ioChordSelection );
//FixBytes( FBT_SHORT, &wSize );
// hr = pStream->Write( &wSize, sizeof( wSize ), &cb );
// if( FAILED( hr ) || cb != sizeof( wSize ) )
// {
// RELEASE( pStream );
// return E_FAIL;
//}
DWORD dwRoot = m_bRoot; DWORD dwScale = DEFAULT_SCALE_PATTERN | (dwRoot << 24);
ckHeader.ckid = DMUS_FOURCC_CHORDTRACKHEADER_CHUNK; hr = pRIFF->CreateChunk(&ckHeader, 0); if (FAILED(hr)) { pStream->Release(); return hr; } hr = pStream->Write( &dwScale, sizeof( dwScale ), &cb ); if (FAILED(hr)) { pStream->Release(); return hr; } hr = pRIFF->Ascend( &ckHeader, 0 ); if (hr != S_OK) { pStream->Release(); return hr; }
for( pChord = m_ChordList.GetHead() ; pChord != NULL ; pChord = pChord->GetNext() ) { hr = pChord->GetItemValue().Save(pRIFF); if (FAILED(hr)) { pStream->Release(); return hr; } } if( pChord == NULL && pRIFF->Ascend( &ck, 0 ) == 0 ) { hr = S_OK; } }
pStream->Release(); return hr; }
HRESULT CDMSection::SaveCommandList( IAARIFFStream* pRIFF ) { IStream* pStream; MMCKINFO ck; HRESULT hr; DWORD cb; DWORD dwSize; DMUS_IO_COMMAND iCommand; TListItem<DMCommand>* pCommand;
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_CommandList.GetHead(); pCommand != NULL ; pCommand = pCommand->GetNext() ) { DMCommand& rCommand = pCommand->GetItemValue(); memset( &iCommand, 0, sizeof( iCommand ) ); iCommand.mtTime = rCommand.m_mtTime; iCommand.wMeasure = rCommand.m_wMeasure; iCommand.bBeat = rCommand.m_bBeat; iCommand.bCommand = rCommand.m_bCommand; iCommand.bGrooveLevel = rCommand.m_bGrooveLevel; iCommand.bGrooveRange = rCommand.m_bGrooveRange; iCommand.bRepeatMode = rCommand.m_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 CDMSection::Save( LPSTREAM pStream, // Stream to store Section.
BOOL /*fClearDirty*/ ) // TRUE to clear dirty flag, FALSE to leave
// dirty flag unchanged.
{ IAARIFFStream* pRIFF; HRESULT hr; MMCKINFO ckMain;
hr = E_FAIL; if( SUCCEEDED( AllocRIFFStream( pStream, &pRIFF ) ) ) { ckMain.fccType = FOURCC_SECTION_FORM; if( pRIFF->CreateChunk( &ckMain, MMIO_CREATERIFF ) != 0 ) { goto ON_ERR; }
if( FAILED( SaveChordList( pRIFF ) ) || FAILED( SaveCommandList( pRIFF ) ) ) { goto ON_ERR; }
if( pRIFF->Ascend( &ckMain, 0 ) != 0 ) { goto ON_ERR; } hr = S_OK; ON_ERR: pRIFF->Release(); } return hr; }
/* IPersist methods */ HRESULT CDMSection::GetClassID( LPCLSID pclsid ) { return E_NOTIMPL; }
HRESULT CDMSection::IsDirty() { return E_NOTIMPL; }
HRESULT CDMSection::GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ ) { return E_NOTIMPL; }
|