dsound: Use frame rather than byte counts to clarify the mixing.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7a27cc89aa
commit
134b684fd9
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -522,7 +514,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer,
|
|||
DSOUND_CheckEvent(dsb, oldpos, ilen);
|
||||
}
|
||||
|
||||
return len;
|
||||
return frames;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
* 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;
|
||||
|
@ -588,14 +579,14 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buff
|
|||
/* 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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -666,8 +657,7 @@ 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);
|
||||
|
@ -675,26 +665,26 @@ static void DSOUND_PerformMix(DirectSoundDevice *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;
|
||||
|
@ -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));
|
||||
|
|
|
@ -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];
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue