From dd8497b40ae145da74ca9aeb8aab274572328bbd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 28 Mar 2015 08:18:10 +0100
Subject: dsound: Apply filters before sound is multiplied to speakers.

Based on a patch by Mark Harmstone.
---
 dlls/dsound/dsound.c         |   1 +
 dlls/dsound/dsound_private.h |   4 +-
 dlls/dsound/mixer.c          | 104 ++++++++++++++++++++++++++++++-------------
 3 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index 065c377..ed0bbba 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -238,6 +238,7 @@ static ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
         if(device->volume)
             IAudioStreamVolume_Release(device->volume);
 
+        HeapFree(GetProcessHeap(), 0, device->dsp_buffer);
         HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
         HeapFree(GetProcessHeap(), 0, device->mix_buffer);
         HeapFree(GetProcessHeap(), 0, device->buffer);
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 726452c..ed645db 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -91,8 +91,8 @@ struct DirectSoundDevice
     int                         speaker_num[DS_MAX_CHANNELS];
     int                         num_speakers;
     int                         lfe_channel;
-    float *mix_buffer, *tmp_buffer;
-    DWORD                       tmp_buffer_len, mix_buffer_len;
+    float                      *mix_buffer, *tmp_buffer, *dsp_buffer;
+    DWORD                       mix_buffer_len, tmp_buffer_len, dsp_buffer_len;
 
     DSVOLUMEPAN                 volpan;
 
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 4f22f85..ff92cc1 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -266,23 +266,22 @@ static inline float get_current_sample(const IDirectSoundBufferImpl *dsb,
     return dsb->get(dsb, mixpos % dsb->buflen, channel);
 }
 
-static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count)
+static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, bitsputfunc put, UINT ostride, UINT count)
 {
     UINT istride = dsb->pwfx->nBlockAlign;
-    UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
     DWORD channel, i;
     for (i = 0; i < count; i++)
         for (channel = 0; channel < dsb->mix_channels; channel++)
-            dsb->put(dsb, i * ostride, channel, get_current_sample(dsb,
-                    dsb->sec_mixpos + i * istride, channel));
+            put(dsb, i * ostride, channel, get_current_sample(dsb,
+                dsb->sec_mixpos + i * istride, channel));
     return count;
 }
 
-static UINT cp_fields_resample_lq(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum)
+static UINT cp_fields_resample_lq(IDirectSoundBufferImpl *dsb, bitsputfunc put,
+                                  UINT ostride, UINT count, LONG64 *freqAccNum)
 {
     UINT i, channel;
     UINT istride = dsb->pwfx->nBlockAlign;
-    UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
     UINT channels = dsb->mix_channels;
 
     LONG64 freqAcc_start = *freqAccNum;
@@ -310,7 +309,7 @@ static UINT cp_fields_resample_lq(IDirectSoundBufferImpl *dsb, UINT count, LONG6
             float s1 = get_current_sample(dsb, idx, channel);
             float s2 = get_current_sample(dsb, idx + istride, channel);
             float result = s1 * cur_freqAcc2 + s2 * cur_freqAcc;
-            dsb->put(dsb, i * ostride, channel, result);
+            put(dsb, i * ostride, channel, result);
         }
     }
 
@@ -318,11 +317,11 @@ static UINT cp_fields_resample_lq(IDirectSoundBufferImpl *dsb, UINT count, LONG6
     return max_ipos;
 }
 
-static UINT cp_fields_resample_hq(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum)
+static UINT cp_fields_resample_hq(IDirectSoundBufferImpl *dsb, bitsputfunc put,
+                                  UINT ostride, UINT count, LONG64 *freqAccNum)
 {
     UINT i, channel;
     UINT istride = dsb->pwfx->nBlockAlign;
-    UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
 
     LONG64 freqAcc_start = *freqAccNum;
     LONG64 freqAcc_end = freqAcc_start + count * dsb->freqAdjustNum;
@@ -372,7 +371,7 @@ static UINT cp_fields_resample_hq(IDirectSoundBufferImpl *dsb, UINT count, LONG6
             float* cache = &intermediate[channel * required_input + ipos];
             for (j = 0; j < fir_used; j++)
                 sum += fir_copy[j] * cache[j];
-            dsb->put(dsb, i * ostride, channel, sum * dsb->firgain);
+            put(dsb, i * ostride, channel, sum * dsb->firgain);
         }
     }
 
@@ -384,16 +383,17 @@ static UINT cp_fields_resample_hq(IDirectSoundBufferImpl *dsb, UINT count, LONG6
     return max_ipos;
 }
 
-static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum)
+static void cp_fields(IDirectSoundBufferImpl *dsb, bitsputfunc put,
+                      UINT ostride, UINT count, LONG64 *freqAccNum)
 {
     DWORD ipos, adv;
 
     if (dsb->freqAdjustNum == dsb->freqAdjustDen)
-        adv = cp_fields_noresample(dsb, count); /* *freqAcc is unmodified */
+        adv = cp_fields_noresample(dsb, put, ostride, count); /* *freqAcc is unmodified */
     else if (dsb->device->nrofbuffers > ds_hq_buffers_max)
-        adv = cp_fields_resample_lq(dsb, count, freqAccNum);
+        adv = cp_fields_resample_lq(dsb, put, ostride, count, freqAccNum);
     else
-        adv = cp_fields_resample_hq(dsb, count, freqAccNum);
+        adv = cp_fields_resample_hq(dsb, put, ostride, count, freqAccNum);
 
     ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign;
     if (ipos >= dsb->buflen) {
@@ -423,6 +423,21 @@ static inline DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
 		return buflen + ptr1 - ptr2;
 	}
 }
+
+static float getieee32_dsp(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
+{
+    const BYTE *buf = (BYTE *)dsb->device->dsp_buffer;
+    const float *fbuf = (const float*)(buf + pos + sizeof(float) * channel);
+    return *fbuf;
+}
+
+static void putieee32_dsp(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    BYTE *buf = (BYTE *)dsb->device->dsp_buffer;
+    float *fbuf = (float*)(buf + pos + sizeof(float) * channel);
+    *fbuf = value;
+}
+
 /**
  * Mix at most the given amount of data into the allocated temporary buffer
  * of the given secondary buffer, starting from the dsb's first currently
@@ -438,32 +453,61 @@ static inline DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
  */
 static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames)
 {
-	UINT size_bytes = frames * sizeof(float) * dsb->device->pwfx->nChannels;
+    BOOL using_filters = dsb->num_filters > 0;
+    UINT istride, ostride, size_bytes;
+    DWORD channel, i;
+    bitsputfunc put;
 	HRESULT hr;
-	int i;
 
-	if (dsb->device->tmp_buffer_len < size_bytes || !dsb->device->tmp_buffer)
-	{
-		dsb->device->tmp_buffer_len = size_bytes;
+    put = dsb->put;
+    ostride = dsb->device->pwfx->nChannels * sizeof(float);
+    size_bytes = frames * ostride;
+
+    if (dsb->device->tmp_buffer_len < size_bytes || !dsb->device->tmp_buffer) {
 		if (dsb->device->tmp_buffer)
 			dsb->device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->tmp_buffer, size_bytes);
 		else
 			dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes);
+        dsb->device->tmp_buffer_len = size_bytes;
 	}
 
-	cp_fields(dsb, frames, &dsb->freqAccNum);
+    if (using_filters) {
+        put = putieee32_dsp;
+        ostride = dsb->mix_channels * sizeof(float);
+        size_bytes = frames * ostride;
+
+        if (dsb->device->dsp_buffer_len < size_bytes || !dsb->device->dsp_buffer) {
+            if (dsb->device->dsp_buffer)
+                dsb->device->dsp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->dsp_buffer, size_bytes);
+            else
+                dsb->device->dsp_buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes);
+            dsb->device->dsp_buffer_len = size_bytes;
+        }
+    }
 
-	if (size_bytes > 0) {
-		for (i = 0; i < dsb->num_filters; i++) {
-			if (dsb->filters[i].inplace) {
-				hr = IMediaObjectInPlace_Process(dsb->filters[i].inplace, size_bytes, (BYTE*)dsb->device->tmp_buffer, 0, DMO_INPLACE_NORMAL);
+    cp_fields(dsb, put, ostride, frames, &dsb->freqAccNum);
+
+    if (using_filters) {
+        if (frames > 0) {
+            for (i = 0; i < dsb->num_filters; i++) {
+                if (dsb->filters[i].inplace) {
+                    hr = IMediaObjectInPlace_Process(dsb->filters[i].inplace, frames * sizeof(float) * dsb->mix_channels,
+                                                     (BYTE *)dsb->device->dsp_buffer, 0, DMO_INPLACE_NORMAL);
+                    if (FAILED(hr))
+                        WARN("IMediaObjectInPlace_Process failed for filter %u\n", i);
+                } else
+                    WARN("filter %u has no inplace object - unsupported\n", i);
+            }
+        }
 
-				if (FAILED(hr))
-					WARN("IMediaObjectInPlace_Process failed for filter %u\n", i);
-			} else
-				WARN("filter %u has no inplace object - unsupported\n", i);
-		}
-	}
+        istride = ostride;
+        ostride = dsb->device->pwfx->nChannels * sizeof(float);
+        for (i = 0; i < frames; i++) {
+            for (channel = 0; channel < dsb->mix_channels; channel++) {
+                dsb->put(dsb, i * ostride, channel, getieee32_dsp(dsb, i * istride, channel));
+            }
+        }
+    }
 }
 
 static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
-- 
2.3.3

