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

1131 lines
36 KiB
C++

//+-------------------------------------------------------------------------
//
// 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;
}