Commit 6d009b98 authored by Marton Balint's avatar Marton Balint Committed by Alexandre Julliard

dsound: Convert freqAdjust and freqAcc to integers.

Fixes resampling errors caused by truncating floating point numbers.
parent acccdce4
...@@ -274,7 +274,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *i ...@@ -274,7 +274,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *i
oldFreq = This->freq; oldFreq = This->freq;
This->freq = freq; This->freq = freq;
if (freq != oldFreq) { if (freq != oldFreq) {
This->freqAdjust = This->freq / (float)This->device->pwfx->nSamplesPerSec; This->freqAdjustNum = This->freq;
This->freqAdjustDen = This->device->pwfx->nSamplesPerSec;
This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign; This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
DSOUND_RecalcFormat(This); DSOUND_RecalcFormat(This);
} }
...@@ -935,7 +936,8 @@ HRESULT IDirectSoundBufferImpl_Create( ...@@ -935,7 +936,8 @@ HRESULT IDirectSoundBufferImpl_Create(
dsb->sec_mixpos = 0; dsb->sec_mixpos = 0;
dsb->state = STATE_STOPPED; dsb->state = STATE_STOPPED;
dsb->freqAdjust = dsb->freq / (float)device->pwfx->nSamplesPerSec; dsb->freqAdjustNum = dsb->freq;
dsb->freqAdjustDen = device->pwfx->nSamplesPerSec;
dsb->nAvgBytesPerSec = dsb->freq * dsb->nAvgBytesPerSec = dsb->freq *
dsbd->lpwfxFormat->nBlockAlign; dsbd->lpwfxFormat->nBlockAlign;
......
...@@ -152,7 +152,9 @@ struct IDirectSoundBufferImpl ...@@ -152,7 +152,9 @@ struct IDirectSoundBufferImpl
/* used for frequency conversion (PerfectPitch) */ /* used for frequency conversion (PerfectPitch) */
ULONG freqneeded; ULONG freqneeded;
DWORD firstep; DWORD firstep;
float freqAcc, freqAdjust, firgain; float firgain;
LONG64 freqAdjustNum,freqAdjustDen;
LONG64 freqAccNum;
/* used for mixing */ /* used for mixing */
DWORD sec_mixpos; DWORD sec_mixpos;
......
...@@ -104,7 +104,8 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) ...@@ -104,7 +104,8 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
TRACE("(%p)\n",dsb); TRACE("(%p)\n",dsb);
pwfxe = (WAVEFORMATEXTENSIBLE *) dsb->pwfx; pwfxe = (WAVEFORMATEXTENSIBLE *) dsb->pwfx;
dsb->freqAdjust = (float)dsb->freq / dsb->device->pwfx->nSamplesPerSec; dsb->freqAdjustNum = dsb->freq;
dsb->freqAdjustDen = dsb->device->pwfx->nSamplesPerSec;
if ((pwfxe->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) || ((pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) if ((pwfxe->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) || ((pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
&& (IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))) && (IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))))
...@@ -117,12 +118,12 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) ...@@ -117,12 +118,12 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
* sample in the secondary buffer. firgain specifies what * sample in the secondary buffer. firgain specifies what
* to multiply the FIR output by in order to attenuate it correctly. * to multiply the FIR output by in order to attenuate it correctly.
*/ */
if (dsb->freqAdjust > 1.0f) { if (dsb->freqAdjustNum / dsb->freqAdjustDen > 0) {
/** /**
* Yes, round it a bit to make sure that the * Yes, round it a bit to make sure that the
* linear interpolation factor never changes. * linear interpolation factor never changes.
*/ */
dsb->firstep = ceil(fir_step / dsb->freqAdjust); dsb->firstep = fir_step * dsb->freqAdjustDen / dsb->freqAdjustNum;
} else { } else {
dsb->firstep = fir_step; dsb->firstep = fir_step;
} }
...@@ -131,7 +132,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) ...@@ -131,7 +132,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
/* calculate the 10ms write lead */ /* calculate the 10ms write lead */
dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign; dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign;
dsb->freqAcc = 0; dsb->freqAccNum = 0;
dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1]; dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1];
dsb->put_aux = putieee32; dsb->put_aux = putieee32;
...@@ -262,18 +263,17 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count) ...@@ -262,18 +263,17 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count)
return count; return count;
} }
static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc) static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum)
{ {
UINT i, channel; UINT i, channel;
UINT istride = dsb->pwfx->nBlockAlign; UINT istride = dsb->pwfx->nBlockAlign;
UINT ostride = dsb->device->pwfx->nChannels * sizeof(float); UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
float freqAdjust = dsb->freqAdjust; LONG64 freqAcc_start = *freqAccNum;
float freqAcc_start = *freqAcc; LONG64 freqAcc_end = freqAcc_start + count * dsb->freqAdjustNum;
float freqAcc_end = freqAcc_start + count * freqAdjust;
UINT dsbfirstep = dsb->firstep; UINT dsbfirstep = dsb->firstep;
UINT channels = dsb->mix_channels; UINT channels = dsb->mix_channels;
UINT max_ipos = freqAcc_start + count * freqAdjust; UINT max_ipos = (freqAcc_start + count * dsb->freqAdjustNum) / dsb->freqAdjustDen;
UINT fir_cachesize = (fir_len + dsbfirstep - 2) / dsbfirstep; UINT fir_cachesize = (fir_len + dsbfirstep - 2) / dsbfirstep;
UINT required_input = max_ipos + fir_cachesize; UINT required_input = max_ipos + fir_cachesize;
...@@ -295,8 +295,8 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f ...@@ -295,8 +295,8 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
dsb->sec_mixpos + i * istride, channel); dsb->sec_mixpos + i * istride, channel);
for(i = 0; i < count; ++i) { for(i = 0; i < count; ++i) {
float total_fir_steps = (freqAcc_start + i * freqAdjust) * dsbfirstep; UINT int_fir_steps = (freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / dsb->freqAdjustDen;
UINT int_fir_steps = total_fir_steps; float total_fir_steps = (freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / (float)dsb->freqAdjustDen;
UINT ipos = int_fir_steps / dsbfirstep; UINT ipos = int_fir_steps / dsbfirstep;
UINT idx = (ipos + 1) * dsbfirstep - int_fir_steps - 1; UINT idx = (ipos + 1) * dsbfirstep - int_fir_steps - 1;
...@@ -321,8 +321,7 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f ...@@ -321,8 +321,7 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
} }
} }
freqAcc_end -= (int)freqAcc_end; *freqAccNum = freqAcc_end % dsb->freqAdjustDen;
*freqAcc = freqAcc_end;
HeapFree(GetProcessHeap(), 0, fir_copy); HeapFree(GetProcessHeap(), 0, fir_copy);
HeapFree(GetProcessHeap(), 0, intermediate); HeapFree(GetProcessHeap(), 0, intermediate);
...@@ -330,14 +329,14 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f ...@@ -330,14 +329,14 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
return max_ipos; return max_ipos;
} }
static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc) static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum)
{ {
DWORD ipos, adv; DWORD ipos, adv;
if (dsb->freqAdjust == 1.0) if (dsb->freqAdjustNum == dsb->freqAdjustDen)
adv = cp_fields_noresample(dsb, count); /* *freqAcc is unmodified */ adv = cp_fields_noresample(dsb, count); /* *freqAccNum is unmodified */
else else
adv = cp_fields_resample(dsb, count, freqAcc); adv = cp_fields_resample(dsb, count, freqAccNum);
ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign; ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign;
if (ipos >= dsb->buflen) { if (ipos >= dsb->buflen) {
...@@ -393,7 +392,7 @@ static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames) ...@@ -393,7 +392,7 @@ static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames)
dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes); dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes);
} }
cp_fields(dsb, frames, &dsb->freqAcc); cp_fields(dsb, frames, &dsb->freqAccNum);
} }
static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames) static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
...@@ -505,7 +504,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi ...@@ -505,7 +504,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
mixlen = 2 * dsb->device->fraglen; mixlen = 2 * dsb->device->fraglen;
writepos += primary_done; writepos += primary_done;
dsb->sec_mixpos += (primary_done / dsb->device->pwfx->nBlockAlign) * dsb->sec_mixpos += (primary_done / dsb->device->pwfx->nBlockAlign) *
dsb->pwfx->nBlockAlign * dsb->freqAdjust; dsb->pwfx->nBlockAlign * dsb->freqAdjustNum / dsb->freqAdjustDen;
} }
} }
......
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