dmsynth/tests: Test DirectMusicSynth class in isolation.
[wine.git] / dlls / dmsynth / tests / dmsynth.c
blob6919e22c6d6f3f66d187da775bc44ea6b571818e
1 /*
2 * Unit tests for dmsynth functions
4 * Copyright (C) 2012 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdio.h>
25 #include "wine/test.h"
26 #include "uuids.h"
27 #include "ole2.h"
28 #include "initguid.h"
29 #include "dmusics.h"
30 #include "dmusici.h"
31 #include "dmksctrl.h"
33 static BOOL missing_dmsynth(void)
35 IDirectMusicSynth *dms;
36 HRESULT hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER,
37 &IID_IDirectMusicSynth, (void**)&dms);
39 if (hr == S_OK && dms)
41 IDirectMusicSynth_Release(dms);
42 return FALSE;
44 return TRUE;
47 static ULONG get_refcount(void *iface)
49 IUnknown *unknown = iface;
50 IUnknown_AddRef(unknown);
51 return IUnknown_Release(unknown);
54 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
55 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
57 ULONG expect_ref = get_refcount(iface_ptr);
58 IUnknown *iface = iface_ptr;
59 HRESULT hr, expected;
60 IUnknown *unk;
62 expected = supported ? S_OK : E_NOINTERFACE;
63 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
64 ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected);
65 if (SUCCEEDED(hr))
67 LONG ref = get_refcount(unk);
68 ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref);
69 IUnknown_Release(unk);
70 ref = get_refcount(iface_ptr);
71 ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref);
75 struct test_synth
77 IDirectMusicSynth8 IDirectMusicSynth8_iface;
78 LONG refcount;
81 static HRESULT WINAPI test_synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void **ret_iface)
83 ok(0, "unexpected %s\n", __func__);
84 return S_OK;
87 static ULONG WINAPI test_synth_AddRef(IDirectMusicSynth8 *iface)
89 struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface);
90 return InterlockedIncrement(&sink->refcount);
93 static ULONG WINAPI test_synth_Release(IDirectMusicSynth8 *iface)
95 struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface);
96 ULONG ref = InterlockedDecrement(&sink->refcount);
97 if (!ref) free(sink);
98 return ref;
101 static HRESULT WINAPI test_synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params)
103 ok(0, "unexpected %s\n", __func__);
104 return S_OK;
107 static HRESULT WINAPI test_synth_Close(IDirectMusicSynth8 *iface)
109 ok(0, "unexpected %s\n", __func__);
110 return S_OK;
113 static HRESULT WINAPI test_synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, DWORD groups)
115 ok(0, "unexpected %s\n", __func__);
116 return S_OK;
119 static HRESULT WINAPI test_synth_Download(IDirectMusicSynth8 *iface, HANDLE *handle, void *data, BOOL *can_free)
121 ok(0, "unexpected %s\n", __func__);
122 return S_OK;
125 static HRESULT WINAPI test_synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle,
126 HRESULT (CALLBACK *free_callback)(HANDLE,HANDLE), HANDLE user_data)
128 ok(0, "unexpected %s\n", __func__);
129 return S_OK;
132 static HRESULT WINAPI test_synth_PlayBuffer(IDirectMusicSynth8 *iface, REFERENCE_TIME time, BYTE *buffer, DWORD size)
134 ok(0, "unexpected %s\n", __func__);
135 return S_OK;
138 static HRESULT WINAPI test_synth_GetRunningStats(IDirectMusicSynth8 *iface, DMUS_SYNTHSTATS *stats)
140 ok(0, "unexpected %s\n", __func__);
141 return S_OK;
144 static HRESULT WINAPI test_synth_GetPortCaps(IDirectMusicSynth8 *iface, DMUS_PORTCAPS *caps)
146 ok(0, "unexpected %s\n", __func__);
147 return S_OK;
150 static HRESULT WINAPI test_synth_SetMasterClock(IDirectMusicSynth8 *iface, IReferenceClock *clock)
152 ok(0, "unexpected %s\n", __func__);
153 return S_OK;
156 static HRESULT WINAPI test_synth_GetLatencyClock(IDirectMusicSynth8 *iface, IReferenceClock **clock)
158 ok(0, "unexpected %s\n", __func__);
159 return S_OK;
162 static HRESULT WINAPI test_synth_Activate(IDirectMusicSynth8 *iface, BOOL enable)
164 ok(0, "unexpected %s\n", __func__);
165 return S_OK;
168 static HRESULT WINAPI test_synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *sink)
170 ok(0, "unexpected %s\n", __func__);
171 return S_OK;
174 static HRESULT WINAPI test_synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position)
176 return S_OK;
179 static HRESULT WINAPI test_synth_SetChannelPriority(IDirectMusicSynth8 *iface, DWORD group, DWORD channel, DWORD priority)
181 ok(0, "unexpected %s\n", __func__);
182 return S_OK;
185 static HRESULT WINAPI test_synth_GetChannelPriority(IDirectMusicSynth8 *iface, DWORD group, DWORD channel, DWORD *priority)
187 ok(0, "unexpected %s\n", __func__);
188 return S_OK;
191 static HRESULT WINAPI test_synth_GetFormat(IDirectMusicSynth8 *iface, WAVEFORMATEX *format, DWORD *ext_size)
193 *ext_size = 0;
194 memset(format, 0, sizeof(*format));
195 format->wFormatTag = WAVE_FORMAT_PCM;
196 format->nChannels = 2;
197 format->wBitsPerSample = 16;
198 format->nSamplesPerSec = 44100;
199 format->nBlockAlign = format->nChannels * format->wBitsPerSample / 8;
200 format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
201 return S_OK;
204 static HRESULT WINAPI test_synth_GetAppend(IDirectMusicSynth8 *iface, DWORD *append)
206 ok(0, "unexpected %s\n", __func__);
207 return S_OK;
210 static HRESULT WINAPI test_synth_PlayVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD voice_id,
211 DWORD group, DWORD channel, DWORD dlid, LONG pitch, LONG volume, SAMPLE_TIME voice_start,
212 SAMPLE_TIME loop_start, SAMPLE_TIME loop_end)
214 ok(0, "unexpected %s\n", __func__);
215 return S_OK;
218 static HRESULT WINAPI test_synth_StopVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD voice_id)
220 ok(0, "unexpected %s\n", __func__);
221 return S_OK;
224 static HRESULT WINAPI test_synth_GetVoiceState(IDirectMusicSynth8 *iface, DWORD voice_buf[], DWORD voice_len,
225 DMUS_VOICE_STATE voice_state[])
227 ok(0, "unexpected %s\n", __func__);
228 return S_OK;
231 static HRESULT WINAPI test_synth_Refresh(IDirectMusicSynth8 *iface, DWORD dlid, DWORD flags)
233 ok(0, "unexpected %s\n", __func__);
234 return S_OK;
237 static HRESULT WINAPI test_synth_AssignChannelToBuses(IDirectMusicSynth8 *iface, DWORD group, DWORD channel,
238 DWORD *buses, DWORD buses_count)
240 ok(0, "unexpected %s\n", __func__);
241 return S_OK;
244 static const IDirectMusicSynth8Vtbl test_synth_vtbl =
246 test_synth_QueryInterface,
247 test_synth_AddRef,
248 test_synth_Release,
249 test_synth_Open,
250 test_synth_Close,
251 test_synth_SetNumChannelGroups,
252 test_synth_Download,
253 test_synth_Unload,
254 test_synth_PlayBuffer,
255 test_synth_GetRunningStats,
256 test_synth_GetPortCaps,
257 test_synth_SetMasterClock,
258 test_synth_GetLatencyClock,
259 test_synth_Activate,
260 test_synth_SetSynthSink,
261 test_synth_Render,
262 test_synth_SetChannelPriority,
263 test_synth_GetChannelPriority,
264 test_synth_GetFormat,
265 test_synth_GetAppend,
266 test_synth_PlayVoice,
267 test_synth_StopVoice,
268 test_synth_GetVoiceState,
269 test_synth_Refresh,
270 test_synth_AssignChannelToBuses,
273 static HRESULT test_synth_create(IDirectMusicSynth8 **out)
275 struct test_synth *synth;
277 *out = NULL;
278 if (!(synth = calloc(1, sizeof(*synth)))) return E_OUTOFMEMORY;
279 synth->IDirectMusicSynth8_iface.lpVtbl = &test_synth_vtbl;
280 synth->refcount = 1;
282 *out = &synth->IDirectMusicSynth8_iface;
283 return S_OK;
286 static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *params, const char *context)
288 WAVEFORMATEX format;
289 DWORD size;
290 HRESULT hr;
292 winetest_push_context("%s", context);
294 size = sizeof(format);
295 hr = IDirectMusicSynth_GetFormat(synth, &format, &size);
296 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
297 ok(format.wFormatTag == WAVE_FORMAT_PCM, "wFormatTag: %#x\n", format.wFormatTag);
298 ok(format.nChannels == params->dwAudioChannels, "nChannels: %d\n", format.nChannels);
299 ok(format.nSamplesPerSec == params->dwSampleRate, "nSamplesPerSec: %ld\n", format.nSamplesPerSec);
300 ok(format.wBitsPerSample == 16, "wBitsPerSample: %d\n", format.wBitsPerSample);
301 ok(format.nBlockAlign == params->dwAudioChannels * format.wBitsPerSample / 8, "nBlockAlign: %d\n",
302 format.nBlockAlign);
303 ok(format.nAvgBytesPerSec == params->dwSampleRate * format.nBlockAlign, "nAvgBytesPerSec: %ld\n",
304 format.nAvgBytesPerSec);
305 ok(format.cbSize == 0, "cbSize: %d\n", format.cbSize);
307 winetest_pop_context();
310 static void test_dmsynth(void)
312 IDirectMusicSynth *dmsynth = NULL;
313 IDirectMusicSynthSink *dmsynth_sink = NULL, *dmsynth_sink2 = NULL;
314 IReferenceClock* clock_synth = NULL;
315 IReferenceClock* clock_sink = NULL;
316 IKsControl* control_synth = NULL;
317 IKsControl* control_sink = NULL;
318 ULONG ref_clock_synth, ref_clock_sink;
319 HRESULT hr;
320 KSPROPERTY property;
321 ULONG value;
322 ULONG bytes;
323 DMUS_PORTCAPS caps;
324 DMUS_PORTPARAMS params;
325 const DWORD all_params = DMUS_PORTPARAMS_VOICES|DMUS_PORTPARAMS_CHANNELGROUPS|DMUS_PORTPARAMS_AUDIOCHANNELS|
326 DMUS_PORTPARAMS_SAMPLERATE|DMUS_PORTPARAMS_EFFECTS|DMUS_PORTPARAMS_SHARE|DMUS_PORTPARAMS_FEATURES;
327 WAVEFORMATEX format;
328 DWORD size;
330 hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth, (LPVOID*)&dmsynth);
331 ok(hr == S_OK, "CoCreateInstance returned: %#lx\n", hr);
333 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink,
334 (void **)&dmsynth_sink);
335 ok(hr == S_OK, "CoCreateInstance returned: %#lx\n", hr);
336 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink,
337 (void **)&dmsynth_sink2);
338 ok(hr == S_OK, "CoCreateInstance returned: %#lx\n", hr);
340 hr = IDirectMusicSynth_QueryInterface(dmsynth, &IID_IKsControl, (LPVOID*)&control_synth);
341 ok(hr == S_OK, "IDirectMusicSynth_QueryInterface returned: %#lx\n", hr);
343 property.Id = 0;
344 property.Flags = KSPROPERTY_TYPE_GET;
346 property.Set = GUID_DMUS_PROP_INSTRUMENT2;
347 hr = IKsControl_KsProperty(control_synth, &property, sizeof(property), &value, sizeof(value), &bytes);
348 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
349 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
350 ok(value == TRUE, "Return value: %lu, should be 1\n", value);
351 property.Set = GUID_DMUS_PROP_DLS2;
352 hr = IKsControl_KsProperty(control_synth, &property, sizeof(property), &value, sizeof(value), &bytes);
353 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
354 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
355 ok(value == TRUE, "Return value: %lu, should be 1\n", value);
356 property.Set = GUID_DMUS_PROP_GM_Hardware;
357 hr = IKsControl_KsProperty(control_synth, &property, sizeof(property), &value, sizeof(value), &bytes);
358 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
359 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
360 ok(value == FALSE, "Return value: %lu, should be 0\n", value);
361 property.Set = GUID_DMUS_PROP_GS_Hardware;
362 hr = IKsControl_KsProperty(control_synth, &property, sizeof(property), &value, sizeof(value), &bytes);
363 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
364 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
365 ok(value == FALSE, "Return value: %lu, should be 0\n", value);
366 property.Set = GUID_DMUS_PROP_XG_Hardware;
367 hr = IKsControl_KsProperty(control_synth, &property, sizeof(property), &value, sizeof(value), &bytes);
368 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
369 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
370 ok(value == FALSE, "Return value: %lu, should be 0\n", value);
372 hr = IDirectMusicSynthSink_QueryInterface(dmsynth_sink, &IID_IKsControl, (LPVOID*)&control_sink);
373 ok(hr == S_OK, "IDirectMusicSynthSink_QueryInterface returned: %#lx\n", hr);
375 property.Set = GUID_DMUS_PROP_SinkUsesDSound;
376 hr = IKsControl_KsProperty(control_sink, &property, sizeof(property), &value, sizeof(value), &bytes);
377 ok(hr == S_OK, "IKsControl_KsProperty returned: %#lx\n", hr);
378 ok(bytes == sizeof(DWORD), "Returned bytes: %lu, should be 4\n", bytes);
379 ok(value == TRUE, "Return value: %lu, should be 1\n", value);
381 /* Synth isn't fully initialized yet */
382 hr = IDirectMusicSynth_Activate(dmsynth, TRUE);
383 ok(hr == DMUS_E_NOSYNTHSINK, "IDirectMusicSynth_Activate returned: %#lx\n", hr);
384 hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, &size);
385 ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr);
387 /* Open / Close */
388 hr = IDirectMusicSynth_Open(dmsynth, NULL);
389 ok(hr == S_OK, "Open failed: %#lx\n", hr);
390 hr = IDirectMusicSynth_Open(dmsynth, NULL);
391 ok(hr == DMUS_E_ALREADYOPEN, "Open failed: %#lx\n", hr);
392 hr = IDirectMusicSynth_Close(dmsynth);
393 ok(hr == S_OK, "Close failed: %#lx\n", hr);
394 hr = IDirectMusicSynth_Close(dmsynth);
395 ok(hr == DMUS_E_ALREADYCLOSED, "Close failed: %#lx\n", hr);
396 memset(&params, 0, sizeof(params));
397 hr = IDirectMusicSynth_Open(dmsynth, &params);
398 ok(hr == E_INVALIDARG, "Open failed: %#lx\n", hr);
399 params.dwSize = sizeof(DMUS_PORTPARAMS7);
400 hr = IDirectMusicSynth_Open(dmsynth, &params);
401 ok(hr == S_OK, "Open failed: %#lx\n", hr);
402 IDirectMusicSynth_Close(dmsynth);
403 /* All params supported and set to 0 */
404 params.dwSize = sizeof(params);
405 params.dwValidParams = all_params;
406 hr = IDirectMusicSynth_Open(dmsynth, &params);
407 ok(hr == S_OK, "Open failed: %#lx\n", hr);
408 ok(params.dwSize == sizeof(params), "dwSize: %ld\n", params.dwSize);
409 ok(params.dwValidParams == all_params, "dwValidParams: %#lx\n", params.dwValidParams);
410 ok(params.dwVoices == 32, "dwVoices: %ld\n", params.dwVoices);
411 ok(params.dwChannelGroups == 2, "dwChannelGroups: %ld\n", params.dwChannelGroups);
412 ok(params.dwAudioChannels == 2, "dwAudioChannels: %ld\n", params.dwAudioChannels);
413 ok(params.dwSampleRate == 22050, "dwSampleRate: %ld\n", params.dwSampleRate);
414 ok(params.dwEffectFlags == DMUS_EFFECT_REVERB, "params.dwEffectFlags: %#lx\n", params.dwEffectFlags);
415 ok(params.fShare == FALSE, "fShare: %d\n", params.fShare);
416 ok(params.dwFeatures == 0, "dwFeatures: %#lx\n", params.dwFeatures);
417 test_synth_getformat(dmsynth, &params, "defaults");
418 IDirectMusicSynth_Close(dmsynth);
419 /* Requesting more than supported */
420 params.dwValidParams = DMUS_PORTPARAMS_SAMPLERATE;
421 params.dwSampleRate = 100003;
422 hr = IDirectMusicSynth_Open(dmsynth, &params);
423 ok(hr == S_FALSE, "Open failed: %#lx\n", hr);
424 ok(params.dwValidParams == all_params, "dwValidParams: %#lx\n", params.dwValidParams);
425 ok(params.dwSampleRate == 96000, "dwSampleRate: %ld\n", params.dwSampleRate);
426 test_synth_getformat(dmsynth, &params, "max");
427 IDirectMusicSynth_Close(dmsynth);
428 /* Minimums */
429 params.dwValidParams = DMUS_PORTPARAMS_VOICES|DMUS_PORTPARAMS_CHANNELGROUPS|DMUS_PORTPARAMS_AUDIOCHANNELS|
430 DMUS_PORTPARAMS_SAMPLERATE;
431 params.dwVoices = 1;
432 params.dwChannelGroups = 1;
433 params.dwAudioChannels = 1;
434 params.dwSampleRate = 1;
435 hr = IDirectMusicSynth_Open(dmsynth, &params);
436 ok(hr == S_FALSE, "Open failed: %#lx\n", hr);
437 ok(params.dwValidParams == all_params, "dwValidParams: %#lx\n", params.dwValidParams);
438 ok(params.dwVoices == 1, "dwVoices: %ld\n", params.dwVoices);
439 ok(params.dwChannelGroups == 1, "dwChannelGroups: %ld\n", params.dwChannelGroups);
440 ok(params.dwAudioChannels == 1, "dwAudioChannels: %ld\n", params.dwAudioChannels);
441 ok(params.dwSampleRate == 11025, "dwSampleRate: %ld\n", params.dwSampleRate);
442 test_synth_getformat(dmsynth, &params, "min");
443 IDirectMusicSynth_Close(dmsynth);
444 /* Test share and features */
445 params.dwValidParams = DMUS_PORTPARAMS_SHARE|DMUS_PORTPARAMS_FEATURES;
446 params.fShare = TRUE;
447 params.dwFeatures = DMUS_PORT_FEATURE_AUDIOPATH|DMUS_PORT_FEATURE_STREAMING;
448 hr = IDirectMusicSynth_Open(dmsynth, &params);
449 ok(hr == S_FALSE, "Open failed: %#lx\n", hr);
450 ok(params.dwValidParams == all_params, "dwValidParams: %#lx\n", params.dwValidParams);
451 ok(params.fShare == FALSE, "fShare: %d\n", params.fShare);
452 ok(params.dwFeatures == (DMUS_PORT_FEATURE_AUDIOPATH|DMUS_PORT_FEATURE_STREAMING),
453 "dwFeatures: %#lx\n", params.dwFeatures);
454 test_synth_getformat(dmsynth, &params, "features");
455 IDirectMusicSynth_Close(dmsynth);
457 /* Synth has no default clock */
458 hr = IDirectMusicSynth_GetLatencyClock(dmsynth, &clock_synth);
459 ok(hr == DMUS_E_NOSYNTHSINK, "IDirectMusicSynth_GetLatencyClock returned: %#lx\n", hr);
461 /* SynthSink has a default clock */
462 hr = IDirectMusicSynthSink_GetLatencyClock(dmsynth_sink, &clock_sink);
463 ok(hr == S_OK, "IDirectMusicSynth_GetLatencyClock returned: %#lx\n", hr);
464 ok(clock_sink != NULL, "No clock returned\n");
465 ref_clock_sink = get_refcount(clock_sink);
467 /* This will Init() the SynthSink and finish initializing the Synth */
468 hr = IDirectMusicSynthSink_Init(dmsynth_sink2, NULL);
469 ok(hr == S_OK, "IDirectMusicSynthSink_Init returned: %#lx\n", hr);
470 hr = IDirectMusicSynth_SetSynthSink(dmsynth, dmsynth_sink2);
471 ok(hr == S_OK, "IDirectMusicSynth_SetSynthSink returned: %#lx\n", hr);
472 hr = IDirectMusicSynth_SetSynthSink(dmsynth, dmsynth_sink);
473 ok(hr == S_OK, "IDirectMusicSynth_SetSynthSink returned: %#lx\n", hr);
475 /* Check clocks are the same */
476 hr = IDirectMusicSynth_GetLatencyClock(dmsynth, &clock_synth);
477 ok(hr == S_OK, "IDirectMusicSynth_GetLatencyClock returned: %#lx\n", hr);
478 ok(clock_synth != NULL, "No clock returned\n");
479 ok(clock_synth == clock_sink, "Synth and SynthSink clocks are not the same\n");
480 ref_clock_synth = get_refcount(clock_synth);
481 ok(ref_clock_synth > ref_clock_sink + 1, "Latency clock refcount didn't increase\n");
483 /* GetPortCaps */
484 hr = IDirectMusicSynth_GetPortCaps(dmsynth, NULL);
485 ok(hr == E_INVALIDARG, "GetPortCaps failed: %#lx\n", hr);
486 memset(&caps, 0, sizeof(caps));
487 hr = IDirectMusicSynth_GetPortCaps(dmsynth, &caps);
488 ok(hr == E_INVALIDARG, "GetPortCaps failed: %#lx\n", hr);
489 caps.dwSize = sizeof(caps) + 1;
490 hr = IDirectMusicSynth_GetPortCaps(dmsynth, &caps);
491 ok(hr == S_OK, "GetPortCaps failed: %#lx\n", hr);
493 /* GetFormat */
494 hr = IDirectMusicSynth_GetFormat(dmsynth, NULL, NULL);
495 ok(hr == E_POINTER, "GetFormat failed: %#lx\n", hr);
496 hr = IDirectMusicSynth_GetFormat(dmsynth, NULL, &size);
497 ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "GetFormat failed: %#lx\n", hr);
498 hr = IDirectMusicSynth_Open(dmsynth, NULL);
499 ok(hr == S_OK, "Open failed: %#lx\n", hr);
500 hr = IDirectMusicSynth_GetFormat(dmsynth, NULL, &size);
501 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
502 ok(size == sizeof(format), "GetFormat size mismatch, got %ld\n", size);
503 size = 1;
504 hr = IDirectMusicSynth_GetFormat(dmsynth, &format, &size);
505 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
506 ok(size == sizeof(format), "GetFormat size mismatch, got %ld\n", size);
507 size = sizeof(format) + 1;
508 hr = IDirectMusicSynth_GetFormat(dmsynth, &format, &size);
509 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
510 ok(size == sizeof(format), "GetFormat size mismatch, got %ld\n", size);
511 IDirectMusicSynth_Close(dmsynth);
513 /* GetDesiredBufferSize */
514 hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, NULL);
515 ok(hr == E_POINTER, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr);
516 hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, &size);
517 ok(hr == E_UNEXPECTED, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr);
518 params.dwValidParams = 0;
519 hr = IDirectMusicSynth_Open(dmsynth, &params);
520 ok(hr == S_OK, "Open failed: %#lx\n", hr);
521 hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, &size);
522 ok(hr == S_OK, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr);
523 ok(size == params.dwSampleRate * params.dwAudioChannels * 4, "size: %ld\n", size);
524 IDirectMusicSynth_Close(dmsynth);
525 params.dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS;
526 params.dwAudioChannels = 1;
527 hr = IDirectMusicSynth_Open(dmsynth, &params);
528 ok(hr == S_OK, "Open failed: %#lx\n", hr);
529 hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, &size);
530 ok(hr == S_OK, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr);
531 ok(size == params.dwSampleRate * params.dwAudioChannels * 4, "size: %ld\n", size);
532 IDirectMusicSynth_Close(dmsynth);
534 if (control_synth)
535 IDirectMusicSynth_Release(control_synth);
536 if (control_sink)
537 IDirectMusicSynth_Release(control_sink);
538 if (clock_synth)
539 IReferenceClock_Release(clock_synth);
540 if (clock_sink)
541 IReferenceClock_Release(clock_sink);
542 if (dmsynth_sink)
543 IDirectMusicSynthSink_Release(dmsynth_sink);
544 if (dmsynth_sink2)
545 IDirectMusicSynthSink_Release(dmsynth_sink2);
546 IDirectMusicSynth_Release(dmsynth);
549 static void test_COM(void)
551 IDirectMusicSynth8 *dms8 = (IDirectMusicSynth8*)0xdeadbeef;
552 HRESULT hr;
554 /* COM aggregation */
555 hr = CoCreateInstance(&CLSID_DirectMusicSynth, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
556 &IID_IUnknown, (void**)&dms8);
557 ok(hr == CLASS_E_NOAGGREGATION,
558 "DirectMusicSynth create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
559 ok(!dms8, "dms8 = %p\n", dms8);
561 /* Invalid RIID */
562 hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER,
563 &IID_IDirectMusicObject, (void**)&dms8);
564 ok(hr == E_NOINTERFACE, "DirectMusicSynth create failed: %#lx, expected E_NOINTERFACE\n", hr);
566 hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER,
567 &IID_IDirectMusicSynth8, (void**)&dms8);
568 ok(hr == S_OK, "DirectMusicSynth create failed: %#lx, expected S_OK\n", hr);
570 check_interface(dms8, &IID_IUnknown, TRUE);
571 check_interface(dms8, &IID_IKsControl, TRUE);
573 /* Unsupported interfaces */
574 check_interface(dms8, &IID_IDirectMusicSynthSink, FALSE);
575 check_interface(dms8, &IID_IReferenceClock, FALSE);
577 IDirectMusicSynth8_Release(dms8);
580 static void test_COM_synthsink(void)
582 IDirectMusicSynthSink *dmss = (IDirectMusicSynthSink*)0xdeadbeef;
583 HRESULT hr;
585 /* COM aggregation */
586 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
587 &IID_IUnknown, (void**)&dmss);
588 ok(hr == CLASS_E_NOAGGREGATION,
589 "DirectMusicSynthSink create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
590 ok(!dmss, "dmss = %p\n", dmss);
592 /* Invalid RIID */
593 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER,
594 &IID_IDirectMusicObject, (void**)&dmss);
595 ok(hr == E_NOINTERFACE, "DirectMusicSynthSink create failed: %#lx, expected E_NOINTERFACE\n", hr);
597 /* Same refcount for all DirectMusicSynthSink interfaces */
598 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER,
599 &IID_IDirectMusicSynthSink, (void**)&dmss);
600 ok(hr == S_OK, "DirectMusicSynthSink create failed: %#lx, expected S_OK\n", hr);
602 check_interface(dmss, &IID_IUnknown, TRUE);
603 check_interface(dmss, &IID_IKsControl, TRUE);
605 /* Unsupported interfaces */
606 check_interface(dmss, &IID_IReferenceClock, FALSE);
608 IDirectMusicSynthSink_Release(dmss);
611 struct test_sink
613 IDirectMusicSynthSink IDirectMusicSynthSink_iface;
614 IReferenceClock IReferenceClock_iface;
615 LONG refcount;
617 IReferenceClock *clock;
618 IDirectMusicSynth *synth;
619 REFERENCE_TIME activate_time;
620 REFERENCE_TIME latency_time;
621 DWORD written;
624 static HRESULT WINAPI test_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface)
626 ok(0, "unexpected %s\n", __func__);
627 return S_OK;
630 static ULONG WINAPI test_sink_AddRef(IDirectMusicSynthSink *iface)
632 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
633 return InterlockedIncrement(&sink->refcount);
636 static ULONG WINAPI test_sink_Release(IDirectMusicSynthSink *iface)
638 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
639 ULONG ref = InterlockedDecrement(&sink->refcount);
640 if (!ref) free(sink);
641 return ref;
644 static HRESULT WINAPI test_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth)
646 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
647 sink->synth = synth;
648 return S_OK;
651 static HRESULT WINAPI test_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock)
653 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
654 if (sink->clock)
655 IReferenceClock_Release(sink->clock);
656 if ((sink->clock = clock))
657 IReferenceClock_AddRef(sink->clock);
658 return S_OK;
661 static HRESULT WINAPI test_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock)
663 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
664 *clock = &sink->IReferenceClock_iface;
665 IReferenceClock_AddRef(*clock);
666 return S_OK;
669 static HRESULT WINAPI test_sink_Activate(IDirectMusicSynthSink *iface, BOOL enable)
671 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
673 if (!sink->clock)
674 return DMUS_E_NO_MASTER_CLOCK;
676 IReferenceClock_GetTime(sink->clock, &sink->activate_time);
677 sink->latency_time = sink->activate_time;
678 return S_OK;
681 static HRESULT WINAPI test_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample, REFERENCE_TIME *time)
683 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
684 WAVEFORMATEX format;
685 DWORD format_size = sizeof(format);
686 HRESULT hr;
688 hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
689 ok(hr == S_OK, "got %#lx\n", hr);
691 *time = sink->activate_time + ((sample * 10000) / format.nSamplesPerSec) * 1000;
692 return S_OK;
695 static HRESULT WINAPI test_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME time, LONGLONG *sample)
697 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
698 WAVEFORMATEX format;
699 DWORD format_size = sizeof(format);
700 HRESULT hr;
702 hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
703 ok(hr == S_OK, "got %#lx\n", hr);
705 *sample = (((time - sink->activate_time) / 1000) * format.nSamplesPerSec) / 10000;
706 return S_OK;
709 static HRESULT WINAPI test_sink_SetDirectSound(IDirectMusicSynthSink *iface, IDirectSound *dsound,
710 IDirectSoundBuffer *dsound_buffer)
712 ok(0, "unexpected %s\n", __func__);
713 return S_OK;
716 static HRESULT WINAPI test_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, DWORD *size)
718 ok(0, "unexpected %s\n", __func__);
719 return S_OK;
722 static const IDirectMusicSynthSinkVtbl test_sink_vtbl =
724 test_sink_QueryInterface,
725 test_sink_AddRef,
726 test_sink_Release,
727 test_sink_Init,
728 test_sink_SetMasterClock,
729 test_sink_GetLatencyClock,
730 test_sink_Activate,
731 test_sink_SampleToRefTime,
732 test_sink_RefTimeToSample,
733 test_sink_SetDirectSound,
734 test_sink_GetDesiredBufferSize,
737 static HRESULT WINAPI test_sink_latency_clock_QueryInterface(IReferenceClock *iface, REFIID iid, void **out)
739 ok(0, "unexpected %s\n", __func__);
740 return E_NOINTERFACE;
743 static ULONG WINAPI test_sink_latency_clock_AddRef(IReferenceClock *iface)
745 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
746 return IDirectMusicSynthSink_AddRef(&sink->IDirectMusicSynthSink_iface);
749 static ULONG WINAPI test_sink_latency_clock_Release(IReferenceClock *iface)
751 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
752 return IDirectMusicSynthSink_Release(&sink->IDirectMusicSynthSink_iface);
755 static HRESULT WINAPI test_sink_latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TIME *time)
757 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
758 *time = sink->latency_time;
759 return S_OK;
762 static HRESULT WINAPI test_sink_latency_clock_AdviseTime(IReferenceClock *iface,
763 REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie)
765 ok(0, "unexpected %s\n", __func__);
766 return E_NOTIMPL;
769 static HRESULT WINAPI test_sink_latency_clock_AdvisePeriodic(IReferenceClock *iface,
770 REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie)
772 ok(0, "unexpected %s\n", __func__);
773 return E_NOTIMPL;
776 static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD cookie)
778 ok(0, "unexpected %s\n", __func__);
779 return E_NOTIMPL;
782 static const IReferenceClockVtbl test_sink_latency_clock_vtbl =
784 test_sink_latency_clock_QueryInterface,
785 test_sink_latency_clock_AddRef,
786 test_sink_latency_clock_Release,
787 test_sink_latency_clock_GetTime,
788 test_sink_latency_clock_AdviseTime,
789 test_sink_latency_clock_AdvisePeriodic,
790 test_sink_latency_clock_Unadvise,
793 static HRESULT test_sink_create(IDirectMusicSynthSink **out)
795 struct test_sink *sink;
797 *out = NULL;
798 if (!(sink = calloc(1, sizeof(*sink)))) return E_OUTOFMEMORY;
799 sink->IDirectMusicSynthSink_iface.lpVtbl = &test_sink_vtbl;
800 sink->IReferenceClock_iface.lpVtbl = &test_sink_latency_clock_vtbl;
801 sink->refcount = 1;
803 *out = &sink->IDirectMusicSynthSink_iface;
804 return S_OK;
807 static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD buffer_size, HANDLE output)
809 struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
810 DWORD written, format_size;
811 WAVEFORMATEX format;
812 HRESULT hr;
814 format_size = sizeof(format);
815 hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
816 ok(hr == S_OK, "got %#lx\n", hr);
818 memset(buffer, 0, buffer_size);
819 hr = IDirectMusicSynth_Render(sink->synth, buffer, buffer_size / format.nBlockAlign, sink->written / format.nBlockAlign);
820 ok(hr == S_OK, "got %#lx\n", hr);
821 sink->written += buffer_size;
823 hr = IDirectMusicSynthSink_SampleToRefTime(iface, sink->written / format.nBlockAlign, &sink->latency_time);
824 ok(hr == S_OK, "got %#lx\n", hr);
826 if (output)
828 BOOL ret = WriteFile(output, buffer, buffer_size, &written, NULL);
829 ok(!!ret, "WriteFile failed, error %lu.\n", GetLastError());
833 static void test_IDirectMusicSynth(void)
835 static const UINT RENDER_ITERATIONS = 8;
837 struct wave_download
839 DMUS_DOWNLOADINFO info;
840 ULONG offsets[2];
841 DMUS_WAVE wave;
842 union
844 DMUS_WAVEDATA wave_data;
845 struct
847 ULONG size;
848 BYTE samples[256];
851 } wave_download =
853 .info =
855 .dwDLType = DMUS_DOWNLOADINFO_WAVE,
856 .dwDLId = 1,
857 .dwNumOffsetTableEntries = 2,
858 .cbSize = sizeof(struct wave_download),
860 .offsets =
862 offsetof(struct wave_download, wave),
863 offsetof(struct wave_download, wave_data),
865 .wave =
867 .ulWaveDataIdx = 1,
868 .WaveformatEx =
870 .wFormatTag = WAVE_FORMAT_PCM,
871 .nChannels = 1,
872 .wBitsPerSample = 8,
873 .nSamplesPerSec = 44100,
874 .nAvgBytesPerSec = 44100,
875 .nBlockAlign = 1,
878 .wave_data =
880 .cbSize = sizeof(wave_download.samples),
883 struct instrument_download
885 DMUS_DOWNLOADINFO info;
886 ULONG offsets[4];
887 DMUS_INSTRUMENT instrument;
888 DMUS_REGION region;
889 DMUS_ARTICULATION articulation;
890 DMUS_ARTICPARAMS artic_params;
891 } instrument_download =
893 .info =
895 .dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT,
896 .dwDLId = 2,
897 .dwNumOffsetTableEntries = 4,
898 .cbSize = sizeof(struct instrument_download),
900 .offsets =
902 offsetof(struct instrument_download, instrument),
903 offsetof(struct instrument_download, region),
904 offsetof(struct instrument_download, articulation),
905 offsetof(struct instrument_download, artic_params),
907 .instrument =
909 .ulPatch = 0,
910 .ulFirstRegionIdx = 1,
911 .ulGlobalArtIdx = 2,
913 .region =
915 .RangeKey = {.usLow = 0, .usHigh = 127},
916 .RangeVelocity = {.usLow = 0, .usHigh = 127},
917 .fusOptions = F_RGN_OPTION_SELFNONEXCLUSIVE,
918 .WaveLink = {.ulChannel = 1, .ulTableIndex = 1},
919 .WSMP = {.cbSize = sizeof(WSMPL), .usUnityNote = 60, .fulOptions = F_WSMP_NO_TRUNCATION},
920 .WLOOP[0] = {.cbSize = sizeof(WLOOP), .ulType = WLOOP_TYPE_FORWARD},
922 .articulation = {.ulArt1Idx = 3},
923 .artic_params =
925 .VolEG = {.tcAttack = 32768u << 16, .tcDecay = 32768u << 16, .ptSustain = 10000 << 16, .tcRelease = 32768u << 16},
928 DMUS_BUFFERDESC buffer_desc =
930 .dwSize = sizeof(DMUS_BUFFERDESC),
931 .cbBuffer = 4096,
933 DMUS_PORTPARAMS port_params =
935 .dwSize = sizeof(DMUS_PORTPARAMS),
936 .dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS | DMUS_PORTPARAMS_SAMPLERATE,
937 .dwAudioChannels = 2,
938 .dwSampleRate = 44100,
940 WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH];
941 IReferenceClock *latency_clock;
942 IDirectMusicSynthSink *sink;
943 IDirectMusicBuffer *buffer;
944 DWORD format_size, written;
945 IDirectMusicSynth *synth;
946 HANDLE wave_file, handle;
947 IReferenceClock *clock;
948 BOOL can_free = FALSE;
949 REFERENCE_TIME time;
950 WAVEFORMATEX format;
951 IDirectMusic *music;
952 short samples[256];
953 ULONG i, ref;
954 HRESULT hr;
955 DWORD len;
956 BYTE *raw;
957 BOOL ret;
959 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER,
960 &IID_IDirectMusic, (void **)&music);
961 ok(hr == S_OK, "got %#lx\n", hr);
962 hr = IDirectMusic_GetMasterClock(music, NULL, &clock);
963 ok(hr == S_OK, "got %#lx\n", hr);
965 hr = test_sink_create(&sink);
966 ok(hr == S_OK, "got %#lx\n", hr);
969 hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER,
970 &IID_IDirectMusicSynth, (void **)&synth);
971 ok(hr == S_OK, "got %#lx\n", hr);
973 /* SetNumChannelGroups needs Open */
974 hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1);
975 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
976 /* GetFormat needs Open */
977 hr = IDirectMusicSynth_GetFormat(synth, NULL, NULL);
978 ok(hr == E_POINTER, "got %#lx\n", hr);
979 hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size);
980 ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
982 /* Open / Close don't need a sink */
983 hr = IDirectMusicSynth_Open(synth, NULL);
984 ok(hr == S_OK, "got %#lx\n", hr);
985 hr = IDirectMusicSynth_Open(synth, NULL);
986 ok(hr == DMUS_E_ALREADYOPEN, "got %#lx\n", hr);
987 hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1);
988 ok(hr == S_OK, "got %#lx\n", hr);
989 format_size = sizeof(format);
990 hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size);
991 ok(hr == S_OK, "got %#lx\n", hr);
992 ok(format_size == sizeof(format), "got %lu\n", format_size);
993 hr = IDirectMusicSynth_Close(synth);
994 ok(hr == S_OK, "got %#lx\n", hr);
995 hr = IDirectMusicSynth_Close(synth);
996 ok(hr == DMUS_E_ALREADYCLOSED, "got %#lx\n", hr);
998 /* GetLatencyClock needs a sink */
999 hr = IDirectMusicSynth_GetLatencyClock(synth, NULL);
1000 ok(hr == E_POINTER, "got %#lx\n", hr);
1001 hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock);
1002 ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr);
1004 /* Activate needs a sink, synth to be open, and a master clock on the sink */
1005 hr = IDirectMusicSynth_Open(synth, NULL);
1006 ok(hr == S_OK, "got %#lx\n", hr);
1007 hr = IDirectMusicSynth_Activate(synth, TRUE);
1008 ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr);
1009 hr = IDirectMusicSynth_Activate(synth, FALSE);
1010 todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
1012 hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
1013 ok(hr == S_OK, "got %#lx\n", hr);
1014 hr = IDirectMusicSynth_SetSynthSink(synth, sink);
1015 ok(hr == S_OK, "got %#lx\n", hr);
1016 ref = get_refcount(sink);
1017 todo_wine ok(ref == 2, "got %lu\n", ref);
1018 hr = IDirectMusicSynth_Activate(synth, TRUE);
1019 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1021 /* SetMasterClock does nothing */
1022 hr = IDirectMusicSynth_SetMasterClock(synth, NULL);
1023 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
1024 hr = IDirectMusicSynth_SetMasterClock(synth, clock);
1025 ok(hr == S_OK, "got %#lx\n", hr);
1026 ref = get_refcount(clock);
1027 todo_wine ok(ref == 1, "got %lu\n", ref);
1028 hr = IDirectMusicSynth_Activate(synth, TRUE);
1029 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1031 /* SetMasterClock needs to be called on the sink */
1032 hr = IDirectMusicSynthSink_SetMasterClock(sink, clock);
1033 ok(hr == S_OK, "got %#lx\n", hr);
1034 hr = IDirectMusicSynth_Activate(synth, TRUE);
1035 todo_wine ok(hr == S_OK, "got %#lx\n", hr);
1036 hr = IDirectMusicSynth_Activate(synth, TRUE);
1037 todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
1039 /* Close is fine while active */
1040 hr = IDirectMusicSynth_Close(synth);
1041 ok(hr == S_OK, "got %#lx\n", hr);
1042 /* Removing the sink is fine while active */
1043 hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
1044 ok(hr == S_OK, "got %#lx\n", hr);
1045 ref = get_refcount(sink);
1046 ok(ref == 1, "got %lu\n", ref);
1048 /* but Activate might fail then */
1049 hr = IDirectMusicSynth_Activate(synth, FALSE);
1050 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1051 hr = IDirectMusicSynth_Activate(synth, FALSE);
1052 todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
1055 /* Test generating some samples */
1056 hr = IDirectMusicSynth_Open(synth, &port_params);
1057 ok(hr == S_OK, "got %#lx\n", hr);
1059 format_size = sizeof(format);
1060 hr = IDirectMusicSynth_GetFormat(synth, &format, &format_size);
1061 ok(hr == S_OK, "got %#lx\n", hr);
1062 hr = IDirectMusicSynth_SetSynthSink(synth, sink);
1063 ok(hr == S_OK, "got %#lx\n", hr);
1064 ref = get_refcount(sink);
1065 todo_wine ok(ref == 2, "got %lu\n", ref);
1066 hr = IDirectMusicSynth_Activate(synth, TRUE);
1067 todo_wine ok(hr == S_OK, "got %#lx\n", hr);
1069 GetTempPathW(MAX_PATH, temp_path);
1070 GetTempFileNameW(temp_path, L"synth", 0, temp_file);
1071 wave_file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1072 ok(wave_file != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu.\n", GetLastError());
1073 ret = WriteFile(wave_file, "RIFF", 4, &written, NULL);
1074 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1075 format_size = (RENDER_ITERATIONS + 1) * sizeof(samples) + sizeof(format) + 20;
1076 ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
1077 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1078 ret = WriteFile(wave_file, "WAVEfmt ", 8, &written, NULL);
1079 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1080 format_size = sizeof(format);
1081 ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
1082 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1083 ret = WriteFile(wave_file, &format, format_size, &written, NULL);
1084 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1085 ret = WriteFile(wave_file, "data", 4, &written, NULL);
1086 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1087 format_size = (RENDER_ITERATIONS + 1) * sizeof(samples);
1088 ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
1089 ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
1091 /* native needs to render at least once before producing samples */
1092 test_sink_render(sink, samples, sizeof(samples), wave_file);
1094 for (i = 0; i < ARRAY_SIZE(wave_download.samples); i++)
1095 wave_download.samples[i] = i;
1097 can_free = 0xdeadbeef;
1098 handle = (HANDLE)0xdeadbeef;
1099 hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free);
1100 ok(hr == S_OK, "got %#lx\n", hr);
1101 ok(handle != 0, "got %p\n", handle);
1102 todo_wine ok(can_free == FALSE, "got %u\n", can_free);
1104 can_free = 0xdeadbeef;
1105 handle = (HANDLE)0xdeadbeef;
1106 hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free);
1107 ok(hr == S_OK, "got %#lx\n", hr);
1108 ok(handle != 0, "got %p\n", handle);
1109 todo_wine ok(can_free == TRUE, "got %u\n", can_free);
1111 /* add a MIDI note to a buffer and play it */
1112 hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock);
1113 ok(hr == S_OK, "got %#lx\n", hr);
1114 hr = IDirectMusic_CreateMusicBuffer(music, &buffer_desc, &buffer, NULL);
1115 ok(hr == S_OK, "got %#lx\n", hr);
1116 /* status = 0x90 (NOTEON / channel 0), key = 0x27 (39), vel = 0x78 (120) */
1117 hr = IDirectMusicBuffer_PackStructured(buffer, 0, 1, 0x782790);
1118 ok(hr == S_OK, "got %#lx\n", hr);
1119 hr = IReferenceClock_GetTime(latency_clock, &time);
1120 ok(hr == S_OK, "got %#lx\n", hr);
1121 hr = IDirectMusicBuffer_GetRawBufferPtr(buffer, (BYTE **)&raw);
1122 ok(hr == S_OK, "got %#lx\n", hr);
1123 hr = IDirectMusicBuffer_GetUsedBytes(buffer, &len);
1124 ok(hr == S_OK, "got %#lx\n", hr);
1125 hr = IDirectMusicSynth_PlayBuffer(synth, time, (BYTE *)raw, len);
1126 ok(hr == S_OK, "got %#lx\n", hr);
1127 IDirectMusicBuffer_Release(buffer);
1128 IReferenceClock_Release(latency_clock);
1130 for (i = 0; i < RENDER_ITERATIONS; i++)
1131 test_sink_render(sink, samples, sizeof(samples), wave_file);
1133 CloseHandle(wave_file);
1134 trace("Rendered samples to %s\n", debugstr_w(temp_file));
1136 hr = IDirectMusicSynth_Activate(synth, FALSE);
1137 ok(hr == S_OK, "got %#lx\n", hr);
1138 hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
1139 ok(hr == S_OK, "got %#lx\n", hr);
1140 ref = get_refcount(sink);
1141 ok(ref == 1, "got %lu\n", ref);
1142 hr = IDirectMusicSynth_Close(synth);
1143 ok(hr == S_OK, "got %#lx\n", hr);
1145 IDirectMusicSynth_Release(synth);
1148 if (strcmp(winetest_platform, "wine")) IDirectMusicSynthSink_Release(sink);
1149 IReferenceClock_Release(clock);
1150 IDirectMusic_Release(music);
1153 static void test_IDirectMusicSynthSink(void)
1155 IReferenceClock *latency_clock;
1156 REFERENCE_TIME time, tmp_time;
1157 IDirectMusicSynthSink *sink;
1158 IDirectMusicSynth8 *synth;
1159 IReferenceClock *clock;
1160 IDirectSound *dsound;
1161 IDirectMusic *music;
1162 LONGLONG sample;
1163 HRESULT hr;
1164 DWORD size;
1165 ULONG ref;
1167 hr = DirectSoundCreate(NULL, &dsound, NULL);
1168 ok(hr == S_OK || broken(hr == DSERR_NODRIVER), "got %#lx\n", hr);
1169 if (broken(hr == DSERR_NODRIVER))
1171 win_skip("Failed to create IDirectSound, skipping tests");
1172 return;
1175 hr = IDirectSound_SetCooperativeLevel(dsound, GetDesktopWindow(), DSSCL_PRIORITY);
1176 ok(hr == S_OK, "got %#lx\n", hr);
1178 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER,
1179 &IID_IDirectMusic, (void **)&music);
1180 ok(hr == S_OK, "got %#lx\n", hr);
1181 hr = IDirectMusic_GetMasterClock(music, NULL, &clock);
1182 ok(hr == S_OK, "got %#lx\n", hr);
1183 IDirectMusic_Release(music);
1185 hr = test_synth_create(&synth);
1186 ok(hr == S_OK, "got %#lx\n", hr);
1189 hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER,
1190 &IID_IDirectMusicSynthSink, (void **)&sink);
1191 ok(hr == S_OK, "got %#lx\n", hr);
1193 /* sink is not configured */
1194 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1195 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1196 hr = IDirectMusicSynthSink_Activate(sink, FALSE);
1197 ok(hr == S_OK, "got %#lx\n", hr);
1199 hr = IDirectMusicSynthSink_SampleToRefTime(sink, 0, NULL);
1200 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
1201 time = 0xdeadbeef;
1202 hr = IDirectMusicSynthSink_SampleToRefTime(sink, 10, &time);
1203 ok(hr == S_OK, "got %#lx\n", hr);
1204 todo_wine ok(time == 4000, "got %I64d\n", time);
1206 hr = IDirectMusicSynthSink_RefTimeToSample(sink, 0, NULL);
1207 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
1208 sample = 0xdeadbeef;
1209 hr = IDirectMusicSynthSink_RefTimeToSample(sink, 4000, &sample);
1210 ok(hr == S_OK, "got %#lx\n", hr);
1211 todo_wine ok(sample == 8, "got %I64d\n", sample);
1213 hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size);
1214 ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1216 /* latency clock is available but not usable */
1217 hr = IDirectMusicSynthSink_GetLatencyClock(sink, NULL);
1218 ok(hr == E_POINTER, "got %#lx\n", hr);
1219 ref = get_refcount(sink);
1220 ok(ref == 1, "got %#lx\n", ref);
1221 hr = IDirectMusicSynthSink_GetLatencyClock(sink, &latency_clock);
1222 ok(hr == S_OK, "got %#lx\n", hr);
1223 ok(latency_clock != clock, "got same clock\n");
1224 ref = get_refcount(sink);
1225 todo_wine ok(ref == 2, "got %#lx\n", ref);
1227 hr = IReferenceClock_GetTime(latency_clock, NULL);
1228 todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr);
1229 hr = IReferenceClock_GetTime(latency_clock, &time);
1230 todo_wine ok(hr == E_FAIL, "got %#lx\n", hr);
1232 hr = IDirectMusicSynthSink_Init(sink, NULL);
1233 ok(hr == S_OK, "got %#lx\n", hr);
1234 hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL);
1235 ok(hr == S_OK, "got %#lx\n", hr);
1236 hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL);
1237 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1239 /* Activate requires a synth, dsound and a clock */
1240 ref = get_refcount(synth);
1241 ok(ref == 1, "got %#lx\n", ref);
1242 hr = IDirectMusicSynthSink_Init(sink, (IDirectMusicSynth *)synth);
1243 ok(hr == S_OK, "got %#lx\n", hr);
1244 ref = get_refcount(synth);
1245 ok(ref == 1, "got %#lx\n", ref);
1246 hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size);
1247 ok(hr == S_OK, "got %#lx\n", hr);
1248 ok(size == 352800, "got %lu\n", size);
1249 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1250 todo_wine ok(hr == DMUS_E_DSOUND_NOT_SET, "got %#lx\n", hr);
1251 hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL);
1252 ok(hr == S_OK, "got %#lx\n", hr);
1253 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1254 todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
1255 hr = IDirectMusicSynthSink_SetMasterClock(sink, clock);
1256 ok(hr == S_OK, "got %#lx\n", hr);
1257 hr = IReferenceClock_GetTime(latency_clock, &time);
1258 todo_wine ok(hr == E_FAIL, "got %#lx\n", hr);
1259 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1260 ok(hr == S_OK, "got %#lx\n", hr);
1261 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1262 todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr);
1263 ref = get_refcount(synth);
1264 ok(ref == 1, "got %#lx\n", ref);
1266 hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size);
1267 ok(hr == S_OK, "got %#lx\n", hr);
1268 ok(size == 352800, "got %lu\n", size);
1270 /* conversion functions now use the activation time and master clock */
1271 hr = IReferenceClock_GetTime(clock, &time);
1272 ok(hr == S_OK, "got %#lx\n", hr);
1273 sample = 0xdeadbeef;
1274 hr = IDirectMusicSynthSink_RefTimeToSample(sink, time, &sample);
1275 ok(hr == S_OK, "got %#lx\n", hr);
1276 todo_wine ok(sample <= 3000, "got %I64d\n", sample);
1277 tmp_time = time + 1;
1278 hr = IDirectMusicSynthSink_SampleToRefTime(sink, sample, &tmp_time);
1279 ok(hr == S_OK, "got %#lx\n", hr);
1280 todo_wine ok(tmp_time <= time, "got %I64d\n", tmp_time - time);
1281 ok(time - tmp_time <= 5000, "got %I64d\n", time - tmp_time);
1283 /* latency clock now works fine */
1284 tmp_time = time;
1285 hr = IReferenceClock_GetTime(latency_clock, &tmp_time);
1286 todo_wine_if(hr == S_FALSE) ok(hr == S_OK, "got %#lx\n", hr);
1287 todo_wine_if(tmp_time <= time) ok(tmp_time > time, "got %I64d\n", tmp_time - time);
1288 ok(tmp_time - time <= 2000000, "got %I64d\n", tmp_time - time);
1290 /* setting the clock while active is fine */
1291 hr = IDirectMusicSynthSink_SetMasterClock(sink, clock);
1292 ok(hr == S_OK, "got %#lx\n", hr);
1294 /* removing synth while active is fine */
1295 hr = IDirectMusicSynthSink_Init(sink, NULL);
1296 ok(hr == S_OK, "got %#lx\n", hr);
1297 ref = get_refcount(synth);
1298 ok(ref == 1, "got %#lx\n", ref);
1299 hr = IDirectMusicSynthSink_Activate(sink, TRUE);
1300 todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
1302 /* changing dsound while active fails */
1303 hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL);
1304 todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr);
1305 hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL);
1306 todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr);
1307 hr = IDirectMusicSynthSink_Activate(sink, FALSE);
1308 ok(hr == S_OK, "got %#lx\n", hr);
1309 hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL);
1310 ok(hr == S_OK, "got %#lx\n", hr);
1312 /* SetMasterClock doesn't need the sink to be configured */
1313 hr = IDirectMusicSynthSink_SetMasterClock(sink, NULL);
1314 ok(hr == E_POINTER, "got %#lx\n", hr);
1315 hr = IDirectMusicSynthSink_SetMasterClock(sink, clock);
1316 ok(hr == S_OK, "got %#lx\n", hr);
1318 IReferenceClock_Release(latency_clock);
1319 IDirectMusicSynthSink_Release(sink);
1322 IDirectMusicSynth8_Release(synth);
1323 IReferenceClock_Release(clock);
1325 IDirectSound_Release(dsound);
1328 START_TEST(dmsynth)
1330 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1332 if (missing_dmsynth())
1334 skip("dmsynth not available\n");
1335 CoUninitialize();
1336 return;
1338 test_dmsynth();
1339 test_COM();
1340 test_COM_synthsink();
1341 test_IDirectMusicSynth();
1342 test_IDirectMusicSynthSink();
1344 CoUninitialize();