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
25 #include "wine/test.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
);
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
;
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
);
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
);
77 IDirectMusicSynth8 IDirectMusicSynth8_iface
;
81 static HRESULT WINAPI
test_synth_QueryInterface(IDirectMusicSynth8
*iface
, REFIID riid
, void **ret_iface
)
83 ok(0, "unexpected %s\n", __func__
);
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
);
101 static HRESULT WINAPI
test_synth_Open(IDirectMusicSynth8
*iface
, DMUS_PORTPARAMS
*params
)
103 ok(0, "unexpected %s\n", __func__
);
107 static HRESULT WINAPI
test_synth_Close(IDirectMusicSynth8
*iface
)
109 ok(0, "unexpected %s\n", __func__
);
113 static HRESULT WINAPI
test_synth_SetNumChannelGroups(IDirectMusicSynth8
*iface
, DWORD groups
)
115 ok(0, "unexpected %s\n", __func__
);
119 static HRESULT WINAPI
test_synth_Download(IDirectMusicSynth8
*iface
, HANDLE
*handle
, void *data
, BOOL
*can_free
)
121 ok(0, "unexpected %s\n", __func__
);
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__
);
132 static HRESULT WINAPI
test_synth_PlayBuffer(IDirectMusicSynth8
*iface
, REFERENCE_TIME time
, BYTE
*buffer
, DWORD size
)
134 ok(0, "unexpected %s\n", __func__
);
138 static HRESULT WINAPI
test_synth_GetRunningStats(IDirectMusicSynth8
*iface
, DMUS_SYNTHSTATS
*stats
)
140 ok(0, "unexpected %s\n", __func__
);
144 static HRESULT WINAPI
test_synth_GetPortCaps(IDirectMusicSynth8
*iface
, DMUS_PORTCAPS
*caps
)
146 ok(0, "unexpected %s\n", __func__
);
150 static HRESULT WINAPI
test_synth_SetMasterClock(IDirectMusicSynth8
*iface
, IReferenceClock
*clock
)
152 ok(0, "unexpected %s\n", __func__
);
156 static HRESULT WINAPI
test_synth_GetLatencyClock(IDirectMusicSynth8
*iface
, IReferenceClock
**clock
)
158 ok(0, "unexpected %s\n", __func__
);
162 static HRESULT WINAPI
test_synth_Activate(IDirectMusicSynth8
*iface
, BOOL enable
)
164 ok(0, "unexpected %s\n", __func__
);
168 static HRESULT WINAPI
test_synth_SetSynthSink(IDirectMusicSynth8
*iface
, IDirectMusicSynthSink
*sink
)
170 ok(0, "unexpected %s\n", __func__
);
174 static HRESULT WINAPI
test_synth_Render(IDirectMusicSynth8
*iface
, short *buffer
, DWORD length
, LONGLONG position
)
179 static HRESULT WINAPI
test_synth_SetChannelPriority(IDirectMusicSynth8
*iface
, DWORD group
, DWORD channel
, DWORD priority
)
181 ok(0, "unexpected %s\n", __func__
);
185 static HRESULT WINAPI
test_synth_GetChannelPriority(IDirectMusicSynth8
*iface
, DWORD group
, DWORD channel
, DWORD
*priority
)
187 ok(0, "unexpected %s\n", __func__
);
191 static HRESULT WINAPI
test_synth_GetFormat(IDirectMusicSynth8
*iface
, WAVEFORMATEX
*format
, DWORD
*ext_size
)
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
;
204 static HRESULT WINAPI
test_synth_GetAppend(IDirectMusicSynth8
*iface
, DWORD
*append
)
206 ok(0, "unexpected %s\n", __func__
);
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__
);
218 static HRESULT WINAPI
test_synth_StopVoice(IDirectMusicSynth8
*iface
, REFERENCE_TIME rt
, DWORD voice_id
)
220 ok(0, "unexpected %s\n", __func__
);
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__
);
231 static HRESULT WINAPI
test_synth_Refresh(IDirectMusicSynth8
*iface
, DWORD dlid
, DWORD flags
)
233 ok(0, "unexpected %s\n", __func__
);
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__
);
244 static const IDirectMusicSynth8Vtbl test_synth_vtbl
=
246 test_synth_QueryInterface
,
251 test_synth_SetNumChannelGroups
,
254 test_synth_PlayBuffer
,
255 test_synth_GetRunningStats
,
256 test_synth_GetPortCaps
,
257 test_synth_SetMasterClock
,
258 test_synth_GetLatencyClock
,
260 test_synth_SetSynthSink
,
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
,
270 test_synth_AssignChannelToBuses
,
273 static HRESULT
test_synth_create(IDirectMusicSynth8
**out
)
275 struct test_synth
*synth
;
278 if (!(synth
= calloc(1, sizeof(*synth
)))) return E_OUTOFMEMORY
;
279 synth
->IDirectMusicSynth8_iface
.lpVtbl
= &test_synth_vtbl
;
282 *out
= &synth
->IDirectMusicSynth8_iface
;
286 static void test_synth_getformat(IDirectMusicSynth
*synth
, DMUS_PORTPARAMS
*params
, const char *context
)
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",
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
;
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
;
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
);
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
);
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(¶ms
, 0, sizeof(params
));
397 hr
= IDirectMusicSynth_Open(dmsynth
, ¶ms
);
398 ok(hr
== E_INVALIDARG
, "Open failed: %#lx\n", hr
);
399 params
.dwSize
= sizeof(DMUS_PORTPARAMS7
);
400 hr
= IDirectMusicSynth_Open(dmsynth
, ¶ms
);
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
, ¶ms
);
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
, ¶ms
, "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
, ¶ms
);
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
, ¶ms
, "max");
427 IDirectMusicSynth_Close(dmsynth
);
429 params
.dwValidParams
= DMUS_PORTPARAMS_VOICES
|DMUS_PORTPARAMS_CHANNELGROUPS
|DMUS_PORTPARAMS_AUDIOCHANNELS
|
430 DMUS_PORTPARAMS_SAMPLERATE
;
432 params
.dwChannelGroups
= 1;
433 params
.dwAudioChannels
= 1;
434 params
.dwSampleRate
= 1;
435 hr
= IDirectMusicSynth_Open(dmsynth
, ¶ms
);
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
, ¶ms
, "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
, ¶ms
);
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
, ¶ms
, "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");
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
);
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
);
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
, ¶ms
);
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
, ¶ms
);
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
);
535 IDirectMusicSynth_Release(control_synth
);
537 IDirectMusicSynth_Release(control_sink
);
539 IReferenceClock_Release(clock_synth
);
541 IReferenceClock_Release(clock_sink
);
543 IDirectMusicSynthSink_Release(dmsynth_sink
);
545 IDirectMusicSynthSink_Release(dmsynth_sink2
);
546 IDirectMusicSynth_Release(dmsynth
);
549 static void test_COM(void)
551 IDirectMusicSynth8
*dms8
= (IDirectMusicSynth8
*)0xdeadbeef;
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
);
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;
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
);
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
);
613 IDirectMusicSynthSink IDirectMusicSynthSink_iface
;
614 IReferenceClock IReferenceClock_iface
;
617 IReferenceClock
*clock
;
618 IDirectMusicSynth
*synth
;
619 REFERENCE_TIME activate_time
;
620 REFERENCE_TIME latency_time
;
624 static HRESULT WINAPI
test_sink_QueryInterface(IDirectMusicSynthSink
*iface
, REFIID riid
, void **ret_iface
)
626 ok(0, "unexpected %s\n", __func__
);
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
);
644 static HRESULT WINAPI
test_sink_Init(IDirectMusicSynthSink
*iface
, IDirectMusicSynth
*synth
)
646 struct test_sink
*sink
= CONTAINING_RECORD(iface
, struct test_sink
, IDirectMusicSynthSink_iface
);
651 static HRESULT WINAPI
test_sink_SetMasterClock(IDirectMusicSynthSink
*iface
, IReferenceClock
*clock
)
653 struct test_sink
*sink
= CONTAINING_RECORD(iface
, struct test_sink
, IDirectMusicSynthSink_iface
);
655 IReferenceClock_Release(sink
->clock
);
656 if ((sink
->clock
= clock
))
657 IReferenceClock_AddRef(sink
->clock
);
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
);
669 static HRESULT WINAPI
test_sink_Activate(IDirectMusicSynthSink
*iface
, BOOL enable
)
671 struct test_sink
*sink
= CONTAINING_RECORD(iface
, struct test_sink
, IDirectMusicSynthSink_iface
);
674 return DMUS_E_NO_MASTER_CLOCK
;
676 IReferenceClock_GetTime(sink
->clock
, &sink
->activate_time
);
677 sink
->latency_time
= sink
->activate_time
;
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
);
685 DWORD format_size
= sizeof(format
);
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;
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
);
699 DWORD format_size
= sizeof(format
);
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;
709 static HRESULT WINAPI
test_sink_SetDirectSound(IDirectMusicSynthSink
*iface
, IDirectSound
*dsound
,
710 IDirectSoundBuffer
*dsound_buffer
)
712 ok(0, "unexpected %s\n", __func__
);
716 static HRESULT WINAPI
test_sink_GetDesiredBufferSize(IDirectMusicSynthSink
*iface
, DWORD
*size
)
718 ok(0, "unexpected %s\n", __func__
);
722 static const IDirectMusicSynthSinkVtbl test_sink_vtbl
=
724 test_sink_QueryInterface
,
728 test_sink_SetMasterClock
,
729 test_sink_GetLatencyClock
,
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
;
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__
);
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__
);
776 static HRESULT WINAPI
test_sink_latency_clock_Unadvise(IReferenceClock
*iface
, DWORD cookie
)
778 ok(0, "unexpected %s\n", __func__
);
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
;
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
;
803 *out
= &sink
->IDirectMusicSynthSink_iface
;
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
;
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
);
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;
839 DMUS_DOWNLOADINFO info
;
844 DMUS_WAVEDATA wave_data
;
855 .dwDLType
= DMUS_DOWNLOADINFO_WAVE
,
857 .dwNumOffsetTableEntries
= 2,
858 .cbSize
= sizeof(struct wave_download
),
862 offsetof(struct wave_download
, wave
),
863 offsetof(struct wave_download
, wave_data
),
870 .wFormatTag
= WAVE_FORMAT_PCM
,
873 .nSamplesPerSec
= 44100,
874 .nAvgBytesPerSec
= 44100,
880 .cbSize
= sizeof(wave_download
.samples
),
883 struct instrument_download
885 DMUS_DOWNLOADINFO info
;
887 DMUS_INSTRUMENT instrument
;
889 DMUS_ARTICULATION articulation
;
890 DMUS_ARTICPARAMS artic_params
;
891 } instrument_download
=
895 .dwDLType
= DMUS_DOWNLOADINFO_INSTRUMENT
,
897 .dwNumOffsetTableEntries
= 4,
898 .cbSize
= sizeof(struct instrument_download
),
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
),
910 .ulFirstRegionIdx
= 1,
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},
925 .VolEG
= {.tcAttack
= 32768u << 16, .tcDecay
= 32768u << 16, .ptSustain
= 10000 << 16, .tcRelease
= 32768u << 16},
928 DMUS_BUFFERDESC buffer_desc
=
930 .dwSize
= sizeof(DMUS_BUFFERDESC
),
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
;
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
;
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");
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
);
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 */
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
);
1330 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
1332 if (missing_dmsynth())
1334 skip("dmsynth not available\n");
1340 test_COM_synthsink();
1341 test_IDirectMusicSynth();
1342 test_IDirectMusicSynthSink();