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

389 lines
19 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// File: ptrntrk.h
//
//--------------------------------------------------------------------------
// PtrnTrk.h : Declaration of the Pattern Track info and state structs
#ifndef __PATTERNTRACK_H_
#define __PATTERNTRACK_H_
#include "dmsect.h"
#include "dmstyle.h"
const MUSIC_TIME MAX_END = 2147483647; // max end time for a track
#define DMUS_PATTERN_AUDITION 1
#define DMUS_PATTERN_MOTIF 2
#define DMUS_PATTERN_STYLE 3
#include <time.h> // to seed random number generator
const long MULTIPLIER = 48271;
const long MODULUS = 2147483647;
class CRandomNumbers
{
public:
CRandomNumbers(long nSeed = 0)
{
nCurrent = (long)(nSeed ? nSeed : time(NULL));
}
void Seed(long nSeed)
{
nCurrent = nSeed;
}
long Next(long nCeiling = 0)
{
LONGLONG llProduct = MULTIPLIER * (LONGLONG) nCurrent;
nCurrent = (long) (llProduct % MODULUS);
return nCeiling ? nCurrent % nCeiling : nCurrent;
}
private:
long nCurrent;
};
struct PatternTrackState;
struct StylePair
{
StylePair() : m_mtTime(0), m_pStyle(NULL) {}
~StylePair() { if (m_pStyle) m_pStyle->Release(); }
MUSIC_TIME m_mtTime;
IDMStyle* m_pStyle;
};
struct StatePair
{
StatePair() : m_pSegState(NULL), m_pStateData(NULL) {}
StatePair(const StatePair& rPair)
{
m_pSegState = rPair.m_pSegState;
m_pStateData = rPair.m_pStateData;
}
StatePair(IDirectMusicSegmentState* pSegState, PatternTrackState* pStateData)
{
m_pSegState = pSegState;
m_pStateData = pStateData;
}
StatePair& operator= (const StatePair& rPair)
{
if (this != &rPair)
{
m_pSegState = rPair.m_pSegState;
m_pStateData = rPair.m_pStateData;
}
return *this;
}
~StatePair()
{
}
IDirectMusicSegmentState* m_pSegState;
PatternTrackState* m_pStateData;
};
struct PatternTrackInfo
{
PatternTrackInfo();
PatternTrackInfo(const PatternTrackInfo* pInfo, MUSIC_TIME mtStart, MUSIC_TIME mtEnd);
virtual ~PatternTrackInfo();
virtual HRESULT STDMETHODCALLTYPE Init(
/*[in]*/ IDirectMusicSegment* pSegment
) = 0;
virtual HRESULT STDMETHODCALLTYPE InitPlay(
/*[in]*/ IDirectMusicTrack* pParentrack,
/*[in]*/ IDirectMusicSegmentState* pSegmentState,
/*[in]*/ IDirectMusicPerformance* pPerformance,
/*[out]*/ void** ppStateData,
/*[in]*/ DWORD dwTrackID,
/*[in]*/ DWORD dwFlags
) = 0;
HRESULT STDMETHODCALLTYPE EndPlay(
/*[in]*/ PatternTrackState* pStateData
);
HRESULT STDMETHODCALLTYPE AddNotificationType(
/* [in] */ REFGUID pGuidNotify
);
HRESULT STDMETHODCALLTYPE RemoveNotificationType(
/* [in] */ REFGUID pGuidNotify
);
PatternTrackState* FindState(IDirectMusicSegmentState* pSegState);
HRESULT MergePChannels();
HRESULT InitTrackVariations(CDirectMusicPattern* pPattern);
TList<StatePair> m_StateList; // The track's state information
TList<StylePair> m_pISList; // The track's Style interfaces
DWORD m_dwPChannels; // # of PChannels the track knows about
DWORD* m_pdwPChannels; // dynamic array of PChannels
BOOL m_fNotifyMeasureBeat;
BOOL m_fActive;
// BOOL m_fTrackPlay;
BOOL m_fStateSetBySetParam; // If TRUE, active flag was set by GUID. Don't override.
// BOOL m_fStatePlaySetBySetParam; // If TRUE, trackplay flag was set by GUID. Don't override.
BOOL m_fChangeStateMappings; // If TRUE, state data needs to change m_pMappings
long m_lRandomNumberSeed; // If non-zero, use as a seed for variation selection
DWORD m_dwPatternTag; // replaces need for dynamic casting
DWORD m_dwValidate; // used to validate state data
BYTE* m_pVariations; // Track's array of variations (1 per part)
DWORD* m_pdwRemoveVariations; // Track's array of variations already played (1 per part)
};
#define PLAYPARTSF_CLOCKTIME 0x1
#define PLAYPARTSF_FIRST_CALL 0x2
#define PLAYPARTSF_START 0x4
#define PLAYPARTSF_RELOOP 0x8
#define PLAYPARTSF_FLUSH 0x10
struct PatternTrackState
{
PatternTrackState();
virtual ~PatternTrackState();
// methods
virtual HRESULT Play(
/*[in]*/ MUSIC_TIME mtStart,
/*[in]*/ MUSIC_TIME mtEnd,
/*[in]*/ MUSIC_TIME mtOffset,
REFERENCE_TIME rtOffset,
IDirectMusicPerformance* pPerformance,
DWORD dwFlags,
BOOL fClockTime
) = 0;
void GetNextChord(MUSIC_TIME mtNow, MUSIC_TIME mtOffset, IDirectMusicPerformance* pPerformance, BOOL fStart = FALSE, BOOL fSkipVariations = FALSE);
HRESULT ResetMappings()
{
HRESULT hr = S_OK;
if (m_pMappings) delete [] m_pMappings;
m_pMappings = new MuteMapping[m_pPatternTrack->m_dwPChannels];
if (!m_pMappings)
{
hr = E_OUTOFMEMORY;
}
else
{
for (DWORD dw = 0; dw < m_pPatternTrack->m_dwPChannels; dw++)
{
m_pMappings[dw].m_mtTime = 0;
m_pMappings[dw].m_dwPChannelMap = m_pPatternTrack->m_pdwPChannels[dw];
m_pMappings[dw].m_fMute = FALSE;
}
}
m_pPatternTrack->m_fChangeStateMappings = FALSE;
return hr;
}
void GetNextMute(DWORD dwPart, MUSIC_TIME mtStart, MUSIC_TIME mtNow, MUSIC_TIME mtOffset, IDirectMusicPerformance* pPerformance, BOOL fClockTime)
{
HRESULT hr = S_OK;
if (m_pPatternTrack->m_fChangeStateMappings)
{
hr = ResetMappings();
}
if (SUCCEEDED(hr))
{
for (DWORD dw = 0; dw < m_pPatternTrack->m_dwPChannels; dw++)
{
if ( (m_pPatternTrack->m_pdwPChannels[dw] == dwPart) &&
(0 <= m_pMappings[dw].m_mtTime && m_pMappings[dw].m_mtTime <= mtNow) )
{
DMUS_MUTE_PARAM MD;
MUSIC_TIME mtNext = 0;
MD.dwPChannel = m_pPatternTrack->m_pdwPChannels[dw];
if (fClockTime)
{
MUSIC_TIME mtMusic;
REFERENCE_TIME rtTime = (mtNow + mtOffset) * 10000;
pPerformance->ReferenceToMusicTime(rtTime,&mtMusic);
hr = pPerformance->GetParam(GUID_MuteParam, m_dwGroupID, DMUS_SEG_ANYTRACK, mtMusic,
&mtNext, (void*) &MD);
if (SUCCEEDED(hr))
{
REFERENCE_TIME rtNext;
// Convert to absolute reference time.
pPerformance->MusicToReferenceTime(mtNext + mtMusic,&rtNext);
rtNext -= (mtOffset * 10000); // Subtract out to get the time from segment start.
m_pMappings[dw].m_mtTime = (MUSIC_TIME)(rtNext / 10000); // Convert to milliseconds. Could be problematic if there's a tempo change.
m_pMappings[dw].m_dwPChannelMap = MD.dwPChannelMap;
m_pMappings[dw].m_fMute = MD.fMute;
}
else
{
// If we fail, disable mapping
m_pMappings[dw].m_mtTime = -1;
m_pMappings[dw].m_dwPChannelMap = m_pPatternTrack->m_pdwPChannels[dw];
m_pMappings[dw].m_fMute = FALSE;
}
}
else
{
hr = pPerformance->GetParam(GUID_MuteParam, m_dwGroupID, DMUS_SEG_ANYTRACK, mtNow + mtOffset,
&mtNext, (void*) &MD);
if (SUCCEEDED(hr))
{
m_pMappings[dw].m_mtTime = (mtNext) ? (mtNext + mtNow) : 0;
m_pMappings[dw].m_dwPChannelMap = MD.dwPChannelMap;
m_pMappings[dw].m_fMute = MD.fMute;
}
else
{
// If we fail, disable mapping
m_pMappings[dw].m_mtTime = -1;
m_pMappings[dw].m_dwPChannelMap = m_pPatternTrack->m_pdwPChannels[dw];
m_pMappings[dw].m_fMute = FALSE;
}
}
}
}
}
}
BOOL MapPChannel(DWORD dwPChannel, DWORD& dwMapPChannel);
HRESULT PlayParts(MUSIC_TIME mtStart,
MUSIC_TIME mtFinish,
MUSIC_TIME mtOffset,
REFERENCE_TIME rtOffset,
MUSIC_TIME mtSection,
IDirectMusicPerformance* pPerformance,
DWORD dwPartFlags,
DWORD dwPlayFlags,
bool& rfReloop);
void PlayPatternEvent(
MUSIC_TIME mtNow,
CDirectMusicEventItem* pEventItem,
DirectMusicTimeSig& TimeSig,
MUSIC_TIME mtPartOffset,
MUSIC_TIME mtSegmentOffset,
REFERENCE_TIME rtOffset,
IDirectMusicPerformance* pPerformance,
short nPart,
DirectMusicPartRef& rPartRef,
BOOL fClockTime,
MUSIC_TIME mtPartStart,
bool& rfChangedVariation);
void BumpTime(
CDirectMusicEventItem* pEvent,
DirectMusicTimeSig& TimeSig,
MUSIC_TIME mtOffset,
MUSIC_TIME& mtResult)
{
if (pEvent != NULL)
{
mtResult = TimeSig.GridToClocks(pEvent->m_nGridStart) + mtOffset;
}
}
virtual DWORD Variations(DirectMusicPartRef& rPartRef, int nPartIndex);
virtual BOOL PlayAsIs();
DirectMusicTimeSig& PatternTimeSig()
{
return
(m_pPattern && m_pPattern->m_timeSig.m_bBeat != 0) ?
m_pPattern->m_timeSig :
(m_pStyle != NULL ? m_pStyle->m_TimeSignature : (::DefaultTimeSig));
}
void SendTimeSigMessage(MUSIC_TIME mtNow, MUSIC_TIME mtOffset, MUSIC_TIME mtTime, IDirectMusicPerformance* pPerformance);
short FindGroup(WORD wID);
short AddGroup(WORD wID, WORD wCount, short m_nOffset);
DMStyleStruct* FindStyle(MUSIC_TIME mtTime, MUSIC_TIME& rmtTime);
MUSIC_TIME NotifyMeasureBeat(
MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, IDirectMusicPerformance* pPerformance, DWORD dwFlags);
HRESULT InitVariationSeeds(long lBaseSeed);
HRESULT RemoveVariationSeeds();
long RandomVariation(MUSIC_TIME mtTime, long lModulus);
virtual MUSIC_TIME PartOffset(int nPartIndex);
HRESULT InitPattern(CDirectMusicPattern* pTargetPattern, MUSIC_TIME mtNow, CDirectMusicPattern* pOldPattern = NULL);
// attributes
PatternTrackInfo* m_pPatternTrack; // This track state's parent track info
IDirectMusicTrack* m_pTrack; // This track state's parent track
DMStyleStruct* m_pStyle; // The style struct for the current style
IDirectMusicSegmentState* m_pSegState; // The segment state for a performance
DWORD m_dwVirtualTrackID; // The track's ID
MUSIC_TIME m_mtCurrentChordTime; // when the current chord began
MUSIC_TIME m_mtNextChordTime; // when the next chord begins
MUSIC_TIME m_mtLaterChordTime; // when the chord after the next chord begins
DMUS_CHORD_PARAM m_CurrentChord; // current chord
DMUS_CHORD_PARAM m_NextChord; // next chord
CDirectMusicPattern* m_pPattern; // currently playing pattern
DWORD* m_pdwPChannels; // array of PChannels for the pattern (1 per part)
BYTE* m_pVariations; // array of variations (1 per part)
DWORD* m_pdwVariationMask; // array of disabled variations (1 per part)
DWORD* m_pdwRemoveVariations; // array of variations already played (1 per part)
MUSIC_TIME* m_pmtPartOffset; // array of part offsets (1 per part)
bool* m_pfChangedVariation; // array: have this part's variations changed?
BOOL m_fNewPattern; // TRUE if we're starting a new pattern
BOOL m_mtPatternStart; // Time the current pattern started
BOOL m_fStateActive;
// BOOL m_fStatePlay;
InversionGroup m_aInversionGroups[INVERSIONGROUPLIMIT];
short m_nInversionGroupCount;
MuteMapping* m_pMappings; // dynamic array of PChannel mappings
// (sized to # of PChannels)
BYTE m_abVariationGroups[MAX_VARIATION_LOCKS];
CDirectMusicEventItem** m_ppEventSeek; // dynamic array of event list seek pointers
DWORD m_dwGroupID; // Track's group ID
CRandomNumbers* m_plVariationSeeds; // dynamic array of random # generators (1 per beat)
int m_nTotalGenerators; // size of m_plVariationSeeds
DWORD m_dwValidate; // used to validate state data
HRESULT m_hrPlayCode; // last HRESULT returned by Play
IDirectMusicPerformance* m_pPerformance; // performance used to init the state data
MUSIC_TIME m_mtPerformanceOffset; // from track::play
};
const int CURVE_TYPES = 258; // one for each CC, one for each PAT, one for PB, one for MAT
class CurveSeek
{
public:
CurveSeek();
void AddCurve(CDirectMusicEventItem* pEvent, MUSIC_TIME mtTimeStamp);
void PlayCurves(
PatternTrackState* pStateData,
DirectMusicTimeSig& TimeSig,
MUSIC_TIME mtPatternOffset,
MUSIC_TIME mtOffset,
REFERENCE_TIME rtOffset,
IDirectMusicPerformance* pPerformance,
short nPart,
DirectMusicPartRef& rPartRef,
BOOL fClockTime,
MUSIC_TIME mtPartStart);
private:
CDirectMusicEventItem* m_apCurves[CURVE_TYPES];
MUSIC_TIME m_amtTimeStamps[CURVE_TYPES];
bool m_fFoundCurve;
};
#endif //__PATTERNTRACK_H_