From 653d93fc2909f55eb48a5865345922c531f02256 Mon Sep 17 00:00:00 2001 From: Ben <17994859+ben-rnd@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:03:26 +1000 Subject: [PATCH 1/5] ds-api: Export original DirectSoundCreate for games predating dsound8 --- src/ds-api.c | 14 ++++++++++++-- src/dsound.def | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ds-api.c b/src/ds-api.c index a45d6d7..9f9d14a 100644 --- a/src/ds-api.c +++ b/src/ds-api.c @@ -431,9 +431,9 @@ static IDirectSound8Vtbl ds_api_vtbl = { .VerifyCertification = ds_api_verify_certification, }; -/* DirectSound API entry point, exported as DirectSoundCreate8 */ +/* DirectSound8 API entry point, exported as DirectSoundCreate8 */ -HRESULT __stdcall ds_api_create( +HRESULT __stdcall ds_api_create8( const GUID *guid_device, IDirectSound8 **out, IUnknown *outer) @@ -479,3 +479,13 @@ HRESULT __stdcall ds_api_create( return hr; } + +/* DirectSound API entry point, exported as DirectSoundCreate */ + +HRESULT __stdcall ds_api_create( + const GUID *guid_device, + IDirectSound **out, + IUnknown *outer) +{ + return ds_api_create8(guid_device, (IDirectSound8 **) out, outer); +} diff --git a/src/dsound.def b/src/dsound.def index 4b928e2..98408e0 100644 --- a/src/dsound.def +++ b/src/dsound.def @@ -1,4 +1,5 @@ LIBRARY dsound EXPORTS - DirectSoundCreate8=ds_api_create@12 @11 + DirectSoundCreate=ds_api_create@12 @1 + DirectSoundCreate8=ds_api_create8@12 @11 From 5c2bef0e3ad367796d9df861d44ae9ab9179e6fa Mon Sep 17 00:00:00 2001 From: Ben <17994859+ben-rnd@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:09:30 +1000 Subject: [PATCH 2/5] snd-service: Fix SetVolume(0) silencing all audio. SetVolume(0) should set max volume not mute. Per docs volume range is -10000 (min) to 0 (max): https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mt708939(v=vs.85)#remarks --- src/snd-service.c | 2 +- src/snd-service.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/snd-service.c b/src/snd-service.c index 409dfd7..3ff4cc9 100644 --- a/src/snd-service.c +++ b/src/snd-service.c @@ -132,7 +132,7 @@ void snd_command_set_volume( struct snd_command *cmd, struct snd_stream *stm, size_t channel_no, - uint8_t value) + uint16_t value) { assert(cmd != NULL); diff --git a/src/snd-service.h b/src/snd-service.h index 8ae9adf..4c85137 100644 --- a/src/snd-service.h +++ b/src/snd-service.h @@ -23,7 +23,7 @@ void snd_command_set_volume( struct snd_command *cmd, struct snd_stream *stm, size_t channel_no, - uint8_t value); + uint16_t value); void snd_command_set_callback( struct snd_command *cmd, snd_callback_t callback, From ca3370f7db18b710a42a9565c00052e93d8039e7 Mon Sep 17 00:00:00 2001 From: Ben <17994859+ben-rnd@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:13:53 +1000 Subject: [PATCH 3/5] snd-stream: prevent looping streams being removed early. EZ2DJ uses looping streams as a circular buffer for playing longer audio files for most BGMs. looping stream was being removed before next write, causing audio to go silent. As per dsound docs a looping buffer should only stop when stopped explicitly. https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee418074(v=vs.85)#parameters --- src/snd-stream.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/snd-stream.c b/src/snd-stream.c index 4e74cc2..f3a0906 100644 --- a/src/snd-stream.c +++ b/src/snd-stream.c @@ -109,11 +109,13 @@ bool snd_stream_render( pos = pos_end; + if (pos >= buf_nsamples && stm->looping) { + pos = 0; + } + if (dest_nsamples == 0 || !stm->looping) { break; } - - pos = 0; } atomic_store(&stm->pos, pos); From 871f7690ae477de49f2ad223dbaf5499397e2a3d Mon Sep 17 00:00:00 2001 From: Ben <17994859+ben-rnd@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:22:58 +1000 Subject: [PATCH 4/5] ds-buffer: prevent restarting play on already playing buffer. EZ2DJ likes to spam play() on a few buffers. this was causing terrible audio most notably on the name entry screen. Per direct sound docs, subsequent play()'s should only update the flag. https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee418074(v=vs.85)#remarks --- src/ds-buffer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ds-buffer.c b/src/ds-buffer.c index db29df8..353c40c 100644 --- a/src/ds-buffer.c +++ b/src/ds-buffer.c @@ -635,12 +635,15 @@ static __stdcall HRESULT ds_buffer_play( if (r < 0) { return hr_from_errno(r); } - - self->playing = true; + self->looping = flags & DSBPLAY_LOOPING; - snd_command_play(cmd, self->stm, self->looping); - snd_client_cmd_submit(self->cli, cmd); + if (!self->playing) { + self->playing = true; + + snd_command_play(cmd, self->stm, self->looping); + snd_client_cmd_submit(self->cli, cmd); + } return S_OK; } From 3860a91b444ea247bdbb0329edc6c883f2a4ce1d Mon Sep 17 00:00:00 2001 From: Ben <17994859+ben-rnd@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:28:53 +1000 Subject: [PATCH 5/5] ds-buffer: implement SetPan, GetPan, GetVolume used by ez2dj --- src/ds-buffer.c | 80 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/src/ds-buffer.c b/src/ds-buffer.c index 353c40c..d337a8a 100644 --- a/src/ds-buffer.c +++ b/src/ds-buffer.c @@ -40,6 +40,8 @@ struct ds_buffer { bool buf_owned; bool playing; bool looping; + LONG volume; + LONG pan; }; static bool ds_buffer_requires_conversion(const struct ds_buffer *self); @@ -465,9 +467,16 @@ static __stdcall HRESULT ds_buffer_get_pan( IDirectSoundBuffer *com, LONG *out) { - trace("%s(%p) [stub]", __func__, out); + struct ds_buffer *self; + + if (out == NULL) { + return E_POINTER; + } + + self = ds_buffer_downcast(com); + *out = self->pan; - return E_NOTIMPL; + return S_OK; } static __stdcall HRESULT ds_buffer_get_status( @@ -508,9 +517,16 @@ static __stdcall HRESULT ds_buffer_get_volume( IDirectSoundBuffer *com, LONG *out) { - trace("%s(%p)", __func__, out); + struct ds_buffer *self; - return E_NOTIMPL; + if (out == NULL) { + return E_POINTER; + } + + self = ds_buffer_downcast(com); + *out = self->volume; + + return S_OK; } static __stdcall HRESULT ds_buffer_initialize( @@ -693,13 +709,48 @@ static __stdcall HRESULT ds_buffer_set_frequency( return S_OK; } +static HRESULT ds_buffer_apply_volume(struct ds_buffer *self) +{ + struct snd_command *cmd; + int16_t left_vol; + int16_t right_vol; + LONG left_mb; + LONG right_mb; + int r; + + left_mb = self->volume - (self->pan > 0 ? self->pan : 0); + right_mb = self->volume + (self->pan < 0 ? self->pan : 0); + + left_vol = 256.0 * pow(10.0, left_mb / 2000.0); + right_vol = 256.0 * pow(10.0, right_mb / 2000.0); + + r = snd_client_cmd_alloc(self->cli, &cmd); + + if (r < 0) { + return hr_from_errno(r); + } + + snd_command_set_volume(cmd, self->stm, 0, left_vol); + snd_command_set_volume(cmd, self->stm, 1, right_vol); + snd_client_cmd_submit(self->cli, cmd); + + return S_OK; +} + static __stdcall HRESULT ds_buffer_set_pan( IDirectSoundBuffer *com, LONG pan) { - // stub + struct ds_buffer *self; - return S_OK; + if (pan < -10000 || pan > 10000) { + return E_INVALIDARG; + } + + self = ds_buffer_downcast(com); + self->pan = pan; + + return ds_buffer_apply_volume(self); } static __stdcall HRESULT ds_buffer_set_volume( @@ -707,9 +758,6 @@ static __stdcall HRESULT ds_buffer_set_volume( LONG millibels) { struct ds_buffer *self; - struct snd_command *cmd; - int16_t linear_vol; - int r; if (millibels < -10000 || millibels > 0) { trace("%s: Attenutation param out of range: %li", millibels); @@ -718,19 +766,9 @@ static __stdcall HRESULT ds_buffer_set_volume( } self = ds_buffer_downcast(com); - linear_vol = 256.0 * pow(10.0, millibels / 2000.0); + self->volume = millibels; - r = snd_client_cmd_alloc(self->cli, &cmd); - - if (r < 0) { - return hr_from_errno(r); - } - - snd_command_set_volume(cmd, self->stm, 0, linear_vol); - snd_command_set_volume(cmd, self->stm, 1, linear_vol); - snd_client_cmd_submit(self->cli, cmd); - - return S_OK; + return ds_buffer_apply_volume(self); } static __stdcall HRESULT ds_buffer_stop(IDirectSoundBuffer *com)