dsound: Don't derive the secondary position from the primary position.
This commit is contained in:
parent
f393a98a8a
commit
4354be123c
|
@ -516,15 +516,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuff
|
|||
{
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
|
||||
HRESULT hres = DS_OK;
|
||||
DWORD oldpos;
|
||||
|
||||
TRACE("(%p,%d)\n",This,newpos);
|
||||
|
||||
/* **** */
|
||||
RtlAcquireResourceExclusive(&This->lock, TRUE);
|
||||
|
||||
oldpos = This->sec_mixpos;
|
||||
|
||||
/* start mixing from this new location instead */
|
||||
newpos %= This->buflen;
|
||||
newpos -= newpos%This->pwfx->nBlockAlign;
|
||||
|
@ -533,10 +530,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuff
|
|||
/* at this point, do not attempt to reset buffers, mess with primary mix position,
|
||||
or anything like that to reduce latency. The data already prebuffered cannot be changed */
|
||||
|
||||
/* position HW buffer if applicable, else just start mixing from new location instead */
|
||||
if (oldpos != newpos)
|
||||
This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
|
||||
|
||||
RtlReleaseResource(&This->lock);
|
||||
/* **** */
|
||||
|
||||
|
@ -909,7 +902,7 @@ HRESULT IDirectSoundBufferImpl_Create(
|
|||
|
||||
/* It's not necessary to initialize values to zero since */
|
||||
/* we allocated this structure with HEAP_ZERO_MEMORY... */
|
||||
dsb->buf_mixpos = dsb->sec_mixpos = 0;
|
||||
dsb->sec_mixpos = 0;
|
||||
dsb->state = STATE_STOPPED;
|
||||
|
||||
dsb->freqAdjust = dsb->freq / (float)device->pwfx->nSamplesPerSec;
|
||||
|
@ -1024,7 +1017,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
|
|||
dsb->refiks = 0;
|
||||
dsb->numIfaces = 0;
|
||||
dsb->state = STATE_STOPPED;
|
||||
dsb->buf_mixpos = dsb->sec_mixpos = 0;
|
||||
dsb->sec_mixpos = 0;
|
||||
dsb->notifies = NULL;
|
||||
dsb->nrofnotifies = 0;
|
||||
dsb->device = device;
|
||||
|
|
|
@ -178,14 +178,15 @@ struct IDirectSoundBufferImpl
|
|||
DWORD playflags,state,leadin;
|
||||
DWORD writelead,buflen;
|
||||
DWORD nAvgBytesPerSec;
|
||||
DWORD freq, tmp_buffer_len;
|
||||
DWORD freq;
|
||||
DSVOLUMEPAN volpan;
|
||||
DSBUFFERDESC dsbd;
|
||||
/* used for frequency conversion (PerfectPitch) */
|
||||
ULONG freqneeded;
|
||||
float freqAcc, freqAccNext, freqAdjust;
|
||||
float freqAcc, freqAdjust;
|
||||
/* used for mixing */
|
||||
DWORD primary_mixpos, buf_mixpos, sec_mixpos;
|
||||
DWORD primary_mixpos, sec_mixpos;
|
||||
|
||||
/* IDirectSoundNotify fields */
|
||||
LPDSBPOSITIONNOTIFY notifies;
|
||||
int nrofnotifies;
|
||||
|
|
|
@ -108,65 +108,6 @@ DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* NOTE: Not all secpos have to always be mapped to a bufpos, other way around is always the case
|
||||
* DWORD64 is used here because a single DWORD wouldn't be big enough to fit the freqAcc for big buffers
|
||||
*/
|
||||
/** This function converts a 'native' sample pointer to a resampled pointer that fits for primary
|
||||
* secmixpos is used to decide which freqAcc is needed
|
||||
* overshot tells what the 'actual' secpos is now (optional)
|
||||
*/
|
||||
DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, float* overshot)
|
||||
{
|
||||
DWORD64 framelen = secpos / dsb->pwfx->nBlockAlign;
|
||||
float acc, freqAcc;
|
||||
|
||||
if (secpos < secmixpos)
|
||||
freqAcc = dsb->freqAccNext;
|
||||
else
|
||||
freqAcc = dsb->freqAcc;
|
||||
acc = ceil((framelen - freqAcc) / dsb->freqAdjust);
|
||||
if (overshot)
|
||||
{
|
||||
*overshot = acc * dsb->freqAdjust + freqAcc;
|
||||
assert(*overshot >= framelen);
|
||||
*overshot -= framelen;
|
||||
assert(*overshot < dsb->freqAdjust);
|
||||
}
|
||||
return (DWORD)acc * dsb->device->pwfx->nBlockAlign;
|
||||
}
|
||||
|
||||
/** Convert a resampled pointer that fits for primary to a 'native' sample pointer
|
||||
*/
|
||||
static DWORD DSOUND_bufpos_to_secpos(const IDirectSoundBufferImpl *dsb, DWORD bufpos)
|
||||
{
|
||||
DWORD oAdv = dsb->device->pwfx->nBlockAlign, iAdv = dsb->pwfx->nBlockAlign, pos;
|
||||
DWORD64 framelen;
|
||||
DWORD64 acc;
|
||||
|
||||
framelen = bufpos/oAdv;
|
||||
acc = ((DWORD64)framelen) * dsb->freqAdjust + dsb->freqAcc;
|
||||
pos = (DWORD)acc * iAdv;
|
||||
if (pos >= dsb->buflen) {
|
||||
/* FIXME: can this happen at all? */
|
||||
ERR("pos >= dsb->buflen: %d >= %d, capping\n", pos, dsb->buflen);
|
||||
pos = dsb->buflen - iAdv;
|
||||
}
|
||||
|
||||
TRACE("Converted %d/%d to %d/%d\n", bufpos, dsb->tmp_buffer_len, pos, dsb->buflen);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move freqAccNext to freqAcc, and find new values for buffer length and freqAccNext
|
||||
*/
|
||||
static void DSOUND_RecalcFreqAcc(IDirectSoundBufferImpl *dsb)
|
||||
{
|
||||
if (!dsb->freqneeded) return;
|
||||
dsb->freqAcc = dsb->freqAccNext;
|
||||
dsb->tmp_buffer_len = DSOUND_secpos_to_bufpos(dsb, dsb->buflen, 0, &dsb->freqAccNext);
|
||||
TRACE("New freqadjust: %f, new buflen: %d\n", dsb->freqAccNext, dsb->tmp_buffer_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate the size for temporary buffer, and new writelead
|
||||
* Should be called when one of the following things occur:
|
||||
|
@ -177,8 +118,6 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
|
|||
{
|
||||
DWORD ichannels = dsb->pwfx->nChannels;
|
||||
DWORD ochannels = dsb->device->pwfx->nChannels;
|
||||
BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec);
|
||||
DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign;
|
||||
WAVEFORMATEXTENSIBLE *pwfxe;
|
||||
BOOL ieee = FALSE;
|
||||
|
||||
|
@ -193,11 +132,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
|
|||
/* calculate the 10ms write lead */
|
||||
dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign;
|
||||
|
||||
if ((dsb->pwfx->wBitsPerSample == dsb->device->pwfx->wBitsPerSample) &&
|
||||
(dsb->pwfx->nChannels == dsb->device->pwfx->nChannels) && !needresample && !ieee)
|
||||
needremix = FALSE;
|
||||
dsb->freqAcc = dsb->freqAccNext = 0;
|
||||
dsb->freqneeded = needresample;
|
||||
dsb->freqAcc = 0;
|
||||
|
||||
dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1];
|
||||
dsb->put_aux = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1];
|
||||
|
@ -229,16 +164,6 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
|
|||
FIXME("Conversion from %u to %u channels is not implemented, falling back to stereo\n", ichannels, ochannels);
|
||||
dsb->mix_channels = 2;
|
||||
}
|
||||
|
||||
if (needremix)
|
||||
{
|
||||
if (needresample)
|
||||
DSOUND_RecalcFreqAcc(dsb);
|
||||
else
|
||||
dsb->tmp_buffer_len = dsb->buflen / bAlign * pAlign;
|
||||
}
|
||||
else dsb->tmp_buffer_len = dsb->buflen;
|
||||
dsb->buf_mixpos = DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,23 +232,34 @@ static inline float get_current_sample(const IDirectSoundBufferImpl *dsb,
|
|||
* Copy frames from the given input buffer to the given output buffer.
|
||||
* Translate 8 <-> 16 bits and mono <-> stereo
|
||||
*/
|
||||
static inline void cp_fields(const IDirectSoundBufferImpl *dsb,
|
||||
UINT ostride, UINT count, float freqAcc)
|
||||
static inline void cp_fields(IDirectSoundBufferImpl *dsb,
|
||||
UINT ostride, UINT count, float *freqAcc)
|
||||
{
|
||||
DWORD ipos = dsb->sec_mixpos;
|
||||
UINT istride = dsb->pwfx->nBlockAlign;
|
||||
UINT istride = dsb->pwfx->nBlockAlign, i;
|
||||
DWORD opos = 0;
|
||||
|
||||
while (count-- > 0) {
|
||||
for (i = 0; i < count; ++i){
|
||||
DWORD channel;
|
||||
for (channel = 0; channel < dsb->mix_channels; channel++)
|
||||
dsb->put(dsb, opos, channel,
|
||||
get_current_sample(dsb, ipos, channel));
|
||||
freqAcc += dsb->freqAdjust;
|
||||
ipos += ((DWORD)freqAcc) * istride;
|
||||
freqAcc -= truncf(freqAcc);
|
||||
*freqAcc += dsb->freqAdjust;
|
||||
ipos += ((DWORD)*freqAcc) * istride;
|
||||
*freqAcc -= truncf(*freqAcc);
|
||||
opos += ostride;
|
||||
}
|
||||
|
||||
if (ipos >= dsb->buflen) {
|
||||
if (dsb->playflags & DSBPLAY_LOOPING)
|
||||
ipos %= dsb->buflen;
|
||||
else {
|
||||
ipos = 0;
|
||||
dsb->state = STATE_STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
dsb->sec_mixpos = ipos;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,11 +290,10 @@ static inline DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
|
|||
*
|
||||
* NOTE: writepos + len <= buflen. When called by mixer, MixOne makes sure of this.
|
||||
*/
|
||||
static void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD tmp_len)
|
||||
static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD tmp_len)
|
||||
{
|
||||
INT oAdvance = dsb->device->pwfx->nBlockAlign;
|
||||
INT size = tmp_len / oAdvance;
|
||||
float freqAcc;
|
||||
|
||||
if (dsb->device->tmp_buffer_len < tmp_len || !dsb->device->tmp_buffer)
|
||||
{
|
||||
|
@ -369,10 +304,7 @@ static void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD tmp_l
|
|||
dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, tmp_len);
|
||||
}
|
||||
|
||||
DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, dsb->sec_mixpos, &freqAcc);
|
||||
|
||||
/* FIXME: Small problem here when we're overwriting buf_mixpos, it then STILL uses old freqAcc, not sure if it matters or not */
|
||||
cp_fields(dsb, oAdvance, size, freqAcc);
|
||||
cp_fields(dsb, oAdvance, size, &dsb->freqAcc);
|
||||
}
|
||||
|
||||
/** Apply volume to the given soundbuffer from (primary) position writepos and length len
|
||||
|
@ -458,15 +390,13 @@ static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT len)
|
|||
*/
|
||||
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
|
||||
{
|
||||
INT len = fraglen, ilen;
|
||||
INT len = fraglen;
|
||||
BYTE *ibuf, *volbuf;
|
||||
DWORD oldpos, mixbufpos;
|
||||
|
||||
TRACE("buf_mixpos=%d/%d sec_mixpos=%d/%d\n", dsb->buf_mixpos, dsb->tmp_buffer_len, dsb->sec_mixpos, dsb->buflen);
|
||||
TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen);
|
||||
TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen);
|
||||
|
||||
assert(dsb->buf_mixpos + len <= dsb->tmp_buffer_len);
|
||||
|
||||
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);
|
||||
|
@ -474,6 +404,8 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
|
|||
}
|
||||
|
||||
/* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */
|
||||
oldpos = dsb->sec_mixpos;
|
||||
|
||||
DSOUND_MixToTemporary(dsb, len);
|
||||
ibuf = dsb->device->tmp_buffer;
|
||||
|
||||
|
@ -493,31 +425,17 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
|
|||
dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo);
|
||||
}
|
||||
|
||||
oldpos = dsb->sec_mixpos;
|
||||
dsb->buf_mixpos += len;
|
||||
|
||||
if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
|
||||
if (dsb->playflags & DSBPLAY_LOOPING) {
|
||||
dsb->buf_mixpos -= dsb->tmp_buffer_len;
|
||||
} else {
|
||||
dsb->buf_mixpos = dsb->sec_mixpos = 0;
|
||||
dsb->state = STATE_STOPPED;
|
||||
}
|
||||
DSOUND_RecalcFreqAcc(dsb);
|
||||
}
|
||||
|
||||
dsb->sec_mixpos = DSOUND_bufpos_to_secpos(dsb, dsb->buf_mixpos);
|
||||
ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos);
|
||||
/* check for notification positions */
|
||||
if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
|
||||
dsb->state != STATE_STARTING) {
|
||||
INT ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos);
|
||||
DSOUND_CheckEvent(dsb, oldpos, ilen);
|
||||
}
|
||||
|
||||
/* increase mix position */
|
||||
dsb->primary_mixpos += len;
|
||||
if (dsb->primary_mixpos >= dsb->device->buflen)
|
||||
dsb->primary_mixpos -= dsb->device->buflen;
|
||||
dsb->primary_mixpos %= dsb->device->buflen;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -540,8 +458,8 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
|
|||
DWORD primary_done;
|
||||
|
||||
TRACE("(%p,%d,%d)\n",dsb,writepos,mixlen);
|
||||
TRACE("writepos=%d, buf_mixpos=%d, primary_mixpos=%d, mixlen=%d\n", writepos, dsb->buf_mixpos, dsb->primary_mixpos, mixlen);
|
||||
TRACE("looping=%d, leadin=%d, buflen=%d\n", dsb->playflags, dsb->leadin, dsb->tmp_buffer_len);
|
||||
TRACE("writepos=%d, primary_mixpos=%d, mixlen=%d\n", writepos, dsb->primary_mixpos, mixlen);
|
||||
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 (dsb->leadin && dsb->state == STATE_STARTING)
|
||||
|
@ -561,7 +479,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
|
|||
if(mixlen < primary_done)
|
||||
{
|
||||
/* Should *NEVER* happen */
|
||||
ERR("Fatal error. Under/Overflow? primary_done=%d, mixpos=%d/%d (%d/%d), primary_mixpos=%d, writepos=%d, mixlen=%d\n", primary_done,dsb->buf_mixpos,dsb->tmp_buffer_len,dsb->sec_mixpos, dsb->buflen, dsb->primary_mixpos, writepos, mixlen);
|
||||
ERR("Fatal error. Under/Overflow? primary_done=%d, mixpos=%d/%d, primary_mixpos=%d, writepos=%d, mixlen=%d\n", primary_done,dsb->sec_mixpos, dsb->buflen, dsb->primary_mixpos, writepos, mixlen);
|
||||
dsb->primary_mixpos = writepos + mixlen;
|
||||
dsb->primary_mixpos %= dsb->device->buflen;
|
||||
return mixlen;
|
||||
|
@ -578,21 +496,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
|
|||
/* First try to mix to the end of the buffer if possible
|
||||
* Theoretically it would allow for better optimization
|
||||
*/
|
||||
if (mixlen + dsb->buf_mixpos >= dsb->tmp_buffer_len)
|
||||
{
|
||||
DWORD newmixed, mixfirst = dsb->tmp_buffer_len - dsb->buf_mixpos;
|
||||
newmixed = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixfirst);
|
||||
mixlen -= newmixed;
|
||||
|
||||
if (dsb->playflags & DSBPLAY_LOOPING)
|
||||
while (newmixed && mixlen)
|
||||
{
|
||||
mixfirst = (dsb->tmp_buffer_len < mixlen ? dsb->tmp_buffer_len : mixlen);
|
||||
newmixed = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixfirst);
|
||||
mixlen -= newmixed;
|
||||
}
|
||||
}
|
||||
else DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixlen);
|
||||
DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixlen);
|
||||
|
||||
/* re-calculate the primary done */
|
||||
primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
|
||||
|
|
Loading…
Reference in New Issue