Skip to content

Commit

Permalink
dsound: Use frame rather than byte counts to clarify the mixing.
Browse files Browse the repository at this point in the history
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
  • Loading branch information
hdmdavies authored and julliard committed Mar 1, 2017
1 parent 7a27cc8 commit 134b684
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 56 deletions.
2 changes: 1 addition & 1 deletion dlls/dsound/dsound_private.h
Expand Up @@ -77,7 +77,7 @@ struct DirectSoundDevice
DWORD priolevel, sleeptime;
PWAVEFORMATEX pwfx, primary_pwfx;
LPBYTE buffer;
DWORD writelead, buflen, aclen, fraglen, playpos, pad, stopped;
DWORD writelead, buflen, ac_frames, frag_frames, playpos, pad, stopped;
int nrofbuffers;
IDirectSoundBufferImpl** buffers;
RTL_RWLOCK buffer_list_lock;
Expand Down
93 changes: 42 additions & 51 deletions dlls/dsound/mixer.c
Expand Up @@ -489,21 +489,13 @@ static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
* dsb = the secondary buffer to mix from
* 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;
DWORD oldpos;
UINT frames = fraglen / dsb->device->pwfx->nBlockAlign;

TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen);
TRACE("(%p,%d)\n",dsb,fraglen);

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 */
}
TRACE("(%p, frames=%d)\n",dsb,frames);

/* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */
oldpos = dsb->sec_mixpos;
Expand All @@ -522,7 +514,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer,
DSOUND_CheckEvent(dsb, oldpos, ilen);
}

return len;
return frames;
}

/**
Expand All @@ -531,37 +523,37 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer,
*
* dsb = the secondary 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.
*
* 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;

TRACE("(%p,%d)\n",dsb,mixlen);
TRACE("(%p, frames=%d)\n",dsb,frames);
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 */
/* FIXME: Is this needed? */
if (dsb->leadin && dsb->state == STATE_STARTING) {
if (mixlen > 2 * dsb->device->fraglen) {
primary_done = mixlen - 2 * dsb->device->fraglen;
mixlen = 2 * dsb->device->fraglen;
dsb->sec_mixpos += (primary_done / dsb->device->pwfx->nBlockAlign) *
if (frames > 2 * dsb->device->frag_frames) {
primary_done = frames - 2 * dsb->device->frag_frames;
frames = 2 * dsb->device->frag_frames;
dsb->sec_mixpos += primary_done *
dsb->pwfx->nBlockAlign * dsb->freqAdjustNum / dsb->freqAdjustDen;
}
}

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
* 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);

Expand All @@ -573,29 +565,28 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD
* For a DirectSoundDevice, go through all the currently playing buffers and
* mix them in to the device buffer.
*
* mixlen = the maximum amount to mix into the primary buffer
* (beyond the current writepos)
* frames = the maximum amount to mix into the primary buffer
* all_stopped = reports back if all buffers have stopped
*
* 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;
IDirectSoundBufferImpl *dsb;

/* unless we find a running buffer, all have stopped */
*all_stopped = TRUE;

TRACE("(%d)\n", mixlen);
TRACE("(frames %d)\n", frames);
for (i = 0; i < device->nrofbuffers; i++) {
dsb = device->buffers[i];

TRACE("MixToPrimary for %p, state=%d\n", dsb, 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);
/* if buffer is stopping it is stopped now */
if (dsb->state == STATE_STOPPING) {
Expand All @@ -608,7 +599,7 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff
dsb->state = STATE_PLAYING;

/* mix next buffer into the main buffer */
DSOUND_MixOne(dsb, mix_buffer, mixlen);
DSOUND_MixOne(dsb, mix_buffer, frames);

*all_stopped = FALSE;
}
Expand Down Expand Up @@ -666,35 +657,34 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, LPBYTE pos, DWORD bytes)
*/
static void DSOUND_PerformMix(DirectSoundDevice *device)
{
UINT32 pad, maxq;
DWORD block;
DWORD block, pad_frames, pad_bytes, frames;
HRESULT hr;

TRACE("(%p)\n", device);

/* **** */
EnterCriticalSection(&device->mixlock);

hr = IAudioClient_GetCurrentPadding(device->client, &pad);
hr = IAudioClient_GetCurrentPadding(device->client, &pad_frames);
if(FAILED(hr)){
WARN("GetCurrentPadding failed: %08x\n", hr);
LeaveCriticalSection(&device->mixlock);
return;
}
block = device->pwfx->nBlockAlign;
pad *= block;
device->playpos += device->pad - pad;
pad_bytes = pad_frames * block;
device->playpos += device->pad - pad_bytes;
device->playpos %= device->buflen;
device->pad = pad;
device->pad = pad_bytes;

maxq = device->aclen - pad;
if(!maxq){
frames = device->ac_frames - pad_frames;
if(!frames){
/* nothing to do! */
LeaveCriticalSection(&device->mixlock);
return;
}
if (maxq > device->fraglen * 3)
maxq = device->fraglen * 3;
if (frames > device->frag_frames * 3)
frames = device->frag_frames * 3;

if (device->priolevel != DSSCL_WRITEPRIMARY) {
BOOL all_stopped = FALSE;
Expand All @@ -706,44 +696,45 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)

/* check for underrun. underrun occurs when the write position passes the mix position
* also wipe out just-played sound data */
if (!pad)
if (!pad_frames)
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)){
WARN("GetBuffer failed: %08x\n", hr);
LeaveCriticalSection(&device->mixlock);
return;
}

memset(buffer, nfiller, maxq);
memset(buffer, nfiller, frames * block);

if (!device->normfunction)
DSOUND_MixToPrimary(device, buffer, maxq, &all_stopped);
DSOUND_MixToPrimary(device, buffer, frames, &all_stopped);
else {
memset(device->buffer, nfiller, device->buflen);

/* 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))
ERR("ReleaseBuffer failed: %08x\n", hr);

device->pad += maxq;
device->pad += frames * block;
} 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)
maxq = device->buflen;
if (writepos + maxq > device->buflen) {
if (bytes > device->buflen)
bytes = device->buflen;
if (writepos + bytes > device->buflen) {
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
DSOUND_WaveQueue(device, device->buffer + writepos, maxq);
DSOUND_WaveQueue(device, device->buffer + writepos, bytes);
}

LeaveCriticalSection(&(device->mixlock));
Expand Down
8 changes: 4 additions & 4 deletions dlls/dsound/primary.c
Expand Up @@ -264,7 +264,7 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,

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)
device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1];
Expand Down Expand Up @@ -351,7 +351,7 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)

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);
if(FAILED(hres))
Expand All @@ -361,8 +361,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
device->client = client;
device->render = render;
device->volume = volume;
device->fraglen = frag_frames * wfx->nBlockAlign;
device->aclen = aclen_frames * wfx->nBlockAlign;
device->frag_frames = frag_frames;
device->ac_frames = aclen_frames;

if (period_ms < 3)
device->sleeptime = 5;
Expand Down

0 comments on commit 134b684

Please sign in to comment.