windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmscript/autperformance.cpp
2020-09-26 16:20:57 +08:00

323 lines
11 KiB
C++
Raw Blame History

// 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; // <20><> 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;
}