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