mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
659 lines
18 KiB
659 lines
18 KiB
//--------------------------------------------------------------------------;
|
|
//
|
|
// File: idsbi.c
|
|
//
|
|
// Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Abstract:
|
|
// This file contains worker functions called internally by
|
|
// IDirectSoundBuffer member functions. These
|
|
// functions do not perform parameter validation, nor do they
|
|
// take critical sections. In all cases, the calling function is
|
|
// responsible for doing this.
|
|
//
|
|
// Contents:
|
|
// IDsbSetFormatI
|
|
// IDsbStopI
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
#include "dsoundpr.h"
|
|
#include "grace.h"
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// LPWAVEFORMATEX wfxAllocDuplicate
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
LPWAVEFORMATEX wfxAllocDuplicate(LPWAVEFORMATEX pwfx)
|
|
{
|
|
LPWAVEFORMATEX pwfxDup;
|
|
int cbFormat;
|
|
|
|
cbFormat = SIZEOF_WAVEFORMATEX(pwfx);
|
|
pwfxDup = MemAlloc(cbFormat);
|
|
if (NULL == pwfxDup) return NULL;
|
|
CopyMemory(pwfxDup, pwfx, cbFormat);
|
|
return pwfxDup;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// BOOL wfxEqual
|
|
//
|
|
// Description:
|
|
// This function determines whether two wave formats are equal.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
BOOL wfxEqual(LPWAVEFORMATEX pwfxA, LPWAVEFORMATEX pwfxB)
|
|
{
|
|
int cbA;
|
|
int cbB;
|
|
|
|
cbA = SIZEOF_WAVEFORMATEX(pwfxA);
|
|
cbB = SIZEOF_WAVEFORMATEX(pwfxB);
|
|
|
|
if (cbA != cbB) return FALSE;
|
|
|
|
return (0 == memcmp(pwfxA, pwfxB, cbA));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// void DsbFillSilence
|
|
//
|
|
// Description:
|
|
// This function fills a buffer with silence.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void DsbFillSilence(LPDSBUFFER pdsb)
|
|
{
|
|
LPVOID pBuffer1;
|
|
LPVOID pBuffer2;
|
|
DWORD cbBufferSize1;
|
|
DWORD cbBufferSize2;
|
|
BOOL fNeedLock;
|
|
HRESULT hr;
|
|
|
|
|
|
ASSERT(VALID_DSBUFFER_PTR(pdsb));
|
|
ASSERT(DSBUFFSIG == pdsb->dwSig);
|
|
ASSERT(VALID_WAVEFORMATEX_PTR(pdsb->pwfx));
|
|
|
|
ASSERT(WAVE_FORMAT_PCM == pdsb->pwfx->wFormatTag);
|
|
|
|
|
|
hr = DS_OK;
|
|
|
|
fNeedLock = ( (pdsb->fdwDsbI&DSB_INTERNALF_HARDWARE) &&
|
|
( ( (pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) &&
|
|
!(pdsb->pds->fdwDriverDesc&DSDDESC_DONTNEEDPRIMARYLOCK) ) ||
|
|
( !(pdsb->fdwDsbI&DSB_INTERNALF_PRIMARY) &&
|
|
!(pdsb->pds->fdwDriverDesc&DSDDESC_DONTNEEDSECONDARYLOCK) ) ));
|
|
|
|
|
|
if( fNeedLock )
|
|
{
|
|
ASSERT( !(pdsb->fdwDsbI&DSB_INTERNALF_WAVEEMULATED) );
|
|
|
|
pBuffer1 = pdsb->pDSBuffer;
|
|
pBuffer2 = NULL;
|
|
cbBufferSize1 = pdsb->cbBufferSize;
|
|
cbBufferSize2 = 0;
|
|
|
|
hr = vxdBufferLock( pdsb->hBuffer, &pBuffer1, &cbBufferSize1,
|
|
&pBuffer2, &cbBufferSize2, 0,
|
|
cbBufferSize1, 0 );
|
|
|
|
DPF(4,"DsbFillSilence: locking entire buffer pdsb=0x%8x, hr=%lu.",pdsb,hr);
|
|
DPF(5,"DsbFillSilence: pBuffer1=0x%8x, cbBufferSize1=%lu, pBuffer2=0x%8x, cbBufferSize2=%lu",pBuffer1,cbBufferSize1,pBuffer2,cbBufferSize2);
|
|
|
|
// Validate that we really locked what we wanted or got an error.
|
|
ASSERT( (DS_OK!=hr) || (pBuffer1==pdsb->pDSBuffer) );
|
|
ASSERT( (DS_OK!=hr) || (pBuffer2==NULL) );
|
|
ASSERT( (DS_OK!=hr) || (cbBufferSize1==pdsb->cbBufferSize) );
|
|
ASSERT( (DS_OK!=hr) || (cbBufferSize2==0) );
|
|
}
|
|
|
|
if( DS_OK == hr )
|
|
{
|
|
//
|
|
// Write the silence.
|
|
//
|
|
if (8 == pdsb->pwfx->wBitsPerSample) {
|
|
FillMemory(pdsb->pDSBuffer, pdsb->cbBufferSize, 0x80);
|
|
} else {
|
|
ASSERT(16 == pdsb->pwfx->wBitsPerSample);
|
|
FillMemory(pdsb->pDSBuffer, pdsb->cbBufferSize, 0x00);
|
|
}
|
|
|
|
if( fNeedLock )
|
|
{
|
|
DPF(5,"DsbFillSilence: unlocking buffer");
|
|
vxdBufferUnlock( pdsb->hBuffer, pBuffer1, cbBufferSize1,
|
|
pBuffer2, cbBufferSize2 );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// void DsbSetFormatHelInfo
|
|
//
|
|
// Description:
|
|
// This function sets pdsb->helinfo format info of a buffer.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
void DsbSetFormatHelInfo(LPDSBUFFER pdsb, LPWAVEFORMATEX pwfx)
|
|
{
|
|
//Set the helInfo stuff
|
|
pdsb->helInfo.dwSampleRate = pwfx->nSamplesPerSec;
|
|
pdsb->helInfo.hfFormat = 0;
|
|
if( pwfx->wFormatTag == WAVE_FORMAT_PCM ) {
|
|
if( pdsb->pwfx->wBitsPerSample == 8 ) {
|
|
pdsb->helInfo.hfFormat |= (H_8_BITS | H_UNSIGNED);
|
|
} else {
|
|
pdsb->helInfo.hfFormat |= (H_16_BITS | H_SIGNED);
|
|
}
|
|
if( pwfx->nChannels == 2 ) {
|
|
pdsb->helInfo.hfFormat |= (H_STEREO | H_ORDER_LR);
|
|
} else {
|
|
pdsb->helInfo.hfFormat |= H_MONO;
|
|
}
|
|
}
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_LOOPING ) {
|
|
pdsb->helInfo.hfFormat |= H_LOOP;
|
|
} else {
|
|
pdsb->helInfo.hfFormat |= H_NO_LOOP;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
pdsb->cSamples = pdsb->cbBufferSize / pdsb->pwfx->nBlockAlign;
|
|
|
|
switch (pdsb->pwfx->nBlockAlign) {
|
|
case 1:
|
|
pdsb->uBlockAlignShift = 0;
|
|
break;
|
|
case 2:
|
|
pdsb->uBlockAlignShift = 1;
|
|
break;
|
|
case 4:
|
|
pdsb->uBlockAlignShift = 2;
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT IDsbSetFormatI
|
|
//
|
|
// Description:
|
|
// This function sets the format on the primary buffer.
|
|
//
|
|
// Notes: There are a bunch of checks inside this function to determine
|
|
// if this is the primary buffer. I have left them in just because
|
|
// I didn't want to bother checking them out. They are probably all
|
|
// redundant.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
HRESULT IDsbSetFormatI
|
|
(
|
|
LPDSBUFFER pdsb,
|
|
LPWAVEFORMATEX pwfx,
|
|
UINT uFlags
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
DWORD dwSize;
|
|
LPWAVEFORMATEX pwfxNew;
|
|
LPWAVEFORMATEX pwfxOld;
|
|
MMRESULT mmr;
|
|
HRESULT hrClient;
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Make sure we're being called in a good state.
|
|
//
|
|
ASSERT( NULL != pdsb );
|
|
ASSERT( VALID_DSBUFFER_PTR(pdsb) );
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
ASSERT( pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY );
|
|
ASSERT( pdsb == pdsb->pds->pdsbPrimary );
|
|
ASSERT( NULL != pwfx );
|
|
ASSERT( ValidPCMFormat( pwfx ) );
|
|
ASSERT( NULL != pdsb->pwfx );
|
|
|
|
pds = pdsb->pds;
|
|
|
|
dwSize = SIZEOF_WAVEFORMATEX(pwfx);
|
|
|
|
if (!(uFlags & IDSBSETFORMATIF_ALWAYS) && wfxEqual(pdsb->pwfx, pwfx)) {
|
|
// Don't waste my time, you... you... you... waster of my time!!!
|
|
DPF(3, "IDsbSetFormatI: note: same format");
|
|
return DS_OK;
|
|
}
|
|
|
|
pwfxOld = pdsb->pwfx;
|
|
pwfxNew = wfxAllocDuplicate(pwfx);
|
|
if(NULL == pwfxNew) return DSERR_OUTOFMEMORY;
|
|
pdsb->pwfx = pwfxNew;
|
|
|
|
// Handle the setting of the wave emulated primary separatly
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
DPF(4, "Changed emulator primary format");
|
|
|
|
// ??? Can we optimize this process at all? Do we need to?
|
|
//
|
|
DSShutdownEmulator(pds);
|
|
// In this case, the looping buffer will not be free'd
|
|
// because that is normally the job of the release code for
|
|
// the primary. Do it now.
|
|
//
|
|
MemFree(pds->pLoopingBuffer);
|
|
pds->pLoopingBuffer = NULL;
|
|
pds->pdsbPrimary->pDSBuffer = NULL;
|
|
|
|
DsbSetFormatHelInfo(pdsb, pdsb->pwfx);
|
|
|
|
mmr = DSInitializeEmulator(pds);
|
|
if (mmr) {
|
|
DPF(0,"Attempt to reinitialize emulator failed! %u",mmr);
|
|
if (WAVERR_BADFORMAT == mmr) {
|
|
hrClient = DSERR_BADFORMAT;
|
|
} else if (MMSYSERR_NOMEM == mmr) {
|
|
hrClient = DSERR_OUTOFMEMORY;
|
|
} else {
|
|
hrClient = DSERR_GENERIC;
|
|
}
|
|
|
|
// Try to restore the old format
|
|
MemFree(pdsb->pwfx);
|
|
pdsb->pwfx = pwfxOld;
|
|
pwfxOld = NULL;
|
|
DsbSetFormatHelInfo(pdsb, pdsb->pwfx);
|
|
mmr = DSInitializeEmulator(pds);
|
|
if (mmr) {
|
|
DPF(0, "IDsbSetFormatI: !note: couldn't restore old format");
|
|
DPF(0, " DsInitializeEmulator returned %08Xh", mmr);
|
|
}
|
|
|
|
return hrClient;
|
|
}
|
|
|
|
DPF(3,"Exiting buffer set format method");
|
|
|
|
MemFree(pwfxOld);
|
|
|
|
return DS_OK;
|
|
}
|
|
|
|
// Set the format to the device
|
|
DPF(3," Change HW format format %X freq %X",
|
|
pdsb->helInfo.hfFormat, pdsb->helInfo.dwSampleRate );
|
|
|
|
hrClient = DS_OK;
|
|
hr = DS_OK;
|
|
|
|
// We stop the primary when setting formats. If it wasn't already
|
|
// stopped, then we need to put the mixer into a RESTART state.
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
|
|
DWORD dwPlay, dwWrite;
|
|
LONG posPlay;
|
|
|
|
hr = vxdBufferGetPosition(pdsb->hBuffer, &dwPlay, &dwWrite);
|
|
vxdBufferStop(pdsb->hBuffer);
|
|
if (DS_OK != hr) {
|
|
DPF(0, "IDsbSetFormatI: !note: vxdBufferGetPosition returned %08Xh", hr);
|
|
pdsb->iMixerState = DSPBMIXERSTATE_START;
|
|
} else {
|
|
posPlay = dwPlay >> pdsb->uBlockAlignShift;
|
|
pds->dposPRemix = pdsb->posNextMix - posPlay;
|
|
if (pds->dposPRemix < 0) pds->dposPRemix += pdsb->cSamples;
|
|
ASSERT(pds->dposPRemix >= 0);
|
|
pds->dposPRemix = MulDivRN(pds->dposPRemix,
|
|
pdsb->pwfx->nSamplesPerSec,
|
|
pwfxOld->nSamplesPerSec);
|
|
pdsb->iMixerState = DSPBMIXERSTATE_RESTART;
|
|
}
|
|
hr = DS_OK;
|
|
}
|
|
|
|
DsbSetFormatHelInfo(pdsb, pdsb->pwfx);
|
|
|
|
if (DSDDESC_DOMMSYSTEMSETFORMAT & pds->fdwDriverDesc) {
|
|
//
|
|
// We need to set the wave format by doing a waveOutOpen on the
|
|
// mmsystem wave device
|
|
//
|
|
UINT uDeviceID;
|
|
MMRESULT mmr;
|
|
|
|
DPF(3, "IDsbSetFormatI: DSDDESC_DOMMSYSTEMSETFORMAT");
|
|
|
|
ASSERT(pds->hwo);
|
|
waveOutGetID(pds->hwo, &uDeviceID);
|
|
|
|
HelperWaveClose( (DWORD)(pds->hwo) );
|
|
pds->hwo = NULL;
|
|
|
|
mmr = (MMRESULT)HelperWaveOpen(&(pds->hwo), uDeviceID, pdsb->pwfx);
|
|
if (MMSYSERR_NOERROR != mmr) {
|
|
|
|
DPF(0, "IDsbSetFormatI: error: HelperWaveOpen returned %08Xh", mmr);
|
|
if (WAVERR_BADFORMAT == mmr) {
|
|
hrClient = DSERR_BADFORMAT;
|
|
} else if (MMSYSERR_NOMEM == mmr) {
|
|
hrClient = DSERR_OUTOFMEMORY;
|
|
} else {
|
|
hrClient = DSERR_GENERIC;
|
|
}
|
|
|
|
// Try to reset the old format
|
|
MemFree(pdsb->pwfx);
|
|
pdsb->pwfx = pwfxOld;
|
|
pwfxOld = NULL;
|
|
|
|
DsbSetFormatHelInfo(pdsb, pdsb->pwfx);
|
|
mmr = HelperWaveOpen(&(pds->hwo), uDeviceID, pdsb->pwfx);
|
|
if (mmr) {
|
|
DPF(0, "IDsbSetFormatI: error: couldn't restore old format HelperWaveOpen returned %08Xh", mmr);
|
|
// Well, we're in a world of shit. We can't seem to
|
|
// open the wave device.
|
|
hr = DSERR_GENERIC;
|
|
if (MMSYSERR_NOMEM == mmr) {
|
|
// Might as well return this one instead of whatever was
|
|
// in hrClient
|
|
hrClient = DSERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Below this point, if pwfxOld==NULL, then we are trying to restore
|
|
// the original format because there was a failure setting the new format
|
|
// pdsb->pwfx and the associated helInfo are for the old format. hrClient
|
|
// should contain a proper return code.
|
|
//
|
|
// if (hr != DS_OK) then we have an unrecoverable error condition, so
|
|
// pack up our bags and bail. We should have tried restoring the old
|
|
// format in such a case, so pwfxOld should be NULL and hrClient should
|
|
// contain the proper return code.
|
|
if (DS_OK != hr) {
|
|
ASSERT(NULL == pwfxOld);
|
|
ASSERT(DS_OK != hrClient);
|
|
return hrClient;
|
|
}
|
|
|
|
// If the driver specified DOMMSYSTEMSETFORMAT, this call
|
|
// is just a notification to the ds driver that we've set the
|
|
// format through waveOutOpen. It is okay for the driver to
|
|
// return DS_NOTSUPPORTED in that case.
|
|
hr = vxdBufferSetFormat(pdsb->hBuffer, pdsb->pwfx);
|
|
if ((DSDDESC_DOMMSYSTEMSETFORMAT & pds->fdwDriverDesc) && (DSERR_UNSUPPORTED == hr)) {
|
|
hr = DS_OK;
|
|
}
|
|
if (DS_OK != hr) {
|
|
|
|
DPF(0,"IDsbSetFormatI: error: vxdBufferSetFormat returned %08Xh", hr);
|
|
|
|
// If we've already tried restoring the old format, then we're in
|
|
// real trouble and all we can do is return in a pretty wierd state
|
|
if (NULL == pwfxOld) {
|
|
return hrClient;
|
|
}
|
|
|
|
// try to restore old format
|
|
hrClient = hr;
|
|
MemFree(pdsb->pwfx);
|
|
pdsb->pwfx = pwfxOld;
|
|
pwfxOld = NULL;
|
|
DsbSetFormatHelInfo(pdsb, pdsb->pwfx);
|
|
hr = vxdBufferSetFormat(pdsb->hBuffer, pdsb->pwfx);
|
|
if (DS_OK != hr) {
|
|
// We're in real trouble here!
|
|
DPF(0,"IDsbSetFormatI: error: couldn't restore old format vxdBufferSetFormat returned %08Xh", hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
DsbFillSilence(pdsb);
|
|
|
|
|
|
// We need to re-start it if it was playing
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
|
|
vxdBufferPlay(pdsb->hBuffer, 0, 0, DSBPLAY_LOOPING );
|
|
if (!(pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
|
|
mxSignalRemix(pds, 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
if (NULL == pwfxOld) {
|
|
// We must have restored the old format. We should be returning an
|
|
// error to the client in hrClient but we have successfully restored
|
|
// the old format (i.e. hr == DS_OK).
|
|
ASSERT(DS_OK != hrClient);
|
|
ASSERT(DS_OK == hr);
|
|
} else {
|
|
// We must have successfully set the new format. No errors
|
|
ASSERT(DS_OK == hrClient);
|
|
ASSERT(DS_OK == hr);
|
|
MemFree(pwfxOld);
|
|
}
|
|
|
|
return hrClient;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT IDsbSetCurrentPositionI
|
|
//
|
|
// Description:
|
|
//
|
|
// Arguments:
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
HRESULT IDsbSetCurrentPositionI
|
|
(
|
|
LPDSBUFFER pdsb,
|
|
DWORD dwNewPos
|
|
)
|
|
{
|
|
HRESULT hr = DS_OK;
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
// Set Position on HW buffer
|
|
hr = vxdBufferSetPosition(pdsb->hBuffer, dwNewPos );
|
|
} else {
|
|
// Set new position on the buffer. If this buffer is playing,
|
|
// then signal the mixer about it.
|
|
pdsb->posNextMix = dwNewPos >> pdsb->uBlockAlignShift;
|
|
|
|
// For waveem case, we need to modify the "mixed from" position
|
|
// for each of the remembered mixes.
|
|
if (DS_INTERNALF_WAVEEMULATED & pdsb->pds->fdwInternal) {
|
|
int i;
|
|
for (i = 0; i < NUMELMS(pdsb->aposWhMix); i++) {
|
|
pdsb->aposWhMix[i] = dwNewPos >> pdsb->uBlockAlignShift;
|
|
}
|
|
}
|
|
|
|
// For native mode buffers that are playing, we need
|
|
// to signal the mixer
|
|
if ((0 == (DS_INTERNALF_WAVEEMULATED & pdsb->pds->fdwInternal)) &&
|
|
(0 == (DSB_INTERNALF_STOP & pdsb->fdwDsbI)))
|
|
{
|
|
if (0 == (DSBMIXERSIGNAL_SETPOSITION & pdsb->fdwMixerSignal)) {
|
|
pdsb->fdwMixerSignal |= DSBMIXERSIGNAL_SETPOSITION;
|
|
// REMIND the following line should really be done in grace.cpp
|
|
// where we check for SETPOSITION flag set; and also, all those
|
|
// calls should call uMixNewBuffer, instead of looping/nonlooping.
|
|
pdsb->iMixerSubstate = DSBMIXERSUBSTATE_NEW;
|
|
mxSignalRemix(pdsb->pds, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
} // IDsbSetCurrentPositionI
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT IDsbStopI
|
|
//
|
|
// Description:
|
|
// This function stops the specified buffer.
|
|
//
|
|
// Arguments:
|
|
// pdsb: Buffer to stop.
|
|
// fAutoStop: TRUE if the buffer is being stopped automatically by
|
|
// the mixer since it has been mixed to the end and is
|
|
// not a looping buffer.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
HRESULT IDsbStopI
|
|
(
|
|
LPDSBUFFER pdsb,
|
|
BOOL fAutoStop
|
|
)
|
|
{
|
|
LPDSOUND pds;
|
|
|
|
|
|
ASSERT( VALID_DSBUFFER_PTR(pdsb) );
|
|
ASSERT( DSBUFFSIG == pdsb->dwSig );
|
|
|
|
// If we're looping, we should not be called with fAutoStop set.
|
|
ASSERT( !( (pdsb->helInfo.hfFormat&H_LOOP) && fAutoStop ) );
|
|
|
|
|
|
pds = pdsb->pds;
|
|
|
|
|
|
// Are we stopped?
|
|
if((pdsb->fdwDsbI & DSB_INTERNALF_STOP)) {
|
|
DPF(1,"Stop: Already stopped!");
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
// Buffer is to stop, remove it from the mix list, save its position,
|
|
// and decrease playing count
|
|
if( (pdsb != pds->pdsbPrimary) && (!(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE)) ) {
|
|
|
|
if (DSB_INTERNALF_WAVEEMULATED & pdsb->fdwDsbI) {
|
|
// For waveem case, we need to modify the "mixed from" position
|
|
// for each of the remembered mixes.
|
|
if (DS_INTERNALF_WAVEEMULATED & pdsb->pds->fdwInternal) {
|
|
int i;
|
|
for (i = 0; i < NUMELMS(pdsb->aposWhMix); i++) {
|
|
pdsb->aposWhMix[i] = pdsb->posNextMix >> pdsb->uBlockAlignShift;
|
|
}
|
|
}
|
|
} else {
|
|
DWORD dwPlayCursor;
|
|
|
|
mxGetPosition(pdsb, &dwPlayCursor, NULL, NULL);
|
|
mxListRemove(pdsb);
|
|
|
|
// Don't want to signal a remix if we're stopping this buffer
|
|
// because we just ran off the end and we're not looping.
|
|
if( !fAutoStop )
|
|
{
|
|
mxSignalRemix(pds, 0);
|
|
}
|
|
|
|
pdsb->posNextMix = dwPlayCursor >> pdsb->uBlockAlignShift;
|
|
}
|
|
ASSERT( pds->dwBuffersPlaying >= 1 );
|
|
pds->dwBuffersPlaying--;
|
|
}
|
|
|
|
|
|
// Set new state.
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_STOP;
|
|
|
|
|
|
//
|
|
if( pds->dwBuffersPlaying > 0x7fff ) {
|
|
// We must have wrapped set to zero
|
|
pds->dwBuffersPlaying = 0;
|
|
}
|
|
|
|
|
|
// IF this is a the last secondary buffer to be stopped playing
|
|
// Then notify Just Stopped
|
|
if( !(pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE) &&
|
|
(pdsb != pds->pdsbPrimary) &&
|
|
(pds->dwBuffersPlaying == 0 ) )
|
|
{
|
|
pds->pdsbPrimary->fdwDsbI |= DSB_INTERNALF_JUSTSTOPPED;
|
|
|
|
if (0 == pds->cPlayPrimary) {
|
|
DPF(2, "IdsbStopI: note: auto stopping primary pdsb %08Xh on pds %08Xh", pds->pdsbPrimary, pds);
|
|
IDsbStopI( pds->pdsbPrimary, FALSE );
|
|
}
|
|
|
|
// CHECK CHECK Should we Zero out Primary now....?
|
|
}
|
|
|
|
|
|
|
|
// If this is not the primary then we are done.....
|
|
if( pdsb != pds->pdsbPrimary) {
|
|
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_HARDWARE ) {
|
|
// If this is a HW secondary buffer then stop it
|
|
vxdBufferStop(pdsb->hBuffer);
|
|
}
|
|
DPF(3,"Exit stop method NOT primary %X", pdsb);
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
|
|
// If this is a WaveEmulated buffer.....
|
|
if( pdsb->fdwDsbI & DSB_INTERNALF_WAVEEMULATED ) {
|
|
if(pds->pdsbPrimary == pdsb) {
|
|
DPF(3,"*********** Stopping Wave Emulated Primary %X", pdsb);
|
|
}
|
|
|
|
DPF(3,"Exit stop For WaveEmulated %X", pdsb);
|
|
return DS_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* From here down in the Stop processing only applies to stopping the
|
|
* Primary for a HW device
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
// Primary is being stopped
|
|
|
|
// This is the primary buffer so stop it playing
|
|
vxdBufferStop(pdsb->hBuffer);
|
|
|
|
pds->pdsbPrimary->fdwDsbI |= DSB_INTERNALF_JUSTSTOPPED;
|
|
|
|
return DS_OK;
|
|
}
|