209 lines
6.8 KiB
C
209 lines
6.8 KiB
C
|
// Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
// DSLink.h
|
||
|
|
||
|
#ifndef __DS_LINK__
|
||
|
#define __DS_LINK__
|
||
|
|
||
|
#include <math.h>
|
||
|
#include <mmsystem.h>
|
||
|
#include <dsound.h>
|
||
|
#include "dmusicc.h"
|
||
|
#include "dmusics.h"
|
||
|
#include "cclock.h"
|
||
|
#include "PLClock.h"
|
||
|
#include "clist.h"
|
||
|
|
||
|
|
||
|
class CDSLink;
|
||
|
typedef HRESULT (CDSLink::*SINKPROPHANDLER)(ULONG ulId, BOOL fSet, LPVOID pvPropertyData, PULONG pcbPropertyData);
|
||
|
|
||
|
#define SINKPROP_F_STATIC 0x00000001
|
||
|
#define SINKPROP_F_FNHANDLER 0x00000002
|
||
|
|
||
|
#include <pshpack4.h>
|
||
|
// Struct for holding a property item supported by the sink
|
||
|
//
|
||
|
struct SINKPROPERTY
|
||
|
{
|
||
|
const GUID *pguidPropertySet; // What property set?
|
||
|
ULONG ulId; // What item?
|
||
|
|
||
|
ULONG ulSupported; // Get/Set flags for QuerySupported
|
||
|
|
||
|
ULONG ulFlags; // SINKPROP_F_xxx
|
||
|
|
||
|
LPVOID pPropertyData;
|
||
|
ULONG cbPropertyData; // and its size
|
||
|
|
||
|
SINKPROPHANDLER pfnHandler; // Handler fn if SINKPROP_F_FNHANDLER
|
||
|
};
|
||
|
#include <poppack.h>
|
||
|
|
||
|
class CDSLink : public CListItem, public IDirectMusicSynthSink, public IKsControl
|
||
|
{
|
||
|
friend class CClock;
|
||
|
friend class CDSLinkList;
|
||
|
public:
|
||
|
CDSLink * GetNext();
|
||
|
// IUnknown
|
||
|
//
|
||
|
virtual STDMETHODIMP QueryInterface(const IID &iid, void **ppv);
|
||
|
virtual STDMETHODIMP_(ULONG) AddRef();
|
||
|
virtual STDMETHODIMP_(ULONG) Release();
|
||
|
|
||
|
// IDirectMusicSynthSink
|
||
|
public:
|
||
|
virtual STDMETHODIMP Init(IDirectMusicSynth *pSynth);
|
||
|
virtual STDMETHODIMP SetMasterClock(IReferenceClock *pClock);
|
||
|
virtual STDMETHODIMP GetLatencyClock(IReferenceClock **ppClock);
|
||
|
virtual STDMETHODIMP Activate(BOOL fEnable);
|
||
|
virtual STDMETHODIMP SampleToRefTime(LONGLONG llSampleTime,REFERENCE_TIME *prfTime);
|
||
|
virtual STDMETHODIMP RefTimeToSample(REFERENCE_TIME rfTime, LONGLONG *pllSampleTime);
|
||
|
virtual STDMETHODIMP SetDirectSound(LPDIRECTSOUND pDirectSound, LPDIRECTSOUNDBUFFER pDirectSoundBuffer);
|
||
|
virtual STDMETHODIMP GetDesiredBufferSize(LPDWORD pdwBufferSizeInSamples);
|
||
|
|
||
|
// IKsPropertySet
|
||
|
virtual STDMETHODIMP KsProperty(
|
||
|
IN PKSPROPERTY Property,
|
||
|
IN ULONG PropertyLength,
|
||
|
IN OUT LPVOID PropertyData,
|
||
|
IN ULONG DataLength,
|
||
|
OUT PULONG BytesReturned
|
||
|
);
|
||
|
|
||
|
virtual STDMETHODIMP KsMethod(
|
||
|
IN PKSMETHOD Method,
|
||
|
IN ULONG MethodLength,
|
||
|
IN OUT LPVOID MethodData,
|
||
|
IN ULONG DataLength,
|
||
|
OUT PULONG BytesReturned
|
||
|
);
|
||
|
|
||
|
virtual STDMETHODIMP KsEvent(
|
||
|
IN PKSEVENT Event,
|
||
|
IN ULONG EventLength,
|
||
|
IN OUT LPVOID EventData,
|
||
|
IN ULONG DataLength,
|
||
|
OUT PULONG BytesReturned
|
||
|
);
|
||
|
|
||
|
CDSLink();
|
||
|
~CDSLink();
|
||
|
void Clear();
|
||
|
private:
|
||
|
IDirectMusicSynth * m_pSynth; // Reference to synth that uses this.
|
||
|
CClock m_Clock; // Latency clock.
|
||
|
IReferenceClock * m_pIMasterClock; // Master clock from app.
|
||
|
CSampleClock m_SampleClock; // Use to synchronize timing with master clock.
|
||
|
long m_cRef;
|
||
|
WAVEFORMATEX m_wfSynth; // Waveform requested by synth.
|
||
|
|
||
|
LPDIRECTSOUND m_pDSound;
|
||
|
LPDIRECTSOUNDBUFFER m_pPrimary; // Primary buffer.
|
||
|
LPDIRECTSOUNDBUFFER m_pBuffer; // Mix buffer.
|
||
|
LPDIRECTSOUNDBUFFER m_pExtBuffer; // Optional buffer from SetDirectSound.
|
||
|
CRITICAL_SECTION m_CriticalSection; // Critical section to manage access.
|
||
|
BOOL m_fCSInitialized; // Was CS initialized?
|
||
|
LONGLONG m_llAbsPlay; // Absolute point where play head is.
|
||
|
DWORD m_dwLastPlay; // Point in buffer where play head is.
|
||
|
LONGLONG m_llAbsWrite; // Absolute point we've written up to.
|
||
|
DWORD m_dwLastWrite; // Last position we wrote to in buffer.
|
||
|
DWORD m_dwBufferSize; // Size of buffer.
|
||
|
DWORD m_dwWriteTo; // Distance between write head and where we are writing.
|
||
|
DWORD m_dwWriteFromMax; // Max distance observed between play and write head.
|
||
|
BOOL m_fActive; // Currently active.
|
||
|
|
||
|
HRESULT Connect();
|
||
|
HRESULT Disconnect();
|
||
|
void SynthProc();
|
||
|
|
||
|
static SINKPROPERTY m_aProperty[];
|
||
|
static const int m_nProperty;
|
||
|
static SINKPROPERTY *FindPropertyItem(REFGUID rguid, ULONG ulId);
|
||
|
|
||
|
HRESULT HandleLatency(
|
||
|
ULONG ulId,
|
||
|
BOOL fSet,
|
||
|
LPVOID pbBuffer,
|
||
|
PULONG pcbBuffer);
|
||
|
|
||
|
// helpers
|
||
|
LONGLONG SampleToByte(LONGLONG llSamples) {return llSamples << m_wfSynth.nChannels;} // REVIEW: dwSamples * m_wfSynth.nBlockAlign
|
||
|
DWORD SampleToByte(DWORD dwSamples) {return dwSamples << m_wfSynth.nChannels;} // REVIEW: dwSamples * m_wfSynth.nBlockAlign
|
||
|
LONGLONG ByteToSample(LONGLONG llBytes) {return llBytes >> m_wfSynth.nChannels;} // REVIEW: dwBytes / m_wfSynth.nBlockAlign
|
||
|
DWORD ByteToSample(DWORD dwBytes) {return dwBytes >> m_wfSynth.nChannels;} // REVIEW: dwBytes / m_wfSynth.nBlockAlign
|
||
|
LONGLONG SampleAlign(LONGLONG llBytes) {return SampleToByte(ByteToSample(llBytes));}
|
||
|
DWORD SampleAlign(DWORD dwBytes) {return SampleToByte(ByteToSample(dwBytes));}
|
||
|
|
||
|
BOOL IsValidFormat(LPCWAVEFORMATEX pwf)
|
||
|
{
|
||
|
return (pwf &&
|
||
|
pwf->wFormatTag == WAVE_FORMAT_PCM &&
|
||
|
(pwf->nChannels == 1 || pwf->nChannels == 2) &&
|
||
|
(pwf->nSamplesPerSec == 44100 || pwf->nSamplesPerSec == 22050 || pwf->nSamplesPerSec == 11025) &&
|
||
|
pwf->wBitsPerSample == 16 &&
|
||
|
pwf->nBlockAlign == (pwf->nChannels * (pwf->wBitsPerSample / 8)) &&
|
||
|
pwf->nAvgBytesPerSec == (pwf->nSamplesPerSec * pwf->nBlockAlign));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
class CDSLinkList : public CList
|
||
|
{
|
||
|
public:
|
||
|
CDSLinkList();
|
||
|
BOOL OpenUp();
|
||
|
void CloseDown();
|
||
|
CDSLink * GetHead();
|
||
|
CDSLink * RemoveHead();
|
||
|
void Remove(CDSLink *pLink);
|
||
|
void AddTail(CDSLink *pLink);
|
||
|
CDSLink * GetItem(LONG index);
|
||
|
BOOL InitThread();
|
||
|
void ActivateLink(CDSLink *pLink);
|
||
|
void DeactivateLink(CDSLink *pLink);
|
||
|
void SynthProc();
|
||
|
|
||
|
BOOL m_fOpened;
|
||
|
CRITICAL_SECTION m_CriticalSection; // Critical section to manage access.
|
||
|
HANDLE m_hThread; // Handle for synth thread.
|
||
|
BOOL m_fPleaseDie; // Triggers exit.
|
||
|
DWORD m_dwThread; // ID for thread.
|
||
|
HANDLE m_hEvent; // Used to signal thread.
|
||
|
DWORD m_dwCount; // Number of sinks
|
||
|
DWORD m_dwResolution; // Synth thread timeout (ms)
|
||
|
};
|
||
|
|
||
|
// Class factory
|
||
|
//
|
||
|
// Common to emulation/WDM.
|
||
|
//
|
||
|
class CDirectMusicSynthSinkFactory : public IClassFactory
|
||
|
{
|
||
|
public:
|
||
|
// IUnknown
|
||
|
//
|
||
|
virtual STDMETHODIMP QueryInterface(const IID &iid, void **ppv);
|
||
|
virtual STDMETHODIMP_(ULONG) AddRef();
|
||
|
virtual STDMETHODIMP_(ULONG) Release();
|
||
|
|
||
|
// Interface IClassFactory
|
||
|
//
|
||
|
virtual STDMETHODIMP CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv);
|
||
|
virtual STDMETHODIMP LockServer(BOOL bLock);
|
||
|
|
||
|
// Constructor
|
||
|
//
|
||
|
CDirectMusicSynthSinkFactory();
|
||
|
|
||
|
// Destructor
|
||
|
~CDirectMusicSynthSinkFactory();
|
||
|
|
||
|
private:
|
||
|
long m_cRef;
|
||
|
};
|
||
|
|
||
|
|
||
|
#endif // __DS_LINK__
|
||
|
|