//+------------------------------------------------------------------------- // // Copyright (c) 1998-2001 Microsoft Corporation // // File: dmsect.cpp // //-------------------------------------------------------------------------- // DMSection.cpp : Implementation of CDMSection #include "DMSect.h" #include "DMStyle.h" #include #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(this); } else if (iid == IID_IPersistStream) { *ppv = static_cast(this); } else if (iid == IID_IDirectMusicObject) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(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& ChordList ) { HRESULT hr = S_OK; DWORD cb; long lSize; TListItem* 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; 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* pSubChord = new TListItem; 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* pLowerSubChord = new TListItem; 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* pUpperSubChord = new TListItem; 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& CommandList ) { HRESULT hr = S_OK; DWORD cb; long lSize; TListItem* 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; 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* pSub = new TListItem(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* pScan = DMC.m_SubChordList.GetHead(); for (; pScan != NULL; pScan = pScan->GetNext()) { TListItem* pSub = new TListItem(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* pScan = DMC.m_SubChordList.GetHead(); for (; pScan != NULL; pScan = pScan->GetNext()) { TListItem* pSub = new TListItem(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* 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* 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* 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* 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; }