mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3702 lines
104 KiB
3702 lines
104 KiB
//--------------------------------------------------------------------------;
|
|
//
|
|
// File: DsBuffHW.c
|
|
//
|
|
// Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Abstract:
|
|
//
|
|
//
|
|
// Contents:
|
|
// IDSHWBufferQueryInterface()
|
|
// IDSHWBufferAddRef()
|
|
// IDSHWBufferRelease()
|
|
// IDSHWBufferGetCaps()
|
|
// IDSHWBufferGetCurrentPosition()
|
|
// IDSHWBufferGetFormat()
|
|
// IDSHWBufferGetVolume()
|
|
// IDSHWBufferGetPan()
|
|
// IDSHWBufferGetFrequency()
|
|
// IDSHWBufferGetStatus()
|
|
// IDSHWBufferInitialize()
|
|
// IDSHWBufferLock()
|
|
// IDSHWBufferPlay()
|
|
// IDSHWBufferSetCurrentPosition()
|
|
// IDSHWBufferSetFormat()
|
|
// IDSHWBufferSetVolume()
|
|
// IDSHWBufferSetPan()
|
|
// IDSHWBufferSetFrequency()
|
|
// IDSHWBufferStop()
|
|
// IDSHWBufferRestore()
|
|
// IDSHWBufferUnlock()
|
|
// IDSHWBufferWaveBlt()
|
|
// DSBufferCreateTable()
|
|
// DSBufferActivate()
|
|
// DSBufferDeactivate()
|
|
//
|
|
// History:
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
#include "dsoundpr.h"
|
|
#include "grace.h"
|
|
|
|
__inline BOOL CircularBufferRegionsIntersect
|
|
(
|
|
int cbBuffer,
|
|
int iStart1,
|
|
int iLen1,
|
|
int iStart2,
|
|
int iLen2
|
|
)
|
|
{
|
|
int iEnd1;
|
|
int iEnd2;
|
|
|
|
ASSERT(iStart1 >= 0);
|
|
ASSERT(iStart2 >= 0);
|
|
ASSERT(iStart1 + iLen1 >= 0);
|
|
ASSERT(iStart2 + iLen2 >= 0);
|
|
|
|
iEnd1 = iStart1 + iLen1;
|
|
iEnd2 = iStart2 + iLen2;
|
|
|
|
if ((0 == iLen1) || (0 == iLen2)) return FALSE;
|
|
if (iStart1 == iStart2) return TRUE;
|
|
|
|
// Handle r1 does not wrap
|
|
if ((iStart1 < iStart2) && (iEnd1 > iStart2)) return TRUE;
|
|
|
|
// Handle r2 does not wrap
|
|
if ((iStart2 < iStart1) && (iEnd2 > iStart1)) return TRUE;
|
|
|
|
// Handle r1 wraps
|
|
if (iEnd1 >= cbBuffer) {
|
|
iEnd1 -= cbBuffer;
|
|
ASSERT(iEnd1 < cbBuffer);
|
|
if (iEnd1 > iStart2) return TRUE;
|
|
}
|
|
|
|
// Handle r2 wraps
|
|
if (iEnd2 >= cbBuffer) {
|
|
iEnd2 -= cbBuffer;
|
|
ASSERT(iEnd2 < cbBuffer);
|
|
if (iEnd2 > iStart1) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferQueryInterface
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
REFIID riid,
|
|
LPVOID FAR* ppvObj
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(4,"Entering Buffer Query Interface method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::QueryInterface - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::QueryInterface - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
|
|
if( riid == NULL ) {
|
|
RPF("IDirectSoundBuffer::QueryInterface - NULL riid");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if( ppvObj == NULL ) {
|
|
RPF("IDirectSoundBuffer::QueryInterface - NULL ppvObj");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
if( pdsbe->dwPID == DWBUFFER_INTERNAL_PID ) {
|
|
DPF(0,"Query Internface on INTERNAL external obj");
|
|
DPF(0,"**************ERROR****************");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if( IsEqualGUID(riid,&IID_IDirectSoundBuffer) ||
|
|
IsEqualGUID(riid,&IID_IUnknown) ) {
|
|
*ppvObj = pdsbe;
|
|
|
|
pidsb->lpVtbl->AddRef( pidsb );
|
|
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} else {
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_NOINTERFACE;
|
|
}
|
|
|
|
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
} // IDSHWBufferQueryInterface()
|
|
|
|
|
|
ULONG FAR PASCAL IDSHWBufferAddRef
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(4,"Entering Buffer add ref method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::AddRef - Invalid Object or ref count");
|
|
return 0;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::AddRef - Invalid Object or ref count");
|
|
return 0;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( pdsbe->dwPID == DWBUFFER_INTERNAL_PID ) {
|
|
DPF(0,"AddRef on INTERNAL external obj");
|
|
DPF(0,"**************ERROR****************");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
|
|
pdsb->uRefCount++;
|
|
pdsbe->uRefCount++;
|
|
|
|
if( DSBIncAccess( pdsb ) != DS_OK ) {
|
|
DPF(0,"Increment access error");
|
|
LEAVE_DLL_CSECT();
|
|
return 0;
|
|
}
|
|
|
|
|
|
DPF(4,"Exiting buffer add ref method");
|
|
LEAVE_DLL_CSECT();
|
|
return (pdsbe->uRefCount);
|
|
} // IDSHWBufferAddRef()
|
|
|
|
|
|
ULONG FAR PASCAL IDSHWBufferRelease
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSOUNDEXTERNAL pdse;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LPDSBUFFEREXTERNAL pdsbe1;
|
|
LPDSBUFFER pdsb1,pdsbPrimary;
|
|
|
|
DPF(3,"Entering Buffer release method %X", pidsb);
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Release - Invalid Object or ref count");
|
|
return 0;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Release - Invalid Object or ref count");
|
|
return 0;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( pdsbe->dwPID == DWBUFFER_INTERNAL_PID ) {
|
|
DPF(0,"Release on INTERNAL external obj");
|
|
DPF(0,"************RELASE PRIMARY PROBLEM*********");
|
|
return 0;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
|
|
if( pdsbe->dwPID == DWPRIMARY_INTERNAL_PID ) {
|
|
// FORCE A RELEASE our common DS object is going away
|
|
DPF(0,"Release on PRIMARY INTERNAL external obj ");
|
|
if( pdsbe->uRefCount != 1 ) {
|
|
DPF(0,"************RELASE PRIMARY PROBLEM*********");
|
|
}
|
|
}
|
|
|
|
|
|
DPF(0," BUFFER RELEASE ext %X core %X, PID %X",
|
|
pdsbe, pdsbe->pdsb, pdsbe->dwPID );
|
|
|
|
|
|
|
|
|
|
// If this is last ref make sure it is stopped....
|
|
if(pdsb->uRefCount == 1) {
|
|
IDsbStopI( pdsb, FALSE );
|
|
}
|
|
|
|
pdsb->uRefCount--;
|
|
pdsbe->uRefCount--;
|
|
|
|
if( (pdsbe->uRefCount == 0) &&
|
|
(pdsbe->dwPID == DWPRIMARY_INTERNAL_PID) ) {
|
|
// This will have process ID different from task
|
|
DPF(0," RELEASE ORIGINAL PRIMARY " );
|
|
MemFree( pdsb->plProcess );
|
|
pdsb->plProcess = NULL;
|
|
} else {
|
|
if( DSBDecAccess( pdsb ) != DS_OK ) {
|
|
DPF(0,"Decrement access error");
|
|
LEAVE_DLL_CSECT();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// If this is the freeing of the last access this process had
|
|
// on this object, then free any locks that this process may have had
|
|
// and release exclusive access as well
|
|
if( DSBAccessCount( pdsb ) == 0 ) {
|
|
// This process is not longer accessing this DS obj
|
|
|
|
// Now release any buffers this process may have accessed.
|
|
// Release all buffers for this process for this object
|
|
FreeLocksOnBufferForProcess( pdsb );
|
|
} else {
|
|
if( pdsbe->uRefCount == 0 ) {
|
|
DPF(0,"******** external ref count 0 but access > 0" );
|
|
}
|
|
}
|
|
|
|
|
|
if( pdsbe->uRefCount > 0) {
|
|
// This object is still refrenced
|
|
DPF(3," Object still accessed %X", pdsbe->uRefCount );
|
|
LEAVE_DLL_CSECT();
|
|
return (pdsbe->uRefCount);
|
|
}
|
|
|
|
// Kill off the external object
|
|
|
|
|
|
DPF(2,"Destroying DirectSoundBuffer External object");
|
|
|
|
pdse = pdsbe->pdse;
|
|
|
|
// Remove it from list
|
|
if( pdse ) {
|
|
// pdse will be null for Primary created by DS obj creation
|
|
if(pdse->pdsbe == pdsbe)
|
|
{
|
|
pdse->pdsbe = pdsbe->pNext;
|
|
} else {
|
|
for(pdsbe1 = pdse->pdsbe; pdsbe1 != NULL; pdsbe1 = pdsbe1->pNext)
|
|
{
|
|
if(pdsbe1->pNext == pdsbe) {
|
|
pdsbe1->pNext = pdsbe->pNext;
|
|
pdsbe->pNext = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// For non-waveemulated primary buffers free the alias pointer
|
|
// to the data buffer.
|
|
if (pdsbe->pDSBufferAlias) {
|
|
ASSERT((DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) &&
|
|
!(DS_INTERNALF_WAVEEMULATED & pds->fdwInternal));
|
|
vxdMemFreeAlias(pdsbe->pDSBufferAlias, pdsb->cbBufferSize);
|
|
} else {
|
|
ASSERT(!(DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) ||
|
|
(DS_INTERNALF_WAVEEMULATED & pds->fdwInternal));
|
|
}
|
|
|
|
MemFree( pdsbe );
|
|
|
|
if(pdsb->uRefCount) {
|
|
// If object is still accessed
|
|
DPF(2,"External Object Destroyed, core remains");
|
|
LEAVE_DLL_CSECT();
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Core object has no ref left - destroy it.
|
|
DPF(2,"Destroying DirectSound Buffer object");
|
|
|
|
|
|
// Check to see if we are freeing the primary.....
|
|
if(pds->pdsbPrimary == pdsb) {
|
|
DPF(3,"Destroying Primary %X", pdsb);
|
|
|
|
// Check to see if we are on the WAVE apis
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
DSShutdownEmulator(pds);
|
|
}
|
|
|
|
pdsbPrimary = pds->pdsbPrimary;
|
|
pds->pdsbPrimary = NULL;
|
|
pds->pdsbePrimary = NULL;
|
|
|
|
}
|
|
|
|
// Remove it from list
|
|
if(pds->pdsb == pdsb)
|
|
{
|
|
pds->pdsb = pdsb->pNext;
|
|
} else {
|
|
for(pdsb1 = pds->pdsb; pdsb1 != NULL; pdsb1 = pdsb1->pNext)
|
|
{
|
|
if(pdsb1->pNext == pdsb) {
|
|
pdsb1->pNext = pdsb->pNext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
// This is a HW buffer - do not free it normally
|
|
DPF(3,"Release HW buffer %X", pdsb);
|
|
vxdBufferRelease(pdsb->hBuffer);
|
|
pdsb->hBuffer = NULL;
|
|
}
|
|
|
|
|
|
DPF(3,"Free memory for this buffer");
|
|
if( pdsb->pMixBuffer != NULL ) {
|
|
MemFree(pdsb->pMixBuffer);
|
|
}
|
|
|
|
// If this buffer has been duplicated then do not free memory, but erase
|
|
// this buffer from dup list.
|
|
if( pdsb->pdsbDuplicateNext == pdsb ) {
|
|
// No duplicate Just free
|
|
DPF(3,"NO Duplicate exists" );
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
// This is a HW buffer - handle card and system mem snd buffer
|
|
if (0 != pdsb->dwCardAddress) {
|
|
DPF(3,"Freeing card memory at %08Xh", pdsb->dwCardAddress);
|
|
ASSERT(NULL != pdsb->pds->pDriverHeap);
|
|
VidMemFree(pdsb->pds->pDriverHeap, pdsb->dwCardAddress);
|
|
}
|
|
|
|
if( (DSDDESC_USESYSTEMMEMORY & pdsb->pds->fdwDriverDesc) &&
|
|
!(pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) ) {
|
|
DPF(3,"Freeing system memory at %08Xh", pdsb->pDSBuffer);
|
|
MemFree(pdsb->pDSBuffer);
|
|
}
|
|
} else {
|
|
// This is a SW buffer - free system mem snd buffer
|
|
if( pdsb->pDSBuffer != NULL ) {
|
|
MemFree(pdsb->pDSBuffer);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// There is a duplicate. Just remove this one from the list
|
|
DPF(3,"Duplicate exists, do not free main memory" );
|
|
pdsb->pdsbDuplicateNext->pdsbDuplicatePrev = pdsb->pdsbDuplicatePrev;
|
|
pdsb->pdsbDuplicatePrev->pdsbDuplicateNext = pdsb->pdsbDuplicateNext;
|
|
pdsb->pdsbDuplicateNext = NULL;
|
|
pdsb->pdsbDuplicatePrev = NULL;
|
|
}
|
|
|
|
|
|
MemFree(pdsb->pwfx);
|
|
|
|
DPF(1, "Freeing DSBUFFER obj 0x%8x",pdsb);
|
|
pdsb->dwSig = 0xdeaddead;
|
|
MemFree(pdsb);
|
|
|
|
ASSERT(mxListIsValid(pds));
|
|
|
|
DPF(3,"Exiting buffer release method");
|
|
LEAVE_DLL_CSECT();
|
|
return 0;
|
|
} // IDSHWBufferRelease()
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetCaps
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPDSBCAPS pBufferCaps
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSOUNDEXTERNAL pdse;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(4,"Entering Get Caps method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetCaps - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
pdse = pdsbe->pdse;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetCaps - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_DSBCAPS_PTR( pBufferCaps ) ) {
|
|
RPF("IDirectSoundBuffer::GetCaps - Invalid DSBCAPS pointer or dwSize member.");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
pBufferCaps->dwFlags = pdsb->fdwBufferDesc;
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
pBufferCaps->dwFlags |= DSBCAPS_LOCHARDWARE;
|
|
pBufferCaps->dwFlags |= (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLDEFAULT);
|
|
}
|
|
else if( pdsb->fdwDsbI & DSB_INTERNALF_EMULATED ) {
|
|
pBufferCaps->dwFlags &= (~DSBCAPS_LOCHARDWARE);
|
|
pBufferCaps->dwFlags |= DSBCAPS_LOCSOFTWARE;
|
|
pBufferCaps->dwFlags |= (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLDEFAULT);
|
|
}
|
|
|
|
pBufferCaps->dwBufferBytes = pdsb->cbBufferSize;
|
|
pBufferCaps->dwUnlockTransferRate = 0;
|
|
pBufferCaps->dwPlayCpuOverhead = 0;
|
|
|
|
DPF(4,"Exiting get buffer caps method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetCaps()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetCurrentPosition
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPDWORD pdwPlay,
|
|
LPDWORD pdwWrite
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
DWORD cbSample;
|
|
DSVAL dsv;
|
|
|
|
DPF(4,"Entering HW Get Position method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_DWORD_PTR(pdwPlay) ) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Invalid Play pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if( !VALID_DWORD_PTR(pdwWrite) ) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Invalid Write pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
*pdwPlay = 0;
|
|
*pdwWrite = 0;
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( pdsbe != pds->pdsbePrimary ) {
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
}
|
|
|
|
|
|
// If called on a primary buffer, caller must be WRITEPRIMARY
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->dwPriority < DSSCL_WRITEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Caller isn't WRITEPRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
if( (pdsb->pwfx) && (pdsb->pwfx->nBlockAlign) ) {
|
|
cbSample = pdsb->pwfx->nBlockAlign;
|
|
} else {
|
|
cbSample = 4;
|
|
}
|
|
|
|
// If called on a primary buffer and the buffer is lost, return its
|
|
// position as 0.
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) )
|
|
{
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Buffer is lost");
|
|
LEAVE_DLL_CSECT();
|
|
*pdwPlay = 0;
|
|
*pdwWrite = 0;
|
|
return DS_OK;
|
|
}
|
|
|
|
if ((pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) &&
|
|
(pdsb->fdwDsbI & DSB_INTERNALF_SETPOS_WHILE_LOST)) {
|
|
|
|
// Buffer is lost, they've set the position since... just use that
|
|
//
|
|
|
|
*pdwPlay = pdsb->dwSavePosition;
|
|
*pdwWrite = pdsb->dwSavePosition;
|
|
} else if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
|
|
// We are a HW buffer - get position from HW
|
|
dsv = vxdBufferGetPosition(pdsb->hBuffer, pdwPlay, pdwWrite);
|
|
if (DS_OK != dsv) {
|
|
RPF("IDirectSoundBuffer::GetCurrentPosition - Hardware returned error.");
|
|
LEAVE_DLL_CSECT();
|
|
return dsv;
|
|
}
|
|
|
|
//
|
|
// REMIND: really this should only be true for HW buffers, which return
|
|
// dwPlay==cbBufferSize when a non-looping buffer reaches the end.
|
|
// We should stop those buffers as we do below.
|
|
//
|
|
if( (*pdwPlay >= pdsb->cbBufferSize) ) {
|
|
ASSERT(!(pdsb->fdwDsbI & DSB_INTERNALF_LOOPING));
|
|
// We are past end of buffer and not looping stop the buffer
|
|
DPF(0,"Play postion is past end - Stop it.");
|
|
IDsbStopI( pdsb, FALSE );
|
|
|
|
// Now set position back to beginning
|
|
IDsbSetCurrentPositionI(pdsb, 0);
|
|
|
|
*pdwPlay = 0;
|
|
*pdwWrite = 0;
|
|
|
|
}
|
|
|
|
// If the buffer is not stopped then we need to pad the write cursor
|
|
if (!(pdsb->fdwDsbI & DSB_INTERNALF_STOP)) {
|
|
*pdwWrite += pdsb->helInfo.dwSampleRate * MIXER_WRITEPAD / 1000;
|
|
if (*pdwWrite >= pdsb->cbBufferSize) *pdwWrite -= pdsb->cbBufferSize;
|
|
}
|
|
ASSERT(*pdwPlay >= 0 && *pdwPlay < pdsb->cbBufferSize);
|
|
ASSERT(*pdwWrite >= 0 && *pdwWrite < pdsb->cbBufferSize);
|
|
|
|
} else {
|
|
// We are not a HW buffer
|
|
// Check to see if we are on the WAVE apis
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
if (pdsb == pds->pdsbPrimary) {
|
|
// NOTE: The mechanics of the looping engine ensure that
|
|
// mod'ing these is already taken care of
|
|
int iawhWrite;
|
|
iawhWrite = (pds->iawhPlaying + NUMELMS(pds->aWaveHeader) - 1) % NUMELMS(pds->aWaveHeader);
|
|
|
|
*pdwPlay = pds->iawhPlaying * pds->cbDMASize;;
|
|
*pdwWrite = iawhWrite * pds->cbDMASize;
|
|
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
//
|
|
// This logic is somewhat screwy. We really should do a
|
|
// better job of finding the current play position and the
|
|
// current write position.
|
|
//
|
|
|
|
//
|
|
// ??? Want to be sample accurate here ???
|
|
//
|
|
if (0 == (DSB_INTERNALF_STOP & pdsb->fdwDsbI)) {
|
|
if (DSBCAPS_GETCURRENTPOSITION2 & pdsb->fdwBufferDesc) {
|
|
*pdwPlay = pdsb->aposWhMix[pds->iawhPlaying] << pdsb->uBlockAlignShift;
|
|
*pdwWrite = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
} else {
|
|
*pdwPlay = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
*pdwWrite = (pdsb->posNextMix+1) << pdsb->uBlockAlignShift;
|
|
if (*pdwWrite >= pdsb->cbBufferSize) *pdwWrite -= pdsb->cbBufferSize;
|
|
}
|
|
} else {
|
|
*pdwPlay = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
*pdwWrite = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
}
|
|
|
|
} else {
|
|
// Get position on Secondary
|
|
|
|
if (0 == (DSB_INTERNALF_STOP & pdsb->fdwDsbI)) {
|
|
dsv = mxGetPosition(pdsb, pdwPlay, pdwWrite, NULL);
|
|
if (DS_OK != dsv) {
|
|
LEAVE_DLL_CSECT();
|
|
return dsv;
|
|
}
|
|
} else {
|
|
*pdwPlay = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
*pdwWrite = pdsb->posNextMix << pdsb->uBlockAlignShift;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Round up positions to even samples
|
|
if( cbSample > 1 ) {
|
|
// Round up positions to sample position.
|
|
*pdwPlay += cbSample - 1;
|
|
*pdwWrite += cbSample - 1;
|
|
|
|
*pdwPlay -= (*pdwPlay % cbSample);
|
|
*pdwWrite -= (*pdwWrite % cbSample);
|
|
}
|
|
|
|
DPF(4,"Exit HW Get Postion %X Write %X", *pdwPlay, *pdwWrite);
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
|
|
} // IDSHWBufferGetCurrentPosition()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetFormat
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPWAVEFORMATEX pwfx,
|
|
DWORD cbwfx,
|
|
LPDWORD lpdwSizeReturned
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
DWORD dwSize;
|
|
LPWAVEFORMATEX pwfxToRet;
|
|
|
|
DPF(4,"Entering Buffer get format method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetFormat - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetFormat - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( ( NULL == pwfx ) &&
|
|
( NULL == lpdwSizeReturned ) )
|
|
{
|
|
RPF("IDirectSoundBuffer::GetFormat - Both pwfx and lpdwSizeWritten are NULL.");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
pwfxToRet = pdsb->pwfx;
|
|
if ((pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) &&
|
|
(pdsb->fdwDsbI & DSB_INTERNALF_WFX_WHILE_LOST)) {
|
|
pwfxToRet = pdsb->pwfxSave;
|
|
}
|
|
else if( pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY )
|
|
{
|
|
// Primary buffer - return app's preferred format if it has one,
|
|
// otherwise return the default format.
|
|
if( pdsbe->pdse->pwfxApp ) {
|
|
pwfxToRet = pdsbe->pdse->pwfxApp;
|
|
} else {
|
|
pwfxToRet = &pds->wfxDefault;
|
|
}
|
|
}
|
|
|
|
|
|
if( NULL != lpdwSizeReturned )
|
|
{
|
|
if( !VALID_DWORD_PTR(lpdwSizeReturned) ) {
|
|
RPF("IDirectSoundBuffer::GetFormat - Invalid lpdwSizeWritten pointer");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
*lpdwSizeReturned = SIZEOF_WAVEFORMATEX( pwfxToRet );
|
|
}
|
|
|
|
if( pwfx == NULL ) {
|
|
// pwfx is NULL just return size needed.
|
|
DPF(4,"Exiting buffer get format method - NULL pwfx");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
dwSize = SIZEOF_WAVEFORMATEX(pwfxToRet);
|
|
|
|
if(dwSize > cbwfx)
|
|
{
|
|
RPF("IDirectSoundBuffer::GetFormat - Not enough space for format");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
if( !VALID_SIZE_PTR(pwfx, dwSize) ) {
|
|
DPF(0,"Invalid Format size");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
hmemcpy(pwfx,pwfxToRet,dwSize);
|
|
|
|
DPF(4,"Exiting buffer get format method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetFormat()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetVolume
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPLONG plVolume
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(3,"Entering get volume method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
DPF(0,"Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
DPF(0,"Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
|
|
if( !VALID_LONG_PTR(plVolume) ) {
|
|
RPF("IDirectSoundBuffer::GetVolume - Invalid Volume pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ENTER_DLL_CSECT();
|
|
|
|
// Only primary buffers may have CTRLVOLUMEPRIMARY set.
|
|
ASSERT( !(pdsbe->fdwDsbeI&DSBE_INTERNALF_CTRLVOLUMEPRIMARY) ||
|
|
(pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) );
|
|
|
|
if( !(pdsb->fdwBufferDesc & DSBCAPS_CTRLVOLUME) &&
|
|
!(pdsbe->fdwDsbeI & DSBE_INTERNALF_CTRLVOLUMEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::GetVolume - Caller did not have CTRL permission for Volume!");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::GetVolume - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
if ((pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) &&
|
|
(pdsb->fdwDsbI & DSB_INTERNALF_VOLUME_WHILE_LOST)) {
|
|
*plVolume = pdsb->lSaveVolume;
|
|
} else if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
|
|
WAVEOUTCAPS woc;
|
|
DWORD dwWaveVolume;
|
|
UINT uWaveId;
|
|
|
|
if ( (DS_OK == wavGetIdFromDrvGuid(&pds->guid, &uWaveId)) &&
|
|
(!waveOutGetDevCaps(uWaveId, &woc, sizeof(woc))) &&
|
|
(woc.dwSupport & WAVECAPS_VOLUME) &&
|
|
(!waveOutGetVolume((HWAVEOUT)uWaveId, &dwWaveVolume)) )
|
|
{
|
|
if (woc.dwSupport & WAVECAPS_LRVOLUME) {
|
|
dwWaveVolume = max((dwWaveVolume & 0xffff), (dwWaveVolume >> 16));
|
|
} else {
|
|
dwWaveVolume &= 0xffff;
|
|
}
|
|
*plVolume = AmpFactorToDB( dwWaveVolume );
|
|
} else {
|
|
DPF(0, "IDSHWBufferGetVolume: error: couldn't get wave volume");
|
|
*plVolume = 0;
|
|
}
|
|
|
|
} else {
|
|
*plVolume = pdsb->helInfo.lVolume;
|
|
}
|
|
|
|
DPF(3,"Exiting buffer get volume method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetVolume()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetPan
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPLONG plPan
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(3,"Entering get pan method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetPan - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetPan - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_LONG_PTR(plPan) ) {
|
|
RPF("IDirectSoundBuffer::GetPan - Invalid Pan pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::GetPan - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
// Only primary buffers may have CTRLPANPRIMARY set.
|
|
ASSERT( !(pdsbe->fdwDsbeI&DSBE_INTERNALF_CTRLPANPRIMARY) ||
|
|
(pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) );
|
|
|
|
if (!(pdsb->fdwBufferDesc & DSBCAPS_CTRLPAN) &&
|
|
!(pdsbe->fdwDsbeI & DSBE_INTERNALF_CTRLPANPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::GetPan - Control not available");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
if ((pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) &&
|
|
(pdsb->fdwDsbI & DSB_INTERNALF_PAN_WHILE_LOST)) {
|
|
*plPan = pdsb->lSavePan;
|
|
} else if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
|
|
WAVEOUTCAPS woc;
|
|
DWORD dwWaveVolume;
|
|
DWORD dwWaveVolumeL;
|
|
DWORD dwWaveVolumeR;
|
|
UINT uWaveId;
|
|
|
|
if ( (DS_OK == wavGetIdFromDrvGuid(&pds->guid, &uWaveId)) &&
|
|
(!waveOutGetDevCaps(uWaveId, &woc, sizeof(woc))) &&
|
|
(woc.dwSupport & WAVECAPS_VOLUME) &&
|
|
(!waveOutGetVolume((HWAVEOUT)uWaveId, &dwWaveVolume)) )
|
|
{
|
|
if (woc.dwSupport & WAVECAPS_LRVOLUME) {
|
|
|
|
dwWaveVolumeL = dwWaveVolume & 0xffff;
|
|
dwWaveVolumeR = dwWaveVolume >> 16;
|
|
|
|
if (dwWaveVolumeL < dwWaveVolumeR) {
|
|
// pan to right
|
|
*plPan = -AmpFactorToDB((dwWaveVolumeL << 16) / dwWaveVolumeR);
|
|
} else if (dwWaveVolumeR < dwWaveVolumeL) {
|
|
// pan to left
|
|
*plPan = AmpFactorToDB((dwWaveVolumeR << 16) / dwWaveVolumeL);
|
|
} else {
|
|
*plPan = 0;
|
|
}
|
|
|
|
} else {
|
|
*plPan = 0;
|
|
}
|
|
} else {
|
|
DPF(0, "IDSHWBufferGetVolume: error: couldn't get wave volume");
|
|
*plPan = 0;
|
|
}
|
|
|
|
} else {
|
|
*plPan = pdsb->helInfo.lPan;
|
|
}
|
|
|
|
|
|
DPF(3,"Exiting buffer get pan method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetPan()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetFrequency
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPDWORD pdwFrequency
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(3,"Entering get frequency method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetFrequency - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetFrequency - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_DWORD_PTR(pdwFrequency) ) {
|
|
RPF("IDirectSoundBuffer::GetFrequency - Invalid Frequency pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::GetFrequency - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
if (0 == (pdsb->fdwBufferDesc & DSBCAPS_CTRLFREQUENCY)) {
|
|
RPF("IDirectSoundBuffer::GetFrequency - CTRLFREQUENCY unavailable");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
// DSBCAPS_CTRLFREQUENCY is not supported on primary buffers
|
|
ASSERT(0 == (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY));
|
|
|
|
if ((pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) &&
|
|
(pdsb->fdwDsbI & DSB_INTERNALF_FREQ_WHILE_LOST)) {
|
|
*pdwFrequency = pdsb->dwSaveFreq;
|
|
} else {
|
|
*pdwFrequency = pdsb->helInfo.dwSampleRate;
|
|
}
|
|
|
|
DPF(3,"Exiting buffer get frequency method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetFrequency()
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferGetStatus
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPDWORD pdwStatus
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(5,"Entering HW get Status method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::GetStatus - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::GetStatus - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_DWORD_PTR(pdwStatus) ) {
|
|
RPF("IDirectSoundBuffer::GetStatus - Invalid Status pointer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
ENTER_DLL_CSECT();
|
|
|
|
*pdwStatus = 0;
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY )
|
|
{
|
|
if( pdsbe->dwPriority >= DSSCL_WRITEPRIMARY ) {
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
|
|
*pdwStatus |= DSBSTATUS_PLAYING;
|
|
}
|
|
}
|
|
else if( pdsbe->fdwDsbeI & DSBE_INTERNALF_PLAYING ) {
|
|
*pdwStatus |= DSBSTATUS_PLAYING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Since secondary hardware buffers can't notify us when they have stopped, we poll
|
|
// them by calling GetCurrentPosition on them. The GetCurrentPosition
|
|
// method will check whether the buffer has stopped and update its status.
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) {
|
|
DWORD dwPlay, dwWrite;
|
|
IDirectSoundBuffer_GetCurrentPosition(pidsb, &dwPlay, &dwWrite);
|
|
}
|
|
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
|
|
*pdwStatus |= DSBSTATUS_PLAYING;
|
|
}
|
|
}
|
|
|
|
if( pdsb->helInfo.hfFormat & H_LOOP ) {
|
|
*pdwStatus |= DSBSTATUS_LOOPING;
|
|
}
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
*pdwStatus |= DSBSTATUS_BUFFERLOST;
|
|
}
|
|
|
|
DPF(5,"Exiting buffer get Status method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferGetStatus()
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferInitialize
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPDIRECTSOUND pids,
|
|
LPDSBUFFERDESC pdsbd
|
|
)
|
|
{
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LPDSOUND pds;
|
|
LPDSOUNDEXTERNAL pdse;
|
|
|
|
if( !VALID_DSBUFFERE_PTR(pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Initialize - Invalid DSBuffer Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Initialize - Invalid DSBuffer Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
pdse = (LPDSOUNDEXTERNAL)pids;
|
|
pds = pdse->pds;
|
|
|
|
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Initialize - Invalid DSound Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
if( !VALID_DSBUFFERDESC_PTR(pdsbd) ) {
|
|
RPF("IDirectSoundBuffer::Initialize - Invalid Buffer Description or dwSize member.");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
// This is all we have to do for this rev...
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
LEAVE_DLL_CSECT();
|
|
|
|
return DSERR_ALREADYINITIALIZED;
|
|
} // IDSHWBufferInitialize()
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferLock
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
DWORD dwWriteOffset,
|
|
DWORD dwSize,
|
|
LPLPVOID ppBuffer1,
|
|
LPDWORD pcbBufferSize1,
|
|
LPLPVOID ppBuffer2,
|
|
LPDWORD pcbBufferSize2,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
INT iExtraSize;
|
|
DWORD dwPlay;
|
|
DWORD dwWrite;
|
|
DWORD cbSample;
|
|
HRESULT hrslt;
|
|
DWORD dwOffset1;
|
|
LPVOID pBuffer1;
|
|
DWORD cbBufferSize1;
|
|
DWORD dwOffset2;
|
|
LPVOID pBuffer2;
|
|
DWORD cbBufferSize2;
|
|
BOOL fCommittedAlias;
|
|
|
|
DPF(4,"Entering LOCK HW obj %X start %X len %X",
|
|
pidsb, dwWriteOffset, dwSize );
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
|
|
|
|
if( (dwSize == 0) || (dwSize > pdsb->cbBufferSize) ) {
|
|
RPF("IDirectSoundBuffer::Lock - Size is too large for buffer");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if( dwFlags & (~DSBLOCK_VALIDFLAGS)) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid flags passed to Lock");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if( !VALID_DWORD_PTR(ppBuffer1) ) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid Pointer to Pointer to 1st section of buffer." );
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
if( !VALID_DWORD_PTR(pcbBufferSize1) ) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid Pointer to DWORD to 1st buffer size." );
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
if( dwWriteOffset >= pdsb->cbBufferSize ) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid Write Offset." );
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
dwOffset1 = 0;
|
|
dwOffset2 = 0;
|
|
|
|
pBuffer1 = NULL;
|
|
cbBufferSize1 = 0;
|
|
pBuffer2 = NULL;
|
|
cbBufferSize2 = 0;
|
|
|
|
*ppBuffer1 = NULL;
|
|
*pcbBufferSize1 = 0;
|
|
if( (ppBuffer2 != NULL) && (pcbBufferSize2 != NULL) ) {
|
|
*ppBuffer2 = NULL;
|
|
*pcbBufferSize2 = 0;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
// Trying to free a buffer with active locks is a Bad Thing
|
|
//
|
|
ASSERT(0 == pdsbe->cLocks);
|
|
|
|
if( pdsbe != pds->pdsbePrimary ) {
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::Lock - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
}
|
|
|
|
// Must be WRITEPRIMARY to lock the primary buffer
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->dwPriority < DSSCL_WRITEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::Lock - Caller not WRITEPRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
// Calculate general useful info
|
|
if( (pdsb->pwfx) && (pdsb->pwfx->nBlockAlign) ) {
|
|
cbSample = pdsb->pwfx->nBlockAlign;
|
|
} else {
|
|
cbSample = 4;
|
|
}
|
|
// Use the position from GetPos if needed.
|
|
if( dwFlags & DSBLOCK_FROMWRITECURSOR ) {
|
|
// Find current position
|
|
hrslt = pidsb->lpVtbl->GetCurrentPosition(
|
|
pidsb,
|
|
&dwPlay,
|
|
&dwWrite );
|
|
if(DS_OK != hrslt) {
|
|
DPF(0,"ERROR GetPosiiton return %ld obj %X ", hrslt, pdsb);
|
|
LEAVE_DLL_CSECT();
|
|
return hrslt;
|
|
}
|
|
|
|
// HACK - use better size?
|
|
// Check to see if we are on the WAVE apis
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
// ??? Do we have to be able to get the position on the primary if
|
|
// they aren't allowed to lock it?
|
|
//
|
|
if (pdsb == pds->pdsbPrimary) {
|
|
DPF(0, "IDSBufferGetCurrentPosition on primary");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
}
|
|
dwWriteOffset = dwWrite + cbSample;
|
|
}
|
|
|
|
// Round off positions to even samples
|
|
if( cbSample > 1 ) {
|
|
// Round of positions to sample position.
|
|
dwWriteOffset -= (dwWriteOffset % cbSample);
|
|
}
|
|
|
|
// Does buffer wrap?
|
|
iExtraSize = (LONG)(pdsb->cbBufferSize) - (LONG)(dwWriteOffset + dwSize);
|
|
|
|
|
|
if( (ppBuffer2 == NULL) || (pcbBufferSize2 == NULL) ) {
|
|
// Only report 1st pointer back to user.
|
|
dwOffset1 = dwWriteOffset;
|
|
|
|
if (pdsbe->pDSBufferAlias) {
|
|
pBuffer1 = pdsbe->pDSBufferAlias + dwWriteOffset;
|
|
} else {
|
|
pBuffer1 = pdsb->pDSBuffer + dwWriteOffset;
|
|
}
|
|
|
|
if( iExtraSize >= 0 ) {
|
|
cbBufferSize1 = dwSize;
|
|
} else {
|
|
cbBufferSize1 = pdsb->cbBufferSize - dwWriteOffset;
|
|
}
|
|
} else {
|
|
// Report both pointers to user
|
|
dwOffset1 = dwWriteOffset;
|
|
|
|
if (NULL != pdsbe->pDSBufferAlias) {
|
|
pBuffer1 = pdsbe->pDSBufferAlias + dwWriteOffset;
|
|
} else {
|
|
pBuffer1 = pdsb->pDSBuffer + dwWriteOffset;
|
|
}
|
|
|
|
if( iExtraSize >= 0 ) {
|
|
cbBufferSize1 = dwSize;
|
|
} else {
|
|
dwOffset2 = 0;
|
|
|
|
cbBufferSize1 = pdsb->cbBufferSize - dwWriteOffset;
|
|
|
|
if (pdsbe->pDSBufferAlias) {
|
|
pBuffer2 = pdsbe->pDSBufferAlias;
|
|
} else {
|
|
pBuffer2 = pdsb->pDSBuffer;
|
|
}
|
|
|
|
cbBufferSize2 = dwSize - cbBufferSize1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check to see if we can lock this buffer at that pos
|
|
if( DSBLockAccess( pdsb, dwOffset1, cbBufferSize1 ) ) {
|
|
// This section is already locked
|
|
RPF("IDirectSoundBuffer::Lock - Section already locked." );
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
|
|
}
|
|
if( (cbBufferSize2 > 0) &&
|
|
DSBLockAccess( pdsb, dwOffset2, cbBufferSize2 ) ) {
|
|
// There is a wrap section and
|
|
// This section is already locked
|
|
// Unlock the previous seciton
|
|
DSBUnlockAccess( pdsb, dwOffset1 );
|
|
RPF("IDirectSoundBuffer::Lock - Section already locked." );
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
|
|
// Maintain a count of the number of locks on this buffer.
|
|
pdsbe->cLocks++;
|
|
ASSERT(pdsbe->cLocks > 0);
|
|
|
|
// If we have an alias buffer ptr, we need to commit the physical
|
|
// buffer memory to the aliased pointer if this is the first lock.
|
|
fCommittedAlias = FALSE;
|
|
if (pdsbe->pDSBufferAlias && (1 == pdsbe->cLocks)) {
|
|
if (!vxdMemCommitAlias(pdsbe->pDSBufferAlias, pdsb->pDSBuffer, pdsb->cbBufferSize))
|
|
{
|
|
pdsbe->cLocks--;
|
|
DSBUnlockAccess( pdsb, dwOffset1 );
|
|
DSBUnlockAccess( pdsb, dwOffset2 );
|
|
DPF(0, "Lock: error: vxdMemCommitAlias failed");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_OUTOFMEMORY;
|
|
}
|
|
fCommittedAlias = TRUE;
|
|
}
|
|
|
|
// If this is a hardware buffer and they will be reading the memory
|
|
// from the system memory buffer, then get the driver to update
|
|
// the system memory from the card
|
|
|
|
// REMIND do we want to use LOCKF_READDATA?
|
|
// if( (dwFlags & DSB_LOCKF_READDATA) &&
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) {
|
|
// This is a HW buffer - Ask driver to lock
|
|
|
|
if ( ( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(pds->fdwDriverDesc & DSDDESC_DONTNEEDPRIMARYLOCK)) ||
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(pds->fdwDriverDesc & DSDDESC_DONTNEEDSECONDARYLOCK)) )
|
|
{
|
|
DSVAL dsv;
|
|
dsv = vxdBufferLock( pdsb->hBuffer, &pBuffer1, &cbBufferSize1,
|
|
&pBuffer2, &cbBufferSize2, dwWriteOffset,
|
|
dwSize, 0 );
|
|
if (DS_OK != dsv) {
|
|
if (fCommittedAlias) {
|
|
vxdMemDecommitAlias(pdsbe->pDSBufferAlias, pdsb->cbBufferSize);
|
|
}
|
|
pdsbe->cLocks--;
|
|
DSBUnlockAccess( pdsb, dwOffset1 );
|
|
DSBUnlockAccess( pdsb, dwOffset2 );
|
|
DPF(0, "Lock: error: vxdBufferLock returned %08Xh", dsv);
|
|
LEAVE_DLL_CSECT();
|
|
return dsv;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
*ppBuffer1 = pBuffer1;
|
|
*pcbBufferSize1 = cbBufferSize1;
|
|
if( (ppBuffer2 != NULL) && (pcbBufferSize2 != NULL) ) {
|
|
*ppBuffer2 = pBuffer2;
|
|
*pcbBufferSize2 = cbBufferSize2;
|
|
}
|
|
|
|
|
|
DPF(4,"Lock buffer ptr %X 1 %X 2 %X",pdsb->pDSBuffer, pBuffer1, pBuffer2);
|
|
DPF(4, "Lock offset 1 %X 2 %X ", dwWriteOffset, 0 );
|
|
|
|
|
|
|
|
|
|
DPF(4,"Exiting buffer lock method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferLock()
|
|
|
|
|
|
#ifdef DEBUG
|
|
DWORD dwLastTime;
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
//
|
|
// !!! This code is no longer supported but is left here as a reference
|
|
// til we have complete confidence in the grace.cpp mixing code
|
|
//
|
|
|
|
VOID CALLBACK HWMixThreadCallback
|
|
(
|
|
UINT wTimerID,
|
|
UINT uMsg,
|
|
DWORD dwUser,
|
|
DWORD dw1,
|
|
DWORD dw2
|
|
)
|
|
{
|
|
volatile LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
UINT iCount;
|
|
LPDSBWAVEBLTI pdswb;
|
|
HRESULT hrslt;
|
|
DWORD dwPlay, dwWrite;
|
|
DWORD dwNewPos;
|
|
DWORD cbSample;
|
|
#ifdef DEBUG
|
|
DWORD dwTime;
|
|
DWORD dwEndTime;
|
|
#endif
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
pds = (LPDSOUND)dwUser;
|
|
#pragma message( REMIND( "Find better way to synch pds in HwMixThreadCallback" ))
|
|
if (IsBadWritePtr(pds, sizeof(*pds)) || DSOUNDSIG != pds->dwSig) {
|
|
// DPF(0, "HwMixThreadCallback invalid pds=%08Xh", pds);
|
|
LEAVE_DLL_CSECT();
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
DPF(7,"*************** Mix Thread Prelim" );
|
|
|
|
dwTime = timeGetTime();
|
|
if( (dwTime - dwLastTime) > (pds->dwTimerDelay + (pds->dwTimerDelay)/2) ) {
|
|
DPF(0, "s %dms", dwTime - dwLastTime );
|
|
}
|
|
dwLastTime = dwTime;
|
|
|
|
DPF(5,"HW Mix Callback. %X", wTimerID );
|
|
#endif
|
|
|
|
DPF(7,"*************** Mix Thread CS " );
|
|
DPF(5,"Mix Thread " );
|
|
|
|
// Only do something if buffers (other than primary) playing
|
|
// or if a secondary buffer is jsut stopped
|
|
while( (pds->pdsbPrimary != NULL) &&
|
|
(!(pds->pdsbPrimary->fdwDsbI & DSB_INTERNALF_STOP)) &&
|
|
((pds->dwBuffersPlaying > 0) ||
|
|
(pds->pdsbPrimary->fdwDsbI & DSB_INTERNALF_JUSTSTOPPED)) ) {
|
|
DPF(5,"Buffers playing");
|
|
// Only mix in if it is time
|
|
|
|
// Find current position
|
|
hrslt = pds->pdsbePrimary->lpVtbl->GetCurrentPosition(
|
|
(LPDIRECTSOUNDBUFFER)pds->pdsbePrimary,
|
|
&dwPlay,
|
|
&dwWrite );
|
|
if(DS_OK != hrslt) {
|
|
DPF(1,"ERROR DS getpos return %ld obj %X buff %X ",
|
|
hrslt, pds, pds->pdsbPrimary);
|
|
}
|
|
|
|
|
|
dwNewPos = ((pds->dwLastCopyPlayPos +
|
|
pds->pdsbPrimary->cbFracSecondSize) %
|
|
pds->pdsbPrimary->cbBufferSize);
|
|
|
|
|
|
// If PLAY <= NEW
|
|
// Do not do blt unless
|
|
// New in last frac and Play in 1st frac
|
|
// If PLAY > NEW
|
|
// Blt unless new is First and play in last frac
|
|
//
|
|
|
|
if( dwPlay > dwNewPos ) {
|
|
// Play > New
|
|
if( ((dwPlay + pds->pdsbPrimary->cbFracSecondSize) >
|
|
pds->pdsbPrimary->cbBufferSize) &&
|
|
(dwNewPos < pds->pdsbPrimary->cbFracSecondSize) ) {
|
|
// Play is in last frac and new us in 1st
|
|
// Do not blt
|
|
DPF( 5, "DO NOT BLT Play > New but new has wrapped " );
|
|
LEAVE_DLL_CSECT();
|
|
return;
|
|
} else {
|
|
// Blt new has not wrapped
|
|
DPF( 5, "BLT Play > New" );
|
|
}
|
|
} else {
|
|
// Play <= New
|
|
if( ((dwNewPos + pds->pdsbPrimary->cbFracSecondSize) >
|
|
pds->pdsbPrimary->cbBufferSize) &&
|
|
(dwPlay < pds->pdsbPrimary->cbFracSecondSize) ) {
|
|
// New is in last frac and Play in 1st
|
|
// Do blt
|
|
DPF( 5, "BLT Play <= New and play has wrapped " );
|
|
} else {
|
|
// Do not blt play has not wrapped
|
|
DPF( 5, "DO NOT BLT Play > New" );
|
|
LEAVE_DLL_CSECT();
|
|
return;
|
|
}
|
|
}
|
|
|
|
DPF(5," LAST COPY %X NEW %X ",pds->dwLastCopyPlayPos,dwNewPos);
|
|
DPF(5," Play %X write %X LastCopyPos %X",dwPlay, dwWrite,
|
|
pds->dwLastCopyPos);
|
|
pds->dwLastCopyPlayPos = dwNewPos;
|
|
|
|
// Set up blt info for dst
|
|
// Note that size of the BLT struct is set at init time.
|
|
pdswb = pds->pdswb;
|
|
pdswb->dwPosition = pds->dwLastCopyPos;
|
|
pdswb->cbCopyLength = pds->pdsbPrimary->cbFracSecondSize;
|
|
pdswb->fdwWaveBlt = DSBBLT_COPY;
|
|
pdswb->dwCount = 0;
|
|
|
|
|
|
DPF(5,"Focus Window hwnd=%08X", gpdsinfo->hwndSoundFocus);
|
|
|
|
// Get data for each buffer
|
|
iCount = 0;
|
|
pdsb = pds->pdsb;
|
|
while( pdsb != NULL ) {
|
|
DPF( 5, "PDSB %X Window %X", pdsb, pdsb->dsbe.hwndOwner );
|
|
if( (pdsb != pds->pdsbPrimary) &&
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) &&
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_STOP)) &&
|
|
(pdsb->dsbe.hwndOwner == gpdsinfo->hwndSoundFocus) ) {
|
|
// We have a buffer that needs to be blt.
|
|
pdswb->padswbs[iCount].pdsbe = &pdsb->dsbe;
|
|
pdswb->padswbs[iCount].dwPosition = pdsb->dwNextCopyPos;
|
|
pdswb->padswbs[iCount].cbCopyLength = 0;
|
|
pdswb->padswbs[iCount].fdwWaveBltBuffer =
|
|
DSBBLTSRC_USEDSTLENGTH;
|
|
|
|
// If we are looping - set the flag for this buffer
|
|
if( pdsb->helInfo.hfFormat & H_LOOP ) {
|
|
pdswb->padswbs[iCount].fdwWaveBltBuffer |=
|
|
DSBBLT_BLTTODSTEND;
|
|
}
|
|
|
|
|
|
iCount++;
|
|
if( iCount >= LIMIT_BLT_SOURCES ) {
|
|
DPF(1,"PLAY ERROR TOO MANY BUFFERS ");
|
|
break;
|
|
}
|
|
}
|
|
pdsb = pdsb->pNext;
|
|
}
|
|
|
|
DPF(5,"Non Primary Buffers playing %X", iCount);
|
|
pdswb->dwCount = iCount;
|
|
|
|
hrslt = pds->pdsbePrimary->lpVtbl->WaveBlt(
|
|
(LPDIRECTSOUNDBUFFER)pds->pdsbePrimary,
|
|
(LPDSBWAVEBLT)pdswb);
|
|
if(DS_OK != hrslt) {
|
|
DPF(1,"PLAY ERROR DS Blt failed ");
|
|
}
|
|
|
|
|
|
// Now reset postions
|
|
iCount = 0;
|
|
pdsb = pds->pdsb;
|
|
while( pdsb != NULL ) {
|
|
if( (pdsb != pds->pdsbPrimary) &&
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) &&
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_STOP)) ) {
|
|
if( (pdsb->dsbe.hwndOwner == gpdsinfo->hwndSoundFocus) ) {
|
|
// We have a buffer that was blt.
|
|
pdsb->dwNextCopyPos = pdswb->padswbs[iCount].dwPosition;
|
|
|
|
// Check to see if we are at the end and need to
|
|
// stop playing
|
|
// We only stop on non-looped buffers
|
|
if( !(pdswb->padswbs[iCount].fdwWaveBltBuffer &
|
|
DSBBLT_BLTTODSTEND) &&
|
|
((pdsb->dwNextCopyPos >= pdsb->cbBufferSize) ||
|
|
(pdsb->dwNextCopyPos < 20 )) ) {
|
|
// HACK HACK - Watch for less than 20
|
|
// Instead of 0 since playback may wrap when
|
|
// Playback frequency is higher than value converted to
|
|
// For primary....
|
|
DPF(3,"Stop NON Looping buffer %X", pdsb);
|
|
// Buffer is not looped and
|
|
// Next copy is to be at end
|
|
pdsbe = &(pdsb->dsbe);
|
|
pdsbe->lpVtbl->Stop( (LPDIRECTSOUNDBUFFER)pdsbe );
|
|
// Note that the stop may kill off the primary buffer
|
|
// If primary was allocated at play time
|
|
|
|
|
|
// Set pos of next play back to start
|
|
pdsb->dwNextCopyPos = 0;
|
|
|
|
}
|
|
|
|
// Inc count into blt array
|
|
iCount++;
|
|
if( iCount >= LIMIT_BLT_SOURCES ) {
|
|
DPF(1,"PLAY ERROR TOO MANY BUFFERS ");
|
|
break;
|
|
}
|
|
} else {
|
|
// Buffer is playing, but is not from active app
|
|
// just advance pointers.
|
|
// We have a buffer that was blt.
|
|
pdsb->dwNextCopyPos += pdsb->cbFracSecondSize;
|
|
|
|
DPF(5,"Advance non active buffer %X by %X pos %X",
|
|
pdsb, pdsb->cbFracSecondSize, pdsb->dwNextCopyPos );
|
|
// Check to see if we are at the end and need to
|
|
// stop playing
|
|
// We only stop on non-looped buffers
|
|
if( (!(pdsb->helInfo.hfFormat & H_LOOP)) &&
|
|
((pdsb->dwNextCopyPos >= pdsb->cbBufferSize) ||
|
|
(pdsb->dwNextCopyPos < 20 )) ) {
|
|
// HACK HACK - Watch for less than 20
|
|
// Instead of 0 since playback may wrap when
|
|
// Playback frequency is higher than value converted to
|
|
// For primary....
|
|
DPF(3,"Stop NON Looping bufferg %X", pdsb);
|
|
// Buffer is not looped and
|
|
// Next copy is to be at end
|
|
pdsbe = &(pdsb->dsbe);
|
|
pdsbe->lpVtbl->Stop( (LPDIRECTSOUNDBUFFER)pdsbe );
|
|
// Note that the stop may kill off the primary buffer
|
|
// If primary was allocated at play time
|
|
|
|
|
|
// Set pos of next play back to start
|
|
pdsb->dwNextCopyPos = 0;
|
|
|
|
} else {
|
|
// else if looping then wrap buffer
|
|
if( (pdsb->pwfx) && (pdsb->pwfx->nBlockAlign) ) {
|
|
cbSample = pdsb->pwfx->nBlockAlign;
|
|
} else {
|
|
cbSample = 4;
|
|
}
|
|
|
|
pdsb->dwNextCopyPos = (pdsb->dwNextCopyPos %
|
|
pdsb->cbBufferSize);
|
|
pdsb->dwNextCopyPos -= (pdsb->dwNextCopyPos%cbSample);
|
|
}
|
|
|
|
}
|
|
}
|
|
pdsb = pdsb->pNext;
|
|
}
|
|
// Primary buffer may no longer exist just exit if so....
|
|
if( pds->pdsbPrimary != NULL ) {
|
|
// Blt has been done advance pointers....
|
|
pds->dwLastCopyPos += pds->pdsbPrimary->cbFracSecondSize;
|
|
pds->dwLastCopyPos = pds->dwLastCopyPos %
|
|
pds->pdsbPrimary->cbBufferSize;
|
|
} else {
|
|
DPF(0,"****** ERROR, Primary now NULL in MIX ******");
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef NOCOMP
|
|
|
|
if( pds->dwBuffersPlaying <= 0 ) {
|
|
if( pds->pdsbPrimary->fdwBuffer & DSBUFFERF_JUSTSTOPPED) {
|
|
DPF(3,"JustStop: Fill buffer");
|
|
pds->pdsbPrimary->fdwBuffer &= (~DSBUFFERF_JUSTSTOPPED);
|
|
|
|
|
|
// Set up blt info for dst
|
|
pdswb = pds->pdswb;
|
|
pdswb->dwPosition = 0;
|
|
pdswb->cbCopyLength = pds->pdsbPrimary->cbBufferSize;
|
|
pdswb->fdwWaveBlt = DSBBLT_COPY;
|
|
pdswb->dwCount = 0;
|
|
|
|
|
|
//ifndef HACKONBLTSIZE
|
|
if( pds->pdsbPrimary->pwfx->wBitsPerSample == 8 ) {
|
|
// Eight bit set to NULL value of 128
|
|
_fmemset( pds->pdsbPrimary->pDSBuffer,
|
|
128,
|
|
pdswb->cbCopyLength);
|
|
} else {
|
|
// Sixteen bit set to NULL value of 0
|
|
_fmemset( pds->pdsbPrimary->pDSBuffer,
|
|
0,
|
|
pdswb->cbCopyLength);
|
|
}
|
|
//else
|
|
hrslt = pds->pdsbPrimary->lpVtbl->WaveBlt(
|
|
(LPDIRECTSOUNDBUFFER)pds->pdsbPrimary,
|
|
(LPDSBWAVEBLT)pdswb);
|
|
if(DS_OK != hrslt) {
|
|
DPF(1,"PLAY ERROR FILL Blt failed ");
|
|
}
|
|
//endif
|
|
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
dwEndTime = timeGetTime();
|
|
if( (dwEndTime - dwTime) > (pds->dwTimerDelay)/2 ) {
|
|
DPF(0, "d %dms", dwEndTime - dwTime );
|
|
}
|
|
#endif
|
|
|
|
|
|
LEAVE_DLL_CSECT();
|
|
|
|
} // HWMixThreadCallback()
|
|
|
|
|
|
#endif // !USEGRACE
|
|
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferPlay
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
DWORD dwReserved1,
|
|
DWORD dwReserved2,
|
|
DWORD fdwPlay
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
DWORD dwPlay, dwWrite;
|
|
BOOL fResetDevice;
|
|
|
|
DPF(5, ";;Dump debug queue");
|
|
|
|
DPF(1,"Entering HW Play method pdsb %X flags %X",
|
|
pidsb, fdwPlay );
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Play - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Play - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( fdwPlay & (~DSBPLAY_VALIDFLAGS)) {
|
|
RPF("IDirectSoundBuffer::Play - Invalid flags passed to Play");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if((0 != dwReserved1) || (0 != dwReserved2)) {
|
|
RPF("IDirectSoundBuffer::Play - Reserved parameters were non-zero!");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
// If this is not our internal primary, then check for priority
|
|
if( pdsbe != pds->pdsbePrimary ) {
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::Play - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Fail if app has WRITEPRIMARY access and tries to play a secondary.
|
|
//
|
|
if( ( DSSCL_WRITEPRIMARY == pdsbe->dwPriority ) &&
|
|
!( pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY ) )
|
|
{
|
|
RPF("IDirectSoundBuffer::Play - Can't play secondary buffers when you have DSSCL_WRITEPRIMARY access.");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
|
|
// If this is primary, then we cannot play without looping
|
|
if ((pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(fdwPlay & DSBPLAY_LOOPING))
|
|
{
|
|
RPF("IDirectSoundBuffer::Play - Can't play Primary without LOOPING");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
// If the primary dsbe object's priority is less than WRITEPRIMARY then
|
|
// we set a flag saying that the external primary is playing and inc a
|
|
// count of external primaries that have playing status.
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->dwPriority < DSSCL_WRITEPRIMARY) )
|
|
{
|
|
// Set flag saying the external primary is playing.
|
|
if (!(pdsbe->fdwDsbeI & DSBE_INTERNALF_PLAYING)) {
|
|
pdsbe->fdwDsbeI |= DSBE_INTERNALF_PLAYING;
|
|
pds->cPlayPrimary++;
|
|
ASSERT(pds->cPlayPrimary > 0);
|
|
}
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
// Since hardware buffers can't notify us when they have stopped, we poll
|
|
// them by calling GetCurrentPosition on them. The GetCurrentPosition
|
|
// method will check whether the buffer has stopped and update its status.
|
|
if ((pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) &&
|
|
!(pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(pdsb->fdwDsbI & DSB_INTERNALF_STOP))
|
|
{
|
|
DWORD dwPlay, dwWrite;
|
|
IDirectSoundBuffer_GetCurrentPosition(pidsb, &dwPlay, &dwWrite);
|
|
}
|
|
|
|
// If it is already playing, then we only need to worry about
|
|
// changes in LOOPING
|
|
if(!(pdsb->fdwDsbI & DSB_INTERNALF_STOP))
|
|
{
|
|
// it is already playing...
|
|
// Reset looping flags
|
|
|
|
// If the looping has changed then reset the HW device
|
|
fResetDevice = FALSE;
|
|
if(DSBPLAY_LOOPING & fdwPlay) {
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_LOOPING) ) {
|
|
fResetDevice = TRUE;
|
|
}
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_LOOPING;
|
|
pdsb->helInfo.hfFormat |= H_LOOP;
|
|
} else {
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_LOOPING ) {
|
|
fResetDevice = TRUE;
|
|
}
|
|
pdsb->fdwDsbI &= (~DSB_INTERNALF_LOOPING);
|
|
pdsb->helInfo.hfFormat &= (~H_LOOP);
|
|
}
|
|
|
|
// If there was a change then either call the ds driver or
|
|
// call the mixer to remix
|
|
if (fResetDevice) {
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) {
|
|
vxdBufferPlay(pdsb->hBuffer, dwReserved1, dwReserved2,
|
|
fdwPlay & DSBPLAY_DRIVERFLAGSMASK);
|
|
} else if (!(pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
|
|
mxSignalRemix(pds, 0);
|
|
}
|
|
}
|
|
|
|
DPF(1,"Play: Exit - Already playing %X", pdsb);
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
// If this is the primary being told to play
|
|
if( pdsb == pds->pdsbPrimary ) {
|
|
// This is the primary being told to play
|
|
// Check to see if we are on the WAVE apis
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
// Primary is always playing
|
|
// do nothing
|
|
DPF(1,"Playing Wave Emulated Primary %X", pdsb);
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
} else {
|
|
// If this is not a HW buffer then start the primary playing
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) ) {
|
|
// Start primary playing
|
|
// Note that we can say play again even though it is already
|
|
// playing
|
|
pds->pdsbePrimary->lpVtbl->Play(
|
|
(LPDIRECTSOUNDBUFFER)(pds->pdsbePrimary),
|
|
0, 0,
|
|
(DSBPLAY_SECONDARY | DSBPLAY_LOOPING) );
|
|
}
|
|
}
|
|
|
|
|
|
dwPlay = 0;
|
|
dwWrite = 0;
|
|
|
|
|
|
if(DSBPLAY_LOOPING & fdwPlay) {
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_LOOPING;
|
|
pdsb->helInfo.hfFormat |= H_LOOP;
|
|
} else {
|
|
pdsb->fdwDsbI &= (~DSB_INTERNALF_LOOPING);
|
|
pdsb->helInfo.hfFormat &= (~H_LOOP);
|
|
}
|
|
|
|
|
|
|
|
// If we are doing a play on the primary then
|
|
// start it off for mixing....
|
|
// Only do this if the play was forced by the secondary
|
|
// If it was not secondary forced, then user is locking and
|
|
// We do not need a primary
|
|
if( (pdsb == pds->pdsbPrimary) && (fdwPlay & DSBPLAY_SECONDARY) ) {
|
|
// Note that WaveEmulated Primary returned OK before this
|
|
ASSERT( !(pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED) );
|
|
DsbFillSilence( pdsb );
|
|
}
|
|
|
|
// If this is a primary buffer then we set its mixer state to START. This
|
|
// tells the mixer that it hasn't yet been mixed into.
|
|
if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
|
|
pdsb->iMixerState = DSPBMIXERSTATE_START;
|
|
}
|
|
|
|
//
|
|
//
|
|
pdsb->fdwDsbI &= (~DSB_INTERNALF_STOP);
|
|
|
|
// If we are playing on a HW buffer then tell the HW to play. Otherwise
|
|
// signal the mixer that we need to remix.
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
DPF(2, "IDSHWPlay: note: playing hardware buffer");
|
|
vxdBufferPlay(pdsb->hBuffer, dwReserved1, dwReserved2,
|
|
fdwPlay & DSBPLAY_DRIVERFLAGSMASK);
|
|
} else {
|
|
// Add this to the mix list and signal the mixer. pdsb->posNextMix
|
|
// should be the desired starting position in this buffer (either 0 if
|
|
// never played or set by the last Stop or SetCurrentPosition
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED )) {
|
|
mxListAdd(pdsb);
|
|
mxSignalRemix(pds, 0);
|
|
}
|
|
}
|
|
|
|
// Buffer is to play increase count
|
|
if( (pdsb != pds->pdsbPrimary) &&
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) ) {
|
|
pds->dwBuffersPlaying++;
|
|
}
|
|
|
|
|
|
DPF(1,"Playing presumably successful %X", pdsb);
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferPlay()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferSetCurrentPosition
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
DWORD dwNewPos
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
HRESULT hr;
|
|
|
|
DPF(4,"Entering buffer set position method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::SetCurrentPosition - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::SetCurrentPosition - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
ASSERT(pds->pdsbPrimary == pdsb);
|
|
RPF("IDirectSoundBuffer::SetCurrentPosition - Illegal to SetCurrentPosition on primary");
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
|
|
// Since hardware buffers can't notify us when they have stopped, we poll
|
|
// them by calling GetCurrentPosition on them. The GetCurrentPosition
|
|
// method will check whether the buffer has stopped and update its status.
|
|
// We must do this before calling SetPosition otherwise we would set a new
|
|
// position before we found out whether the buffer was stopped.
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) {
|
|
DWORD dwPlay, dwWrite;
|
|
IDirectSoundBuffer_GetCurrentPosition(pidsb, &dwPlay, &dwWrite);
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure we're sample-aligned.
|
|
//
|
|
dwNewPos >>= pdsb->uBlockAlignShift;
|
|
dwNewPos <<= pdsb->uBlockAlignShift;
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::SetCurrentPosition - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
if( dwNewPos >= pdsb->cbBufferSize) {
|
|
RPF("IDirectSoundBuffer::SetCurrentPosition - Invalid Position");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_SETPOS_WHILE_LOST;
|
|
pdsb->dwSavePosition = dwNewPos;
|
|
|
|
DPF(4, "Early out - set position while buffer lost");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
hr = IDsbSetCurrentPositionI(pdsb, dwNewPos);
|
|
|
|
DPF(4,"Exiting buffer set position method");
|
|
LEAVE_DLL_CSECT();
|
|
return hr;
|
|
} // IDSHWBufferSetCurrentPosition()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferSetFormat
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPWAVEFORMATEX pwfx
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSOUNDEXTERNAL pdse;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LPWAVEFORMATEX pwfxNew;
|
|
int cbFormat;
|
|
HRESULT hr;
|
|
|
|
DPF(3,"Entering HW buffer set format method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pdse = pdsbe->pdse;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_WAVEFORMATEX_PTR(pwfx) ) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid Format Description");
|
|
return DSERR_BADFORMAT;
|
|
}
|
|
|
|
if( !ValidPCMFormat( pwfx ) ) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid Format Description");
|
|
return DSERR_BADFORMAT;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
//
|
|
// We don't support this function for NORMAL apps.
|
|
//
|
|
if (pdsbe->dwPriority <= DSSCL_NORMAL) {
|
|
RPF("IDirectSoundBuffer::SetFormat - called by NORMAL app - need PRIORITY cooperative level or higher.");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
//
|
|
// This function is supported only for primary buffers.
|
|
//
|
|
if (0 == (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI)) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Called on secondary buffer - only valid for primaries.");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
|
|
//
|
|
// Verify that this is a valid format for this card.
|
|
//
|
|
if( DS_OK != DseVerifyValidFormat( pdse, pwfx ) )
|
|
{
|
|
RPF("IDirectSoundBuffer::SetFormat - Invalid Format Description for this card");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_BADFORMAT;
|
|
}
|
|
|
|
//
|
|
// Copy the new app format
|
|
//
|
|
cbFormat = SIZEOF_WAVEFORMATEX(pwfx);
|
|
pwfxNew = (LPWAVEFORMATEX)MemAlloc(cbFormat);
|
|
if (NULL == pwfxNew) {
|
|
RPF("IDirectSoundBuffer::SetFormat - Out of memory for app's new format");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_OUTOFMEMORY;
|
|
}
|
|
CopyMemory(pwfxNew, pwfx, cbFormat);
|
|
|
|
// If this buffer is lost, then we need to save the format and retry
|
|
// the set format when restore is called
|
|
//
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
// If someone has already done this, override them -- free the
|
|
// previous format change and replace it with this one
|
|
//
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_WFX_WHILE_LOST) {
|
|
MemFree(pdsb->pwfxSave);
|
|
}
|
|
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_WFX_WHILE_LOST;
|
|
pdsb->pwfxSave = pwfxNew;
|
|
|
|
DPF(4, "Early out - set wave format of primary while lost");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
//
|
|
// Now we need to decide whether to actually change the format of
|
|
// the internal primary buffer
|
|
//
|
|
// Quite simply, if this app has sound focus, then we set the format
|
|
// of the internal primary buffer.
|
|
//
|
|
if (pdse->tidSound == gpdsinfo->tidSoundFocus || pdse->tidSound == gpdsinfo->tidStuckFocus) {
|
|
hr = IDsbSetFormatI(pdsb, pwfxNew, 0);
|
|
if (DS_OK != hr) {
|
|
DPF(0, "SetFormat: error: IDsbSetFormatI returned %08Xh", hr);
|
|
LEAVE_DLL_CSECT();
|
|
MemFree(pwfxNew);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Everything worked, so we save the app's new format in the app's
|
|
// pdse object, replacing any existing app format that might be there.
|
|
//
|
|
if (NULL != pdse->pwfxApp) {
|
|
DPF(1, "SetFormat: note: Freeing previous app format");
|
|
MemFree(pdse->pwfxApp);
|
|
}
|
|
pdse->pwfxApp = pwfxNew;
|
|
|
|
DPF(3,"Exiting buffer set format method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferSetFormat()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferSetVolume
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LONG lVolume
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LONG lPan;
|
|
LONG lTotalLeftDB;
|
|
LONG lTotalRightDB;
|
|
DSVOLUMEPAN dsVolPan;
|
|
|
|
DPF(3,"Entering buffer set volume method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::SetVolume - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::SetVolume - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
|
|
if(( lVolume < -10000 ) || ( lVolume > 0 )) {
|
|
RPF("IDirectSoundBuffer::SetVolume - Volume: %l out of range", lVolume);
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_VOLUME_WHILE_LOST;
|
|
pdsb->lSaveVolume = lVolume;
|
|
|
|
DPF(4, "Early out - set volume while buffer lost");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
// Only primary buffers may have CTRLVOLUMEPRIMARY set.
|
|
ASSERT( !(pdsbe->fdwDsbeI&DSBE_INTERNALF_CTRLVOLUMEPRIMARY) ||
|
|
(pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) );
|
|
|
|
if( !(pdsb->fdwBufferDesc & DSBCAPS_CTRLVOLUME) &&
|
|
!(pdsbe->fdwDsbeI & DSBE_INTERNALF_CTRLVOLUMEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::SetVolume - Caller did not have CTRL permission for Volume!");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::SetVolume - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
pdsb->helInfo.lVolume = lVolume;
|
|
lPan = pdsb->helInfo.lPan;
|
|
|
|
//
|
|
// Compute multpliers (scaling factors) for the mixer to use
|
|
//
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
lTotalLeftDB = lVolume - lPan ;
|
|
lTotalRightDB = lVolume;
|
|
} else {
|
|
// right is attenuated
|
|
lTotalLeftDB = lVolume;
|
|
lTotalRightDB = lVolume - (-lPan);
|
|
}
|
|
|
|
dsVolPan.dwTotalLeftAmpFactor = DBToAmpFactor(lTotalLeftDB);
|
|
dsVolPan.dwTotalRightAmpFactor = DBToAmpFactor(lTotalRightDB);
|
|
|
|
dsVolPan.lVolume = lVolume;
|
|
dsVolPan.dwVolAmpFactor = DBToAmpFactor(lVolume);
|
|
|
|
dsVolPan.lPan = pdsb->helInfo.lPan;
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(-lPan);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(0);
|
|
} else {
|
|
// right is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(0);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(lPan);
|
|
}
|
|
|
|
pdsb->helInfo.dwLVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
pdsb->helInfo.dwRVolume = dsVolPan.dwTotalRightAmpFactor;
|
|
pdsb->helInfo.dwMVolume = (pdsb->helInfo.dwLVolume + pdsb->helInfo.dwRVolume)/2;
|
|
|
|
DPF(3," Volume %ld Pan %ld left %Xh right %Xh ",
|
|
pdsb->helInfo.lVolume, pdsb->helInfo.lPan,
|
|
pdsb->helInfo.dwLVolume, pdsb->helInfo.dwRVolume );
|
|
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
|
|
// Will this work on wave-em primaries??? [ask jimge]
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
WAVEOUTCAPS woc;
|
|
DWORD dwWaveVolume;
|
|
UINT uWaveId;
|
|
|
|
// Anyone can always set the volume on the primary
|
|
|
|
ASSERT(dsVolPan.dwTotalLeftAmpFactor <= 0xffff);
|
|
ASSERT(dsVolPan.dwTotalRightAmpFactor <= 0xffff);
|
|
|
|
if ( (DS_OK == wavGetIdFromDrvGuid(&pds->guid, &uWaveId)) &&
|
|
(!waveOutGetDevCaps(uWaveId, &woc, sizeof(woc))) )
|
|
{
|
|
if (woc.dwSupport & WAVECAPS_VOLUME) {
|
|
|
|
if (woc.dwSupport & WAVECAPS_LRVOLUME) {
|
|
dwWaveVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
dwWaveVolume |= dsVolPan.dwTotalRightAmpFactor << 16;
|
|
} else {
|
|
dwWaveVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
dwWaveVolume += dsVolPan.dwTotalRightAmpFactor;
|
|
dwWaveVolume /= 2;
|
|
}
|
|
|
|
if (!waveOutSetVolume((HWAVEOUT)uWaveId, dwWaveVolume)) {
|
|
// We never create primaries w/ CTRLVOLUME
|
|
#if 0
|
|
DPF(3," HW Change volume %l ", lVolume );
|
|
if( vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan ) != DS_OK ) {
|
|
DPF(1," HAL Change VolumePan FAILED!!! ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
}
|
|
DPF(3," Changed HW format ");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is a HW buffer so set the Volume to the device.
|
|
//
|
|
// If this buffer's app doesn't have sound focus, then we
|
|
// won't actually call the driver- the volume has been minimized
|
|
// in order to mute the buffer while the app is out of sound focus
|
|
//
|
|
if (!pdsbe->pdsb->fMixerMute) {
|
|
|
|
DPF(3," HW Change volume %l ", lVolume );
|
|
if( vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan ) != DS_OK ) {
|
|
DPF(1," HAL Change VolumePan FAILED!!! ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
}
|
|
DPF(3," Changed HW format ");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DPF(3,"Exiting set volume method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferSetVolume()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferSetPan
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LONG lPan
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LONG lVolume;
|
|
LONG lTotalLeftDB;
|
|
LONG lTotalRightDB;
|
|
DSVOLUMEPAN dsVolPan;
|
|
|
|
DPF(3,"Entering buffer set Pan method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::SetPan - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::SetPan - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if(( lPan < -10000 ) || ( lPan > 10000 )) {
|
|
RPF("IDirectSoundBuffer::SetPan - Pan: %l out of range", lPan);
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_PAN_WHILE_LOST;
|
|
pdsb->lSavePan = lPan;
|
|
|
|
DPF(4, "Early out - set pan while buffer lost");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
// Only primary buffers may have CTRLPANPRIMARY set.
|
|
ASSERT( !(pdsbe->fdwDsbeI&DSBE_INTERNALF_CTRLPANPRIMARY) ||
|
|
(pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) );
|
|
|
|
if (!(pdsb->fdwBufferDesc & DSBCAPS_CTRLPAN) &&
|
|
!(pdsbe->fdwDsbeI & DSBE_INTERNALF_CTRLPANPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::SetPan - Caller did not have CTRL permission for Pan!");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::SetPan - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
pdsb->helInfo.lPan = lPan;
|
|
|
|
lVolume = pdsb->helInfo.lVolume;
|
|
|
|
//
|
|
// Compute multpliers (scaling factors) for the mixer to use
|
|
//
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
lTotalLeftDB = lVolume - lPan ;
|
|
lTotalRightDB = lVolume;
|
|
} else {
|
|
// right is attenuated
|
|
lTotalLeftDB = lVolume;
|
|
lTotalRightDB = lVolume - (-lPan);
|
|
}
|
|
|
|
dsVolPan.dwTotalLeftAmpFactor = DBToAmpFactor(lTotalLeftDB);
|
|
dsVolPan.dwTotalRightAmpFactor = DBToAmpFactor(lTotalRightDB);
|
|
|
|
dsVolPan.lVolume = lVolume;
|
|
dsVolPan.dwVolAmpFactor = DBToAmpFactor(lVolume);
|
|
|
|
dsVolPan.lPan = pdsb->helInfo.lPan;
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(-lPan);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(0);
|
|
} else {
|
|
// right is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(0);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(lPan);
|
|
}
|
|
|
|
pdsb->helInfo.dwLVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
pdsb->helInfo.dwRVolume = dsVolPan.dwTotalRightAmpFactor;
|
|
pdsb->helInfo.dwMVolume = (pdsb->helInfo.dwLVolume + pdsb->helInfo.dwRVolume)/2;
|
|
|
|
DPF(3," Volume %ld Pan %ld left %Xh right %Xh ",
|
|
pdsb->helInfo.lVolume, pdsb->helInfo.lPan,
|
|
pdsb->helInfo.dwLVolume, pdsb->helInfo.dwRVolume );
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
|
|
// Will this work on wave-em primaries??? [ask jimge]
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
WAVEOUTCAPS woc;
|
|
DWORD dwWaveVolume;
|
|
UINT uWaveId;
|
|
|
|
// Anyone can always set the volume on the primary
|
|
|
|
ASSERT(dsVolPan.dwTotalLeftAmpFactor <= 0xffff);
|
|
ASSERT(dsVolPan.dwTotalRightAmpFactor <= 0xffff);
|
|
|
|
if ( (DS_OK == wavGetIdFromDrvGuid(&pds->guid, &uWaveId)) &&
|
|
(!waveOutGetDevCaps(uWaveId, &woc, sizeof(woc))) )
|
|
{
|
|
if (woc.dwSupport & WAVECAPS_VOLUME) {
|
|
|
|
if (woc.dwSupport & WAVECAPS_LRVOLUME) {
|
|
dwWaveVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
dwWaveVolume |= dsVolPan.dwTotalRightAmpFactor << 16;
|
|
} else {
|
|
dwWaveVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
dwWaveVolume += dsVolPan.dwTotalRightAmpFactor;
|
|
dwWaveVolume /= 2;
|
|
}
|
|
|
|
if (!waveOutSetVolume((HWAVEOUT)uWaveId, dwWaveVolume)) {
|
|
// We never create primaries w/ CTRLVOLUME
|
|
#if 0
|
|
DPF(3," HW Change volume %l ", lVolume );
|
|
if( vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan ) != DS_OK ) {
|
|
DPF(1," HAL Change VolumePan FAILED!!! ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
}
|
|
DPF(3," Changed HW format ");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
|
|
// This is a HW buffer so set the Pan to the device
|
|
//
|
|
// If this buffer's app doesn't have sound focus, then we
|
|
// won't actually call the driver- the volume has been minimized
|
|
// in order to mute the buffer while the app is out of sound focus
|
|
//
|
|
if (!pdsbe->pdsb->fMixerMute) {
|
|
|
|
DPF(3," HW Change pan %ld ", lPan );
|
|
if( DS_OK != vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan )) {
|
|
DPF(1," HAL Change VolumePan FAILED!!! ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
}
|
|
DPF(3," Changed HW pan");
|
|
}
|
|
}
|
|
}
|
|
|
|
DPF(3,"Exiting set Pan method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferSetPan()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferSetFrequency
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
DWORD dwFrequency
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
|
|
DPF(3,"Entering buffer set Frequency method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::SetFrequency - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::SetFrequency - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( (dwFrequency != 0) &&
|
|
((dwFrequency < 100) || (dwFrequency > 100000) ) ) {
|
|
RPF("IDirectSoundBuffer::SetFrequency - Invalid Frequency Range");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_FREQ_WHILE_LOST;
|
|
pdsb->dwSaveFreq = dwFrequency;
|
|
|
|
DPF(4, "Early out - set freq while buffer lost");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
if( !(pdsb->fdwBufferDesc & DSBCAPS_CTRLFREQUENCY )) {
|
|
RPF("IDirectSoundBuffer::SetFrequency - Caller did not have CTRL permission for Frequency!");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY) ) {
|
|
RPF("IDirectSoundBuffer::SetFrequency - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
// Primary buffers never get DSBCAPS_CTRLFREQUENCY
|
|
ASSERT(0 == (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY));
|
|
|
|
if( dwFrequency == 0 ) {
|
|
dwFrequency = pdsb->pwfx->nSamplesPerSec;
|
|
}
|
|
|
|
|
|
if (dwFrequency == pdsb->helInfo.dwSampleRate) {
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
// If this buffer is being mixed, then signal the mixer
|
|
if ((0 == (DSB_INTERNALF_STOP & pdsb->fdwDsbI)) &&
|
|
(0 == (DSB_INTERNALF_HARDWARE & pdsb->fdwDsbI)) &&
|
|
(0 == (DS_INTERNALF_WAVEEMULATED & pds->fdwInternal)))
|
|
{
|
|
mxSignalRemix(pds, 0);
|
|
}
|
|
|
|
pdsb->helInfo.dwSampleRate = dwFrequency;
|
|
|
|
// Physically reset the device if a HW buffer has changed
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
// This is a HW buffer so set the format to the device
|
|
DPF(3," Change HW RATE format %X freq %X",
|
|
pdsb->helInfo.hfFormat, pdsb->helInfo.dwSampleRate );
|
|
if( vxdBufferSetFrequency( pdsb->hBuffer, pdsb->helInfo.dwSampleRate ) != HAL_OK ) {
|
|
DPF(1," HAL Change RATE FAILED!!! ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_GENERIC;
|
|
}
|
|
DPF(4," Changed HW RATE ");
|
|
}
|
|
|
|
|
|
|
|
DPF(3,"Exiting set Frequency method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferSetFrequency()
|
|
|
|
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferStop
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
HRESULT hr;
|
|
|
|
DPF(3,"Enter buffer stop method %X", pidsb);
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Stop - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Stop - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
//
|
|
// Shouldn't call this external method on our internal primary
|
|
// object - call IDsbStopI instead.
|
|
//
|
|
ASSERT( pdsbe != pds->pdsbePrimary );
|
|
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::Stop - Invalid priority level or buffer owner");
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
// All lost buffers are stopped by definition. Primary buffers
|
|
// may be playing for some other app, however. We can assert
|
|
// that this buffer is either primary or stopped.
|
|
ASSERT((pdsb->fdwDsbI & (DSB_INTERNALF_PRIMARY | DSB_INTERNALF_STOP)));
|
|
return DS_OK;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
// If the app has less than WRITEPRIMARY, we allow Stop
|
|
// on the external primary but stop the internal primary only if
|
|
// there are no other buffers playing on it.
|
|
if( ( pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY ) &&
|
|
( pdsbe->dwPriority < DSSCL_WRITEPRIMARY ) )
|
|
{
|
|
ASSERT( pdsb == pds->pdsbPrimary );
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_PLAYING ) {
|
|
pdsbe->fdwDsbeI &= ~DSBE_INTERNALF_PLAYING;
|
|
pds->cPlayPrimary--;
|
|
ASSERT(pds->cPlayPrimary >= 0);
|
|
if( (0 != pds->cPlayPrimary) || (0 != pds->dwBuffersPlaying) ){
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
pds->pdsbPrimary->fdwDsbI |= DSB_INTERNALF_JUSTSTOPPED;
|
|
}
|
|
}
|
|
|
|
|
|
hr = IDsbStopI( pdsb, FALSE );
|
|
|
|
LEAVE_DLL_CSECT();
|
|
|
|
return hr;
|
|
} // IDSHWBufferStop()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferRestore
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSOUNDEXTERNAL pdse;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
DWORD dwActivePrio;
|
|
|
|
DPF(4,"Enter buffer Restore method %X", pidsb);
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Restore - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Restore - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if (!(pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST)) {
|
|
RPF("IDirectSoundBuffer::Restore - Buffer is not lost! Restore returning success.");
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if (gpdsinfo->fApmSuspended) {
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
// This should never get called on the internal primary
|
|
ASSERT(pdsbe != pds->pdsbePrimary);
|
|
|
|
// We can restore the primary only if the app is WRITEPRIMARY and
|
|
// it is the active app.
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
|
|
if (pdsbe->dwPriority < DSSCL_WRITEPRIMARY) {
|
|
RPF("IDirectSoundBuffer::Restore - Can't restore primary; no DSSCL_WRITEPRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
if (gpdsinfo->tidSoundFocus != pdsbe->pdse->tidSound) {
|
|
RPF("IDirectSoundBuffer::Restore - Tried to restore primary while not active");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
// We need to clear LOST
|
|
DPF(1, "IDSHWBufferRestore: note: restoring primary dsbe %08Xh", pdsbe);
|
|
pdsbe->fdwDsbeI &= ~DSBE_INTERNALF_LOST;
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
// Validate that the active app no longer has WRITEPRIMARY
|
|
dwActivePrio = DSSCL_NORMAL;
|
|
for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
|
|
if (gpdsinfo->tidSoundFocus == pdse->tidSound && pdse->dwPriority > dwActivePrio) {
|
|
dwActivePrio = pdse->dwPriority;
|
|
}
|
|
}
|
|
|
|
if (dwActivePrio >= DSSCL_WRITEPRIMARY) {
|
|
DPF(4,"Restore: Active app still running at DSSCL_WRITEPRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
// "Once I was lost, but now I'm found
|
|
// Was blind but now can see"
|
|
pdsbe->fdwDsbeI &= ~DSBE_INTERNALF_LOST;
|
|
|
|
// Handle anything that was set while we were lost
|
|
//
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_SETPOS_WHILE_LOST) {
|
|
DPF(4, "Restore: SetCurrentPosition to %u", pdsb->dwSavePosition);
|
|
|
|
pdsbe->lpVtbl->SetCurrentPosition((LPDIRECTSOUNDBUFFER)pdsbe,
|
|
pdsb->dwSavePosition);
|
|
pdsb->fdwDsbI &= ~DSB_INTERNALF_SETPOS_WHILE_LOST;
|
|
}
|
|
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_VOLUME_WHILE_LOST) {
|
|
DPF(4, "Restore: SetVolume to %u", pdsb->lSaveVolume);
|
|
|
|
pdsbe->lpVtbl->SetVolume((LPDIRECTSOUNDBUFFER)pdsbe,
|
|
pdsb->lSaveVolume);
|
|
pdsb->fdwDsbI &= ~DSB_INTERNALF_VOLUME_WHILE_LOST;
|
|
}
|
|
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_PAN_WHILE_LOST) {
|
|
DPF(4, "Restore: Set pan to %u", pdsb->lSavePan);
|
|
|
|
pdsbe->lpVtbl->SetPan((LPDIRECTSOUNDBUFFER)pdsbe,
|
|
pdsb->lSavePan);
|
|
pdsb->fdwDsbI &= ~DSB_INTERNALF_PAN_WHILE_LOST;
|
|
}
|
|
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_FREQ_WHILE_LOST) {
|
|
DPF(4, "Restore: Set freq to %u", pdsb->dwSaveFreq);
|
|
|
|
pdsbe->lpVtbl->SetFrequency((LPDIRECTSOUNDBUFFER)pdsbe,
|
|
pdsb->dwSaveFreq);
|
|
pdsb->fdwDsbI &= ~DSB_INTERNALF_FREQ_WHILE_LOST;
|
|
}
|
|
|
|
if (pdsb->fdwDsbI & DSB_INTERNALF_WFX_WHILE_LOST) {
|
|
DPF(4, "Restore: Set format\n");
|
|
|
|
pdsbe->lpVtbl->SetFormat((LPDIRECTSOUNDBUFFER)pdsbe,
|
|
pdsb->pwfxSave);
|
|
|
|
pdsb->fdwDsbI &= ~DSB_INTERNALF_WFX_WHILE_LOST;
|
|
MemFree(pdsb->pwfxSave);
|
|
pdsb->pwfxSave = NULL;
|
|
}
|
|
|
|
DPF(3,"Exit Restore method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferRestore()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferUnlock
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsb,
|
|
LPVOID pBuffer,
|
|
DWORD dwWriteLen,
|
|
LPVOID pBufferWrap,
|
|
DWORD dwWrapWriteLen
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
DWORD dwOffset1;
|
|
DWORD dwOffset2;
|
|
|
|
DPF(4,"Entering UNLock HW obj %X ", pidsb );
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsb) ) {
|
|
RPF("IDirectSoundBuffer::Unlock - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsb;
|
|
pdsb = pdsbe->pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::Unlock - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
if( !VALID_DWORD_PTR(pBuffer) ) {
|
|
RPF("IDirectSoundBuffer::Unlock - Invalid first buffer pointer.");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
// If the buffer was lost while it was locked, then we'll unlock it but
|
|
// with write lengths of 0, effectively throwing away whatever the app
|
|
// may have written to the buffer but still unlocking the pointers.
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
dwWriteLen = 0;
|
|
dwWrapWriteLen = 0;
|
|
}
|
|
|
|
if( pdsbe != pds->pdsbePrimary ) {
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::Unlock - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
}
|
|
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->dwPriority < DSSCL_WRITEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::Unlock - Can't unlock primary buffer: caller not WRITE_PRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
DPF(5,"unlock buffer ptr %X 1 %X 2 %X",pdsb->pDSBuffer, pBuffer, pBufferWrap);
|
|
|
|
if (pdsbe->pDSBufferAlias) {
|
|
dwOffset1 = (DWORD)pBuffer - (DWORD)(pdsbe->pDSBufferAlias);
|
|
dwOffset2 = (DWORD)pBufferWrap - (DWORD)(pdsbe->pDSBufferAlias);
|
|
} else {
|
|
dwOffset1 = (DWORD)pBuffer - (DWORD)(pdsb->pDSBuffer);
|
|
dwOffset2 = (DWORD)pBufferWrap - (DWORD)(pdsb->pDSBuffer);
|
|
}
|
|
|
|
DPF(5, "Unlock offset 1 %X 2 %X ", dwOffset1, dwOffset2 );
|
|
|
|
|
|
if( DSBUnlockAccess( pdsb, dwOffset1 ) != DS_OK ) {
|
|
RPF("IDirectSoundBuffer::Unlock - Error unlocking section 1." );
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
|
|
}
|
|
|
|
if( (pBufferWrap != NULL) &&
|
|
(DSBUnlockAccess( pdsb, dwOffset2 ) != DS_OK) ) {
|
|
// There is a wrap section
|
|
RPF("IDirectSoundBuffer::Unlock - Error unlocking section2." );
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
|
|
// If this is a hardware buffer and they will be reading the memory
|
|
// from the system memory buffer, then get the driver to update
|
|
// the system memory from the card
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) ) {
|
|
// This is a HW buffer - Ask driver to lock
|
|
if ( ( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(pds->fdwDriverDesc & DSDDESC_DONTNEEDPRIMARYLOCK)) ||
|
|
(!(pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
!(pds->fdwDriverDesc & DSDDESC_DONTNEEDSECONDARYLOCK)) )
|
|
{
|
|
vxdBufferUnlock( pdsb->hBuffer, pBuffer, dwWriteLen,
|
|
pBufferWrap, dwWrapWriteLen);
|
|
}
|
|
}
|
|
|
|
// If this is a non wave-emulated software buffer that is currently
|
|
// playing, then we need to check whether any of the unlocked region lies
|
|
// in the premixed region of the buffer.
|
|
if (!(pds->fdwInternal & DS_INTERNALF_WAVEEMULATED) &&
|
|
!(pdsb->fdwDsbI & (DSB_INTERNALF_HARDWARE | DSB_INTERNALF_STOP)))
|
|
{
|
|
int iWriteCursor, iMixCursor;
|
|
int iPremixLen;
|
|
BOOL fRegionsIntersect;
|
|
|
|
mxGetPosition(pdsb, NULL, &iWriteCursor, &iMixCursor);
|
|
ASSERT(iWriteCursor >= 0);
|
|
ASSERT(iMixCursor >= 0);
|
|
iPremixLen = iMixCursor - iWriteCursor;
|
|
if (iPremixLen < 0) iPremixLen += pdsb->cbBufferSize;
|
|
ASSERT(iPremixLen >= 0);
|
|
|
|
fRegionsIntersect = CircularBufferRegionsIntersect(pdsb->cbBufferSize,
|
|
iWriteCursor, iPremixLen, dwOffset1, dwWriteLen);
|
|
|
|
if (!fRegionsIntersect && pBufferWrap) {
|
|
fRegionsIntersect = CircularBufferRegionsIntersect(pdsb->cbBufferSize,
|
|
iWriteCursor, iPremixLen, dwOffset2, dwWrapWriteLen);
|
|
}
|
|
|
|
if (fRegionsIntersect) {
|
|
DPF(2, "Lock: note: unlocked premixed region");
|
|
mxSignalRemix(pdsb->pds, 0);
|
|
}
|
|
}
|
|
|
|
// Maintain a count of the number of locks on this buffer.
|
|
pdsbe->cLocks--;
|
|
ASSERT(pdsbe->cLocks >= 0);
|
|
|
|
// If we have a buffer alias ptr and this is the last unlock then we need
|
|
// to decommit the physical buffer memory from the alias ptr
|
|
if (pdsbe->pDSBufferAlias && (0 == pdsbe->cLocks)) {
|
|
vxdMemDecommitAlias(pdsbe->pDSBufferAlias, pdsb->cbBufferSize);
|
|
}
|
|
|
|
DPF(4,"Exiting unlock method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferUnlock()
|
|
|
|
|
|
HRESULT FAR PASCAL IDSHWBufferWaveBlt
|
|
(
|
|
LPDIRECTSOUNDBUFFER pidsbDst,
|
|
LPDSBWAVEBLT pidswb
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LPDSBUFFEREXTERNAL pdsbe;
|
|
LPDSBUFFEREXTERNAL pdsbeSrc;
|
|
LPDSBUFFER pdsbDst;
|
|
DWORD dwDstPlay;
|
|
DWORD dwDstWrite;
|
|
DWORD dwDstPosition;
|
|
LPBYTE pDstBuffer;
|
|
DWORD dwDstLock;
|
|
LPBYTE pDstBuffer2;
|
|
DWORD dwDstLock2;
|
|
LPBYTE pMixBuffer;
|
|
DWORD cbMixBufferSize;
|
|
int cbAdjustedMixBuffer;
|
|
HRESULT hrslt;
|
|
LPDSBWAVEBLTI pdswb;
|
|
DWORD i;
|
|
LPHALSTRBUF pHelInfo;
|
|
|
|
|
|
DPF(4,"Entering wave blt method");
|
|
if( !VALID_DSBUFFERE_PTR((LPDSBUFFEREXTERNAL)pidsbDst) ) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
pdsbe = (LPDSBUFFEREXTERNAL)pidsbDst;
|
|
pdsb = pdsbe->pdsb;
|
|
pdsbDst = pdsb;
|
|
pds = pdsb->pds;
|
|
if( !VALID_DSBUFFER_PTR(pdsb) || (0 == pdsbe->uRefCount)) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid Object or ref count");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
pdswb = (LPDSBWAVEBLTI)(pidswb);
|
|
if( !VALID_DSBWAVEBLT_PTR(pdswb) ) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid BLT structure");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if( pdswb->fdwWaveBlt & (~DSBBLT_VALIDFLAGS)) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid flags passed to WaveBlt");
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
|
|
if (pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST) {
|
|
return DSERR_BUFFERLOST;
|
|
}
|
|
|
|
ENTER_DLL_CSECT();
|
|
|
|
if( pdsbe != pds->pdsbePrimary ) {
|
|
if( (pdsbe->dwPriority < DSSCL_NORMAL)
|
|
|| (pdsbe->dwPriority > DSSCL_WRITEPRIMARY)) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid priority level or buffer owner");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
}
|
|
|
|
if( (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) &&
|
|
(pdsbe->dwPriority < DSSCL_WRITEPRIMARY) )
|
|
{
|
|
RPF("IDirectSoundBuffer::WaveBlt - Can't wavblt on primary buffer: caller not WRITEPRIMARY");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_PRIOLEVELNEEDED;
|
|
}
|
|
|
|
// Init local copy of position
|
|
dwDstPosition = pdswb->dwPosition;
|
|
|
|
// Check sources are valid
|
|
for( i = 0; i < pdswb->dwCount; i++ ) {
|
|
// Check object and ref count are fine
|
|
if( !VALID_DSBUFFERE_PTR(pdswb->padswbs[i].pdsbe) ||
|
|
(0 == pdswb->padswbs[i].pdsbe->uRefCount) ) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Invalid object or ref count on src buffer");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDPARAM;
|
|
}
|
|
}
|
|
|
|
// Check to see this is a buffer we can blt to
|
|
if( pdsbDst->cbMixBufferSize == 0 ) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Trying to blt to a nomix buffer");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
// Check formats are the PCM
|
|
if( !CheckFormatsPCM( pdsbDst, pdswb ) ) {
|
|
RPF("IDirectSoundBuffer::WaveBlt - Formats not the PCM");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_CONTROLUNAVAIL;
|
|
}
|
|
|
|
// Check the size of the blt against dst buffer total size
|
|
if( pdswb->cbCopyLength >= pdsbDst->cbBufferSize ) {
|
|
pdswb->cbCopyLength = pdsbDst->cbBufferSize -
|
|
pdsbDst->pwfx->nBlockAlign;
|
|
}
|
|
|
|
// Do nothing on NULL copy
|
|
if( 0 == pdswb->cbCopyLength )
|
|
{
|
|
RPF("IDirectSoundBuffer::WaveBlt - Zero source size");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
}
|
|
|
|
// Get Positions in buffer
|
|
hrslt = pidsbDst->lpVtbl->GetCurrentPosition(pidsbDst,
|
|
&dwDstPlay,
|
|
&dwDstWrite );
|
|
if(DS_OK != hrslt)
|
|
{
|
|
DPF(1,"DS get position failed return %ld ", hrslt);
|
|
LEAVE_DLL_CSECT();
|
|
return hrslt;
|
|
}
|
|
|
|
// Reset position
|
|
if( pdswb->fdwWaveBlt & DSBBLT_DSTWRITECURSOR ) {
|
|
DPF(5,"Wave BLT DST current pos");
|
|
dwDstPosition = dwDstWrite;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check for writing at current play pos
|
|
if( dwDstPosition == dwDstPlay ) {
|
|
// if stopped this is fine... Go forward....
|
|
if( pdsbDst->fdwDsbI & DSB_INTERNALF_STOP ) {
|
|
DPF(1,"DstPostion == PlayPosition - Ok we are stopped ");
|
|
} else {
|
|
DPF(1,"DstPostion == PlayPosition - NOT Ok NOT stopped ");
|
|
LEAVE_DLL_CSECT();
|
|
return DSERR_INVALIDCALL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lock buffers for copy
|
|
DPF(4, "Lock Dest %X ", pdsbDst );
|
|
hrslt = pidsbDst->lpVtbl->Lock(pidsbDst,
|
|
dwDstPosition,
|
|
pdswb->cbCopyLength,
|
|
&pDstBuffer,
|
|
&dwDstLock,
|
|
&pDstBuffer2,
|
|
&dwDstLock2,
|
|
0L);
|
|
if(DS_OK != hrslt)
|
|
{
|
|
DPF(1,"DS Buffer Lock failed ");
|
|
LEAVE_DLL_CSECT();
|
|
return hrslt;
|
|
}
|
|
|
|
|
|
// Get the helInfo for mixing
|
|
pHelInfo = &(pdsbDst->helInfo);
|
|
|
|
|
|
|
|
// For each source buffer get the relevant info
|
|
for( i = 0; i < pdswb->dwCount; i++ ) {
|
|
// Get Positions in buffer
|
|
DPF(4,"**************Blt Source %X", pdswb->padswbs[i].pdsbe->pdsb );
|
|
|
|
pdsbeSrc = pdswb->padswbs[i].pdsbe;
|
|
|
|
pdswb->padswbs[i].cbBufferSize =
|
|
pdswb->padswbs[i].pdsbe->pdsb->cbBufferSize;
|
|
|
|
// Since these are emulated buffers, we do not need to lock them
|
|
// since they are just system meory
|
|
|
|
// Copy may be in 2 sections to end of buffer
|
|
// and from start of buffer
|
|
|
|
// If required set sourc or dest based on position
|
|
if( pdswb->padswbs[i].fdwWaveBltBuffer & DSBBLTSRC_SRCCURRENTPOS ) {
|
|
hrslt = pdsbeSrc->lpVtbl->
|
|
GetCurrentPosition((LPDIRECTSOUNDBUFFER)pdsbeSrc,
|
|
&(pdswb->padswbs[i].dwPlay),
|
|
&(pdswb->padswbs[i].dwWrite) );
|
|
if(DS_OK != hrslt) {
|
|
DPF(1,"DS get position failed return %ld ", hrslt);
|
|
LEAVE_DLL_CSECT();
|
|
return hrslt;
|
|
}
|
|
|
|
DPF(5, "Src Postion Play %X", pdswb->padswbs[i].dwPlay );
|
|
DPF(5, "Src Postion Write %X", pdswb->padswbs[i].dwWrite );
|
|
|
|
pdswb->padswbs[i].dwPosition = pdswb->padswbs[i].dwPlay;
|
|
}
|
|
|
|
DPF(4,"Wave BLT SRC Pos %X",pdswb->padswbs[i].dwPosition );
|
|
|
|
pdswb->padswbs[i].cbCopyLength = 0x0800000;
|
|
if( !(pdswb->padswbs[i].fdwWaveBltBuffer & DSBBLT_BLTTODSTEND) ) {
|
|
// Limit size to end of buffer
|
|
DPF(5," Wave BLT src LIMIT NOLOOP");
|
|
pdswb->padswbs[i].cbCopyLength =
|
|
pdswb->padswbs[i].cbBufferSize -
|
|
pdswb->padswbs[i].dwPosition;
|
|
}
|
|
DPF(5,"Wave BLT copy length %X", pdswb->padswbs[i].cbCopyLength );
|
|
|
|
|
|
pdswb->padswbs[i].cbLeftToCopy = pdswb->padswbs[i].cbCopyLength;
|
|
|
|
DPF(5,"Wave BLT OBJ src %X",pdswb->padswbs[i].pdsbe->pdsb );
|
|
DPF(5,"Wave BLT obj buffer %X",pdswb->padswbs[i].pdsbe->pdsb->pDSBuffer );
|
|
DPF(5,"Wave BLT SRC Pos %X",pdswb->padswbs[i].dwPosition );
|
|
DPF(5,"Wave BLT SRC Length %X",pdswb->padswbs[i].cbCopyLength );
|
|
|
|
|
|
}
|
|
|
|
// Grab the mix buffer -
|
|
// Mix buffer is 32 bit so size the copies as Mix/2 or Mix/4
|
|
pMixBuffer = pdsbDst->pMixBuffer;
|
|
cbMixBufferSize = pdsbDst->cbMixBufferSize;
|
|
if( pdsbDst->pwfx->wBitsPerSample == 16 ) {
|
|
cbAdjustedMixBuffer = cbMixBufferSize / 2;
|
|
} else {
|
|
cbAdjustedMixBuffer = cbMixBufferSize / 4;
|
|
}
|
|
|
|
|
|
|
|
#ifdef NOCOMP
|
|
if( (pdswb->dwCount == 1) &&
|
|
(pdswb->fdwWaveBlt & DSBBLT_COPY) ) {
|
|
// Blt is jsut a copy from one src to dest don't need mix
|
|
|
|
} else {
|
|
#endif
|
|
|
|
if( pdswb->dwCount == 0 ) {
|
|
// No source buffers
|
|
// Just blank out the dest buffer.....
|
|
DPF(5, "silence dst pos %X lenght %X ",
|
|
dwDstPosition,
|
|
pdswb->cbCopyLength );
|
|
if( pdsbDst->pwfx->wBitsPerSample == 8 ) {
|
|
// Eight bit set to NULL value of 128
|
|
// Check for wrap around end
|
|
_fmemset( pDstBuffer, 128, dwDstLock );
|
|
if( dwDstLock2 ) {
|
|
_fmemset( pDstBuffer2, 128, dwDstLock2 );
|
|
}
|
|
} else {
|
|
// Sixteen bit set to NULL value of 0
|
|
// Check for wrap around end
|
|
_fmemset( pDstBuffer, 0, dwDstLock );
|
|
if( dwDstLock2 ) {
|
|
_fmemset( pDstBuffer2, 0, dwDstLock2 );
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Blt is not a simple blt - use mix buffer
|
|
|
|
int cbRemainingDstCopy;
|
|
|
|
cbRemainingDstCopy = pdswb->cbCopyLength;
|
|
|
|
DPF(5, "Start mix loop cbCopyLength %x", cbRemainingDstCopy);
|
|
do {
|
|
int cbThisDstCopy;
|
|
|
|
cbThisDstCopy = min(cbRemainingDstCopy, cbAdjustedMixBuffer);
|
|
ASSERT(cbThisDstCopy > 0);
|
|
|
|
DPF(5, "\n\ncbThisDstCopy %x\n", cbThisDstCopy);
|
|
|
|
DPF(5, "Begin Mix session pMix %X ", pMixBuffer );
|
|
DPF(5, "Begin Mix session cbMixSize %X ", cbMixBufferSize );
|
|
DPF(5, "Begin Mix session helinfo %X ", pHelInfo );
|
|
DPF(5, "Begin Mix session dst length %X ", cbThisDstCopy );
|
|
{
|
|
MIXSESSION mixSession;
|
|
|
|
mixSession.pBuildBuffer = pMixBuffer;
|
|
mixSession.dwBuildSize = cbMixBufferSize;
|
|
mixSession.HALOutStrBuf = *pHelInfo;
|
|
mixSession.pBuffer = pdsbDst->pDSBuffer;
|
|
mixSession.cbBuffer = pdsbDst->cbBufferSize;
|
|
mixSession.nOutputBytes = cbThisDstCopy;
|
|
|
|
mixBeginSession(&mixSession);
|
|
}
|
|
|
|
// Check to see if we mix into the src buffer fist
|
|
if( pdswb->fdwWaveBlt & DSBBLT_COPY ) {
|
|
DPF(5,"Wave BLT copy - do not first copy dst ");
|
|
} else {
|
|
|
|
MIXINPUT mixInput;
|
|
DWORD dw;
|
|
|
|
DPF(5,"Wave BLT Mix");
|
|
|
|
DPF(5, "DST HEL MIX Buf helInfo %X ", pHelInfo);
|
|
DPF(5, "DST HEL MIX position %X ", dwDstPosition );
|
|
DPF(5, "DST HEL MIX length %X ", cbThisDstCopy );
|
|
DPF(5, "DST HEL MIX build pos %X ", 0 );
|
|
|
|
dw = dwDstPosition;
|
|
mixInput.HALInStrBuf = *pHelInfo;
|
|
mixInput.pBuffer = pdsbDst->pDSBuffer;
|
|
mixInput.cbBuffer = pdsbDst->cbBufferSize;
|
|
mixInput.pdwInputPos = &dw;
|
|
mixInput.dwInputBytes = cbThisDstCopy;
|
|
mixInput.dwOutputOffset = 0;
|
|
|
|
mixMixSession(&mixInput);
|
|
}
|
|
|
|
// For each source buffer mix into mix buffer
|
|
for( i = 0; i < pdswb->dwCount; i++ ) {
|
|
|
|
MIXINPUT mixInput;
|
|
DWORD dwPosition;
|
|
|
|
DPF(5, " HEL MIX Buf helInfo %X ", &(pdswb->padswbs[i].pdsbe->pdsb->helInfo) );
|
|
DPF(5, " HEL MIX position %X ", pdswb->padswbs[i].dwPosition );
|
|
DPF(5, " HEL MIX length %X ", pdswb->padswbs[i].cbLeftToCopy );
|
|
DPF(5, " HEL MIX build pos %X ", 0 );
|
|
|
|
if (pdswb->padswbs[i].cbLeftToCopy > 0) {
|
|
|
|
int cbCopied;
|
|
|
|
mixInput.HALInStrBuf = pdswb->padswbs[i].pdsbe->pdsb->helInfo;
|
|
mixInput.pBuffer = pdswb->padswbs[i].pdsbe->pdsb->pDSBuffer;
|
|
mixInput.cbBuffer = pdswb->padswbs[i].pdsbe->pdsb->cbBufferSize;
|
|
mixInput.pdwInputPos = &dwPosition;
|
|
mixInput.dwInputBytes = pdswb->padswbs[i].cbLeftToCopy;
|
|
mixInput.dwOutputOffset = 0;
|
|
|
|
dwPosition = pdswb->padswbs[i].dwPosition;
|
|
mixMixSession(&mixInput);
|
|
|
|
// Because of resampling, the position may wrap past
|
|
// beginning of buffer. You'll have to understand the
|
|
// mixer code if you wanna know why. This can make
|
|
// cbLeftToCopy go below 0.
|
|
cbCopied = dwPosition - pdswb->padswbs[i].dwPosition;
|
|
if (dwPosition <= pdswb->padswbs[i].dwPosition) {
|
|
cbCopied += pdswb->padswbs[i].cbBufferSize;
|
|
}
|
|
pdswb->padswbs[i].cbLeftToCopy -= cbCopied;
|
|
pdswb->padswbs[i].dwPosition = dwPosition;
|
|
|
|
DPF(5, " HEL MIX NEW position %X ", pdswb->padswbs[i].dwPosition );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// When all secondary buffers have been mixed into the build buffer,
|
|
// copy the build buffer to the output stream
|
|
//
|
|
|
|
DPF(5, "Write Mix position %X ", dwDstPosition );
|
|
mixWriteSession(dwDstPosition);
|
|
|
|
dwDstPosition = (dwDstPosition + cbThisDstCopy) % pdsbDst->cbBufferSize;
|
|
cbRemainingDstCopy -= cbThisDstCopy;
|
|
ASSERT(cbRemainingDstCopy >= 0);
|
|
|
|
// DPF(3,"End Mix Position");
|
|
|
|
} while (cbRemainingDstCopy > 0);
|
|
}
|
|
|
|
// Done copy - unlock buffers
|
|
DPF(5,"done copy - unlock now Dest %X", pidsbDst);
|
|
hrslt = pidsbDst->lpVtbl->Unlock(pidsbDst,pDstBuffer, dwDstLock,
|
|
pDstBuffer2, dwDstLock2);
|
|
if(DS_OK != hrslt)
|
|
{
|
|
DPF(1,"DS Buffer UnLock failed ");
|
|
LEAVE_DLL_CSECT();
|
|
return hrslt;
|
|
}
|
|
|
|
DPF(4,"Exiting wave blt method");
|
|
LEAVE_DLL_CSECT();
|
|
return DS_OK;
|
|
} // IDSHWBufferWaveBlt()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// void DSBufferCreateTable
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// LPDSOUNDBUFFERCALLBACKS lpVtbl:
|
|
//
|
|
// Return (void):
|
|
//
|
|
// History:
|
|
// 02/17/95 Fwong
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
void FNGLOBAL DSHWBufferCreateTable
|
|
(
|
|
LPDSOUNDBUFFERCALLBACKS lpVtbl
|
|
)
|
|
{
|
|
DPF(4,"Entering HW buffer create table");
|
|
|
|
lpVtbl->QueryInterface = IDSHWBufferQueryInterface;
|
|
lpVtbl->AddRef = IDSHWBufferAddRef;
|
|
lpVtbl->Release = IDSHWBufferRelease;
|
|
lpVtbl->GetCaps = IDSHWBufferGetCaps;
|
|
lpVtbl->GetCurrentPosition = IDSHWBufferGetCurrentPosition;
|
|
lpVtbl->GetFormat = IDSHWBufferGetFormat;
|
|
lpVtbl->GetVolume = IDSHWBufferGetVolume;
|
|
lpVtbl->GetPan = IDSHWBufferGetPan;
|
|
lpVtbl->GetFrequency = IDSHWBufferGetFrequency;
|
|
lpVtbl->GetStatus = IDSHWBufferGetStatus;
|
|
lpVtbl->Initialize = IDSHWBufferInitialize;
|
|
lpVtbl->Lock = IDSHWBufferLock;
|
|
lpVtbl->Play = IDSHWBufferPlay;
|
|
lpVtbl->SetCurrentPosition = IDSHWBufferSetCurrentPosition;
|
|
lpVtbl->SetFormat = IDSHWBufferSetFormat;
|
|
lpVtbl->SetVolume = IDSHWBufferSetVolume;
|
|
lpVtbl->SetPan = IDSHWBufferSetPan;
|
|
lpVtbl->SetFrequency = IDSHWBufferSetFrequency;
|
|
lpVtbl->Stop = IDSHWBufferStop;
|
|
lpVtbl->Unlock = IDSHWBufferUnlock;
|
|
lpVtbl->Restore = IDSHWBufferRestore;
|
|
|
|
|
|
DPF(4,"Exiting HW buffer create table");
|
|
} // DSHWBufferCreateTable()
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// void DSBufferActivate
|
|
//
|
|
// Description:
|
|
// This is called on an external buffer object to notify the buffer that
|
|
// the owning app has been activated (i.e., the app gains sound focus).
|
|
//
|
|
// Arguments:
|
|
// LPDSBUFFEREXTERNAL:
|
|
//
|
|
// Return (void):
|
|
//
|
|
// History:
|
|
// 08/01/95 FrankYe
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void DSBufferActivate(LPDSBUFFEREXTERNAL pdsbe)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
LONG lVolume;
|
|
LONG lPan;
|
|
LONG lTotalLeftDB;
|
|
LONG lTotalRightDB;
|
|
DSVOLUMEPAN dsVolPan;
|
|
|
|
ASSERT(VALID_DSBUFFERE_PTR(pdsbe));
|
|
|
|
pdsb = pdsbe->pdsb;
|
|
ASSERT(VALID_DSBUFFER_PTR(pdsb) && (0 != pdsbe->uRefCount));
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
pds = pdsb->pds;
|
|
|
|
// Don't need to do anything on primary buffers
|
|
if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) return;
|
|
|
|
pdsb->fMixerMute = FALSE;
|
|
|
|
// On software buffers, reseting the fMuteMixer flag is enough
|
|
// and the mixer does the rest.
|
|
if (0 == (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) return;
|
|
|
|
// For hardware buffers...
|
|
|
|
// Restore volume levels
|
|
lVolume = pdsb->helInfo.lVolume;
|
|
lPan = pdsb->helInfo.lPan;
|
|
|
|
// Compute multpliers (scaling factors) for the mixer to use
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
lTotalLeftDB = lVolume - lPan ;
|
|
lTotalRightDB = lVolume;
|
|
} else {
|
|
// right is attenuated
|
|
lTotalLeftDB = lVolume;
|
|
lTotalRightDB = lVolume - (-lPan);
|
|
}
|
|
|
|
dsVolPan.dwTotalLeftAmpFactor = DBToAmpFactor(lTotalLeftDB);
|
|
dsVolPan.dwTotalRightAmpFactor = DBToAmpFactor(lTotalRightDB);
|
|
|
|
dsVolPan.lVolume = lVolume;
|
|
dsVolPan.dwVolAmpFactor = DBToAmpFactor(lVolume);
|
|
|
|
dsVolPan.lPan = pdsb->helInfo.lPan;
|
|
if (lPan >= 0) {
|
|
// left is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(-lPan);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(0);
|
|
} else {
|
|
// right is attenuated
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(0);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(lPan);
|
|
}
|
|
|
|
pdsb->helInfo.dwLVolume = dsVolPan.dwTotalLeftAmpFactor;
|
|
pdsb->helInfo.dwRVolume = dsVolPan.dwTotalRightAmpFactor;
|
|
pdsb->helInfo.dwMVolume = (pdsb->helInfo.dwLVolume + pdsb->helInfo.dwRVolume)/2;
|
|
|
|
vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan );
|
|
|
|
return;
|
|
} // DSBufferActivate()
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// void DSBufferDeactivate
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// LPDSBUFFEREXTERNAL:
|
|
//
|
|
// Return (void):
|
|
//
|
|
// History:
|
|
// 08/01/95 FrankYe
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void DSBufferDeactivate(LPDSBUFFEREXTERNAL pdsbe)
|
|
{
|
|
LPDSOUND pds;
|
|
LPDSBUFFER pdsb;
|
|
DSVOLUMEPAN dsVolPan;
|
|
|
|
ASSERT(VALID_DSBUFFERE_PTR(pdsbe));
|
|
|
|
pdsb = pdsbe->pdsb;
|
|
ASSERT(VALID_DSBUFFER_PTR(pdsb) && (0 != pdsbe->uRefCount));
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
pds = pdsb->pds;
|
|
|
|
pdsb->fMixerMute = TRUE;
|
|
|
|
// For software buffers, setting fMixerMute is enough
|
|
// and the mixer does the rest.
|
|
if (0 == (pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) return;
|
|
|
|
// Non-WRITEPRIMARY primary buffers need nothing done. If this is a
|
|
// primary buffer for a WRITEPRIMARY app, we need to mark it as lost
|
|
// and fill the buffer with silence.
|
|
if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
|
|
|
|
if (pdsbe->dwPriority < DSSCL_WRITEPRIMARY) return;
|
|
|
|
DPF(1, "DsBufferDeactivate: note: losing primary dsbe %08Xh", pdsbe);
|
|
|
|
// If the app's primary buffer is locked and we have an alias buffer ptr
|
|
// then we redirect the alias ptr to some dummy buffer. That way, the
|
|
// app can keep writing to the ptr and the data goes into the bit
|
|
// bucket (actually, the data goes into the dummy buffer).
|
|
if (pdsbe->pDSBufferAlias && (pdsbe->cLocks)) {
|
|
BOOL fSuccess;
|
|
DPF(1, "DsBufferDeactivate: note: losing primary while locked");
|
|
fSuccess = vxdMemRedirectAlias(pdsbe->pDSBufferAlias, pdsb->cbBufferSize);
|
|
ASSERT(fSuccess);
|
|
}
|
|
|
|
DsbFillSilence(pdsb);
|
|
|
|
pdsbe->fdwDsbeI |= DSBE_INTERNALF_LOST;
|
|
return;
|
|
}
|
|
|
|
dsVolPan.dwTotalLeftAmpFactor = DBToAmpFactor(-10000);
|
|
dsVolPan.dwTotalRightAmpFactor = DBToAmpFactor(-10000);
|
|
|
|
dsVolPan.lVolume = -10000;
|
|
dsVolPan.dwVolAmpFactor = DBToAmpFactor(-10000);
|
|
|
|
dsVolPan.lPan = 0;
|
|
dsVolPan.dwPanLeftAmpFactor = DBToAmpFactor(0);
|
|
dsVolPan.dwPanRightAmpFactor = DBToAmpFactor(0);
|
|
|
|
vxdBufferSetVolumePan( pdsb->hBuffer, &dsVolPan );
|
|
|
|
return;
|
|
}
|