[PATCH v3 0/5] MR9259: dmusic,dmime: Volume control part 2
-- v3: dmime: Update master volume when GUID_PerfMasterVolume is set. dmime: Set master volume when adding a port. https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmusic/tests/dmusic.c | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 3b2f7d9160e..b6fd97c896e 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1035,6 +1035,51 @@ static void test_synthport(void) IDirectMusic_Release(dmusic); } +static void test_port_kscontrol(void) +{ + IDirectMusicPort *port; + IDirectMusic *dmusic; + IKsControl *control; + KSPROPERTY property; + DWORD volume_size; + LONG volume; + HRESULT hr; + + port = create_synth_port(&dmusic); + hr = IDirectMusicPort_QueryInterface(port, &IID_IKsControl, (void **)&control); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicPort_Release(port); + + property.Set = GUID_DMUS_PROP_Volume; + property.Id = 0; + property.Flags = KSPROPERTY_TYPE_GET; + hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); + todo_wine ok(hr == DMUS_E_GET_UNSUPPORTED, "got hr %#lx.\n", hr); + + property.Set = GUID_DMUS_PROP_Volume; + property.Id = 1; + property.Flags = KSPROPERTY_TYPE_GET; + hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); + todo_wine ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); + + volume = 0; + property.Set = GUID_DMUS_PROP_Volume; + property.Id = 0; + property.Flags = KSPROPERTY_TYPE_SET; + hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); + todo_wine ok(hr == S_OK, "got hr %#lx.\n", hr); + + volume = 0; + property.Set = GUID_DMUS_PROP_Volume; + property.Id = 1; + property.Flags = KSPROPERTY_TYPE_SET; + hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); + todo_wine ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); + + IDirectMusicPort_Release(port); + IDirectMusic_Release(dmusic); +} + static void test_port_download(void) { struct wave_download @@ -1665,6 +1710,7 @@ START_TEST(dmusic) test_parsedescriptor(); test_master_clock(); test_synthport(); + test_port_kscontrol(); test_port_download(); test_download_instrument(); test_default_gm_collection(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmusic/port.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index f98d73f4444..49219ae10c5 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -686,6 +686,7 @@ static const IKsControlVtbl ikscontrol_vtbl = { HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, DMUS_PORTCAPS *port_caps, IDirectMusicPort **port) { + IKsControl *synth_control = NULL; struct synth_port *obj; HRESULT hr = E_FAIL; int i; @@ -711,6 +712,9 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth, (void **)&obj->synth); + if (SUCCEEDED(hr)) + hr = IDirectMusicSynth_QueryInterface(obj->synth, &IID_IKsControl, (void **)&synth_control); + if (SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink, (void**)&obj->synth_sink); @@ -726,6 +730,29 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param if (SUCCEEDED(hr)) hr = IDirectMusicSynth_Open(obj->synth, port_params); + if (SUCCEEDED(hr)) + { + KSPROPERTY volume_prop; + DWORD volume_size; + LONG volume = 0; + + volume = -600; + volume_prop.Set = GUID_DMUS_PROP_Volume; + volume_prop.Id = 0; + volume_prop.Flags = KSPROPERTY_TYPE_SET; + + IKsControl_KsProperty(synth_control, &volume_prop, sizeof(volume_prop), &volume, + sizeof(volume), &volume_size); + + volume = 0; + volume_prop.Set = GUID_DMUS_PROP_Volume; + volume_prop.Id = 1; + volume_prop.Flags = KSPROPERTY_TYPE_SET; + + IKsControl_KsProperty(synth_control, &volume_prop, sizeof(volume_prop), &volume, + sizeof(volume), &volume_size); + } + if (0) { if (port_params->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS) { @@ -753,6 +780,9 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param } } + if (synth_control) + IKsControl_Release(synth_control); + if (SUCCEEDED(hr)) { *port = &obj->IDirectMusicPort_iface; return S_OK; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmusic/port.c | 51 ++++++++++++++++++++++++++++++++------ dlls/dmusic/tests/dmusic.c | 8 +++--- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 49219ae10c5..84a9e759ab2 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -42,6 +42,7 @@ struct synth_port { IDirectSound *dsound; IDirectSoundBuffer *dsbuffer; IDirectMusicSynth *synth; + IKsControl *synth_control; IDirectMusicSynthSink *synth_sink; BOOL active; DMUS_PORTPARAMS params; @@ -129,6 +130,7 @@ static ULONG WINAPI synth_port_Release(IDirectMusicPort *iface) IDirectMusicSynthSink_Release(This->synth_sink); IDirectMusicSynth_Activate(This->synth, FALSE); IDirectMusicSynth_Close(This->synth); + IKsControl_Release(This->synth_control); IDirectMusicSynth_Release(This->synth); if (This->dsbuffer) IDirectSoundBuffer_Release(This->dsbuffer); @@ -639,15 +641,52 @@ static ULONG WINAPI IKsControlImpl_Release(IKsControl *iface) static HRESULT WINAPI IKsControlImpl_KsProperty(IKsControl *iface, KSPROPERTY *prop, ULONG prop_len, void *data, ULONG data_len, ULONG *ret_len) { + struct synth_port *This = synth_from_IKsControl(iface); + TRACE("(%p, %p, %lu, %p, %lu, %p)\n", iface, prop, prop_len, data, data_len, ret_len); TRACE("prop = %s - %lu - %lu\n", debugstr_guid(&prop->Set), prop->Id, prop->Flags); + if (prop->Flags == KSPROPERTY_TYPE_SET) + { + if (data_len < sizeof(LONG)) + return E_NOT_SUFFICIENT_BUFFER; + + if (IsEqualGUID(&prop->Set, &GUID_DMUS_PROP_Volume)) + { + KSPROPERTY volume_prop; + DWORD volume_size; + + if (prop->Id != 0) + return DMUS_E_UNKNOWN_PROPERTY; + + volume_prop.Set = GUID_DMUS_PROP_Volume; + volume_prop.Id = 1; + volume_prop.Flags = KSPROPERTY_TYPE_SET; + + return IKsControl_KsProperty(This->synth_control, &volume_prop, sizeof(volume_prop), + data, data_len, &volume_size); + } + else + { + FIXME("Unknown property %s\n", debugstr_guid(&prop->Set)); + } + + return S_OK; + } + if (prop->Flags != KSPROPERTY_TYPE_GET) { FIXME("prop flags %lu not yet supported\n", prop->Flags); return S_FALSE; } + if (IsEqualGUID(&prop->Set, &GUID_DMUS_PROP_Volume)) + { + if (prop->Id != 0) + return DMUS_E_UNKNOWN_PROPERTY; + return DMUS_E_GET_UNSUPPORTED; + } + if (data_len < sizeof(DWORD)) return E_NOT_SUFFICIENT_BUFFER; @@ -686,7 +725,6 @@ static const IKsControlVtbl ikscontrol_vtbl = { HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, DMUS_PORTCAPS *port_caps, IDirectMusicPort **port) { - IKsControl *synth_control = NULL; struct synth_port *obj; HRESULT hr = E_FAIL; int i; @@ -713,7 +751,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param (void **)&obj->synth); if (SUCCEEDED(hr)) - hr = IDirectMusicSynth_QueryInterface(obj->synth, &IID_IKsControl, (void **)&synth_control); + hr = IDirectMusicSynth_QueryInterface(obj->synth, &IID_IKsControl, (void **)&obj->synth_control); if (SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink, (void**)&obj->synth_sink); @@ -741,7 +779,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param volume_prop.Id = 0; volume_prop.Flags = KSPROPERTY_TYPE_SET; - IKsControl_KsProperty(synth_control, &volume_prop, sizeof(volume_prop), &volume, + IKsControl_KsProperty(obj->synth_control, &volume_prop, sizeof(volume_prop), &volume, sizeof(volume), &volume_size); volume = 0; @@ -749,7 +787,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param volume_prop.Id = 1; volume_prop.Flags = KSPROPERTY_TYPE_SET; - IKsControl_KsProperty(synth_control, &volume_prop, sizeof(volume_prop), &volume, + IKsControl_KsProperty(obj->synth_control, &volume_prop, sizeof(volume_prop), &volume, sizeof(volume), &volume_size); } @@ -780,14 +818,13 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param } } - if (synth_control) - IKsControl_Release(synth_control); - if (SUCCEEDED(hr)) { *port = &obj->IDirectMusicPort_iface; return S_OK; } + if (obj->synth_control) + IKsControl_Release(obj->synth_control); if (obj->synth) IDirectMusicSynth_Release(obj->synth); if (obj->synth_sink) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index b6fd97c896e..41041294faa 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1054,27 +1054,27 @@ static void test_port_kscontrol(void) property.Id = 0; property.Flags = KSPROPERTY_TYPE_GET; hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); - todo_wine ok(hr == DMUS_E_GET_UNSUPPORTED, "got hr %#lx.\n", hr); + ok(hr == DMUS_E_GET_UNSUPPORTED, "got hr %#lx.\n", hr); property.Set = GUID_DMUS_PROP_Volume; property.Id = 1; property.Flags = KSPROPERTY_TYPE_GET; hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); - todo_wine ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); + ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); volume = 0; property.Set = GUID_DMUS_PROP_Volume; property.Id = 0; property.Flags = KSPROPERTY_TYPE_SET; hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); - todo_wine ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(hr == S_OK, "got hr %#lx.\n", hr); volume = 0; property.Set = GUID_DMUS_PROP_Volume; property.Id = 1; property.Flags = KSPROPERTY_TYPE_SET; hr = IKsControl_KsProperty(control, &property, sizeof(property), &volume, sizeof(volume), &volume_size); - todo_wine ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); + ok(hr == DMUS_E_UNKNOWN_PROPERTY, "got hr %#lx.\n", hr); IDirectMusicPort_Release(port); IDirectMusic_Release(dmusic); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmime/dmime_main.c | 1 + dlls/dmime/performance.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/dlls/dmime/dmime_main.c b/dlls/dmime/dmime_main.c index 05d094fc2a2..8fc9cc702f6 100644 --- a/dlls/dmime/dmime_main.c +++ b/dlls/dmime/dmime_main.c @@ -32,6 +32,7 @@ #include "rpcproxy.h" #include "initguid.h" #include "dmusici.h" +#include "dmksctrl.h" #include "dmime_private.h" diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 3c67fbcadb4..ac0777c2dc0 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -20,6 +20,7 @@ #include "dmime_private.h" #include "dmusic_midi.h" +#include "dmksctrl.h" #include "wine/rbtree.h" #include <math.h> @@ -1138,6 +1139,25 @@ static void performance_update_latency_time(struct performance *This, IDirectMus if (FAILED(hr)) ERR("Failed to update performance %p latency, hr %#lx\n", This, hr); } +static void set_port_volume(IDirectMusicPort *port, LONG volume) +{ + KSPROPERTY volume_prop; + IKsControl *control; + DWORD volume_size; + + if (FAILED(IDirectMusicPort_QueryInterface(port, &IID_IKsControl, (void **)&control))) + return; + + volume_prop.Set = GUID_DMUS_PROP_Volume; + volume_prop.Id = 0; + volume_prop.Flags = KSPROPERTY_TYPE_SET; + + IKsControl_KsProperty(control, &volume_prop, sizeof(volume_prop), &volume, sizeof(volume), + &volume_size); + + IKsControl_Release(control); +} + static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) { IDirectMusicPort *port; @@ -1167,6 +1187,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } performance_update_latency_time(perf, port, NULL); + set_port_volume(port, perf->lMasterVolume); IDirectMusicPort_Release(port); return S_OK; } @@ -1197,6 +1218,7 @@ static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDire */ performance_update_latency_time(This, port, NULL); + set_port_volume(port, This->lMasterVolume); return S_OK; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmime/performance.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index ac0777c2dc0..ef33fc3dac6 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1379,6 +1379,8 @@ static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface void *pParam, DWORD dwSize) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct channel_block *block; + int i; TRACE("(%p, %s, %p, %ld)\n", This, debugstr_dmguid(rguidType), pParam, dwSize); @@ -1396,6 +1398,11 @@ static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface } if (IsEqualGUID (rguidType, &GUID_PerfMasterVolume)) { memcpy(&This->lMasterVolume, pParam, dwSize); + RB_FOR_EACH_ENTRY(block, &This->channel_blocks, struct channel_block, entry) + { + for (i = 0; i < ARRAYSIZE(block->channels); ++i) + set_port_volume(block->channels[i].port, This->lMasterVolume); + } TRACE("=> MasterVolume set to %li\n", This->lMasterVolume); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
On Sun Oct 26 17:23:20 2025 +0000, Michael Stefaniuc wrote:
Caching the `IKsControl` in `struct channel` feels excessive. As most stuff just uses a single port you could cache the last `port` <==> `control` mapping in `update_master_volume()`. Or am I missing something? No, you are right, I don't know why I did it this way. I've removed the caching in v3.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9259#note_119706
v3: - Remove `IKsControl` caching. - Also set the volume when adding an existing port. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9259#note_119705
On Sun Oct 26 19:52:08 2025 +0000, Anton Baskanov wrote:
By trying different values and comparing the volume by ear. I can probably make an interactive test for this. OK, that was one of the options I've imagined.\ The other one was that it is documented somewhere.
I don't think we need an interactive test for this. Just wanted it documented and in the MR it is good enough as that is findable. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9259#note_119717
This merge request was approved by Michael Stefaniuc. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9259
Test failures are unrelated to this MR, all in wldap32. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9259#note_119719
participants (3)
-
Anton Baskanov -
Anton Baskanov (@baskanov) -
Michael Stefaniuc (@mstefani)