diff --git a/README.md b/README.md index 930ee89b..16c61904 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,14 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [5]:** +**Bugfixes and features included in the next upcoming release [6]:** * Add stubs for Power[Set|Clear]Request * Avoid spam of FIXME messages for PsLookupProcessByProcessId stub ([Wine Bug #36821](https://bugs.winehq.org/show_bug.cgi?id=36821)) * Fix compatibility of Uplay with gnutls28 ([Wine Bug #38134](https://bugs.winehq.org/show_bug.cgi?id=38134)) * Fix handling of ANSI NTLM credentials ([Wine Bug #37063](https://bugs.winehq.org/show_bug.cgi?id=37063)) * Implement empty enumerator for IWiaDevMgr::EnumDeviceInfo ([Wine Bug #27775](https://bugs.winehq.org/show_bug.cgi?id=27775)) +* Software support for Environmental Audio Extensions (EAX) **Bugs fixed in Wine Staging 1.7.39 [205]:** diff --git a/debian/changelog b/debian/changelog index bc5c081f..347a1024 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ wine-staging (1.7.40) UNRELEASED; urgency=low * Added patch to implement empty enumerator for IWiaDevMgr::EnumDeviceInfo. * Added patch to fix handling of ANSI NTLM credentials. * Added patch to fix compatibility of Uplay with gnutls28. + * Added patches for Environmental Audio Extensions (EAX), pull request #311 from Mark Harmstone. * Removed patch to fix regression causing black screen on startup (accepted upstream). * Removed patch to fix edge cases in TOOLTIPS_GetTipText (fixed upstream). * Removed patch for IConnectionPoint/INetworkListManagerEvents stub interface (accepted upstream). diff --git a/patches/dsound-EAX/0001-dsound-Apply-filters-before-sound-is-multiplied-to-s.patch b/patches/dsound-EAX/0001-dsound-Apply-filters-before-sound-is-multiplied-to-s.patch new file mode 100644 index 00000000..92827be0 --- /dev/null +++ b/patches/dsound-EAX/0001-dsound-Apply-filters-before-sound-is-multiplied-to-s.patch @@ -0,0 +1,229 @@ +From dd8497b40ae145da74ca9aeb8aab274572328bbd Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +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 + diff --git a/patches/dsound-EAX/0002-dsound-Add-EAX-v1-constants-and-structs.patch b/patches/dsound-EAX/0002-dsound-Add-EAX-v1-constants-and-structs.patch new file mode 100644 index 00000000..ee2f6bd9 --- /dev/null +++ b/patches/dsound-EAX/0002-dsound-Add-EAX-v1-constants-and-structs.patch @@ -0,0 +1,121 @@ +From b95848a7794ff437b58f1a307da8c8fdca6a362f Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 15 Mar 2015 18:04:16 +0000 +Subject: dsound: Add EAX v1 constants and structs. + +--- + dlls/dsound/dsound_eax.h | 89 ++++++++++++++++++++++++++++++++++++++++++++ + dlls/dsound/dsound_private.h | 1 + + 2 files changed, 90 insertions(+) + create mode 100644 dlls/dsound/dsound_eax.h + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +new file mode 100644 +index 0000000..600029f +--- /dev/null ++++ b/dlls/dsound/dsound_eax.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2015 Mark Harmstone ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#ifndef DSOUND_EAX_H_DEFINED ++#define DSOUND_EAX_H_DEFINED ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++DEFINE_GUID(DSPROPSETID_EAX_ReverbProperties, 0x4a4e6fc1, 0xc341, 0x11d1, 0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00); ++DEFINE_GUID(DSPROPSETID_EAXBUFFER_ReverbProperties, 0x4a4e6fc0, 0xc341, 0x11d1, 0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00); ++ ++typedef enum { ++ DSPROPERTY_EAX_ALL, ++ DSPROPERTY_EAX_ENVIRONMENT, ++ DSPROPERTY_EAX_VOLUME, ++ DSPROPERTY_EAX_DECAYTIME, ++ DSPROPERTY_EAX_DAMPING ++} DSPROPERTY_EAX_REVERBPROPERTY; ++ ++typedef struct { ++ unsigned long environment; ++ float fVolume; ++ float fDecayTime_sec; ++ float fDamping; ++} EAX_REVERBPROPERTIES; ++ ++enum { ++ EAX_ENVIRONMENT_GENERIC, ++ EAX_ENVIRONMENT_PADDEDCELL, ++ EAX_ENVIRONMENT_ROOM, ++ EAX_ENVIRONMENT_BATHROOM, ++ EAX_ENVIRONMENT_LIVINGROOM, ++ EAX_ENVIRONMENT_STONEROOM, ++ EAX_ENVIRONMENT_AUDITORIUM, ++ EAX_ENVIRONMENT_CONCERTHALL, ++ EAX_ENVIRONMENT_CAVE, ++ EAX_ENVIRONMENT_ARENA, ++ EAX_ENVIRONMENT_HANGAR, ++ EAX_ENVIRONMENT_CARPETEDHALLWAY, ++ EAX_ENVIRONMENT_HALLWAY, ++ EAX_ENVIRONMENT_STONECORRIDOR, ++ EAX_ENVIRONMENT_ALLEY, ++ EAX_ENVIRONMENT_FOREST, ++ EAX_ENVIRONMENT_CITY, ++ EAX_ENVIRONMENT_MOUNTAINS, ++ EAX_ENVIRONMENT_QUARRY, ++ EAX_ENVIRONMENT_PLAIN, ++ EAX_ENVIRONMENT_PARKINGLOT, ++ EAX_ENVIRONMENT_SEWERPIPE, ++ EAX_ENVIRONMENT_UNDERWATER, ++ EAX_ENVIRONMENT_DRUGGED, ++ EAX_ENVIRONMENT_DIZZY, ++ EAX_ENVIRONMENT_PSYCHOTIC, ++ EAX_ENVIRONMENT_COUNT ++}; ++ ++typedef enum { ++ DSPROPERTY_EAXBUFFER_ALL, ++ DSPROPERTY_EAXBUFFER_REVERBMIX ++} DSPROPERTY_EAXBUFFER_REVERBPROPERTY; ++ ++typedef struct { ++ float fMix; ++} EAXBUFFER_REVERBPROPERTIES; ++ ++#define EAX_REVERBMIX_USEDISTANCE -1.0f ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index ed645db..3c7dc7a 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -29,6 +29,7 @@ + #include "mediaobj.h" + #include "mmsystem.h" + #include "uuids.h" ++#include "dsound_eax.h" + + #include "wine/list.h" + +-- +2.3.3 + diff --git a/patches/dsound-EAX/0003-dsound-Report-that-we-support-EAX-v1.patch b/patches/dsound-EAX/0003-dsound-Report-that-we-support-EAX-v1.patch new file mode 100644 index 00000000..4eebaec7 --- /dev/null +++ b/patches/dsound-EAX/0003-dsound-Report-that-we-support-EAX-v1.patch @@ -0,0 +1,35 @@ +From 8d33bbc39a573848f00c95699ec8c0eee9fdb416 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 15 Mar 2015 18:04:38 +0000 +Subject: dsound: Report that we support EAX v1. + +--- + dlls/dsound/buffer.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c +index d735dc3..9eff140 100644 +--- a/dlls/dsound/buffer.c ++++ b/dlls/dsound/buffer.c +@@ -1319,6 +1319,18 @@ static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REF + + TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport); + ++ if (IsEqualGUID(&DSPROPSETID_EAX_ReverbProperties, guidPropSet)) { ++ if (dwPropID <= DSPROPERTY_EAX_DAMPING) { ++ *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; ++ return S_OK; ++ } ++ } else if (IsEqualGUID(&DSPROPSETID_EAXBUFFER_ReverbProperties, guidPropSet)) { ++ if (dwPropID <= DSPROPERTY_EAXBUFFER_REVERBMIX) { ++ *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; ++ return S_OK; ++ } ++ } ++ + return E_PROP_ID_UNSUPPORTED; + } + +-- +2.3.3 + diff --git a/patches/dsound-EAX/0004-dsound-Add-EAX-propset-stubs.patch b/patches/dsound-EAX/0004-dsound-Add-EAX-propset-stubs.patch new file mode 100644 index 00000000..c93b7333 --- /dev/null +++ b/patches/dsound-EAX/0004-dsound-Add-EAX-propset-stubs.patch @@ -0,0 +1,131 @@ +From 601e237d1321fcdea3a678c31fd9eac62b89cfb4 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 13:58:53 +0000 +Subject: dsound: Add EAX propset stubs. + +--- + dlls/dsound/Makefile.in | 1 + + dlls/dsound/buffer.c | 6 +++++ + dlls/dsound/dsound_private.h | 8 +++++++ + dlls/dsound/eax.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 69 insertions(+) + create mode 100644 dlls/dsound/eax.c + +diff --git a/dlls/dsound/Makefile.in b/dlls/dsound/Makefile.in +index 6cb653f..1c04bf3 100644 +--- a/dlls/dsound/Makefile.in ++++ b/dlls/dsound/Makefile.in +@@ -9,6 +9,7 @@ C_SRCS = \ + dsound_convert.c \ + dsound_main.c \ + duplex.c \ ++ eax.c \ + mixer.c \ + primary.c \ + propset.c \ +diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c +index 9eff140..0596ce3 100644 +--- a/dlls/dsound/buffer.c ++++ b/dlls/dsound/buffer.c +@@ -1298,6 +1298,9 @@ static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guid + TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n", + This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned); + ++ if (IsEqualGUID(&DSPROPSETID_EAX_ReverbProperties, guidPropSet) || IsEqualGUID(&DSPROPSETID_EAXBUFFER_ReverbProperties, guidPropSet)) ++ return EAX_Get(This, guidPropSet, dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned); ++ + return E_PROP_ID_UNSUPPORTED; + } + +@@ -1309,6 +1312,9 @@ static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guid + + TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData); + ++ if (IsEqualGUID(&DSPROPSETID_EAX_ReverbProperties, guidPropSet) || IsEqualGUID(&DSPROPSETID_EAXBUFFER_ReverbProperties, guidPropSet)) ++ return EAX_Set(This, guidPropSet, dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData); ++ + return E_PROP_ID_UNSUPPORTED; + } + +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index 3c7dc7a..e4495b2 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -229,6 +229,14 @@ LONG capped_refcount_dec(LONG *ref) DECLSPEC_HIDDEN; + + HRESULT DSOUND_FullDuplexCreate(REFIID riid, void **ppv) DECLSPEC_HIDDEN; + ++/* eax.c */ ++HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, ++ ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ++ ULONG cbPropData, ULONG *pcbReturned) DECLSPEC_HIDDEN; ++HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, ++ ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ++ ULONG cbPropData) DECLSPEC_HIDDEN; ++ + /* mixer.c */ + void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len) DECLSPEC_HIDDEN; + void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan) DECLSPEC_HIDDEN; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +new file mode 100644 +index 0000000..c30c7e1 +--- /dev/null ++++ b/dlls/dsound/eax.c +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2015 Mark Harmstone ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include ++#include ++ ++#include "windef.h" ++#include "winbase.h" ++#include "winuser.h" ++#include "mmsystem.h" ++#include "winternl.h" ++#include "vfwmsgs.h" ++#include "wine/debug.h" ++#include "dsound.h" ++#include "dsound_private.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(eax); ++ ++HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, ++ ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ++ ULONG cbPropData, ULONG *pcbReturned) ++{ ++ TRACE("(buf=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n", ++ buf, debugstr_guid(guidPropSet), dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned); ++ ++ *pcbReturned = 0; ++ ++ return E_PROP_ID_UNSUPPORTED; ++} ++ ++HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, ++ ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ++ ULONG cbPropData) ++{ ++ TRACE("(%p,%s,%d,%p,%d,%p,%d)\n", ++ buf, debugstr_guid(guidPropSet), dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData); ++ ++ return E_PROP_ID_UNSUPPORTED; ++} +-- +2.3.3 + diff --git a/patches/dsound-EAX/0005-dsound-Add-EAX-presets.patch b/patches/dsound-EAX/0005-dsound-Add-EAX-presets.patch new file mode 100644 index 00000000..ae4dbb5b --- /dev/null +++ b/patches/dsound-EAX/0005-dsound-Add-EAX-presets.patch @@ -0,0 +1,149 @@ +From e46e2000764539dab113dd508b6a20beba953c87 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 14:10:06 +0000 +Subject: dsound: Add EAX presets. + +--- + dlls/dsound/dsound_eax.h | 29 +++++++++++++++++++++++ + dlls/dsound/eax.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 90 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 600029f..06d961e 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -1,4 +1,5 @@ + /* ++ * Copyright (c) 2008-2009 Christopher Fitzgerald + * Copyright (c) 2015 Mark Harmstone + * + * This library is free software; you can redistribute it and/or +@@ -16,6 +17,8 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + ++/* Taken in large part from OpenAL. */ ++ + #ifndef DSOUND_EAX_H_DEFINED + #define DSOUND_EAX_H_DEFINED + +@@ -82,6 +85,32 @@ typedef struct { + + #define EAX_REVERBMIX_USEDISTANCE -1.0f + ++typedef struct { ++ float flDensity; ++ float flDiffusion; ++ float flGain; ++ float flGainHF; ++ float flGainLF; ++ float flDecayTime; ++ float flDecayHFRatio; ++ float flDecayLFRatio; ++ float flReflectionsGain; ++ float flReflectionsDelay; ++ float flReflectionsPan[3]; ++ float flLateReverbGain; ++ float flLateReverbDelay; ++ float flLateReverbPan[3]; ++ float flEchoTime; ++ float flEchoDepth; ++ float flModulationTime; ++ float flModulationDepth; ++ float flAirAbsorptionGainHF; ++ float flHFReference; ++ float flLFReference; ++ float flRoomRolloffFactor; ++ int iDecayHFLimit; ++} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; ++ + #ifdef __cplusplus + } + #endif +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index c30c7e1..57d88e7 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -1,4 +1,5 @@ + /* ++ * Copyright (c) 2008-2009 Christopher Fitzgerald + * Copyright (c) 2015 Mark Harmstone + * + * This library is free software; you can redistribute it and/or +@@ -16,6 +17,8 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + ++/* Taken in large part from OpenAL's Alc/alcReverb.c. */ ++ + #include + #include + +@@ -31,6 +34,64 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(eax); + ++static const EAX_REVERBPROPERTIES presets[] = { ++ { EAX_ENVIRONMENT_GENERIC, 0.5f, 1.493f, 0.5f }, ++ { EAX_ENVIRONMENT_PADDEDCELL, 0.25f, 0.1f, 0.0f }, ++ { EAX_ENVIRONMENT_ROOM, 0.417f, 0.4f, 0.666f }, ++ { EAX_ENVIRONMENT_BATHROOM, 0.653f, 1.499f, 0.166f }, ++ { EAX_ENVIRONMENT_LIVINGROOM, 0.208f, 0.478f, 0.0f }, ++ { EAX_ENVIRONMENT_STONEROOM, 0.5f, 2.309f, 0.888f }, ++ { EAX_ENVIRONMENT_AUDITORIUM, 0.403f, 4.279f, 0.5f }, ++ { EAX_ENVIRONMENT_CONCERTHALL, 0.5f, 3.961f, 0.5f }, ++ { EAX_ENVIRONMENT_CAVE, 0.5f, 2.886f, 1.304f }, ++ { EAX_ENVIRONMENT_ARENA, 0.361f, 7.284f, 0.332f }, ++ { EAX_ENVIRONMENT_HANGAR, 0.5f, 10.0f, 0.3f }, ++ { EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153f, 0.259f, 2.0f }, ++ { EAX_ENVIRONMENT_HALLWAY, 0.361f, 1.493f, 0.0f }, ++ { EAX_ENVIRONMENT_STONECORRIDOR, 0.444f, 2.697f, 0.638f }, ++ { EAX_ENVIRONMENT_ALLEY, 0.25f, 1.752f, 0.776f }, ++ { EAX_ENVIRONMENT_FOREST, 0.111f, 3.145f, 0.472f }, ++ { EAX_ENVIRONMENT_CITY, 0.111f, 2.767f, 0.224f }, ++ { EAX_ENVIRONMENT_MOUNTAINS, 0.194f, 7.841f, 0.472f }, ++ { EAX_ENVIRONMENT_QUARRY, 1.0f, 1.499f, 0.5f }, ++ { EAX_ENVIRONMENT_PLAIN, 0.097f, 2.767f, 0.224f }, ++ { EAX_ENVIRONMENT_PARKINGLOT, 0.208f, 1.652f, 1.5f }, ++ { EAX_ENVIRONMENT_SEWERPIPE, 0.652f, 2.886f, 0.25f }, ++ { EAX_ENVIRONMENT_UNDERWATER, 1.0f, 1.499f, 0.0f }, ++ { EAX_ENVIRONMENT_DRUGGED, 0.875f, 8.392f, 1.388f }, ++ { EAX_ENVIRONMENT_DIZZY, 0.139f, 17.234f, 0.666f }, ++ { EAX_ENVIRONMENT_PSYCHOTIC, 0.486f, 7.563f, 0.806f } ++}; ++ ++static const EFXEAXREVERBPROPERTIES efx_presets[] = { ++ { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* generic */ ++ { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* padded cell */ ++ { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* room */ ++ { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* bathroom */ ++ { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* living room */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* stone room */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* auditorium */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* concert hall */ ++ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }, /* cave */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* arena */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* hangar */ ++ { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* carpeted hallway */ ++ { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* hallway */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* stone corridor */ ++ { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* alley */ ++ { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* forest */ ++ { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* city */ ++ { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }, /* mountains */ ++ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* quarry */ ++ { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* plain */ ++ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }, /* parking lot */ ++ { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* sewer pipe */ ++ { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }, /* underwater */ ++ { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }, /* drugged */ ++ { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }, /* dizzy */ ++ { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ ++}; ++ + HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, + ULONG cbPropData, ULONG *pcbReturned) +-- +2.3.3 + diff --git a/patches/dsound-EAX/0006-dsound-Support-getting-and-setting-EAX-properties.patch b/patches/dsound-EAX/0006-dsound-Support-getting-and-setting-EAX-properties.patch new file mode 100644 index 00000000..c8348005 --- /dev/null +++ b/patches/dsound-EAX/0006-dsound-Support-getting-and-setting-EAX-properties.patch @@ -0,0 +1,240 @@ +From fe1de4d0856517f1ce59a3a5eb15a13f6ce4a9e6 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 14:22:02 +0000 +Subject: dsound: Support getting and setting EAX properties. + +--- + dlls/dsound/dsound_eax.h | 8 +++ + dlls/dsound/dsound_private.h | 2 + + dlls/dsound/eax.c | 167 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 177 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 06d961e..c90d82d 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -111,6 +111,14 @@ typedef struct { + int iDecayHFLimit; + } EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; + ++typedef struct { ++ BOOL using_eax; ++ unsigned long environment; ++ float volume; ++ float damping; ++ EFXEAXREVERBPROPERTIES eax_props; ++} eax_info; ++ + #ifdef __cplusplus + } + #endif +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index e4495b2..c16f770 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -99,6 +99,8 @@ struct DirectSoundDevice + + normfunc normfunction; + ++ eax_info eax; ++ + /* DirectSound3DListener fields */ + DS3DLISTENER ds3dl; + BOOL ds3dl_need_recalc; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 57d88e7..cdd03be 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,6 +92,22 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) ++{ ++ /* stub */ ++ return TRUE; ++} ++ ++static void init_eax(DirectSoundDevice *dev) ++{ ++ dev->eax.using_eax = TRUE; ++ dev->eax.environment = presets[0].environment; ++ dev->eax.volume = presets[0].fVolume; ++ dev->eax.damping = presets[0].fDamping; ++ memcpy(&dev->eax.eax_props, &efx_presets[0], sizeof(dev->eax.eax_props)); ++ dev->eax.eax_props.flDecayTime = presets[0].fDecayTime_sec; ++} ++ + HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, + ULONG cbPropData, ULONG *pcbReturned) +@@ -101,6 +117,70 @@ HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + + *pcbReturned = 0; + ++ if (IsEqualGUID(&DSPROPSETID_EAX_ReverbProperties, guidPropSet)) { ++ EAX_REVERBPROPERTIES *props; ++ ++ if (!buf->device->eax.using_eax) ++ init_eax(buf->device); ++ ++ switch (dwPropID) { ++ case DSPROPERTY_EAX_ALL: ++ if (cbPropData < sizeof(EAX_REVERBPROPERTIES)) ++ return E_FAIL; ++ ++ props = pPropData; ++ ++ props->environment = buf->device->eax.environment; ++ props->fVolume = buf->device->eax.volume; ++ props->fDecayTime_sec = buf->device->eax.eax_props.flDecayTime; ++ props->fDamping = buf->device->eax.damping; ++ ++ *pcbReturned = sizeof(EAX_REVERBPROPERTIES); ++ break; ++ ++ case DSPROPERTY_EAX_ENVIRONMENT: ++ if (cbPropData < sizeof(unsigned long)) ++ return E_FAIL; ++ ++ *(unsigned long*)pPropData = buf->device->eax.environment; ++ ++ *pcbReturned = sizeof(unsigned long); ++ break; ++ ++ case DSPROPERTY_EAX_VOLUME: ++ if (cbPropData < sizeof(float)) ++ return E_FAIL; ++ ++ *(float*)pPropData = buf->device->eax.volume; ++ ++ *pcbReturned = sizeof(float); ++ break; ++ ++ case DSPROPERTY_EAX_DECAYTIME: ++ if (cbPropData < sizeof(float)) ++ return E_FAIL; ++ ++ *(float*)pPropData = buf->device->eax.eax_props.flDecayTime; ++ ++ *pcbReturned = sizeof(float); ++ break; ++ ++ case DSPROPERTY_EAX_DAMPING: ++ if (cbPropData < sizeof(float)) ++ return E_FAIL; ++ ++ *(float*)pPropData = buf->device->eax.damping; ++ ++ *pcbReturned = sizeof(float); ++ break; ++ ++ default: ++ return E_PROP_ID_UNSUPPORTED; ++ } ++ ++ return S_OK; ++ } ++ + return E_PROP_ID_UNSUPPORTED; + } + +@@ -108,8 +188,95 @@ HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, + ULONG cbPropData) + { ++ EAX_REVERBPROPERTIES *props; ++ + TRACE("(%p,%s,%d,%p,%d,%p,%d)\n", + buf, debugstr_guid(guidPropSet), dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData); + ++ if (IsEqualGUID(&DSPROPSETID_EAX_ReverbProperties, guidPropSet)) { ++ if (!buf->device->eax.using_eax) ++ init_eax(buf->device); ++ ++ switch (dwPropID) { ++ case DSPROPERTY_EAX_ALL: ++ if (cbPropData != sizeof(EAX_REVERBPROPERTIES)) ++ return E_FAIL; ++ ++ props = pPropData; ++ ++ TRACE("setting environment = %lu, fVolume = %f, fDecayTime_sec = %f, fDamping = %f\n", ++ props->environment, props->fVolume, props->fDecayTime_sec, ++ props->fDamping); ++ ++ buf->device->eax.environment = props->environment; ++ ++ if (buf->device->eax.environment < EAX_ENVIRONMENT_COUNT) ++ memcpy(&buf->device->eax.eax_props, &efx_presets[buf->device->eax.environment], sizeof(buf->device->eax.eax_props)); ++ ++ buf->device->eax.volume = props->fVolume; ++ buf->device->eax.eax_props.flDecayTime = props->fDecayTime_sec; ++ buf->device->eax.damping = props->fDamping; ++ ++ ReverbDeviceUpdate(buf->device); ++ break; ++ ++ case DSPROPERTY_EAX_ENVIRONMENT: ++ if (cbPropData != sizeof(unsigned long)) ++ return E_FAIL; ++ ++ TRACE("setting environment to %lu\n", *(unsigned long*)pPropData); ++ ++ buf->device->eax.environment = *(unsigned long*)pPropData; ++ ++ if (buf->device->eax.environment < EAX_ENVIRONMENT_COUNT) { ++ memcpy(&buf->device->eax.eax_props, &efx_presets[buf->device->eax.environment], sizeof(buf->device->eax.eax_props)); ++ buf->device->eax.volume = presets[buf->device->eax.environment].fVolume; ++ buf->device->eax.eax_props.flDecayTime = presets[buf->device->eax.environment].fDecayTime_sec; ++ buf->device->eax.damping = presets[buf->device->eax.environment].fDamping; ++ } ++ ++ ReverbDeviceUpdate(buf->device); ++ break; ++ ++ case DSPROPERTY_EAX_VOLUME: ++ if (cbPropData != sizeof(float)) ++ return E_FAIL; ++ ++ TRACE("setting volume to %f\n", *(float*)pPropData); ++ ++ buf->device->eax.volume = *(float*)pPropData; ++ ++ ReverbDeviceUpdate(buf->device); ++ break; ++ ++ case DSPROPERTY_EAX_DECAYTIME: ++ if (cbPropData != sizeof(float)) ++ return E_FAIL; ++ ++ TRACE("setting decay time to %f\n", *(float*)pPropData); ++ ++ buf->device->eax.eax_props.flDecayTime = *(float*)pPropData; ++ ++ ReverbDeviceUpdate(buf->device); ++ break; ++ ++ case DSPROPERTY_EAX_DAMPING: ++ if (cbPropData != sizeof(float)) ++ return E_FAIL; ++ ++ TRACE("setting damping to %f\n", *(float*)pPropData); ++ ++ buf->device->eax.damping = *(float*)pPropData; ++ ++ ReverbDeviceUpdate(buf->device); ++ break; ++ ++ default: ++ return E_PROP_ID_UNSUPPORTED; ++ } ++ ++ return S_OK; ++ } ++ + return E_PROP_ID_UNSUPPORTED; + } +-- +2.3.3 + diff --git a/patches/dsound-EAX/0007-dsound-Support-getting-and-setting-EAX-buffer-proper.patch b/patches/dsound-EAX/0007-dsound-Support-getting-and-setting-EAX-buffer-proper.patch new file mode 100644 index 00000000..0fad271e --- /dev/null +++ b/patches/dsound-EAX/0007-dsound-Support-getting-and-setting-EAX-buffer-proper.patch @@ -0,0 +1,138 @@ +From 43637cb46c48e84e7f1b127ba4427900c76f2470 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Fri, 27 Mar 2015 20:48:19 +0000 +Subject: dsound: Support getting and setting EAX buffer properties. + +--- + dlls/dsound/buffer.c | 2 ++ + dlls/dsound/dsound_eax.h | 4 +++ + dlls/dsound/dsound_private.h | 2 ++ + dlls/dsound/eax.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 72 insertions(+) + +diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c +index 0596ce3..1c318f5 100644 +--- a/dlls/dsound/buffer.c ++++ b/dlls/dsound/buffer.c +@@ -1092,6 +1092,8 @@ HRESULT IDirectSoundBufferImpl_Create( + /* calculate fragment size and write lead */ + DSOUND_RecalcFormat(dsb); + ++ dsb->eax.reverb_mix = EAX_REVERBMIX_USEDISTANCE; ++ + if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) { + dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); + dsb->ds3db_ds3db.vPosition.x = 0.0; +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index c90d82d..2ee83b9 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -119,6 +119,10 @@ typedef struct { + EFXEAXREVERBPROPERTIES eax_props; + } eax_info; + ++typedef struct { ++ float reverb_mix; ++} eax_buffer_info; ++ + #ifdef __cplusplus + } + #endif +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index c16f770..c732b52 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -176,6 +176,8 @@ struct IDirectSoundBufferImpl + int num_filters; + DSFilter* filters; + ++ eax_buffer_info eax; ++ + struct list entry; + }; + +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index cdd03be..3931681 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -179,6 +179,38 @@ HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + } + + return S_OK; ++ } else if (IsEqualGUID(&DSPROPSETID_EAXBUFFER_ReverbProperties, guidPropSet)) { ++ EAXBUFFER_REVERBPROPERTIES *props; ++ ++ if (!buf->device->eax.using_eax) ++ init_eax(buf->device); ++ ++ switch (dwPropID) { ++ case DSPROPERTY_EAXBUFFER_ALL: ++ if (cbPropData < sizeof(EAXBUFFER_REVERBPROPERTIES)) ++ return E_FAIL; ++ ++ props = pPropData; ++ ++ props->fMix = buf->eax.reverb_mix; ++ ++ *pcbReturned = sizeof(EAXBUFFER_REVERBPROPERTIES); ++ break; ++ ++ case DSPROPERTY_EAXBUFFER_REVERBMIX: ++ if (cbPropData < sizeof(float)) ++ return E_FAIL; ++ ++ *(float*)pPropData = buf->eax.reverb_mix; ++ ++ *pcbReturned = sizeof(float); ++ break; ++ ++ default: ++ return E_PROP_ID_UNSUPPORTED; ++ } ++ ++ return S_OK; + } + + return E_PROP_ID_UNSUPPORTED; +@@ -276,6 +308,38 @@ HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + } + + return S_OK; ++ } else if (IsEqualGUID(&DSPROPSETID_EAXBUFFER_ReverbProperties, guidPropSet)) { ++ EAXBUFFER_REVERBPROPERTIES *props; ++ ++ if (!buf->device->eax.using_eax) ++ init_eax(buf->device); ++ ++ switch (dwPropID) { ++ case DSPROPERTY_EAXBUFFER_ALL: ++ if (cbPropData != sizeof(EAXBUFFER_REVERBPROPERTIES)) ++ return E_FAIL; ++ ++ props = pPropData; ++ ++ TRACE("setting reverb mix to %f\n", props->fMix); ++ ++ buf->eax.reverb_mix = props->fMix; ++ break; ++ ++ case DSPROPERTY_EAXBUFFER_REVERBMIX: ++ if (cbPropData != sizeof(float)) ++ return E_FAIL; ++ ++ TRACE("setting reverb mix to %f\n", *(float*)pPropData); ++ ++ buf->eax.reverb_mix = *(float*)pPropData; ++ break; ++ ++ default: ++ return E_PROP_ID_UNSUPPORTED; ++ } ++ ++ return S_OK; + } + + return E_PROP_ID_UNSUPPORTED; +-- +2.3.3 + diff --git a/patches/dsound-EAX/0008-dsound-Add-EAX-init-and-free-stubs.patch b/patches/dsound-EAX/0008-dsound-Add-EAX-init-and-free-stubs.patch new file mode 100644 index 00000000..096f8f6b --- /dev/null +++ b/patches/dsound-EAX/0008-dsound-Add-EAX-init-and-free-stubs.patch @@ -0,0 +1,102 @@ +From 76cd66f5f32045665fe392401b63738a5a089072 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Fri, 27 Mar 2015 20:58:37 +0000 +Subject: dsound: Add EAX init and free stubs. + +--- + dlls/dsound/buffer.c | 5 +++++ + dlls/dsound/dsound_private.h | 2 ++ + dlls/dsound/eax.c | 28 +++++++++++++++++++++++++++- + 3 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c +index 1c318f5..c098043 100644 +--- a/dlls/dsound/buffer.c ++++ b/dlls/dsound/buffer.c +@@ -1130,6 +1130,9 @@ HRESULT IDirectSoundBufferImpl_Create( + HeapFree(GetProcessHeap(),0,dsb); + dsb = NULL; + } ++ ++ if (dsb->device->eax.using_eax) ++ init_eax_buffer(dsb); + } + + IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface); +@@ -1169,6 +1172,8 @@ void secondarybuffer_destroy(IDirectSoundBufferImpl *This) + HeapFree(GetProcessHeap(), 0, This->filters); + } + ++ free_eax_buffer(This); ++ + HeapFree(GetProcessHeap(), 0, This); + + TRACE("(%p) released\n", This); +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index c732b52..a918cd2 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -240,6 +240,8 @@ HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, + ULONG cbPropData) DECLSPEC_HIDDEN; ++void free_eax_buffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN; ++void init_eax_buffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN; + + /* mixer.c */ + void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len) DECLSPEC_HIDDEN; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 3931681..c0afb0f 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,20 +92,46 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + +-static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) ++static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { + /* stub */ ++} ++ ++static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->nrofbuffers; i++) { ++ ReverbUpdate(dev->buffers[i]); ++ } ++ + return TRUE; + } + ++void init_eax_buffer(IDirectSoundBufferImpl *dsb) ++{ ++ ReverbUpdate(dsb); ++} ++ + static void init_eax(DirectSoundDevice *dev) + { ++ int i; ++ + dev->eax.using_eax = TRUE; + dev->eax.environment = presets[0].environment; + dev->eax.volume = presets[0].fVolume; + dev->eax.damping = presets[0].fDamping; + memcpy(&dev->eax.eax_props, &efx_presets[0], sizeof(dev->eax.eax_props)); + dev->eax.eax_props.flDecayTime = presets[0].fDecayTime_sec; ++ ++ for (i = 0; i < dev->nrofbuffers; i++) { ++ init_eax_buffer(dev->buffers[i]); ++ } ++} ++ ++void free_eax_buffer(IDirectSoundBufferImpl *dsb) ++{ ++ /* stub */ + } + + HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, +-- +2.3.3 + diff --git a/patches/dsound-EAX/0009-dsound-Feed-data-through-EAX-function.patch b/patches/dsound-EAX/0009-dsound-Feed-data-through-EAX-function.patch new file mode 100644 index 00000000..9d928b63 --- /dev/null +++ b/patches/dsound-EAX/0009-dsound-Feed-data-through-EAX-function.patch @@ -0,0 +1,65 @@ +From 735da63bda0fed9b01779bd8922a4cc13b05d598 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Fri, 27 Mar 2015 20:59:57 +0000 +Subject: dsound: Feed data through EAX function. + +--- + dlls/dsound/dsound_private.h | 1 + + dlls/dsound/eax.c | 5 +++++ + dlls/dsound/mixer.c | 5 ++++- + 3 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h +index a918cd2..cc55d70 100644 +--- a/dlls/dsound/dsound_private.h ++++ b/dlls/dsound/dsound_private.h +@@ -242,6 +242,7 @@ HRESULT WINAPI EAX_Set(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, + ULONG cbPropData) DECLSPEC_HIDDEN; + void free_eax_buffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN; + void init_eax_buffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN; ++void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) DECLSPEC_HIDDEN; + + /* mixer.c */ + void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len) DECLSPEC_HIDDEN; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index c0afb0f..4368594 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,6 +92,11 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) ++{ ++ /* stub */ ++} ++ + static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { + /* stub */ +diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c +index ff92cc1..b159834 100644 +--- a/dlls/dsound/mixer.c ++++ b/dlls/dsound/mixer.c +@@ -453,7 +453,7 @@ static void putieee32_dsp(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD ch + */ + static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames) + { +- BOOL using_filters = dsb->num_filters > 0; ++ BOOL using_filters = dsb->num_filters > 0 || dsb->device->eax.using_eax; + UINT istride, ostride, size_bytes; + DWORD channel, i; + bitsputfunc put; +@@ -500,6 +500,9 @@ static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames) + } + } + ++ if (dsb->device->eax.using_eax) ++ process_eax_buffer(dsb, dsb->device->dsp_buffer, frames * dsb->mix_channels); ++ + istride = ostride; + ostride = dsb->device->pwfx->nChannels * sizeof(float); + for (i = 0; i < frames; i++) { +-- +2.3.3 + diff --git a/patches/dsound-EAX/0010-dsound-Allocate-EAX-delay-lines.patch b/patches/dsound-EAX/0010-dsound-Allocate-EAX-delay-lines.patch new file mode 100644 index 00000000..1a54035b --- /dev/null +++ b/patches/dsound-EAX/0010-dsound-Allocate-EAX-delay-lines.patch @@ -0,0 +1,184 @@ +From 213aef0ba57c925f48c36e6167584a4ee0b7587b Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Fri, 27 Mar 2015 21:06:42 +0000 +Subject: dsound: Allocate EAX delay lines. + +--- + dlls/dsound/dsound_eax.h | 16 ++++++++ + dlls/dsound/eax.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 112 insertions(+), 2 deletions(-) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 2ee83b9..132f060 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -85,6 +85,9 @@ typedef struct { + + #define EAX_REVERBMIX_USEDISTANCE -1.0f + ++#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) ++#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) ++ + typedef struct { + float flDensity; + float flDiffusion; +@@ -111,6 +114,12 @@ typedef struct { + int iDecayHFLimit; + } EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; + ++typedef struct DelayLine ++{ ++ unsigned int Mask; ++ float *Line; ++} DelayLine; ++ + typedef struct { + BOOL using_eax; + unsigned long environment; +@@ -121,6 +130,13 @@ typedef struct { + + typedef struct { + float reverb_mix; ++ ++ float *SampleBuffer; ++ unsigned int TotalSamples; ++ ++ DelayLine Delay; ++ ++ unsigned int Offset; + } eax_buffer_info; + + #ifdef __cplusplus +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 4368594..babc2a7 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,14 +92,99 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static unsigned int fastf2u(float f) ++{ ++ return (unsigned int)f; ++} ++ + void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) + { + /* stub */ + } + ++static unsigned int NextPowerOf2(unsigned int value) ++{ ++ if (value > 0) ++ { ++ value--; ++ value |= value>>1; ++ value |= value>>2; ++ value |= value>>4; ++ value |= value>>8; ++ value |= value>>16; ++ } ++ return value+1; ++} ++ ++static unsigned int CalcLineLength(float length, unsigned int offset, unsigned int frequency, DelayLine *Delay) ++{ ++ unsigned int samples; ++ ++ /* All line lengths are powers of 2, calculated from their lengths, with ++ * an additional sample in case of rounding errors. */ ++ samples = NextPowerOf2(fastf2u(length * frequency) + 1); ++ /* All lines share a single sample buffer. */ ++ Delay->Mask = samples - 1; ++ Delay->Line = (float*)offset; ++ /* Return the sample count for accumulation. */ ++ return samples; ++} ++ ++static void RealizeLineOffset(float *sampleBuffer, DelayLine *Delay) ++{ ++ Delay->Line = &sampleBuffer[(unsigned int)Delay->Line]; ++} ++ ++static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) ++{ ++ unsigned int totalSamples, index; ++ float length; ++ float *newBuffer = NULL; ++ ++ /* All delay line lengths are calculated to accomodate the full range of ++ * lengths given their respective paramters. */ ++ totalSamples = 0; ++ ++ /* The initial delay is the sum of the reflections and late reverb ++ * delays. */ ++ length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + ++ AL_EAXREVERB_MAX_LATE_REVERB_DELAY; ++ totalSamples += CalcLineLength(length, totalSamples, frequency, ++ &dsb->eax.Delay); ++ ++ if (totalSamples != dsb->eax.TotalSamples) ++ { ++ TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); ++ ++ if (dsb->eax.SampleBuffer) ++ newBuffer = HeapReAlloc(GetProcessHeap(), 0, dsb->eax.SampleBuffer, sizeof(float) * totalSamples); ++ else ++ newBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(float) * totalSamples); ++ ++ if (newBuffer == NULL) ++ return FALSE; ++ dsb->eax.SampleBuffer = newBuffer; ++ dsb->eax.TotalSamples = totalSamples; ++ } ++ ++ /* Update all delays to reflect the new sample buffer. */ ++ RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Delay); ++ ++ /* Clear the sample buffer. */ ++ for (index = 0; index < dsb->eax.TotalSamples; index++) ++ dsb->eax.SampleBuffer[index] = 0.0f; ++ ++ return TRUE; ++} ++ + static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { +- /* stub */ ++ /* avoid segfaults in mixing thread when we recalculate the line offsets */ ++ EnterCriticalSection(&dsb->device->mixlock); ++ ++ AllocLines(dsb->device->pwfx->nSamplesPerSec, dsb); ++ ++ LeaveCriticalSection(&dsb->device->mixlock); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -115,6 +200,14 @@ static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) + + void init_eax_buffer(IDirectSoundBufferImpl *dsb) + { ++ dsb->eax.TotalSamples = 0; ++ dsb->eax.SampleBuffer = NULL; ++ ++ dsb->eax.Delay.Mask = 0; ++ dsb->eax.Delay.Line = NULL; ++ ++ dsb->eax.Offset = 0; ++ + ReverbUpdate(dsb); + } + +@@ -136,7 +229,8 @@ static void init_eax(DirectSoundDevice *dev) + + void free_eax_buffer(IDirectSoundBufferImpl *dsb) + { +- /* stub */ ++ if (dsb->eax.SampleBuffer) ++ HeapFree(GetProcessHeap(), 0, dsb->eax.SampleBuffer); + } + + HRESULT WINAPI EAX_Get(IDirectSoundBufferImpl *buf, REFGUID guidPropSet, +-- +2.3.3 + diff --git a/patches/dsound-EAX/0011-dsound-Add-EAX-VerbPass-stub.patch b/patches/dsound-EAX/0011-dsound-Add-EAX-VerbPass-stub.patch new file mode 100644 index 00000000..3a52fb56 --- /dev/null +++ b/patches/dsound-EAX/0011-dsound-Add-EAX-VerbPass-stub.patch @@ -0,0 +1,67 @@ +From de72257b18ac1a07ed770f20bede6b42e5baa99b Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 15:38:15 +0000 +Subject: dsound: Add EAX VerbPass stub. + +--- + dlls/dsound/eax.c | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index babc2a7..6ac4cdf 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,6 +92,14 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) ++{ ++ /* stub */ ++ ++ /* Step all delays forward one sample. */ ++ dsb->eax.Offset++; ++} ++ + static unsigned int fastf2u(float f) + { + return (unsigned int)f; +@@ -99,7 +107,34 @@ static unsigned int fastf2u(float f) + + void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) + { +- /* stub */ ++ int i; ++ float* out; ++ float gain; ++ ++ if (dsb->device->eax.volume == 0.0f) ++ return; ++ ++ if (dsb->mix_channels > 1) { ++ WARN("EAX not yet supported for non-mono sources\n"); ++ return; ++ } ++ ++ out = HeapAlloc(GetProcessHeap(), 0, sizeof(float)*count*4); ++ ++ for (i = 0; i < count; i++) { ++ VerbPass(dsb, buf[i], &out[i*4]); ++ } ++ ++ if (dsb->eax.reverb_mix == EAX_REVERBMIX_USEDISTANCE) ++ gain = 1.0f; /* FIXME - should be calculated from distance */ ++ else ++ gain = dsb->eax.reverb_mix; ++ ++ for (i = 0; i < count; i++) { ++ buf[i] += gain * out[i*4]; ++ } ++ ++ HeapFree(GetProcessHeap(), 0, out); + } + + static unsigned int NextPowerOf2(unsigned int value) +-- +2.3.3 + diff --git a/patches/dsound-EAX/0012-dsound-Implement-EAX-lowpass-filter.patch b/patches/dsound-EAX/0012-dsound-Implement-EAX-lowpass-filter.patch new file mode 100644 index 00000000..aaf0afa3 --- /dev/null +++ b/patches/dsound-EAX/0012-dsound-Implement-EAX-lowpass-filter.patch @@ -0,0 +1,126 @@ +From 858f3b43a1197c3b9a8e6f2228995451776b29b4 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 17:57:38 +0000 +Subject: dsound: Implement EAX lowpass filter. + +--- + dlls/dsound/dsound_eax.h | 7 +++++++ + dlls/dsound/eax.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 54 insertions(+), 1 deletion(-) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 132f060..82b1408 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -121,6 +121,11 @@ typedef struct DelayLine + } DelayLine; + + typedef struct { ++ float coeff; ++ float history[2]; ++} FILTER; ++ ++typedef struct { + BOOL using_eax; + unsigned long environment; + float volume; +@@ -134,6 +139,8 @@ typedef struct { + float *SampleBuffer; + unsigned int TotalSamples; + ++ FILTER LpFilter; ++ + DelayLine Delay; + + unsigned int Offset; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 6ac4cdf..bbb5dad 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,9 +92,24 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static float lpFilter2P(FILTER *iir, unsigned int offset, float input) ++{ ++ float *history = &iir->history[offset*2]; ++ float a = iir->coeff; ++ float output = input; ++ ++ output = output + (history[0]-output)*a; ++ history[0] = output; ++ output = output + (history[1]-output)*a; ++ history[1] = output; ++ ++ return output; ++} ++ + static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + { +- /* stub */ ++ /* Low-pass filter the incoming sample. */ ++ in = lpFilter2P(&dsb->eax.LpFilter, 0, in); + + /* Step all delays forward one sample. */ + dsb->eax.Offset++; +@@ -137,6 +152,27 @@ void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) + HeapFree(GetProcessHeap(), 0, out); + } + ++static float lpCoeffCalc(float g, float cw) ++{ ++ float a = 0.0f; ++ ++ if (g < 0.9999f) /* 1-epsilon */ ++ { ++ /* Be careful with gains < 0.001, as that causes the coefficient head ++ * towards 1, which will flatten the signal */ ++ if (g < 0.001f) g = 0.001f; ++ a = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) / ++ (1 - g); ++ } ++ ++ return a; ++} ++ ++static float CalcI3DL2HFreq(float hfRef, unsigned int frequency) ++{ ++ return cosf(M_PI*2.0f * hfRef / frequency); ++} ++ + static unsigned int NextPowerOf2(unsigned int value) + { + if (value > 0) +@@ -214,12 +250,18 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + + static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { ++ float cw; ++ + /* avoid segfaults in mixing thread when we recalculate the line offsets */ + EnterCriticalSection(&dsb->device->mixlock); + + AllocLines(dsb->device->pwfx->nSamplesPerSec, dsb); + + LeaveCriticalSection(&dsb->device->mixlock); ++ ++ cw = CalcI3DL2HFreq(dsb->device->eax.eax_props.flHFReference, dsb->device->pwfx->nSamplesPerSec); ++ ++ dsb->eax.LpFilter.coeff = lpCoeffCalc(dsb->device->eax.eax_props.flGainHF, cw); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -238,6 +280,10 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + dsb->eax.TotalSamples = 0; + dsb->eax.SampleBuffer = NULL; + ++ dsb->eax.LpFilter.coeff = 0.0f; ++ dsb->eax.LpFilter.history[0] = 0.0f; ++ dsb->eax.LpFilter.history[1] = 0.0f; ++ + dsb->eax.Delay.Mask = 0; + dsb->eax.Delay.Line = NULL; + +-- +2.3.3 + diff --git a/patches/dsound-EAX/0013-dsound-Add-delay-line-EAX-functions.patch b/patches/dsound-EAX/0013-dsound-Add-delay-line-EAX-functions.patch new file mode 100644 index 00000000..e116cadb --- /dev/null +++ b/patches/dsound-EAX/0013-dsound-Add-delay-line-EAX-functions.patch @@ -0,0 +1,89 @@ +From 687ccff7f8b336d29eb72b7975500de8cedbae93 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 18:00:10 +0000 +Subject: dsound: Add delay line EAX functions. + +--- + dlls/dsound/dsound_eax.h | 1 + + dlls/dsound/eax.c | 27 +++++++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 82b1408..bd002d7 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -142,6 +142,7 @@ typedef struct { + FILTER LpFilter; + + DelayLine Delay; ++ unsigned int DelayTap[2]; + + unsigned int Offset; + } eax_buffer_info; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index bbb5dad..9569c33 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -106,11 +106,26 @@ static float lpFilter2P(FILTER *iir, unsigned int offset, float input) + return output; + } + ++static void DelayLineIn(DelayLine *Delay, unsigned int offset, float in) ++{ ++ Delay->Line[offset&Delay->Mask] = in; ++} ++ ++static float DelayLineOut(DelayLine *Delay, unsigned int offset) ++{ ++ return Delay->Line[offset&Delay->Mask]; ++} ++ + static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + { + /* Low-pass filter the incoming sample. */ + in = lpFilter2P(&dsb->eax.LpFilter, 0, in); + ++ /* Feed the initial delay line. */ ++ DelayLineIn(&dsb->eax.Delay, dsb->eax.Offset, in); ++ ++ in = DelayLineOut(&dsb->eax.Delay, dsb->eax.Offset - dsb->eax.DelayTap[0]); ++ + /* Step all delays forward one sample. */ + dsb->eax.Offset++; + } +@@ -152,6 +167,12 @@ void process_eax_buffer(IDirectSoundBufferImpl *dsb, float *buf, DWORD count) + HeapFree(GetProcessHeap(), 0, out); + } + ++static void UpdateDelayLine(float earlyDelay, float lateDelay, unsigned int frequency, eax_buffer_info *State) ++{ ++ State->DelayTap[0] = fastf2u(earlyDelay * frequency); ++ State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); ++} ++ + static float lpCoeffCalc(float g, float cw) + { + float a = 0.0f; +@@ -262,6 +283,10 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + cw = CalcI3DL2HFreq(dsb->device->eax.eax_props.flHFReference, dsb->device->pwfx->nSamplesPerSec); + + dsb->eax.LpFilter.coeff = lpCoeffCalc(dsb->device->eax.eax_props.flGainHF, cw); ++ ++ UpdateDelayLine(dsb->device->eax.eax_props.flReflectionsDelay, ++ dsb->device->eax.eax_props.flLateReverbDelay, ++ dsb->device->pwfx->nSamplesPerSec, &dsb->eax); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -286,6 +311,8 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + + dsb->eax.Delay.Mask = 0; + dsb->eax.Delay.Line = NULL; ++ dsb->eax.DelayTap[0] = 0; ++ dsb->eax.DelayTap[1] = 0; + + dsb->eax.Offset = 0; + +-- +2.3.3 + diff --git a/patches/dsound-EAX/0014-dsound-Implement-EAX-early-reflections.patch b/patches/dsound-EAX/0014-dsound-Implement-EAX-early-reflections.patch new file mode 100644 index 00000000..ccd9d65f --- /dev/null +++ b/patches/dsound-EAX/0014-dsound-Implement-EAX-early-reflections.patch @@ -0,0 +1,227 @@ +From bb7edc0e1283a60b1cfc121356d6a8702f96f689 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 18:09:34 +0000 +Subject: dsound: Implement EAX early reflections. + +--- + dlls/dsound/dsound_eax.h | 7 +++ + dlls/dsound/eax.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 121 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index bd002d7..184f7ce 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -144,6 +144,13 @@ typedef struct { + DelayLine Delay; + unsigned int DelayTap[2]; + ++ struct { ++ float Gain; ++ float Coeff[4]; ++ DelayLine Delay[4]; ++ unsigned int Offset[4]; ++ } Early; ++ + unsigned int Offset; + } eax_buffer_info; + +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 9569c33..964e5f8 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,6 +92,11 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static const float EARLY_LINE_LENGTH[4] = ++{ ++ 0.0015f, 0.0045f, 0.0135f, 0.0405f ++}; ++ + static float lpFilter2P(FILTER *iir, unsigned int offset, float input) + { + float *history = &iir->history[offset*2]; +@@ -116,6 +121,62 @@ static float DelayLineOut(DelayLine *Delay, unsigned int offset) + return Delay->Line[offset&Delay->Mask]; + } + ++static float AttenuatedDelayLineOut(DelayLine *Delay, unsigned int offset, float coeff) ++{ ++ return coeff * Delay->Line[offset&Delay->Mask]; ++} ++ ++static float EarlyDelayLineOut(IDirectSoundBufferImpl* dsb, unsigned int index) ++{ ++ return AttenuatedDelayLineOut(&dsb->eax.Early.Delay[index], ++ dsb->eax.Offset - dsb->eax.Early.Offset[index], ++ dsb->eax.Early.Coeff[index]); ++} ++ ++static void EarlyReflection(IDirectSoundBufferImpl* dsb, float in, float *out) ++{ ++ float d[4], v, f[4]; ++ ++ /* Obtain the decayed results of each early delay line. */ ++ d[0] = EarlyDelayLineOut(dsb, 0); ++ d[1] = EarlyDelayLineOut(dsb, 1); ++ d[2] = EarlyDelayLineOut(dsb, 2); ++ d[3] = EarlyDelayLineOut(dsb, 3); ++ ++ /* The following uses a lossless scattering junction from waveguide ++ * theory. It actually amounts to a householder mixing matrix, which ++ * will produce a maximally diffuse response, and means this can probably ++ * be considered a simple feed-back delay network (FDN). ++ * N ++ * --- ++ * \ ++ * v = 2/N / d_i ++ * --- ++ * i=1 ++ */ ++ v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; ++ /* The junction is loaded with the input here. */ ++ v += in; ++ ++ /* Calculate the feed values for the delay lines. */ ++ f[0] = v - d[0]; ++ f[1] = v - d[1]; ++ f[2] = v - d[2]; ++ f[3] = v - d[3]; ++ ++ /* Re-feed the delay lines. */ ++ DelayLineIn(&dsb->eax.Early.Delay[0], dsb->eax.Offset, f[0]); ++ DelayLineIn(&dsb->eax.Early.Delay[1], dsb->eax.Offset, f[1]); ++ DelayLineIn(&dsb->eax.Early.Delay[2], dsb->eax.Offset, f[2]); ++ DelayLineIn(&dsb->eax.Early.Delay[3], dsb->eax.Offset, f[3]); ++ ++ /* Output the results of the junction for all four channels. */ ++ out[0] = dsb->eax.Early.Gain * f[0]; ++ out[1] = dsb->eax.Early.Gain * f[1]; ++ out[2] = dsb->eax.Early.Gain * f[2]; ++ out[3] = dsb->eax.Early.Gain * f[3]; ++} ++ + static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + { + /* Low-pass filter the incoming sample. */ +@@ -124,7 +185,9 @@ static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + /* Feed the initial delay line. */ + DelayLineIn(&dsb->eax.Delay, dsb->eax.Offset, in); + ++ /* Calculate the early reflection from the first delay tap. */ + in = DelayLineOut(&dsb->eax.Delay, dsb->eax.Offset - dsb->eax.DelayTap[0]); ++ EarlyReflection(dsb, in, out); + + /* Step all delays forward one sample. */ + dsb->eax.Offset++; +@@ -173,6 +236,27 @@ static void UpdateDelayLine(float earlyDelay, float lateDelay, unsigned int freq + State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); + } + ++static float CalcDecayCoeff(float length, float decayTime) ++{ ++ return powf(0.001f/*-60 dB*/, length/decayTime); ++} ++ ++static void UpdateEarlyLines(float reverbGain, float earlyGain, float lateDelay, eax_buffer_info *State) ++{ ++ unsigned int index; ++ ++ /* Calculate the early reflections gain (from the master effect gain, and ++ * reflections gain parameters) with a constant attenuation of 0.5. */ ++ State->Early.Gain = 0.5f * reverbGain * earlyGain; ++ ++ /* Calculate the gain (coefficient) for each early delay line using the ++ * late delay time. This expands the early reflections to the start of ++ * the late reverb. */ ++ for(index = 0; index < 4; index++) ++ State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], ++ lateDelay); ++} ++ + static float lpCoeffCalc(float g, float cw) + { + float a = 0.0f; +@@ -244,6 +328,11 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + totalSamples += CalcLineLength(length, totalSamples, frequency, + &dsb->eax.Delay); + ++ /* The early reflection lines. */ ++ for (index = 0; index < 4; index++) ++ totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, ++ frequency, &dsb->eax.Early.Delay[index]); ++ + if (totalSamples != dsb->eax.TotalSamples) + { + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); +@@ -261,6 +350,10 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + + /* Update all delays to reflect the new sample buffer. */ + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Delay); ++ for(index = 0; index < 4; index++) ++ { ++ RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Early.Delay[index]); ++ } + + /* Clear the sample buffer. */ + for (index = 0; index < dsb->eax.TotalSamples; index++) +@@ -271,6 +364,7 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + + static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { ++ unsigned int index; + float cw; + + /* avoid segfaults in mixing thread when we recalculate the line offsets */ +@@ -280,6 +374,11 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + + LeaveCriticalSection(&dsb->device->mixlock); + ++ for(index = 0; index < 4; index++) ++ { ++ dsb->eax.Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * dsb->device->pwfx->nSamplesPerSec); ++ } ++ + cw = CalcI3DL2HFreq(dsb->device->eax.eax_props.flHFReference, dsb->device->pwfx->nSamplesPerSec); + + dsb->eax.LpFilter.coeff = lpCoeffCalc(dsb->device->eax.eax_props.flGainHF, cw); +@@ -287,6 +386,10 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + UpdateDelayLine(dsb->device->eax.eax_props.flReflectionsDelay, + dsb->device->eax.eax_props.flLateReverbDelay, + dsb->device->pwfx->nSamplesPerSec, &dsb->eax); ++ ++ UpdateEarlyLines(dsb->device->eax.eax_props.flGain, ++ dsb->device->eax.eax_props.flReflectionsGain, ++ dsb->device->eax.eax_props.flLateReverbDelay, &dsb->eax); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -302,6 +405,8 @@ static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) + + void init_eax_buffer(IDirectSoundBufferImpl *dsb) + { ++ unsigned int index; ++ + dsb->eax.TotalSamples = 0; + dsb->eax.SampleBuffer = NULL; + +@@ -314,6 +419,15 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + dsb->eax.DelayTap[0] = 0; + dsb->eax.DelayTap[1] = 0; + ++ dsb->eax.Early.Gain = 0.0f; ++ for(index = 0; index < 4; index++) ++ { ++ dsb->eax.Early.Coeff[index] = 0.0f; ++ dsb->eax.Early.Delay[index].Mask = 0; ++ dsb->eax.Early.Delay[index].Line = NULL; ++ dsb->eax.Early.Offset[index] = 0; ++ } ++ + dsb->eax.Offset = 0; + + ReverbUpdate(dsb); +-- +2.3.3 + diff --git a/patches/dsound-EAX/0015-dsound-Implement-EAX-decorrelator.patch b/patches/dsound-EAX/0015-dsound-Implement-EAX-decorrelator.patch new file mode 100644 index 00000000..39ad4aeb --- /dev/null +++ b/patches/dsound-EAX/0015-dsound-Implement-EAX-decorrelator.patch @@ -0,0 +1,124 @@ +From 51655ef153a69a2cd2e34e8791a4e3b9088962fe Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 18:19:17 +0000 +Subject: dsound: Implement EAX decorrelator. + +--- + dlls/dsound/dsound_eax.h | 3 +++ + dlls/dsound/eax.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 49 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index 184f7ce..c33a2ff 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -151,6 +151,9 @@ typedef struct { + unsigned int Offset[4]; + } Early; + ++ DelayLine Decorrelator; ++ unsigned int DecoTap[3]; ++ + unsigned int Offset; + } eax_buffer_info; + +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index 964e5f8..d40b7d6 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -92,11 +92,21 @@ static const EFXEAXREVERBPROPERTIES efx_presets[] = { + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } /* psychotic */ + }; + ++static const float DECO_FRACTION = 0.15f; ++static const float DECO_MULTIPLIER = 2.0f; ++ + static const float EARLY_LINE_LENGTH[4] = + { + 0.0015f, 0.0045f, 0.0135f, 0.0405f + }; + ++static const float LATE_LINE_LENGTH[4] = ++{ ++ 0.0211f, 0.0311f, 0.0461f, 0.0680f ++}; ++ ++static const float LATE_LINE_MULTIPLIER = 4.0f; ++ + static float lpFilter2P(FILTER *iir, unsigned int offset, float input) + { + float *history = &iir->history[offset*2]; +@@ -273,6 +283,26 @@ static float lpCoeffCalc(float g, float cw) + return a; + } + ++static void UpdateDecorrelator(float density, unsigned int frequency, eax_buffer_info *State) ++{ ++ unsigned int index; ++ float length; ++ ++ /* The late reverb inputs are decorrelated to smooth the reverb tail and ++ * reduce harsh echos. The first tap occurs immediately, while the ++ * remaining taps are delayed by multiples of a fraction of the smallest ++ * cyclical delay time. ++ * ++ * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay ++ */ ++ for (index = 0; index < 3; index++) ++ { ++ length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (float)index)) * ++ LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); ++ State->DecoTap[index] = fastf2u(length * frequency); ++ } ++} ++ + static float CalcI3DL2HFreq(float hfRef, unsigned int frequency) + { + return cosf(M_PI*2.0f * hfRef / frequency); +@@ -333,6 +363,13 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, + frequency, &dsb->eax.Early.Delay[index]); + ++ /* The decorrelator line is calculated from the lowest reverb density (a ++ * parameter value of 1). */ ++ length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * ++ LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); ++ totalSamples += CalcLineLength(length, totalSamples, frequency, ++ &dsb->eax.Decorrelator); ++ + if (totalSamples != dsb->eax.TotalSamples) + { + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); +@@ -350,6 +387,7 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + + /* Update all delays to reflect the new sample buffer. */ + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Delay); ++ RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Decorrelator); + for(index = 0; index < 4; index++) + { + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Early.Delay[index]); +@@ -390,6 +428,8 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + UpdateEarlyLines(dsb->device->eax.eax_props.flGain, + dsb->device->eax.eax_props.flReflectionsGain, + dsb->device->eax.eax_props.flLateReverbDelay, &dsb->eax); ++ ++ UpdateDecorrelator(dsb->device->eax.eax_props.flDensity, dsb->device->pwfx->nSamplesPerSec, &dsb->eax); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -428,6 +468,12 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + dsb->eax.Early.Offset[index] = 0; + } + ++ dsb->eax.Decorrelator.Mask = 0; ++ dsb->eax.Decorrelator.Line = NULL; ++ dsb->eax.DecoTap[0] = 0; ++ dsb->eax.DecoTap[1] = 0; ++ dsb->eax.DecoTap[2] = 0; ++ + dsb->eax.Offset = 0; + + ReverbUpdate(dsb); +-- +2.3.3 + diff --git a/patches/dsound-EAX/0016-dsound-Implement-EAX-late-reverb.patch b/patches/dsound-EAX/0016-dsound-Implement-EAX-late-reverb.patch new file mode 100644 index 00000000..85e353a0 --- /dev/null +++ b/patches/dsound-EAX/0016-dsound-Implement-EAX-late-reverb.patch @@ -0,0 +1,372 @@ +From 03930e42e47619af1b84a11aa21b937404e290fc Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 18:21:02 +0000 +Subject: dsound: Implement EAX late reverb. + +--- + dlls/dsound/dsound_eax.h | 13 +++ + dlls/dsound/eax.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 268 insertions(+), 1 deletion(-) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index c33a2ff..fac4d9b 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -154,6 +154,19 @@ typedef struct { + DelayLine Decorrelator; + unsigned int DecoTap[3]; + ++ struct { ++ float Gain; ++ float DensityGain; ++ float MixCoeff; ++ ++ float Coeff[4]; ++ DelayLine Delay[4]; ++ unsigned int Offset[4]; ++ ++ float LpCoeff[4]; ++ float LpSample[4]; ++ } Late; ++ + unsigned int Offset; + } eax_buffer_info; + +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index d40b7d6..c9a5eb6 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -107,6 +107,8 @@ static const float LATE_LINE_LENGTH[4] = + + static const float LATE_LINE_MULTIPLIER = 4.0f; + ++#define SPEEDOFSOUNDMETRESPERSEC 343.3f ++ + static float lpFilter2P(FILTER *iir, unsigned int offset, float input) + { + float *history = &iir->history[offset*2]; +@@ -121,6 +123,11 @@ static float lpFilter2P(FILTER *iir, unsigned int offset, float input) + return output; + } + ++static float lerp(float val1, float val2, float mu) ++{ ++ return val1 + (val2-val1)*mu; ++} ++ + static void DelayLineIn(DelayLine *Delay, unsigned int offset, float in) + { + Delay->Line[offset&Delay->Mask] = in; +@@ -187,8 +194,85 @@ static void EarlyReflection(IDirectSoundBufferImpl* dsb, float in, float *out) + out[3] = dsb->eax.Early.Gain * f[3]; + } + ++static float LateDelayLineOut(IDirectSoundBufferImpl* dsb, unsigned int index) ++{ ++ return AttenuatedDelayLineOut(&dsb->eax.Late.Delay[index], ++ dsb->eax.Offset - dsb->eax.Late.Offset[index], ++ dsb->eax.Late.Coeff[index]); ++} ++ ++static float LateLowPassInOut(IDirectSoundBufferImpl* dsb, unsigned int index, float in) ++{ ++ in = lerp(in, dsb->eax.Late.LpSample[index], dsb->eax.Late.LpCoeff[index]); ++ dsb->eax.Late.LpSample[index] = in; ++ return in; ++} ++ ++static void LateReverb(IDirectSoundBufferImpl* dsb, const float *in, float *out) ++{ ++ float d[4], f[4]; ++ ++ /* Obtain the decayed results of the cyclical delay lines, and add the ++ * corresponding input channels. Then pass the results through the ++ * low-pass filters. */ ++ ++ /* This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back ++ * to 0. */ ++ d[0] = LateLowPassInOut(dsb, 2, in[2] + LateDelayLineOut(dsb, 2)); ++ d[1] = LateLowPassInOut(dsb, 0, in[0] + LateDelayLineOut(dsb, 0)); ++ d[2] = LateLowPassInOut(dsb, 3, in[3] + LateDelayLineOut(dsb, 3)); ++ d[3] = LateLowPassInOut(dsb, 1, in[1] + LateDelayLineOut(dsb, 1)); ++ ++ /* Late reverb is done with a modified feed-back delay network (FDN) ++ * topology. Four input lines are each fed through their own all-pass ++ * filter and then into the mixing matrix. The four outputs of the ++ * mixing matrix are then cycled back to the inputs. Each output feeds ++ * a different input to form a circlular feed cycle. ++ * ++ * The mixing matrix used is a 4D skew-symmetric rotation matrix derived ++ * using a single unitary rotational parameter: ++ * ++ * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 ++ * [ -a, d, c, -b ] ++ * [ -b, -c, d, a ] ++ * [ -c, b, -a, d ] ++ * ++ * The rotation is constructed from the effect's diffusion parameter, ++ * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y ++ * with differing signs, and d is the coefficient x. The matrix is thus: ++ * ++ * [ x, y, -y, y ] n = sqrt(matrix_order - 1) ++ * [ -y, x, y, y ] t = diffusion_parameter * atan(n) ++ * [ y, -y, x, y ] x = cos(t) ++ * [ -y, -y, -y, x ] y = sin(t) / n ++ * ++ * To reduce the number of multiplies, the x coefficient is applied with ++ * the cyclical delay line coefficients. Thus only the y coefficient is ++ * applied when mixing, and is modified to be: y / x. ++ */ ++ f[0] = d[0] + (dsb->eax.Late.MixCoeff * ( d[1] + -d[2] + d[3])); ++ f[1] = d[1] + (dsb->eax.Late.MixCoeff * (-d[0] + d[2] + d[3])); ++ f[2] = d[2] + (dsb->eax.Late.MixCoeff * ( d[0] + -d[1] + d[3])); ++ f[3] = d[3] + (dsb->eax.Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); ++ ++ /* Output the results of the matrix for all four channels, attenuated by ++ * the late reverb gain (which is attenuated by the 'x' mix coefficient). */ ++ out[0] = dsb->eax.Late.Gain * f[0]; ++ out[1] = dsb->eax.Late.Gain * f[1]; ++ out[2] = dsb->eax.Late.Gain * f[2]; ++ out[3] = dsb->eax.Late.Gain * f[3]; ++ ++ /* Re-feed the cyclical delay lines. */ ++ DelayLineIn(&dsb->eax.Late.Delay[0], dsb->eax.Offset, f[0]); ++ DelayLineIn(&dsb->eax.Late.Delay[1], dsb->eax.Offset, f[1]); ++ DelayLineIn(&dsb->eax.Late.Delay[2], dsb->eax.Offset, f[2]); ++ DelayLineIn(&dsb->eax.Late.Delay[3], dsb->eax.Offset, f[3]); ++} ++ + static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + { ++ float feed, late[4], taps[4]; ++ + /* Low-pass filter the incoming sample. */ + in = lpFilter2P(&dsb->eax.LpFilter, 0, in); + +@@ -199,6 +283,25 @@ static void VerbPass(IDirectSoundBufferImpl* dsb, float in, float* out) + in = DelayLineOut(&dsb->eax.Delay, dsb->eax.Offset - dsb->eax.DelayTap[0]); + EarlyReflection(dsb, in, out); + ++ /* Feed the decorrelator from the energy-attenuated output of the second ++ * delay tap. */ ++ in = DelayLineOut(&dsb->eax.Delay, dsb->eax.Offset - dsb->eax.DelayTap[1]); ++ feed = in * dsb->eax.Late.DensityGain; ++ DelayLineIn(&dsb->eax.Decorrelator, dsb->eax.Offset, feed); ++ ++ /* Calculate the late reverb from the decorrelator taps. */ ++ taps[0] = feed; ++ taps[1] = DelayLineOut(&dsb->eax.Decorrelator, dsb->eax.Offset - dsb->eax.DecoTap[0]); ++ taps[2] = DelayLineOut(&dsb->eax.Decorrelator, dsb->eax.Offset - dsb->eax.DecoTap[1]); ++ taps[3] = DelayLineOut(&dsb->eax.Decorrelator, dsb->eax.Offset - dsb->eax.DecoTap[2]); ++ LateReverb(dsb, taps, late); ++ ++ /* Mix early reflections and late reverb. */ ++ out[0] += late[0]; ++ out[1] += late[1]; ++ out[2] += late[2]; ++ out[3] += late[3]; ++ + /* Step all delays forward one sample. */ + dsb->eax.Offset++; + } +@@ -308,6 +411,95 @@ static float CalcI3DL2HFreq(float hfRef, unsigned int frequency) + return cosf(M_PI*2.0f * hfRef / frequency); + } + ++static float CalcDensityGain(float a) ++{ ++ return sqrtf(1.0f - (a * a)); ++} ++ ++static float CalcDampingCoeff(float hfRatio, float length, float decayTime, float decayCoeff, float cw) ++{ ++ float coeff, g; ++ ++ coeff = 0.0f; ++ if (hfRatio < 1.0f) ++ { ++ /* Calculate the low-pass coefficient by dividing the HF decay ++ * coefficient by the full decay coefficient. */ ++ g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; ++ ++ /* Damping is done with a 1-pole filter, so g needs to be squared. */ ++ g *= g; ++ coeff = lpCoeffCalc(g, cw); ++ ++ /* Very low decay times will produce minimal output, so apply an ++ * upper bound to the coefficient. */ ++ if (coeff > 0.98f) coeff = 0.98f; ++ } ++ return coeff; ++} ++ ++static void UpdateLateLines(float reverbGain, float lateGain, float xMix, float density, float decayTime, ++ float diffusion, float hfRatio, float cw, unsigned int frequency, eax_buffer_info *State) ++{ ++ float length; ++ unsigned int index; ++ ++ /* Calculate the late reverb gain (from the master effect gain, and late ++ * reverb gain parameters). Since the output is tapped prior to the ++ * application of the next delay line coefficients, this gain needs to be ++ * attenuated by the 'x' mixing matrix coefficient as well. ++ */ ++ State->Late.Gain = reverbGain * lateGain * xMix; ++ ++ /* To compensate for changes in modal density and decay time of the late ++ * reverb signal, the input is attenuated based on the maximal energy of ++ * the outgoing signal. This approximation is used to keep the apparent ++ * energy of the signal equal for all ranges of density and decay time. ++ * ++ * The average length of the cyclcical delay lines is used to calculate ++ * the attenuation coefficient. ++ */ ++ length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + ++ LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; ++ length *= 1.0f + (density * LATE_LINE_MULTIPLIER); ++ State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, ++ decayTime)); ++ ++ for(index = 0; index < 4; index++) ++ { ++ /* Calculate the length (in seconds) of each cyclical delay line. */ ++ length = LATE_LINE_LENGTH[index] * (1.0f + (density * LATE_LINE_MULTIPLIER)); ++ ++ /* Calculate the delay offset for each cyclical delay line. */ ++ State->Late.Offset[index] = fastf2u(length * frequency); ++ ++ /* Calculate the gain (coefficient) for each cyclical line. */ ++ State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); ++ ++ /* Calculate the damping coefficient for each low-pass filter. */ ++ State->Late.LpCoeff[index] = CalcDampingCoeff(hfRatio, length, decayTime, ++ State->Late.Coeff[index], cw); ++ ++ /* Attenuate the cyclical line coefficients by the mixing coefficient ++ * (x). */ ++ State->Late.Coeff[index] *= xMix; ++ } ++} ++ ++static void CalcMatrixCoeffs(float diffusion, float *x, float *y) ++{ ++ float n, t; ++ ++ /* The matrix is of order 4, so n is sqrt (4 - 1). */ ++ n = sqrtf(3.0f); ++ t = diffusion * atanf(n); ++ ++ /* Calculate the first mixing matrix coefficient. */ ++ *x = cosf(t); ++ /* Calculate the second mixing matrix coefficient. */ ++ *y = sinf(t) / n; ++} ++ + static unsigned int NextPowerOf2(unsigned int value) + { + if (value > 0) +@@ -370,6 +562,14 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + totalSamples += CalcLineLength(length, totalSamples, frequency, + &dsb->eax.Decorrelator); + ++ /* The late delay lines are calculated from the lowest reverb density. */ ++ for (index = 0; index < 4; index++) ++ { ++ length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); ++ totalSamples += CalcLineLength(length, totalSamples, frequency, ++ &dsb->eax.Late.Delay[index]); ++ } ++ + if (totalSamples != dsb->eax.TotalSamples) + { + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); +@@ -391,6 +591,7 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + for(index = 0; index < 4; index++) + { + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Early.Delay[index]); ++ RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Late.Delay[index]); + } + + /* Clear the sample buffer. */ +@@ -400,10 +601,35 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + return TRUE; + } + ++static inline float CalcDecayLength(float coeff, float decayTime) ++{ ++ return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; ++} ++ ++static float CalcLimitedHfRatio(float hfRatio, float airAbsorptionGainHF, float decayTime) ++{ ++ float limitRatio; ++ ++ /* Find the attenuation due to air absorption in dB (converting delay ++ * time to meters using the speed of sound). Then reversing the decay ++ * equation, solve for HF ratio. The delay length is cancelled out of ++ * the equation, so it can be calculated once for all lines. ++ */ ++ limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * ++ SPEEDOFSOUNDMETRESPERSEC); ++ /* Using the limit calculated above, apply the upper bound to the HF ++ * ratio. Also need to limit the result to a minimum of 0.1, just like the ++ * HF ratio parameter. */ ++ if (limitRatio < 0.1f) limitRatio = 0.1f; ++ else if (limitRatio > hfRatio) limitRatio = hfRatio; ++ ++ return limitRatio; ++} ++ + static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + { + unsigned int index; +- float cw; ++ float cw, hfRatio, x, y; + + /* avoid segfaults in mixing thread when we recalculate the line offsets */ + EnterCriticalSection(&dsb->device->mixlock); +@@ -430,6 +656,20 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + dsb->device->eax.eax_props.flLateReverbDelay, &dsb->eax); + + UpdateDecorrelator(dsb->device->eax.eax_props.flDensity, dsb->device->pwfx->nSamplesPerSec, &dsb->eax); ++ ++ CalcMatrixCoeffs(dsb->device->eax.eax_props.flDiffusion, &x, &y); ++ dsb->eax.Late.MixCoeff = y / x; ++ ++ hfRatio = dsb->device->eax.eax_props.flDecayHFRatio; ++ ++ if (dsb->device->eax.eax_props.iDecayHFLimit && dsb->device->eax.eax_props.flAirAbsorptionGainHF < 1.0f) { ++ hfRatio = CalcLimitedHfRatio(hfRatio, dsb->device->eax.eax_props.flAirAbsorptionGainHF, ++ dsb->device->eax.eax_props.flDecayTime); ++ } ++ ++ UpdateLateLines(dsb->device->eax.eax_props.flGain, dsb->device->eax.eax_props.flLateReverbGain, ++ x, dsb->device->eax.eax_props.flDensity, dsb->device->eax.eax_props.flDecayTime, ++ dsb->device->eax.eax_props.flDiffusion, hfRatio, cw, dsb->device->pwfx->nSamplesPerSec, &dsb->eax); + } + + static BOOL ReverbDeviceUpdate(DirectSoundDevice *dev) +@@ -474,6 +714,20 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + dsb->eax.DecoTap[1] = 0; + dsb->eax.DecoTap[2] = 0; + ++ dsb->eax.Late.Gain = 0.0f; ++ dsb->eax.Late.DensityGain = 0.0f; ++ dsb->eax.Late.MixCoeff = 0.0f; ++ for(index = 0; index < 4; index++) ++ { ++ dsb->eax.Late.Coeff[index] = 0.0f; ++ dsb->eax.Late.Delay[index].Mask = 0; ++ dsb->eax.Late.Delay[index].Line = NULL; ++ dsb->eax.Late.Offset[index] = 0; ++ ++ dsb->eax.Late.LpCoeff[index] = 0.0f; ++ dsb->eax.Late.LpSample[index] = 0.0f; ++ } ++ + dsb->eax.Offset = 0; + + ReverbUpdate(dsb); +-- +2.3.3 + diff --git a/patches/dsound-EAX/0017-dsound-Implement-EAX-late-all-pass-filter.patch b/patches/dsound-EAX/0017-dsound-Implement-EAX-late-all-pass-filter.patch new file mode 100644 index 00000000..4268907e --- /dev/null +++ b/patches/dsound-EAX/0017-dsound-Implement-EAX-late-all-pass-filter.patch @@ -0,0 +1,151 @@ +From 510838b8d83a085bda82ac87c0f22ee856eb0f67 Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Sun, 22 Mar 2015 18:21:18 +0000 +Subject: dsound: Implement EAX late all-pass filter. + +--- + dlls/dsound/dsound_eax.h | 5 +++++ + dlls/dsound/eax.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 60 insertions(+) + +diff --git a/dlls/dsound/dsound_eax.h b/dlls/dsound/dsound_eax.h +index fac4d9b..a650108 100644 +--- a/dlls/dsound/dsound_eax.h ++++ b/dlls/dsound/dsound_eax.h +@@ -157,8 +157,13 @@ typedef struct { + struct { + float Gain; + float DensityGain; ++ float ApFeedCoeff; + float MixCoeff; + ++ float ApCoeff[4]; ++ DelayLine ApDelay[4]; ++ unsigned int ApOffset[4]; ++ + float Coeff[4]; + DelayLine Delay[4]; + unsigned int Offset[4]; +diff --git a/dlls/dsound/eax.c b/dlls/dsound/eax.c +index c9a5eb6..a05b00e 100644 +--- a/dlls/dsound/eax.c ++++ b/dlls/dsound/eax.c +@@ -100,6 +100,11 @@ static const float EARLY_LINE_LENGTH[4] = + 0.0015f, 0.0045f, 0.0135f, 0.0405f + }; + ++static const float ALLPASS_LINE_LENGTH[4] = ++{ ++ 0.0151f, 0.0167f, 0.0183f, 0.0200f, ++}; ++ + static const float LATE_LINE_LENGTH[4] = + { + 0.0211f, 0.0311f, 0.0461f, 0.0680f +@@ -194,6 +199,28 @@ static void EarlyReflection(IDirectSoundBufferImpl* dsb, float in, float *out) + out[3] = dsb->eax.Early.Gain * f[3]; + } + ++static float AllpassInOut(DelayLine *Delay, unsigned int outOffset, unsigned int inOffset, float in, float feedCoeff, float coeff) ++{ ++ float out, feed; ++ ++ out = DelayLineOut(Delay, outOffset); ++ feed = feedCoeff * in; ++ DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); ++ ++ /* The time-based attenuation is only applied to the delay output to ++ * keep it from affecting the feed-back path (which is already controlled ++ * by the all-pass feed coefficient). */ ++ return (coeff * out) - feed; ++} ++ ++static float LateAllPassInOut(IDirectSoundBufferImpl* dsb, unsigned int index, float in) ++{ ++ return AllpassInOut(&dsb->eax.Late.ApDelay[index], ++ dsb->eax.Offset - dsb->eax.Late.ApOffset[index], ++ dsb->eax.Offset, in, dsb->eax.Late.ApFeedCoeff, ++ dsb->eax.Late.ApCoeff[index]); ++} ++ + static float LateDelayLineOut(IDirectSoundBufferImpl* dsb, unsigned int index) + { + return AttenuatedDelayLineOut(&dsb->eax.Late.Delay[index], +@@ -223,6 +250,14 @@ static void LateReverb(IDirectSoundBufferImpl* dsb, const float *in, float *out) + d[2] = LateLowPassInOut(dsb, 3, in[3] + LateDelayLineOut(dsb, 3)); + d[3] = LateLowPassInOut(dsb, 1, in[1] + LateDelayLineOut(dsb, 1)); + ++ /* To help increase diffusion, run each line through an all-pass filter. ++ * When there is no diffusion, the shortest all-pass filter will feed the ++ * shortest delay line. */ ++ d[0] = LateAllPassInOut(dsb, 0, d[0]); ++ d[1] = LateAllPassInOut(dsb, 1, d[1]); ++ d[2] = LateAllPassInOut(dsb, 2, d[2]); ++ d[3] = LateAllPassInOut(dsb, 3, d[3]); ++ + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the +@@ -465,8 +500,15 @@ static void UpdateLateLines(float reverbGain, float lateGain, float xMix, float + State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, + decayTime)); + ++ /* Calculate the all-pass feed-back and feed-forward coefficient. */ ++ State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); ++ + for(index = 0; index < 4; index++) + { ++ /* Calculate the gain (coefficient) for each all-pass line. */ ++ State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index], ++ decayTime); ++ + /* Calculate the length (in seconds) of each cyclical delay line. */ + length = LATE_LINE_LENGTH[index] * (1.0f + (density * LATE_LINE_MULTIPLIER)); + +@@ -562,6 +604,11 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + totalSamples += CalcLineLength(length, totalSamples, frequency, + &dsb->eax.Decorrelator); + ++ /* The late all-pass lines. */ ++ for(index = 0;index < 4;index++) ++ totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, ++ frequency, &dsb->eax.Late.ApDelay[index]); ++ + /* The late delay lines are calculated from the lowest reverb density. */ + for (index = 0; index < 4; index++) + { +@@ -591,6 +638,7 @@ static BOOL AllocLines(unsigned int frequency, IDirectSoundBufferImpl *dsb) + for(index = 0; index < 4; index++) + { + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Early.Delay[index]); ++ RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Late.ApDelay[index]); + RealizeLineOffset(dsb->eax.SampleBuffer, &dsb->eax.Late.Delay[index]); + } + +@@ -641,6 +689,7 @@ static void ReverbUpdate(IDirectSoundBufferImpl *dsb) + for(index = 0; index < 4; index++) + { + dsb->eax.Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * dsb->device->pwfx->nSamplesPerSec); ++ dsb->eax.Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * dsb->device->pwfx->nSamplesPerSec); + } + + cw = CalcI3DL2HFreq(dsb->device->eax.eax_props.flHFReference, dsb->device->pwfx->nSamplesPerSec); +@@ -716,9 +765,15 @@ void init_eax_buffer(IDirectSoundBufferImpl *dsb) + + dsb->eax.Late.Gain = 0.0f; + dsb->eax.Late.DensityGain = 0.0f; ++ dsb->eax.Late.ApFeedCoeff = 0.0f; + dsb->eax.Late.MixCoeff = 0.0f; + for(index = 0; index < 4; index++) + { ++ dsb->eax.Late.ApCoeff[index] = 0.0f; ++ dsb->eax.Late.ApDelay[index].Mask = 0; ++ dsb->eax.Late.ApDelay[index].Line = NULL; ++ dsb->eax.Late.ApOffset[index] = 0; ++ + dsb->eax.Late.Coeff[index] = 0.0f; + dsb->eax.Late.Delay[index].Mask = 0; + dsb->eax.Late.Delay[index].Line = NULL; +-- +2.3.3 + diff --git a/patches/dsound-EAX/definition b/patches/dsound-EAX/definition new file mode 100644 index 00000000..f400f020 --- /dev/null +++ b/patches/dsound-EAX/definition @@ -0,0 +1,2 @@ +Fixes: Software support for Environmental Audio Extensions (EAX) +Depends: dsound-Fast_Mixer diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 5629a70b..ee61f6a0 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -94,6 +94,7 @@ patch_enable_all () enable_ddraw_Hotpatch="$1" enable_ddraw_d3d_execute_buffer="$1" enable_dinput_Events="$1" + enable_dsound_EAX="$1" enable_dsound_Fast_Mixer="$1" enable_dxgi_GetDesc="$1" enable_dxva2_Video_Decoder="$1" @@ -340,6 +341,9 @@ patch_enable () dinput-Events) enable_dinput_Events="$2" ;; + dsound-EAX) + enable_dsound_EAX="$2" + ;; dsound-Fast_Mixer) enable_dsound_Fast_Mixer="$2" ;; @@ -1170,6 +1174,13 @@ if test "$enable_wined3d_CSMT_Helper" -eq 1; then enable_wined3d_DXTn=1 fi +if test "$enable_dsound_EAX" -eq 1; then + if test "$enable_dsound_Fast_Mixer" -gt 1; then + abort "Patchset dsound-Fast_Mixer disabled, but dsound-EAX depends on that." + fi + enable_dsound_Fast_Mixer=1 +fi + if test "$enable_d3dx9_36_AnimationController" -eq 1; then if test "$enable_d3dx9_36_DXTn" -gt 1; then abort "Patchset d3dx9_36-DXTn disabled, but d3dx9_36-AnimationController depends on that." @@ -1797,6 +1808,51 @@ if test "$enable_dsound_Fast_Mixer" -eq 1; then ) >> "$patchlist" fi +# Patchset dsound-EAX +# | +# | Modified files: +# | * dlls/dsound/Makefile.in, dlls/dsound/buffer.c, dlls/dsound/dsound.c, dlls/dsound/dsound_eax.h, +# | dlls/dsound/dsound_private.h, dlls/dsound/eax.c, dlls/dsound/mixer.c +# | +if test "$enable_dsound_EAX" -eq 1; then + patch_apply dsound-EAX/0001-dsound-Apply-filters-before-sound-is-multiplied-to-s.patch + patch_apply dsound-EAX/0002-dsound-Add-EAX-v1-constants-and-structs.patch + patch_apply dsound-EAX/0003-dsound-Report-that-we-support-EAX-v1.patch + patch_apply dsound-EAX/0004-dsound-Add-EAX-propset-stubs.patch + patch_apply dsound-EAX/0005-dsound-Add-EAX-presets.patch + patch_apply dsound-EAX/0006-dsound-Support-getting-and-setting-EAX-properties.patch + patch_apply dsound-EAX/0007-dsound-Support-getting-and-setting-EAX-buffer-proper.patch + patch_apply dsound-EAX/0008-dsound-Add-EAX-init-and-free-stubs.patch + patch_apply dsound-EAX/0009-dsound-Feed-data-through-EAX-function.patch + patch_apply dsound-EAX/0010-dsound-Allocate-EAX-delay-lines.patch + patch_apply dsound-EAX/0011-dsound-Add-EAX-VerbPass-stub.patch + patch_apply dsound-EAX/0012-dsound-Implement-EAX-lowpass-filter.patch + patch_apply dsound-EAX/0013-dsound-Add-delay-line-EAX-functions.patch + patch_apply dsound-EAX/0014-dsound-Implement-EAX-early-reflections.patch + patch_apply dsound-EAX/0015-dsound-Implement-EAX-decorrelator.patch + patch_apply dsound-EAX/0016-dsound-Implement-EAX-late-reverb.patch + patch_apply dsound-EAX/0017-dsound-Implement-EAX-late-all-pass-filter.patch + ( + echo '+ { "Sebastian Lackner", "dsound: Apply filters before sound is multiplied to speakers.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add EAX v1 constants and structs.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Report that we support EAX.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add EAX propset stubs.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add EAX presets.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Support getting and setting EAX properties.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Support getting and setting EAX buffer properties.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add EAX init and free stubs.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Feed data through EAX function.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Allocate EAX delay lines.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add EAX VerbPass stub.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Implement EAX lowpass filter.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Add delay line EAX functions.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Implement EAX early reflections.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Implement EAX decorrelator.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Implement EAX late reverb.", 1 },'; + echo '+ { "Mark Harmstone", "dsound: Implement EAX late all-pass filter.", 1 },'; + ) >> "$patchlist" +fi + # Patchset dxgi-GetDesc # | # | This patchset fixes the following Wine bugs: @@ -2486,6 +2542,20 @@ if test "$enable_kernel32_Console_Handles" -eq 1; then ) >> "$patchlist" fi +# Patchset kernel32-SetFileInformationByHandle +# | +# | Modified files: +# | * dlls/kernel32/file.c, include/winbase.h +# | +if test "$enable_kernel32_SetFileInformationByHandle" -eq 1; then + patch_apply kernel32-SetFileInformationByHandle/0001-include-Declare-a-couple-more-file-information-class.patch + patch_apply kernel32-SetFileInformationByHandle/0002-kernel32-Implement-SetFileInformationByHandle.patch + ( + echo '+ { "Michael Müller", "include: Declare a couple more file information class structures.", 1 },'; + echo '+ { "Michael Müller", "kernel32: Implement SetFileInformationByHandle.", 1 },'; + ) >> "$patchlist" +fi + # Patchset ntdll-FileDispositionInformation # | # | This patchset fixes the following Wine bugs: @@ -2505,20 +2575,6 @@ if test "$enable_ntdll_FileDispositionInformation" -eq 1; then ) >> "$patchlist" fi -# Patchset kernel32-SetFileInformationByHandle -# | -# | Modified files: -# | * dlls/kernel32/file.c, include/winbase.h -# | -if test "$enable_kernel32_SetFileInformationByHandle" -eq 1; then - patch_apply kernel32-SetFileInformationByHandle/0001-include-Declare-a-couple-more-file-information-class.patch - patch_apply kernel32-SetFileInformationByHandle/0002-kernel32-Implement-SetFileInformationByHandle.patch - ( - echo '+ { "Michael Müller", "include: Declare a couple more file information class structures.", 1 },'; - echo '+ { "Michael Müller", "kernel32: Implement SetFileInformationByHandle.", 1 },'; - ) >> "$patchlist" -fi - # Patchset kernel32-CopyFileEx # | # | This patchset fixes the following Wine bugs: