-- v3: dsound: Avoid division by zero when calculating Doppler shift. dsound: Change the speed of sound to 360. dsound: Enable Doppler shift. dsound/tests: Add tests for Doppler shift. dsound: Store the frequency of 3D buffers separately.
From: Anton Baskanov baskanov@gmail.com
--- dlls/dsound/buffer.c | 40 ++++++++++++++++++++++-------------- dlls/dsound/dsound_private.h | 1 + dlls/dsound/sound3d.c | 11 +++++----- 3 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c index 7b830604a60..1b724ee775b 100644 --- a/dlls/dsound/buffer.c +++ b/dlls/dsound/buffer.c @@ -287,10 +287,17 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *i
AcquireSRWLockExclusive(&This->lock);
- oldFreq = This->freq; - This->freq = freq; - if (freq != oldFreq) - DSOUND_RecalcFormat(This); + if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) { + oldFreq = This->ds3db_freq; + This->ds3db_freq = freq; + if (freq != oldFreq) + DSOUND_Calc3DBuffer(This); + } else { + oldFreq = This->freq; + This->freq = freq; + if (freq != oldFreq) + DSOUND_RecalcFormat(This); + }
ReleaseSRWLockExclusive(&This->lock);
@@ -700,7 +707,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *i return DSERR_INVALIDPARAM; }
- *freq = This->freq; + *freq = (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ? This->ds3db_freq : This->freq; TRACE("-> %ld\n", *freq);
return DS_OK; @@ -1100,15 +1107,6 @@ HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *ds dsb->sec_mixpos = 0; dsb->state = STATE_STOPPED;
- /* calculate fragment size and write lead */ - DSOUND_RecalcFormat(dsb); - - dsb->committedbuff = malloc(dsb->maxwritelead); - if(!dsb->committedbuff) { - IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface); - return DSERR_OUTOFMEMORY; - } - if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) { dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); dsb->ds3db_ds3db.vPosition.x = 0.0; @@ -1127,11 +1125,23 @@ HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *ds dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
+ dsb->ds3db_freq = dsbd->lpwfxFormat->nSamplesPerSec; + dsb->ds3db_need_recalc = FALSE; DSOUND_Calc3DBuffer(dsb); - } else + } else { DSOUND_RecalcVolPan(&(dsb->volpan));
+ /* calculate fragment size and write lead */ + DSOUND_RecalcFormat(dsb); + } + + dsb->committedbuff = malloc(dsb->maxwritelead); + if(!dsb->committedbuff) { + IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface); + return DSERR_OUTOFMEMORY; + } + InitializeSRWLock(&dsb->lock);
/* register buffer */ diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index d9f488c25b8..e67d474d61d 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -164,6 +164,7 @@ struct IDirectSoundBufferImpl /* DirectSound3DBuffer fields */ DS3DBUFFER ds3db_ds3db; LONG ds3db_lVolume; + DWORD ds3db_freq; BOOL ds3db_need_recalc; /* Used for bit depth conversion */ int mix_channels; diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c index 939e0091815..4e98cdc0b8d 100644 --- a/dlls/dsound/sound3d.c +++ b/dlls/dsound/sound3d.c @@ -288,6 +288,8 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) } TRACE("panning: Angle = %f rad, lPan = %ld\n", flAngle, dsb->volpan.lPan);
+ dsb->freq = dsb->ds3db_freq; + /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */ if(0) { @@ -310,16 +312,15 @@ if(0) if listener moves AWAY from buffer, its velocity component is NEGATIVE */ flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance); /* formula taken from Gianicoli D.: Physics, 4th edition: */ - /* FIXME: replace dsb->freq with appropriate frequency ! */ - flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel)); + flFreq = dsb->ds3db_freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel)); TRACE("doppler: Buffer velocity (component) = %f, Listener velocity (component) = %f => Doppler shift: %ld Hz -> %f Hz\n", - flBufferVel, flListenerVel, dsb->freq, flFreq); - /* FIXME: replace following line with correct frequency setting ! */ + flBufferVel, flListenerVel, dsb->ds3db_freq, flFreq); dsb->freq = flFreq; - DSOUND_RecalcFormat(dsb); } }
+ DSOUND_RecalcFormat(dsb); + for (i = 0; i < dsb->device->pwfx->nChannels; i++) dsb->volpan.dwTotalAmpFactor[i] = 0;
From: Anton Baskanov baskanov@gmail.com
--- dlls/dsound/tests/ds3d.c | 201 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)
diff --git a/dlls/dsound/tests/ds3d.c b/dlls/dsound/tests/ds3d.c index 577c4155e9f..4b70e0cc0ee 100644 --- a/dlls/dsound/tests/ds3d.c +++ b/dlls/dsound/tests/ds3d.c @@ -1249,6 +1249,205 @@ return DSERR_GENERIC; return rc; }
+static void check_doppler(IDirectSound *dsound, IDirectSound3DListener *listener, + BOOL play, DWORD mode, float listener_pos, float listener_velocity, + float buffer_pos, float buffer_velocity, DWORD set_freq, DWORD expected_freq) +{ + IDirectSound3DBuffer *buffer_3d; + IDirectSoundBuffer *ref_buffer; + IDirectSoundBuffer *buffer; + WAVEFORMATEX format; + DSBUFFERDESC desc; + DWORD locked_size; + void *locked_data; + HRESULT hr; + DWORD freq; + DWORD size; + char *data; + LONG ref; + + if (play) + { + const char *mode_str = ""; + if (mode == DS3DMODE_HEADRELATIVE) + mode_str = "in head-relative mode "; + else if (mode == DS3DMODE_DISABLE) + mode_str = "with 3D processing disabled "; + trace(" Testing Doppler shift %swith listener at %g, velocity %g" + " with sound at %g, velocity %g, frequency %luHz\n", + mode_str, listener_pos, listener_velocity, buffer_pos, buffer_velocity, set_freq); + } + + memset(&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 1; + format.nSamplesPerSec = 22050; + format.wBitsPerSample = 16; + format.nAvgBytesPerSec = 2 * 22050; + format.nBlockAlign = 2; + + data = wave_generate_la(&format, 0.6, &size, FALSE); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = 0; + desc.lpwfxFormat = &format; + desc.dwBufferBytes = size; + + hr = IDirectSound_CreateSoundBuffer(dsound, &desc, &ref_buffer, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSoundBuffer_Lock(ref_buffer, 0, 0, &locked_data, &locked_size, NULL, NULL, DSBLOCK_ENTIREBUFFER); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + memcpy(locked_data, data, size); + hr = IDirectSoundBuffer_Unlock(ref_buffer, locked_data, locked_size, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + HeapFree(GetProcessHeap(), 0, data); + + memset(&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 1; + /* Set the sampling frequency of the generated waveform to the frequency + * that the buffer is expected to be played at. This way a successful + * test will produce a 440Hz tone. */ + format.nSamplesPerSec = expected_freq; + format.wBitsPerSample = 16; + format.nAvgBytesPerSec = 2 * expected_freq; + format.nBlockAlign = 2; + + data = wave_generate_la(&format, 0.6, &size, FALSE); + + memset(&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 1; + format.nSamplesPerSec = 22050; + format.wBitsPerSample = 16; + format.nAvgBytesPerSec = 2 * 22050; + format.nBlockAlign = 2; + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRL3D; + desc.lpwfxFormat = &format; + desc.dwBufferBytes = size; + + hr = IDirectSound_CreateSoundBuffer(dsound, &desc, &buffer, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSoundBuffer_QueryInterface(buffer, &IID_IDirectSound3DBuffer, (void *)&buffer_3d); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSoundBuffer_Lock(buffer, 0, 0, &locked_data, &locked_size, NULL, NULL, DSBLOCK_ENTIREBUFFER); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + memcpy(locked_data, data, size); + hr = IDirectSoundBuffer_Unlock(buffer, locked_data, locked_size, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + HeapFree(GetProcessHeap(), 0, data); + + /* Set to different values first to test that the frequency is updated. */ + hr = IDirectSound3DListener_SetPosition(listener, 0, 0, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DListener_SetVelocity(listener, 0, 0, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DBuffer_SetPosition(buffer_3d, 0, 1, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DBuffer_SetVelocity(buffer_3d, 0, -60, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DListener_CommitDeferredSettings(listener); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSound3DListener_SetPosition(listener, 0, listener_pos, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DListener_SetVelocity(listener, 0, listener_velocity, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSoundBuffer_SetFrequency(buffer, set_freq); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSound3DBuffer_SetMode(buffer_3d, mode, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DBuffer_SetPosition(buffer_3d, 0, buffer_pos, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSound3DBuffer_SetVelocity(buffer_3d, 0, buffer_velocity, 0, DS3D_DEFERRED); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSound3DListener_CommitDeferredSettings(listener); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + freq = 0xdeadbeef; + hr = IDirectSoundBuffer_GetFrequency(buffer, &freq); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(freq == set_freq, "Got frequency %lu\n", freq); + + if (play) + { + trace(" Playing a reference 440Hz tone\n"); + hr = IDirectSoundBuffer_Play(ref_buffer, 0, 0, DSBPLAY_LOOPING); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + Sleep(500); + hr = IDirectSoundBuffer_Stop(ref_buffer); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + trace(" Playing a test tone (should be 440Hz)\n"); + hr = IDirectSoundBuffer_Play(buffer, 0, 0, DSBPLAY_LOOPING); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + Sleep(500); + hr = IDirectSoundBuffer_Stop(buffer); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + + IDirectSound3DBuffer_Release(buffer_3d); + ref = IDirectSoundBuffer_Release(buffer); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IDirectSoundBuffer_Release(ref_buffer); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + +static void test_doppler(GUID *guid, BOOL play) +{ + IDirectSound3DListener *listener; + IDirectSoundBuffer *primary; + IDirectSound *dsound; + DSBUFFERDESC desc; + HRESULT hr; + HWND hwnd; + LONG ref; + + hwnd = get_hwnd(); + + hr = DirectSoundCreate(guid, &dsound, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectSound_SetCooperativeLevel(dsound, hwnd, DSSCL_PRIORITY); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; + hr = IDirectSound_CreateSoundBuffer(dsound, &desc, &primary, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSound3DListener, (void *)&listener); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* When run in interactive mode, the following tests should produce a series + * of 440Hz tones. Any deviation from 440Hz indicates a test failure. */ + + check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 0, 22050, 22050); + check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, -90, 1, -90, 22050, 22050); + + /* Wine TODO: Doppler shift is missing. */ + check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, -90, 22050, 29400); + /* Wine TODO: Doppler shift is missing. */ + check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 90, 22050, 17640); + + IDirectSound3DListener_Release(listener); + ref = IDirectSoundBuffer_Release(primary); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IDirectSound_Release(dsound); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + static unsigned driver_count = 0;
static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, @@ -1295,6 +1494,8 @@ static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1);
+ test_doppler(lpGuid,winetest_interactive); + return TRUE; }
From: Anton Baskanov baskanov@gmail.com
--- dlls/dsound/sound3d.c | 6 +----- dlls/dsound/tests/ds3d.c | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c index 4e98cdc0b8d..3dc563b3579 100644 --- a/dlls/dsound/sound3d.c +++ b/dlls/dsound/sound3d.c @@ -167,6 +167,7 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) int i, num_main_speakers; float a, ingain; /* doppler shift related stuff */ + D3DVALUE flFreq, flBufferVel, flListenerVel;
TRACE("(%p)\n",dsb);
@@ -290,10 +291,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
dsb->freq = dsb->ds3db_freq;
- /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */ -if(0) -{ - D3DVALUE flFreq, flBufferVel, flListenerVel; /* doppler shift*/ if (!VectorMagnitude(&dsb->ds3db_ds3db.vVelocity) && !VectorMagnitude(&dsb->device->ds3dl.vVelocity)) { @@ -317,7 +314,6 @@ if(0) flBufferVel, flListenerVel, dsb->ds3db_freq, flFreq); dsb->freq = flFreq; } -}
DSOUND_RecalcFormat(dsb);
diff --git a/dlls/dsound/tests/ds3d.c b/dlls/dsound/tests/ds3d.c index 4b70e0cc0ee..e71041e3a00 100644 --- a/dlls/dsound/tests/ds3d.c +++ b/dlls/dsound/tests/ds3d.c @@ -1436,9 +1436,9 @@ static void test_doppler(GUID *guid, BOOL play) check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 0, 22050, 22050); check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, -90, 1, -90, 22050, 22050);
- /* Wine TODO: Doppler shift is missing. */ + /* Wine TODO: The frequency is slightly off. */ check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, -90, 22050, 29400); - /* Wine TODO: Doppler shift is missing. */ + /* Wine TODO: The frequency is slightly off. */ check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 90, 22050, 17640);
IDirectSound3DListener_Release(listener);
From: Anton Baskanov baskanov@gmail.com
--- dlls/dsound/sound3d.c | 4 ++-- dlls/dsound/tests/ds3d.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c index 3dc563b3579..5d10af4329c 100644 --- a/dlls/dsound/sound3d.c +++ b/dlls/dsound/sound3d.c @@ -49,8 +49,8 @@ #include "dsound.h" #include "dsound_private.h"
-/* default velocity of sound in the air */ -#define DEFAULT_VELOCITY 340 +/* according to the tests, native uses 360 as the speed of sound */ +#define DEFAULT_VELOCITY 360
WINE_DEFAULT_DEBUG_CHANNEL(dsound3d);
diff --git a/dlls/dsound/tests/ds3d.c b/dlls/dsound/tests/ds3d.c index e71041e3a00..76269f1fcfe 100644 --- a/dlls/dsound/tests/ds3d.c +++ b/dlls/dsound/tests/ds3d.c @@ -1436,9 +1436,7 @@ static void test_doppler(GUID *guid, BOOL play) check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 0, 22050, 22050); check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, -90, 1, -90, 22050, 22050);
- /* Wine TODO: The frequency is slightly off. */ check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, -90, 22050, 29400); - /* Wine TODO: The frequency is slightly off. */ check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 90, 22050, 17640);
IDirectSound3DListener_Release(listener);
From: Anton Baskanov baskanov@gmail.com
--- dlls/dsound/sound3d.c | 3 ++- dlls/dsound/tests/ds3d.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c index 5d10af4329c..b062917b219 100644 --- a/dlls/dsound/sound3d.c +++ b/dlls/dsound/sound3d.c @@ -298,7 +298,8 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) } else if (!(dsb->ds3db_ds3db.vVelocity.x == dsb->device->ds3dl.vVelocity.x && dsb->ds3db_ds3db.vVelocity.y == dsb->device->ds3dl.vVelocity.y && - dsb->ds3db_ds3db.vVelocity.z == dsb->device->ds3dl.vVelocity.z)) + dsb->ds3db_ds3db.vVelocity.z == dsb->device->ds3dl.vVelocity.z) && + !(vDistance.x == 0.0f && vDistance.y == 0.0f && vDistance.z == 0.0f)) { /* calculate length of ds3db_ds3db.vVelocity component which causes Doppler Effect NOTE: if buffer moves TOWARDS the listener, its velocity component is NEGATIVE diff --git a/dlls/dsound/tests/ds3d.c b/dlls/dsound/tests/ds3d.c index 76269f1fcfe..5e6ba4d204e 100644 --- a/dlls/dsound/tests/ds3d.c +++ b/dlls/dsound/tests/ds3d.c @@ -1439,6 +1439,8 @@ static void test_doppler(GUID *guid, BOOL play) check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, -90, 22050, 29400); check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 1, 90, 22050, 17640);
+ check_doppler(dsound, listener, play, DS3DMODE_NORMAL, 0, 0, 0, -90, 22050, 22050); + IDirectSound3DListener_Release(listener); ref = IDirectSoundBuffer_Release(primary); ok(!ref, "Got outstanding refcount %ld.\n", ref);
On Tue May 23 06:21:27 2023 +0000, Huw Davies wrote:
So let's squash the last two commits to avoid this.
Done in v3.
This merge request was approved by Huw Davies.