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

1317 lines
32 KiB
C++

//
// dmsport.cpp
//
// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
//
// CDirectMusicSynthPort implementation; code common to DX7 and DX8 style ports.
//
#include <objbase.h>
#include "debug.h"
#include <mmsystem.h>
#include "dmusicp.h"
#include "validate.h"
#include "debug.h"
#include "dmvoice.h"
#include "dmsport7.h"
#include "dmsport8.h"
const GUID guidZero = {0};
HRESULT CALLBACK FreeHandle(HANDLE hHandle, HANDLE hUserData);
////////////////////////////////////////////////////////////////////////////////
//
// CreateCDirectMusicSynthPort
//
// Determine which type of port (DX7 or DX8) is being created and which
// types the requested synth supports. Create the highest level of
// port possible.
//
HRESULT
CreateCDirectMusicSynthPort(
PORTENTRY *pe,
CDirectMusic *pDM,
UINT uVersion,
DMUS_PORTPARAMS *pPortParams,
IDirectMusicPort **ppPort)
{
HRESULT hr = S_OK;
// Determine what type of connection we can get. We can only
// do DX-8 if we've been asked for it and the synth supports
// it.
//
IDirectMusicSynth *pSynth = NULL;
IDirectMusicSynth8 *pSynth8 = NULL;
bool fAudioPathSet = false;
bool fAudioPath = false;
if (uVersion >= 8 && (pPortParams->dwValidParams & DMUS_PORTPARAMS_FEATURES))
{
fAudioPathSet = true;
fAudioPath = (pPortParams->dwFeatures & DMUS_PORT_FEATURE_AUDIOPATH) ? true : false;
}
if (!fAudioPath)
{
// Specifically requested old style interface.
//
uVersion = 7;
}
if (uVersion >= 8)
{
// Asked for DX-8 interfaces.
//
hr = CoCreateInstance(
pe->pc.guidPort,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectMusicSynth8,
(void**)&pSynth8);
// If creation failed for some legitimate reason, return.
// If E_NOINTERFACE then we can try to fall back on DX-7.
//
if (FAILED(hr) && hr != E_NOINTERFACE)
{
return hr;
}
}
if (uVersion < 8 || hr == E_NOINTERFACE)
{
// Asked for DX-7 interfaces or we couldn't get DX-8 interfaces.
//
hr = CoCreateInstance(
pe->pc.guidPort,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectMusicSynth,
(void**)&pSynth);
// If synth doesn't support that, we have nothing to fall back
// onto.
//
if (FAILED(hr))
{
return hr;
}
}
// Create and initialize the correct type of port.
//
if (pSynth)
{
assert(!pSynth8);
CDirectMusicSynthPort7 *pPort7 = new CDirectMusicSynthPort7(pe, pDM, pSynth);
if (pPort7 == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pPort7->Initialize(pPortParams);
}
if (SUCCEEDED(hr))
{
*ppPort = static_cast<IDirectMusicPort*>(pPort7);
(*ppPort)->AddRef();
}
RELEASE(pPort7);
RELEASE(pSynth);
if (SUCCEEDED(hr) && fAudioPath)
{
// They asked for an audio path but ended up without it
//
pPortParams->dwFeatures &= ~DMUS_PORT_FEATURE_AUDIOPATH;
hr = S_FALSE;
}
}
else if (pSynth8)
{
assert(!pSynth);
CDirectMusicSynthPort8 *pPort8 = new CDirectMusicSynthPort8(pe, pDM, pSynth8);
if (pPort8 == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pPort8->Initialize(pPortParams);
}
if (SUCCEEDED(hr))
{
*ppPort = static_cast<IDirectMusicPort*>(pPort8);
(*ppPort)->AddRef();
}
RELEASE(pPort8);
RELEASE(pSynth8);
}
else
{
assert(false);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::CDirectMusicSynthPort
//
CDirectMusicSynthPort::CDirectMusicSynthPort(
PORTENTRY *pPE,
CDirectMusic *pDM,
IDirectMusicSynth *pSynth)
{
m_cRef = 1;
m_pDM = pDM;
m_pSynth = pSynth;
m_dmpc = pPE->pc;
m_pNotify = NULL;
m_pSynthPropSet = NULL;
m_pSinkPropSet = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::~CDirectMusicSynthPort
//
CDirectMusicSynthPort::~CDirectMusicSynthPort()
{
Close();
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::QueryInterface
//
STDMETHODIMP
CDirectMusicSynthPort::QueryInterface(const IID &iid,
void **ppv)
{
V_INAME(IDirectMusicPort::QueryInterface);
V_REFGUID(iid);
V_PTRPTR_WRITE(ppv);
if (iid == IID_IUnknown || iid == IID_IDirectMusicPort)
{
*ppv = static_cast<IDirectMusicPort*>(this);
}
else if (iid == IID_IDirectMusicPortP)
{
*ppv = static_cast<IDirectMusicPortP*>(this);
}
else if (iid == IID_IDirectMusicPortDownload)
{
*ppv = static_cast<IDirectMusicPortDownload*>(this);
}
else if (iid == IID_IDirectMusicPortPrivate)
{
*ppv = static_cast<IDirectMusicPortPrivate*>(this);
}
else if (iid == IID_IKsControl)
{
*ppv = static_cast<IKsControl*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::AddRef
//
STDMETHODIMP_(ULONG)
CDirectMusicSynthPort::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Release
//
STDMETHODIMP_(ULONG)
CDirectMusicSynthPort::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
delete this;
return 0;
}
return m_cRef;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Initialize
//
// Initialization common to all versions
//
HRESULT
CDirectMusicSynthPort::Initialize(
DMUS_PORTPARAMS *pPortParams)
{
HRESULT hr;
// Get our notification interface
//
hr = m_pDM->QueryInterface(IID_IDirectMusicPortNotify, (void**)&m_pNotify);
if (SUCCEEDED(hr))
{
// HACK HACK: Don't hold a refcount against DirectMusic
//
m_pNotify->Release();
}
else
{
TraceI(1, "Failed to get IDirectMusicPortNotify\n");
}
// Save off property set handler
//
if (SUCCEEDED(hr))
{
hr = m_pSynth->QueryInterface(
IID_IKsControl,
(void**)&m_pSynthPropSet);
if (FAILED(hr))
{
TraceI(1, "NOTE: Synth has no property set\n");
// This is a warning, not an error
//
hr = S_OK;
}
}
// Cache number of channel groups
//
if (SUCCEEDED(hr))
{
if (pPortParams->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS)
{
m_dwChannelGroups = pPortParams->dwChannelGroups;
}
else
{
m_dwChannelGroups = 1;
}
if (pPortParams->dwValidParams & DMUS_PORTPARAMS_FEATURES)
{
m_dwFeatures = pPortParams->dwFeatures;
}
else
{
m_dwFeatures = 0;
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Close
//
STDMETHODIMP CDirectMusicSynthPort::Close()
{
if (m_pNotify)
{
m_pNotify->NotifyFinalRelease(static_cast<IDirectMusicPort*>(this));
m_pNotify = NULL;
}
RELEASE(m_pSynthPropSet);
RELEASE(m_pSinkPropSet);
m_pDM = NULL;
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::InitChannelPriorities
//
//
static DWORD adwChannelPriorities[16] =
{
DAUD_CHAN1_DEF_VOICE_PRIORITY,
DAUD_CHAN2_DEF_VOICE_PRIORITY,
DAUD_CHAN3_DEF_VOICE_PRIORITY,
DAUD_CHAN4_DEF_VOICE_PRIORITY,
DAUD_CHAN5_DEF_VOICE_PRIORITY,
DAUD_CHAN6_DEF_VOICE_PRIORITY,
DAUD_CHAN7_DEF_VOICE_PRIORITY,
DAUD_CHAN8_DEF_VOICE_PRIORITY,
DAUD_CHAN9_DEF_VOICE_PRIORITY,
DAUD_CHAN10_DEF_VOICE_PRIORITY,
DAUD_CHAN11_DEF_VOICE_PRIORITY,
DAUD_CHAN12_DEF_VOICE_PRIORITY,
DAUD_CHAN13_DEF_VOICE_PRIORITY,
DAUD_CHAN14_DEF_VOICE_PRIORITY,
DAUD_CHAN15_DEF_VOICE_PRIORITY,
DAUD_CHAN16_DEF_VOICE_PRIORITY
};
void CDirectMusicSynthPort::InitChannelPriorities(
UINT uLowCG,
UINT uHighCG)
{
while (uLowCG <= uHighCG)
{
for (UINT uChannel = 0; uChannel < 16; uChannel++)
{
m_pSynth->SetChannelPriority(uLowCG, uChannel, adwChannelPriorities[uChannel]);
}
uLowCG++;
}
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::SetSinkKsControl
//
//
void CDirectMusicSynthPort::SetSinkKsControl(
IKsControl *pSinkKsControl)
{
RELEASE(m_pSinkPropSet);
m_pSinkPropSet = pSinkKsControl;
if (m_pSinkPropSet)
{
m_pSinkPropSet->AddRef();
}
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::InitializeVolumeBoost
//
//
void CDirectMusicSynthPort::InitializeVolumeBoost()
{
HRESULT hr;
if (m_pSynthPropSet)
{
// set volume boost
//
KSPROPERTY ksp;
ULONG cb;
ULONG lVolume = 0; // zero boost by default
ZeroMemory(&ksp, sizeof(ksp));
ksp.Set = KSPROPSETID_Synth;
ksp.Id = KSPROPERTY_SYNTH_VOLUMEBOOST;
ksp.Flags = KSPROPERTY_TYPE_SET;
hr = m_pSynthPropSet->KsProperty(&ksp,
sizeof(ksp),
(LPVOID)&lVolume,
sizeof(lVolume),
&cb);
if (FAILED(hr))
{
TraceI(2, "NOTE: Set volume boost failed %08X\n", hr);
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Compact
//
STDMETHODIMP CDirectMusicSynthPort::Compact()
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetCaps
//
STDMETHODIMP CDirectMusicSynthPort::GetCaps(
LPDMUS_PORTCAPS pPortCaps)
{
V_INAME(IDirectMusicPort::GetCaps);
V_STRUCTPTR_WRITE(pPortCaps, DMUS_PORTCAPS);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
CopyMemory(pPortCaps, &m_dmpc, sizeof(DMUS_PORTCAPS));
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::DeviceIoControl
//
STDMETHODIMP CDirectMusicSynthPort::DeviceIoControl(
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::SetNumChannelGroups
//
STDMETHODIMP CDirectMusicSynthPort::SetNumChannelGroups(
DWORD dwChannelGroups)
{
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
HRESULT hr = m_pSynth->SetNumChannelGroups(dwChannelGroups);
if (FAILED(hr))
{
return hr;
}
if (dwChannelGroups > m_dwChannelGroups)
{
InitChannelPriorities(m_dwChannelGroups + 1, dwChannelGroups);
}
m_dwChannelGroups = dwChannelGroups;
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetNumChannelGroups
//
STDMETHODIMP CDirectMusicSynthPort::GetNumChannelGroups(
LPDWORD pdwChannelGroups)
{
V_INAME(IDirectMusicPort::GetNumChannelGroups);
V_PTR_WRITE(pdwChannelGroups, DWORD);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
*pdwChannelGroups = m_dwChannelGroups;
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::PlayBuffer
//
STDMETHODIMP CDirectMusicSynthPort::PlayBuffer(
IDirectMusicBuffer *pIBuffer)
{
HRESULT hr;
REFERENCE_TIME rt;
DWORD cb;
LPBYTE lpb;
V_INAME(IDirectMusicPort::PlayBuffer);
V_INTERFACE(pIBuffer);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
hr = pIBuffer->GetStartTime(&rt);
if (!SUCCEEDED(hr))
{
return hr;
}
hr = pIBuffer->GetUsedBytes(&cb);
if (!SUCCEEDED(hr))
{
return hr;
}
hr = pIBuffer->GetRawBufferPtr(&lpb);
if (!SUCCEEDED(hr))
{
return hr;
}
return m_pSynth->PlayBuffer(rt, lpb, cb);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::SetEventNotification
//
STDMETHODIMP CDirectMusicSynthPort::SetReadNotificationHandle(
HANDLE hEvent)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Read
//
STDMETHODIMP CDirectMusicSynthPort::Read(
IDirectMusicBuffer *pIBuffer)
{
V_INAME(IDirectMusicPort::Read);
V_INTERFACE(pIBuffer);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::DownloadInstrument
//
STDMETHODIMP CDirectMusicSynthPort::DownloadInstrument(
IDirectMusicInstrument* pInstrument,
IDirectMusicDownloadedInstrument** ppDownloadedInstrument,
DMUS_NOTERANGE* pNoteRanges,
DWORD dwNumNoteRanges)
{
V_INAME(IDirectMusicPort::DownloadInstrument);
V_INTERFACE(pInstrument);
V_PTRPTR_WRITE(ppDownloadedInstrument);
V_BUFPTR_READ(pNoteRanges, (dwNumNoteRanges * sizeof(DMUS_NOTERANGE)));
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return CDirectMusicPortDownload::DownloadP(pInstrument,
ppDownloadedInstrument,
pNoteRanges,
dwNumNoteRanges,
TRUE);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::UnloadInstrument
//
STDMETHODIMP CDirectMusicSynthPort::UnloadInstrument(
IDirectMusicDownloadedInstrument* pDownloadedInstrument)
{
V_INAME(IDirectMusicPort::UnloadInstrument);
V_INTERFACE(pDownloadedInstrument);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return CDirectMusicPortDownload::UnloadP(pDownloadedInstrument);
}
//////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Download
//
STDMETHODIMP CDirectMusicSynthPort::Download(
IDirectMusicDownload* pIDMDownload)
{
V_INAME(IDirectMusicPort::Download);
V_INTERFACE(pIDMDownload);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
EnterCriticalSection(&m_DMDLCriticalSection);
// If you can QI pIDMDownload for private interface IDirectMusicDownloadPrivate
// pIDMDownload is of type CDownloadBuffer.
IDirectMusicDownloadPrivate* pDMDLP = NULL;
HRESULT hr = pIDMDownload->QueryInterface(IID_IDirectMusicDownloadPrivate, (void **)&pDMDLP);
if(SUCCEEDED(hr))
{
pDMDLP->Release();
hr = ((CDownloadBuffer *)pIDMDownload)->IsDownloaded();
if(hr != S_FALSE)
{
LeaveCriticalSection(&m_DMDLCriticalSection);
return DMUS_E_ALREADY_DOWNLOADED;
}
void* pvBuffer = NULL;
hr = ((CDownloadBuffer *)pIDMDownload)->GetBuffer(&pvBuffer);
if(pvBuffer == NULL)
{
hr = DMUS_E_BUFFERNOTSET;
}
if (SUCCEEDED(hr) && !(m_dwFeatures & DMUS_PORT_FEATURE_STREAMING))
{
DMUS_DOWNLOADINFO *pdl = (DMUS_DOWNLOADINFO*)pvBuffer;
if (pdl->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE)
{
// That feature is disabled, pretend we don't understand
//
hr = DMUS_E_UNKNOWNDOWNLOAD;
}
}
BOOL bFree = false;
if(SUCCEEDED(hr))
{
hr = m_pSynth->Download(&(((CDownloadBuffer *)pIDMDownload)->m_DLHandle),
pvBuffer,
&bFree);
if(SUCCEEDED(hr))
{
// AddRef() before we add it to the list.
pIDMDownload->AddRef();
DWORD dwID = ((DMUS_DOWNLOADINFO*)pvBuffer)->dwDLId;
((CDownloadBuffer *)pIDMDownload)->m_dwDLId = dwID;
m_DLBufferList[dwID % DLB_HASH_SIZE].AddHead((CDownloadBuffer*)pIDMDownload);
((CDownloadBuffer*)pIDMDownload)->IncDownloadCount();
if(bFree)
{
pvBuffer = NULL;
DWORD dw;
((CDownloadBuffer *)pIDMDownload)->GetHeader(&pvBuffer, &dw);
((CDownloadBuffer *)pIDMDownload)->SetBuffer(NULL, 0, 0);
delete [] pvBuffer;
}
else
{
// If we do not free buffer we need to AddRef()
// We do not want buffer to go away until the IDirectMusicPort is
// finished with it.
pIDMDownload->AddRef();
}
}
else if(FAILED(hr))
{
((CDownloadBuffer *)pIDMDownload)->m_DLHandle = NULL;
}
}
}
LeaveCriticalSection(&m_DMDLCriticalSection);
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Unload
//
STDMETHODIMP CDirectMusicSynthPort::Unload(
IDirectMusicDownload* pIDMDownload)
{
V_INAME(IDirectMusicPort::Unload);
V_INTERFACE(pIDMDownload);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
EnterCriticalSection(&m_DMDLCriticalSection);
// If you can QI pIDMDownload for private interface IDirectMusicDownloadPrivate
// pIDMDownload is of type CDownloadBuffer.
IDirectMusicDownloadPrivate* pDMDLP = NULL;
HRESULT hr = pIDMDownload->QueryInterface(IID_IDirectMusicDownloadPrivate, (void **)&pDMDLP);
if(SUCCEEDED(hr))
{
pDMDLP->Release();
if (((CDownloadBuffer *)pIDMDownload)->IsDownloaded() == S_OK)
{
if(((CDownloadBuffer *)pIDMDownload)->DecDownloadCount() == 0)
{
m_DLBufferList[((CDownloadBuffer *)pIDMDownload)->m_dwDLId % DLB_HASH_SIZE].Remove(
(CDownloadBuffer *)pIDMDownload);
pIDMDownload->Release();
hr = m_pSynth->Unload(((CDownloadBuffer *)pIDMDownload)->m_DLHandle, FreeHandle, (HANDLE)pIDMDownload);
}
}
else
{
TraceI(0, "CDirectMusicSynthPort::Unload- not downloaded\n");
}
}
LeaveCriticalSection(&m_DMDLCriticalSection);
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetAppend
//
STDMETHODIMP CDirectMusicSynthPort::GetAppend(
DWORD* pdwAppend)
{
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
V_INAME(IDirectMusicPort::GetAppend);
V_PTR_WRITE(pdwAppend, DWORD);
return m_pSynth->GetAppend(pdwAppend);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetLatencyClock
//
STDMETHODIMP CDirectMusicSynthPort::GetLatencyClock(
IReferenceClock **ppClock)
{
V_INAME(IDirectMusicPort::GetLatencyClock);
V_PTRPTR_WRITE(ppClock);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return m_pSynth->GetLatencyClock(ppClock);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetRunningStats
//
STDMETHODIMP CDirectMusicSynthPort::GetRunningStats(
LPDMUS_SYNTHSTATS pStats)
{
V_INAME(IDirectMusicPort::GetRunningStats);
V_STRUCTPTR_WRITE(pStats, DMUS_SYNTHSTATS);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return m_pSynth->GetRunningStats(pStats);
}
#if 0
// XXX Different
#endif
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicPort::SetChannelPriority
//
STDMETHODIMP CDirectMusicSynthPort::SetChannelPriority(
DWORD dwChannelGroup,
DWORD dwChannel,
DWORD dwPriority)
{
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return m_pSynth->SetChannelPriority(dwChannelGroup, dwChannel, dwPriority);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicPort::GetChannelPriority
//
STDMETHODIMP CDirectMusicSynthPort::GetChannelPriority(
DWORD dwChannelGroup,
DWORD dwChannel,
LPDWORD pdwPriority)
{
V_INAME(IDirectMusicPort::GetChannelPriority);
V_PTR_WRITE(pdwPriority, DWORD);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
return m_pSynth->GetChannelPriority(dwChannelGroup, dwChannel, pdwPriority);
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicPort::SetDirectSound
//
// XXX What does this mean in terms of DX8?
// XXX This can probably become pure virtual
//
STDMETHODIMP
CDirectMusicSynthPort::SetDirectSound(
LPDIRECTSOUND pDirectSound,
LPDIRECTSOUNDBUFFER pDirectSoundBuffer)
{
V_INAME(IDirectMusicPort::SetDirectSound);
V_INTERFACE_OPT(pDirectSound);
V_INTERFACE_OPT(pDirectSoundBuffer);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetFormat
//
// XXX What does pcbBuffer mean in terms of DX8?
// XXX This can probably become pure virtual
//
STDMETHODIMP CDirectMusicSynthPort::GetFormat(
LPWAVEFORMATEX pwfex,
LPDWORD pdwwfex,
LPDWORD pcbBuffer)
{
V_INAME(IDirectMusicPort::GetFormat);
V_PTR_WRITE(pdwwfex, DWORD);
V_BUFPTR_WRITE_OPT(pwfex, *pdwwfex);
V_PTR_WRITE_OPT(pcbBuffer, DWORD);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::DownloadWave
//
STDMETHODIMP CDirectMusicSynthPort::DownloadWave(
IDirectSoundWave *pWave,
IDirectSoundDownloadedWaveP **ppWave,
REFERENCE_TIME rtStartHint)
{
V_INAME(IDirectMusicPort::DownloadWave);
V_INTERFACE(pWave);
V_PTRPTR_WRITE(ppWave);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::UnloadWave
//
STDMETHODIMP CDirectMusicSynthPort::UnloadWave(
IDirectSoundDownloadedWaveP *pDownloadedWave)
{
V_INAME(IDirectMusicPort::UnloadWave);
V_INTERFACE(pDownloadedWave);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::AllocVoice
//
STDMETHODIMP
CDirectMusicSynthPort::AllocVoice(
IDirectSoundDownloadedWaveP *pWave,
DWORD dwChannel,
DWORD dwChannelGroup,
REFERENCE_TIME rtStart,
SAMPLE_TIME stLoopStart,
SAMPLE_TIME stLoopEnd,
IDirectMusicVoiceP **ppVoice)
{
V_INAME(IDirectMusicPort::AllocVoice);
V_INTERFACE(pWave);
V_PTRPTR_WRITE(ppVoice);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::AssignChannelToBuses
//
STDMETHODIMP
CDirectMusicSynthPort::AssignChannelToBuses(
DWORD dwChannelGroup,
DWORD dwChannel,
LPDWORD pdwBuses,
DWORD cBusCount)
{
V_INAME(IDirectMusicPort::AssignChannelToBuses);
V_BUFPTR_WRITE(pdwBuses, sizeof(DWORD) * cBusCount);
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::StartVoice
//
STDMETHODIMP CDirectMusicSynthPort::StartVoice(
DWORD dwVoiceId,
DWORD dwChannel,
DWORD dwChannelGroup,
REFERENCE_TIME rtStart,
DWORD dwDLId,
LONG prPitch,
LONG vrVolume,
SAMPLE_TIME stVoiceStart,
SAMPLE_TIME stLoopStart,
SAMPLE_TIME stLoopEnd)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::StopVoice
//
STDMETHODIMP CDirectMusicSynthPort::StopVoice(
DWORD dwVoiceId,
REFERENCE_TIME rtStop)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetVoiceState
//
STDMETHODIMP CDirectMusicSynthPort::GetVoiceState(
DWORD dwVoice[],
DWORD cbVoice,
DMUS_VOICE_STATE VoiceState[])
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::Refresh
//
STDMETHODIMP CDirectMusicSynthPort::Refresh(
DWORD dwDownloadId,
DWORD dwFlags)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::SetSink
//
STDMETHODIMP CDirectMusicSynthPort::SetSink(
IDirectSoundConnect *pSinkConnect)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetSink
//
STDMETHODIMP CDirectMusicSynthPort::GetSink(
IDirectSoundConnect **ppSinkConnect)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::KsProperty
//
STDMETHODIMP CDirectMusicSynthPort::KsProperty(
IN PKSPROPERTY pProperty,
IN ULONG ulPropertyLength,
IN OUT LPVOID pvPropertyData,
IN ULONG ulDataLength,
OUT PULONG pulBytesReturned)
{
LONG lVolume;
V_INAME(DirectMusicSynthPort::IKsContol::KsProperty);
V_BUFPTR_WRITE(pProperty, ulPropertyLength);
// pvPropertyData is not optional on a SET operation
//
if (pProperty->Flags & KSPROPERTY_TYPE_SET)
{
V_BUFPTR_WRITE(pvPropertyData, ulDataLength);
}
else
{
V_BUFPTR_WRITE_OPT(pvPropertyData, ulDataLength);
}
V_PTR_WRITE(pulBytesReturned, ULONG);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
HRESULT hr = DMUS_E_UNKNOWN_PROPERTY;
// Don't let callers touch property sets we use
//
if (pProperty->Set == KSPROPSETID_Synth)
{
if (pProperty->Id != KSPROPERTY_SYNTH_VOLUME)
{
return DMUS_E_UNKNOWN_PROPERTY;
}
else if (ulDataLength != sizeof(LONG))
{
return E_INVALIDARG;
}
else if (pProperty->Flags & KSPROPERTY_TYPE_SET)
{
lVolume = *(LONG*)pvPropertyData;
// Clamp to -200..+20 db
//
if (lVolume < -20000)
{
lVolume = -20000;
pvPropertyData = &lVolume;
}
else if (lVolume > 2000)
{
lVolume = 2000;
pvPropertyData = &lVolume;
}
}
}
else if (pProperty->Set == KSPROPSETID_Synth_Dls)
{
return DMUS_E_UNKNOWN_PROPERTY;
}
if (m_pSynthPropSet)
{
hr = m_pSynthPropSet->KsProperty(pProperty,
ulPropertyLength,
pvPropertyData,
ulDataLength,
pulBytesReturned);
}
if (hr == DMUS_E_UNKNOWN_PROPERTY && m_pSinkPropSet)
{
hr = m_pSinkPropSet->KsProperty(pProperty,
ulPropertyLength,
pvPropertyData,
ulDataLength,
pulBytesReturned);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::KsMethod
//
STDMETHODIMP CDirectMusicSynthPort::KsMethod(
IN PKSMETHOD pMethod,
IN ULONG ulMethodLength,
IN OUT LPVOID pvMethodData,
IN ULONG ulDataLength,
OUT PULONG pulBytesReturned)
{
V_INAME(DirectMusicSynthPort::IKsContol::KsMethod);
V_BUFPTR_WRITE(pMethod, ulMethodLength);
V_BUFPTR_WRITE_OPT(pvMethodData, ulDataLength);
V_PTR_WRITE(pulBytesReturned, ULONG);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
// If they don't support it, then it's unknown
//
HRESULT hr = DMUS_E_UNKNOWN_PROPERTY;
if (m_pSynthPropSet)
{
hr = m_pSynthPropSet->KsMethod(pMethod,
ulMethodLength,
pvMethodData,
ulDataLength,
pulBytesReturned);
}
if (hr == DMUS_E_UNKNOWN_PROPERTY && m_pSinkPropSet)
{
hr = m_pSinkPropSet->KsMethod(pMethod,
ulMethodLength,
pvMethodData,
ulDataLength,
pulBytesReturned);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::KsEvent
//
STDMETHODIMP CDirectMusicSynthPort::KsEvent(
IN PKSEVENT pEvent,
IN ULONG ulEventLength,
IN OUT LPVOID pvEventData,
IN ULONG ulDataLength,
OUT PULONG pulBytesReturned)
{
V_INAME(DirectMusicSynthPort::IKsContol::KsEvent);
V_BUFPTR_WRITE(pEvent, ulEventLength);
V_BUFPTR_WRITE_OPT(pvEventData, ulDataLength);
V_PTR_WRITE(pulBytesReturned, ULONG);
if (!m_pDM)
{
return DMUS_E_DMUSIC_RELEASED;
}
HRESULT hr = DMUS_E_UNKNOWN_PROPERTY;
if (m_pSynthPropSet)
{
hr = m_pSynthPropSet->KsEvent(pEvent,
ulEventLength,
pvEventData,
ulDataLength,
pulBytesReturned);
}
if (hr == DMUS_E_UNKNOWN_PROPERTY && m_pSinkPropSet)
{
hr = m_pSinkPropSet->KsEvent(pEvent,
ulEventLength,
pvEventData,
ulDataLength,
pulBytesReturned);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// FreeHandle - Callback function used by Synth
//
HRESULT CALLBACK FreeHandle(HANDLE hHandle, HANDLE hUserData)
{
DWORD dw;
void* pvBuffer = NULL;
HRESULT hr = ((CDownloadBuffer *)hUserData)->GetHeader(&pvBuffer, &dw);
if(SUCCEEDED(hr))
{
hr = ((CDownloadBuffer *)hUserData)->SetBuffer(NULL, 0, 0);
delete [] pvBuffer;
}
((CDownloadBuffer *)hUserData)->Release();
return hr;
}
#if 0
////////////////////////////////////////////////////////////////////////////////
//
// CDirectMusicSynthPort::GetCachedFormat
//
HRESULT CDirectMusicSynthPort::GetCachedFormat(LPWAVEFORMATEX *ppwfex)
{
HRESULT hr;
if (m_pwfex == NULL)
{
DWORD cbWaveFormat;
hr = m_pSynth->GetFormat(NULL, &cbWaveFormat);
if (FAILED(hr))
{
TraceI(0, "DownloadWave: Synth failed GetFormat size query %08X\n", hr);
return hr;
}
m_pwfex = (LPWAVEFORMATEX)(new BYTE[cbWaveFormat]);
if (m_pwfex == NULL)
{
return E_OUTOFMEMORY;
}
hr = m_pSynth->GetFormat(m_pwfex, &cbWaveFormat);
if (FAILED(hr))
{
delete[] m_pwfex;
m_pwfex = NULL;
TraceI(0, "DownloadWave: Synth failed GetFormat %08X\n", hr);
return hr;
}
}
*ppwfex = m_pwfex;
return S_OK;
}
#endif