[PATCH] dsound: convert freqAdjust and freqAcc to integers

Marton Balint cus at passwd.hu
Sat Dec 27 16:41:07 CST 2014


Fixes resamping errors caused by truncating floating point numbers.  These
errors were responsible for clicking noises when resampling from 44100 to 48000
Hz, as mentioned in bug 35971.

Signed-off-by: Marton Balint <cus at passwd.hu>
---
 dlls/dsound/buffer.c         |  6 ++++--
 dlls/dsound/dsound_private.h |  4 +++-
 dlls/dsound/mixer.c          | 37 ++++++++++++++++++-------------------
 3 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
index 9794b84..36ec132 100644
--- a/dlls/dsound/buffer.c
+++ b/dlls/dsound/buffer.c
@@ -274,7 +274,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *i
 	oldFreq = This->freq;
 	This->freq = freq;
 	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;
 		DSOUND_RecalcFormat(This);
 	}
@@ -935,7 +936,8 @@ HRESULT IDirectSoundBufferImpl_Create(
 	dsb->sec_mixpos = 0;
 	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 *
 		dsbd->lpwfxFormat->nBlockAlign;
 
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index a8f5f42..aa3985a 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -154,7 +154,9 @@ struct IDirectSoundBufferImpl
     /* used for frequency conversion (PerfectPitch) */
     ULONG                       freqneeded;
     DWORD                       firstep;
-    float freqAcc, freqAdjust, firgain;
+    float                       firgain;
+    LONG64                      freqAdjustNum,freqAdjustDen;
+    LONG64                      freqAccNum;
     /* used for mixing */
     DWORD                       sec_mixpos;
 
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 0fae20e..7f9ec3c 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -112,7 +112,8 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	TRACE("(%p)\n",dsb);
 
 	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)
 	    && (IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))))
@@ -125,12 +126,12 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	 * sample in the secondary buffer. firgain specifies what
 	 * 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
 		 * linear interpolation factor never changes.
 		 */
-		dsb->firstep = ceil(fir_step / dsb->freqAdjust);
+		dsb->firstep = fir_step * dsb->freqAdjustDen / dsb->freqAdjustNum;
 	} else {
 		dsb->firstep = fir_step;
 	}
@@ -139,7 +140,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	/* calculate the 10ms write lead */
 	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->put_aux = putieee32;
@@ -270,18 +271,17 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT 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 istride = dsb->pwfx->nBlockAlign;
     UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
 
-    float freqAdjust = dsb->freqAdjust;
-    float freqAcc_start = *freqAcc;
-    float freqAcc_end = freqAcc_start + count * freqAdjust;
+    LONG64 freqAcc_start = *freqAccNum;
+    LONG64 freqAcc_end = freqAcc_start + count * dsb->freqAdjustNum;
     UINT dsbfirstep = dsb->firstep;
     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 required_input = max_ipos + fir_cachesize;
@@ -303,8 +303,8 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
                     dsb->sec_mixpos + i * istride, channel);
 
     for(i = 0; i < count; ++i) {
-        float total_fir_steps = (freqAcc_start + i * freqAdjust) * dsbfirstep;
-        UINT int_fir_steps = total_fir_steps;
+        UINT int_fir_steps = (freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / dsb->freqAdjustDen;
+        float total_fir_steps = (freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / (float)dsb->freqAdjustDen;
         UINT ipos = int_fir_steps / dsbfirstep;
 
         UINT idx = (ipos + 1) * dsbfirstep - int_fir_steps - 1;
@@ -329,8 +329,7 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
         }
     }
 
-    freqAcc_end -= (int)freqAcc_end;
-    *freqAcc = freqAcc_end;
+    *freqAccNum = freqAcc_end % dsb->freqAdjustDen;
 
     HeapFree(GetProcessHeap(), 0, fir_copy);
     HeapFree(GetProcessHeap(), 0, intermediate);
@@ -338,14 +337,14 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
     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;
 
-    if (dsb->freqAdjust == 1.0)
-        adv = cp_fields_noresample(dsb, count); /* *freqAcc is unmodified */
+    if (dsb->freqAdjustNum == dsb->freqAdjustDen)
+        adv = cp_fields_noresample(dsb, count); /* *freqAccNum is unmodified */
     else
-        adv = cp_fields_resample(dsb, count, freqAcc);
+        adv = cp_fields_resample(dsb, count, freqAccNum);
 
     ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign;
     if (ipos >= dsb->buflen) {
@@ -401,7 +400,7 @@ static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames)
 			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)
@@ -515,7 +514,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
 			mixlen = 2 * dsb->device->fraglen;
 			writepos += primary_done;
 			dsb->sec_mixpos += (primary_done / dsb->device->pwfx->nBlockAlign) *
-				dsb->pwfx->nBlockAlign * dsb->freqAdjust;
+				dsb->pwfx->nBlockAlign * dsb->freqAdjustNum / dsb->freqAdjustDen;
 		}
 	}
 
-- 
2.1.2




More information about the wine-patches mailing list