//+------------------------------------------------------------------------- // // 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* pLastFragment); HRESULT GetVariations(CompositionFragment& rCompFragment, CompositionFragment& rfragmentRepeat, CompositionFragment& rfragmentLast, DMUS_CHORD_PARAM& rCurrentChord, DMUS_CHORD_PARAM& rNextChord, MUSIC_TIME mtNextChord, TListItem* 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* pLastFragment); HRESULT TestHarmonicConstraints(TListItem* pOldEventHead, TList& 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*& rpEventItem); HRESULT TransposeEventList(int nInterval, CompositionFragment& rfragmentRepeat, DMUS_CHORD_PARAM& rCurrentChord, DMUS_CHORD_PARAM& rRealCurrentChord, BYTE bPlaymode, DirectMusicPartRef& rPartRef, TListItem*& rpOldEventHead, TList& 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* pLastFragment, MUSIC_TIME& rmtFirstNote, TList& 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 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* GetOverlapHead() { return m_listEventOverlaps.GetHead(); } TList& EventList(int i) { return m_aFragmentParts[i].m_listEvents; } void AddOverlap(TListItem* pOverlap) { m_listEventOverlaps.AddHead(pOverlap); } TListItem* GetEventHead(int i) { return m_aFragmentParts[i].m_listEvents.GetHead(); } TListItem* RemoveEventHead(int i) { return m_aFragmentParts[i].m_listEvents.RemoveHead(); } void AddEvent(int i, TListItem* pEvent) { m_aFragmentParts[i].m_listEvents.AddHead(pEvent); } void InsertEvent(int i, TListItem* pEvent) { TListItem* pScan = m_aFragmentParts[i].m_listEvents.GetHead(); TListItem* 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 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 m_FragmentList; DWORD m_dwLastId; BYTE m_bPlaymode; // playmode for events in the generated pattern track. }; #endif // __MELGENTRK_H_