389 lines
19 KiB
C
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_
|