dmime: Requeue the note message instead of directly queueing MIDI note-off.
[wine.git] / dlls / dmime / tests / dmime.c
blobb4b6d848fdc4481c955a5a9c784f05c0ceccebfd
1 /*
2 * Copyright 2012, 2014 Michael Stefaniuc
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <stdarg.h>
22 #include <math.h>
23 #include <windef.h>
24 #include <wine/test.h>
25 #include <initguid.h>
26 #include <ole2.h>
27 #include <dmusici.h>
28 #include <dmusicf.h>
29 #include <audioclient.h>
30 #include <guiddef.h>
32 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
33 DEFINE_GUID(GUID_Bunk,0xFFFFFFFF,0xFFFF,0xFFFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
35 static ULONG get_refcount(void *iface)
37 IUnknown *unknown = iface;
38 IUnknown_AddRef(unknown);
39 return IUnknown_Release(unknown);
42 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c, FALSE)
43 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported, BOOL check_refs)
45 ULONG expect_ref = get_refcount(iface_ptr);
46 IUnknown *iface = iface_ptr;
47 HRESULT hr, expected;
48 IUnknown *unk;
50 expected = supported ? S_OK : E_NOINTERFACE;
51 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
52 ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected);
53 if (SUCCEEDED(hr))
55 LONG ref = get_refcount(unk);
56 if (check_refs) ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref);
57 IUnknown_Release(unk);
58 ref = get_refcount(iface_ptr);
59 if (check_refs) ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref);
63 static double scale_music_time(MUSIC_TIME time, double tempo)
65 return (600000000.0 * time) / (tempo * 768.0);
68 #define check_dmus_note_pmsg(a, b, c, d, e, f, g) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f, g)
69 static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan,
70 UINT duration, UINT key, UINT vel, UINT flags)
72 ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
73 ok_(__FILE__, line)(!!msg->rtTime, "got rtTime %I64u\n", msg->rtTime);
74 ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
75 ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel);
76 ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
77 ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#lx\n", msg->dwType);
78 ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
79 ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID);
80 ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
81 ok_(__FILE__, line)(msg->mtDuration == duration, "got mtDuration %lu\n", msg->mtDuration);
82 ok_(__FILE__, line)(msg->wMusicValue == key, "got wMusicValue %u\n", msg->wMusicValue);
83 ok_(__FILE__, line)(!msg->wMeasure, "got wMeasure %u\n", msg->wMeasure);
84 /* FIXME: ok_(__FILE__, line)(!msg->nOffset, "got nOffset %u\n", msg->nOffset); */
85 /* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */
86 /* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */
87 ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity);
88 ok_(__FILE__, line)(msg->bFlags == flags, "got bFlags %#x\n", msg->bFlags);
89 ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange);
90 ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange);
91 ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange);
92 ok_(__FILE__, line)(!msg->bPlayModeFlags, "got bPlayModeFlags %#x\n", msg->bPlayModeFlags);
93 ok_(__FILE__, line)(!msg->bSubChordLevel, "got bSubChordLevel %u\n", msg->bSubChordLevel);
94 ok_(__FILE__, line)(msg->bMidiValue == key, "got bMidiValue %u\n", msg->bMidiValue);
95 ok_(__FILE__, line)(!msg->cTranspose, "got cTranspose %u\n", msg->cTranspose);
98 static void load_resource(const WCHAR *name, WCHAR *filename)
100 static WCHAR path[MAX_PATH];
101 DWORD written;
102 HANDLE file;
103 HRSRC res;
104 void *ptr;
106 GetTempPathW(ARRAY_SIZE(path), path);
107 GetTempFileNameW(path, name, 0, filename);
109 file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
110 ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError());
112 res = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA);
113 ok(res != 0, "couldn't find resource\n");
114 ptr = LockResource(LoadResource(GetModuleHandleW(NULL ), res ));
115 WriteFile(file, ptr, SizeofResource(GetModuleHandleW(NULL ), res ), &written, NULL);
116 ok(written == SizeofResource(GetModuleHandleW(NULL ), res ), "couldn't write resource\n");
117 CloseHandle(file);
120 static void stream_begin_chunk(IStream *stream, const char type[5], ULARGE_INTEGER *offset)
122 static const LARGE_INTEGER zero = {0};
123 HRESULT hr;
124 hr = IStream_Write(stream, type, 4, NULL);
125 ok(hr == S_OK, "got %#lx\n", hr);
126 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, offset);
127 ok(hr == S_OK, "got %#lx\n", hr);
128 hr = IStream_Write(stream, "\0\0\0\0", 4, NULL);
129 ok(hr == S_OK, "got %#lx\n", hr);
132 static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset)
134 static const LARGE_INTEGER zero = {0};
135 ULARGE_INTEGER position;
136 HRESULT hr;
137 UINT size;
138 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position);
139 ok(hr == S_OK, "got %#lx\n", hr);
140 hr = IStream_Seek(stream, *(LARGE_INTEGER *)offset, STREAM_SEEK_SET, NULL);
141 ok(hr == S_OK, "got %#lx\n", hr);
142 size = position.QuadPart - offset->QuadPart - 4;
143 hr = IStream_Write(stream, &size, 4, NULL);
144 ok(hr == S_OK, "got %#lx\n", hr);
145 hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL);
146 ok(hr == S_OK, "got %#lx\n", hr);
147 hr = IStream_Write(stream, &zero, (position.QuadPart & 1), NULL);
148 ok(hr == S_OK, "got %#lx\n", hr);
151 #define CHUNK_BEGIN(stream, type) \
152 do { \
153 ULARGE_INTEGER __off; \
154 IStream *__stream = (stream); \
155 stream_begin_chunk(stream, type, &__off); \
158 #define CHUNK_RIFF(stream, form) \
159 do { \
160 ULARGE_INTEGER __off; \
161 IStream *__stream = (stream); \
162 stream_begin_chunk(stream, "RIFF", &__off); \
163 IStream_Write(stream, form, 4, NULL); \
166 #define CHUNK_LIST(stream, form) \
167 do { \
168 ULARGE_INTEGER __off; \
169 IStream *__stream = (stream); \
170 stream_begin_chunk(stream, "LIST", &__off); \
171 IStream_Write(stream, form, 4, NULL); \
174 #define CHUNK_END \
175 while (0); \
176 stream_end_chunk(__stream, &__off); \
177 } while (0)
179 #define CHUNK_DATA(stream, type, data) \
180 CHUNK_BEGIN(stream, type) \
182 IStream_Write((stream), &(data), sizeof(data), NULL); \
184 CHUNK_END
186 #define CHUNK_ARRAY(stream, type, items) \
187 CHUNK_BEGIN(stream, type) \
189 UINT __size = sizeof(*(items)); \
190 IStream_Write((stream), &__size, 4, NULL); \
191 IStream_Write((stream), &(items), sizeof(items), NULL); \
193 CHUNK_END
195 struct test_tool
197 IDirectMusicTool IDirectMusicTool_iface;
198 LONG ref;
200 IDirectMusicGraph *graph;
201 const DWORD *types;
202 DWORD types_count;
204 SRWLOCK lock;
205 HANDLE message_event;
206 DMUS_PMSG *messages[32];
207 UINT message_count;
210 static DMUS_PMSG *test_tool_push_msg(struct test_tool *tool, DMUS_PMSG *msg)
212 AcquireSRWLockExclusive(&tool->lock);
213 ok(tool->message_count < ARRAY_SIZE(tool->messages),
214 "got %u messages\n", tool->message_count + 1);
215 if (tool->message_count < ARRAY_SIZE(tool->messages))
217 memmove(tool->messages + 1, tool->messages,
218 tool->message_count * sizeof(*tool->messages));
219 tool->messages[0] = msg;
220 tool->message_count++;
221 msg = NULL;
223 ReleaseSRWLockExclusive(&tool->lock);
225 return msg;
228 static struct test_tool *impl_from_IDirectMusicTool(IDirectMusicTool *iface)
230 return CONTAINING_RECORD(iface, struct test_tool, IDirectMusicTool_iface);
233 static HRESULT WINAPI test_tool_QueryInterface(IDirectMusicTool *iface, REFIID iid, void **out)
235 if (IsEqualGUID(iid, &IID_IUnknown)
236 || IsEqualGUID(iid, &IID_IDirectMusicTool))
238 IDirectMusicTool_AddRef(iface);
239 *out = iface;
240 return S_OK;
243 ok(IsEqualGUID(iid, &IID_IDirectMusicTool8) || IsEqualGUID(iid, &IID_IPersistStream),
244 "got iid %s\n", debugstr_guid(iid));
245 *out = NULL;
246 return E_NOINTERFACE;
249 static ULONG WINAPI test_tool_AddRef(IDirectMusicTool *iface)
251 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
252 return InterlockedIncrement(&tool->ref);
255 static ULONG WINAPI test_tool_Release(IDirectMusicTool *iface)
257 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
258 ULONG ref = InterlockedDecrement(&tool->ref);
260 if (!ref)
262 if (tool->graph) IDirectMusicGraph_Release(tool->graph);
263 ok(!tool->message_count, "got %p\n", &tool->message_count);
264 CloseHandle(tool->message_event);
265 free(tool);
268 return ref;
271 static HRESULT WINAPI test_tool_Init(IDirectMusicTool *iface, IDirectMusicGraph *graph)
273 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
274 if ((tool->graph = graph)) IDirectMusicGraph_AddRef(tool->graph);
275 return S_OK;
278 static HRESULT WINAPI test_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWORD *type)
280 *type = DMUS_PMSGF_TOOL_IMMEDIATE;
281 return S_OK;
284 static HRESULT WINAPI test_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size)
286 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
287 *size = tool->types_count;
288 return S_OK;
291 static HRESULT WINAPI test_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size)
293 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
294 UINT i;
295 for (i = 0; i < tool->types_count; i++) (*types)[i] = tool->types[i];
296 return S_OK;
299 static HRESULT WINAPI test_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg)
301 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
302 DMUS_PMSG *clone;
303 HRESULT hr;
305 hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone);
306 ok(hr == S_OK, "got %#lx\n", hr);
307 clone = test_tool_push_msg(tool, clone);
308 ok(!clone, "got %p\n", clone);
309 SetEvent(tool->message_event);
311 hr = IDirectMusicGraph_StampPMsg(msg->pGraph, msg);
312 ok(hr == S_OK, "got %#lx\n", hr);
314 return DMUS_S_REQUEUE;
317 static HRESULT WINAPI test_tool_Flush(IDirectMusicTool *iface, IDirectMusicPerformance *performance,
318 DMUS_PMSG *msg, REFERENCE_TIME time)
320 ok(0, "unexpected %s\n", __func__);
321 return S_OK;
324 static IDirectMusicToolVtbl test_tool_vtbl =
326 test_tool_QueryInterface,
327 test_tool_AddRef,
328 test_tool_Release,
329 test_tool_Init,
330 test_tool_GetMsgDeliveryType,
331 test_tool_GetMediaTypeArraySize,
332 test_tool_GetMediaTypes,
333 test_tool_ProcessPMsg,
334 test_tool_Flush,
337 static HRESULT test_tool_create(const DWORD *types, DWORD types_count,
338 IDirectMusicTool **ret_iface)
340 struct test_tool *tool;
342 *ret_iface = NULL;
343 if (!(tool = calloc(1, sizeof(*tool)))) return E_OUTOFMEMORY;
344 tool->IDirectMusicTool_iface.lpVtbl = &test_tool_vtbl;
345 tool->ref = 1;
347 tool->types = types;
348 tool->types_count = types_count;
349 tool->message_event = CreateEventW(NULL, FALSE, FALSE, NULL);
350 ok(!!tool->message_event, "CreateEventW failed, error %lu\n", GetLastError());
352 *ret_iface = &tool->IDirectMusicTool_iface;
353 return S_OK;
356 static HRESULT test_tool_get_graph(IDirectMusicTool *iface, IDirectMusicGraph **graph)
358 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
359 if ((*graph = tool->graph)) IDirectMusicGraph_AddRef(tool->graph);
360 return tool->graph ? S_OK : DMUS_E_NOT_FOUND;
363 static DWORD test_tool_wait_message(IDirectMusicTool *iface, DWORD timeout, DMUS_PMSG **msg)
365 struct test_tool *tool = impl_from_IDirectMusicTool(iface);
366 DWORD ret = WAIT_FAILED;
370 AcquireSRWLockExclusive(&tool->lock);
371 if (!tool->message_count)
372 *msg = NULL;
373 else
375 UINT index = --tool->message_count;
376 *msg = tool->messages[index];
377 tool->messages[index] = NULL;
379 ReleaseSRWLockExclusive(&tool->lock);
381 if (*msg) return 0;
382 } while (!(ret = WaitForSingleObject(tool->message_event, timeout)));
384 return ret;
387 struct test_loader_stream
389 IStream IStream_iface;
390 IDirectMusicGetLoader IDirectMusicGetLoader_iface;
391 LONG ref;
393 IStream *stream;
394 IDirectMusicLoader *loader;
397 static struct test_loader_stream *impl_from_IStream(IStream *iface)
399 return CONTAINING_RECORD(iface, struct test_loader_stream, IStream_iface);
402 static HRESULT WINAPI test_loader_stream_QueryInterface(IStream *iface, REFIID iid, void **out)
404 struct test_loader_stream *impl = impl_from_IStream(iface);
406 if (IsEqualGUID(iid, &IID_IUnknown)
407 || IsEqualGUID(iid, &IID_IStream))
409 IStream_AddRef(&impl->IStream_iface);
410 *out = &impl->IStream_iface;
411 return S_OK;
414 if (IsEqualGUID(iid, &IID_IDirectMusicGetLoader))
416 IDirectMusicGetLoader_AddRef(&impl->IDirectMusicGetLoader_iface);
417 *out = &impl->IDirectMusicGetLoader_iface;
418 return S_OK;
421 ok(IsEqualGUID(iid, &IID_IStream),
422 "got iid %s\n", debugstr_guid(iid));
423 *out = NULL;
424 return E_NOINTERFACE;
427 static ULONG WINAPI test_loader_stream_AddRef(IStream *iface)
429 struct test_loader_stream *impl = impl_from_IStream(iface);
430 return InterlockedIncrement(&impl->ref);
433 static ULONG WINAPI test_loader_stream_Release(IStream *iface)
435 struct test_loader_stream *impl = impl_from_IStream(iface);
436 ULONG ref = InterlockedDecrement(&impl->ref);
438 if (!ref)
440 IDirectMusicLoader_Release(impl->loader);
441 IStream_Release(impl->stream);
442 free(impl);
445 return ref;
448 static HRESULT WINAPI test_loader_stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size)
450 struct test_loader_stream *impl = impl_from_IStream(iface);
451 return IStream_Read(impl->stream, data, size, ret_size);
454 static HRESULT WINAPI test_loader_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size)
456 ok(0, "Unexpected call.\n");
457 return E_NOTIMPL;
460 static HRESULT WINAPI test_loader_stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset)
462 struct test_loader_stream *impl = impl_from_IStream(iface);
463 return IStream_Seek(impl->stream, offset, method, ret_offset);
466 static HRESULT WINAPI test_loader_stream_SetSize(IStream *iface, ULARGE_INTEGER size)
468 ok(0, "Unexpected call.\n");
469 return E_NOTIMPL;
472 static HRESULT WINAPI test_loader_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
473 ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size)
475 ok(0, "Unexpected call.\n");
476 return E_NOTIMPL;
479 static HRESULT WINAPI test_loader_stream_Commit(IStream *iface, DWORD flags)
481 ok(0, "Unexpected call.\n");
482 return E_NOTIMPL;
485 static HRESULT WINAPI test_loader_stream_Revert(IStream *iface)
487 ok(0, "Unexpected call.\n");
488 return E_NOTIMPL;
491 static HRESULT WINAPI test_loader_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
493 ok(0, "Unexpected call.\n");
494 return E_NOTIMPL;
497 static HRESULT WINAPI test_loader_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
499 ok(0, "Unexpected call.\n");
500 return E_NOTIMPL;
503 static HRESULT WINAPI test_loader_stream_Stat(IStream *iface, STATSTG *stat, DWORD flags)
505 ok(0, "Unexpected call.\n");
506 return E_NOTIMPL;
509 static HRESULT WINAPI test_loader_stream_Clone(IStream *iface, IStream **out)
511 ok(0, "Unexpected call.\n");
512 return E_NOTIMPL;
515 static const IStreamVtbl test_loader_stream_vtbl =
517 test_loader_stream_QueryInterface,
518 test_loader_stream_AddRef,
519 test_loader_stream_Release,
520 test_loader_stream_Read,
521 test_loader_stream_Write,
522 test_loader_stream_Seek,
523 test_loader_stream_SetSize,
524 test_loader_stream_CopyTo,
525 test_loader_stream_Commit,
526 test_loader_stream_Revert,
527 test_loader_stream_LockRegion,
528 test_loader_stream_UnlockRegion,
529 test_loader_stream_Stat,
530 test_loader_stream_Clone,
533 static struct test_loader_stream *impl_from_IDirectMusicGetLoader(IDirectMusicGetLoader *iface)
535 return CONTAINING_RECORD(iface, struct test_loader_stream, IDirectMusicGetLoader_iface);
538 static HRESULT WINAPI test_loader_stream_getter_QueryInterface(IDirectMusicGetLoader *iface, REFIID iid, void **out)
540 struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
541 return IStream_QueryInterface(&impl->IStream_iface, iid, out);
544 static ULONG WINAPI test_loader_stream_getter_AddRef(IDirectMusicGetLoader *iface)
546 struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
547 return IStream_AddRef(&impl->IStream_iface);
550 static ULONG WINAPI test_loader_stream_getter_Release(IDirectMusicGetLoader *iface)
552 struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
553 return IStream_Release(&impl->IStream_iface);
556 static HRESULT WINAPI test_loader_stream_getter_GetLoader(IDirectMusicGetLoader *iface, IDirectMusicLoader **ret_loader)
558 struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
560 *ret_loader = impl->loader;
561 IDirectMusicLoader_AddRef(impl->loader);
563 return S_OK;
566 static const IDirectMusicGetLoaderVtbl test_loader_stream_getter_vtbl =
568 test_loader_stream_getter_QueryInterface,
569 test_loader_stream_getter_AddRef,
570 test_loader_stream_getter_Release,
571 test_loader_stream_getter_GetLoader,
574 static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *loader,
575 IStream **ret_iface)
577 struct test_loader_stream *obj;
579 *ret_iface = NULL;
580 if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY;
581 obj->IStream_iface.lpVtbl = &test_loader_stream_vtbl;
582 obj->IDirectMusicGetLoader_iface.lpVtbl = &test_loader_stream_getter_vtbl;
583 obj->ref = 1;
585 obj->stream = stream;
586 IStream_AddRef(stream);
587 obj->loader = loader;
588 IDirectMusicLoader_AddRef(loader);
590 *ret_iface = &obj->IStream_iface;
591 return S_OK;
594 struct test_track
596 /* Implementing IDirectMusicTrack8 will cause native to call PlayEx */
597 IDirectMusicTrack IDirectMusicTrack_iface;
598 LONG ref;
600 DWORD data;
601 BOOL inserted;
602 BOOL initialized;
603 BOOL downloaded;
604 BOOL playing;
605 BOOL test_play;
606 HANDLE playing_event;
609 #define check_track_state(track, state, value) \
610 do \
612 DWORD ret = impl_from_IDirectMusicTrack(track)->state; \
613 ok(ret == (value), "got %#lx\n", ret); \
614 } while (0);
616 static inline struct test_track *impl_from_IDirectMusicTrack(IDirectMusicTrack *iface)
618 return CONTAINING_RECORD(iface, struct test_track, IDirectMusicTrack_iface);
621 static HRESULT WINAPI test_track_QueryInterface(IDirectMusicTrack *iface, REFIID riid,
622 void **ret_iface)
624 struct test_track *This = impl_from_IDirectMusicTrack(iface);
626 if (IsEqualIID(riid, &IID_IUnknown)
627 || IsEqualIID(riid, &IID_IDirectMusicTrack))
629 *ret_iface = &This->IDirectMusicTrack_iface;
630 IDirectMusicTrack_AddRef(&This->IDirectMusicTrack_iface);
631 return S_OK;
634 ok(IsEqualGUID(riid, &IID_IDirectMusicTrack8) || IsEqualGUID(riid, &IID_IPersistStream),
635 "unexpected %s %p %s\n", __func__, This, debugstr_guid(riid));
636 *ret_iface = NULL;
637 return E_NOINTERFACE;
640 static ULONG WINAPI test_track_AddRef(IDirectMusicTrack *iface)
642 struct test_track *This = impl_from_IDirectMusicTrack(iface);
643 return InterlockedIncrement(&This->ref);
646 static ULONG WINAPI test_track_Release(IDirectMusicTrack *iface)
648 struct test_track *This = impl_from_IDirectMusicTrack(iface);
649 ULONG ref = InterlockedDecrement(&This->ref);
651 if (!ref)
653 CloseHandle(This->playing_event);
654 free(This);
657 return ref;
660 static HRESULT WINAPI test_track_Init(IDirectMusicTrack *iface, IDirectMusicSegment *segment)
662 struct test_track *This = impl_from_IDirectMusicTrack(iface);
663 This->inserted = TRUE;
664 return S_OK;
667 static HRESULT WINAPI test_track_InitPlay(IDirectMusicTrack *iface, IDirectMusicSegmentState *segment_state,
668 IDirectMusicPerformance *performance, void **state_data, DWORD track_id, DWORD segment_flags)
670 struct test_track *This = impl_from_IDirectMusicTrack(iface);
672 ok(!!segment_state, "got %p\n", segment_state);
673 ok(!!performance, "got %p\n", performance);
674 ok(!!state_data, "got %p\n", state_data);
675 ok(!!track_id, "got %lu\n", track_id);
676 ok(!segment_flags, "got %#lx\n", segment_flags);
677 This->initialized = TRUE;
679 *state_data = &This->data;
680 return S_OK;
683 static HRESULT WINAPI test_track_EndPlay(IDirectMusicTrack *iface, void *state_data)
685 struct test_track *This = impl_from_IDirectMusicTrack(iface);
687 ok(state_data == &This->data, "got %p\n", state_data);
688 This->playing = FALSE;
690 return S_OK;
693 static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data,
694 MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags,
695 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id)
697 struct test_track *This = impl_from_IDirectMusicTrack(iface);
699 if (!This->test_play) return S_OK;
701 ok(state_data == &This->data, "got %p\n", state_data);
702 ok(start_time == 50, "got %lu\n", start_time);
703 ok(end_time == 100, "got %lu\n", end_time);
704 todo_wine ok(time_offset < 0, "got %lu\n", time_offset);
705 ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK),
706 "got %#lx\n", segment_flags);
707 ok(!!performance, "got %p\n", performance);
708 ok(!!segment_state, "got %p\n", segment_state);
709 ok(!!track_id, "got %lu\n", track_id);
710 This->playing = TRUE;
711 SetEvent(This->playing_event);
713 return S_OK;
716 static HRESULT WINAPI test_track_GetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time,
717 MUSIC_TIME *next, void *param)
719 struct test_track *This = impl_from_IDirectMusicTrack(iface);
720 ok(0, "unexpected %s %p\n", __func__, This);
721 return E_NOTIMPL;
724 static HRESULT WINAPI test_track_SetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, void *param)
726 struct test_track *This = impl_from_IDirectMusicTrack(iface);
728 if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
730 This->downloaded = TRUE;
731 return S_OK;
734 if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
736 This->downloaded = FALSE;
737 return S_OK;
740 ok(0, "unexpected %s %p %s %lu %p\n", __func__, This, debugstr_guid(type), time, param);
741 return E_NOTIMPL;
744 static HRESULT WINAPI test_track_IsParamSupported(IDirectMusicTrack *iface, REFGUID type)
746 struct test_track *This = impl_from_IDirectMusicTrack(iface);
748 if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) return S_OK;
749 if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) return S_OK;
750 if (IsEqualGUID(type, &GUID_TimeSignature)) return DMUS_E_TYPE_UNSUPPORTED;
751 if (IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_TYPE_UNSUPPORTED;
753 ok(broken(type->Data1 == 0xe8dbd832), /* native also checks some unknown parameter */
754 "unexpected %s %p %s\n", __func__, This, debugstr_guid(type));
755 return E_NOTIMPL;
758 static HRESULT WINAPI test_track_AddNotificationType(IDirectMusicTrack *iface, REFGUID type)
760 ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE),
761 "got %s\n", debugstr_guid(type));
762 return E_NOTIMPL;
765 static HRESULT WINAPI test_track_RemoveNotificationType(IDirectMusicTrack *iface, REFGUID type)
767 ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE),
768 "got %s\n", debugstr_guid(type));
769 return E_NOTIMPL;
772 static HRESULT WINAPI test_track_Clone(IDirectMusicTrack *iface, MUSIC_TIME start_time,
773 MUSIC_TIME end_time, IDirectMusicTrack **ret_track)
775 struct test_track *This = impl_from_IDirectMusicTrack(iface);
776 ok(0, "unexpected %s %p\n", __func__, This);
777 return E_NOTIMPL;
780 static const IDirectMusicTrackVtbl test_track_vtbl =
782 test_track_QueryInterface,
783 test_track_AddRef,
784 test_track_Release,
785 test_track_Init,
786 test_track_InitPlay,
787 test_track_EndPlay,
788 test_track_Play,
789 test_track_GetParam,
790 test_track_SetParam,
791 test_track_IsParamSupported,
792 test_track_AddNotificationType,
793 test_track_RemoveNotificationType,
794 test_track_Clone,
797 static HRESULT test_track_create(IDirectMusicTrack **ret_iface, BOOL test_play)
799 struct test_track *track;
801 *ret_iface = NULL;
802 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
803 track->IDirectMusicTrack_iface.lpVtbl = &test_track_vtbl;
804 track->ref = 1;
805 track->test_play = test_play;
807 track->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
808 ok(!!track->playing_event, "CreateEventW failed, error %lu\n", GetLastError());
810 *ret_iface = &track->IDirectMusicTrack_iface;
811 return S_OK;
814 static DWORD test_track_wait_playing(IDirectMusicTrack *iface, DWORD timeout)
816 struct test_track *This = impl_from_IDirectMusicTrack(iface);
817 return WaitForSingleObject(This->playing_event, timeout);
820 static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic,
821 IDirectSound **dsound, BOOL set_cooplevel)
823 HRESULT hr;
825 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
826 &IID_IDirectMusicPerformance8, (void **)performance);
827 ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx\n", hr);
828 if (dmusic) {
829 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
830 (void **)dmusic);
831 ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr);
833 if (dsound) {
834 hr = DirectSoundCreate8(NULL, (IDirectSound8 **)dsound, NULL);
835 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
836 if (set_cooplevel) {
837 hr = IDirectSound_SetCooperativeLevel(*dsound, GetForegroundWindow(), DSSCL_PRIORITY);
838 ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr);
843 static void destroy_performance(IDirectMusicPerformance8 *performance, IDirectMusic *dmusic,
844 IDirectSound *dsound)
846 HRESULT hr;
848 hr = IDirectMusicPerformance8_CloseDown(performance);
849 ok(hr == S_OK, "CloseDown failed: %#lx\n", hr);
850 IDirectMusicPerformance8_Release(performance);
851 if (dmusic)
852 IDirectMusic_Release(dmusic);
853 if (dsound)
854 IDirectSound_Release(dsound);
857 static BOOL missing_dmime(void)
859 IDirectMusicSegment8 *dms;
860 HRESULT hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
861 &IID_IDirectMusicSegment, (void**)&dms);
863 if (hr == S_OK && dms)
865 IDirectMusicSegment8_Release(dms);
866 return FALSE;
868 return TRUE;
871 static void test_COM_audiopath(void)
873 IDirectMusicAudioPath *dmap;
874 IUnknown *unk;
875 IDirectMusicPerformance8 *performance;
876 IDirectSoundBuffer *dsound;
877 IDirectSoundBuffer8 *dsound8;
878 IDirectSoundNotify *notify;
879 IDirectSound3DBuffer *dsound3d;
880 IKsPropertySet *propset;
881 ULONG refcount;
882 HRESULT hr;
883 DWORD buffer = 0;
885 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
886 &IID_IDirectMusicPerformance8, (void**)&performance);
887 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "DirectMusicPerformance create failed: %#lx\n", hr);
888 if (!performance) {
889 win_skip("IDirectMusicPerformance8 not available\n");
890 return;
892 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL,
893 DMUS_APATH_SHARED_STEREOPLUSREVERB, 64, DMUS_AUDIOF_ALL, NULL);
894 ok(hr == S_OK || hr == DSERR_NODRIVER ||
895 broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED), /* Win 10 testbot */
896 "DirectMusicPerformance_InitAudio failed: %#lx\n", hr);
897 if (FAILED(hr)) {
898 skip("Audio failed to initialize\n");
899 return;
901 hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &dmap);
902 ok(hr == S_OK, "DirectMusicPerformance_GetDefaultAudioPath failed: %#lx\n", hr);
904 /* IDirectMusicObject and IPersistStream are not supported */
905 hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IDirectMusicObject, (void**)&unk);
906 todo_wine ok(FAILED(hr) && !unk, "Unexpected IDirectMusicObject interface: hr=%#lx, iface=%p\n",
907 hr, unk);
908 if (unk) IUnknown_Release(unk);
909 hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IPersistStream, (void**)&unk);
910 todo_wine ok(FAILED(hr) && !unk, "Unexpected IPersistStream interface: hr=%#lx, iface=%p\n",
911 hr, unk);
912 if (unk) IUnknown_Release(unk);
914 /* Same refcount for all DirectMusicAudioPath interfaces */
915 refcount = IDirectMusicAudioPath_AddRef(dmap);
916 ok(refcount == 3, "refcount == %lu, expected 3\n", refcount);
918 hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IUnknown, (void**)&unk);
919 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
920 ok(unk == (IUnknown*)dmap, "got %p, %p\n", unk, dmap);
921 refcount = IUnknown_AddRef(unk);
922 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
923 refcount = IUnknown_Release(unk);
925 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
926 0, &IID_IDirectSoundBuffer, (void**)&dsound);
927 ok(hr == S_OK, "Failed: %#lx\n", hr);
928 IDirectSoundBuffer_Release(dsound);
930 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
931 0, &IID_IDirectSoundBuffer8, (void**)&dsound8);
932 ok(hr == S_OK, "Failed: %#lx\n", hr);
933 IDirectSoundBuffer8_Release(dsound8);
935 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
936 0, &IID_IDirectSoundNotify, (void**)&notify);
937 ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
939 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
940 0, &IID_IDirectSound3DBuffer, (void**)&dsound3d);
941 ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
943 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
944 0, &IID_IKsPropertySet, (void**)&propset);
945 todo_wine ok(hr == S_OK, "Failed: %#lx\n", hr);
946 if (propset)
947 IKsPropertySet_Release(propset);
949 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
950 0, &IID_IUnknown, (void**)&unk);
951 ok(hr == S_OK, "Failed: %#lx\n", hr);
952 IUnknown_Release(unk);
954 hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
955 0, &GUID_NULL, (void**)&unk);
956 ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
958 while (IDirectMusicAudioPath_Release(dmap) > 1); /* performance has a reference too */
959 IDirectMusicPerformance8_CloseDown(performance);
960 IDirectMusicPerformance8_Release(performance);
963 static void test_COM_audiopathconfig(void)
965 IDirectMusicAudioPath *dmap = (IDirectMusicAudioPath*)0xdeadbeef;
966 IDirectMusicObject *dmo;
967 IPersistStream *ps;
968 IUnknown *unk;
969 ULONG refcount;
970 HRESULT hr;
972 /* COM aggregation */
973 hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
974 &IID_IUnknown, (void**)&dmap);
975 if (hr == REGDB_E_CLASSNOTREG) {
976 win_skip("DirectMusicAudioPathConfig not registered\n");
977 return;
979 ok(hr == CLASS_E_NOAGGREGATION,
980 "DirectMusicAudioPathConfig create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
981 ok(!dmap, "dmap = %p\n", dmap);
983 /* IDirectMusicAudioPath not supported */
984 hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
985 &IID_IDirectMusicAudioPath, (void**)&dmap);
986 todo_wine ok(FAILED(hr) && !dmap,
987 "Unexpected IDirectMusicAudioPath interface: hr=%#lx, iface=%p\n", hr, dmap);
989 /* IDirectMusicObject and IPersistStream supported */
990 hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
991 &IID_IPersistStream, (void**)&ps);
992 ok(hr == S_OK, "DirectMusicObject create failed: %#lx, expected S_OK\n", hr);
993 IPersistStream_Release(ps);
994 hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
995 &IID_IDirectMusicObject, (void**)&dmo);
996 ok(hr == S_OK, "DirectMusicObject create failed: %#lx, expected S_OK\n", hr);
998 /* Same refcount for all DirectMusicObject interfaces */
999 refcount = IDirectMusicObject_AddRef(dmo);
1000 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
1002 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IPersistStream, (void**)&ps);
1003 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1004 refcount = IPersistStream_AddRef(ps);
1005 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
1006 IPersistStream_Release(ps);
1008 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IUnknown, (void**)&unk);
1009 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
1010 refcount = IUnknown_AddRef(unk);
1011 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
1012 refcount = IUnknown_Release(unk);
1014 /* IDirectMusicAudioPath still not supported */
1015 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IDirectMusicAudioPath, (void**)&dmap);
1016 todo_wine ok(FAILED(hr) && !dmap,
1017 "Unexpected IDirectMusicAudioPath interface: hr=%#lx, iface=%p\n", hr, dmap);
1019 while (IDirectMusicObject_Release(dmo));
1023 static void test_COM_graph(void)
1025 IDirectMusicGraph *dmg = (IDirectMusicGraph*)0xdeadbeef;
1026 IDirectMusicObject *dmo;
1027 IPersistStream *ps;
1028 IUnknown *unk;
1029 ULONG refcount;
1030 HRESULT hr;
1032 /* COM aggregation */
1033 hr = CoCreateInstance(&CLSID_DirectMusicGraph, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
1034 &IID_IUnknown, (void**)&dmg);
1035 ok(hr == CLASS_E_NOAGGREGATION,
1036 "DirectMusicGraph create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
1037 ok(!dmg, "dmg = %p\n", dmg);
1039 /* Invalid RIID */
1040 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory,
1041 (void**)&dmg);
1042 ok(hr == E_NOINTERFACE, "DirectMusicGraph create failed: %#lx, expected E_NOINTERFACE\n", hr);
1044 /* Same refcount for all DirectMusicGraph interfaces */
1045 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
1046 &IID_IDirectMusicGraph, (void**)&dmg);
1047 ok(hr == S_OK, "DirectMusicGraph create failed: %#lx, expected S_OK\n", hr);
1048 refcount = IDirectMusicGraph_AddRef(dmg);
1049 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
1051 hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IDirectMusicObject, (void**)&dmo);
1052 if (hr == E_NOINTERFACE) {
1053 win_skip("DirectMusicGraph without IDirectMusicObject\n");
1054 return;
1056 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
1057 refcount = IDirectMusicObject_AddRef(dmo);
1058 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
1059 refcount = IDirectMusicObject_Release(dmo);
1061 hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IPersistStream, (void**)&ps);
1062 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1063 refcount = IPersistStream_AddRef(ps);
1064 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
1065 refcount = IPersistStream_Release(ps);
1067 hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IUnknown, (void**)&unk);
1068 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
1069 refcount = IUnknown_AddRef(unk);
1070 ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
1071 refcount = IUnknown_Release(unk);
1073 while (IDirectMusicGraph_Release(dmg));
1076 static void test_COM_segment(void)
1078 IDirectMusicSegment8 *dms = (IDirectMusicSegment8*)0xdeadbeef;
1079 IDirectMusicObject *dmo;
1080 IPersistStream *stream;
1081 IUnknown *unk;
1082 ULONG refcount;
1083 HRESULT hr;
1085 /* COM aggregation */
1086 hr = CoCreateInstance(&CLSID_DirectMusicSegment, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
1087 &IID_IUnknown, (void**)&dms);
1088 ok(hr == CLASS_E_NOAGGREGATION,
1089 "DirectMusicSegment create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
1090 ok(!dms, "dms = %p\n", dms);
1092 /* Invalid RIID */
1093 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
1094 &IID_IDirectSound, (void**)&dms);
1095 ok(hr == E_NOINTERFACE, "DirectMusicSegment create failed: %#lx, expected E_NOINTERFACE\n", hr);
1097 /* Same refcount */
1098 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
1099 &IID_IDirectMusicSegment8, (void**)&dms);
1100 if (hr == E_NOINTERFACE) {
1101 win_skip("DirectMusicSegment without IDirectMusicSegment8\n");
1102 return;
1104 ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
1105 refcount = IDirectMusicSegment8_AddRef(dms);
1106 ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
1107 hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IDirectMusicObject, (void**)&dmo);
1108 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
1109 IDirectMusicSegment8_AddRef(dms);
1110 refcount = IDirectMusicSegment8_Release(dms);
1111 ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
1112 hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IPersistStream, (void**)&stream);
1113 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1114 refcount = IDirectMusicSegment8_Release(dms);
1115 ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
1116 hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IUnknown, (void**)&unk);
1117 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
1118 refcount = IUnknown_Release(unk);
1119 ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
1120 refcount = IDirectMusicObject_Release(dmo);
1121 ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
1122 refcount = IPersistStream_Release(stream);
1123 ok (refcount == 1, "refcount == %lu, expected 1\n", refcount);
1124 refcount = IDirectMusicSegment8_Release(dms);
1125 ok (refcount == 0, "refcount == %lu, expected 0\n", refcount);
1128 static void test_COM_segmentstate(void)
1130 IDirectMusicSegmentState8 *dmss8 = (IDirectMusicSegmentState8*)0xdeadbeef;
1131 IUnknown *unk;
1132 ULONG refcount;
1133 HRESULT hr;
1135 /* COM aggregation */
1136 hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
1137 &IID_IUnknown, (void**)&dmss8);
1138 ok(hr == CLASS_E_NOAGGREGATION,
1139 "DirectMusicSegmentState8 create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
1140 ok(!dmss8, "dmss8 = %p\n", dmss8);
1142 /* Invalid RIID */
1143 hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, NULL, CLSCTX_INPROC_SERVER,
1144 &IID_IDirectMusicObject, (void**)&dmss8);
1145 ok(hr == E_NOINTERFACE, "DirectMusicSegmentState8 create failed: %#lx, expected E_NOINTERFACE\n", hr);
1147 /* Same refcount for all DirectMusicSegmentState interfaces */
1148 hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, NULL, CLSCTX_INPROC_SERVER,
1149 &IID_IDirectMusicSegmentState8, (void**)&dmss8);
1150 if (hr == E_NOINTERFACE) {
1151 win_skip("DirectMusicSegmentState without IDirectMusicSegmentState8\n");
1152 return;
1154 ok(hr == S_OK, "DirectMusicSegmentState8 create failed: %#lx, expected S_OK\n", hr);
1155 refcount = IDirectMusicSegmentState8_AddRef(dmss8);
1156 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
1158 hr = IDirectMusicSegmentState8_QueryInterface(dmss8, &IID_IUnknown, (void**)&unk);
1159 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
1160 refcount = IUnknown_AddRef(unk);
1161 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
1162 refcount = IUnknown_Release(unk);
1164 hr = IDirectMusicSegmentState8_QueryInterface(dmss8, &IID_IUnknown, NULL);
1165 ok(hr == E_POINTER, "got %#lx\n", hr);
1167 while (IDirectMusicSegmentState8_Release(dmss8));
1170 static void test_COM_track(void)
1172 IDirectMusicTrack *dmt;
1173 IDirectMusicTrack8 *dmt8;
1174 IPersistStream *ps;
1175 IUnknown *unk;
1176 ULONG refcount;
1177 HRESULT hr;
1178 #define X(class) &CLSID_ ## class, #class
1179 const struct {
1180 REFCLSID clsid;
1181 const char *name;
1182 BOOL has_dmt8;
1183 } class[] = {
1184 { X(DirectMusicLyricsTrack), TRUE },
1185 { X(DirectMusicMarkerTrack), FALSE },
1186 { X(DirectMusicParamControlTrack), TRUE },
1187 { X(DirectMusicSegmentTriggerTrack), TRUE },
1188 { X(DirectMusicSeqTrack), TRUE },
1189 { X(DirectMusicSysExTrack), TRUE },
1190 { X(DirectMusicTempoTrack), TRUE },
1191 { X(DirectMusicTimeSigTrack), FALSE },
1192 { X(DirectMusicWaveTrack), TRUE }
1194 #undef X
1195 unsigned int i;
1197 for (i = 0; i < ARRAY_SIZE(class); i++) {
1198 trace("Testing %s\n", class[i].name);
1199 /* COM aggregation */
1200 dmt8 = (IDirectMusicTrack8*)0xdeadbeef;
1201 hr = CoCreateInstance(class[i].clsid, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, &IID_IUnknown,
1202 (void**)&dmt8);
1203 if (hr == REGDB_E_CLASSNOTREG) {
1204 win_skip("%s not registered\n", class[i].name);
1205 continue;
1207 ok(hr == CLASS_E_NOAGGREGATION,
1208 "%s create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", class[i].name, hr);
1209 ok(!dmt8, "dmt8 = %p\n", dmt8);
1211 /* Invalid RIID */
1212 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
1213 (void**)&dmt8);
1214 ok(hr == E_NOINTERFACE, "%s create failed: %#lx, expected E_NOINTERFACE\n", class[i].name, hr);
1216 /* Same refcount for all DirectMusicTrack interfaces */
1217 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
1218 (void**)&dmt);
1219 ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
1220 refcount = IDirectMusicTrack_AddRef(dmt);
1221 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
1223 hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IPersistStream, (void**)&ps);
1224 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1225 refcount = IPersistStream_AddRef(ps);
1226 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
1227 IPersistStream_Release(ps);
1229 hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IUnknown, (void**)&unk);
1230 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
1231 refcount = IUnknown_AddRef(unk);
1232 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
1233 refcount = IUnknown_Release(unk);
1235 hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IDirectMusicTrack8, (void**)&dmt8);
1236 if (class[i].has_dmt8) {
1237 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicTrack8 failed: %#lx\n", hr);
1238 refcount = IDirectMusicTrack8_AddRef(dmt8);
1239 ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
1240 refcount = IDirectMusicTrack8_Release(dmt8);
1241 } else {
1242 ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectMusicTrack8 failed: %#lx\n", hr);
1243 refcount = IDirectMusicTrack_AddRef(dmt);
1244 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
1247 while (IDirectMusicTrack_Release(dmt));
1251 static void test_COM_performance(void)
1253 IDirectMusicPerformance *dmp = (IDirectMusicPerformance*)0xdeadbeef;
1254 IDirectMusicPerformance *dmp2;
1255 IDirectMusicPerformance8 *dmp8;
1256 ULONG refcount;
1257 HRESULT hr;
1259 /* COM aggregation */
1260 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
1261 &IID_IUnknown, (void**)&dmp);
1262 ok(hr == CLASS_E_NOAGGREGATION,
1263 "DirectMusicPerformance create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
1264 ok(!dmp, "dmp = %p\n", dmp);
1266 /* Invalid RIID */
1267 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
1268 &IID_IDirectMusicObject, (void**)&dmp);
1269 ok(hr == E_NOINTERFACE, "DirectMusicPerformance create failed: %#lx, expected E_NOINTERFACE\n", hr);
1271 /* Same refcount */
1272 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
1273 &IID_IDirectMusicPerformance, (void**)&dmp);
1274 ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx, expected S_OK\n", hr);
1275 refcount = IDirectMusicPerformance_AddRef(dmp);
1276 ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
1277 hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance2, (void**)&dmp2);
1278 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance2 failed: %#lx\n", hr);
1279 IDirectMusicPerformance_AddRef(dmp);
1280 refcount = IDirectMusicPerformance_Release(dmp);
1281 ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
1282 hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance8, (void**)&dmp8);
1283 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance8 failed: %#lx\n", hr);
1284 refcount = IDirectMusicPerformance_Release(dmp);
1285 ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
1286 refcount = IDirectMusicPerformance8_Release(dmp8);
1287 ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
1288 refcount = IDirectMusicPerformance_Release(dmp2);
1289 ok (refcount == 1, "refcount == %lu, expected 1\n", refcount);
1290 refcount = IDirectMusicPerformance_Release(dmp);
1291 ok (refcount == 0, "refcount == %lu, expected 0\n", refcount);
1294 static void test_audiopathconfig(void)
1296 IDirectMusicObject *dmo;
1297 IPersistStream *ps;
1298 CLSID class = { 0 };
1299 ULARGE_INTEGER size;
1300 HRESULT hr;
1302 hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
1303 &IID_IDirectMusicObject, (void**)&dmo);
1304 if (hr == REGDB_E_CLASSNOTREG) {
1305 win_skip("DirectMusicAudioPathConfig not registered\n");
1306 return;
1308 ok(hr == S_OK, "DirectMusicAudioPathConfig create failed: %#lx, expected S_OK\n", hr);
1310 /* IPersistStream */
1311 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IPersistStream, (void**)&ps);
1312 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1313 hr = IPersistStream_GetClassID(ps, &class);
1314 ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
1315 ok(IsEqualGUID(&class, &CLSID_DirectMusicAudioPathConfig),
1316 "Expected class CLSID_DirectMusicAudioPathConfig got %s\n", wine_dbgstr_guid(&class));
1318 /* Unimplemented IPersistStream methods */
1319 hr = IPersistStream_IsDirty(ps);
1320 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
1321 hr = IPersistStream_GetSizeMax(ps, &size);
1322 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
1323 hr = IPersistStream_Save(ps, NULL, TRUE);
1324 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
1326 while (IDirectMusicObject_Release(dmo));
1329 static void test_graph(void)
1331 IDirectMusicTool *tool1, *tool2, *tmp_tool;
1332 IDirectMusicGraph *graph, *tmp_graph;
1333 IPersistStream *ps;
1334 CLSID class = { 0 };
1335 ULARGE_INTEGER size;
1336 DMUS_PMSG msg;
1337 HRESULT hr;
1339 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
1340 &IID_IDirectMusicGraph, (void**)&graph);
1341 ok(hr == S_OK, "DirectMusicGraph create failed: %#lx, expected S_OK\n", hr);
1343 /* IPersistStream */
1344 hr = IDirectMusicGraph_QueryInterface(graph, &IID_IPersistStream, (void**)&ps);
1345 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1346 hr = IPersistStream_GetClassID(ps, &class);
1347 ok(hr == S_OK || broken(hr == E_NOTIMPL) /* win2k */, "IPersistStream_GetClassID failed: %#lx\n", hr);
1348 if (hr == S_OK)
1349 ok(IsEqualGUID(&class, &CLSID_DirectMusicGraph),
1350 "Expected class CLSID_DirectMusicGraph got %s\n", wine_dbgstr_guid(&class));
1352 /* Unimplemented IPersistStream methods */
1353 hr = IPersistStream_IsDirty(ps);
1354 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
1355 hr = IPersistStream_GetSizeMax(ps, &size);
1356 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
1357 hr = IPersistStream_Save(ps, NULL, TRUE);
1358 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
1360 IDirectMusicGraph_Release(graph);
1363 hr = test_tool_create(NULL, 0, &tool1);
1364 ok(hr == S_OK, "got %#lx\n", hr);
1365 trace("created tool1 %p\n", tool1);
1366 hr = test_tool_create(NULL, 0, &tool2);
1367 ok(hr == S_OK, "got %#lx\n", hr);
1368 trace("created tool2 %p\n", tool2);
1370 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
1371 &IID_IDirectMusicGraph, (void **)&graph);
1372 ok(hr == S_OK, "got %#lx\n", hr);
1375 hr = IDirectMusicGraph_InsertTool(graph, NULL, NULL, 0, -1);
1376 ok(hr == E_POINTER, "got %#lx\n", hr);
1378 /* InsertTool initializes the tool */
1379 hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
1380 ok(hr == S_OK, "got %#lx\n", hr);
1381 hr = test_tool_get_graph(tool1, &tmp_graph);
1382 ok(hr == S_OK, "got %#lx\n", hr);
1383 ok(graph == tmp_graph, "got %#lx\n", hr);
1384 IDirectMusicGraph_Release(tmp_graph);
1386 hr = IDirectMusicGraph_InsertTool(graph, tool2, NULL, 0, 1);
1387 ok(hr == S_OK, "got %#lx\n", hr);
1389 hr = IDirectMusicGraph_GetTool(graph, 0, NULL);
1390 ok(hr == E_POINTER, "got %#lx\n", hr);
1391 hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
1392 ok(hr == S_OK, "got %#lx\n", hr);
1393 ok(tool1 == tmp_tool, "got %p\n", tmp_tool);
1394 if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
1395 hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool);
1396 ok(hr == S_OK, "got %#lx\n", hr);
1397 ok(tool2 == tmp_tool, "got %p\n", tmp_tool);
1398 if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
1399 hr = IDirectMusicGraph_GetTool(graph, 2, &tmp_tool);
1400 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
1402 /* cannot insert the tool twice */
1403 hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
1404 ok(hr == DMUS_E_ALREADY_EXISTS, "got %#lx\n", hr);
1406 /* test removing the first tool */
1407 hr = IDirectMusicGraph_RemoveTool(graph, NULL);
1408 ok(hr == E_POINTER, "got %#lx\n", hr);
1409 hr = IDirectMusicGraph_RemoveTool(graph, tool1);
1410 ok(hr == S_OK, "got %#lx\n", hr);
1411 hr = IDirectMusicGraph_RemoveTool(graph, tool1);
1412 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
1414 hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
1415 ok(hr == S_OK, "got %#lx\n", hr);
1416 ok(tool2 == tmp_tool, "got %p\n", tmp_tool);
1417 if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
1418 hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool);
1419 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
1421 hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
1422 ok(hr == S_OK, "got %#lx\n", hr);
1423 hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
1424 ok(hr == S_OK, "got %#lx\n", hr);
1425 ok(tool1 == tmp_tool, "got %p\n", tmp_tool);
1426 if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
1429 /* Test basic IDirectMusicGraph_StampPMsg usage */
1430 hr = IDirectMusicGraph_StampPMsg(graph, NULL);
1431 ok(hr == E_POINTER, "got %#lx\n", hr);
1432 memset(&msg, 0, sizeof(msg));
1433 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
1434 ok(hr == S_OK, "got %#lx\n", hr);
1435 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1436 ok(msg.pTool == tool1, "got %p\n", msg.pTool);
1438 ok(!msg.dwSize, "got %ld\n", msg.dwSize);
1439 ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
1440 ok(!msg.mtTime, "got %ld\n", msg.mtTime);
1441 ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags);
1442 ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
1443 ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
1444 ok(!msg.dwType, "got %#lx\n", msg.dwType);
1445 ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
1446 ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
1447 ok(!msg.punkUser, "got %p\n", msg.punkUser);
1449 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
1450 ok(hr == S_OK, "got %#lx\n", hr);
1451 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1452 ok(msg.pTool == tool2, "got %p\n", msg.pTool);
1453 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
1454 ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
1455 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1456 ok(!msg.pTool, "got %p\n", msg.pTool);
1457 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
1458 ok(hr == S_OK, "got %#lx\n", hr);
1459 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1460 ok(msg.pTool == tool1, "got %p\n", msg.pTool);
1461 IDirectMusicGraph_Release(msg.pGraph);
1462 msg.pGraph = NULL;
1463 IDirectMusicGraph_Release(msg.pTool);
1464 msg.pTool = NULL;
1467 /* test StampPMsg with the wrong graph or innexistant tools */
1468 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
1469 &IID_IDirectMusicGraph, (void **)&tmp_graph);
1470 ok(hr == S_OK, "got %#lx\n", hr);
1472 msg.pGraph = tmp_graph;
1473 IDirectMusicGraph_AddRef(msg.pGraph);
1474 msg.pTool = tool1;
1475 IDirectMusicTool_AddRef(msg.pTool);
1476 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
1477 ok(hr == S_OK, "got %#lx\n", hr);
1478 ok(msg.pGraph == tmp_graph, "got %p\n", msg.pGraph);
1479 ok(msg.pTool == tool2, "got %p\n", msg.pTool);
1480 IDirectMusicGraph_Release(msg.pGraph);
1481 msg.pGraph = NULL;
1483 msg.pGraph = graph;
1484 IDirectMusicGraph_AddRef(msg.pGraph);
1485 hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
1486 ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
1487 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1488 ok(msg.pTool == NULL, "got %p\n", msg.pTool);
1490 msg.pTool = tool2;
1491 IDirectMusicTool_AddRef(msg.pTool);
1492 hr = IDirectMusicGraph_InsertTool(tmp_graph, tool1, NULL, 0, 0);
1493 ok(hr == S_OK, "got %#lx\n", hr);
1494 hr = IDirectMusicGraph_InsertTool(tmp_graph, tool2, NULL, 0, 0);
1495 ok(hr == S_OK, "got %#lx\n", hr);
1496 hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
1497 ok(hr == S_OK, "got %#lx\n", hr);
1498 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
1499 ok(msg.pTool == tool1, "got %p\n", msg.pTool);
1500 IDirectMusicGraph_Release(msg.pGraph);
1501 msg.pGraph = NULL;
1503 hr = IDirectMusicGraph_RemoveTool(graph, tool1);
1504 ok(hr == S_OK, "got %#lx\n", hr);
1505 hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
1506 ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
1507 ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
1508 ok(msg.pTool == NULL, "got %p\n", msg.pTool);
1510 IDirectMusicGraph_Release(tmp_graph);
1513 IDirectMusicGraph_Release(graph);
1514 IDirectMusicTool_Release(tool2);
1515 IDirectMusicTool_Release(tool1);
1518 static void test_segment(void)
1520 IDirectMusicSegment *dms;
1521 IPersistStream *ps;
1522 CLSID class = { 0 };
1523 ULARGE_INTEGER size;
1524 HRESULT hr;
1526 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
1527 &IID_IDirectMusicSegment, (void**)&dms);
1528 ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
1530 /* IPersistStream */
1531 hr = IDirectMusicSegment_QueryInterface(dms, &IID_IPersistStream, (void**)&ps);
1532 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1533 hr = IPersistStream_GetClassID(ps, &class);
1534 ok(hr == S_OK || broken(hr == E_NOTIMPL) /* win2k */, "IPersistStream_GetClassID failed: %#lx\n", hr);
1535 if (hr == S_OK)
1536 ok(IsEqualGUID(&class, &CLSID_DirectMusicSegment),
1537 "Expected class CLSID_DirectMusicSegment got %s\n", wine_dbgstr_guid(&class));
1539 /* Unimplemented IPersistStream methods */
1540 hr = IPersistStream_IsDirty(ps);
1541 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
1542 hr = IPersistStream_GetSizeMax(ps, &size);
1543 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
1544 hr = IPersistStream_Save(ps, NULL, TRUE);
1545 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
1547 while (IDirectMusicSegment_Release(dms));
1550 static void _add_track(IDirectMusicSegment8 *seg, REFCLSID class, const char *name, DWORD group)
1552 IDirectMusicTrack *track;
1553 HRESULT hr;
1555 hr = CoCreateInstance(class, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
1556 (void**)&track);
1557 ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", name, hr);
1558 hr = IDirectMusicSegment8_InsertTrack(seg, track, group);
1559 if (group)
1560 ok(hr == S_OK, "Inserting %s failed: %#lx, expected S_OK\n", name, hr);
1561 else
1562 ok(hr == E_INVALIDARG, "Inserting %s failed: %#lx, expected E_INVALIDARG\n", name, hr);
1563 IDirectMusicTrack_Release(track);
1566 #define add_track(seg, class, group) _add_track(seg, &CLSID_DirectMusic ## class, #class, group)
1568 static void _expect_track(IDirectMusicSegment8 *seg, REFCLSID expect, const char *name, DWORD group,
1569 DWORD index, BOOL ignore_guid)
1571 IDirectMusicTrack *track;
1572 IPersistStream *ps;
1573 CLSID class;
1574 HRESULT hr;
1576 if (ignore_guid)
1577 hr = IDirectMusicSegment8_GetTrack(seg, &GUID_NULL, group, index, &track);
1578 else
1579 hr = IDirectMusicSegment8_GetTrack(seg, expect, group, index, &track);
1580 if (!expect) {
1581 ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
1582 return;
1585 ok(hr == S_OK, "GetTrack failed: %#lx, expected S_OK\n", hr);
1586 hr = IDirectMusicTrack_QueryInterface(track, &IID_IPersistStream, (void**)&ps);
1587 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1588 hr = IPersistStream_GetClassID(ps, &class);
1589 ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
1590 ok(IsEqualGUID(&class, expect), "For group %#lx index %lu: Expected class %s got %s\n",
1591 group, index, name, wine_dbgstr_guid(&class));
1593 IPersistStream_Release(ps);
1594 IDirectMusicTrack_Release(track);
1597 #define expect_track(seg, class, group, index) \
1598 _expect_track(seg, &CLSID_DirectMusic ## class, #class, group, index, TRUE)
1599 #define expect_guid_track(seg, class, group, index) \
1600 _expect_track(seg, &CLSID_DirectMusic ## class, #class, group, index, FALSE)
1602 static void test_gettrack(void)
1604 IDirectMusicSegment8 *seg;
1605 IDirectMusicTrack *track;
1606 HRESULT hr;
1608 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
1609 &IID_IDirectMusicSegment8, (void**)&seg);
1610 ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
1612 add_track(seg, LyricsTrack, 0x0); /* failure */
1613 add_track(seg, LyricsTrack, 0x1); /* idx 0 group 1 */
1614 add_track(seg, ParamControlTrack, 0x3); /* idx 1 group 1, idx 0 group 2 */
1615 add_track(seg, SegmentTriggerTrack, 0x2); /* idx 1 group 2 */
1616 add_track(seg, SeqTrack, 0x1); /* idx 2 group 1 */
1617 add_track(seg, TempoTrack, 0x7); /* idx 3 group 1, idx 2 group 2, idx 0 group 3 */
1618 add_track(seg, WaveTrack, 0xffffffff); /* idx 4 group 1, idx 3 group 2, idx 1 group 3 */
1620 /* Ignore GUID in GetTrack */
1621 hr = IDirectMusicSegment8_GetTrack(seg, &GUID_NULL, 0, 0, &track);
1622 ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
1624 expect_track(seg, LyricsTrack, 0x1, 0);
1625 expect_track(seg, ParamControlTrack, 0x1, 1);
1626 expect_track(seg, SeqTrack, 0x1, 2);
1627 expect_track(seg, TempoTrack, 0x1, 3);
1628 expect_track(seg, WaveTrack, 0x1, 4);
1629 _expect_track(seg, NULL, "", 0x1, 5, TRUE);
1630 _expect_track(seg, NULL, "", 0x1, DMUS_SEG_ANYTRACK, TRUE);
1631 expect_track(seg, ParamControlTrack, 0x2, 0);
1632 expect_track(seg, WaveTrack, 0x80000000, 0);
1633 expect_track(seg, SegmentTriggerTrack, 0x3, 2); /* groups 1+2 combined index */
1634 expect_track(seg, SeqTrack, 0x3, 3); /* groups 1+2 combined index */
1635 expect_track(seg, TempoTrack, 0x7, 4); /* groups 1+2+3 combined index */
1636 expect_track(seg, TempoTrack, 0xffffffff, 4); /* all groups combined index */
1637 _expect_track(seg, NULL, "", 0xffffffff, DMUS_SEG_ANYTRACK, TRUE);
1639 /* Use the GUID in GetTrack */
1640 hr = IDirectMusicSegment8_GetTrack(seg, &CLSID_DirectMusicLyricsTrack, 0, 0, &track);
1641 ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
1643 expect_guid_track(seg, LyricsTrack, 0x1, 0);
1644 expect_guid_track(seg, ParamControlTrack, 0x1, 0);
1645 expect_guid_track(seg, SeqTrack, 0x1, 0);
1646 expect_guid_track(seg, TempoTrack, 0x1, 0);
1647 expect_guid_track(seg, ParamControlTrack, 0x2, 0);
1648 expect_guid_track(seg, SegmentTriggerTrack, 0x3, 0);
1649 expect_guid_track(seg, SeqTrack, 0x3, 0);
1650 expect_guid_track(seg, TempoTrack, 0x7, 0);
1651 expect_guid_track(seg, TempoTrack, 0xffffffff, 0);
1653 IDirectMusicSegment8_Release(seg);
1656 static void test_segment_param(void)
1658 IDirectMusicSegment8 *seg;
1659 char buf[64];
1660 HRESULT hr;
1662 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
1663 &IID_IDirectMusicSegment8, (void **)&seg);
1664 ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
1666 add_track(seg, LyricsTrack, 0x1); /* no params */
1667 add_track(seg, SegmentTriggerTrack, 0x1); /* all params "supported" */
1669 hr = IDirectMusicSegment8_GetParam(seg, NULL, 0x1, 0, 0, NULL, buf);
1670 ok(hr == E_POINTER, "GetParam failed: %#lx, expected E_POINTER\n", hr);
1671 hr = IDirectMusicSegment8_SetParam(seg, NULL, 0x1, 0, 0, buf);
1672 todo_wine ok(hr == E_POINTER, "SetParam failed: %#lx, expected E_POINTER\n", hr);
1674 hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, 0, 0, NULL, buf);
1675 ok(hr == DMUS_E_GET_UNSUPPORTED, "GetParam failed: %#lx, expected DMUS_E_GET_UNSUPPORTED\n", hr);
1676 hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, 1, 0, NULL, buf);
1677 ok(hr == DMUS_E_TRACK_NOT_FOUND, "GetParam failed: %#lx, expected DMUS_E_TRACK_NOT_FOUND\n", hr);
1678 hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, DMUS_SEG_ANYTRACK, 0,
1679 NULL, buf);
1680 ok(hr == DMUS_E_GET_UNSUPPORTED, "GetParam failed: %#lx, expected DMUS_E_GET_UNSUPPORTED\n", hr);
1682 hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, 0, 0, buf);
1683 ok(hr == S_OK, "SetParam failed: %#lx, expected S_OK\n", hr);
1684 hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, 1, 0, buf);
1685 todo_wine ok(hr == DMUS_E_TRACK_NOT_FOUND,
1686 "SetParam failed: %#lx, expected DMUS_E_TRACK_NOT_FOUND\n", hr);
1687 hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, DMUS_SEG_ALLTRACKS,
1688 0, buf);
1689 ok(hr == S_OK, "SetParam failed: %#lx, expected S_OK\n", hr);
1691 IDirectMusicSegment8_Release(seg);
1694 static void expect_getparam(IDirectMusicTrack *track, REFGUID type, const char *name,
1695 HRESULT expect)
1697 HRESULT hr;
1698 char buf[64] = { 0 };
1700 hr = IDirectMusicTrack_GetParam(track, type, 0, NULL, buf);
1701 ok(hr == expect, "GetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
1704 static void expect_setparam(IDirectMusicTrack *track, REFGUID type, const char *name,
1705 HRESULT expect)
1707 HRESULT hr;
1708 char buf[64] = { 0 };
1710 hr = IDirectMusicTrack_SetParam(track, type, 0, buf);
1711 ok(hr == expect, "SetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
1714 static void test_track(void)
1716 IDirectMusicTrack *dmt;
1717 IDirectMusicTrack8 *dmt8;
1718 IPersistStream *ps;
1719 CLSID classid;
1720 ULARGE_INTEGER size;
1721 HRESULT hr;
1722 #define X(guid) &guid, #guid
1723 const struct {
1724 REFGUID type;
1725 const char *name;
1726 } param_types[] = {
1727 { X(GUID_BandParam) },
1728 { X(GUID_ChordParam) },
1729 { X(GUID_Clear_All_Bands) },
1730 { X(GUID_CommandParam) },
1731 { X(GUID_CommandParam2) },
1732 { X(GUID_CommandParamNext) },
1733 { X(GUID_ConnectToDLSCollection) },
1734 { X(GUID_Disable_Auto_Download) },
1735 { X(GUID_DisableTempo) },
1736 { X(GUID_DisableTimeSig) },
1737 { X(GUID_Download) },
1738 { X(GUID_DownloadToAudioPath) },
1739 { X(GUID_Enable_Auto_Download) },
1740 { X(GUID_EnableTempo) },
1741 { X(GUID_EnableTimeSig) },
1742 { X(GUID_IDirectMusicBand) },
1743 { X(GUID_IDirectMusicChordMap) },
1744 { X(GUID_IDirectMusicStyle) },
1745 { X(GUID_MuteParam) },
1746 { X(GUID_Play_Marker) },
1747 { X(GUID_RhythmParam) },
1748 { X(GUID_SeedVariations) },
1749 { X(GUID_StandardMIDIFile) },
1750 { X(GUID_TempoParam) },
1751 { X(GUID_TimeSignature) },
1752 { X(GUID_Unload) },
1753 { X(GUID_UnloadFromAudioPath) },
1754 { X(GUID_Valid_Start_Time) },
1755 { X(GUID_Variations) },
1756 { X(GUID_NULL) }
1758 #undef X
1759 #define X(class) &CLSID_ ## class, #class
1760 const struct {
1761 REFCLSID clsid;
1762 const char *name;
1763 /* bitfield with supported param types */
1764 unsigned int has_params;
1765 } class[] = {
1766 { X(DirectMusicLyricsTrack), 0 },
1767 { X(DirectMusicMarkerTrack), 0x8080000 },
1768 { X(DirectMusicParamControlTrack), 0 },
1769 { X(DirectMusicSegmentTriggerTrack), 0x3fffffff },
1770 { X(DirectMusicSeqTrack), ~0 }, /* param methods not implemented */
1771 { X(DirectMusicSysExTrack), ~0 }, /* param methods not implemented */
1772 { X(DirectMusicTempoTrack), 0x802100 },
1773 { X(DirectMusicTimeSigTrack), 0x1004200 },
1774 { X(DirectMusicWaveTrack), 0x6001c80 }
1776 #undef X
1777 unsigned int i, j;
1779 for (i = 0; i < ARRAY_SIZE(class); i++) {
1780 trace("Testing %s\n", class[i].name);
1781 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
1782 (void**)&dmt);
1783 ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
1785 /* IDirectMusicTrack */
1786 if (class[i].has_params != ~0) {
1787 for (j = 0; j < ARRAY_SIZE(param_types); j++) {
1788 hr = IDirectMusicTrack_IsParamSupported(dmt, param_types[j].type);
1789 if (class[i].has_params & (1 << j)) {
1790 ok(hr == S_OK, "IsParamSupported(%s) failed: %#lx, expected S_OK\n",
1791 param_types[j].name, hr);
1792 if (class[i].clsid == &CLSID_DirectMusicSegmentTriggerTrack) {
1793 expect_getparam(dmt, param_types[j].type, param_types[j].name,
1794 DMUS_E_GET_UNSUPPORTED);
1795 expect_setparam(dmt, param_types[j].type, param_types[j].name, S_OK);
1796 } else if (class[i].clsid == &CLSID_DirectMusicMarkerTrack)
1797 expect_setparam(dmt, param_types[j].type, param_types[j].name,
1798 DMUS_E_SET_UNSUPPORTED);
1799 else if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
1800 expect_getparam(dmt, param_types[j].type, param_types[j].name,
1801 DMUS_E_GET_UNSUPPORTED);
1802 } else {
1803 ok(hr == DMUS_E_TYPE_UNSUPPORTED,
1804 "IsParamSupported(%s) failed: %#lx, expected DMUS_E_TYPE_UNSUPPORTED\n",
1805 param_types[j].name, hr);
1806 expect_getparam(dmt, param_types[j].type, param_types[j].name,
1807 DMUS_E_GET_UNSUPPORTED);
1808 if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
1809 expect_setparam(dmt, param_types[j].type, param_types[j].name,
1810 DMUS_E_TYPE_UNSUPPORTED);
1811 else
1812 expect_setparam(dmt, param_types[j].type, param_types[j].name,
1813 DMUS_E_SET_UNSUPPORTED);
1816 /* GetParam / SetParam for IsParamSupported supported types */
1817 if (class[i].clsid == &CLSID_DirectMusicTimeSigTrack) {
1818 expect_getparam(dmt, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
1819 DMUS_E_GET_UNSUPPORTED);
1820 expect_getparam(dmt, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
1821 DMUS_E_GET_UNSUPPORTED);
1822 expect_setparam(dmt, &GUID_TimeSignature, "GUID_TimeSignature",
1823 DMUS_E_SET_UNSUPPORTED);
1824 } else if (class[i].clsid == &CLSID_DirectMusicTempoTrack) {
1825 expect_getparam(dmt, &GUID_DisableTempo, "GUID_DisableTempo",
1826 DMUS_E_GET_UNSUPPORTED);
1827 expect_getparam(dmt, &GUID_EnableTempo, "GUID_EnableTempo",
1828 DMUS_E_GET_UNSUPPORTED);
1831 } else {
1832 hr = IDirectMusicTrack_GetParam(dmt, NULL, 0, NULL, NULL);
1833 ok(hr == E_NOTIMPL, "IDirectMusicTrack_GetParam failed: %#lx\n", hr);
1834 hr = IDirectMusicTrack_SetParam(dmt, NULL, 0, NULL);
1835 ok(hr == E_NOTIMPL, "IDirectMusicTrack_SetParam failed: %#lx\n", hr);
1836 hr = IDirectMusicTrack_IsParamSupported(dmt, NULL);
1837 ok(hr == E_NOTIMPL, "IDirectMusicTrack_IsParamSupported failed: %#lx\n", hr);
1839 hr = IDirectMusicTrack_IsParamSupported(dmt, &GUID_IDirectMusicStyle);
1840 ok(hr == E_NOTIMPL, "got: %#lx\n", hr);
1842 if (class[i].clsid != &CLSID_DirectMusicMarkerTrack &&
1843 class[i].clsid != &CLSID_DirectMusicTimeSigTrack) {
1844 hr = IDirectMusicTrack_AddNotificationType(dmt, NULL);
1845 ok(hr == E_NOTIMPL, "IDirectMusicTrack_AddNotificationType failed: %#lx\n", hr);
1846 hr = IDirectMusicTrack_RemoveNotificationType(dmt, NULL);
1847 ok(hr == E_NOTIMPL, "IDirectMusicTrack_RemoveNotificationType failed: %#lx\n", hr);
1849 hr = IDirectMusicTrack_Clone(dmt, 0, 0, NULL);
1850 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack_Clone failed: %#lx\n", hr);
1852 /* IDirectMusicTrack8 */
1853 hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IDirectMusicTrack8, (void**)&dmt8);
1854 if (hr == S_OK) {
1855 hr = IDirectMusicTrack8_PlayEx(dmt8, NULL, 0, 0, 0, 0, NULL, NULL, 0);
1856 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_PlayEx failed: %#lx\n", hr);
1857 if (class[i].has_params == ~0) {
1858 hr = IDirectMusicTrack8_GetParamEx(dmt8, NULL, 0, NULL, NULL, NULL, 0);
1859 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_GetParamEx failed: %#lx\n", hr);
1860 hr = IDirectMusicTrack8_SetParamEx(dmt8, NULL, 0, NULL, NULL, 0);
1861 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_SetParamEx failed: %#lx\n", hr);
1863 hr = IDirectMusicTrack8_Compose(dmt8, NULL, 0, NULL);
1864 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Compose failed: %#lx\n", hr);
1865 hr = IDirectMusicTrack8_Join(dmt8, NULL, 0, NULL, 0, NULL);
1866 if (class[i].clsid == &CLSID_DirectMusicTempoTrack)
1867 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
1868 else
1869 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
1870 IDirectMusicTrack8_Release(dmt8);
1873 /* IPersistStream */
1874 hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IPersistStream, (void**)&ps);
1875 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
1876 hr = IPersistStream_GetClassID(ps, &classid);
1877 ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
1878 ok(IsEqualGUID(&classid, class[i].clsid),
1879 "Expected class %s got %s\n", class[i].name, wine_dbgstr_guid(&classid));
1880 hr = IPersistStream_IsDirty(ps);
1881 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
1883 /* Unimplemented IPersistStream methods */
1884 hr = IPersistStream_GetSizeMax(ps, &size);
1885 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
1886 hr = IPersistStream_Save(ps, NULL, TRUE);
1887 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
1889 while (IDirectMusicTrack_Release(dmt));
1893 struct chunk {
1894 FOURCC id;
1895 DWORD size;
1896 FOURCC type;
1899 #define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
1901 /* Generate a RIFF file format stream from an array of FOURCC ids.
1902 RIFF and LIST need to be followed by the form type respectively list type,
1903 followed by the chunks of the list and terminated with 0. */
1904 static IStream *gen_riff_stream(const FOURCC *ids)
1906 static const LARGE_INTEGER zero;
1907 int level = -1;
1908 DWORD *sizes[4]; /* Stack for the sizes of RIFF and LIST chunks */
1909 char riff[1024];
1910 char *p = riff;
1911 struct chunk *ck;
1912 IStream *stream;
1914 do {
1915 ck = (struct chunk *)p;
1916 ck->id = *ids++;
1917 switch (ck->id) {
1918 case 0:
1919 *sizes[level] = p - (char *)sizes[level] - sizeof(DWORD);
1920 level--;
1921 break;
1922 case FOURCC_LIST:
1923 case FOURCC_RIFF:
1924 level++;
1925 sizes[level] = &ck->size;
1926 ck->type = *ids++;
1927 p += sizeof(*ck);
1928 break;
1929 case DMUS_FOURCC_GUID_CHUNK:
1930 ck->size = sizeof(GUID_NULL);
1931 p += CHUNK_HDR_SIZE;
1932 memcpy(p, &GUID_NULL, sizeof(GUID_NULL));
1933 p += ck->size;
1934 break;
1935 case DMUS_FOURCC_VERSION_CHUNK:
1937 DMUS_VERSION ver = {5, 8};
1939 ck->size = sizeof(ver);
1940 p += CHUNK_HDR_SIZE;
1941 memcpy(p, &ver, sizeof(ver));
1942 p += ck->size;
1943 break;
1945 default:
1947 /* Just convert the FOURCC id to a WCHAR string */
1948 WCHAR *s;
1950 ck->size = 5 * sizeof(WCHAR);
1951 p += CHUNK_HDR_SIZE;
1952 s = (WCHAR *)p;
1953 s[0] = (char)(ck->id);
1954 s[1] = (char)(ck->id >> 8);
1955 s[2] = (char)(ck->id >> 16);
1956 s[3] = (char)(ck->id >> 24);
1957 s[4] = 0;
1958 p += ck->size;
1961 } while (level >= 0);
1963 ck = (struct chunk *)riff;
1964 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1965 IStream_Write(stream, riff, ck->size + CHUNK_HDR_SIZE, NULL);
1966 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
1968 return stream;
1971 static void test_parsedescriptor(void)
1973 IDirectMusicObject *dmo;
1974 IStream *stream;
1975 DMUS_OBJECTDESC desc;
1976 HRESULT hr;
1977 DWORD valid;
1978 unsigned int i;
1979 /* fourcc ~0 will be replaced later on */
1980 FOURCC alldesc[] =
1982 FOURCC_RIFF, ~0, DMUS_FOURCC_CATEGORY_CHUNK, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST,
1983 DMUS_FOURCC_UNAM_CHUNK, DMUS_FOURCC_UCOP_CHUNK, DMUS_FOURCC_UCMT_CHUNK,
1984 DMUS_FOURCC_USBJ_CHUNK, 0, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK, 0
1986 FOURCC dupes[] =
1988 FOURCC_RIFF, ~0, DMUS_FOURCC_CATEGORY_CHUNK, DMUS_FOURCC_CATEGORY_CHUNK,
1989 DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK,
1990 DMUS_FOURCC_GUID_CHUNK, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, DMUS_FOURCC_UNAM_CHUNK, 0,
1991 FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, mmioFOURCC('I','N','A','M'), 0, 0
1993 FOURCC empty[] = {FOURCC_RIFF, ~0, 0};
1994 FOURCC inam[] = {FOURCC_RIFF, ~0, FOURCC_LIST, ~0, mmioFOURCC('I','N','A','M'), 0, 0};
1995 FOURCC noriff[] = {mmioFOURCC('J','U','N','K'), 0};
1996 #define X(class) &CLSID_ ## class, #class
1997 #define Y(form) form, #form
1998 const struct {
1999 REFCLSID clsid;
2000 const char *class;
2001 FOURCC form;
2002 const char *name;
2003 BOOL needs_size;
2004 } forms[] = {
2005 { X(DirectMusicSegment), Y(DMUS_FOURCC_SEGMENT_FORM), FALSE },
2006 { X(DirectMusicSegment), Y(mmioFOURCC('W','A','V','E')), FALSE },
2007 { X(DirectMusicAudioPathConfig), Y(DMUS_FOURCC_AUDIOPATH_FORM), TRUE },
2008 { X(DirectMusicGraph), Y(DMUS_FOURCC_TOOLGRAPH_FORM), TRUE },
2010 #undef X
2011 #undef Y
2013 for (i = 0; i < ARRAY_SIZE(forms); i++) {
2014 trace("Testing %s / %s\n", forms[i].class, forms[i].name);
2015 hr = CoCreateInstance(forms[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
2016 (void **)&dmo);
2017 if (hr != S_OK) {
2018 win_skip("Could not create %s object: %#lx\n", forms[i].class, hr);
2019 return;
2022 /* Nothing loaded */
2023 memset(&desc, 0, sizeof(desc));
2024 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
2025 if (forms[i].needs_size) {
2026 todo_wine ok(hr == E_INVALIDARG, "GetDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
2027 desc.dwSize = sizeof(desc);
2028 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
2030 ok(hr == S_OK, "GetDescriptor failed: %#lx, expected S_OK\n", hr);
2031 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
2032 desc.dwValidData);
2033 ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
2034 wine_dbgstr_guid(&desc.guidClass), forms[i].class);
2036 /* Empty RIFF stream */
2037 empty[1] = forms[i].form;
2038 stream = gen_riff_stream(empty);
2039 memset(&desc, 0, sizeof(desc));
2040 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2041 if (forms[i].needs_size) {
2042 ok(hr == E_INVALIDARG, "ParseDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
2043 desc.dwSize = sizeof(desc);
2044 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2046 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
2047 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
2048 desc.dwValidData);
2049 ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
2050 wine_dbgstr_guid(&desc.guidClass), forms[i].class);
2052 /* NULL pointers */
2053 memset(&desc, 0, sizeof(desc));
2054 desc.dwSize = sizeof(desc);
2055 hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, &desc);
2056 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
2057 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, NULL);
2058 if (forms[i].needs_size)
2059 ok(hr == E_INVALIDARG, "ParseDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
2060 else
2061 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
2062 hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, NULL);
2063 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
2064 IStream_Release(stream);
2066 /* Wrong form */
2067 empty[1] = DMUS_FOURCC_CONTAINER_FORM;
2068 stream = gen_riff_stream(empty);
2069 memset(&desc, 0, sizeof(desc));
2070 desc.dwSize = sizeof(desc);
2071 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2072 if (forms[i].needs_size)
2073 ok(hr == DMUS_E_CHUNKNOTFOUND,
2074 "ParseDescriptor failed: %#lx, expected DMUS_E_CHUNKNOTFOUND\n", hr);
2075 else
2076 ok(hr == E_FAIL, "ParseDescriptor failed: %#lx, expected E_FAIL\n", hr);
2077 ok(!desc.dwValidData, "Got valid data %#lx, expected 0\n", desc.dwValidData);
2078 IStream_Release(stream);
2080 /* Not a RIFF stream */
2081 stream = gen_riff_stream(noriff);
2082 memset(&desc, 0, sizeof(desc));
2083 desc.dwSize = sizeof(desc);
2084 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2085 if (forms[i].needs_size)
2086 ok(hr == DMUS_E_CHUNKNOTFOUND,
2087 "ParseDescriptor failed: %#lx, expected DMUS_E_CHUNKNOTFOUND\n", hr);
2088 else
2089 ok(hr == E_FAIL, "ParseDescriptor failed: %#lx, expected E_FAIL\n", hr);
2090 ok(!desc.dwValidData, "Got valid data %#lx, expected 0\n", desc.dwValidData);
2091 IStream_Release(stream);
2093 /* All desc chunks */
2094 alldesc[1] = forms[i].form;
2095 stream = gen_riff_stream(alldesc);
2096 memset(&desc, 0, sizeof(desc));
2097 desc.dwSize = sizeof(desc);
2098 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2099 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
2100 valid = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS | DMUS_OBJ_VERSION;
2101 if (forms[i].form != mmioFOURCC('W','A','V','E'))
2102 valid |= DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY;
2103 ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
2104 ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
2105 wine_dbgstr_guid(&desc.guidClass), forms[i].class);
2106 ok(IsEqualGUID(&desc.guidObject, &GUID_NULL), "Got object guid %s, expected GUID_NULL\n",
2107 wine_dbgstr_guid(&desc.guidClass));
2108 ok(desc.vVersion.dwVersionMS == 5 && desc.vVersion.dwVersionLS == 8,
2109 "Got version %lu.%lu, expected 5.8\n", desc.vVersion.dwVersionMS,
2110 desc.vVersion.dwVersionLS);
2111 if (forms[i].form != mmioFOURCC('W','A','V','E'))
2112 ok(!lstrcmpW(desc.wszName, L"UNAM"), "Got name '%s', expected 'UNAM'\n",
2113 wine_dbgstr_w(desc.wszName));
2114 IStream_Release(stream);
2116 /* Duplicated chunks */
2117 dupes[1] = forms[i].form;
2118 stream = gen_riff_stream(dupes);
2119 memset(&desc, 0, sizeof(desc));
2120 desc.dwSize = sizeof(desc);
2121 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2122 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
2123 ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
2124 IStream_Release(stream);
2126 /* UNFO list with INAM */
2127 inam[1] = forms[i].form;
2128 inam[3] = DMUS_FOURCC_UNFO_LIST;
2129 stream = gen_riff_stream(inam);
2130 memset(&desc, 0, sizeof(desc));
2131 desc.dwSize = sizeof(desc);
2132 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2133 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
2134 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
2135 desc.dwValidData);
2136 IStream_Release(stream);
2138 /* INFO list with INAM */
2139 inam[3] = DMUS_FOURCC_INFO_LIST;
2140 stream = gen_riff_stream(inam);
2141 memset(&desc, 0, sizeof(desc));
2142 desc.dwSize = sizeof(desc);
2143 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
2144 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
2145 valid = DMUS_OBJ_CLASS;
2146 if (forms[i].form == mmioFOURCC('W','A','V','E'))
2147 valid |= DMUS_OBJ_NAME;
2148 ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
2149 if (forms[i].form == mmioFOURCC('W','A','V','E'))
2150 ok(!lstrcmpW(desc.wszName, L"I"), "Got name '%s', expected 'I'\n",
2151 wine_dbgstr_w(desc.wszName));
2152 IStream_Release(stream);
2154 IDirectMusicObject_Release(dmo);
2158 static void test_performance_InitAudio(void)
2160 DMUS_PORTPARAMS params =
2162 .dwSize = sizeof(params),
2163 .dwValidParams = DMUS_PORTPARAMS_EFFECTS,
2164 .dwEffectFlags = 1,
2166 IDirectMusicPerformance8 *performance;
2167 IDirectMusic *dmusic;
2168 IDirectSound *dsound;
2169 IDirectMusicPort *port;
2170 IDirectMusicAudioPath *path;
2171 DWORD channel, group;
2172 HRESULT hr;
2173 ULONG ref;
2175 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
2176 &IID_IDirectMusicPerformance8, (void **)&performance);
2177 if (hr != S_OK) {
2178 win_skip("Cannot create DirectMusicPerformance object (%lx)\n", hr);
2179 CoUninitialize();
2180 return;
2183 dsound = NULL;
2184 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL,
2185 DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL);
2186 if (hr != S_OK) {
2187 IDirectMusicPerformance8_Release(performance);
2188 win_skip("InitAudio failed (%lx)\n", hr);
2189 return;
2192 hr = IDirectMusicPerformance8_PChannelInfo(performance, 128, &port, NULL, NULL);
2193 ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
2194 hr = IDirectMusicPerformance8_PChannelInfo(performance, 127, &port, NULL, NULL);
2195 ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
2196 IDirectMusicPort_Release(port);
2197 port = NULL;
2198 hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL);
2199 ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
2200 ok(port != NULL, "IDirectMusicPort not set\n");
2201 hr = IDirectMusicPerformance8_AssignPChannel(performance, 0, port, 0, 0);
2202 ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr);
2203 hr = IDirectMusicPerformance8_AssignPChannelBlock(performance, 0, port, 0);
2204 ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr);
2205 IDirectMusicPort_Release(port);
2207 hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &path);
2208 ok(hr == S_OK, "Failed to call GetDefaultAudioPath (%lx)\n", hr);
2209 if (hr == S_OK)
2210 IDirectMusicAudioPath_Release(path);
2212 hr = IDirectMusicPerformance8_CloseDown(performance);
2213 ok(hr == S_OK, "Failed to call CloseDown (%lx)\n", hr);
2215 IDirectMusicPerformance8_Release(performance);
2217 /* Auto generated dmusic and dsound */
2218 create_performance(&performance, NULL, NULL, FALSE);
2219 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, 0, 64, 0, NULL);
2220 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2221 hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL);
2222 ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
2223 destroy_performance(performance, NULL, NULL);
2225 /* Refcounts for auto generated dmusic and dsound */
2226 create_performance(&performance, NULL, NULL, FALSE);
2227 dmusic = NULL;
2228 dsound = NULL;
2229 hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
2230 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2231 ref = get_refcount(dsound);
2232 ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
2233 ref = get_refcount(dmusic);
2234 ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
2235 destroy_performance(performance, NULL, NULL);
2237 /* dsound without SetCooperativeLevel() */
2238 create_performance(&performance, NULL, &dsound, FALSE);
2239 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
2240 todo_wine ok(hr == DSERR_PRIOLEVELNEEDED, "InitAudio failed: %#lx\n", hr);
2241 destroy_performance(performance, NULL, dsound);
2243 /* Using the wrong CLSID_DirectSound */
2244 create_performance(&performance, NULL, NULL, FALSE);
2245 hr = DirectSoundCreate(NULL, &dsound, NULL);
2246 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
2247 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
2248 todo_wine ok(hr == E_NOINTERFACE, "InitAudio failed: %#lx\n", hr);
2249 destroy_performance(performance, NULL, dsound);
2251 /* Init() works with just a CLSID_DirectSound */
2252 create_performance(&performance, NULL, NULL, FALSE);
2253 hr = DirectSoundCreate(NULL, &dsound, NULL);
2254 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
2255 hr = IDirectSound_SetCooperativeLevel(dsound, GetForegroundWindow(), DSSCL_PRIORITY);
2256 ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr);
2257 hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL);
2258 ok(hr == S_OK, "Init failed: %#lx\n", hr);
2259 destroy_performance(performance, NULL, dsound);
2261 /* Init() followed by InitAudio() */
2262 create_performance(&performance, NULL, &dsound, TRUE);
2263 hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL);
2264 ok(hr == S_OK, "Init failed: %#lx\n", hr);
2265 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
2266 ok(hr == DMUS_E_ALREADY_INITED, "InitAudio failed: %#lx\n", hr);
2267 destroy_performance(performance, NULL, dsound);
2269 /* Provided dmusic and dsound */
2270 create_performance(&performance, &dmusic, &dsound, TRUE);
2271 hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
2272 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2273 ref = get_refcount(dsound);
2274 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
2275 ref = get_refcount(dmusic);
2276 ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
2277 destroy_performance(performance, dmusic, dsound);
2279 /* Provided dmusic initialized with SetDirectSound */
2280 create_performance(&performance, &dmusic, &dsound, TRUE);
2281 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
2282 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
2283 ref = get_refcount(dsound);
2284 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
2285 hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, NULL, NULL, 0, 64, 0, NULL);
2286 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2287 ref = get_refcount(dsound);
2288 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
2289 ref = get_refcount(dmusic);
2290 ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
2291 destroy_performance(performance, dmusic, dsound);
2293 /* Provided dmusic and dsound, dmusic initialized with SetDirectSound */
2294 create_performance(&performance, &dmusic, &dsound, TRUE);
2295 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
2296 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
2297 ref = get_refcount(dsound);
2298 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
2299 hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
2300 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2301 ref = get_refcount(dsound);
2302 ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
2303 ref = get_refcount(dmusic);
2304 ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
2305 destroy_performance(performance, dmusic, dsound);
2307 /* Provided dmusic and dsound, dmusic initialized with SetDirectSound, port created and activated */
2308 create_performance(&performance, &dmusic, &dsound, TRUE);
2309 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
2310 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
2311 hr = IDirectMusic_CreatePort(dmusic, &CLSID_DirectMusicSynth, &params, &port, NULL);
2312 ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
2313 hr = IDirectMusicPort_Activate(port, TRUE);
2314 ok(hr == S_OK, "Activate failed: %#lx\n", hr);
2315 hr = IDirectMusicPort_SetNumChannelGroups(port, 1);
2316 ok(hr == S_OK, "SetNumChannelGroups failed: %#lx\n", hr);
2317 hr = IDirectMusicPerformance8_Init(performance, &dmusic, dsound, 0);
2318 ok(hr == S_OK, "Init failed: %#lx\n", hr);
2319 destroy_performance(performance, dmusic, dsound);
2321 /* InitAudio with perf channel count not a multiple of 16 rounds up */
2322 create_performance(&performance, NULL, NULL, TRUE);
2323 hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL,
2324 DMUS_APATH_SHARED_STEREOPLUSREVERB, 29, DMUS_AUDIOF_ALL, NULL);
2325 ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
2326 hr = IDirectMusicPerformance8_PChannelInfo(performance, 31, &port, &group, &channel);
2327 ok(hr == S_OK && group == 2 && channel == 15,
2328 "PChannelInfo failed, got %#lx, %lu, %lu\n", hr, group, channel);
2329 hr = IDirectMusicPerformance8_PChannelInfo(performance, 32, &port, NULL, NULL);
2330 ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
2331 destroy_performance(performance, NULL, NULL);
2334 static void test_performance_createport(void)
2336 IDirectMusicPerformance8 *perf;
2337 IDirectMusic *music = NULL;
2338 IDirectMusicPort *port = NULL;
2339 DMUS_PORTCAPS portcaps;
2340 DMUS_PORTPARAMS portparams;
2341 DWORD i;
2342 HRESULT hr;
2344 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL,
2345 CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance8, (void**)&perf);
2346 ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr);
2348 hr = IDirectMusicPerformance8_Init(perf, &music, NULL, NULL);
2349 ok(hr == S_OK, "Init failed: %#lx\n", hr);
2350 ok(music != NULL, "Didn't get IDirectMusic pointer\n");
2352 i = 0;
2353 while(1){
2354 portcaps.dwSize = sizeof(portcaps);
2356 hr = IDirectMusic_EnumPort(music, i, &portcaps);
2357 ok(hr == S_OK || hr == S_FALSE || (i == 0 && hr == E_INVALIDARG), "EnumPort failed: %#lx\n", hr);
2358 if(hr != S_OK)
2359 break;
2361 ok(portcaps.dwSize == sizeof(portcaps), "Got unexpected portcaps struct size: %lu\n", portcaps.dwSize);
2362 trace("portcaps(%lu).dwFlags: %#lx\n", i, portcaps.dwFlags);
2363 trace("portcaps(%lu).guidPort: %s\n", i, wine_dbgstr_guid(&portcaps.guidPort));
2364 trace("portcaps(%lu).dwClass: %#lx\n", i, portcaps.dwClass);
2365 trace("portcaps(%lu).dwType: %#lx\n", i, portcaps.dwType);
2366 trace("portcaps(%lu).dwMemorySize: %#lx\n", i, portcaps.dwMemorySize);
2367 trace("portcaps(%lu).dwMaxChannelGroups: %lu\n", i, portcaps.dwMaxChannelGroups);
2368 trace("portcaps(%lu).dwMaxVoices: %lu\n", i, portcaps.dwMaxVoices);
2369 trace("portcaps(%lu).dwMaxAudioChannels: %lu\n", i, portcaps.dwMaxAudioChannels);
2370 trace("portcaps(%lu).dwEffectFlags: %#lx\n", i, portcaps.dwEffectFlags);
2371 trace("portcaps(%lu).wszDescription: %s\n", i, wine_dbgstr_w(portcaps.wszDescription));
2373 ++i;
2376 if(i == 0){
2377 win_skip("No ports available, skipping tests\n");
2378 return;
2381 portparams.dwSize = sizeof(portparams);
2383 /* dwValidParams == 0 -> S_OK, filled struct */
2384 portparams.dwValidParams = 0;
2385 hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
2386 ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
2387 ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
2388 ok(portparams.dwValidParams, "portparams struct was not filled in\n");
2389 IDirectMusicPort_Release(port);
2390 port = NULL;
2392 /* dwValidParams != 0, invalid param -> S_FALSE, filled struct */
2393 portparams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
2394 portparams.dwChannelGroups = 0;
2395 hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
2396 todo_wine ok(hr == S_FALSE, "CreatePort failed: %#lx\n", hr);
2397 ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
2398 ok(portparams.dwValidParams, "portparams struct was not filled in\n");
2399 IDirectMusicPort_Release(port);
2400 port = NULL;
2402 /* dwValidParams != 0, valid params -> S_OK */
2403 hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
2404 ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
2405 ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
2406 IDirectMusicPort_Release(port);
2407 port = NULL;
2409 /* GUID_NULL succeeds */
2410 portparams.dwValidParams = 0;
2411 hr = IDirectMusic_CreatePort(music, &GUID_NULL, &portparams, &port, NULL);
2412 ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
2413 ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
2414 ok(portparams.dwValidParams, "portparams struct was not filled in\n");
2415 IDirectMusicPort_Release(port);
2416 port = NULL;
2418 /* null GUID fails */
2419 portparams.dwValidParams = 0;
2420 hr = IDirectMusic_CreatePort(music, NULL, &portparams, &port, NULL);
2421 ok(hr == E_POINTER, "CreatePort failed: %#lx\n", hr);
2422 ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port);
2423 ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n");
2425 /* garbage GUID fails */
2426 portparams.dwValidParams = 0;
2427 hr = IDirectMusic_CreatePort(music, &GUID_Bunk, &portparams, &port, NULL);
2428 ok(hr == E_NOINTERFACE, "CreatePort failed: %#lx\n", hr);
2429 ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port);
2430 ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n");
2432 hr = IDirectMusicPerformance8_CloseDown(perf);
2433 ok(hr == S_OK, "CloseDown failed: %#lx\n", hr);
2435 IDirectMusic_Release(music);
2436 IDirectMusicPerformance8_Release(perf);
2439 static void test_performance_pchannel(void)
2441 IDirectMusicPerformance8 *perf;
2442 IDirectMusicPort *port = NULL, *port2;
2443 DWORD channel, group;
2444 unsigned int i;
2445 HRESULT hr;
2447 create_performance(&perf, NULL, NULL, TRUE);
2448 hr = IDirectMusicPerformance8_Init(perf, NULL, NULL, NULL);
2449 ok(hr == S_OK, "Init failed: %#lx\n", hr);
2450 hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL);
2451 ok(hr == E_INVALIDARG && !port, "PChannelInfo failed, got %#lx, %p\n", hr, port);
2453 /* Add default port. Sets PChannels 0-15 to the corresponding channels in group 1 */
2454 hr = IDirectMusicPerformance8_AddPort(perf, NULL);
2455 ok(hr == S_OK, "AddPort of default port failed: %#lx\n", hr);
2456 hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, NULL, NULL, NULL);
2457 ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
2458 hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL);
2459 ok(hr == S_OK && port, "PChannelInfo failed, got %#lx, %p\n", hr, port);
2460 for (i = 1; i < 16; i++) {
2461 hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
2462 ok(hr == S_OK && port == port2 && group == 1 && channel == i,
2463 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2464 IDirectMusicPort_Release(port2);
2467 /* Unset PChannels fail to retrieve */
2468 hr = IDirectMusicPerformance8_PChannelInfo(perf, 16, &port2, NULL, NULL);
2469 ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port);
2470 hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD - 16, &port2, NULL, NULL);
2471 ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port);
2473 /* Channel group 0 can be set just fine */
2474 hr = IDirectMusicPerformance8_AssignPChannel(perf, 0, port, 0, 0);
2475 ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
2476 hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, 0, port, 0);
2477 ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr);
2478 for (i = 1; i < 16; i++) {
2479 hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
2480 ok(hr == S_OK && port == port2 && group == 0 && channel == i,
2481 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2482 IDirectMusicPort_Release(port2);
2485 /* Last PChannel Block can be set only individually but not read */
2486 hr = IDirectMusicPerformance8_AssignPChannel(perf, MAXDWORD, port, 0, 3);
2487 ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
2488 port2 = (IDirectMusicPort *)0xdeadbeef;
2489 hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD, &port2, NULL, NULL);
2490 todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef,
2491 "PChannelInfo failed, got %#lx, %p\n", hr, port2);
2492 hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD, port, 0);
2493 ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
2494 hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16, port, 1);
2495 todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
2496 for (i = MAXDWORD - 15; i < MAXDWORD; i++) {
2497 hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 0, 0);
2498 ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
2499 hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, NULL, NULL);
2500 todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef,
2501 "PChannelInfo failed, got %#lx, %p\n", hr, port2);
2504 /* Second to last PChannel Block can be set only individually and read */
2505 hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 1, port, 1);
2506 todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
2507 for (i = MAXDWORD - 31; i < MAXDWORD - 15; i++) {
2508 hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 1, 7);
2509 ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
2510 hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
2511 ok(hr == S_OK && port2 == port && group == 1 && channel == 7,
2512 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2513 IDirectMusicPort_Release(port2);
2516 /* Third to last PChannel Block behaves normal */
2517 hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 2, port, 0);
2518 ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr);
2519 for (i = MAXDWORD - 47; i < MAXDWORD - 31; i++) {
2520 hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
2521 ok(hr == S_OK && port2 == port && group == 0 && channel == i % 16,
2522 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2523 IDirectMusicPort_Release(port2);
2526 /* One PChannel set in a Block, rest is initialized too */
2527 hr = IDirectMusicPerformance8_AssignPChannel(perf, 4711, port, 1, 13);
2528 ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
2529 hr = IDirectMusicPerformance8_PChannelInfo(perf, 4711, &port2, &group, &channel);
2530 ok(hr == S_OK && port2 == port && group == 1 && channel == 13,
2531 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2532 IDirectMusicPort_Release(port2);
2533 group = channel = 0xdeadbeef;
2534 hr = IDirectMusicPerformance8_PChannelInfo(perf, 4712, &port2, &group, &channel);
2535 ok(hr == S_OK && port2 == port && group == 0 && channel == 8,
2536 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2537 IDirectMusicPort_Release(port2);
2538 group = channel = 0xdeadbeef;
2539 hr = IDirectMusicPerformance8_PChannelInfo(perf, 4719, &port2, &group, &channel);
2540 ok(hr == S_OK && port2 == port && group == 0 && channel == 15,
2541 "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
2542 IDirectMusicPort_Release(port2);
2544 IDirectMusicPort_Release(port);
2545 destroy_performance(perf, NULL, NULL);
2548 static void test_performance_tool(void)
2550 DMUS_NOTE_PMSG note60 =
2552 .dwSize = sizeof(DMUS_NOTE_PMSG),
2553 .dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE,
2554 .dwVirtualTrackID = 1,
2555 .dwType = DMUS_PMSGT_NOTE,
2556 .dwGroupID = 1,
2557 .mtDuration = 1000,
2558 .wMusicValue = 60,
2559 .bVelocity = 127,
2560 .bFlags = DMUS_NOTEF_NOTEON,
2561 .bPlayModeFlags = DMUS_PLAYMODE_FIXED,
2562 .bMidiValue = 60,
2564 IDirectMusicPerformance *performance;
2565 IDirectMusicGraph *graph;
2566 IDirectMusicTool *tool;
2567 DWORD value, types[1];
2568 DMUS_NOTE_PMSG *note;
2569 DMUS_PMSG msg = {0};
2570 HRESULT hr;
2572 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
2573 &IID_IDirectMusicPerformance, (void **)&performance);
2574 ok(hr == S_OK, "got %#lx\n", hr);
2576 check_interface(performance, &IID_IDirectMusicTool8, FALSE);
2578 hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicTool, (void **)&tool);
2579 ok(hr == S_OK, "got %#lx\n", hr);
2580 hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
2581 ok(hr == S_OK, "got %#lx\n", hr);
2583 hr = IDirectMusicTool_Init(tool, graph);
2584 ok(hr == E_NOTIMPL, "got %#lx\n", hr);
2585 value = 0xdeadbeef;
2586 hr = IDirectMusicTool_GetMsgDeliveryType(tool, &value);
2587 ok(hr == S_OK, "got %#lx\n", hr);
2588 ok(value == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", value);
2589 value = 0xdeadbeef;
2590 hr = IDirectMusicTool_GetMediaTypeArraySize(tool, &value);
2591 ok(hr == S_OK, "got %#lx\n", hr);
2592 ok(value == 0, "got %#lx\n", value);
2593 hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64);
2594 ok(hr == E_NOTIMPL, "got %#lx\n", hr);
2595 hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg);
2596 ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
2597 hr = IDirectMusicTool_Flush(tool, performance, &msg, 0);
2598 todo_wine ok(hr == S_OK, "got %#lx\n", hr);
2600 hr = IDirectMusicPerformance_Init(performance, NULL, NULL, NULL);
2601 ok(hr == S_OK, "got %#lx\n", hr);
2603 hr = IDirectMusicPerformance_AddPort(performance, NULL);
2604 ok(hr == S_OK, "got %#lx\n", hr);
2606 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_NOTE_PMSG), (DMUS_PMSG **)&note);
2607 ok(hr == S_OK, "got %#lx\n", hr);
2609 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2610 ok(hr == S_OK, "got %#lx\n", hr);
2611 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2612 ok(hr == S_OK, "got %#lx\n", hr);
2614 *note = note60;
2615 note->bFlags = 0;
2616 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2617 ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
2619 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2620 ok(hr == S_OK, "got %#lx\n", hr);
2621 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2622 ok(hr == S_OK, "got %#lx\n", hr);
2624 *note = note60;
2625 note->mtDuration = 0;
2626 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2627 ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
2629 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2630 ok(hr == S_OK, "got %#lx\n", hr);
2631 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2632 ok(hr == S_OK, "got %#lx\n", hr);
2634 *note = note60;
2635 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2636 ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
2637 ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0,
2638 "got %I64d\n", note->rtTime - note60.rtTime);
2639 ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime);
2640 check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0);
2642 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2643 ok(hr == S_OK, "got %#lx\n", hr);
2644 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2645 ok(hr == S_OK, "got %#lx\n", hr);
2647 *note = note60;
2648 note->nOffset = 1000;
2649 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2650 ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
2651 ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0,
2652 "got %I64d\n", note->rtTime - note60.rtTime);
2653 ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime);
2654 check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0);
2656 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2657 ok(hr == S_OK, "got %#lx\n", hr);
2658 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2659 ok(hr == S_OK, "got %#lx\n", hr);
2661 *note = note60;
2662 note->mtDuration = 2;
2663 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2664 ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
2665 ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0,
2666 "got %I64d\n", note->rtTime - note60.rtTime);
2667 ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime);
2668 check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0);
2670 hr = IDirectMusicPerformance_GetTime(performance, NULL, &note60.mtTime);
2671 ok(hr == S_OK, "got %#lx\n", hr);
2672 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, &note60.rtTime);
2673 ok(hr == S_OK, "got %#lx\n", hr);
2675 *note = note60;
2676 note->mtDuration = 1;
2677 hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
2678 ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
2679 ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0,
2680 "got %I64d\n", note->rtTime - note60.rtTime);
2681 ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime);
2682 check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 1, 60, 127, 0);
2684 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
2685 ok(hr == S_OK, "got %#lx\n", hr);
2687 hr = IDirectMusicPerformance_CloseDown(performance);
2688 ok(hr == S_OK, "got %#lx\n", hr);
2690 IDirectMusicGraph_Release(graph);
2691 IDirectMusicTool_Release(tool);
2693 IDirectMusicPerformance_Release(performance);
2696 static void test_performance_graph(void)
2698 IDirectMusicPerformance *performance;
2699 IDirectMusicGraph *graph, *tmp_graph;
2700 IDirectMusicTool *tool, *tmp_tool;
2701 DMUS_PMSG msg;
2702 HRESULT hr;
2704 hr = test_tool_create(NULL, 0, &tool);
2705 ok(hr == S_OK, "got %#lx\n", hr);
2707 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
2708 &IID_IDirectMusicPerformance, (void **)&performance);
2709 ok(hr == S_OK, "got %#lx\n", hr);
2712 /* performance exposes a graph interface but it's not an actual toolgraph */
2713 hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
2714 ok(hr == S_OK, "got %#lx\n", hr);
2715 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
2716 ok(hr == E_NOTIMPL, "got %#lx\n", hr);
2717 hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
2718 ok(hr == E_NOTIMPL, "got %#lx\n", hr);
2719 hr = IDirectMusicGraph_RemoveTool(graph, tool);
2720 ok(hr == E_NOTIMPL, "got %#lx\n", hr);
2722 /* test IDirectMusicGraph_StampPMsg usage */
2723 hr = IDirectMusicGraph_StampPMsg(graph, NULL);
2724 ok(hr == E_POINTER, "got %#lx\n", hr);
2725 memset(&msg, 0, sizeof(msg));
2726 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
2727 ok(hr == S_OK, "got %#lx\n", hr);
2728 ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
2729 ok(msg.pTool != NULL, "got %p\n", msg.pTool);
2730 check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
2732 ok(!msg.dwSize, "got %ld\n", msg.dwSize);
2733 ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
2734 ok(!msg.mtTime, "got %ld\n", msg.mtTime);
2735 ok(msg.dwFlags == DMUS_PMSGF_TOOL_QUEUE, "got %#lx\n", msg.dwFlags);
2736 ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
2737 ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
2738 ok(!msg.dwType, "got %#lx\n", msg.dwType);
2739 ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
2740 ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
2741 ok(!msg.punkUser, "got %p\n", msg.punkUser);
2743 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
2744 ok(hr == S_OK, "got %#lx\n", hr);
2745 ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
2746 ok(msg.pTool != NULL, "got %p\n", msg.pTool);
2747 check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
2749 IDirectMusicTool_Release(msg.pTool);
2750 msg.pTool = NULL;
2752 IDirectMusicGraph_Release(graph);
2755 /* performance doesn't have a default embedded toolgraph */
2756 hr = IDirectMusicPerformance_GetGraph(performance, &graph);
2757 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
2760 /* test adding a graph to the performance */
2761 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
2762 &IID_IDirectMusicGraph, (void **)&graph);
2763 ok(hr == S_OK, "got %#lx\n", hr);
2764 hr = IDirectMusicPerformance_SetGraph(performance, graph);
2765 ok(hr == S_OK, "got %#lx\n", hr);
2767 hr = IDirectMusicPerformance_GetGraph(performance, &tmp_graph);
2768 ok(hr == S_OK, "got %#lx\n", hr);
2769 ok(tmp_graph == graph, "got %p\n", graph);
2770 IDirectMusicGraph_Release(tmp_graph);
2772 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
2773 ok(hr == S_OK, "got %#lx\n", hr);
2775 IDirectMusicGraph_Release(graph);
2778 /* test IDirectMusicGraph_StampPMsg usage */
2779 hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
2780 ok(hr == S_OK, "got %#lx\n", hr);
2782 memset(&msg, 0, sizeof(msg));
2783 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
2784 ok(hr == S_OK, "got %#lx\n", hr);
2785 ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
2786 ok(msg.pTool == tool, "got %p\n", msg.pTool);
2788 ok(!msg.dwSize, "got %ld\n", msg.dwSize);
2789 ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
2790 ok(!msg.mtTime, "got %ld\n", msg.mtTime);
2791 ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags);
2792 ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
2793 ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
2794 ok(!msg.dwType, "got %#lx\n", msg.dwType);
2795 ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
2796 ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
2797 ok(!msg.punkUser, "got %p\n", msg.punkUser);
2799 hr = IDirectMusicGraph_StampPMsg(graph, &msg);
2800 ok(hr == S_OK, "got %#lx\n", hr);
2801 ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
2802 ok(msg.pTool != NULL, "got %p\n", msg.pTool);
2803 check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
2805 IDirectMusicTool_Release(msg.pTool);
2806 msg.pTool = NULL;
2808 IDirectMusicGraph_Release(graph);
2811 IDirectMusicPerformance_Release(performance);
2812 IDirectMusicTool_Release(tool);
2815 #define check_music_time(a, b) check_music_time_(__LINE__, a, b)
2816 static void check_music_time_(int line, MUSIC_TIME time, MUSIC_TIME expect)
2818 ok_(__FILE__, line)(abs(time - expect) <= 1, "got %ld, expected %ld\n", time, expect);
2821 static void test_performance_time(void)
2823 IDirectMusicPerformance *performance;
2824 REFERENCE_TIME init_time, time;
2825 IReferenceClock *clock;
2826 MUSIC_TIME music_time;
2827 IDirectMusic *dmusic;
2828 HRESULT hr;
2830 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
2831 &IID_IDirectMusicPerformance, (void **)&performance);
2832 ok(hr == S_OK, "got %#lx\n", hr);
2835 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, NULL);
2836 ok(hr == E_POINTER, "got %#lx\n", hr);
2837 time = 0xdeadbeef;
2838 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
2839 ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
2840 ok(time == 0, "got %I64d\n", time);
2842 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, NULL);
2843 ok(hr == E_POINTER, "got %#lx\n", hr);
2844 music_time = 0xdeadbeef;
2845 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, &music_time);
2846 ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
2847 ok(music_time == 0, "got %ld\n", music_time);
2850 dmusic = NULL;
2851 hr = IDirectMusicPerformance_Init(performance, &dmusic, NULL, NULL);
2852 ok(hr == S_OK, "got %#lx\n", hr);
2853 hr = IDirectMusic_GetMasterClock(dmusic, NULL, &clock);
2854 ok(hr == S_OK, "got %#lx\n", hr);
2855 IDirectMusic_Release(dmusic);
2856 hr = IReferenceClock_GetTime(clock, &init_time);
2857 ok(hr == S_OK, "got %#lx\n", hr);
2858 IReferenceClock_Release(clock);
2861 time = 0xdeadbeef;
2862 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
2863 ok(hr == S_OK, "got %#lx\n", hr);
2864 ok(time - init_time <= 100 * 10000, "got %I64d\n", time - init_time);
2865 init_time = time;
2867 time = 0xdeadbeef;
2868 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time);
2869 ok(hr == S_OK, "got %#lx\n", hr);
2870 check_music_time(time - init_time, scale_music_time(1, 120));
2871 time = 0xdeadbeef;
2872 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time);
2873 ok(hr == S_OK, "got %#lx\n", hr);
2874 check_music_time(time - init_time, scale_music_time(1000, 120));
2875 time = 0xdeadbeef;
2876 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time);
2877 ok(hr == S_OK, "got %#lx\n", hr);
2878 check_music_time(time - init_time, scale_music_time(2000, 120));
2880 music_time = 0xdeadbeef;
2881 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time);
2882 ok(hr == S_OK, "got %#lx\n", hr);
2883 ok(music_time == 0, "got %ld\n", music_time);
2884 music_time = 0xdeadbeef;
2885 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(1000, 120), &music_time);
2886 ok(hr == S_OK, "got %#lx\n", hr);
2887 ok(music_time == 1000, "got %ld\n", music_time);
2888 music_time = 0xdeadbeef;
2889 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(2000, 120), &music_time);
2890 ok(hr == S_OK, "got %#lx\n", hr);
2891 ok(music_time == 2000, "got %ld\n", music_time);
2893 time = 0xdeadbeef;
2894 music_time = 0xdeadbeef;
2895 hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time);
2896 ok(hr == S_OK, "got %#lx\n", hr);
2897 ok(time - init_time <= 200 * 10000, "got %I64d\n", time - init_time);
2898 ok(music_time == (time - init_time) / 6510, "got %ld\n", music_time);
2901 hr = IDirectMusicPerformance_CloseDown(performance);
2902 ok(hr == S_OK, "got %#lx\n", hr);
2904 IDirectMusicPerformance_Release(performance);
2908 static void test_performance_pmsg(void)
2910 static const DWORD delivery_flags[] = {DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGF_TOOL_ATTIME};
2911 static const DWORD message_types[] = {DMUS_PMSGT_MIDI, DMUS_PMSGT_USER};
2912 IDirectMusicPerformance *performance;
2913 IDirectMusicGraph *graph, *performance_graph;
2914 IDirectMusicTool *tool;
2915 DMUS_PMSG *msg, *clone;
2916 MUSIC_TIME music_time;
2917 REFERENCE_TIME time;
2918 HRESULT hr;
2919 DWORD ret;
2920 UINT i;
2922 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
2923 ok(hr == S_OK, "got %#lx\n", hr);
2925 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
2926 &IID_IDirectMusicPerformance, (void **)&performance);
2927 ok(hr == S_OK, "got %#lx\n", hr);
2928 hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&performance_graph);
2929 ok(hr == S_OK, "got %#lx\n", hr);
2932 hr = IDirectMusicPerformance_AllocPMsg(performance, 0, NULL);
2933 ok(hr == E_POINTER, "got %#lx\n", hr);
2934 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG) - 1, &msg);
2935 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2937 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
2938 ok(hr == S_OK, "got %#lx\n", hr);
2939 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
2940 ok(!msg->rtTime, "got %I64d\n", msg->rtTime);
2941 ok(!msg->mtTime, "got %ld\n", msg->mtTime);
2942 ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags);
2943 ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
2944 ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
2945 ok(!msg->dwType, "got %#lx\n", msg->dwType);
2946 ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
2947 ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
2948 ok(!msg->punkUser, "got %p\n", msg->punkUser);
2950 hr = IDirectMusicPerformance_SendPMsg(performance, NULL);
2951 ok(hr == E_POINTER, "got %#lx\n", hr);
2952 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
2953 ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
2955 hr = IDirectMusicPerformance_FreePMsg(performance, NULL);
2956 ok(hr == E_POINTER, "got %#lx\n", hr);
2957 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
2958 ok(hr == S_OK, "got %#lx\n", hr);
2961 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
2962 ok(hr == S_OK, "got %#lx\n", hr);
2964 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
2965 &IID_IDirectMusicGraph, (void **)&graph);
2966 ok(hr == S_OK, "got %#lx\n", hr);
2967 hr = IDirectMusicPerformance_SetGraph(performance, graph);
2968 ok(hr == S_OK, "got %#lx\n", hr);
2969 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
2970 ok(hr == S_OK, "got %#lx\n", hr);
2971 IDirectMusicGraph_Release(graph);
2973 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
2974 ok(hr == S_OK, "got %#lx\n", hr);
2975 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
2976 ok(!msg->rtTime, "got %I64d\n", msg->rtTime);
2977 ok(!msg->mtTime, "got %ld\n", msg->mtTime);
2978 ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags);
2979 ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
2980 ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
2981 ok(!msg->pTool, "got %p\n", msg->pTool);
2982 ok(!msg->pGraph, "got %p\n", msg->pGraph);
2983 ok(!msg->dwType, "got %#lx\n", msg->dwType);
2984 ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
2985 ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
2986 ok(!msg->punkUser, "got %p\n", msg->punkUser);
2987 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
2988 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2990 hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, NULL);
2991 ok(hr == E_POINTER, "got %#lx\n", hr);
2992 hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, NULL, &clone);
2993 ok(hr == E_POINTER, "got %#lx\n", hr);
2994 clone = NULL;
2995 hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone);
2996 ok(hr == S_OK, "got %#lx\n", hr);
2997 ok(clone != NULL, "got %p\n", clone);
2999 msg->mtTime = 500;
3000 msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE;
3001 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3002 ok(hr == S_OK, "got %#lx\n", hr);
3003 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3004 ok(hr == DMUS_E_ALREADY_SENT, "got %#lx\n", hr);
3005 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3006 ok(hr == DMUS_E_CANNOT_FREE, "got %#lx\n", hr);
3008 hr = IDirectMusicPerformance_FreePMsg(performance, clone);
3009 ok(hr == S_OK, "got %#lx\n", hr);
3012 /* SendPMsg skips all the tools unless messages are stamped beforehand */
3014 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
3015 ok(hr == S_OK, "got %#lx\n", hr);
3016 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3017 msg->mtTime = 0;
3018 msg->dwFlags = DMUS_PMSGF_MUSICTIME;
3019 msg->dwType = DMUS_PMSGT_USER;
3020 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3021 ok(hr == S_OK, "got %#lx\n", hr);
3023 ret = test_tool_wait_message(tool, 10, &msg);
3024 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3025 ok(!msg, "got %p\n", msg);
3028 /* SendPMsg converts music time to reference time if it is missing */
3030 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
3031 ok(hr == S_OK, "got %#lx\n", hr);
3032 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3033 msg->mtTime = 500;
3034 msg->dwFlags = DMUS_PMSGF_MUSICTIME;
3035 msg->dwType = DMUS_PMSGT_USER;
3036 hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
3037 ok(hr == S_OK, "got %#lx\n", hr);
3038 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3039 ok(hr == S_OK, "got %#lx\n", hr);
3041 ret = test_tool_wait_message(tool, 50, &msg);
3042 ok(!ret, "got %#lx\n", ret);
3043 ok(msg != NULL, "got %p\n", msg);
3045 time = 0xdeadbeef;
3046 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time);
3047 ok(hr == S_OK, "got %#lx\n", hr);
3048 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3049 ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
3050 ok(msg->mtTime == 500, "got %ld\n", msg->mtTime);
3051 ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
3052 ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
3053 ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
3054 ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
3055 ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
3056 ok(msg->pTool == tool, "got %p\n", msg->pTool);
3057 ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph);
3058 ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType);
3059 ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
3060 ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
3061 ok(!msg->punkUser, "got %p\n", msg->punkUser);
3063 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3064 ok(hr == S_OK, "got %#lx\n", hr);
3067 /* SendPMsg converts reference time to music time if it is missing */
3069 hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time);
3070 ok(hr == S_OK, "got %#lx\n", hr);
3072 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
3073 ok(hr == S_OK, "got %#lx\n", hr);
3074 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3075 msg->rtTime = time;
3076 msg->dwFlags = DMUS_PMSGF_REFTIME;
3077 msg->dwType = DMUS_PMSGT_USER;
3078 hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
3079 ok(hr == S_OK, "got %#lx\n", hr);
3080 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3081 ok(hr == S_OK, "got %#lx\n", hr);
3083 ret = test_tool_wait_message(tool, 50, &msg);
3084 ok(!ret, "got %#lx\n", ret);
3085 ok(msg != NULL, "got %p\n", msg);
3087 music_time = 0xdeadbeef;
3088 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, msg->rtTime, &music_time);
3089 ok(hr == S_OK, "got %#lx\n", hr);
3090 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3091 ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
3092 ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime);
3093 ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
3094 ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
3095 ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
3096 ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
3097 ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
3098 ok(msg->pTool == tool, "got %p\n", msg->pTool);
3099 ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph);
3100 ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType);
3101 ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
3102 ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
3103 ok(!msg->punkUser, "got %p\n", msg->punkUser);
3105 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3106 ok(hr == S_OK, "got %#lx\n", hr);
3109 for (i = 0; i < ARRAY_SIZE(delivery_flags); i++)
3111 DWORD duration = 0;
3113 hr = IDirectMusicPerformance_GetTime(performance, &time, NULL);
3114 ok(hr == S_OK, "got %#lx\n", hr);
3115 hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
3116 ok(hr == S_OK, "got %#lx\n", hr);
3117 ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
3118 msg->rtTime = time + 150 * 10000;
3119 msg->dwFlags = DMUS_PMSGF_REFTIME;
3120 msg->dwType = DMUS_PMSGT_USER;
3121 hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
3122 ok(hr == S_OK, "got %#lx\n", hr);
3124 msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME);
3125 msg->dwFlags |= delivery_flags[i];
3127 duration -= GetTickCount();
3128 hr = IDirectMusicPerformance_SendPMsg(performance, msg);
3129 ok(hr == S_OK, "got %#lx\n", hr);
3130 msg = NULL;
3131 ret = test_tool_wait_message(tool, 1000, &msg);
3132 ok(!ret, "got %#lx\n", ret);
3133 ok(msg != NULL, "got %p\n", msg);
3134 duration += GetTickCount();
3136 if (msg) hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3137 ok(hr == S_OK, "got %#lx\n", hr);
3139 switch (delivery_flags[i])
3141 case DMUS_PMSGF_TOOL_IMMEDIATE: ok(duration <= 50, "got %lu\n", duration); break;
3142 case DMUS_PMSGF_TOOL_QUEUE: ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break;
3143 case DMUS_PMSGF_TOOL_ATTIME: ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break;
3148 hr = IDirectMusicPerformance_CloseDown(performance);
3149 ok(hr == S_OK, "got %#lx\n", hr);
3152 IDirectMusicGraph_Release(performance_graph);
3154 IDirectMusicPerformance_Release(performance);
3155 IDirectMusicTool_Release(tool);
3158 #define check_dmus_dirty_pmsg(a, b) check_dmus_dirty_pmsg_(__LINE__, a, b)
3159 static void check_dmus_dirty_pmsg_(int line, DMUS_PMSG *msg, MUSIC_TIME music_time)
3161 ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize);
3162 ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime);
3163 ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | DMUS_PMSGF_TOOL_IMMEDIATE),
3164 "got dwFlags %#lx\n", msg->dwFlags);
3165 ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel);
3166 ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID);
3167 ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool);
3168 ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph);
3169 ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_DIRTY, "got dwType %#lx\n", msg->dwType);
3170 ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID);
3171 todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID);
3172 ok_(__FILE__, line)(msg->punkUser == 0, "got punkUser %p\n", msg->punkUser);
3175 #define check_dmus_notification_pmsg(a, b, c, d, e, f) check_dmus_notification_pmsg_(__LINE__, a, b, c, d, e, f)
3176 static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, MUSIC_TIME music_time, DWORD flags,
3177 const GUID *type, DWORD option, void *user)
3179 ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize);
3180 ok_(__FILE__, line)(msg->rtTime > 0, "got rtTime %I64d\n", msg->rtTime);
3181 ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime);
3182 todo_wine_if(flags == DMUS_PMSGF_TOOL_ATTIME)
3183 ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | flags),
3184 "got dwFlags %#lx\n", msg->dwFlags);
3185 ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel);
3186 ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID);
3187 if (flags == DMUS_PMSGF_TOOL_ATTIME)
3189 todo_wine ok_(__FILE__, line)(msg->pTool == 0, "got pTool %p\n", msg->pTool);
3190 ok_(__FILE__, line)(msg->pGraph == 0, "got pGraph %p\n", msg->pGraph);
3192 else
3194 ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool);
3195 ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph);
3197 ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTIFICATION, "got dwType %#lx\n", msg->dwType);
3198 ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID);
3199 todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID);
3200 ok_(__FILE__, line)(msg->punkUser == (IUnknown *)user, "got punkUser %p\n", msg->punkUser);
3202 ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type),
3203 "got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType));
3204 ok_(__FILE__, line)(msg->dwNotificationOption == option,
3205 "got dwNotificationOption %#lx\n", msg->dwNotificationOption);
3206 ok_(__FILE__, line)(!msg->dwField1, "got dwField1 %lu\n", msg->dwField1);
3207 ok_(__FILE__, line)(!msg->dwField2, "got dwField2 %lu\n", msg->dwField2);
3209 if (!IsEqualGUID(&msg->guidNotificationType, &GUID_NOTIFICATION_SEGMENT))
3210 ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
3211 else
3213 check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState, TRUE, FALSE);
3214 check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState8, TRUE, FALSE);
3218 static void test_notification_pmsg(void)
3220 static const DWORD message_types[] =
3222 DMUS_PMSGT_DIRTY,
3223 DMUS_PMSGT_NOTIFICATION,
3224 DMUS_PMSGT_WAVE,
3226 IDirectMusicPerformance *performance;
3227 IDirectMusicSegmentState *state;
3228 DMUS_NOTIFICATION_PMSG *notif;
3229 MUSIC_TIME music_time, length;
3230 IDirectMusicSegment *segment;
3231 IDirectMusicTrack *track;
3232 IDirectMusicGraph *graph;
3233 IDirectMusicTool *tool;
3234 DMUS_PMSG *msg;
3235 HRESULT hr;
3236 DWORD ret;
3238 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
3239 ok(hr == S_OK, "got %#lx\n", hr);
3241 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
3242 &IID_IDirectMusicPerformance, (void **)&performance);
3243 ok(hr == S_OK, "got %#lx\n", hr);
3245 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
3246 &IID_IDirectMusicGraph, (void **)&graph);
3247 ok(hr == S_OK, "got %#lx\n", hr);
3248 hr = IDirectMusicPerformance_SetGraph(performance, graph);
3249 ok(hr == S_OK, "got %#lx\n", hr);
3250 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
3251 ok(hr == S_OK, "got %#lx\n", hr);
3252 IDirectMusicGraph_Release(graph);
3254 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
3255 ok(hr == S_OK, "got %#lx\n", hr);
3258 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
3259 &IID_IDirectMusicSegment, (void **)&segment);
3260 ok(hr == S_OK, "got %#lx\n", hr);
3263 /* native needs a track or the segment will end immediately */
3265 hr = test_track_create(&track, FALSE);
3266 ok(hr == S_OK, "got %#lx\n", hr);
3267 hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
3268 ok(hr == S_OK, "got %#lx\n", hr);
3269 IDirectMusicTrack_Release(track);
3271 /* native sends dirty / notification by batch of 1s, shorter length
3272 * will cause all messages to be received immediately */
3273 length = 10005870 / 6510;
3274 hr = IDirectMusicSegment_SetLength(segment, length);
3275 ok(hr == S_OK, "got %#lx\n", hr);
3277 hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
3278 ok(hr == S_OK, "got %#lx\n", hr);
3279 hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
3280 ok(hr == S_OK, "got %#lx\n", hr);
3282 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
3283 ok(hr == S_OK, "got %#lx\n", hr);
3284 hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
3285 ok(hr == S_OK, "got %#lx\n", hr);
3287 ret = test_tool_wait_message(tool, 50, &msg);
3288 ok(!ret, "got %#lx\n", ret);
3289 check_dmus_dirty_pmsg(msg, music_time);
3290 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3291 ok(hr == S_OK, "got %#lx\n", hr);
3293 ret = test_tool_wait_message(tool, 50, &msg);
3294 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3295 ret = test_tool_wait_message(tool, 500, &msg);
3296 ok(!ret, "got %#lx\n", ret);
3297 check_dmus_dirty_pmsg(msg, music_time + length);
3298 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3299 ok(hr == S_OK, "got %#lx\n", hr);
3301 ret = test_tool_wait_message(tool, 100, &msg);
3302 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3303 ok(!msg, "got %p\n", msg);
3306 /* AddNotificationType is necessary to receive notification messages */
3308 hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
3309 ok(hr == S_OK, "got %#lx\n", hr);
3310 hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3311 ok(hr == S_OK, "got %#lx\n", hr);
3312 hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3313 ok(hr == S_FALSE, "got %#lx\n", hr);
3315 /* avoid discarding older notifications */
3316 hr = IDirectMusicPerformance_SetNotificationHandle(performance, 0, 100000000);
3317 ok(hr == S_OK, "got %#lx\n", hr);
3319 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
3320 ok(hr == S_OK, "got %#lx\n", hr);
3321 hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
3322 ok(hr == S_OK, "got %#lx\n", hr);
3324 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3325 ok(!ret, "got %#lx\n", ret);
3326 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE,
3327 DMUS_NOTIFICATION_MUSICSTARTED, NULL);
3328 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3329 ok(hr == S_OK, "got %#lx\n", hr);
3331 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3332 ok(!ret, "got %#lx\n", ret);
3333 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3334 DMUS_NOTIFICATION_SEGSTART, state);
3335 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3336 ok(hr == S_OK, "got %#lx\n", hr);
3338 ret = test_tool_wait_message(tool, 50, &msg);
3339 ok(!ret, "got %#lx\n", ret);
3340 check_dmus_dirty_pmsg(msg, music_time);
3341 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3342 ok(hr == S_OK, "got %#lx\n", hr);
3344 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&notif);
3345 ok(!ret, "got %#lx\n", ret);
3346 check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3347 DMUS_NOTIFICATION_SEGALMOSTEND, state);
3348 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3349 ok(hr == S_OK, "got %#lx\n", hr);
3351 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3352 ok(!ret, "got %#lx\n", ret);
3353 check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3354 DMUS_NOTIFICATION_SEGEND, state);
3355 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3356 ok(hr == S_OK, "got %#lx\n", hr);
3358 ret = test_tool_wait_message(tool, 50, &msg);
3359 ok(!ret, "got %#lx\n", ret);
3360 check_dmus_dirty_pmsg(msg, music_time + length);
3361 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3362 ok(hr == S_OK, "got %#lx\n", hr);
3364 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3365 ok(!ret, "got %#lx\n", ret);
3366 check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE,
3367 DMUS_NOTIFICATION_MUSICSTOPPED, NULL);
3368 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3369 ok(hr == S_OK, "got %#lx\n", hr);
3372 /* wait enough time for notifications to be delivered */
3374 ret = test_tool_wait_message(tool, 2000, &msg);
3375 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3376 ok(!msg, "got %p\n", msg);
3379 /* notification messages are also queued for direct access */
3381 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3382 ok(hr == S_OK, "got %#lx\n", hr);
3383 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE,
3384 DMUS_NOTIFICATION_MUSICSTARTED, NULL);
3385 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3386 ok(hr == S_OK, "got %#lx\n", hr);
3388 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3389 ok(hr == S_OK, "got %#lx\n", hr);
3390 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
3391 DMUS_NOTIFICATION_SEGSTART, state);
3392 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3393 ok(hr == S_OK, "got %#lx\n", hr);
3395 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3396 ok(hr == S_OK, "got %#lx\n", hr);
3397 check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
3398 DMUS_NOTIFICATION_SEGALMOSTEND, state);
3399 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3400 ok(hr == S_OK, "got %#lx\n", hr);
3402 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3403 ok(hr == S_OK, "got %#lx\n", hr);
3404 check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
3405 DMUS_NOTIFICATION_SEGEND, state);
3406 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3407 ok(hr == S_OK, "got %#lx\n", hr);
3409 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3410 ok(hr == S_OK, "got %#lx\n", hr);
3411 check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE,
3412 DMUS_NOTIFICATION_MUSICSTOPPED, NULL);
3413 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3414 ok(hr == S_OK, "got %#lx\n", hr);
3416 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3417 ok(hr == S_FALSE, "got %#lx\n", hr);
3419 IDirectMusicSegmentState_Release(state);
3421 hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
3422 ok(hr == S_OK, "got %#lx\n", hr);
3423 hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3424 ok(hr == S_OK, "got %#lx\n", hr);
3427 /* RemoveNotificationType returns S_FALSE if already removed */
3429 hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
3430 ok(hr == S_FALSE, "got %#lx\n", hr);
3433 /* Stop finishes segment immediately and skips notification messages */
3435 hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3436 ok(hr == S_OK, "got %#lx\n", hr);
3437 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
3438 ok(hr == S_OK, "got %#lx\n", hr);
3439 hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
3440 ok(hr == S_OK, "got %#lx\n", hr);
3442 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3443 ok(!ret, "got %#lx\n", ret);
3444 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3445 DMUS_NOTIFICATION_SEGSTART, state);
3446 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3447 ok(hr == S_OK, "got %#lx\n", hr);
3449 hr = IDirectMusicPerformance_Stop(performance, NULL, NULL, 0, DMUS_SEGF_DEFAULT);
3450 ok(hr == S_OK, "got %#lx\n", hr);
3451 hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3452 ok(hr == S_OK, "got %#lx\n", hr);
3454 ret = test_tool_wait_message(tool, 50, &msg);
3455 ok(!ret, "got %#lx\n", ret);
3456 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
3457 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3458 ok(hr == S_OK, "got %#lx\n", hr);
3460 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3461 ok(!ret, "got %#lx\n", ret);
3462 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3463 DMUS_NOTIFICATION_SEGABORT, state);
3464 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3465 ok(hr == S_OK, "got %#lx\n", hr);
3467 ret = test_tool_wait_message(tool, 500, &msg);
3468 ok(!ret, "got %#lx\n", ret);
3469 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got dwType %#lx\n", msg->dwType);
3470 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3471 ok(hr == S_OK, "got %#lx\n", hr);
3473 ret = test_tool_wait_message(tool, 100, &msg);
3474 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3476 IDirectMusicSegmentState_Release(state);
3479 /* CloseDown removes all notifications and notification messages */
3481 hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3482 ok(hr == S_OK, "got %#lx\n", hr);
3483 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
3484 ok(hr == S_OK, "got %#lx\n", hr);
3485 hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
3486 ok(hr == S_OK, "got %#lx\n", hr);
3488 ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)&notif);
3489 ok(!ret, "got %#lx\n", ret);
3490 check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
3491 DMUS_NOTIFICATION_SEGSTART, state);
3492 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
3493 ok(hr == S_OK, "got %#lx\n", hr);
3495 hr = IDirectMusicPerformance_CloseDown(performance);
3496 ok(hr == S_OK, "got %#lx\n", hr);
3497 hr = IDirectMusicPerformance_GetNotificationPMsg(performance, &notif);
3498 ok(hr == S_FALSE, "got %#lx\n", hr);
3499 hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
3500 ok(hr == S_FALSE, "got %#lx\n", hr);
3502 ret = test_tool_wait_message(tool, 50, &msg);
3503 ok(!ret, "got %#lx\n", ret);
3504 check_dmus_dirty_pmsg(msg, music_time);
3505 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3506 ok(hr == S_OK, "got %#lx\n", hr);
3508 ret = test_tool_wait_message(tool, 500, &msg);
3509 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3511 IDirectMusicSegmentState_Release(state);
3512 IDirectMusicSegment_Release(segment);
3515 IDirectMusicPerformance_Release(performance);
3516 IDirectMusicTool_Release(tool);
3519 static void test_wave_pmsg(void)
3521 static const DWORD message_types[] =
3523 DMUS_PMSGT_DIRTY,
3524 DMUS_PMSGT_WAVE,
3526 IDirectMusicPerformance *performance;
3527 IDirectMusicSegment *segment;
3528 IDirectMusicLoader8 *loader;
3529 IDirectMusicGraph *graph;
3530 WCHAR test_wav[MAX_PATH];
3531 IDirectMusicTool *tool;
3532 DMUS_WAVE_PMSG *wave;
3533 MUSIC_TIME length;
3534 DMUS_PMSG *msg;
3535 HRESULT hr;
3536 DWORD ret;
3538 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
3539 ok(hr == S_OK, "got %#lx\n", hr);
3541 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
3542 &IID_IDirectMusicPerformance, (void **)&performance);
3543 ok(hr == S_OK, "got %#lx\n", hr);
3545 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
3546 &IID_IDirectMusicGraph, (void **)&graph);
3547 ok(hr == S_OK, "got %#lx\n", hr);
3548 hr = IDirectMusicPerformance_SetGraph(performance, graph);
3549 ok(hr == S_OK, "got %#lx\n", hr);
3550 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
3551 ok(hr == S_OK, "got %#lx\n", hr);
3552 IDirectMusicGraph_Release(graph);
3554 hr = IDirectMusicPerformance8_InitAudio((IDirectMusicPerformance8 *)performance, NULL, NULL, NULL,
3555 DMUS_APATH_SHARED_STEREOPLUSREVERB, 64, DMUS_AUDIOF_ALL, NULL);
3556 ok(hr == S_OK, "got %#lx\n", hr);
3559 load_resource(L"test.wav", test_wav);
3561 hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER,
3562 &IID_IDirectMusicLoader8, (void **)&loader);
3563 ok(hr == S_OK, "got %#lx\n", hr);
3564 hr = IDirectMusicLoader8_LoadObjectFromFile(loader, &CLSID_DirectMusicSegment,
3565 &IID_IDirectMusicSegment, test_wav, (void **)&segment);
3566 ok(hr == S_OK, "got %#lx\n", hr);
3567 IDirectMusicLoader8_Release(loader);
3570 length = 0xdeadbeef;
3571 hr = IDirectMusicSegment_GetLength(segment, &length);
3572 ok(hr == S_OK, "got %#lx\n", hr);
3573 ok(length == 1, "got %lu\n", length);
3576 /* without Download, no DMUS_PMSGT_WAVE is sent */
3578 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
3579 ok(hr == S_OK, "got %#lx\n", hr);
3581 ret = test_tool_wait_message(tool, 500, &msg);
3582 ok(!ret, "got %#lx\n", ret);
3583 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
3584 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3585 ok(hr == S_OK, "got %#lx\n", hr);
3587 ret = test_tool_wait_message(tool, 500, &msg);
3588 ok(!ret, "got %#lx\n", ret);
3589 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
3590 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3591 ok(hr == S_OK, "got %#lx\n", hr);
3593 ret = test_tool_wait_message(tool, 100, &msg);
3594 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3595 ok(!msg, "got %p\n", msg);
3598 /* a single DMUS_PMSGT_WAVE message is sent with punkUser set */
3600 hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
3601 ok(hr == S_OK, "got %#lx\n", hr);
3603 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
3604 ok(hr == S_OK, "got %#lx\n", hr);
3606 ret = test_tool_wait_message(tool, 500, &msg);
3607 ok(!ret, "got %#lx\n", ret);
3608 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
3609 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3610 ok(hr == S_OK, "got %#lx\n", hr);
3612 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&wave);
3613 ok(!ret, "got %#lx\n", ret);
3614 ok(wave->dwType == DMUS_PMSGT_WAVE, "got %p\n", wave);
3615 ok(!!wave->punkUser, "got %p\n", wave->punkUser);
3616 ok(wave->rtStartOffset == 0, "got %I64d\n", wave->rtStartOffset);
3617 ok(wave->rtDuration == 1000000, "got %I64d\n", wave->rtDuration);
3618 ok(wave->lOffset == 0, "got %lu\n", wave->lOffset);
3619 ok(wave->lVolume == 0, "got %lu\n", wave->lVolume);
3620 ok(wave->lPitch == 0, "got %lu\n", wave->lPitch);
3621 ok(wave->bFlags == 0, "got %#x\n", wave->bFlags);
3622 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)wave);
3623 ok(hr == S_OK, "got %#lx\n", hr);
3625 ret = test_tool_wait_message(tool, 500, &msg);
3626 ok(!ret, "got %#lx\n", ret);
3627 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
3628 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3629 ok(hr == S_OK, "got %#lx\n", hr);
3631 hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
3632 ok(hr == S_OK, "got %#lx\n", hr);
3634 ret = test_tool_wait_message(tool, 100, &msg);
3635 ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
3636 ok(!msg, "got %p\n", msg);
3639 IDirectMusicSegment_Release(segment);
3642 hr = IDirectMusicPerformance_CloseDown(performance);
3643 ok(hr == S_OK, "got %#lx\n", hr);
3645 IDirectMusicPerformance_Release(performance);
3646 IDirectMusicTool_Release(tool);
3649 static void test_sequence_track(void)
3651 static const DWORD message_types[] =
3653 DMUS_PMSGT_MIDI,
3654 DMUS_PMSGT_NOTE,
3655 DMUS_PMSGT_CURVE,
3656 DMUS_PMSGT_DIRTY,
3658 static const LARGE_INTEGER zero = {0};
3659 IDirectMusicPerformance *performance;
3660 IDirectMusicSegment *segment;
3661 IDirectMusicGraph *graph;
3662 IDirectMusicTrack *track;
3663 IPersistStream *persist;
3664 IDirectMusicTool *tool;
3665 DMUS_NOTE_PMSG *note;
3666 IStream *stream;
3667 DMUS_PMSG *msg;
3668 HRESULT hr;
3669 DWORD ret;
3671 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
3672 ok(hr == S_OK, "got %#lx\n", hr);
3674 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
3675 &IID_IDirectMusicPerformance, (void **)&performance);
3676 ok(hr == S_OK, "got %#lx\n", hr);
3678 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
3679 &IID_IDirectMusicGraph, (void **)&graph);
3680 ok(hr == S_OK, "got %#lx\n", hr);
3681 hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
3682 ok(hr == S_OK, "got %#lx\n", hr);
3683 hr = IDirectMusicPerformance_SetGraph(performance, graph);
3684 ok(hr == S_OK, "got %#lx\n", hr);
3685 IDirectMusicGraph_Release(graph);
3688 /* create a segment and load a simple RIFF stream */
3690 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
3691 &IID_IDirectMusicSegment, (void **)&segment);
3692 ok(hr == S_OK, "got %#lx\n", hr);
3694 hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
3695 ok(hr == S_OK, "got %#lx\n", hr);
3696 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
3697 ok(hr == S_OK, "got %#lx\n", hr);
3699 CHUNK_RIFF(stream, "DMSG")
3701 /* set a non-zero segment length, or nothing will be played */
3702 DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000};
3703 CHUNK_DATA(stream, "segh", head);
3704 CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
3706 CHUNK_END;
3708 hr = IStream_Seek(stream, zero, 0, NULL);
3709 ok(hr == S_OK, "got %#lx\n", hr);
3710 hr = IPersistStream_Load(persist, stream);
3711 ok(hr == S_OK, "got %#lx\n", hr);
3712 IPersistStream_Release(persist);
3713 IStream_Release(stream);
3716 /* add a sequence track to our segment */
3718 hr = CoCreateInstance(&CLSID_DirectMusicSeqTrack, NULL, CLSCTX_INPROC_SERVER,
3719 &IID_IDirectMusicTrack, (void **)&track);
3720 ok(hr == S_OK, "got %#lx\n", hr);
3722 hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
3723 ok(hr == S_OK, "got %#lx\n", hr);
3724 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
3725 ok(hr == S_OK, "got %#lx\n", hr);
3727 CHUNK_BEGIN(stream, "seqt")
3729 DMUS_IO_SEQ_ITEM items[] =
3731 {.mtTime = 0, .mtDuration = 500, .dwPChannel = 0, .bStatus = 0x90, .bByte1 = 60, .bByte2 = 120},
3732 {.mtTime = 1000, .mtDuration = 200, .dwPChannel = 1, .bStatus = 0x90, .bByte1 = 50, .bByte2 = 100},
3734 CHUNK_ARRAY(stream, "evtl", items);
3736 CHUNK_END;
3738 hr = IStream_Seek(stream, zero, 0, NULL);
3739 ok(hr == S_OK, "got %#lx\n", hr);
3740 hr = IPersistStream_Load(persist, stream);
3741 ok(hr == S_OK, "got %#lx\n", hr);
3742 IPersistStream_Release(persist);
3743 IStream_Release(stream);
3745 hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
3746 ok(hr == S_OK, "got %#lx\n", hr);
3747 IDirectMusicTrack_Release(track);
3750 /* now play the segment, and check produced messages */
3752 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
3753 ok(hr == S_OK, "got %#lx\n", hr);
3755 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
3756 ok(hr == S_OK, "got %#lx\n", hr);
3758 ret = test_tool_wait_message(tool, 500, &msg);
3759 ok(!ret, "got %#lx\n", ret);
3760 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
3761 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3762 ok(hr == S_OK, "got %#lx\n", hr);
3764 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&note);
3765 ok(!ret, "got %#lx\n", ret);
3766 check_dmus_note_pmsg(note, 0, 0, 500, 60, 120, DMUS_NOTEF_NOTEON);
3767 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
3768 ok(hr == S_OK, "got %#lx\n", hr);
3770 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&note);
3771 ok(!ret, "got %#lx\n", ret);
3772 check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100, DMUS_NOTEF_NOTEON);
3773 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
3774 ok(hr == S_OK, "got %#lx\n", hr);
3776 ret = test_tool_wait_message(tool, 500, &msg);
3777 ok(!ret, "got %#lx\n", ret);
3778 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
3779 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
3780 ok(hr == S_OK, "got %#lx\n", hr);
3782 IDirectMusicSegment_Release(segment);
3785 hr = IDirectMusicPerformance_CloseDown(performance);
3786 ok(hr == S_OK, "got %#lx\n", hr);
3788 IDirectMusicPerformance_Release(performance);
3789 IDirectMusicTool_Release(tool);
3792 #define check_dmus_patch_pmsg(a, b, c, d, e) check_dmus_patch_pmsg_(__LINE__, a, b, c, d, e)
3793 static void check_dmus_patch_pmsg_(int line, DMUS_PATCH_PMSG *msg, MUSIC_TIME time, UINT chan,
3794 UINT bank, UINT patch)
3796 ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
3797 ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime);
3798 ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
3799 ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel);
3800 ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
3801 ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_PATCH, "got %#lx\n", msg->dwType);
3802 ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
3803 ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID);
3804 ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
3805 ok_(__FILE__, line)(msg->byInstrument == patch, "got byInstrument %u\n", msg->byInstrument);
3806 ok_(__FILE__, line)(msg->byMSB == bank >> 8, "got byMSB %u\n", msg->byMSB);
3807 ok_(__FILE__, line)(msg->byLSB == (bank & 0xff), "got byLSB %u\n", msg->byLSB);
3810 static void test_band_track_play(void)
3812 static const DWORD message_types[] =
3814 DMUS_PMSGT_MIDI,
3815 DMUS_PMSGT_NOTE,
3816 DMUS_PMSGT_SYSEX,
3817 DMUS_PMSGT_NOTIFICATION,
3818 DMUS_PMSGT_TEMPO,
3819 DMUS_PMSGT_CURVE,
3820 DMUS_PMSGT_TIMESIG,
3821 DMUS_PMSGT_PATCH,
3822 DMUS_PMSGT_TRANSPOSE,
3823 DMUS_PMSGT_CHANNEL_PRIORITY,
3824 DMUS_PMSGT_STOP,
3825 DMUS_PMSGT_DIRTY,
3826 DMUS_PMSGT_WAVE,
3827 DMUS_PMSGT_LYRIC,
3828 DMUS_PMSGT_SCRIPTLYRIC,
3829 DMUS_PMSGT_USER,
3831 DMUS_OBJECTDESC desc =
3833 .dwSize = sizeof(DMUS_OBJECTDESC),
3834 .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH,
3835 .guidClass = CLSID_DirectMusicCollection,
3836 .guidObject = GUID_DefaultGMCollection,
3837 .wszFileName = L"C:\\windows\\system32\\drivers\\gm.dls",
3839 static const LARGE_INTEGER zero = {0};
3840 IDirectMusicPerformance *performance;
3841 IStream *stream, *loader_stream;
3842 IDirectMusicSegment *segment;
3843 IDirectMusicLoader *loader;
3844 IDirectMusicGraph *graph;
3845 IDirectMusicTrack *track;
3846 IPersistStream *persist;
3847 IDirectMusicTool *tool;
3848 DMUS_PATCH_PMSG *patch;
3849 DMUS_PMSG *msg;
3850 HRESULT hr;
3851 DWORD ret;
3853 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
3854 ok(hr == S_OK, "got %#lx\n", hr);
3856 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
3857 &IID_IDirectMusicPerformance, (void **)&performance);
3858 ok(hr == S_OK, "got %#lx\n", hr);
3860 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
3861 &IID_IDirectMusicGraph, (void **)&graph);
3862 ok(hr == S_OK, "got %#lx\n", hr);
3863 hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
3864 ok(hr == S_OK, "got %#lx\n", hr);
3865 hr = IDirectMusicPerformance_SetGraph(performance, graph);
3866 ok(hr == S_OK, "got %#lx\n", hr);
3867 IDirectMusicGraph_Release(graph);
3870 /* create a segment and load a simple RIFF stream */
3872 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
3873 &IID_IDirectMusicSegment, (void **)&segment);
3874 ok(hr == S_OK, "got %#lx\n", hr);
3876 hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
3877 ok(hr == S_OK, "got %#lx\n", hr);
3878 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
3879 ok(hr == S_OK, "got %#lx\n", hr);
3881 CHUNK_RIFF(stream, "DMSG")
3883 /* set a non-zero segment length, or nothing will be played */
3884 DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000};
3885 CHUNK_DATA(stream, "segh", head);
3886 CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
3888 CHUNK_END;
3890 hr = IStream_Seek(stream, zero, 0, NULL);
3891 ok(hr == S_OK, "got %#lx\n", hr);
3892 hr = IPersistStream_Load(persist, stream);
3893 ok(hr == S_OK, "got %#lx\n", hr);
3894 IPersistStream_Release(persist);
3895 IStream_Release(stream);
3898 /* add a sequence track to our segment */
3900 hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER,
3901 &IID_IDirectMusicTrack, (void **)&track);
3902 ok(hr == S_OK, "got %#lx\n", hr);
3904 hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
3905 ok(hr == S_OK, "got %#lx\n", hr);
3906 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
3907 ok(hr == S_OK, "got %#lx\n", hr);
3909 CHUNK_RIFF(stream, "DMBT")
3911 DMUS_IO_BAND_TRACK_HEADER head = {.bAutoDownload = TRUE};
3913 CHUNK_DATA(stream, "bdth", head);
3914 CHUNK_LIST(stream, "lbdl")
3916 CHUNK_LIST(stream, "lbnd")
3918 DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 0};
3919 CHUNK_DATA(stream, "bdih", head);
3921 CHUNK_RIFF(stream, "DMBD")
3923 GUID guid = CLSID_DirectMusicBand;
3924 CHUNK_DATA(stream, "guid", guid);
3926 CHUNK_LIST(stream, "lbil")
3928 CHUNK_LIST(stream, "lbin")
3930 DMUS_IO_INSTRUMENT head = {.dwPatch = 1, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH};
3931 CHUNK_DATA(stream, "bins", head);
3933 CHUNK_END;
3935 CHUNK_END;
3937 CHUNK_END;
3939 CHUNK_END;
3941 CHUNK_LIST(stream, "lbnd")
3943 DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 1000};
3944 CHUNK_DATA(stream, "bdih", head);
3946 CHUNK_RIFF(stream, "DMBD")
3948 GUID guid = CLSID_DirectMusicBand;
3949 CHUNK_DATA(stream, "guid", guid);
3951 CHUNK_LIST(stream, "lbil")
3953 CHUNK_LIST(stream, "lbin")
3955 DMUS_IO_INSTRUMENT head = {.dwPatch = 2, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH};
3956 CHUNK_DATA(stream, "bins", head);
3958 CHUNK_END;
3960 CHUNK_LIST(stream, "lbin")
3962 DMUS_IO_INSTRUMENT head = {.dwPatch = 3, .dwPChannel = 2, .dwFlags = DMUS_IO_INST_PATCH};
3963 CHUNK_DATA(stream, "bins", head);
3965 CHUNK_END;
3967 CHUNK_END;
3969 CHUNK_END;
3971 CHUNK_END;
3973 CHUNK_END;
3975 CHUNK_END;
3977 hr = IStream_Seek(stream, zero, 0, NULL);
3978 ok(hr == S_OK, "got %#lx\n", hr);
3980 /* band track requires the stream to implement IDirectMusicGetLoader */
3982 hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER,
3983 &IID_IDirectMusicLoader8, (void **)&loader);
3984 ok(hr == S_OK, "got %#lx\n", hr);
3985 hr = IDirectMusicLoader_SetObject(loader, &desc);
3986 if (hr == DMUS_E_LOADER_FAILEDOPEN)
3987 skip("Failed to open gm.dls, missing system SoundFont?\n");
3988 else
3989 ok(hr == S_OK, "got %#lx\n", hr);
3991 hr = test_loader_stream_create(stream, loader, &loader_stream);
3992 ok(hr == S_OK, "got %#lx\n", hr);
3993 IDirectMusicLoader8_Release(loader);
3995 hr = IPersistStream_Load(persist, loader_stream);
3996 ok(hr == S_OK, "got %#lx\n", hr);
3997 IStream_Release(loader_stream);
3999 IPersistStream_Release(persist);
4000 IStream_Release(stream);
4002 hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
4003 ok(hr == S_OK, "got %#lx\n", hr);
4004 IDirectMusicTrack_Release(track);
4007 /* now play the segment, and check produced messages */
4009 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
4010 ok(hr == S_OK, "got %#lx\n", hr);
4012 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
4013 ok(hr == S_OK, "got %#lx\n", hr);
4015 ret = test_tool_wait_message(tool, 500, &msg);
4016 ok(!ret, "got %#lx\n", ret);
4017 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
4018 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
4019 ok(hr == S_OK, "got %#lx\n", hr);
4021 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
4022 ok(!ret, "got %#lx\n", ret);
4023 check_dmus_patch_pmsg(patch, 0, 1, 0, 1);
4024 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
4025 ok(hr == S_OK, "got %#lx\n", hr);
4027 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
4028 ok(!ret, "got %#lx\n", ret);
4029 check_dmus_patch_pmsg(patch, 1000, 2, 0, 3);
4030 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
4031 ok(hr == S_OK, "got %#lx\n", hr);
4033 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
4034 ok(!ret, "got %#lx\n", ret);
4035 check_dmus_patch_pmsg(patch, 1000, 1, 0, 2);
4036 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
4037 ok(hr == S_OK, "got %#lx\n", hr);
4039 ret = test_tool_wait_message(tool, 500, &msg);
4040 ok(!ret, "got %#lx\n", ret);
4041 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
4042 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
4043 ok(hr == S_OK, "got %#lx\n", hr);
4045 IDirectMusicSegment_Release(segment);
4048 hr = IDirectMusicPerformance_CloseDown(performance);
4049 ok(hr == S_OK, "got %#lx\n", hr);
4051 IDirectMusicPerformance_Release(performance);
4052 IDirectMusicTool_Release(tool);
4055 #define check_dmus_tempo_pmsg(a, b, c) check_dmus_tempo_pmsg_(__LINE__, a, b, c)
4056 static void check_dmus_tempo_pmsg_(int line, DMUS_TEMPO_PMSG *msg, MUSIC_TIME time, double tempo)
4058 ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
4059 ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime);
4060 ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
4061 ok_(__FILE__, line)(!msg->dwPChannel, "got dwPChannel %lu\n", msg->dwPChannel);
4062 ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
4063 ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_TEMPO, "got dwType %#lx\n", msg->dwType);
4064 ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
4065 ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %lu\n", msg->dwGroupID);
4066 ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
4067 ok_(__FILE__, line)(msg->dblTempo == tempo, "got tempo %f\n", msg->dblTempo);
4070 static void test_tempo_track_play(void)
4072 static const DWORD message_types[] =
4074 DMUS_PMSGT_MIDI,
4075 DMUS_PMSGT_NOTE,
4076 DMUS_PMSGT_SYSEX,
4077 DMUS_PMSGT_NOTIFICATION,
4078 DMUS_PMSGT_TEMPO,
4079 DMUS_PMSGT_CURVE,
4080 DMUS_PMSGT_TIMESIG,
4081 DMUS_PMSGT_PATCH,
4082 DMUS_PMSGT_TRANSPOSE,
4083 DMUS_PMSGT_CHANNEL_PRIORITY,
4084 DMUS_PMSGT_STOP,
4085 DMUS_PMSGT_DIRTY,
4086 DMUS_PMSGT_WAVE,
4087 DMUS_PMSGT_LYRIC,
4088 DMUS_PMSGT_SCRIPTLYRIC,
4089 DMUS_PMSGT_USER,
4091 static const LARGE_INTEGER zero = {0};
4092 DMUS_IO_TEMPO_ITEM tempo_items[] =
4094 {.lTime = 100, .dblTempo = 80},
4095 {.lTime = 300, .dblTempo = 60},
4096 {.lTime = 200, .dblTempo = 20},
4097 {.lTime = 4000, .dblTempo = 50},
4099 IDirectMusicPerformance *performance;
4100 MUSIC_TIME music_time, next_time;
4101 REFERENCE_TIME init_time, time;
4102 IDirectMusicSegment *segment;
4103 IDirectMusicGraph *graph;
4104 IDirectMusicTrack *track;
4105 IPersistStream *persist;
4106 IDirectMusicTool *tool;
4107 DMUS_TEMPO_PMSG *tempo;
4108 DMUS_TEMPO_PARAM param;
4109 IStream *stream;
4110 DMUS_PMSG *msg;
4111 HRESULT hr;
4112 DWORD ret;
4114 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
4115 ok(hr == S_OK, "got %#lx\n", hr);
4117 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
4118 &IID_IDirectMusicPerformance, (void **)&performance);
4119 ok(hr == S_OK, "got %#lx\n", hr);
4121 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
4122 &IID_IDirectMusicGraph, (void **)&graph);
4123 ok(hr == S_OK, "got %#lx\n", hr);
4124 hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
4125 ok(hr == S_OK, "got %#lx\n", hr);
4126 hr = IDirectMusicPerformance_SetGraph(performance, graph);
4127 ok(hr == S_OK, "got %#lx\n", hr);
4128 IDirectMusicGraph_Release(graph);
4131 /* create a segment and load a simple RIFF stream */
4133 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
4134 &IID_IDirectMusicSegment, (void **)&segment);
4135 ok(hr == S_OK, "got %#lx\n", hr);
4137 hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
4138 ok(hr == S_OK, "got %#lx\n", hr);
4139 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
4140 ok(hr == S_OK, "got %#lx\n", hr);
4142 CHUNK_RIFF(stream, "DMSG")
4144 /* set a non-zero segment length, or nothing will be played */
4145 DMUS_IO_SEGMENT_HEADER head = {.mtLength = 1000};
4146 CHUNK_DATA(stream, "segh", head);
4147 CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
4149 CHUNK_END;
4151 hr = IStream_Seek(stream, zero, 0, NULL);
4152 ok(hr == S_OK, "got %#lx\n", hr);
4153 hr = IPersistStream_Load(persist, stream);
4154 ok(hr == S_OK, "got %#lx\n", hr);
4155 IPersistStream_Release(persist);
4156 IStream_Release(stream);
4159 /* add a tempo track to our segment */
4161 hr = CoCreateInstance(&CLSID_DirectMusicTempoTrack, NULL, CLSCTX_INPROC_SERVER,
4162 &IID_IDirectMusicTrack, (void **)&track);
4163 ok(hr == S_OK, "got %#lx\n", hr);
4165 hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
4166 ok(hr == S_OK, "got %#lx\n", hr);
4167 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
4168 ok(hr == S_OK, "got %#lx\n", hr);
4169 CHUNK_ARRAY(stream, "tetr", tempo_items);
4170 hr = IStream_Seek(stream, zero, 0, NULL);
4171 ok(hr == S_OK, "got %#lx\n", hr);
4172 hr = IPersistStream_Load(persist, stream);
4173 ok(hr == S_OK, "got %#lx\n", hr);
4174 IPersistStream_Release(persist);
4175 IStream_Release(stream);
4177 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, &param);
4178 ok(hr == DMUS_E_TRACK_NOT_FOUND, "got %#lx\n", hr);
4180 hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
4181 ok(hr == S_OK, "got %#lx\n", hr);
4182 IDirectMusicTrack_Release(track);
4184 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL);
4185 ok(hr == E_POINTER, "got %#lx\n", hr);
4186 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, &param);
4187 ok(hr == S_OK, "got %#lx\n", hr);
4189 memset(&param, 0xcd, sizeof(param));
4190 next_time = 0xdeadbeef;
4191 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, &param);
4192 ok(hr == S_OK, "got %#lx\n", hr);
4193 ok(next_time == 100, "got next_time %lu\n", next_time);
4194 ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime);
4195 ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
4196 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, &param);
4197 ok(hr == S_OK, "got %#lx\n", hr);
4198 ok(next_time == 200, "got next_time %lu\n", next_time);
4199 ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime);
4200 ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
4201 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, &param);
4202 ok(hr == S_OK, "got %#lx\n", hr);
4203 ok(next_time == 101, "got next_time %lu\n", next_time);
4204 ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime);
4205 ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
4206 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, &param);
4207 ok(hr == S_OK, "got %#lx\n", hr);
4208 ok(next_time == 100, "got next_time %lu\n", next_time);
4209 ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime);
4210 ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
4211 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, &param);
4212 ok(hr == S_OK, "got %#lx\n", hr);
4213 ok(next_time == 1, "got next_time %lu\n", next_time);
4214 ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime);
4215 ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
4216 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, &param);
4217 ok(hr == S_OK, "got %#lx\n", hr);
4218 ok(next_time == 3700, "got next_time %lu\n", next_time);
4219 ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime);
4220 ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo);
4221 hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, &param);
4222 ok(hr == S_OK, "got %#lx\n", hr);
4223 ok(next_time == 0, "got next_time %lu\n", next_time);
4224 ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime);
4225 ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo);
4228 /* now play the segment, and check produced messages */
4230 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
4231 ok(hr == S_OK, "got %#lx\n", hr);
4233 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
4234 ok(hr == S_OK, "got %#lx\n", hr);
4236 /* the tempo track only takes effect after DMUS_PMSGT_DIRTY */
4238 ret = test_tool_wait_message(tool, 500, &msg);
4239 ok(!ret, "got %#lx\n", ret);
4240 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
4241 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
4242 ok(hr == S_OK, "got %#lx\n", hr);
4245 time = 0xdeadbeef;
4246 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
4247 ok(hr == S_OK, "got %#lx\n", hr);
4248 init_time = time;
4250 time = 0xdeadbeef;
4251 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time);
4252 ok(hr == S_OK, "got %#lx\n", hr);
4253 check_music_time(time - init_time, scale_music_time(1, 120));
4254 time = 0xdeadbeef;
4255 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time);
4256 ok(hr == S_OK, "got %#lx\n", hr);
4257 check_music_time(time - init_time, scale_music_time(100, 120));
4258 time = 0xdeadbeef;
4259 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time);
4260 ok(hr == S_OK, "got %#lx\n", hr);
4261 check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80));
4262 time = 0xdeadbeef;
4263 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time);
4264 ok(hr == S_OK, "got %#lx\n", hr);
4265 check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80));
4266 time = 0xdeadbeef;
4267 hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time);
4268 ok(hr == S_OK, "got %#lx\n", hr);
4269 check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20));
4271 music_time = 0xdeadbeef;
4272 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time);
4273 ok(hr == S_OK, "got %#lx\n", hr);
4274 ok(music_time == 0, "got %ld\n", music_time);
4275 music_time = 0xdeadbeef;
4276 time = scale_music_time(100, 120) + scale_music_time(50, 80);
4277 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time);
4278 ok(hr == S_OK, "got %#lx\n", hr);
4279 ok(music_time == 150, "got %ld\n", music_time);
4280 music_time = 0xdeadbeef;
4281 time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20);
4282 hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time);
4283 ok(hr == S_OK, "got %#lx\n", hr);
4284 ok(music_time == 400, "got %ld\n", music_time);
4287 ret = test_tool_wait_message(tool, 2000, (DMUS_PMSG **)&tempo);
4288 ok(!ret, "got %#lx\n", ret);
4289 todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType);
4290 if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests;
4291 check_dmus_tempo_pmsg(tempo, 100, 80);
4292 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo);
4293 ok(hr == S_OK, "got %#lx\n", hr);
4295 ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo);
4296 todo_wine ok(!ret, "got %#lx\n", ret);
4297 check_dmus_tempo_pmsg(tempo, 300, 60);
4298 hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo);
4299 ok(hr == S_OK, "got %#lx\n", hr);
4301 ret = test_tool_wait_message(tool, 500, &msg);
4302 todo_wine ok(!ret, "got %#lx\n", ret);
4303 ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
4304 hr = IDirectMusicPerformance_FreePMsg(performance, msg);
4305 ok(hr == S_OK, "got %#lx\n", hr);
4307 skip_tests:
4308 IDirectMusicSegment_Release(segment);
4311 hr = IDirectMusicPerformance_CloseDown(performance);
4312 ok(hr == S_OK, "got %#lx\n", hr);
4314 IDirectMusicPerformance_Release(performance);
4315 IDirectMusicTool_Release(tool);
4318 static void test_connect_to_collection(void)
4320 IDirectMusicCollection *collection;
4321 IDirectMusicSegment *segment;
4322 IDirectMusicTrack *track;
4323 void *param;
4324 HRESULT hr;
4326 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
4327 &IID_IDirectMusicCollection, (void **)&collection);
4328 ok(hr == S_OK, "got %#lx\n", hr);
4329 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
4330 &IID_IDirectMusicSegment, (void **)&segment);
4331 ok(hr == S_OK, "got %#lx\n", hr);
4332 hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER,
4333 &IID_IDirectMusicTrack, (void **)&track);
4334 ok(hr == S_OK, "got %#lx\n", hr);
4336 hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
4337 ok(hr == S_OK, "got %#lx\n", hr);
4339 /* it is possible to connect the band track to another collection, but not to disconnect it */
4340 hr = IDirectMusicTrack_IsParamSupported(track, &GUID_ConnectToDLSCollection);
4341 ok(hr == S_OK, "got %#lx\n", hr);
4343 hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, NULL);
4344 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
4345 hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, collection);
4346 ok(hr == S_OK, "got %#lx\n", hr);
4348 hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, NULL);
4349 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
4350 hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, &param);
4351 ok(hr == DMUS_E_GET_UNSUPPORTED, "got %#lx\n", hr);
4353 hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, NULL);
4354 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
4355 hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, collection);
4356 ok(hr == S_OK, "got %#lx\n", hr);
4358 IDirectMusicTrack_Release(track);
4359 IDirectMusicSegment_Release(segment);
4360 IDirectMusicCollection_Release(collection);
4363 static void test_segment_state(void)
4365 static const DWORD message_types[] =
4367 DMUS_PMSGT_DIRTY,
4368 DMUS_PMSGT_NOTIFICATION,
4369 DMUS_PMSGT_WAVE,
4371 IDirectMusicSegmentState *state, *tmp_state;
4372 IDirectMusicSegment *segment, *tmp_segment;
4373 IDirectMusicPerformance *performance;
4374 IDirectMusicTrack *track;
4375 IDirectMusicGraph *graph;
4376 IDirectMusicTool *tool;
4377 DWORD value, ret;
4378 MUSIC_TIME time;
4379 HRESULT hr;
4381 hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
4382 ok(hr == S_OK, "got %#lx\n", hr);
4383 hr = test_track_create(&track, TRUE);
4384 ok(hr == S_OK, "got %#lx\n", hr);
4386 hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
4387 &IID_IDirectMusicPerformance, (void **)&performance);
4388 ok(hr == S_OK, "got %#lx\n", hr);
4390 hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
4391 &IID_IDirectMusicGraph, (void **)&graph);
4392 ok(hr == S_OK, "got %#lx\n", hr);
4393 hr = IDirectMusicPerformance_SetGraph(performance, graph);
4394 ok(hr == S_OK, "got %#lx\n", hr);
4395 hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
4396 ok(hr == S_OK, "got %#lx\n", hr);
4397 IDirectMusicGraph_Release(graph);
4400 hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
4401 &IID_IDirectMusicSegment, (void **)&segment);
4402 ok(hr == S_OK, "got %#lx\n", hr);
4404 check_track_state(track, inserted, FALSE);
4405 hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
4406 ok(hr == S_OK, "got %#lx\n", hr);
4407 check_track_state(track, inserted, TRUE);
4409 check_track_state(track, downloaded, FALSE);
4410 hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
4411 ok(hr == S_OK, "got %#lx\n", hr);
4412 check_track_state(track, downloaded, TRUE);
4413 hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
4414 ok(hr == S_OK, "got %#lx\n", hr);
4415 check_track_state(track, downloaded, FALSE);
4418 /* by default the segment length is 1 */
4420 time = 0xdeadbeef;
4421 hr = IDirectMusicSegment_GetLength(segment, &time);
4422 ok(hr == S_OK, "got %#lx\n", hr);
4423 todo_wine ok(time == 1, "got %lu\n", time);
4424 hr = IDirectMusicSegment_SetStartPoint(segment, 50);
4425 ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr);
4426 hr = IDirectMusicSegment_SetRepeats(segment, 10);
4427 ok(hr == S_OK, "got %#lx\n", hr);
4428 hr = IDirectMusicSegment_SetLoopPoints(segment, 10, 70);
4429 ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr);
4431 /* Setting a larger length will cause PlayEx to be called multiple times,
4432 * as native splits the segment into chunks and play each chunk separately */
4433 hr = IDirectMusicSegment_SetLength(segment, 100);
4434 ok(hr == S_OK, "got %#lx\n", hr);
4435 hr = IDirectMusicSegment_SetStartPoint(segment, 50);
4436 ok(hr == S_OK, "got %#lx\n", hr);
4437 hr = IDirectMusicSegment_SetRepeats(segment, 0);
4438 ok(hr == S_OK, "got %#lx\n", hr);
4439 hr = IDirectMusicSegment_SetLoopPoints(segment, 0, 0);
4440 ok(hr == S_OK, "got %#lx\n", hr);
4443 /* InitPlay returns a dummy segment state */
4445 state = (void *)0xdeadbeef;
4446 hr = IDirectMusicSegment_InitPlay(segment, &state, performance, 0);
4447 ok(hr == S_OK, "got %#lx\n", hr);
4448 ok(state != NULL, "got %p\n", state);
4449 ok(state != (void *)0xdeadbeef, "got %p\n", state);
4450 check_track_state(track, initialized, FALSE);
4452 tmp_segment = (void *)0xdeadbeef;
4453 hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment);
4454 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
4455 ok(tmp_segment == NULL, "got %p\n", tmp_segment);
4456 time = 0xdeadbeef;
4457 hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
4458 ok(hr == S_OK, "got %#lx\n", hr);
4459 ok(time == 0, "got %#lx\n", time);
4460 time = 0xdeadbeef;
4461 hr = IDirectMusicSegmentState_GetRepeats(state, &value);
4462 ok(hr == S_OK, "got %#lx\n", hr);
4463 ok(time == 0xdeadbeef, "got %#lx\n", time);
4464 time = 0xdeadbeef;
4465 hr = IDirectMusicSegmentState_GetStartTime(state, &time);
4466 ok(hr == S_OK, "got %#lx\n", hr);
4467 ok(time == -1, "got %#lx\n", time);
4468 time = 0xdeadbeef;
4469 hr = IDirectMusicSegmentState_GetSeek(state, &time);
4470 ok(hr == S_OK, "got %#lx\n", hr);
4471 ok(time == 0, "got %#lx\n", time);
4474 /* PlaySegment returns a different, genuine segment state */
4476 hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
4477 ok(hr == S_OK, "got %#lx\n", hr);
4479 check_track_state(track, downloaded, FALSE);
4480 check_track_state(track, initialized, FALSE);
4481 check_track_state(track, playing, FALSE);
4483 hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0);
4484 ok(hr == E_POINTER, "got %#lx\n", hr);
4485 hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
4486 ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
4489 tmp_state = state;
4490 state = (void *)0xdeadbeef;
4491 hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state);
4492 ok(hr == S_OK, "got %#lx\n", hr);
4493 ok(state != NULL, "got %p\n", state);
4494 ok(state != (void *)0xdeadbeef, "got %p\n", state);
4495 ok(state != tmp_state, "got %p\n", state);
4496 IDirectMusicSegmentState_Release(tmp_state);
4498 tmp_state = (void *)0xdeadbeef;
4499 hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
4500 ok(hr == S_OK, "got %#lx\n", hr);
4501 ok(state == tmp_state, "got %p\n", state);
4502 IDirectMusicSegmentState_Release(tmp_state);
4504 tmp_state = (void *)0xdeadbeef;
4505 hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69);
4506 ok(hr == S_OK, "got %#lx\n", hr);
4507 ok(state == tmp_state, "got %p\n", state);
4508 IDirectMusicSegmentState_Release(tmp_state);
4510 hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 70);
4511 todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
4514 check_track_state(track, downloaded, FALSE);
4515 check_track_state(track, initialized, TRUE);
4518 /* The track can be removed from the segment */
4519 hr = IDirectMusicSegment_RemoveTrack(segment, track);
4520 ok(hr == S_OK, "got %#lx\n", hr);
4523 ret = test_track_wait_playing(track, 50);
4524 ok(ret == 0, "got %#lx\n", ret);
4526 hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
4527 todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
4530 tmp_segment = (void *)0xdeadbeef;
4531 hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment);
4532 ok(hr == S_OK, "got %#lx\n", hr);
4533 ok(tmp_segment == segment, "got %p\n", tmp_segment);
4534 IDirectMusicSegment_Release(tmp_segment);
4536 time = 0xdeadbeef;
4537 hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
4538 ok(hr == S_OK, "got %#lx\n", hr);
4539 ok(time == 50, "got %lu\n", time);
4540 time = 0xdeadbeef;
4541 hr = IDirectMusicSegmentState_GetRepeats(state, &value);
4542 ok(hr == S_OK, "got %#lx\n", hr);
4543 ok(time == 0xdeadbeef, "got %#lx\n", time);
4544 time = 0xdeadbeef;
4545 hr = IDirectMusicSegmentState_GetStartTime(state, &time);
4546 ok(hr == S_OK, "got %#lx\n", hr);
4547 ok(time == 20, "got %#lx\n", time);
4548 time = 0xdeadbeef;
4550 /* The seek value is also dependent on whether the tracks are playing.
4551 * It is initially 0, then start_point right before playing, then length.
4553 hr = IDirectMusicSegmentState_GetSeek(state, &time);
4554 ok(hr == S_OK, "got %#lx\n", hr);
4555 todo_wine ok(time == 100, "got %#lx\n", time);
4557 /* changing the segment values doesn't change the segment state */
4559 hr = IDirectMusicSegment_SetStartPoint(segment, 0);
4560 ok(hr == S_OK, "got %#lx\n", hr);
4561 hr = IDirectMusicSegment_SetRepeats(segment, 10);
4562 ok(hr == S_OK, "got %#lx\n", hr);
4563 hr = IDirectMusicSegment_SetLoopPoints(segment, 50, 70);
4564 ok(hr == S_OK, "got %#lx\n", hr);
4566 time = 0xdeadbeef;
4567 hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
4568 ok(hr == S_OK, "got %#lx\n", hr);
4569 ok(time == 50, "got %#lx\n", time);
4570 time = 0xdeadbeef;
4571 hr = IDirectMusicSegmentState_GetRepeats(state, &value);
4572 ok(hr == S_OK, "got %#lx\n", hr);
4573 ok(time == 0xdeadbeef, "got %#lx\n", time);
4574 time = 0xdeadbeef;
4575 hr = IDirectMusicSegmentState_GetStartTime(state, &time);
4576 ok(hr == S_OK, "got %#lx\n", hr);
4577 ok(time == 20, "got %#lx\n", time);
4578 time = 0xdeadbeef;
4579 hr = IDirectMusicSegmentState_GetSeek(state, &time);
4580 ok(hr == S_OK, "got %#lx\n", hr);
4581 todo_wine ok(time == 100, "got %#lx\n", time);
4583 IDirectMusicSegment_Release(segment);
4586 check_track_state(track, downloaded, FALSE);
4587 check_track_state(track, initialized, TRUE);
4588 check_track_state(track, playing, TRUE);
4590 hr = IDirectMusicPerformance_CloseDown(performance);
4591 ok(hr == S_OK, "got %#lx\n", hr);
4593 check_track_state(track, downloaded, FALSE);
4594 check_track_state(track, initialized, TRUE);
4595 check_track_state(track, playing, FALSE);
4598 IDirectMusicPerformance_Release(performance);
4599 IDirectMusicTrack_Release(track);
4600 IDirectMusicTool_Release(tool);
4603 START_TEST(dmime)
4605 CoInitialize(NULL);
4607 if (missing_dmime())
4609 skip("dmime not available\n");
4610 CoUninitialize();
4611 return;
4613 test_COM_audiopath();
4614 test_COM_audiopathconfig();
4615 test_COM_graph();
4616 test_COM_segment();
4617 test_COM_segmentstate();
4618 test_COM_track();
4619 test_COM_performance();
4620 test_audiopathconfig();
4621 test_graph();
4622 test_segment();
4623 test_gettrack();
4624 test_segment_param();
4625 test_track();
4626 test_parsedescriptor();
4627 test_performance_InitAudio();
4628 test_performance_createport();
4629 test_performance_pchannel();
4630 test_performance_tool();
4631 test_performance_graph();
4632 test_performance_time();
4633 test_performance_pmsg();
4634 test_notification_pmsg();
4635 test_wave_pmsg();
4636 test_sequence_track();
4637 test_band_track_play();
4638 test_tempo_track_play();
4639 test_connect_to_collection();
4640 test_segment_state();
4642 CoUninitialize();