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

589 lines
19 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) 1999-1999 Microsoft Corporation
//
// File: mgentrk.h
//
//--------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// MelodyFragment
#ifndef __MELGENTRK_H_
#define __MELGENTRK_H_
#include "dmusici.h"
#include "TList.h"
//#include "dmpublic.h" // remove when this gets incorporated into dmusici.h/dmusicf.h
#include "dmstyle.h"
#define DMUS_TRANSITIONF_GHOST_FOUND 1
#define DMUS_TRANSITIONF_OVERLAP_FOUND 2
#define DMUS_TRANSITIONF_LAST_FOUND 4
#define DMUS_TRANSITIONF_GHOST_OK 8
#define DMUS_TRANSITIONF_OVERLAP_OK 0x10
#define DMUS_TRANSITIONF_LAST_OK 0x20
// overlap delta is largest value less than a 128th note triplet
#define OVERLAP_DELTA 15
HRESULT CopyMelodyFragment(DMUS_MELODY_FRAGMENT& rTo, const DMUS_MELODY_FRAGMENT& rFrom);
HRESULT CopyMelodyFragment(DMUS_MELODY_FRAGMENT& rTo, const DMUS_IO_MELODY_FRAGMENT& rFrom);
HRESULT CopyMelodyFragment(DMUS_IO_MELODY_FRAGMENT& rTo, const DMUS_MELODY_FRAGMENT& rFrom);
HRESULT CopyMelodyFragment(DMUS_IO_MELODY_FRAGMENT& rTo, const DMUS_IO_MELODY_FRAGMENT& rFrom);
struct CompositionFragment;
struct EventWrapper;
BOOL Less(DMUS_IO_SEQ_ITEM& SeqItem1, DMUS_IO_SEQ_ITEM& SeqItem2);
BOOL Greater(DMUS_IO_SEQ_ITEM& SeqItem1, DMUS_IO_SEQ_ITEM& SeqItem2);
BOOL Less(EventWrapper& SeqItem1, EventWrapper& SeqItem2);
BOOL Greater(EventWrapper& SeqItem1, EventWrapper& SeqItem2);
/////////////////////////////////////////////////////////////////////////////
// MelodyFragment
struct MelodyFragment
{
MelodyFragment() {}
MelodyFragment(DMUS_MELODY_FRAGMENT& rSource) :
m_mtTime(rSource.mtTime),
m_dwID(rSource.dwID),
m_dwVariationFlags(rSource.dwVariationFlags),
m_dwRepeatFragmentID(rSource.dwRepeatFragmentID),
m_dwFragmentFlags(rSource.dwFragmentFlags),
m_dwPlayModeFlags(rSource.dwPlayModeFlags),
m_dwTransposeIntervals(rSource.dwTransposeIntervals),
m_ConnectionArc(rSource.ConnectionArc),
m_Command(rSource.Command)
{
wcscpy(m_wszVariationLabel, rSource.wszVariationLabel);
}
MelodyFragment(MelodyFragment& rSource) :
m_mtTime(rSource.m_mtTime),
m_dwID(rSource.m_dwID),
m_dwVariationFlags(rSource.m_dwVariationFlags),
m_dwRepeatFragmentID(rSource.m_dwRepeatFragmentID),
m_dwFragmentFlags(rSource.m_dwFragmentFlags),
m_dwPlayModeFlags(rSource.m_dwPlayModeFlags),
m_dwTransposeIntervals(rSource.m_dwTransposeIntervals),
m_ConnectionArc(rSource.m_ConnectionArc),
m_Command(rSource.m_Command)
{
wcscpy(m_wszVariationLabel, rSource.m_wszVariationLabel);
for (int i = 0; i < INVERSIONGROUPLIMIT; i++)
{
m_aInversionGroups[i] = rSource.m_aInversionGroups[i];
}
}
HRESULT GetPattern(DMStyleStruct* pStyleStruct,
CDirectMusicPattern*& rPattern,
TListItem<CompositionFragment>* pLastFragment);
HRESULT GetVariations(CompositionFragment& rCompFragment,
CompositionFragment& rfragmentRepeat,
CompositionFragment& rfragmentLast,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rNextChord,
MUSIC_TIME mtNextChord,
TListItem<CompositionFragment>* pLastFragment);
/* HRESULT GetVariation(DirectMusicPartRef& rPartRef,
DMUS_CHORD_PARAM& rCurrentChord,
MUSIC_TIME mtNext,
MUSIC_TIME mtNextChord,
IDirectMusicTrack* pChordTrack,
DWORD& rdwVariation);
*/
HRESULT GetChord(IDirectMusicSegment* pTempSeg,
IDirectMusicSong* pSong,
DWORD dwTrackGroup,
MUSIC_TIME& rmtNext,
DMUS_CHORD_PARAM& rCurrentChord,
MUSIC_TIME& rmtCurrent,
DMUS_CHORD_PARAM& rRealCurrentChord);
HRESULT GetChord(MUSIC_TIME mtTime,
IDirectMusicSegment* pTempSeg,
IDirectMusicSong* pSong,
DWORD dwTrackGroup,
MUSIC_TIME& rmtNext,
DMUS_CHORD_PARAM& rCurrentChord);
HRESULT TestTransition(BYTE bMIDI,
MUSIC_TIME mtTime,
DMUS_CHORD_PARAM& rCurrentChord,
int nPartIndex,
DirectMusicPartRef& rPartRef,
TListItem<CompositionFragment>* pLastFragment);
HRESULT TestHarmonicConstraints(TListItem<EventWrapper>* pOldEventHead,
TList<EventWrapper>& rNewEventList);
HRESULT GetFirstNote(int nVariation,
DMUS_CHORD_PARAM& rCurrentChord,
CompositionFragment& rCompFragment,
DirectMusicPartRef& rPartRef,
BYTE& rbMidi,
MUSIC_TIME& rmtNote);
HRESULT GetNote(CDirectMusicEventItem* pEvent,
DMUS_CHORD_PARAM& rCurrentChord,
DirectMusicPartRef& rPartRef,
BYTE& rbMidi);
HRESULT GetEvent(CDirectMusicEventItem* pEvent,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rRealCurrentChord,
MUSIC_TIME mtNow,
DirectMusicPartRef& rPartRef,
TListItem<EventWrapper>*& rpEventItem);
HRESULT TransposeEventList(int nInterval,
CompositionFragment& rfragmentRepeat,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rRealCurrentChord,
BYTE bPlaymode,
DirectMusicPartRef& rPartRef,
TListItem<EventWrapper>*& rpOldEventHead,
TList<EventWrapper>& rNewEventList,
BYTE& rbFirstMIDI,
MUSIC_TIME& rmtFirstTime);
HRESULT GetRepeatedEvents(CompositionFragment& rfragmentRepeat,
DMUS_CHORD_PARAM& rCurrentChord,
DMUS_CHORD_PARAM& rRealCurrentChord,
BYTE bPlaymode,
int nPartIndex,
DirectMusicPartRef& rPartRef,
TListItem<CompositionFragment>* pLastFragment,
MUSIC_TIME& rmtFirstNote,
TList<EventWrapper>& rEventList);
bool UsesRepeat()
{
return (m_dwFragmentFlags & DMUS_FRAGMENTF_USE_REPEAT) ? true : false;
}
bool UsesTransitionRules()
{
return (m_ConnectionArc.dwFlags & (DMUS_CONNECTIONF_GHOST | DMUS_CONNECTIONF_INTERVALS | DMUS_CONNECTIONF_OVERLAP)) ? true : false;
}
bool RepeatsWithConstraints()
{
return
UsesRepeat() &&
( (m_dwFragmentFlags & (DMUS_FRAGMENTF_SCALE | DMUS_FRAGMENTF_CHORD)) ? true : false );
}
DWORD GetID()
{
return m_dwID;
}
DWORD GetRepeatID()
{
return m_dwRepeatFragmentID;
}
MUSIC_TIME GetTime()
{
return m_mtTime;
}
DMUS_COMMAND_PARAM GetCommand()
{
return m_Command;
}
DMUS_CONNECTION_RULE GetConnectionArc()
{
return m_ConnectionArc;
}
DWORD GetVariationFlags()
{
return m_dwVariationFlags;
}
void ClearInversionGroups()
{
for (int i = 0; i < INVERSIONGROUPLIMIT; i++)
m_aInversionGroups[i].m_wGroupID = 0;
}
protected:
MUSIC_TIME m_mtTime;
DWORD m_dwID; // This fragment's ID
WCHAR m_wszVariationLabel[DMUS_MAX_FRAGMENTLABEL]; // Each style translates this into a set of variations (held in part ref)
DWORD m_dwVariationFlags; // A set of variations
DWORD m_dwRepeatFragmentID; // ID of a fragment to repeat
DWORD m_dwFragmentFlags; // including things like: invert the fragment, transpose it...
DWORD m_dwPlayModeFlags; // including new playmodes (only use 8 bits of this)
DWORD m_dwTransposeIntervals; // Legal transposition intervals (first 24 bits; two-octave range)
DMUS_COMMAND_PARAM m_Command;
DMUS_CONNECTION_RULE m_ConnectionArc;
InversionGroup m_aInversionGroups[INVERSIONGROUPLIMIT]; // Inversion Groups for composing melodies
};
// TransitionConstraint (for keeping track of transition constraints)
struct TransitionConstraint
{
TransitionConstraint() : dwFlags(0), bGhost(0), bOverlap(0), bLastPlayed(0)
{
}
DWORD dwFlags;
BYTE bGhost;
BYTE bOverlap;
BYTE bLastPlayed;
};
// EventOverlap (for remembering events that might overlap succeeding fragments)
struct EventOverlap
{
~EventOverlap()
{
ZeroMemory(&m_PartRef, sizeof(m_PartRef));
m_pEvent = NULL;
}
DirectMusicPartRef m_PartRef;
MUSIC_TIME m_mtTime;
MUSIC_TIME m_mtDuration;
CDirectMusicEventItem* m_pEvent;
DMUS_CHORD_PARAM m_Chord;
DMUS_CHORD_PARAM m_RealChord;
};
struct EventWrapper
{
EventWrapper() : m_pEvent(NULL), m_mtTime(0), m_bMIDI(0), m_dwPChannel(0), m_wMusic(0), m_bPlaymode(DMUS_PLAYMODE_NONE)
{
}
~EventWrapper()
{
m_pEvent = NULL;
}
CDirectMusicEventItem* m_pEvent;
MUSIC_TIME m_mtTime;
DWORD m_dwPChannel;
WORD m_wMusic;
BYTE m_bMIDI;
BYTE m_bScaleFlat;
BYTE m_bScaleSharp;
BYTE m_bChordFlat;
BYTE m_bChordSharp;
BYTE m_bPlaymode;
};
// FragmentPartRecord (for keeping track of previously generated melody fragment parts)
// (in addition to sequence events, may also want to keep track of note events)
struct FragmentPartRecord
{
FragmentPartRecord()
{
}
~FragmentPartRecord()
{
m_listEvents.CleanUp();
}
TList<EventWrapper> m_listEvents;
};
// CompositionFragment (melody fragment used in the composition process)
struct CompositionFragment : MelodyFragment
{
CompositionFragment()
{
m_aFragmentParts = NULL;
m_abVariations = NULL;
m_pStyle = NULL;
m_pPattern = NULL;
}
CompositionFragment(MelodyFragment& rFragment) : MelodyFragment(rFragment)
{
m_aFragmentParts = NULL;
m_abVariations = NULL;
m_pStyle = NULL;
m_pPattern = NULL;
}
~CompositionFragment()
{
if (m_aFragmentParts) delete [] m_aFragmentParts;
if (m_abVariations) delete [] m_abVariations;
}
HRESULT Init(CDirectMusicPattern* pPattern, DMStyleStruct* pStyleStruct, int nParts)
{
m_pStyle = pStyleStruct;
m_pPattern = pPattern;
m_abVariations = new BYTE [nParts];
if (!m_abVariations)
{
return E_OUTOFMEMORY;
}
m_aFragmentParts = new FragmentPartRecord[nParts];
if (!m_aFragmentParts)
{
delete [] m_abVariations;
m_abVariations = NULL;
return E_OUTOFMEMORY;
}
return S_OK;
}
void SetPattern(CDirectMusicPattern* pPattern)
{
m_pPattern = pPattern;
}
void SetStyle(DMStyleStruct* pStyle)
{
m_pStyle = pStyle;
}
TListItem<EventOverlap>* GetOverlapHead()
{
return m_listEventOverlaps.GetHead();
}
TList<EventWrapper>& EventList(int i)
{
return m_aFragmentParts[i].m_listEvents;
}
void AddOverlap(TListItem<EventOverlap>* pOverlap)
{
m_listEventOverlaps.AddHead(pOverlap);
}
TListItem<EventWrapper>* GetEventHead(int i)
{
return m_aFragmentParts[i].m_listEvents.GetHead();
}
TListItem<EventWrapper>* RemoveEventHead(int i)
{
return m_aFragmentParts[i].m_listEvents.RemoveHead();
}
void AddEvent(int i, TListItem<EventWrapper>* pEvent)
{
m_aFragmentParts[i].m_listEvents.AddHead(pEvent);
}
void InsertEvent(int i, TListItem<EventWrapper>* pEvent)
{
TListItem<EventWrapper>* pScan = m_aFragmentParts[i].m_listEvents.GetHead();
TListItem<EventWrapper>* pPrevious = NULL;
for (; pScan; pScan = pScan->GetNext() )
{
if ( Greater(pEvent->GetItemValue(), pScan->GetItemValue()) ) break;
pPrevious = pScan;
}
if (!pPrevious)
{
m_aFragmentParts[i].m_listEvents.AddHead(pEvent);
}
else
{
pPrevious->SetNext(pEvent);
pEvent->SetNext(pScan);
}
}
void SortEvents(int i)
{
m_aFragmentParts[i].m_listEvents.MergeSort(Greater);
}
BOOL IsEmptyEvents(int i)
{
return m_aFragmentParts[i].m_listEvents.IsEmpty();
}
void CleanupEvents(int i)
{
m_aFragmentParts[i].m_listEvents.CleanUp();
}
DirectMusicTimeSig& GetTimeSig(DirectMusicPart* pPart)
{
if (pPart && pPart->m_timeSig.m_bBeat != 0)
{
return pPart->m_timeSig;
}
else if (m_pPattern && m_pPattern->m_timeSig.m_bBeat != 0)
{
return m_pPattern->m_timeSig;
}
else if (m_pStyle && m_pStyle->m_TimeSignature.m_bBeat != 0)
{
return m_pStyle->m_TimeSignature;
}
else
{
return m_staticTimeSig;
}
}
CDirectMusicPattern* m_pPattern;
FragmentPartRecord* m_aFragmentParts;
BYTE* m_abVariations;
TList<EventOverlap> m_listEventOverlaps;
DMStyleStruct* m_pStyle;
static DirectMusicTimeSig m_staticTimeSig;
};
/////////////////////////////////////////////////////////////////////////////
// CMelodyFormulationTrack
class CMelodyFormulationTrack :
public IDirectMusicTrack8,
public IPersistStream
{
public:
CMelodyFormulationTrack();
CMelodyFormulationTrack(const CMelodyFormulationTrack& rTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd);
~CMelodyFormulationTrack();
void Clear();
// IUnknown
//
virtual STDMETHODIMP QueryInterface(const IID &iid, void **ppv);
virtual STDMETHODIMP_(ULONG) AddRef();
virtual STDMETHODIMP_(ULONG) Release();
public:
HRESULT STDMETHODCALLTYPE Init(
/*[in]*/ IDirectMusicSegment* pSegment
);
HRESULT STDMETHODCALLTYPE InitPlay(
/*[in]*/ IDirectMusicSegmentState* pSegmentState,
/*[in]*/ IDirectMusicPerformance* pPerformance,
/*[out]*/ void** ppStateData,
/*[in]*/ DWORD dwTrackID,
/*[in]*/ DWORD dwFlags
);
HRESULT STDMETHODCALLTYPE EndPlay(
/*[in]*/ void* pStateData
);
HRESULT STDMETHODCALLTYPE Play(
/*[in]*/ void* pStateData,
/*[in]*/ MUSIC_TIME mtStart,
/*[in]*/ MUSIC_TIME mtEnd,
/*[in]*/ MUSIC_TIME mtOffset,
DWORD dwFlags,
IDirectMusicPerformance* pPerf,
IDirectMusicSegmentState* pSegState,
DWORD dwVirtualID
);
HRESULT STDMETHODCALLTYPE GetParam(
REFGUID pCommandGuid,
MUSIC_TIME mtTime,
MUSIC_TIME* pmtNext,
void *pData);
HRESULT STDMETHODCALLTYPE SetParam(
/* [in] */ REFGUID pCommandGuid,
/* [in] */ MUSIC_TIME mtTime,
/* [out] */ void __RPC_FAR *pData);
HRESULT STDMETHODCALLTYPE AddNotificationType(
/* [in] */ REFGUID pGuidNotify
);
HRESULT STDMETHODCALLTYPE RemoveNotificationType(
/* [in] */ REFGUID pGuidNotify
);
HRESULT STDMETHODCALLTYPE Clone(
MUSIC_TIME mtStart,
MUSIC_TIME mtEnd,
IDirectMusicTrack** ppTrack);
HRESULT STDMETHODCALLTYPE IsParamSupported(
/*[in]*/ REFGUID pGuid
);
// IDirectMusicTrack8 Methods
STDMETHODIMP PlayEx(void* pStateData,REFERENCE_TIME rtStart,
REFERENCE_TIME rtEnd,REFERENCE_TIME rtOffset,
DWORD dwFlags,IDirectMusicPerformance* pPerf,
IDirectMusicSegmentState* pSegSt,DWORD dwVirtualID) ;
STDMETHODIMP GetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,
REFERENCE_TIME* prtNext,void* pParam,void * pStateData, DWORD dwFlags) ;
STDMETHODIMP SetParamEx(REFGUID rguidType,REFERENCE_TIME rtTime,void* pParam, void * pStateData, DWORD dwFlags) ;
STDMETHODIMP Compose(IUnknown* pContext,
DWORD dwTrackGroup,
IDirectMusicTrack** ppResultTrack) ;
STDMETHODIMP Join(IDirectMusicTrack* pNewTrack,
MUSIC_TIME mtJoin,
IUnknown* pContext,
DWORD dwTrackGroup,
IDirectMusicTrack** ppResultTrack) ;
// IPersist methods
HRESULT STDMETHODCALLTYPE GetClassID( LPCLSID pclsid );
// IPersistStream methods
HRESULT STDMETHODCALLTYPE IsDirty();
HRESULT STDMETHODCALLTYPE Save( LPSTREAM pStream, BOOL fClearDirty );
HRESULT STDMETHODCALLTYPE GetSizeMax( ULARGE_INTEGER* /*pcbSize*/ );
HRESULT STDMETHODCALLTYPE Load( LPSTREAM pStream );
// Methods for dealing with melody fragments
HRESULT SendNotification(MUSIC_TIME mtTime,
IDirectMusicPerformance* pPerf,
IDirectMusicSegment* pSegment,
IDirectMusicSegmentState* pSegState,
DWORD dwFlags);
HRESULT LoadFragments(LPSTREAM pStream, long lFileSize );
HRESULT SetID(DWORD& rdwID);
HRESULT GetID(DWORD& rdwID);
HRESULT AddToSegment(IDirectMusicSegment* pTempSeg,
IDirectMusicTrack* pNewPatternTrack,
DWORD dwGroupBits);
protected:
// attributes
long m_cRef;
CRITICAL_SECTION m_CriticalSection; // for load and playback
BYTE m_bRequiresSave;
BOOL m_fNotifyRecompose;
TList<DMUS_MELODY_FRAGMENT> m_FragmentList;
DWORD m_dwLastId;
BYTE m_bPlaymode; // playmode for events in the generated pattern track.
};
#endif // __MELGENTRK_H_