|
|
// Copyright (c) 1999 Microsoft Corporation. All rights reserved.
//
// Implementation of CAutDirectMusicPerformance.
//
#include "stdinc.h"
#include "autperformance.h"
#include <limits>
#include "dmusicf.h"
const WCHAR CAutDirectMusicPerformance::ms_wszClassName[] = L"Performance";
//////////////////////////////////////////////////////////////////////
// Method Names/DispIDs
const DISPID DMPDISP_SetMasterTempo = 1; const DISPID DMPDISP_GetMasterTempo = 2; const DISPID DMPDISP_SetMasterVolume = 3; const DISPID DMPDISP_GetMasterVolume = 4; const DISPID DMPDISP_SetMasterGrooveLevel = 5; const DISPID DMPDISP_GetMasterGrooveLevel = 6; const DISPID DMPDISP_SetMasterTranspose = 7; const DISPID DMPDISP_GetMasterTranspose = 8; const DISPID DMPDISP_Trace = 9; const DISPID DMPDISP_Rand = 10;
const AutDispatchMethod CAutDirectMusicPerformance::ms_Methods[] = { // dispid, name,
// return: type, (opt), (iid),
// parm 1: type, opt, iid,
// parm 2: type, opt, iid,
// ...
// ADT_None
{ DMPDISP_SetMasterTempo, L"SetMasterTempo", ADPARAM_NORETURN, ADT_Long, false, &IID_NULL, // tempo!New value for master tempo scaling factor as a percentage. For example, 50 would halve the tempo and 200 would double it.
ADT_None }, /// Calls IDirectMusicPerformance::SetGlobalParam(GUID_PerfMasterTempo, tempo / 100, sizeof(float)).
{ DMPDISP_GetMasterTempo, L"GetMasterTempo", ADT_Long, true, &IID_NULL, // Current master tempo scaling factor as a percentage.
ADT_None }, /// Calls IDirectMusicPerformance::GetGlobalParam(GUID_PerfMasterTempo, X, sizeof(float)) and returns X * 100.
{ DMPDISP_SetMasterVolume, L"SetMasterVolume", ADPARAM_NORETURN, ADT_Long, false, &IID_NULL, // volume!New value for master volume attenuation.
ADT_Long, true, &IID_NULL, // duration
ADT_None }, /// Calls IDirectMusicPerformance::SetGlobalParam(GUID_PerfMasterVolume, volume, sizeof(long)).
/// Range is 100th of a dB. 0 is full volume.
{ DMPDISP_GetMasterVolume, L"GetMasterVolume", ADT_Long, true, &IID_NULL, // Current value of master volume attenuation.
ADT_None }, /// Calls IDirectMusicPerformance::GetGlobalParam(GUID_PerfMasterVolume, X, sizeof(long)) and returns X.
{ DMPDISP_SetMasterGrooveLevel, L"SetMasterGrooveLevel", ADPARAM_NORETURN, ADT_Long, false, &IID_NULL, // groove level!New value for the global groove level, which is added to the level in the command track.
ADT_None }, { DMPDISP_GetMasterGrooveLevel, L"GetMasterGrooveLevel", ADT_Long, true, &IID_NULL, // Current value of the global groove level, which is added to the level in the command track.
ADT_None }, { DMPDISP_SetMasterTranspose, L"SetMasterTranspose", ADPARAM_NORETURN, ADT_Long, false, &IID_NULL, // transpose!Number of semitones to transpose everything.
ADT_None }, { DMPDISP_GetMasterTranspose, L"GetMasterTranspose", ADT_Long, true, &IID_NULL, // Current global transposition (number of semitones).
ADT_None }, { DMPDISP_Trace, L"Trace", ADPARAM_NORETURN, ADT_Bstr, false, &IID_NULL, // string!text to output to testing log
ADT_None }, /// This allocates, stamps, and sends a DMUS_LYRIC_PMSG with the following fields:
/// <ul>
/// <li> dwPChannel = channel
/// <li> dwVirtualTrackID = 0
/// <li> dwGroupID = -1
/// <li> mtTime = GetTime(X, 0) is called and X * 10000 is used
/// <li> dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME
/// <li> dwType = DMUS_PMSGT_SCRIPTLYRIC
/// <li> wszString = string
/// </ul>
/// This is used to send text to a trace log for debugging purposes. Less commonly, a script could be
/// running in an application that listens and reacts to the script's trace output.
{ DMPDISP_Rand, L"Rand", ADT_Long, true, &IID_NULL, // Returns a randomly-generated number
ADT_Long, false, &IID_NULL, // Max value--returned number will be between 1 and this max. Cannot be zero or negative.
ADT_None }, { DISPID_UNKNOWN } };
const DispatchHandlerEntry<CAutDirectMusicPerformance> CAutDirectMusicPerformance::ms_Handlers[] = { { DMPDISP_SetMasterTempo, SetMasterTempo }, { DMPDISP_GetMasterTempo, GetMasterTempo }, { DMPDISP_SetMasterVolume, SetMasterVolume }, { DMPDISP_GetMasterVolume, GetMasterVolume }, { DMPDISP_SetMasterGrooveLevel, SetMasterGrooveLevel }, { DMPDISP_GetMasterGrooveLevel, GetMasterGrooveLevel }, { DMPDISP_SetMasterTranspose, SetMasterTranspose }, { DMPDISP_GetMasterTranspose, GetMasterTranspose }, { DMPDISP_Trace, _Trace }, { DMPDISP_Rand, Rand }, { DISPID_UNKNOWN } };
//////////////////////////////////////////////////////////////////////
// Creation
CAutDirectMusicPerformance::CAutDirectMusicPerformance( IUnknown* pUnknownOuter, const IID& iid, void** ppv, HRESULT *phr) : BaseImpPerf(pUnknownOuter, iid, ppv, phr), m_nTranspose(0), m_nVolume(0) { // set the random seed used by the Rand method
m_lRand = GetTickCount();
*phr = m_pITarget->QueryInterface(IID_IDirectMusicGraph, reinterpret_cast<void**>(&m_scomGraph));
if (SUCCEEDED(*phr)) { // Due to the aggregation contract, our object is wholely contained in the lifetime of
// the outer object and we shouldn't hold any references to it.
ULONG ulCheck = m_pITarget->Release(); assert(ulCheck); } }
HRESULT CAutDirectMusicPerformance::CreateInstance( IUnknown* pUnknownOuter, const IID& iid, void** ppv) { HRESULT hr = S_OK; CAutDirectMusicPerformance *pInst = new CAutDirectMusicPerformance(pUnknownOuter, iid, ppv, &hr); if (FAILED(hr)) { delete pInst; return hr; } if (pInst == NULL) return E_OUTOFMEMORY; return hr; }
//////////////////////////////////////////////////////////////////////
// Automation methods
HRESULT CAutDirectMusicPerformance::SetMasterTempo(AutDispatchDecodedParams *paddp) { LONG lTempo = paddp->params[0].lVal; float fltTempo = ConvertToTempo(lTempo); if (fltTempo < DMUS_MASTERTEMPO_MIN) fltTempo = DMUS_MASTERTEMPO_MIN; else if (fltTempo > DMUS_MASTERTEMPO_MAX) fltTempo = DMUS_MASTERTEMPO_MAX; return m_pITarget->SetGlobalParam(GUID_PerfMasterTempo, &fltTempo, sizeof(float)); }
HRESULT CAutDirectMusicPerformance::GetMasterTempo(AutDispatchDecodedParams *paddp) { LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn); if (!plRet) return S_OK;
float fltTempo = 1; // default value is 1 (multiplicative identity)
HRESULT hr = this->GetMasterParam(GUID_PerfMasterTempo, &fltTempo, sizeof(float)); if (SUCCEEDED(hr)) *plRet = ConvertFromTempo(fltTempo); return hr; }
HRESULT CAutDirectMusicPerformance::SetMasterVolume(AutDispatchDecodedParams *paddp) { if (!m_scomGraph) { assert(false); return E_FAIL; }
LONG lVol = paddp->params[0].lVal; LONG lDuration = paddp->params[1].lVal;
return SendVolumePMsg(lVol, lDuration, DMUS_PCHANNEL_BROADCAST_PERFORMANCE, m_scomGraph, m_pITarget, &m_nVolume); }
HRESULT CAutDirectMusicPerformance::GetMasterVolume(AutDispatchDecodedParams *paddp) { LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn); if (plRet) *plRet = m_nVolume; return S_OK; }
HRESULT CAutDirectMusicPerformance::SetMasterGrooveLevel(AutDispatchDecodedParams *paddp) { LONG lGroove = paddp->params[0].lVal; char chGroove = ClipLongRangeToType<char>(lGroove, char()); return m_pITarget->SetGlobalParam(GUID_PerfMasterGrooveLevel, reinterpret_cast<void*>(&chGroove), sizeof(char)); }
HRESULT CAutDirectMusicPerformance::GetMasterGrooveLevel(AutDispatchDecodedParams *paddp) { LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn); if (!plRet) return S_OK;
char chGroove = 0; // default value is 0 (additive identity)
HRESULT hr = this->GetMasterParam(GUID_PerfMasterGrooveLevel, reinterpret_cast<void*>(&chGroove), sizeof(char)); if (SUCCEEDED(hr)) *plRet = chGroove; return hr; }
HRESULT CAutDirectMusicPerformance::SetMasterTranspose(AutDispatchDecodedParams *paddp) { LONG lTranspose = paddp->params[0].lVal; short nTranspose = ClipLongRangeToType<short>(lTranspose, short());
SmartRef::PMsg<DMUS_TRANSPOSE_PMSG> pmsg(m_pITarget); HRESULT hr = pmsg.hr(); if FAILED(hr) return hr;
// Generic PMSG stuff
hr = m_pITarget->GetTime(&pmsg.p->rtTime, NULL); if (FAILED(hr)) return hr; pmsg.p->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME | DMUS_PMSGF_DX8; pmsg.p->dwType = DMUS_PMSGT_TRANSPOSE; pmsg.p->dwPChannel = DMUS_PCHANNEL_BROADCAST_PERFORMANCE; pmsg.p->dwVirtualTrackID = 0; pmsg.p->dwGroupID = -1;
// Transpose PMSG stuff
pmsg.p->nTranspose = nTranspose; pmsg.p->wMergeIndex = 0xFFFF; // �� special merge index so this won't get stepped on. is a big number OK? define a constant for this value?
pmsg.StampAndSend(m_scomGraph); hr = pmsg.hr(); if (SUCCEEDED(hr)) m_nTranspose = nTranspose; return hr; }
HRESULT CAutDirectMusicPerformance::GetMasterTranspose(AutDispatchDecodedParams *paddp) { LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn); if (plRet) *plRet = m_nTranspose; return S_OK; }
HRESULT CAutDirectMusicPerformance::_Trace(AutDispatchDecodedParams *paddp) { BSTR bstr = paddp->params[0].bstrVal; int cwch = wcslen(bstr);
SmartRef::PMsg<DMUS_LYRIC_PMSG> pmsg(m_pITarget, cwch * sizeof(WCHAR)); HRESULT hr = pmsg.hr(); if (FAILED(hr)) return hr;
// Generic PMSG stuff
hr = m_pITarget->GetTime(&pmsg.p->rtTime, NULL); if (FAILED(hr)) return hr; pmsg.p->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME; pmsg.p->dwType = DMUS_PMSGT_SCRIPTLYRIC; pmsg.p->dwPChannel = 0; pmsg.p->dwVirtualTrackID = 0; pmsg.p->dwGroupID = -1;
// Lyric PMSG stuff
wcscpy(pmsg.p->wszString, bstr);
pmsg.StampAndSend(m_scomGraph); return pmsg.hr(); }
HRESULT CAutDirectMusicPerformance::Rand(AutDispatchDecodedParams *paddp) { LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn); LONG lMax = paddp->params[0].lVal;
if (lMax < 1 || lMax > 0x7fff) return E_INVALIDARG;
// Use random number generation lifted from the standard library's rand.c. We don't just
// use the rand function because the multithreaded library has a per-thread random chain,
// but this function is called from various threads and it would be difficult to manage
// getting them seeded. Generates pseudo-random numbers 0 through 32767.
long lRand = ((m_lRand = m_lRand * 214013L + 2531011L) >> 16) & 0x7fff;
if (plRet) *plRet = lRand % lMax + 1; // trim to the requested range [1,lMax]
return S_OK; }
HRESULT CAutDirectMusicPerformance::GetMasterParam(const GUID &guid, void *pParam, DWORD dwSize) { HRESULT hr = m_pITarget->GetGlobalParam(guid, pParam, dwSize); if (SUCCEEDED(hr) || hr == E_INVALIDARG) // E_INVALIDARG is the performance's polite way of telling us the param hasn't been set yet
return S_OK; return hr; }
|