Commit a7d6ed8e authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Alexandre Julliard

dsound: Simplify mixing by removing remixing support, and fix its waveout breakage.

Based on a patch by Peter Dons Tychsen.
parent 95912460
...@@ -236,8 +236,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume( ...@@ -236,8 +236,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
if (hres != DS_OK) if (hres != DS_OK)
WARN("IDsDriverBuffer_SetVolumePan failed\n"); WARN("IDsDriverBuffer_SetVolumePan failed\n");
} else }
DSOUND_ForceRemix(This);
} }
LeaveCriticalSection(&(This->lock)); LeaveCriticalSection(&(This->lock));
...@@ -297,8 +296,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency( ...@@ -297,8 +296,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec; This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign; This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
DSOUND_RecalcFormat(This); DSOUND_RecalcFormat(This);
if (!This->hwbuf)
DSOUND_ForceRemix(This);
} }
LeaveCriticalSection(&(This->lock)); LeaveCriticalSection(&(This->lock));
...@@ -424,29 +421,51 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p ...@@ -424,29 +421,51 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
/* we need to know how far away we are from there */ /* we need to know how far away we are from there */
if (pmix < pplay) pmix += device->buflen; /* wraparound */ if (pmix < pplay) pmix += device->buflen; /* wraparound */
pmix -= pplay; pmix -= pplay;
/* detect buffer underrun */
/* detect buffer underrun (sanity) */
if (pwrite < pplay) pwrite += device->buflen; /* wraparound */ if (pwrite < pplay) pwrite += device->buflen; /* wraparound */
pwrite -= pplay; pwrite -= pplay;
if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) { if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) {
WARN("detected an underrun: primary queue was %d\n",pmix); ERR("detected an underrun: primary queue was %d\n",pmix);
pmix = 0; pmix = 0;
} }
TRACE("primary back-samples=%d\n",pmix);
/* divide the offset by its sample size */ /* divide the offset by its sample size */
pmix /= device->pwfx->nBlockAlign; pmix /= device->pwfx->nBlockAlign;
TRACE("primary back-samples=%d\n",pmix);
/* adjust for our frequency */ /* adjust for our frequency */
pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT; pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
/* multiply by our own sample size */ /* multiply by our own sample size */
pmix *= This->pwfx->nBlockAlign; pmix *= This->pwfx->nBlockAlign;
TRACE("this back-offset=%d\n", pmix); TRACE("this back-offset=%d\n", pmix);
/* sanity */
if(pmix > This->buflen){
ERR("Bad length in CalcPlayPosition!\n");
return 0;
}
/* subtract from our last mixed position */ /* subtract from our last mixed position */
while (bplay < pmix) bplay += This->buflen; /* wraparound */ if (bplay < pmix) bplay += This->buflen; /* wraparound */
bplay -= pmix; bplay -= pmix;
/* check for lead-in */
if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) { if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
/* seems we haven't started playing yet */ /* seems we haven't started playing yet */
TRACE("this still in lead-in phase\n"); TRACE("this still in lead-in phase\n");
bplay = This->startpos; bplay = This->startpos;
} }
/* sanity */
if(bplay > This->buflen){
ERR("Bad play position in CalcPlayPosition!\n");
return 0;
}
/* return the result */ /* return the result */
return bplay; return bplay;
} }
...@@ -469,13 +488,13 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( ...@@ -469,13 +488,13 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
*playpos = This->buf_mixpos; *playpos = This->buf_mixpos;
} else if (playpos) { } else if (playpos) {
DWORD pplay, pwrite; DWORD pplay, pwrite;
/* let's get this exact; first, recursively call GetPosition on the primary */
/* get primary lock, before messing with primary/device data */
EnterCriticalSection(&(This->device->mixlock)); EnterCriticalSection(&(This->device->mixlock));
/* let's get this exact; first, recursively call GetPosition on the primary */
if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK) if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK)
WARN("DSOUND_PrimaryGetPosition failed\n"); WARN("DSOUND_PrimaryGetPosition failed\n");
/* detect HEL mode underrun */
if (!(This->device->hwbuf || This->device->pwqueue))
TRACE("detected an underrun\n");
if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) { if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) {
/* calculate play position using this */ /* calculate play position using this */
*playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite); *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
...@@ -489,7 +508,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( ...@@ -489,7 +508,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen; wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen;
wp %= This->device->buflen; wp %= This->device->buflen;
*playpos = DSOUND_CalcPlayPosition(This, wp, pwrite); *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
TRACE("Using non-GETCURRENTPOSITION2\n");
} }
LeaveCriticalSection(&(This->device->mixlock)); LeaveCriticalSection(&(This->device->mixlock));
} }
if (writepos) if (writepos)
...@@ -504,7 +525,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( ...@@ -504,7 +525,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
} }
if (playpos) if (playpos)
This->last_playpos = *playpos; This->last_playpos = *playpos;
TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
playpos?*playpos:0, writepos?*writepos:0, This->buflen, This, GetTickCount());
return DS_OK; return DS_OK;
} }
...@@ -610,19 +634,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock( ...@@ -610,19 +634,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
/* **** */
EnterCriticalSection(&(This->lock)); EnterCriticalSection(&(This->lock));
if ((writebytes == This->buflen) &&
((This->state == STATE_STARTING) ||
(This->state == STATE_PLAYING)))
/* some games, like Half-Life, try to be clever (not) and
* keep one secondary buffer, and mix sounds into it itself,
* locking the entire buffer every time... so we can just forget
* about tracking the last-written-to-position... */
This->probably_valid_to = (DWORD)-1;
else
This->probably_valid_to = writecursor;
if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
hres = IDsDriverBuffer_Lock(This->hwbuf, hres = IDsDriverBuffer_Lock(This->hwbuf,
lplpaudioptr1, audiobytes1, lplpaudioptr1, audiobytes1,
...@@ -635,7 +649,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock( ...@@ -635,7 +649,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
return hres; return hres;
} }
} else { } else {
BOOL remix = FALSE;
if (writecursor+writebytes <= This->buflen) { if (writecursor+writebytes <= This->buflen) {
*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
*audiobytes1 = writebytes; *audiobytes1 = writebytes;
...@@ -643,6 +656,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock( ...@@ -643,6 +656,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
*(LPBYTE*)lplpaudioptr2 = NULL; *(LPBYTE*)lplpaudioptr2 = NULL;
if (audiobytes2) if (audiobytes2)
*audiobytes2 = 0; *audiobytes2 = 0;
TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
*(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
TRACE("->%d.0\n",writebytes); TRACE("->%d.0\n",writebytes);
} else { } else {
*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
...@@ -651,30 +666,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock( ...@@ -651,30 +666,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
*(LPBYTE*)lplpaudioptr2 = This->buffer->memory; *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
if (audiobytes2) if (audiobytes2)
*audiobytes2 = writebytes-(This->buflen-writecursor); *audiobytes2 = writebytes-(This->buflen-writecursor);
TRACE("->%d.%d\n",*audiobytes1,audiobytes2?*audiobytes2:0); TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
}
if (This->state == STATE_PLAYING) {
/* if the segment between playpos and buf_mixpos is touched,
* we need to cancel some mixing */
/* we'll assume that the app always calls GetCurrentPosition before
* locking a playing buffer, so that last_playpos is up-to-date */
if (This->buf_mixpos >= This->last_playpos) {
if (This->buf_mixpos > writecursor &&
This->last_playpos < writecursor+writebytes)
remix = TRUE;
} else {
if (This->buf_mixpos > writecursor ||
This->last_playpos < writecursor+writebytes)
remix = TRUE;
}
if (remix) {
TRACE("locking prebuffered region, ouch\n");
DSOUND_MixCancelAt(This, writecursor);
}
} }
} }
LeaveCriticalSection(&(This->lock)); LeaveCriticalSection(&(This->lock));
/* **** */
return DS_OK; return DS_OK;
} }
...@@ -689,9 +686,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition( ...@@ -689,9 +686,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
/* **** */ /* **** */
EnterCriticalSection(&(This->lock)); EnterCriticalSection(&(This->lock));
/* start mixing from this new location instead */
newpos %= This->buflen; newpos %= This->buflen;
newpos -= newpos%This->pwfx->nBlockAlign; newpos -= newpos%This->pwfx->nBlockAlign;
This->buf_mixpos = newpos; This->buf_mixpos = newpos;
/* at this point, do not attempt to reset buffers, mess with primary mix position,
or anything like that to reduce latancy. The data already prebuffered cannot be changed */
/* position HW buffer if applicable */
if (This->hwbuf) { if (This->hwbuf) {
hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos); hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
if (hres != DS_OK) if (hres != DS_OK)
...@@ -735,8 +738,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan( ...@@ -735,8 +738,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
if (hres != DS_OK) if (hres != DS_OK)
WARN("IDsDriverBuffer_SetVolumePan failed\n"); WARN("IDsDriverBuffer_SetVolumePan failed\n");
} else }
DSOUND_ForceRemix(This);
} }
LeaveCriticalSection(&(This->lock)); LeaveCriticalSection(&(This->lock));
...@@ -770,7 +772,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock( ...@@ -770,7 +772,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
) { ) {
IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
DWORD probably_valid_to;
HRESULT hres = DS_OK; HRESULT hres = DS_OK;
TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2); TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
...@@ -784,22 +785,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock( ...@@ -784,22 +785,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
WARN("IDsDriverBuffer_Unlock failed\n"); WARN("IDsDriverBuffer_Unlock failed\n");
} }
if (hres == DS_OK) {
if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
probably_valid_to %= This->buflen;
if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
((This->state == STATE_STARTING) ||
(This->state == STATE_PLAYING)))
/* see IDirectSoundBufferImpl_Lock */
probably_valid_to = (DWORD)-1;
This->probably_valid_to = probably_valid_to;
}
LeaveCriticalSection(&(This->lock)); LeaveCriticalSection(&(This->lock));
/* **** */ /* **** */
TRACE("probably_valid_to=%d\n", This->probably_valid_to);
return hres; return hres;
} }
...@@ -1044,6 +1032,8 @@ HRESULT IDirectSoundBufferImpl_Create( ...@@ -1044,6 +1032,8 @@ HRESULT IDirectSoundBufferImpl_Create(
dsb->lpVtbl = &dsbvt; dsb->lpVtbl = &dsbvt;
dsb->iks = NULL; dsb->iks = NULL;
dsb->remix_pos = 0;
/* size depends on version */ /* size depends on version */
CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize); CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
......
...@@ -66,8 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound); ...@@ -66,8 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound);
#define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
* (this will affect HEL sound reliability and latency) */ * (this will affect HEL sound reliability and latency) */
#define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */ #define DS_SND_QUEUE_MAX 10 /* max number of fragments to prebuffer */
#define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS]; DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS];
GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
...@@ -104,7 +103,6 @@ int ds_emuldriver = DS_EMULDRIVER; ...@@ -104,7 +103,6 @@ int ds_emuldriver = DS_EMULDRIVER;
int ds_hel_margin = DS_HEL_MARGIN; int ds_hel_margin = DS_HEL_MARGIN;
int ds_hel_queue = DS_HEL_QUEUE; int ds_hel_queue = DS_HEL_QUEUE;
int ds_snd_queue_max = DS_SND_QUEUE_MAX; int ds_snd_queue_max = DS_SND_QUEUE_MAX;
int ds_snd_queue_min = DS_SND_QUEUE_MIN;
int ds_hw_accel = DS_HW_ACCEL_FULL; int ds_hw_accel = DS_HW_ACCEL_FULL;
int ds_default_playback = 0; int ds_default_playback = 0;
int ds_default_capture = 0; int ds_default_capture = 0;
...@@ -170,9 +168,6 @@ void setup_dsound_options(void) ...@@ -170,9 +168,6 @@ void setup_dsound_options(void)
if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH )) if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
ds_snd_queue_max = atoi(buffer); ds_snd_queue_max = atoi(buffer);
if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH ))
ds_snd_queue_min = atoi(buffer);
if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) {
if (strcmp(buffer, "Full") == 0) if (strcmp(buffer, "Full") == 0)
ds_hw_accel = DS_HW_ACCEL_FULL; ds_hw_accel = DS_HW_ACCEL_FULL;
...@@ -207,8 +202,6 @@ void setup_dsound_options(void) ...@@ -207,8 +202,6 @@ void setup_dsound_options(void)
WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE ); WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE );
if (ds_snd_queue_max != DS_SND_QUEUE_MAX) if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX); WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
if (ds_hw_accel != DS_HW_ACCEL_FULL) if (ds_hw_accel != DS_HW_ACCEL_FULL)
WARN("ds_hw_accel = %s (default=Full)\n", WARN("ds_hw_accel = %s (default=Full)\n",
ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
......
...@@ -20,10 +20,11 @@ ...@@ -20,10 +20,11 @@
*/ */
/* Linux does not support better timing than 10ms */ /* Linux does not support better timing than 10ms */
#define DS_TIME_RES 10 /* Resolution of multimedia timer */ #define DS_TIME_RES 2 /* Resolution of multimedia timer */
#define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */ #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
#define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer #define DS_HEL_BUFLEN 0x8000 /* HEL: The buffer length of the emulated buffer */
#define DS_HEL_FRAGS 0x40 /* HEL only: number of waveOut fragments in primary buffer
* (changing this won't help you) */ * (changing this won't help you) */
/* direct sound hardware acceleration levels */ /* direct sound hardware acceleration levels */
...@@ -36,7 +37,6 @@ extern int ds_emuldriver; ...@@ -36,7 +37,6 @@ extern int ds_emuldriver;
extern int ds_hel_margin; extern int ds_hel_margin;
extern int ds_hel_queue; extern int ds_hel_queue;
extern int ds_snd_queue_max; extern int ds_snd_queue_max;
extern int ds_snd_queue_min;
extern int ds_hw_accel; extern int ds_hw_accel;
extern int ds_default_playback; extern int ds_default_playback;
extern int ds_default_capture; extern int ds_default_capture;
...@@ -91,7 +91,6 @@ struct DirectSoundDevice ...@@ -91,7 +91,6 @@ struct DirectSoundDevice
PIDSDRIVERBUFFER hwbuf; PIDSDRIVERBUFFER hwbuf;
LPBYTE buffer; LPBYTE buffer;
DWORD writelead, buflen, state, playpos, mixpos; DWORD writelead, buflen, state, playpos, mixpos;
BOOL need_remix;
int nrofbuffers; int nrofbuffers;
IDirectSoundBufferImpl** buffers; IDirectSoundBufferImpl** buffers;
RTL_RWLOCK buffer_list_lock; RTL_RWLOCK buffer_list_lock;
...@@ -168,14 +167,12 @@ struct IDirectSoundBufferImpl ...@@ -168,14 +167,12 @@ struct IDirectSoundBufferImpl
DWORD playpos,startpos,writelead,buflen; DWORD playpos,startpos,writelead,buflen;
DWORD nAvgBytesPerSec; DWORD nAvgBytesPerSec;
DWORD freq; DWORD freq;
DSVOLUMEPAN volpan, cvolpan; DSVOLUMEPAN volpan;
DSBUFFERDESC dsbd; DSBUFFERDESC dsbd;
/* used for frequency conversion (PerfectPitch) */ /* used for frequency conversion (PerfectPitch) */
ULONG freqAdjust, freqAcc; ULONG freqAdjust, freqAcc;
/* used for intelligent (well, sort of) prebuffering */ /* used for intelligent (well, sort of) prebuffering */
DWORD probably_valid_to, last_playpos; DWORD primary_mixpos, buf_mixpos, last_playpos, remix_pos;
DWORD primary_mixpos, buf_mixpos;
BOOL need_remix;
/* IDirectSoundNotifyImpl fields */ /* IDirectSoundNotifyImpl fields */
IDirectSoundNotifyImpl* notify; IDirectSoundNotifyImpl* notify;
...@@ -439,9 +436,6 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p ...@@ -439,9 +436,6 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
/* mixer.c */ /* mixer.c */
void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len); void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb);
void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos);
void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq);
void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan); void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan); void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb); void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb);
......
...@@ -82,12 +82,14 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) ...@@ -82,12 +82,14 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
waveOutPause(device->hwo); waveOutPause(device->hwo);
if (device->state == STATE_PLAYING) device->state = STATE_STARTING; if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
/* use fragments of 10ms (1/100s) each (which should get us within
* the documented write cursor lead of 10-15ms) */ /* on original windows, the buffer it set to a fixed size, no matter what the settings are.
buflen = ((device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign) * DS_HEL_FRAGS; on windows this size is always fixed (tested on win-xp) */
buflen = DS_HEL_BUFLEN;
TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer); TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
/* reallocate emulated primary buffer */
/* reallocate emulated primary buffer */
if (device->buffer) if (device->buffer)
newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen); newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
else else
...@@ -106,6 +108,11 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) ...@@ -106,6 +108,11 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
device->fraglen = device->buflen / DS_HEL_FRAGS; device->fraglen = device->buflen / DS_HEL_FRAGS;
/* sanity */
if(device->buflen % DS_HEL_FRAGS){
ERR("Bad DS_HEL_FRAGS resolution\n");
}
/* prepare fragment headers */ /* prepare fragment headers */
for (c=0; c<DS_HEL_FRAGS; c++) { for (c=0; c<DS_HEL_FRAGS; c++) {
device->pwave[c]->lpData = (char*)device->buffer + c*device->fraglen; device->pwave[c]->lpData = (char*)device->buffer + c*device->fraglen;
...@@ -128,7 +135,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) ...@@ -128,7 +135,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
device->mixpos = 0; device->mixpos = 0;
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
TRACE("fraglen=%d\n", device->fraglen); TRACE("fraglen=%d\n", device->fraglen);
DSOUND_WaveQueue(device, (DWORD)-1);
} }
if ((err == DS_OK) && (merr != DS_OK)) if ((err == DS_OK) && (merr != DS_OK))
err = merr; err = merr;
...@@ -161,10 +167,17 @@ static void DSOUND_PrimaryClose(DirectSoundDevice *device) ...@@ -161,10 +167,17 @@ static void DSOUND_PrimaryClose(DirectSoundDevice *device)
if (!device->hwbuf) { if (!device->hwbuf) {
unsigned c; unsigned c;
/* get out of CS when calling the wave system */
LeaveCriticalSection(&(device->mixlock));
/* **** */
device->pwqueue = (DWORD)-1; /* resetting queues */ device->pwqueue = (DWORD)-1; /* resetting queues */
waveOutReset(device->hwo); waveOutReset(device->hwo);
for (c=0; c<DS_HEL_FRAGS; c++) for (c=0; c<DS_HEL_FRAGS; c++)
waveOutUnprepareHeader(device->hwo, device->pwave[c], sizeof(WAVEHDR)); waveOutUnprepareHeader(device->hwo, device->pwave[c], sizeof(WAVEHDR));
/* **** */
EnterCriticalSection(&(device->mixlock));
/* clear the queue */
device->pwqueue = 0; device->pwqueue = 0;
} else { } else {
if (IDsDriverBuffer_Release(device->hwbuf) == 0) if (IDsDriverBuffer_Release(device->hwbuf) == 0)
...@@ -224,7 +237,8 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) ...@@ -224,7 +237,8 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
{ {
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
EnterCriticalSection(&(device->mixlock)); /* **** */
EnterCriticalSection(&(device->mixlock));
DSOUND_PrimaryClose(device); DSOUND_PrimaryClose(device);
if (device->driver) { if (device->driver) {
...@@ -240,7 +254,10 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) ...@@ -240,7 +254,10 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
} }
HeapFree(GetProcessHeap(),0,device->pwfx); HeapFree(GetProcessHeap(),0,device->pwfx);
device->pwfx=NULL; device->pwfx=NULL;
LeaveCriticalSection(&(device->mixlock));
LeaveCriticalSection(&(device->mixlock));
/* **** */
return DS_OK; return DS_OK;
} }
...@@ -267,7 +284,6 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) ...@@ -267,7 +284,6 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
HRESULT err = DS_OK; HRESULT err = DS_OK;
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
EnterCriticalSection(&(device->mixlock));
if (device->hwbuf) { if (device->hwbuf) {
err = IDsDriverBuffer_Stop(device->hwbuf); err = IDsDriverBuffer_Stop(device->hwbuf);
if (err == DSERR_BUFFERLOST) { if (err == DSERR_BUFFERLOST) {
...@@ -296,11 +312,20 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) ...@@ -296,11 +312,20 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
WARN("IDsDriverBuffer_Stop failed\n"); WARN("IDsDriverBuffer_Stop failed\n");
} }
} else { } else {
/* dont call the wave system with the lock set */
LeaveCriticalSection(&(device->mixlock));
/* **** */
err = mmErr(waveOutPause(device->hwo)); err = mmErr(waveOutPause(device->hwo));
/* **** */
EnterCriticalSection(&(device->mixlock));
if (err != DS_OK) if (err != DS_OK)
WARN("waveOutPause failed\n"); WARN("waveOutPause failed\n");
} }
LeaveCriticalSection(&(device->mixlock));
return err; return err;
} }
...@@ -315,19 +340,20 @@ HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LP ...@@ -315,19 +340,20 @@ HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LP
return err; return err;
} }
} else { } else {
/* check if playpos was requested */
if (playpos) { if (playpos) {
MMTIME mtime; /* use the cached play position */
mtime.wType = TIME_BYTES; *playpos = device->pwplay * device->fraglen;
waveOutGetPosition(device->hwo, &mtime, sizeof(mtime));
mtime.u.cb = mtime.u.cb % device->buflen;
*playpos = mtime.u.cb;
} }
/* check if writepos was requested */
if (writepos) { if (writepos) {
/* the writepos should only be used by apps with WRITEPRIMARY priority, TRACE("pwplay=%i, pwqueue=%i\n", device->pwplay, device->pwqueue);
* in which case our software mixer is disabled anyway */
*writepos = (device->pwplay + ds_hel_margin) * device->fraglen; /* the writepos is the first non-queued position */
while (*writepos >= device->buflen) *writepos = (device->pwplay + device->pwqueue) * device->fraglen;
*writepos -= device->buflen; *writepos %= device->buflen;
} }
} }
TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount()); TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
...@@ -607,6 +633,9 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition( ...@@ -607,6 +633,9 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->device; DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->device;
TRACE("(%p,%p,%p)\n", iface, playpos, writepos); TRACE("(%p,%p,%p)\n", iface, playpos, writepos);
/* **** */
EnterCriticalSection(&(device->mixlock));
hres = DSOUND_PrimaryGetPosition(device, playpos, writepos); hres = DSOUND_PrimaryGetPosition(device, playpos, writepos);
if (hres != DS_OK) { if (hres != DS_OK) {
WARN("DSOUND_PrimaryGetPosition failed\n"); WARN("DSOUND_PrimaryGetPosition failed\n");
...@@ -618,6 +647,10 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition( ...@@ -618,6 +647,10 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
*writepos += device->writelead; *writepos += device->writelead;
while (*writepos >= device->buflen) *writepos -= device->buflen; while (*writepos >= device->buflen) *writepos -= device->buflen;
} }
LeaveCriticalSection(&(device->mixlock));
/* **** */
TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount()); TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
return DS_OK; return DS_OK;
} }
......
...@@ -192,7 +192,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) ...@@ -192,7 +192,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
TRACE("3D processing disabled\n"); TRACE("3D processing disabled\n");
/* this one is here only to eliminate annoying warning message */ /* this one is here only to eliminate annoying warning message */
DSOUND_RecalcVolPan (&dsb->volpan); DSOUND_RecalcVolPan (&dsb->volpan);
DSOUND_ForceRemix (dsb);
break; break;
case DS3DMODE_NORMAL: case DS3DMODE_NORMAL:
TRACE("Normal 3D processing mode\n"); TRACE("Normal 3D processing mode\n");
...@@ -319,7 +318,6 @@ static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb) ...@@ -319,7 +318,6 @@ static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb)
TRACE("(%p)\n",dsb); TRACE("(%p)\n",dsb);
DSOUND_Calc3DBuffer(dsb); DSOUND_Calc3DBuffer(dsb);
DSOUND_ForceRemix(dsb);
} }
static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl) static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
...@@ -332,6 +330,8 @@ static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl) ...@@ -332,6 +330,8 @@ static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
crash without the following line) */ crash without the following line) */
if (ds3dl->device->buffers[i]->ds3db == NULL) if (ds3dl->device->buffers[i]->ds3db == NULL)
continue; continue;
/* check if this buffer is waiting for recalculation */
if (ds3dl->device->buffers[i]->ds3db_need_recalc) if (ds3dl->device->buffers[i]->ds3db_need_recalc)
{ {
DSOUND_Mix3DBuffer(ds3dl->device->buffers[i]); DSOUND_Mix3DBuffer(ds3dl->device->buffers[i]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment