Commit 134b684f authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

dsound: Use frame rather than byte counts to clarify the mixing.

parent 7a27cc89
...@@ -77,7 +77,7 @@ struct DirectSoundDevice ...@@ -77,7 +77,7 @@ struct DirectSoundDevice
DWORD priolevel, sleeptime; DWORD priolevel, sleeptime;
PWAVEFORMATEX pwfx, primary_pwfx; PWAVEFORMATEX pwfx, primary_pwfx;
LPBYTE buffer; LPBYTE buffer;
DWORD writelead, buflen, aclen, fraglen, playpos, pad, stopped; DWORD writelead, buflen, ac_frames, frag_frames, playpos, pad, stopped;
int nrofbuffers; int nrofbuffers;
IDirectSoundBufferImpl** buffers; IDirectSoundBufferImpl** buffers;
RTL_RWLOCK buffer_list_lock; RTL_RWLOCK buffer_list_lock;
......
...@@ -489,21 +489,13 @@ static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames) ...@@ -489,21 +489,13 @@ static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
* dsb = the secondary buffer to mix from * dsb = the secondary buffer to mix from
* fraglen = number of bytes to mix * fraglen = number of bytes to mix
*/ */
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD fraglen) static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD frames)
{ {
INT len = fraglen;
float *ibuf; float *ibuf;
DWORD oldpos; DWORD oldpos;
UINT frames = fraglen / dsb->device->pwfx->nBlockAlign;
TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen); TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen);
TRACE("(%p,%d)\n",dsb,fraglen); TRACE("(%p, frames=%d)\n",dsb,frames);
if (len % dsb->device->pwfx->nBlockAlign) {
INT nBlockAlign = dsb->device->pwfx->nBlockAlign;
ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign);
len -= len % nBlockAlign; /* data alignment */
}
/* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */ /* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */
oldpos = dsb->sec_mixpos; oldpos = dsb->sec_mixpos;
...@@ -522,7 +514,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, ...@@ -522,7 +514,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer,
DSOUND_CheckEvent(dsb, oldpos, ilen); DSOUND_CheckEvent(dsb, oldpos, ilen);
} }
return len; return frames;
} }
/** /**
...@@ -531,37 +523,37 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, ...@@ -531,37 +523,37 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer,
* *
* dsb = the secondary buffer * dsb = the secondary buffer
* playpos = the current play position in the device buffer (primary buffer) * playpos = the current play position in the device buffer (primary buffer)
* mixlen = the maximum number of bytes in the primary buffer to mix, from the * frames = the maximum number of frames in the primary buffer to mix, from the
* current writepos. * current writepos.
* *
* Returns: the number of bytes beyond the writepos that were mixed. * Returns: the number of frames beyond the writepos that were mixed.
*/ */
static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD mixlen) static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD frames)
{ {
DWORD primary_done = 0; DWORD primary_done = 0;
TRACE("(%p,%d)\n",dsb,mixlen); TRACE("(%p, frames=%d)\n",dsb,frames);
TRACE("looping=%d, leadin=%d\n", dsb->playflags, dsb->leadin); TRACE("looping=%d, leadin=%d\n", dsb->playflags, dsb->leadin);
/* If leading in, only mix about 20 ms, and 'skip' mixing the rest, for more fluid pointer advancement */ /* If leading in, only mix about 20 ms, and 'skip' mixing the rest, for more fluid pointer advancement */
/* FIXME: Is this needed? */ /* FIXME: Is this needed? */
if (dsb->leadin && dsb->state == STATE_STARTING) { if (dsb->leadin && dsb->state == STATE_STARTING) {
if (mixlen > 2 * dsb->device->fraglen) { if (frames > 2 * dsb->device->frag_frames) {
primary_done = mixlen - 2 * dsb->device->fraglen; primary_done = frames - 2 * dsb->device->frag_frames;
mixlen = 2 * dsb->device->fraglen; frames = 2 * dsb->device->frag_frames;
dsb->sec_mixpos += (primary_done / dsb->device->pwfx->nBlockAlign) * dsb->sec_mixpos += primary_done *
dsb->pwfx->nBlockAlign * dsb->freqAdjustNum / dsb->freqAdjustDen; dsb->pwfx->nBlockAlign * dsb->freqAdjustNum / dsb->freqAdjustDen;
} }
} }
dsb->leadin = FALSE; dsb->leadin = FALSE;
TRACE("mixlen (primary) = %i\n", mixlen); TRACE("frames (primary) = %i\n", frames);
/* First try to mix to the end of the buffer if possible /* First try to mix to the end of the buffer if possible
* Theoretically it would allow for better optimization * Theoretically it would allow for better optimization
*/ */
primary_done += DSOUND_MixInBuffer(dsb, mix_buffer, mixlen); primary_done += DSOUND_MixInBuffer(dsb, mix_buffer, frames);
TRACE("total mixed data=%d\n", primary_done); TRACE("total mixed data=%d\n", primary_done);
...@@ -573,14 +565,13 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD ...@@ -573,14 +565,13 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD
* For a DirectSoundDevice, go through all the currently playing buffers and * For a DirectSoundDevice, go through all the currently playing buffers and
* mix them in to the device buffer. * mix them in to the device buffer.
* *
* mixlen = the maximum amount to mix into the primary buffer * frames = the maximum amount to mix into the primary buffer
* (beyond the current writepos)
* all_stopped = reports back if all buffers have stopped * all_stopped = reports back if all buffers have stopped
* *
* Returns: the length beyond the writepos that was mixed to. * Returns: the length beyond the writepos that was mixed to.
*/ */
static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buffer, DWORD mixlen, BOOL *all_stopped) static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buffer, DWORD frames, BOOL *all_stopped)
{ {
INT i; INT i;
IDirectSoundBufferImpl *dsb; IDirectSoundBufferImpl *dsb;
...@@ -588,14 +579,14 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff ...@@ -588,14 +579,14 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff
/* unless we find a running buffer, all have stopped */ /* unless we find a running buffer, all have stopped */
*all_stopped = TRUE; *all_stopped = TRUE;
TRACE("(%d)\n", mixlen); TRACE("(frames %d)\n", frames);
for (i = 0; i < device->nrofbuffers; i++) { for (i = 0; i < device->nrofbuffers; i++) {
dsb = device->buffers[i]; dsb = device->buffers[i];
TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state); TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state);
if (dsb->buflen && dsb->state) { if (dsb->buflen && dsb->state) {
TRACE("Checking %p, mixlen=%d\n", dsb, mixlen); TRACE("Checking %p, frames=%d\n", dsb, frames);
RtlAcquireResourceShared(&dsb->lock, TRUE); RtlAcquireResourceShared(&dsb->lock, TRUE);
/* if buffer is stopping it is stopped now */ /* if buffer is stopping it is stopped now */
if (dsb->state == STATE_STOPPING) { if (dsb->state == STATE_STOPPING) {
...@@ -608,7 +599,7 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff ...@@ -608,7 +599,7 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff
dsb->state = STATE_PLAYING; dsb->state = STATE_PLAYING;
/* mix next buffer into the main buffer */ /* mix next buffer into the main buffer */
DSOUND_MixOne(dsb, mix_buffer, mixlen); DSOUND_MixOne(dsb, mix_buffer, frames);
*all_stopped = FALSE; *all_stopped = FALSE;
} }
...@@ -666,8 +657,7 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, LPBYTE pos, DWORD bytes) ...@@ -666,8 +657,7 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, LPBYTE pos, DWORD bytes)
*/ */
static void DSOUND_PerformMix(DirectSoundDevice *device) static void DSOUND_PerformMix(DirectSoundDevice *device)
{ {
UINT32 pad, maxq; DWORD block, pad_frames, pad_bytes, frames;
DWORD block;
HRESULT hr; HRESULT hr;
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
...@@ -675,26 +665,26 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) ...@@ -675,26 +665,26 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
/* **** */ /* **** */
EnterCriticalSection(&device->mixlock); EnterCriticalSection(&device->mixlock);
hr = IAudioClient_GetCurrentPadding(device->client, &pad); hr = IAudioClient_GetCurrentPadding(device->client, &pad_frames);
if(FAILED(hr)){ if(FAILED(hr)){
WARN("GetCurrentPadding failed: %08x\n", hr); WARN("GetCurrentPadding failed: %08x\n", hr);
LeaveCriticalSection(&device->mixlock); LeaveCriticalSection(&device->mixlock);
return; return;
} }
block = device->pwfx->nBlockAlign; block = device->pwfx->nBlockAlign;
pad *= block; pad_bytes = pad_frames * block;
device->playpos += device->pad - pad; device->playpos += device->pad - pad_bytes;
device->playpos %= device->buflen; device->playpos %= device->buflen;
device->pad = pad; device->pad = pad_bytes;
maxq = device->aclen - pad; frames = device->ac_frames - pad_frames;
if(!maxq){ if(!frames){
/* nothing to do! */ /* nothing to do! */
LeaveCriticalSection(&device->mixlock); LeaveCriticalSection(&device->mixlock);
return; return;
} }
if (maxq > device->fraglen * 3) if (frames > device->frag_frames * 3)
maxq = device->fraglen * 3; frames = device->frag_frames * 3;
if (device->priolevel != DSSCL_WRITEPRIMARY) { if (device->priolevel != DSSCL_WRITEPRIMARY) {
BOOL all_stopped = FALSE; BOOL all_stopped = FALSE;
...@@ -706,44 +696,45 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) ...@@ -706,44 +696,45 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
/* check for underrun. underrun occurs when the write position passes the mix position /* check for underrun. underrun occurs when the write position passes the mix position
* also wipe out just-played sound data */ * also wipe out just-played sound data */
if (!pad) if (!pad_frames)
WARN("Probable buffer underrun\n"); WARN("Probable buffer underrun\n");
hr = IAudioRenderClient_GetBuffer(device->render, maxq / block, (void*)&buffer); hr = IAudioRenderClient_GetBuffer(device->render, frames, (void*)&buffer);
if(FAILED(hr)){ if(FAILED(hr)){
WARN("GetBuffer failed: %08x\n", hr); WARN("GetBuffer failed: %08x\n", hr);
LeaveCriticalSection(&device->mixlock); LeaveCriticalSection(&device->mixlock);
return; return;
} }
memset(buffer, nfiller, maxq); memset(buffer, nfiller, frames * block);
if (!device->normfunction) if (!device->normfunction)
DSOUND_MixToPrimary(device, buffer, maxq, &all_stopped); DSOUND_MixToPrimary(device, buffer, frames, &all_stopped);
else { else {
memset(device->buffer, nfiller, device->buflen); memset(device->buffer, nfiller, device->buflen);
/* do the mixing */ /* do the mixing */
DSOUND_MixToPrimary(device, (float*)device->buffer, maxq, &all_stopped); DSOUND_MixToPrimary(device, (float*)device->buffer, frames, &all_stopped);
device->normfunction(device->buffer, buffer, maxq); device->normfunction(device->buffer, buffer, frames * block);
} }
hr = IAudioRenderClient_ReleaseBuffer(device->render, maxq / block, 0); hr = IAudioRenderClient_ReleaseBuffer(device->render, frames, 0);
if(FAILED(hr)) if(FAILED(hr))
ERR("ReleaseBuffer failed: %08x\n", hr); ERR("ReleaseBuffer failed: %08x\n", hr);
device->pad += maxq; device->pad += frames * block;
} else if (!device->stopped) { } else if (!device->stopped) {
DWORD writepos = (device->playpos + pad) % device->buflen; DWORD writepos = (device->playpos + pad_bytes) % device->buflen;
DWORD bytes = frames * block;
if (maxq > device->buflen) if (bytes > device->buflen)
maxq = device->buflen; bytes = device->buflen;
if (writepos + maxq > device->buflen) { if (writepos + bytes > device->buflen) {
DSOUND_WaveQueue(device, device->buffer + writepos, device->buflen - writepos); DSOUND_WaveQueue(device, device->buffer + writepos, device->buflen - writepos);
DSOUND_WaveQueue(device, device->buffer, writepos + maxq - device->buflen); DSOUND_WaveQueue(device, device->buffer, writepos + bytes - device->buflen);
} else } else
DSOUND_WaveQueue(device, device->buffer + writepos, maxq); DSOUND_WaveQueue(device, device->buffer + writepos, bytes);
} }
LeaveCriticalSection(&(device->mixlock)); LeaveCriticalSection(&(device->mixlock));
......
...@@ -264,7 +264,7 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx, ...@@ -264,7 +264,7 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,
device->writelead = (wfx->nSamplesPerSec / 100) * wfx->nBlockAlign; device->writelead = (wfx->nSamplesPerSec / 100) * wfx->nBlockAlign;
TRACE("buflen: %u, fraglen: %u\n", device->buflen, device->fraglen); TRACE("buflen: %u, frames %u\n", device->buflen, frames);
if (!mixfloat) if (!mixfloat)
device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1];
...@@ -351,7 +351,7 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) ...@@ -351,7 +351,7 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
aclen_frames = min(acbuf_frames, 3 * frag_frames); aclen_frames = min(acbuf_frames, 3 * frag_frames);
TRACE("period %u ms fraglen %u buflen %u\n", period_ms, frag_frames * wfx->nBlockAlign, aclen_frames * wfx->nBlockAlign); TRACE("period %u ms frag_frames %u buf_frames %u\n", period_ms, frag_frames, aclen_frames);
hres = DSOUND_PrimaryOpen(device, wfx, aclen_frames, forcewave); hres = DSOUND_PrimaryOpen(device, wfx, aclen_frames, forcewave);
if(FAILED(hres)) if(FAILED(hres))
...@@ -361,8 +361,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) ...@@ -361,8 +361,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
device->client = client; device->client = client;
device->render = render; device->render = render;
device->volume = volume; device->volume = volume;
device->fraglen = frag_frames * wfx->nBlockAlign; device->frag_frames = frag_frames;
device->aclen = aclen_frames * wfx->nBlockAlign; device->ac_frames = aclen_frames;
if (period_ms < 3) if (period_ms < 3)
device->sleeptime = 5; device->sleeptime = 5;
......
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