4673 lines
188 KiB
C
4673 lines
188 KiB
C
|
/*
|
||
|
* Copyright 2012, 2014 Michael Stefaniuc
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||
|
*/
|
||
|
|
||
|
#define COBJMACROS
|
||
|
|
||
|
#include <stdarg.h>
|
||
|
#include <math.h>
|
||
|
#include <windef.h>
|
||
|
#include <wine/test.h>
|
||
|
#include <initguid.h>
|
||
|
#include <ole2.h>
|
||
|
#include <dmusici.h>
|
||
|
#include <dmusicf.h>
|
||
|
#include <audioclient.h>
|
||
|
#include <guiddef.h>
|
||
|
|
||
|
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
|
||
|
DEFINE_GUID(GUID_Bunk,0xFFFFFFFF,0xFFFF,0xFFFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
|
||
|
|
||
|
static ULONG get_refcount(void *iface)
|
||
|
{
|
||
|
IUnknown *unknown = iface;
|
||
|
IUnknown_AddRef(unknown);
|
||
|
return IUnknown_Release(unknown);
|
||
|
}
|
||
|
|
||
|
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c, FALSE)
|
||
|
static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported, BOOL check_refs)
|
||
|
{
|
||
|
ULONG expect_ref = get_refcount(iface_ptr);
|
||
|
IUnknown *iface = iface_ptr;
|
||
|
HRESULT hr, expected;
|
||
|
IUnknown *unk;
|
||
|
|
||
|
expected = supported ? S_OK : E_NOINTERFACE;
|
||
|
hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
|
||
|
ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LONG ref = get_refcount(unk);
|
||
|
if (check_refs) ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref);
|
||
|
IUnknown_Release(unk);
|
||
|
ref = get_refcount(iface_ptr);
|
||
|
if (check_refs) ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static double scale_music_time(MUSIC_TIME time, double tempo)
|
||
|
{
|
||
|
return (600000000.0 * time) / (tempo * DMUS_PPQ);
|
||
|
}
|
||
|
|
||
|
static MUSIC_TIME music_time_from_reference(REFERENCE_TIME time, double tempo)
|
||
|
{
|
||
|
return (time * tempo * DMUS_PPQ) / 600000000;
|
||
|
}
|
||
|
|
||
|
#define check_dmus_note_pmsg(a, b, c, d, e, f, g) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f, g)
|
||
|
static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan,
|
||
|
UINT duration, UINT key, UINT vel, UINT flags)
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
|
||
|
ok_(__FILE__, line)(!!msg->rtTime, "got rtTime %I64u\n", msg->rtTime);
|
||
|
ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
|
||
|
ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel);
|
||
|
ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
|
||
|
ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#lx\n", msg->dwType);
|
||
|
ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
|
||
|
ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID);
|
||
|
ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
|
||
|
ok_(__FILE__, line)(msg->mtDuration == duration, "got mtDuration %lu\n", msg->mtDuration);
|
||
|
ok_(__FILE__, line)(msg->wMusicValue == key, "got wMusicValue %u\n", msg->wMusicValue);
|
||
|
ok_(__FILE__, line)(!msg->wMeasure, "got wMeasure %u\n", msg->wMeasure);
|
||
|
/* FIXME: ok_(__FILE__, line)(!msg->nOffset, "got nOffset %u\n", msg->nOffset); */
|
||
|
/* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */
|
||
|
/* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */
|
||
|
ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity);
|
||
|
ok_(__FILE__, line)(msg->bFlags == flags, "got bFlags %#x\n", msg->bFlags);
|
||
|
ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange);
|
||
|
ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange);
|
||
|
ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange);
|
||
|
ok_(__FILE__, line)(!msg->bPlayModeFlags, "got bPlayModeFlags %#x\n", msg->bPlayModeFlags);
|
||
|
ok_(__FILE__, line)(!msg->bSubChordLevel, "got bSubChordLevel %u\n", msg->bSubChordLevel);
|
||
|
ok_(__FILE__, line)(msg->bMidiValue == key, "got bMidiValue %u\n", msg->bMidiValue);
|
||
|
ok_(__FILE__, line)(!msg->cTranspose, "got cTranspose %u\n", msg->cTranspose);
|
||
|
}
|
||
|
|
||
|
static void load_resource(const WCHAR *name, WCHAR *filename)
|
||
|
{
|
||
|
static WCHAR path[MAX_PATH];
|
||
|
DWORD written;
|
||
|
HANDLE file;
|
||
|
HRSRC res;
|
||
|
void *ptr;
|
||
|
|
||
|
GetTempPathW(ARRAY_SIZE(path), path);
|
||
|
GetTempFileNameW(path, name, 0, filename);
|
||
|
|
||
|
file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
|
||
|
ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError());
|
||
|
|
||
|
res = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA);
|
||
|
ok(res != 0, "couldn't find resource\n");
|
||
|
ptr = LockResource(LoadResource(GetModuleHandleW(NULL ), res ));
|
||
|
WriteFile(file, ptr, SizeofResource(GetModuleHandleW(NULL ), res ), &written, NULL);
|
||
|
ok(written == SizeofResource(GetModuleHandleW(NULL ), res ), "couldn't write resource\n");
|
||
|
CloseHandle(file);
|
||
|
}
|
||
|
|
||
|
static void stream_begin_chunk(IStream *stream, const char type[5], ULARGE_INTEGER *offset)
|
||
|
{
|
||
|
static const LARGE_INTEGER zero = {0};
|
||
|
HRESULT hr;
|
||
|
hr = IStream_Write(stream, type, 4, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, offset);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IStream_Write(stream, "\0\0\0\0", 4, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
}
|
||
|
|
||
|
static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset)
|
||
|
{
|
||
|
static const LARGE_INTEGER zero = {0};
|
||
|
ULARGE_INTEGER position;
|
||
|
HRESULT hr;
|
||
|
UINT size;
|
||
|
hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IStream_Seek(stream, *(LARGE_INTEGER *)offset, STREAM_SEEK_SET, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
size = position.QuadPart - offset->QuadPart - 4;
|
||
|
hr = IStream_Write(stream, &size, 4, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IStream_Write(stream, &zero, (position.QuadPart & 1), NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
}
|
||
|
|
||
|
#define CHUNK_BEGIN(stream, type) \
|
||
|
do { \
|
||
|
ULARGE_INTEGER __off; \
|
||
|
IStream *__stream = (stream); \
|
||
|
stream_begin_chunk(stream, type, &__off); \
|
||
|
do
|
||
|
|
||
|
#define CHUNK_RIFF(stream, form) \
|
||
|
do { \
|
||
|
ULARGE_INTEGER __off; \
|
||
|
IStream *__stream = (stream); \
|
||
|
stream_begin_chunk(stream, "RIFF", &__off); \
|
||
|
IStream_Write(stream, form, 4, NULL); \
|
||
|
do
|
||
|
|
||
|
#define CHUNK_LIST(stream, form) \
|
||
|
do { \
|
||
|
ULARGE_INTEGER __off; \
|
||
|
IStream *__stream = (stream); \
|
||
|
stream_begin_chunk(stream, "LIST", &__off); \
|
||
|
IStream_Write(stream, form, 4, NULL); \
|
||
|
do
|
||
|
|
||
|
#define CHUNK_END \
|
||
|
while (0); \
|
||
|
stream_end_chunk(__stream, &__off); \
|
||
|
} while (0)
|
||
|
|
||
|
#define CHUNK_DATA(stream, type, data) \
|
||
|
CHUNK_BEGIN(stream, type) \
|
||
|
{ \
|
||
|
IStream_Write((stream), &(data), sizeof(data), NULL); \
|
||
|
} \
|
||
|
CHUNK_END
|
||
|
|
||
|
#define CHUNK_ARRAY(stream, type, items) \
|
||
|
CHUNK_BEGIN(stream, type) \
|
||
|
{ \
|
||
|
UINT __size = sizeof(*(items)); \
|
||
|
IStream_Write((stream), &__size, 4, NULL); \
|
||
|
IStream_Write((stream), &(items), sizeof(items), NULL); \
|
||
|
} \
|
||
|
CHUNK_END
|
||
|
|
||
|
struct test_tool
|
||
|
{
|
||
|
IDirectMusicTool IDirectMusicTool_iface;
|
||
|
LONG ref;
|
||
|
|
||
|
IDirectMusicGraph *graph;
|
||
|
const DWORD *types;
|
||
|
DWORD types_count;
|
||
|
|
||
|
SRWLOCK lock;
|
||
|
HANDLE message_event;
|
||
|
DMUS_PMSG *messages[32];
|
||
|
UINT message_count;
|
||
|
};
|
||
|
|
||
|
static DMUS_PMSG *test_tool_push_msg(struct test_tool *tool, DMUS_PMSG *msg)
|
||
|
{
|
||
|
AcquireSRWLockExclusive(&tool->lock);
|
||
|
ok(tool->message_count < ARRAY_SIZE(tool->messages),
|
||
|
"got %u messages\n", tool->message_count + 1);
|
||
|
if (tool->message_count < ARRAY_SIZE(tool->messages))
|
||
|
{
|
||
|
memmove(tool->messages + 1, tool->messages,
|
||
|
tool->message_count * sizeof(*tool->messages));
|
||
|
tool->messages[0] = msg;
|
||
|
tool->message_count++;
|
||
|
msg = NULL;
|
||
|
}
|
||
|
ReleaseSRWLockExclusive(&tool->lock);
|
||
|
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
static struct test_tool *impl_from_IDirectMusicTool(IDirectMusicTool *iface)
|
||
|
{
|
||
|
return CONTAINING_RECORD(iface, struct test_tool, IDirectMusicTool_iface);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_QueryInterface(IDirectMusicTool *iface, REFIID iid, void **out)
|
||
|
{
|
||
|
if (IsEqualGUID(iid, &IID_IUnknown)
|
||
|
|| IsEqualGUID(iid, &IID_IDirectMusicTool))
|
||
|
{
|
||
|
IDirectMusicTool_AddRef(iface);
|
||
|
*out = iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ok(IsEqualGUID(iid, &IID_IDirectMusicTool8) || IsEqualGUID(iid, &IID_IPersistStream),
|
||
|
"got iid %s\n", debugstr_guid(iid));
|
||
|
*out = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_tool_AddRef(IDirectMusicTool *iface)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
return InterlockedIncrement(&tool->ref);
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_tool_Release(IDirectMusicTool *iface)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
ULONG ref = InterlockedDecrement(&tool->ref);
|
||
|
|
||
|
if (!ref)
|
||
|
{
|
||
|
if (tool->graph) IDirectMusicGraph_Release(tool->graph);
|
||
|
ok(!tool->message_count, "got %p\n", &tool->message_count);
|
||
|
CloseHandle(tool->message_event);
|
||
|
free(tool);
|
||
|
}
|
||
|
|
||
|
return ref;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_Init(IDirectMusicTool *iface, IDirectMusicGraph *graph)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
if ((tool->graph = graph)) IDirectMusicGraph_AddRef(tool->graph);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWORD *type)
|
||
|
{
|
||
|
*type = DMUS_PMSGF_TOOL_IMMEDIATE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
*size = tool->types_count;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
UINT i;
|
||
|
for (i = 0; i < tool->types_count; i++) (*types)[i] = tool->types[i];
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
DMUS_PMSG *clone;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
clone = test_tool_push_msg(tool, clone);
|
||
|
ok(!clone, "got %p\n", clone);
|
||
|
SetEvent(tool->message_event);
|
||
|
|
||
|
hr = IDirectMusicGraph_StampPMsg(msg->pGraph, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
return DMUS_S_REQUEUE;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_tool_Flush(IDirectMusicTool *iface, IDirectMusicPerformance *performance,
|
||
|
DMUS_PMSG *msg, REFERENCE_TIME time)
|
||
|
{
|
||
|
ok(0, "unexpected %s\n", __func__);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static IDirectMusicToolVtbl test_tool_vtbl =
|
||
|
{
|
||
|
test_tool_QueryInterface,
|
||
|
test_tool_AddRef,
|
||
|
test_tool_Release,
|
||
|
test_tool_Init,
|
||
|
test_tool_GetMsgDeliveryType,
|
||
|
test_tool_GetMediaTypeArraySize,
|
||
|
test_tool_GetMediaTypes,
|
||
|
test_tool_ProcessPMsg,
|
||
|
test_tool_Flush,
|
||
|
};
|
||
|
|
||
|
static HRESULT test_tool_create(const DWORD *types, DWORD types_count,
|
||
|
IDirectMusicTool **ret_iface)
|
||
|
{
|
||
|
struct test_tool *tool;
|
||
|
|
||
|
*ret_iface = NULL;
|
||
|
if (!(tool = calloc(1, sizeof(*tool)))) return E_OUTOFMEMORY;
|
||
|
tool->IDirectMusicTool_iface.lpVtbl = &test_tool_vtbl;
|
||
|
tool->ref = 1;
|
||
|
|
||
|
tool->types = types;
|
||
|
tool->types_count = types_count;
|
||
|
tool->message_event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||
|
ok(!!tool->message_event, "CreateEventW failed, error %lu\n", GetLastError());
|
||
|
|
||
|
*ret_iface = &tool->IDirectMusicTool_iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT test_tool_get_graph(IDirectMusicTool *iface, IDirectMusicGraph **graph)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
if ((*graph = tool->graph)) IDirectMusicGraph_AddRef(tool->graph);
|
||
|
return tool->graph ? S_OK : DMUS_E_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
static DWORD test_tool_wait_message(IDirectMusicTool *iface, DWORD timeout, DMUS_PMSG **msg)
|
||
|
{
|
||
|
struct test_tool *tool = impl_from_IDirectMusicTool(iface);
|
||
|
DWORD ret = WAIT_FAILED;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
AcquireSRWLockExclusive(&tool->lock);
|
||
|
if (!tool->message_count)
|
||
|
*msg = NULL;
|
||
|
else
|
||
|
{
|
||
|
UINT index = --tool->message_count;
|
||
|
*msg = tool->messages[index];
|
||
|
tool->messages[index] = NULL;
|
||
|
}
|
||
|
ReleaseSRWLockExclusive(&tool->lock);
|
||
|
|
||
|
if (*msg) return 0;
|
||
|
} while (!(ret = WaitForSingleObject(tool->message_event, timeout)));
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
struct test_loader_stream
|
||
|
{
|
||
|
IStream IStream_iface;
|
||
|
IDirectMusicGetLoader IDirectMusicGetLoader_iface;
|
||
|
LONG ref;
|
||
|
|
||
|
IStream *stream;
|
||
|
IDirectMusicLoader *loader;
|
||
|
};
|
||
|
|
||
|
static struct test_loader_stream *impl_from_IStream(IStream *iface)
|
||
|
{
|
||
|
return CONTAINING_RECORD(iface, struct test_loader_stream, IStream_iface);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_QueryInterface(IStream *iface, REFIID iid, void **out)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IStream(iface);
|
||
|
|
||
|
if (IsEqualGUID(iid, &IID_IUnknown)
|
||
|
|| IsEqualGUID(iid, &IID_IStream))
|
||
|
{
|
||
|
IStream_AddRef(&impl->IStream_iface);
|
||
|
*out = &impl->IStream_iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(iid, &IID_IDirectMusicGetLoader))
|
||
|
{
|
||
|
IDirectMusicGetLoader_AddRef(&impl->IDirectMusicGetLoader_iface);
|
||
|
*out = &impl->IDirectMusicGetLoader_iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ok(IsEqualGUID(iid, &IID_IStream),
|
||
|
"got iid %s\n", debugstr_guid(iid));
|
||
|
*out = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_loader_stream_AddRef(IStream *iface)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IStream(iface);
|
||
|
return InterlockedIncrement(&impl->ref);
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_loader_stream_Release(IStream *iface)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IStream(iface);
|
||
|
ULONG ref = InterlockedDecrement(&impl->ref);
|
||
|
|
||
|
if (!ref)
|
||
|
{
|
||
|
IDirectMusicLoader_Release(impl->loader);
|
||
|
IStream_Release(impl->stream);
|
||
|
free(impl);
|
||
|
}
|
||
|
|
||
|
return ref;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IStream(iface);
|
||
|
return IStream_Read(impl->stream, data, size, ret_size);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IStream(iface);
|
||
|
return IStream_Seek(impl->stream, offset, method, ret_offset);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_SetSize(IStream *iface, ULARGE_INTEGER size)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
|
||
|
ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Commit(IStream *iface, DWORD flags)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Revert(IStream *iface)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Stat(IStream *iface, STATSTG *stat, DWORD flags)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_Clone(IStream *iface, IStream **out)
|
||
|
{
|
||
|
ok(0, "Unexpected call.\n");
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static const IStreamVtbl test_loader_stream_vtbl =
|
||
|
{
|
||
|
test_loader_stream_QueryInterface,
|
||
|
test_loader_stream_AddRef,
|
||
|
test_loader_stream_Release,
|
||
|
test_loader_stream_Read,
|
||
|
test_loader_stream_Write,
|
||
|
test_loader_stream_Seek,
|
||
|
test_loader_stream_SetSize,
|
||
|
test_loader_stream_CopyTo,
|
||
|
test_loader_stream_Commit,
|
||
|
test_loader_stream_Revert,
|
||
|
test_loader_stream_LockRegion,
|
||
|
test_loader_stream_UnlockRegion,
|
||
|
test_loader_stream_Stat,
|
||
|
test_loader_stream_Clone,
|
||
|
};
|
||
|
|
||
|
static struct test_loader_stream *impl_from_IDirectMusicGetLoader(IDirectMusicGetLoader *iface)
|
||
|
{
|
||
|
return CONTAINING_RECORD(iface, struct test_loader_stream, IDirectMusicGetLoader_iface);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_getter_QueryInterface(IDirectMusicGetLoader *iface, REFIID iid, void **out)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
|
||
|
return IStream_QueryInterface(&impl->IStream_iface, iid, out);
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_loader_stream_getter_AddRef(IDirectMusicGetLoader *iface)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
|
||
|
return IStream_AddRef(&impl->IStream_iface);
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_loader_stream_getter_Release(IDirectMusicGetLoader *iface)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
|
||
|
return IStream_Release(&impl->IStream_iface);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_loader_stream_getter_GetLoader(IDirectMusicGetLoader *iface, IDirectMusicLoader **ret_loader)
|
||
|
{
|
||
|
struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface);
|
||
|
|
||
|
*ret_loader = impl->loader;
|
||
|
IDirectMusicLoader_AddRef(impl->loader);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static const IDirectMusicGetLoaderVtbl test_loader_stream_getter_vtbl =
|
||
|
{
|
||
|
test_loader_stream_getter_QueryInterface,
|
||
|
test_loader_stream_getter_AddRef,
|
||
|
test_loader_stream_getter_Release,
|
||
|
test_loader_stream_getter_GetLoader,
|
||
|
};
|
||
|
|
||
|
static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *loader,
|
||
|
IStream **ret_iface)
|
||
|
{
|
||
|
struct test_loader_stream *obj;
|
||
|
|
||
|
*ret_iface = NULL;
|
||
|
if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY;
|
||
|
obj->IStream_iface.lpVtbl = &test_loader_stream_vtbl;
|
||
|
obj->IDirectMusicGetLoader_iface.lpVtbl = &test_loader_stream_getter_vtbl;
|
||
|
obj->ref = 1;
|
||
|
|
||
|
obj->stream = stream;
|
||
|
IStream_AddRef(stream);
|
||
|
obj->loader = loader;
|
||
|
IDirectMusicLoader_AddRef(loader);
|
||
|
|
||
|
*ret_iface = &obj->IStream_iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
struct test_track
|
||
|
{
|
||
|
/* Implementing IDirectMusicTrack8 will cause native to call PlayEx */
|
||
|
IDirectMusicTrack IDirectMusicTrack_iface;
|
||
|
LONG ref;
|
||
|
|
||
|
DWORD data;
|
||
|
BOOL inserted;
|
||
|
BOOL initialized;
|
||
|
BOOL downloaded;
|
||
|
BOOL playing;
|
||
|
BOOL test_play;
|
||
|
HANDLE playing_event;
|
||
|
};
|
||
|
|
||
|
#define check_track_state(track, state, value) \
|
||
|
do \
|
||
|
{ \
|
||
|
DWORD ret = impl_from_IDirectMusicTrack(track)->state; \
|
||
|
ok(ret == (value), "got %#lx\n", ret); \
|
||
|
} while (0);
|
||
|
|
||
|
static inline struct test_track *impl_from_IDirectMusicTrack(IDirectMusicTrack *iface)
|
||
|
{
|
||
|
return CONTAINING_RECORD(iface, struct test_track, IDirectMusicTrack_iface);
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_QueryInterface(IDirectMusicTrack *iface, REFIID riid,
|
||
|
void **ret_iface)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
if (IsEqualIID(riid, &IID_IUnknown)
|
||
|
|| IsEqualIID(riid, &IID_IDirectMusicTrack))
|
||
|
{
|
||
|
*ret_iface = &This->IDirectMusicTrack_iface;
|
||
|
IDirectMusicTrack_AddRef(&This->IDirectMusicTrack_iface);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ok(IsEqualGUID(riid, &IID_IDirectMusicTrack8) || IsEqualGUID(riid, &IID_IPersistStream),
|
||
|
"unexpected %s %p %s\n", __func__, This, debugstr_guid(riid));
|
||
|
*ret_iface = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_track_AddRef(IDirectMusicTrack *iface)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
return InterlockedIncrement(&This->ref);
|
||
|
}
|
||
|
|
||
|
static ULONG WINAPI test_track_Release(IDirectMusicTrack *iface)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
ULONG ref = InterlockedDecrement(&This->ref);
|
||
|
|
||
|
if (!ref)
|
||
|
{
|
||
|
CloseHandle(This->playing_event);
|
||
|
free(This);
|
||
|
}
|
||
|
|
||
|
return ref;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_Init(IDirectMusicTrack *iface, IDirectMusicSegment *segment)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
This->inserted = TRUE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_InitPlay(IDirectMusicTrack *iface, IDirectMusicSegmentState *segment_state,
|
||
|
IDirectMusicPerformance *performance, void **state_data, DWORD track_id, DWORD segment_flags)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
ok(!!segment_state, "got %p\n", segment_state);
|
||
|
ok(!!performance, "got %p\n", performance);
|
||
|
ok(!!state_data, "got %p\n", state_data);
|
||
|
ok(!!track_id, "got %lu\n", track_id);
|
||
|
ok(!segment_flags, "got %#lx\n", segment_flags);
|
||
|
This->initialized = TRUE;
|
||
|
|
||
|
*state_data = &This->data;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_EndPlay(IDirectMusicTrack *iface, void *state_data)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
ok(state_data == &This->data, "got %p\n", state_data);
|
||
|
This->playing = FALSE;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data,
|
||
|
MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags,
|
||
|
IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
if (!This->test_play) return S_OK;
|
||
|
|
||
|
ok(state_data == &This->data, "got %p\n", state_data);
|
||
|
ok(start_time == 50, "got %lu\n", start_time);
|
||
|
ok(end_time == 100, "got %lu\n", end_time);
|
||
|
todo_wine ok(time_offset < 0, "got %lu\n", time_offset);
|
||
|
ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK),
|
||
|
"got %#lx\n", segment_flags);
|
||
|
ok(!!performance, "got %p\n", performance);
|
||
|
ok(!!segment_state, "got %p\n", segment_state);
|
||
|
ok(!!track_id, "got %lu\n", track_id);
|
||
|
This->playing = TRUE;
|
||
|
SetEvent(This->playing_event);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_GetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time,
|
||
|
MUSIC_TIME *next, void *param)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
ok(0, "unexpected %s %p\n", __func__, This);
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_SetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, void *param)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
|
||
|
{
|
||
|
This->downloaded = TRUE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
|
||
|
{
|
||
|
This->downloaded = FALSE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ok(0, "unexpected %s %p %s %lu %p\n", __func__, This, debugstr_guid(type), time, param);
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_IsParamSupported(IDirectMusicTrack *iface, REFGUID type)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
|
||
|
if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) return S_OK;
|
||
|
if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) return S_OK;
|
||
|
if (IsEqualGUID(type, &GUID_TimeSignature)) return DMUS_E_TYPE_UNSUPPORTED;
|
||
|
if (IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_TYPE_UNSUPPORTED;
|
||
|
|
||
|
ok(broken(type->Data1 == 0xe8dbd832), /* native also checks some unknown parameter */
|
||
|
"unexpected %s %p %s\n", __func__, This, debugstr_guid(type));
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_AddNotificationType(IDirectMusicTrack *iface, REFGUID type)
|
||
|
{
|
||
|
ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE),
|
||
|
"got %s\n", debugstr_guid(type));
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_RemoveNotificationType(IDirectMusicTrack *iface, REFGUID type)
|
||
|
{
|
||
|
ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE),
|
||
|
"got %s\n", debugstr_guid(type));
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI test_track_Clone(IDirectMusicTrack *iface, MUSIC_TIME start_time,
|
||
|
MUSIC_TIME end_time, IDirectMusicTrack **ret_track)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
ok(0, "unexpected %s %p\n", __func__, This);
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static const IDirectMusicTrackVtbl test_track_vtbl =
|
||
|
{
|
||
|
test_track_QueryInterface,
|
||
|
test_track_AddRef,
|
||
|
test_track_Release,
|
||
|
test_track_Init,
|
||
|
test_track_InitPlay,
|
||
|
test_track_EndPlay,
|
||
|
test_track_Play,
|
||
|
test_track_GetParam,
|
||
|
test_track_SetParam,
|
||
|
test_track_IsParamSupported,
|
||
|
test_track_AddNotificationType,
|
||
|
test_track_RemoveNotificationType,
|
||
|
test_track_Clone,
|
||
|
};
|
||
|
|
||
|
static HRESULT test_track_create(IDirectMusicTrack **ret_iface, BOOL test_play)
|
||
|
{
|
||
|
struct test_track *track;
|
||
|
|
||
|
*ret_iface = NULL;
|
||
|
if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
|
||
|
track->IDirectMusicTrack_iface.lpVtbl = &test_track_vtbl;
|
||
|
track->ref = 1;
|
||
|
track->test_play = test_play;
|
||
|
|
||
|
track->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||
|
ok(!!track->playing_event, "CreateEventW failed, error %lu\n", GetLastError());
|
||
|
|
||
|
*ret_iface = &track->IDirectMusicTrack_iface;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static DWORD test_track_wait_playing(IDirectMusicTrack *iface, DWORD timeout)
|
||
|
{
|
||
|
struct test_track *This = impl_from_IDirectMusicTrack(iface);
|
||
|
return WaitForSingleObject(This->playing_event, timeout);
|
||
|
}
|
||
|
|
||
|
static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic,
|
||
|
IDirectSound **dsound, BOOL set_cooplevel)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance8, (void **)performance);
|
||
|
ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx\n", hr);
|
||
|
if (dmusic) {
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
|
||
|
(void **)dmusic);
|
||
|
ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr);
|
||
|
}
|
||
|
if (dsound) {
|
||
|
hr = DirectSoundCreate8(NULL, (IDirectSound8 **)dsound, NULL);
|
||
|
ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
|
||
|
if (set_cooplevel) {
|
||
|
hr = IDirectSound_SetCooperativeLevel(*dsound, GetForegroundWindow(), DSSCL_PRIORITY);
|
||
|
ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void destroy_performance(IDirectMusicPerformance8 *performance, IDirectMusic *dmusic,
|
||
|
IDirectSound *dsound)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = IDirectMusicPerformance8_CloseDown(performance);
|
||
|
ok(hr == S_OK, "CloseDown failed: %#lx\n", hr);
|
||
|
IDirectMusicPerformance8_Release(performance);
|
||
|
if (dmusic)
|
||
|
IDirectMusic_Release(dmusic);
|
||
|
if (dsound)
|
||
|
IDirectSound_Release(dsound);
|
||
|
}
|
||
|
|
||
|
static BOOL missing_dmime(void)
|
||
|
{
|
||
|
IDirectMusicSegment8 *dms;
|
||
|
HRESULT hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void**)&dms);
|
||
|
|
||
|
if (hr == S_OK && dms)
|
||
|
{
|
||
|
IDirectMusicSegment8_Release(dms);
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void test_COM_audiopath(void)
|
||
|
{
|
||
|
IDirectMusicAudioPath *dmap;
|
||
|
IUnknown *unk;
|
||
|
IDirectMusicPerformance8 *performance;
|
||
|
IDirectSoundBuffer *dsound;
|
||
|
IDirectSoundBuffer8 *dsound8;
|
||
|
IDirectSoundNotify *notify;
|
||
|
IDirectSound3DBuffer *dsound3d;
|
||
|
IKsPropertySet *propset;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
DWORD buffer = 0;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance8, (void**)&performance);
|
||
|
ok(hr == S_OK || broken(hr == E_NOINTERFACE), "DirectMusicPerformance create failed: %#lx\n", hr);
|
||
|
if (!performance) {
|
||
|
win_skip("IDirectMusicPerformance8 not available\n");
|
||
|
return;
|
||
|
}
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL,
|
||
|
DMUS_APATH_SHARED_STEREOPLUSREVERB, 64, DMUS_AUDIOF_ALL, NULL);
|
||
|
ok(hr == S_OK || hr == DSERR_NODRIVER ||
|
||
|
broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED), /* Win 10 testbot */
|
||
|
"DirectMusicPerformance_InitAudio failed: %#lx\n", hr);
|
||
|
if (FAILED(hr)) {
|
||
|
skip("Audio failed to initialize\n");
|
||
|
return;
|
||
|
}
|
||
|
hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &dmap);
|
||
|
ok(hr == S_OK, "DirectMusicPerformance_GetDefaultAudioPath failed: %#lx\n", hr);
|
||
|
|
||
|
/* IDirectMusicObject and IPersistStream are not supported */
|
||
|
hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IDirectMusicObject, (void**)&unk);
|
||
|
ok(FAILED(hr) && !unk, "Unexpected IDirectMusicObject interface: hr=%#lx, iface=%p\n", hr, unk);
|
||
|
if (unk) IUnknown_Release(unk);
|
||
|
hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IPersistStream, (void**)&unk);
|
||
|
ok(FAILED(hr) && !unk, "Unexpected IPersistStream interface: hr=%#lx, iface=%p\n", hr, unk);
|
||
|
if (unk) IUnknown_Release(unk);
|
||
|
|
||
|
/* Same refcount for all DirectMusicAudioPath interfaces */
|
||
|
refcount = IDirectMusicAudioPath_AddRef(dmap);
|
||
|
ok(refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_QueryInterface(dmap, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
ok(unk == (IUnknown*)dmap, "got %p, %p\n", unk, dmap);
|
||
|
refcount = IUnknown_AddRef(unk);
|
||
|
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IDirectSoundBuffer, (void**)&dsound);
|
||
|
ok(hr == S_OK, "Failed: %#lx\n", hr);
|
||
|
IDirectSoundBuffer_Release(dsound);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IDirectSoundBuffer8, (void**)&dsound8);
|
||
|
ok(hr == S_OK, "Failed: %#lx\n", hr);
|
||
|
IDirectSoundBuffer8_Release(dsound8);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IDirectSoundNotify, (void**)¬ify);
|
||
|
ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IDirectSound3DBuffer, (void**)&dsound3d);
|
||
|
ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IKsPropertySet, (void**)&propset);
|
||
|
todo_wine ok(hr == S_OK, "Failed: %#lx\n", hr);
|
||
|
if (propset)
|
||
|
IKsPropertySet_Release(propset);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "Failed: %#lx\n", hr);
|
||
|
IUnknown_Release(unk);
|
||
|
|
||
|
hr = IDirectMusicAudioPath_GetObjectInPath(dmap, DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, buffer, &GUID_NULL,
|
||
|
0, &GUID_NULL, (void**)&unk);
|
||
|
ok(hr == E_NOINTERFACE, "Failed: %#lx\n", hr);
|
||
|
|
||
|
while (IDirectMusicAudioPath_Release(dmap) > 1); /* performance has a reference too */
|
||
|
IDirectMusicPerformance8_CloseDown(performance);
|
||
|
IDirectMusicPerformance8_Release(performance);
|
||
|
}
|
||
|
|
||
|
static void test_COM_audiopathconfig(void)
|
||
|
{
|
||
|
IDirectMusicAudioPath *dmap = (IDirectMusicAudioPath*)0xdeadbeef;
|
||
|
IDirectMusicObject *dmo;
|
||
|
IPersistStream *ps;
|
||
|
IUnknown *unk;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
|
||
|
/* COM aggregation */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IUnknown, (void**)&dmap);
|
||
|
if (hr == REGDB_E_CLASSNOTREG) {
|
||
|
win_skip("DirectMusicAudioPathConfig not registered\n");
|
||
|
return;
|
||
|
}
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"DirectMusicAudioPathConfig create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
|
||
|
ok(!dmap, "dmap = %p\n", dmap);
|
||
|
|
||
|
/* IDirectMusicAudioPath not supported */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicAudioPath, (void**)&dmap);
|
||
|
ok(FAILED(hr) && !dmap,
|
||
|
"Unexpected IDirectMusicAudioPath interface: hr=%#lx, iface=%p\n", hr, dmap);
|
||
|
|
||
|
/* IDirectMusicObject and IPersistStream supported */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "DirectMusicObject create failed: %#lx, expected S_OK\n", hr);
|
||
|
IPersistStream_Release(ps);
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicObject, (void**)&dmo);
|
||
|
ok(hr == S_OK, "DirectMusicObject create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
/* Same refcount for all DirectMusicObject interfaces */
|
||
|
refcount = IDirectMusicObject_AddRef(dmo);
|
||
|
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
|
||
|
hr = IDirectMusicObject_QueryInterface(dmo, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
refcount = IPersistStream_AddRef(ps);
|
||
|
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
|
||
|
IPersistStream_Release(ps);
|
||
|
|
||
|
hr = IDirectMusicObject_QueryInterface(dmo, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
refcount = IUnknown_AddRef(unk);
|
||
|
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
|
||
|
/* IDirectMusicAudioPath still not supported */
|
||
|
hr = IDirectMusicObject_QueryInterface(dmo, &IID_IDirectMusicAudioPath, (void**)&dmap);
|
||
|
ok(FAILED(hr) && !dmap,
|
||
|
"Unexpected IDirectMusicAudioPath interface: hr=%#lx, iface=%p\n", hr, dmap);
|
||
|
|
||
|
while (IDirectMusicObject_Release(dmo));
|
||
|
}
|
||
|
|
||
|
|
||
|
static void test_COM_graph(void)
|
||
|
{
|
||
|
IDirectMusicGraph *dmg = (IDirectMusicGraph*)0xdeadbeef;
|
||
|
IDirectMusicObject *dmo;
|
||
|
IPersistStream *ps;
|
||
|
IUnknown *unk;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
|
||
|
/* COM aggregation */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IUnknown, (void**)&dmg);
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"DirectMusicGraph create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
|
||
|
ok(!dmg, "dmg = %p\n", dmg);
|
||
|
|
||
|
/* Invalid RIID */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory,
|
||
|
(void**)&dmg);
|
||
|
ok(hr == E_NOINTERFACE, "DirectMusicGraph create failed: %#lx, expected E_NOINTERFACE\n", hr);
|
||
|
|
||
|
/* Same refcount for all DirectMusicGraph interfaces */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void**)&dmg);
|
||
|
ok(hr == S_OK, "DirectMusicGraph create failed: %#lx, expected S_OK\n", hr);
|
||
|
refcount = IDirectMusicGraph_AddRef(dmg);
|
||
|
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
|
||
|
hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IDirectMusicObject, (void**)&dmo);
|
||
|
if (hr == E_NOINTERFACE) {
|
||
|
win_skip("DirectMusicGraph without IDirectMusicObject\n");
|
||
|
return;
|
||
|
}
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
|
||
|
refcount = IDirectMusicObject_AddRef(dmo);
|
||
|
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
|
||
|
refcount = IDirectMusicObject_Release(dmo);
|
||
|
|
||
|
hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
refcount = IPersistStream_AddRef(ps);
|
||
|
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
|
||
|
refcount = IPersistStream_Release(ps);
|
||
|
|
||
|
hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
refcount = IUnknown_AddRef(unk);
|
||
|
ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
|
||
|
while (IDirectMusicGraph_Release(dmg));
|
||
|
}
|
||
|
|
||
|
static void test_COM_segment(void)
|
||
|
{
|
||
|
IDirectMusicSegment8 *dms = (IDirectMusicSegment8*)0xdeadbeef;
|
||
|
IDirectMusicObject *dmo;
|
||
|
IPersistStream *stream;
|
||
|
IUnknown *unk;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
|
||
|
/* COM aggregation */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IUnknown, (void**)&dms);
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"DirectMusicSegment create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
|
||
|
ok(!dms, "dms = %p\n", dms);
|
||
|
|
||
|
/* Invalid RIID */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectSound, (void**)&dms);
|
||
|
ok(hr == E_NOINTERFACE, "DirectMusicSegment create failed: %#lx, expected E_NOINTERFACE\n", hr);
|
||
|
|
||
|
/* Same refcount */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment8, (void**)&dms);
|
||
|
if (hr == E_NOINTERFACE) {
|
||
|
win_skip("DirectMusicSegment without IDirectMusicSegment8\n");
|
||
|
return;
|
||
|
}
|
||
|
ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
|
||
|
refcount = IDirectMusicSegment8_AddRef(dms);
|
||
|
ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IDirectMusicObject, (void**)&dmo);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
|
||
|
IDirectMusicSegment8_AddRef(dms);
|
||
|
refcount = IDirectMusicSegment8_Release(dms);
|
||
|
ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IPersistStream, (void**)&stream);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
refcount = IDirectMusicSegment8_Release(dms);
|
||
|
ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
hr = IDirectMusicSegment8_QueryInterface(dms, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
refcount = IDirectMusicObject_Release(dmo);
|
||
|
ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
refcount = IPersistStream_Release(stream);
|
||
|
ok (refcount == 1, "refcount == %lu, expected 1\n", refcount);
|
||
|
refcount = IDirectMusicSegment8_Release(dms);
|
||
|
ok (refcount == 0, "refcount == %lu, expected 0\n", refcount);
|
||
|
}
|
||
|
|
||
|
static void test_COM_segmentstate(void)
|
||
|
{
|
||
|
IDirectMusicSegmentState8 *dmss8 = (IDirectMusicSegmentState8*)0xdeadbeef;
|
||
|
IUnknown *unk;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
|
||
|
/* COM aggregation */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IUnknown, (void**)&dmss8);
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"DirectMusicSegmentState8 create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
|
||
|
ok(!dmss8, "dmss8 = %p\n", dmss8);
|
||
|
|
||
|
/* Invalid RIID */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicObject, (void**)&dmss8);
|
||
|
ok(hr == E_NOINTERFACE, "DirectMusicSegmentState8 create failed: %#lx, expected E_NOINTERFACE\n", hr);
|
||
|
|
||
|
/* Same refcount for all DirectMusicSegmentState interfaces */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegmentState, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegmentState8, (void**)&dmss8);
|
||
|
if (hr == E_NOINTERFACE) {
|
||
|
win_skip("DirectMusicSegmentState without IDirectMusicSegmentState8\n");
|
||
|
return;
|
||
|
}
|
||
|
ok(hr == S_OK, "DirectMusicSegmentState8 create failed: %#lx, expected S_OK\n", hr);
|
||
|
refcount = IDirectMusicSegmentState8_AddRef(dmss8);
|
||
|
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
|
||
|
hr = IDirectMusicSegmentState8_QueryInterface(dmss8, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
refcount = IUnknown_AddRef(unk);
|
||
|
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
|
||
|
hr = IDirectMusicSegmentState8_QueryInterface(dmss8, &IID_IUnknown, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
|
||
|
while (IDirectMusicSegmentState8_Release(dmss8));
|
||
|
}
|
||
|
|
||
|
static void test_COM_track(void)
|
||
|
{
|
||
|
IDirectMusicTrack *dmt;
|
||
|
IDirectMusicTrack8 *dmt8;
|
||
|
IPersistStream *ps;
|
||
|
IUnknown *unk;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
#define X(class) &CLSID_ ## class, #class
|
||
|
const struct {
|
||
|
REFCLSID clsid;
|
||
|
const char *name;
|
||
|
BOOL has_dmt8;
|
||
|
} class[] = {
|
||
|
{ X(DirectMusicLyricsTrack), TRUE },
|
||
|
{ X(DirectMusicMarkerTrack), FALSE },
|
||
|
{ X(DirectMusicParamControlTrack), TRUE },
|
||
|
{ X(DirectMusicSegmentTriggerTrack), TRUE },
|
||
|
{ X(DirectMusicSeqTrack), TRUE },
|
||
|
{ X(DirectMusicSysExTrack), TRUE },
|
||
|
{ X(DirectMusicTempoTrack), TRUE },
|
||
|
{ X(DirectMusicTimeSigTrack), FALSE },
|
||
|
{ X(DirectMusicWaveTrack), TRUE }
|
||
|
};
|
||
|
#undef X
|
||
|
unsigned int i;
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(class); i++) {
|
||
|
trace("Testing %s\n", class[i].name);
|
||
|
/* COM aggregation */
|
||
|
dmt8 = (IDirectMusicTrack8*)0xdeadbeef;
|
||
|
hr = CoCreateInstance(class[i].clsid, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, &IID_IUnknown,
|
||
|
(void**)&dmt8);
|
||
|
if (hr == REGDB_E_CLASSNOTREG) {
|
||
|
win_skip("%s not registered\n", class[i].name);
|
||
|
continue;
|
||
|
}
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"%s create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", class[i].name, hr);
|
||
|
ok(!dmt8, "dmt8 = %p\n", dmt8);
|
||
|
|
||
|
/* Invalid RIID */
|
||
|
hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
|
||
|
(void**)&dmt8);
|
||
|
ok(hr == E_NOINTERFACE, "%s create failed: %#lx, expected E_NOINTERFACE\n", class[i].name, hr);
|
||
|
|
||
|
/* Same refcount for all DirectMusicTrack interfaces */
|
||
|
hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
|
||
|
(void**)&dmt);
|
||
|
ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
|
||
|
refcount = IDirectMusicTrack_AddRef(dmt);
|
||
|
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
|
||
|
hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
refcount = IPersistStream_AddRef(ps);
|
||
|
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
|
||
|
IPersistStream_Release(ps);
|
||
|
|
||
|
hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IUnknown, (void**)&unk);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
|
||
|
refcount = IUnknown_AddRef(unk);
|
||
|
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
|
||
|
refcount = IUnknown_Release(unk);
|
||
|
|
||
|
hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IDirectMusicTrack8, (void**)&dmt8);
|
||
|
if (class[i].has_dmt8) {
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IDirectMusicTrack8 failed: %#lx\n", hr);
|
||
|
refcount = IDirectMusicTrack8_AddRef(dmt8);
|
||
|
ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
|
||
|
refcount = IDirectMusicTrack8_Release(dmt8);
|
||
|
} else {
|
||
|
ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectMusicTrack8 failed: %#lx\n", hr);
|
||
|
refcount = IDirectMusicTrack_AddRef(dmt);
|
||
|
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
|
||
|
}
|
||
|
|
||
|
while (IDirectMusicTrack_Release(dmt));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void test_COM_performance(void)
|
||
|
{
|
||
|
IDirectMusicPerformance *dmp = (IDirectMusicPerformance*)0xdeadbeef;
|
||
|
IDirectMusicPerformance *dmp2;
|
||
|
IDirectMusicPerformance8 *dmp8;
|
||
|
IDirectMusicAudioPath *dmap = NULL;
|
||
|
ULONG refcount;
|
||
|
HRESULT hr;
|
||
|
|
||
|
/* COM aggregation */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IUnknown, (void**)&dmp);
|
||
|
ok(hr == CLASS_E_NOAGGREGATION,
|
||
|
"DirectMusicPerformance create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
|
||
|
ok(!dmp, "dmp = %p\n", dmp);
|
||
|
|
||
|
/* Invalid RIID */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicObject, (void**)&dmp);
|
||
|
ok(hr == E_NOINTERFACE, "DirectMusicPerformance create failed: %#lx, expected E_NOINTERFACE\n", hr);
|
||
|
|
||
|
/* Same refcount */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void**)&dmp);
|
||
|
ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx, expected S_OK\n", hr);
|
||
|
refcount = IDirectMusicPerformance_AddRef(dmp);
|
||
|
ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance2, (void**)&dmp2);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance2 failed: %#lx\n", hr);
|
||
|
IDirectMusicPerformance_AddRef(dmp);
|
||
|
refcount = IDirectMusicPerformance_Release(dmp);
|
||
|
ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance8, (void**)&dmp8);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance8 failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_CreateAudioPath(dmp8, NULL, TRUE, &dmap);
|
||
|
ok(hr == E_POINTER, "Unexpected result from CreateAudioPath: %#lx\n", hr);
|
||
|
ok(dmap == NULL, "Unexpected dmap pointer\n");
|
||
|
refcount = IDirectMusicPerformance_Release(dmp);
|
||
|
ok (refcount == 3, "refcount == %lu, expected 3\n", refcount);
|
||
|
refcount = IDirectMusicPerformance8_Release(dmp8);
|
||
|
ok (refcount == 2, "refcount == %lu, expected 2\n", refcount);
|
||
|
refcount = IDirectMusicPerformance_Release(dmp2);
|
||
|
ok (refcount == 1, "refcount == %lu, expected 1\n", refcount);
|
||
|
refcount = IDirectMusicPerformance_Release(dmp);
|
||
|
ok (refcount == 0, "refcount == %lu, expected 0\n", refcount);
|
||
|
}
|
||
|
|
||
|
static void test_audiopathconfig(void)
|
||
|
{
|
||
|
IDirectMusicObject *dmo;
|
||
|
IPersistStream *ps;
|
||
|
CLSID class = { 0 };
|
||
|
ULARGE_INTEGER size;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicAudioPathConfig, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicObject, (void**)&dmo);
|
||
|
if (hr == REGDB_E_CLASSNOTREG) {
|
||
|
win_skip("DirectMusicAudioPathConfig not registered\n");
|
||
|
return;
|
||
|
}
|
||
|
ok(hr == S_OK, "DirectMusicAudioPathConfig create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
/* IPersistStream */
|
||
|
hr = IDirectMusicObject_QueryInterface(dmo, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetClassID(ps, &class);
|
||
|
ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
|
||
|
ok(IsEqualGUID(&class, &CLSID_DirectMusicAudioPathConfig),
|
||
|
"Expected class CLSID_DirectMusicAudioPathConfig got %s\n", wine_dbgstr_guid(&class));
|
||
|
|
||
|
/* Unimplemented IPersistStream methods */
|
||
|
hr = IPersistStream_IsDirty(ps);
|
||
|
ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetSizeMax(ps, &size);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_Save(ps, NULL, TRUE);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
|
||
|
|
||
|
while (IDirectMusicObject_Release(dmo));
|
||
|
}
|
||
|
|
||
|
static void test_graph(void)
|
||
|
{
|
||
|
IDirectMusicTool *tool1, *tool2, *tmp_tool;
|
||
|
IDirectMusicGraph *graph, *tmp_graph;
|
||
|
IPersistStream *ps;
|
||
|
CLSID class = { 0 };
|
||
|
ULARGE_INTEGER size;
|
||
|
DMUS_PMSG msg;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void**)&graph);
|
||
|
ok(hr == S_OK, "DirectMusicGraph create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
/* IPersistStream */
|
||
|
hr = IDirectMusicGraph_QueryInterface(graph, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetClassID(ps, &class);
|
||
|
ok(hr == S_OK || broken(hr == E_NOTIMPL) /* win2k */, "IPersistStream_GetClassID failed: %#lx\n", hr);
|
||
|
if (hr == S_OK)
|
||
|
ok(IsEqualGUID(&class, &CLSID_DirectMusicGraph),
|
||
|
"Expected class CLSID_DirectMusicGraph got %s\n", wine_dbgstr_guid(&class));
|
||
|
|
||
|
/* Unimplemented IPersistStream methods */
|
||
|
hr = IPersistStream_IsDirty(ps);
|
||
|
ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetSizeMax(ps, &size);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_Save(ps, NULL, TRUE);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
hr = test_tool_create(NULL, 0, &tool1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
trace("created tool1 %p\n", tool1);
|
||
|
hr = test_tool_create(NULL, 0, &tool2);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
trace("created tool2 %p\n", tool2);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, NULL, NULL, 0, -1);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
|
||
|
/* InsertTool initializes the tool */
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = test_tool_get_graph(tool1, &tmp_graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(graph == tmp_graph, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(tmp_graph);
|
||
|
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool2, NULL, 0, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 0, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tool1 == tmp_tool, "got %p\n", tmp_tool);
|
||
|
if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tool2 == tmp_tool, "got %p\n", tmp_tool);
|
||
|
if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 2, &tmp_tool);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
/* cannot insert the tool twice */
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
|
||
|
ok(hr == DMUS_E_ALREADY_EXISTS, "got %#lx\n", hr);
|
||
|
|
||
|
/* test removing the first tool */
|
||
|
hr = IDirectMusicGraph_RemoveTool(graph, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_RemoveTool(graph, tool1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_RemoveTool(graph, tool1);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tool2 == tmp_tool, "got %p\n", tmp_tool);
|
||
|
if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tool1 == tmp_tool, "got %p\n", tmp_tool);
|
||
|
if (hr == S_OK) IDirectMusicTool_Release(tmp_tool);
|
||
|
|
||
|
|
||
|
/* Test basic IDirectMusicGraph_StampPMsg usage */
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool1, "got %p\n", msg.pTool);
|
||
|
|
||
|
ok(!msg.dwSize, "got %ld\n", msg.dwSize);
|
||
|
ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
|
||
|
ok(!msg.mtTime, "got %ld\n", msg.mtTime);
|
||
|
ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags);
|
||
|
ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
|
||
|
ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
|
||
|
ok(!msg.dwType, "got %#lx\n", msg.dwType);
|
||
|
ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
|
||
|
ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
|
||
|
ok(!msg.punkUser, "got %p\n", msg.punkUser);
|
||
|
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool2, "got %p\n", msg.pTool);
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(!msg.pTool, "got %p\n", msg.pTool);
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool1, "got %p\n", msg.pTool);
|
||
|
IDirectMusicGraph_Release(msg.pGraph);
|
||
|
msg.pGraph = NULL;
|
||
|
IDirectMusicGraph_Release(msg.pTool);
|
||
|
msg.pTool = NULL;
|
||
|
|
||
|
|
||
|
/* test StampPMsg with the wrong graph or innexistant tools */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&tmp_graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
msg.pGraph = tmp_graph;
|
||
|
IDirectMusicGraph_AddRef(msg.pGraph);
|
||
|
msg.pTool = tool1;
|
||
|
IDirectMusicTool_AddRef(msg.pTool);
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == tmp_graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool2, "got %p\n", msg.pTool);
|
||
|
IDirectMusicGraph_Release(msg.pGraph);
|
||
|
msg.pGraph = NULL;
|
||
|
|
||
|
msg.pGraph = graph;
|
||
|
IDirectMusicGraph_AddRef(msg.pGraph);
|
||
|
hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
|
||
|
ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == NULL, "got %p\n", msg.pTool);
|
||
|
|
||
|
msg.pTool = tool2;
|
||
|
IDirectMusicTool_AddRef(msg.pTool);
|
||
|
hr = IDirectMusicGraph_InsertTool(tmp_graph, tool1, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(tmp_graph, tool2, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool1, "got %p\n", msg.pTool);
|
||
|
IDirectMusicGraph_Release(msg.pGraph);
|
||
|
msg.pGraph = NULL;
|
||
|
|
||
|
hr = IDirectMusicGraph_RemoveTool(graph, tool1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg);
|
||
|
ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == NULL, "got %p\n", msg.pTool);
|
||
|
|
||
|
IDirectMusicGraph_Release(tmp_graph);
|
||
|
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
IDirectMusicTool_Release(tool2);
|
||
|
IDirectMusicTool_Release(tool1);
|
||
|
}
|
||
|
|
||
|
static void test_segment(void)
|
||
|
{
|
||
|
IDirectMusicSegment *dms;
|
||
|
IPersistStream *ps;
|
||
|
CLSID class = { 0 };
|
||
|
ULARGE_INTEGER size;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void**)&dms);
|
||
|
ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
/* IPersistStream */
|
||
|
hr = IDirectMusicSegment_QueryInterface(dms, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetClassID(ps, &class);
|
||
|
ok(hr == S_OK || broken(hr == E_NOTIMPL) /* win2k */, "IPersistStream_GetClassID failed: %#lx\n", hr);
|
||
|
if (hr == S_OK)
|
||
|
ok(IsEqualGUID(&class, &CLSID_DirectMusicSegment),
|
||
|
"Expected class CLSID_DirectMusicSegment got %s\n", wine_dbgstr_guid(&class));
|
||
|
|
||
|
/* Unimplemented IPersistStream methods */
|
||
|
hr = IPersistStream_IsDirty(ps);
|
||
|
ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetSizeMax(ps, &size);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_Save(ps, NULL, TRUE);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
|
||
|
|
||
|
while (IDirectMusicSegment_Release(dms));
|
||
|
}
|
||
|
|
||
|
static void _add_track(IDirectMusicSegment8 *seg, REFCLSID class, const char *name, DWORD group)
|
||
|
{
|
||
|
IDirectMusicTrack *track;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(class, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
|
||
|
(void**)&track);
|
||
|
ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", name, hr);
|
||
|
hr = IDirectMusicSegment8_InsertTrack(seg, track, group);
|
||
|
if (group)
|
||
|
ok(hr == S_OK, "Inserting %s failed: %#lx, expected S_OK\n", name, hr);
|
||
|
else
|
||
|
ok(hr == E_INVALIDARG, "Inserting %s failed: %#lx, expected E_INVALIDARG\n", name, hr);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
}
|
||
|
|
||
|
#define add_track(seg, class, group) _add_track(seg, &CLSID_DirectMusic ## class, #class, group)
|
||
|
|
||
|
static void _expect_track(IDirectMusicSegment8 *seg, REFCLSID expect, const char *name, DWORD group,
|
||
|
DWORD index, BOOL ignore_guid)
|
||
|
{
|
||
|
IDirectMusicTrack *track;
|
||
|
IPersistStream *ps;
|
||
|
CLSID class;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (ignore_guid)
|
||
|
hr = IDirectMusicSegment8_GetTrack(seg, &GUID_NULL, group, index, &track);
|
||
|
else
|
||
|
hr = IDirectMusicSegment8_GetTrack(seg, expect, group, index, &track);
|
||
|
if (!expect) {
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ok(hr == S_OK, "GetTrack failed: %#lx, expected S_OK\n", hr);
|
||
|
hr = IDirectMusicTrack_QueryInterface(track, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetClassID(ps, &class);
|
||
|
ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
|
||
|
ok(IsEqualGUID(&class, expect), "For group %#lx index %lu: Expected class %s got %s\n",
|
||
|
group, index, name, wine_dbgstr_guid(&class));
|
||
|
|
||
|
IPersistStream_Release(ps);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
}
|
||
|
|
||
|
#define expect_track(seg, class, group, index) \
|
||
|
_expect_track(seg, &CLSID_DirectMusic ## class, #class, group, index, TRUE)
|
||
|
#define expect_guid_track(seg, class, group, index) \
|
||
|
_expect_track(seg, &CLSID_DirectMusic ## class, #class, group, index, FALSE)
|
||
|
|
||
|
static void test_gettrack(void)
|
||
|
{
|
||
|
IDirectMusicSegment8 *seg;
|
||
|
IDirectMusicTrack *track;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment8, (void**)&seg);
|
||
|
ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
add_track(seg, LyricsTrack, 0x0); /* failure */
|
||
|
add_track(seg, LyricsTrack, 0x1); /* idx 0 group 1 */
|
||
|
add_track(seg, ParamControlTrack, 0x3); /* idx 1 group 1, idx 0 group 2 */
|
||
|
add_track(seg, SegmentTriggerTrack, 0x2); /* idx 1 group 2 */
|
||
|
add_track(seg, SeqTrack, 0x1); /* idx 2 group 1 */
|
||
|
add_track(seg, TempoTrack, 0x7); /* idx 3 group 1, idx 2 group 2, idx 0 group 3 */
|
||
|
add_track(seg, WaveTrack, 0xffffffff); /* idx 4 group 1, idx 3 group 2, idx 1 group 3 */
|
||
|
|
||
|
/* Ignore GUID in GetTrack */
|
||
|
hr = IDirectMusicSegment8_GetTrack(seg, &GUID_NULL, 0, 0, &track);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
|
||
|
|
||
|
expect_track(seg, LyricsTrack, 0x1, 0);
|
||
|
expect_track(seg, ParamControlTrack, 0x1, 1);
|
||
|
expect_track(seg, SeqTrack, 0x1, 2);
|
||
|
expect_track(seg, TempoTrack, 0x1, 3);
|
||
|
expect_track(seg, WaveTrack, 0x1, 4);
|
||
|
_expect_track(seg, NULL, "", 0x1, 5, TRUE);
|
||
|
_expect_track(seg, NULL, "", 0x1, DMUS_SEG_ANYTRACK, TRUE);
|
||
|
expect_track(seg, ParamControlTrack, 0x2, 0);
|
||
|
expect_track(seg, WaveTrack, 0x80000000, 0);
|
||
|
expect_track(seg, SegmentTriggerTrack, 0x3, 2); /* groups 1+2 combined index */
|
||
|
expect_track(seg, SeqTrack, 0x3, 3); /* groups 1+2 combined index */
|
||
|
expect_track(seg, TempoTrack, 0x7, 4); /* groups 1+2+3 combined index */
|
||
|
expect_track(seg, TempoTrack, 0xffffffff, 4); /* all groups combined index */
|
||
|
_expect_track(seg, NULL, "", 0xffffffff, DMUS_SEG_ANYTRACK, TRUE);
|
||
|
|
||
|
/* Use the GUID in GetTrack */
|
||
|
hr = IDirectMusicSegment8_GetTrack(seg, &CLSID_DirectMusicLyricsTrack, 0, 0, &track);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "GetTrack failed: %#lx, expected DMUS_E_NOT_FOUND\n", hr);
|
||
|
|
||
|
expect_guid_track(seg, LyricsTrack, 0x1, 0);
|
||
|
expect_guid_track(seg, ParamControlTrack, 0x1, 0);
|
||
|
expect_guid_track(seg, SeqTrack, 0x1, 0);
|
||
|
expect_guid_track(seg, TempoTrack, 0x1, 0);
|
||
|
expect_guid_track(seg, ParamControlTrack, 0x2, 0);
|
||
|
expect_guid_track(seg, SegmentTriggerTrack, 0x3, 0);
|
||
|
expect_guid_track(seg, SeqTrack, 0x3, 0);
|
||
|
expect_guid_track(seg, TempoTrack, 0x7, 0);
|
||
|
expect_guid_track(seg, TempoTrack, 0xffffffff, 0);
|
||
|
|
||
|
IDirectMusicSegment8_Release(seg);
|
||
|
}
|
||
|
|
||
|
static void test_segment_param(void)
|
||
|
{
|
||
|
IDirectMusicSegment8 *seg;
|
||
|
char buf[64];
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment8, (void **)&seg);
|
||
|
ok(hr == S_OK, "DirectMusicSegment create failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
add_track(seg, LyricsTrack, 0x1); /* no params */
|
||
|
add_track(seg, SegmentTriggerTrack, 0x1); /* all params "supported" */
|
||
|
|
||
|
hr = IDirectMusicSegment8_GetParam(seg, NULL, 0x1, 0, 0, NULL, buf);
|
||
|
ok(hr == E_POINTER, "GetParam failed: %#lx, expected E_POINTER\n", hr);
|
||
|
hr = IDirectMusicSegment8_SetParam(seg, NULL, 0x1, 0, 0, buf);
|
||
|
todo_wine ok(hr == E_POINTER, "SetParam failed: %#lx, expected E_POINTER\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, 0, 0, NULL, buf);
|
||
|
ok(hr == DMUS_E_GET_UNSUPPORTED, "GetParam failed: %#lx, expected DMUS_E_GET_UNSUPPORTED\n", hr);
|
||
|
hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, 1, 0, NULL, buf);
|
||
|
ok(hr == DMUS_E_TRACK_NOT_FOUND, "GetParam failed: %#lx, expected DMUS_E_TRACK_NOT_FOUND\n", hr);
|
||
|
hr = IDirectMusicSegment8_GetParam(seg, &GUID_Valid_Start_Time, 0x1, DMUS_SEG_ANYTRACK, 0,
|
||
|
NULL, buf);
|
||
|
ok(hr == DMUS_E_GET_UNSUPPORTED, "GetParam failed: %#lx, expected DMUS_E_GET_UNSUPPORTED\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, 0, 0, buf);
|
||
|
ok(hr == S_OK, "SetParam failed: %#lx, expected S_OK\n", hr);
|
||
|
hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, 1, 0, buf);
|
||
|
todo_wine ok(hr == DMUS_E_TRACK_NOT_FOUND,
|
||
|
"SetParam failed: %#lx, expected DMUS_E_TRACK_NOT_FOUND\n", hr);
|
||
|
hr = IDirectMusicSegment8_SetParam(seg, &GUID_Valid_Start_Time, 0x1, DMUS_SEG_ALLTRACKS,
|
||
|
0, buf);
|
||
|
ok(hr == S_OK, "SetParam failed: %#lx, expected S_OK\n", hr);
|
||
|
|
||
|
IDirectMusicSegment8_Release(seg);
|
||
|
}
|
||
|
|
||
|
static void expect_getparam(IDirectMusicTrack *track, REFGUID type, const char *name,
|
||
|
HRESULT expect)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
char buf[64] = { 0 };
|
||
|
|
||
|
hr = IDirectMusicTrack_GetParam(track, type, 0, NULL, buf);
|
||
|
ok(hr == expect, "GetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
|
||
|
}
|
||
|
|
||
|
static void expect_setparam(IDirectMusicTrack *track, REFGUID type, const char *name,
|
||
|
HRESULT expect)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
char buf[64] = { 0 };
|
||
|
|
||
|
hr = IDirectMusicTrack_SetParam(track, type, 0, buf);
|
||
|
ok(hr == expect, "SetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
|
||
|
}
|
||
|
|
||
|
static void test_track(void)
|
||
|
{
|
||
|
IDirectMusicTrack *dmt;
|
||
|
IDirectMusicTrack8 *dmt8;
|
||
|
IPersistStream *ps;
|
||
|
CLSID classid;
|
||
|
ULARGE_INTEGER size;
|
||
|
HRESULT hr;
|
||
|
#define X(guid) &guid, #guid
|
||
|
const struct {
|
||
|
REFGUID type;
|
||
|
const char *name;
|
||
|
} param_types[] = {
|
||
|
{ X(GUID_BandParam) },
|
||
|
{ X(GUID_ChordParam) },
|
||
|
{ X(GUID_Clear_All_Bands) },
|
||
|
{ X(GUID_CommandParam) },
|
||
|
{ X(GUID_CommandParam2) },
|
||
|
{ X(GUID_CommandParamNext) },
|
||
|
{ X(GUID_ConnectToDLSCollection) },
|
||
|
{ X(GUID_Disable_Auto_Download) },
|
||
|
{ X(GUID_DisableTempo) },
|
||
|
{ X(GUID_DisableTimeSig) },
|
||
|
{ X(GUID_Download) },
|
||
|
{ X(GUID_DownloadToAudioPath) },
|
||
|
{ X(GUID_Enable_Auto_Download) },
|
||
|
{ X(GUID_EnableTempo) },
|
||
|
{ X(GUID_EnableTimeSig) },
|
||
|
{ X(GUID_IDirectMusicBand) },
|
||
|
{ X(GUID_IDirectMusicChordMap) },
|
||
|
{ X(GUID_IDirectMusicStyle) },
|
||
|
{ X(GUID_MuteParam) },
|
||
|
{ X(GUID_Play_Marker) },
|
||
|
{ X(GUID_RhythmParam) },
|
||
|
{ X(GUID_SeedVariations) },
|
||
|
{ X(GUID_StandardMIDIFile) },
|
||
|
{ X(GUID_TempoParam) },
|
||
|
{ X(GUID_TimeSignature) },
|
||
|
{ X(GUID_Unload) },
|
||
|
{ X(GUID_UnloadFromAudioPath) },
|
||
|
{ X(GUID_Valid_Start_Time) },
|
||
|
{ X(GUID_Variations) },
|
||
|
{ X(GUID_NULL) }
|
||
|
};
|
||
|
#undef X
|
||
|
#define X(class) &CLSID_ ## class, #class
|
||
|
const struct {
|
||
|
REFCLSID clsid;
|
||
|
const char *name;
|
||
|
/* bitfield with supported param types */
|
||
|
unsigned int has_params;
|
||
|
} class[] = {
|
||
|
{ X(DirectMusicLyricsTrack), 0 },
|
||
|
{ X(DirectMusicMarkerTrack), 0x8080000 },
|
||
|
{ X(DirectMusicParamControlTrack), 0 },
|
||
|
{ X(DirectMusicSegmentTriggerTrack), 0x3fffffff },
|
||
|
{ X(DirectMusicSeqTrack), ~0 }, /* param methods not implemented */
|
||
|
{ X(DirectMusicSysExTrack), ~0 }, /* param methods not implemented */
|
||
|
{ X(DirectMusicTempoTrack), 0x802100 },
|
||
|
{ X(DirectMusicTimeSigTrack), 0x1004200 },
|
||
|
{ X(DirectMusicWaveTrack), 0x6001c80 }
|
||
|
};
|
||
|
#undef X
|
||
|
unsigned int i, j;
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(class); i++) {
|
||
|
trace("Testing %s\n", class[i].name);
|
||
|
hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack,
|
||
|
(void**)&dmt);
|
||
|
ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
|
||
|
|
||
|
/* IDirectMusicTrack */
|
||
|
if (class[i].has_params != ~0) {
|
||
|
for (j = 0; j < ARRAY_SIZE(param_types); j++) {
|
||
|
hr = IDirectMusicTrack_IsParamSupported(dmt, param_types[j].type);
|
||
|
if (class[i].has_params & (1 << j)) {
|
||
|
ok(hr == S_OK, "IsParamSupported(%s) failed: %#lx, expected S_OK\n",
|
||
|
param_types[j].name, hr);
|
||
|
if (class[i].clsid == &CLSID_DirectMusicSegmentTriggerTrack) {
|
||
|
expect_getparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
expect_setparam(dmt, param_types[j].type, param_types[j].name, S_OK);
|
||
|
} else if (class[i].clsid == &CLSID_DirectMusicMarkerTrack)
|
||
|
expect_setparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_SET_UNSUPPORTED);
|
||
|
else if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
|
||
|
expect_getparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
} else {
|
||
|
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
|
||
|
"IsParamSupported(%s) failed: %#lx, expected DMUS_E_TYPE_UNSUPPORTED\n",
|
||
|
param_types[j].name, hr);
|
||
|
expect_getparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
|
||
|
expect_setparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_TYPE_UNSUPPORTED);
|
||
|
else
|
||
|
expect_setparam(dmt, param_types[j].type, param_types[j].name,
|
||
|
DMUS_E_SET_UNSUPPORTED);
|
||
|
}
|
||
|
|
||
|
/* GetParam / SetParam for IsParamSupported supported types */
|
||
|
if (class[i].clsid == &CLSID_DirectMusicTimeSigTrack) {
|
||
|
expect_getparam(dmt, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
expect_getparam(dmt, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
expect_setparam(dmt, &GUID_TimeSignature, "GUID_TimeSignature",
|
||
|
DMUS_E_SET_UNSUPPORTED);
|
||
|
} else if (class[i].clsid == &CLSID_DirectMusicTempoTrack) {
|
||
|
expect_getparam(dmt, &GUID_DisableTempo, "GUID_DisableTempo",
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
expect_getparam(dmt, &GUID_EnableTempo, "GUID_EnableTempo",
|
||
|
DMUS_E_GET_UNSUPPORTED);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
hr = IDirectMusicTrack_GetParam(dmt, NULL, 0, NULL, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack_GetParam failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack_SetParam(dmt, NULL, 0, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack_SetParam failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack_IsParamSupported(dmt, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack_IsParamSupported failed: %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicTrack_IsParamSupported(dmt, &GUID_IDirectMusicStyle);
|
||
|
ok(hr == E_NOTIMPL, "got: %#lx\n", hr);
|
||
|
}
|
||
|
if (class[i].clsid != &CLSID_DirectMusicMarkerTrack &&
|
||
|
class[i].clsid != &CLSID_DirectMusicTimeSigTrack) {
|
||
|
hr = IDirectMusicTrack_AddNotificationType(dmt, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack_AddNotificationType failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack_RemoveNotificationType(dmt, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack_RemoveNotificationType failed: %#lx\n", hr);
|
||
|
}
|
||
|
hr = IDirectMusicTrack_Clone(dmt, 0, 0, NULL);
|
||
|
todo_wine ok(hr == E_POINTER, "IDirectMusicTrack_Clone failed: %#lx\n", hr);
|
||
|
|
||
|
/* IDirectMusicTrack8 */
|
||
|
hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IDirectMusicTrack8, (void**)&dmt8);
|
||
|
if (hr == S_OK) {
|
||
|
hr = IDirectMusicTrack8_PlayEx(dmt8, NULL, 0, 0, 0, 0, NULL, NULL, 0);
|
||
|
todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_PlayEx failed: %#lx\n", hr);
|
||
|
if (class[i].has_params == ~0) {
|
||
|
hr = IDirectMusicTrack8_GetParamEx(dmt8, NULL, 0, NULL, NULL, NULL, 0);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack8_GetParamEx failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack8_SetParamEx(dmt8, NULL, 0, NULL, NULL, 0);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack8_SetParamEx failed: %#lx\n", hr);
|
||
|
}
|
||
|
hr = IDirectMusicTrack8_Compose(dmt8, NULL, 0, NULL);
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Compose failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack8_Join(dmt8, NULL, 0, NULL, 0, NULL);
|
||
|
if (class[i].clsid == &CLSID_DirectMusicTempoTrack)
|
||
|
todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
|
||
|
else
|
||
|
ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
|
||
|
IDirectMusicTrack8_Release(dmt8);
|
||
|
}
|
||
|
|
||
|
/* IPersistStream */
|
||
|
hr = IDirectMusicTrack_QueryInterface(dmt, &IID_IPersistStream, (void**)&ps);
|
||
|
ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_GetClassID(ps, &classid);
|
||
|
ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
|
||
|
ok(IsEqualGUID(&classid, class[i].clsid),
|
||
|
"Expected class %s got %s\n", class[i].name, wine_dbgstr_guid(&classid));
|
||
|
hr = IPersistStream_IsDirty(ps);
|
||
|
ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
|
||
|
|
||
|
/* Unimplemented IPersistStream methods */
|
||
|
hr = IPersistStream_GetSizeMax(ps, &size);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
|
||
|
hr = IPersistStream_Save(ps, NULL, TRUE);
|
||
|
ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
|
||
|
|
||
|
while (IDirectMusicTrack_Release(dmt));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct chunk {
|
||
|
FOURCC id;
|
||
|
DWORD size;
|
||
|
FOURCC type;
|
||
|
};
|
||
|
|
||
|
#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
|
||
|
|
||
|
/* Generate a RIFF file format stream from an array of FOURCC ids.
|
||
|
RIFF and LIST need to be followed by the form type respectively list type,
|
||
|
followed by the chunks of the list and terminated with 0. */
|
||
|
static IStream *gen_riff_stream(const FOURCC *ids)
|
||
|
{
|
||
|
static const LARGE_INTEGER zero;
|
||
|
int level = -1;
|
||
|
DWORD *sizes[4]; /* Stack for the sizes of RIFF and LIST chunks */
|
||
|
char riff[1024];
|
||
|
char *p = riff;
|
||
|
struct chunk *ck;
|
||
|
IStream *stream;
|
||
|
|
||
|
do {
|
||
|
ck = (struct chunk *)p;
|
||
|
ck->id = *ids++;
|
||
|
switch (ck->id) {
|
||
|
case 0:
|
||
|
*sizes[level] = p - (char *)sizes[level] - sizeof(DWORD);
|
||
|
level--;
|
||
|
break;
|
||
|
case FOURCC_LIST:
|
||
|
case FOURCC_RIFF:
|
||
|
level++;
|
||
|
sizes[level] = &ck->size;
|
||
|
ck->type = *ids++;
|
||
|
p += sizeof(*ck);
|
||
|
break;
|
||
|
case DMUS_FOURCC_GUID_CHUNK:
|
||
|
ck->size = sizeof(GUID_NULL);
|
||
|
p += CHUNK_HDR_SIZE;
|
||
|
memcpy(p, &GUID_NULL, sizeof(GUID_NULL));
|
||
|
p += ck->size;
|
||
|
break;
|
||
|
case DMUS_FOURCC_VERSION_CHUNK:
|
||
|
{
|
||
|
DMUS_VERSION ver = {5, 8};
|
||
|
|
||
|
ck->size = sizeof(ver);
|
||
|
p += CHUNK_HDR_SIZE;
|
||
|
memcpy(p, &ver, sizeof(ver));
|
||
|
p += ck->size;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
/* Just convert the FOURCC id to a WCHAR string */
|
||
|
WCHAR *s;
|
||
|
|
||
|
ck->size = 5 * sizeof(WCHAR);
|
||
|
p += CHUNK_HDR_SIZE;
|
||
|
s = (WCHAR *)p;
|
||
|
s[0] = (char)(ck->id);
|
||
|
s[1] = (char)(ck->id >> 8);
|
||
|
s[2] = (char)(ck->id >> 16);
|
||
|
s[3] = (char)(ck->id >> 24);
|
||
|
s[4] = 0;
|
||
|
p += ck->size;
|
||
|
}
|
||
|
}
|
||
|
} while (level >= 0);
|
||
|
|
||
|
ck = (struct chunk *)riff;
|
||
|
CreateStreamOnHGlobal(NULL, TRUE, &stream);
|
||
|
IStream_Write(stream, riff, ck->size + CHUNK_HDR_SIZE, NULL);
|
||
|
IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
|
||
|
|
||
|
return stream;
|
||
|
}
|
||
|
|
||
|
static void test_parsedescriptor(void)
|
||
|
{
|
||
|
IDirectMusicObject *dmo;
|
||
|
IStream *stream;
|
||
|
DMUS_OBJECTDESC desc;
|
||
|
HRESULT hr;
|
||
|
DWORD valid;
|
||
|
unsigned int i;
|
||
|
/* fourcc ~0 will be replaced later on */
|
||
|
FOURCC alldesc[] =
|
||
|
{
|
||
|
FOURCC_RIFF, ~0, DMUS_FOURCC_CATEGORY_CHUNK, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST,
|
||
|
DMUS_FOURCC_UNAM_CHUNK, DMUS_FOURCC_UCOP_CHUNK, DMUS_FOURCC_UCMT_CHUNK,
|
||
|
DMUS_FOURCC_USBJ_CHUNK, 0, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK, 0
|
||
|
};
|
||
|
FOURCC dupes[] =
|
||
|
{
|
||
|
FOURCC_RIFF, ~0, DMUS_FOURCC_CATEGORY_CHUNK, DMUS_FOURCC_CATEGORY_CHUNK,
|
||
|
DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK,
|
||
|
DMUS_FOURCC_GUID_CHUNK, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, DMUS_FOURCC_UNAM_CHUNK, 0,
|
||
|
FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, mmioFOURCC('I','N','A','M'), 0, 0
|
||
|
};
|
||
|
FOURCC empty[] = {FOURCC_RIFF, ~0, 0};
|
||
|
FOURCC inam[] = {FOURCC_RIFF, ~0, FOURCC_LIST, ~0, mmioFOURCC('I','N','A','M'), 0, 0};
|
||
|
FOURCC noriff[] = {mmioFOURCC('J','U','N','K'), 0};
|
||
|
#define X(class) &CLSID_ ## class, #class
|
||
|
#define Y(form) form, #form
|
||
|
const struct {
|
||
|
REFCLSID clsid;
|
||
|
const char *class;
|
||
|
FOURCC form;
|
||
|
const char *name;
|
||
|
BOOL needs_size;
|
||
|
} forms[] = {
|
||
|
{ X(DirectMusicSegment), Y(DMUS_FOURCC_SEGMENT_FORM), FALSE },
|
||
|
{ X(DirectMusicSegment), Y(mmioFOURCC('W','A','V','E')), FALSE },
|
||
|
{ X(DirectMusicAudioPathConfig), Y(DMUS_FOURCC_AUDIOPATH_FORM), TRUE },
|
||
|
{ X(DirectMusicGraph), Y(DMUS_FOURCC_TOOLGRAPH_FORM), TRUE },
|
||
|
};
|
||
|
#undef X
|
||
|
#undef Y
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(forms); i++) {
|
||
|
trace("Testing %s / %s\n", forms[i].class, forms[i].name);
|
||
|
hr = CoCreateInstance(forms[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
|
||
|
(void **)&dmo);
|
||
|
if (hr != S_OK) {
|
||
|
win_skip("Could not create %s object: %#lx\n", forms[i].class, hr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Nothing loaded */
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
|
||
|
if (forms[i].needs_size) {
|
||
|
todo_wine ok(hr == E_INVALIDARG, "GetDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
|
||
|
}
|
||
|
ok(hr == S_OK, "GetDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
|
||
|
desc.dwValidData);
|
||
|
ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
|
||
|
wine_dbgstr_guid(&desc.guidClass), forms[i].class);
|
||
|
|
||
|
/* Empty RIFF stream */
|
||
|
empty[1] = forms[i].form;
|
||
|
stream = gen_riff_stream(empty);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
if (forms[i].needs_size) {
|
||
|
ok(hr == E_INVALIDARG, "ParseDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
}
|
||
|
ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
|
||
|
desc.dwValidData);
|
||
|
ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
|
||
|
wine_dbgstr_guid(&desc.guidClass), forms[i].class);
|
||
|
|
||
|
/* NULL pointers */
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, &desc);
|
||
|
ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, NULL);
|
||
|
if (forms[i].needs_size)
|
||
|
ok(hr == E_INVALIDARG, "ParseDescriptor failed: %#lx, expected E_INVALIDARG\n", hr);
|
||
|
else
|
||
|
ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, NULL);
|
||
|
ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* Wrong form */
|
||
|
empty[1] = DMUS_FOURCC_CONTAINER_FORM;
|
||
|
stream = gen_riff_stream(empty);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
if (forms[i].needs_size)
|
||
|
ok(hr == DMUS_E_CHUNKNOTFOUND,
|
||
|
"ParseDescriptor failed: %#lx, expected DMUS_E_CHUNKNOTFOUND\n", hr);
|
||
|
else
|
||
|
ok(hr == E_FAIL, "ParseDescriptor failed: %#lx, expected E_FAIL\n", hr);
|
||
|
ok(!desc.dwValidData, "Got valid data %#lx, expected 0\n", desc.dwValidData);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* Not a RIFF stream */
|
||
|
stream = gen_riff_stream(noriff);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
if (forms[i].needs_size)
|
||
|
ok(hr == DMUS_E_CHUNKNOTFOUND,
|
||
|
"ParseDescriptor failed: %#lx, expected DMUS_E_CHUNKNOTFOUND\n", hr);
|
||
|
else
|
||
|
ok(hr == E_FAIL, "ParseDescriptor failed: %#lx, expected E_FAIL\n", hr);
|
||
|
ok(!desc.dwValidData, "Got valid data %#lx, expected 0\n", desc.dwValidData);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* All desc chunks */
|
||
|
alldesc[1] = forms[i].form;
|
||
|
stream = gen_riff_stream(alldesc);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
valid = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS | DMUS_OBJ_VERSION;
|
||
|
if (forms[i].form != mmioFOURCC('W','A','V','E'))
|
||
|
valid |= DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY;
|
||
|
ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
|
||
|
ok(IsEqualGUID(&desc.guidClass, forms[i].clsid), "Got class guid %s, expected CLSID_%s\n",
|
||
|
wine_dbgstr_guid(&desc.guidClass), forms[i].class);
|
||
|
ok(IsEqualGUID(&desc.guidObject, &GUID_NULL), "Got object guid %s, expected GUID_NULL\n",
|
||
|
wine_dbgstr_guid(&desc.guidClass));
|
||
|
ok(desc.vVersion.dwVersionMS == 5 && desc.vVersion.dwVersionLS == 8,
|
||
|
"Got version %lu.%lu, expected 5.8\n", desc.vVersion.dwVersionMS,
|
||
|
desc.vVersion.dwVersionLS);
|
||
|
if (forms[i].form != mmioFOURCC('W','A','V','E'))
|
||
|
ok(!lstrcmpW(desc.wszName, L"UNAM"), "Got name '%s', expected 'UNAM'\n",
|
||
|
wine_dbgstr_w(desc.wszName));
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* Duplicated chunks */
|
||
|
dupes[1] = forms[i].form;
|
||
|
stream = gen_riff_stream(dupes);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* UNFO list with INAM */
|
||
|
inam[1] = forms[i].form;
|
||
|
inam[3] = DMUS_FOURCC_UNFO_LIST;
|
||
|
stream = gen_riff_stream(inam);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
|
||
|
desc.dwValidData);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
/* INFO list with INAM */
|
||
|
inam[3] = DMUS_FOURCC_INFO_LIST;
|
||
|
stream = gen_riff_stream(inam);
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.dwSize = sizeof(desc);
|
||
|
hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
|
||
|
ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
|
||
|
valid = DMUS_OBJ_CLASS;
|
||
|
if (forms[i].form == mmioFOURCC('W','A','V','E'))
|
||
|
valid |= DMUS_OBJ_NAME;
|
||
|
ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
|
||
|
if (forms[i].form == mmioFOURCC('W','A','V','E'))
|
||
|
ok(!lstrcmpW(desc.wszName, L"I"), "Got name '%s', expected 'I'\n",
|
||
|
wine_dbgstr_w(desc.wszName));
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
IDirectMusicObject_Release(dmo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void test_performance_InitAudio(void)
|
||
|
{
|
||
|
DMUS_PORTPARAMS params =
|
||
|
{
|
||
|
.dwSize = sizeof(params),
|
||
|
.dwValidParams = DMUS_PORTPARAMS_EFFECTS,
|
||
|
.dwEffectFlags = 1,
|
||
|
};
|
||
|
IDirectMusicPerformance8 *performance;
|
||
|
IDirectMusic *dmusic;
|
||
|
IDirectSound *dsound;
|
||
|
IDirectMusicPort *port;
|
||
|
IDirectMusicAudioPath *path;
|
||
|
DWORD channel, group;
|
||
|
HRESULT hr;
|
||
|
ULONG ref;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance8, (void **)&performance);
|
||
|
if (hr != S_OK) {
|
||
|
win_skip("Cannot create DirectMusicPerformance object (%lx)\n", hr);
|
||
|
CoUninitialize();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
dsound = NULL;
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL,
|
||
|
DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL);
|
||
|
if (hr != S_OK) {
|
||
|
IDirectMusicPerformance8_Release(performance);
|
||
|
win_skip("InitAudio failed (%lx)\n", hr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 128, &port, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 127, &port, NULL, NULL);
|
||
|
ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
IDirectMusicPort_Release(port);
|
||
|
port = NULL;
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL);
|
||
|
ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
ok(port != NULL, "IDirectMusicPort not set\n");
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(performance, 0, port, 0, 0);
|
||
|
ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr);
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(performance, 0, port, 0);
|
||
|
ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr);
|
||
|
IDirectMusicPort_Release(port);
|
||
|
|
||
|
hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &path);
|
||
|
ok(hr == S_OK, "Failed to call GetDefaultAudioPath (%lx)\n", hr);
|
||
|
if (hr == S_OK)
|
||
|
IDirectMusicAudioPath_Release(path);
|
||
|
|
||
|
hr = IDirectMusicPerformance8_CloseDown(performance);
|
||
|
ok(hr == S_OK, "Failed to call CloseDown (%lx)\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance8_Release(performance);
|
||
|
|
||
|
/* Auto generated dmusic and dsound */
|
||
|
create_performance(&performance, NULL, NULL, FALSE);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, 0, 64, 0, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, NULL);
|
||
|
|
||
|
/* Refcounts for auto generated dmusic and dsound */
|
||
|
create_performance(&performance, NULL, NULL, FALSE);
|
||
|
dmusic = NULL;
|
||
|
dsound = NULL;
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
|
||
|
ref = get_refcount(dmusic);
|
||
|
ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
|
||
|
destroy_performance(performance, NULL, NULL);
|
||
|
|
||
|
/* dsound without SetCooperativeLevel() */
|
||
|
create_performance(&performance, NULL, &dsound, FALSE);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
|
||
|
todo_wine ok(hr == DSERR_PRIOLEVELNEEDED, "InitAudio failed: %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, dsound);
|
||
|
|
||
|
/* Using the wrong CLSID_DirectSound */
|
||
|
create_performance(&performance, NULL, NULL, FALSE);
|
||
|
hr = DirectSoundCreate(NULL, &dsound, NULL);
|
||
|
ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
|
||
|
todo_wine ok(hr == E_NOINTERFACE, "InitAudio failed: %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, dsound);
|
||
|
|
||
|
/* Init() works with just a CLSID_DirectSound */
|
||
|
create_performance(&performance, NULL, NULL, FALSE);
|
||
|
hr = DirectSoundCreate(NULL, &dsound, NULL);
|
||
|
ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
|
||
|
hr = IDirectSound_SetCooperativeLevel(dsound, GetForegroundWindow(), DSSCL_PRIORITY);
|
||
|
ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL);
|
||
|
ok(hr == S_OK, "Init failed: %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, dsound);
|
||
|
|
||
|
/* Init() followed by InitAudio() */
|
||
|
create_performance(&performance, NULL, &dsound, TRUE);
|
||
|
hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL);
|
||
|
ok(hr == S_OK, "Init failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL);
|
||
|
ok(hr == DMUS_E_ALREADY_INITED, "InitAudio failed: %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, dsound);
|
||
|
|
||
|
/* Provided dmusic and dsound */
|
||
|
create_performance(&performance, &dmusic, &dsound, TRUE);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
|
||
|
ref = get_refcount(dmusic);
|
||
|
ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
|
||
|
destroy_performance(performance, dmusic, dsound);
|
||
|
|
||
|
/* Provided dmusic initialized with SetDirectSound */
|
||
|
create_performance(&performance, &dmusic, &dsound, TRUE);
|
||
|
hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
|
||
|
ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, NULL, NULL, 0, 64, 0, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
|
||
|
ref = get_refcount(dmusic);
|
||
|
ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
|
||
|
destroy_performance(performance, dmusic, dsound);
|
||
|
|
||
|
/* Provided dmusic and dsound, dmusic initialized with SetDirectSound */
|
||
|
create_performance(&performance, &dmusic, &dsound, TRUE);
|
||
|
hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
|
||
|
ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
ref = get_refcount(dsound);
|
||
|
ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
|
||
|
ref = get_refcount(dmusic);
|
||
|
ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref);
|
||
|
destroy_performance(performance, dmusic, dsound);
|
||
|
|
||
|
/* Provided dmusic and dsound, dmusic initialized with SetDirectSound, port created and activated */
|
||
|
create_performance(&performance, &dmusic, &dsound, TRUE);
|
||
|
hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
|
||
|
ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
|
||
|
hr = IDirectMusic_CreatePort(dmusic, &CLSID_DirectMusicSynth, ¶ms, &port, NULL);
|
||
|
ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPort_Activate(port, TRUE);
|
||
|
ok(hr == S_OK, "Activate failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPort_SetNumChannelGroups(port, 1);
|
||
|
ok(hr == S_OK, "SetNumChannelGroups failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_Init(performance, &dmusic, dsound, 0);
|
||
|
ok(hr == S_OK, "Init failed: %#lx\n", hr);
|
||
|
destroy_performance(performance, dmusic, dsound);
|
||
|
|
||
|
/* InitAudio with perf channel count not a multiple of 16 rounds up */
|
||
|
create_performance(&performance, NULL, NULL, TRUE);
|
||
|
hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL,
|
||
|
DMUS_APATH_SHARED_STEREOPLUSREVERB, 29, DMUS_AUDIOF_ALL, NULL);
|
||
|
ok(hr == S_OK, "InitAudio failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 31, &port, &group, &channel);
|
||
|
ok(hr == S_OK && group == 2 && channel == 15,
|
||
|
"PChannelInfo failed, got %#lx, %lu, %lu\n", hr, group, channel);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(performance, 32, &port, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
destroy_performance(performance, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
static void test_performance_createport(void)
|
||
|
{
|
||
|
IDirectMusicPerformance8 *perf;
|
||
|
IDirectMusic *music = NULL;
|
||
|
IDirectMusicPort *port = NULL;
|
||
|
DMUS_PORTCAPS portcaps;
|
||
|
DMUS_PORTPARAMS portparams;
|
||
|
DWORD i;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL,
|
||
|
CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance8, (void**)&perf);
|
||
|
ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance8_Init(perf, &music, NULL, NULL);
|
||
|
ok(hr == S_OK, "Init failed: %#lx\n", hr);
|
||
|
ok(music != NULL, "Didn't get IDirectMusic pointer\n");
|
||
|
|
||
|
i = 0;
|
||
|
while(1){
|
||
|
portcaps.dwSize = sizeof(portcaps);
|
||
|
|
||
|
hr = IDirectMusic_EnumPort(music, i, &portcaps);
|
||
|
ok(hr == S_OK || hr == S_FALSE || (i == 0 && hr == E_INVALIDARG), "EnumPort failed: %#lx\n", hr);
|
||
|
if(hr != S_OK)
|
||
|
break;
|
||
|
|
||
|
ok(portcaps.dwSize == sizeof(portcaps), "Got unexpected portcaps struct size: %lu\n", portcaps.dwSize);
|
||
|
trace("portcaps(%lu).dwFlags: %#lx\n", i, portcaps.dwFlags);
|
||
|
trace("portcaps(%lu).guidPort: %s\n", i, wine_dbgstr_guid(&portcaps.guidPort));
|
||
|
trace("portcaps(%lu).dwClass: %#lx\n", i, portcaps.dwClass);
|
||
|
trace("portcaps(%lu).dwType: %#lx\n", i, portcaps.dwType);
|
||
|
trace("portcaps(%lu).dwMemorySize: %#lx\n", i, portcaps.dwMemorySize);
|
||
|
trace("portcaps(%lu).dwMaxChannelGroups: %lu\n", i, portcaps.dwMaxChannelGroups);
|
||
|
trace("portcaps(%lu).dwMaxVoices: %lu\n", i, portcaps.dwMaxVoices);
|
||
|
trace("portcaps(%lu).dwMaxAudioChannels: %lu\n", i, portcaps.dwMaxAudioChannels);
|
||
|
trace("portcaps(%lu).dwEffectFlags: %#lx\n", i, portcaps.dwEffectFlags);
|
||
|
trace("portcaps(%lu).wszDescription: %s\n", i, wine_dbgstr_w(portcaps.wszDescription));
|
||
|
|
||
|
++i;
|
||
|
}
|
||
|
|
||
|
if(i == 0){
|
||
|
win_skip("No ports available, skipping tests\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
portparams.dwSize = sizeof(portparams);
|
||
|
|
||
|
/* dwValidParams == 0 -> S_OK, filled struct */
|
||
|
portparams.dwValidParams = 0;
|
||
|
hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
|
||
|
ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
|
||
|
ok(portparams.dwValidParams, "portparams struct was not filled in\n");
|
||
|
IDirectMusicPort_Release(port);
|
||
|
port = NULL;
|
||
|
|
||
|
/* dwValidParams != 0, invalid param -> S_FALSE, filled struct */
|
||
|
portparams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
|
||
|
portparams.dwChannelGroups = 0;
|
||
|
hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
|
||
|
todo_wine ok(hr == S_FALSE, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
|
||
|
ok(portparams.dwValidParams, "portparams struct was not filled in\n");
|
||
|
IDirectMusicPort_Release(port);
|
||
|
port = NULL;
|
||
|
|
||
|
/* dwValidParams != 0, valid params -> S_OK */
|
||
|
hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL);
|
||
|
ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
|
||
|
IDirectMusicPort_Release(port);
|
||
|
port = NULL;
|
||
|
|
||
|
/* GUID_NULL succeeds */
|
||
|
portparams.dwValidParams = 0;
|
||
|
hr = IDirectMusic_CreatePort(music, &GUID_NULL, &portparams, &port, NULL);
|
||
|
ok(hr == S_OK, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port != NULL, "Didn't get IDirectMusicPort pointer\n");
|
||
|
ok(portparams.dwValidParams, "portparams struct was not filled in\n");
|
||
|
IDirectMusicPort_Release(port);
|
||
|
port = NULL;
|
||
|
|
||
|
/* null GUID fails */
|
||
|
portparams.dwValidParams = 0;
|
||
|
hr = IDirectMusic_CreatePort(music, NULL, &portparams, &port, NULL);
|
||
|
ok(hr == E_POINTER, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port);
|
||
|
ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n");
|
||
|
|
||
|
/* garbage GUID fails */
|
||
|
portparams.dwValidParams = 0;
|
||
|
hr = IDirectMusic_CreatePort(music, &GUID_Bunk, &portparams, &port, NULL);
|
||
|
ok(hr == E_NOINTERFACE, "CreatePort failed: %#lx\n", hr);
|
||
|
ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port);
|
||
|
ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n");
|
||
|
|
||
|
hr = IDirectMusicPerformance8_CloseDown(perf);
|
||
|
ok(hr == S_OK, "CloseDown failed: %#lx\n", hr);
|
||
|
|
||
|
IDirectMusic_Release(music);
|
||
|
IDirectMusicPerformance8_Release(perf);
|
||
|
}
|
||
|
|
||
|
static void test_performance_pchannel(void)
|
||
|
{
|
||
|
IDirectMusicPerformance8 *perf;
|
||
|
IDirectMusicPort *port = NULL, *port2;
|
||
|
DWORD channel, group;
|
||
|
unsigned int i;
|
||
|
HRESULT hr;
|
||
|
|
||
|
create_performance(&perf, NULL, NULL, TRUE);
|
||
|
hr = IDirectMusicPerformance8_Init(perf, NULL, NULL, NULL);
|
||
|
ok(hr == S_OK, "Init failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG && !port, "PChannelInfo failed, got %#lx, %p\n", hr, port);
|
||
|
|
||
|
/* Add default port. Sets PChannels 0-15 to the corresponding channels in group 1 */
|
||
|
hr = IDirectMusicPerformance8_AddPort(perf, NULL);
|
||
|
ok(hr == S_OK, "AddPort of default port failed: %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, NULL, NULL, NULL);
|
||
|
ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL);
|
||
|
ok(hr == S_OK && port, "PChannelInfo failed, got %#lx, %p\n", hr, port);
|
||
|
for (i = 1; i < 16; i++) {
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port == port2 && group == 1 && channel == i,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
}
|
||
|
|
||
|
/* Unset PChannels fail to retrieve */
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 16, &port2, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD - 16, &port2, NULL, NULL);
|
||
|
ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port);
|
||
|
|
||
|
/* Channel group 0 can be set just fine */
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(perf, 0, port, 0, 0);
|
||
|
ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, 0, port, 0);
|
||
|
ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr);
|
||
|
for (i = 1; i < 16; i++) {
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port == port2 && group == 0 && channel == i,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
}
|
||
|
|
||
|
/* Last PChannel Block can be set only individually but not read */
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(perf, MAXDWORD, port, 0, 3);
|
||
|
ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
|
||
|
port2 = (IDirectMusicPort *)0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD, &port2, NULL, NULL);
|
||
|
todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef,
|
||
|
"PChannelInfo failed, got %#lx, %p\n", hr, port2);
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD, port, 0);
|
||
|
ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16, port, 1);
|
||
|
todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
|
||
|
for (i = MAXDWORD - 15; i < MAXDWORD; i++) {
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 0, 0);
|
||
|
ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, NULL, NULL);
|
||
|
todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef,
|
||
|
"PChannelInfo failed, got %#lx, %p\n", hr, port2);
|
||
|
}
|
||
|
|
||
|
/* Second to last PChannel Block can be set only individually and read */
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 1, port, 1);
|
||
|
todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr);
|
||
|
for (i = MAXDWORD - 31; i < MAXDWORD - 15; i++) {
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 1, 7);
|
||
|
ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port2 == port && group == 1 && channel == 7,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
}
|
||
|
|
||
|
/* Third to last PChannel Block behaves normal */
|
||
|
hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 2, port, 0);
|
||
|
ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr);
|
||
|
for (i = MAXDWORD - 47; i < MAXDWORD - 31; i++) {
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port2 == port && group == 0 && channel == i % 16,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
}
|
||
|
|
||
|
/* One PChannel set in a Block, rest is initialized too */
|
||
|
hr = IDirectMusicPerformance8_AssignPChannel(perf, 4711, port, 1, 13);
|
||
|
ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 4711, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port2 == port && group == 1 && channel == 13,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
group = channel = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 4712, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port2 == port && group == 0 && channel == 8,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
group = channel = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance8_PChannelInfo(perf, 4719, &port2, &group, &channel);
|
||
|
ok(hr == S_OK && port2 == port && group == 0 && channel == 15,
|
||
|
"PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel);
|
||
|
IDirectMusicPort_Release(port2);
|
||
|
|
||
|
IDirectMusicPort_Release(port);
|
||
|
destroy_performance(perf, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
static void test_performance_tool(void)
|
||
|
{
|
||
|
DMUS_NOTE_PMSG note60 =
|
||
|
{
|
||
|
.dwSize = sizeof(DMUS_NOTE_PMSG),
|
||
|
.dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE,
|
||
|
.dwVirtualTrackID = 1,
|
||
|
.dwType = DMUS_PMSGT_NOTE,
|
||
|
.dwGroupID = 1,
|
||
|
.mtDuration = 1000,
|
||
|
.wMusicValue = 60,
|
||
|
.bVelocity = 127,
|
||
|
.bFlags = DMUS_NOTEF_NOTEON,
|
||
|
.bPlayModeFlags = DMUS_PLAYMODE_FIXED,
|
||
|
.bMidiValue = 60,
|
||
|
};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTool *tool;
|
||
|
DWORD value, types[1];
|
||
|
DMUS_NOTE_PMSG *note;
|
||
|
DMUS_PMSG msg = {0};
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
check_interface(performance, &IID_IDirectMusicTool8, FALSE);
|
||
|
|
||
|
hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicTool, (void **)&tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicTool_Init(tool, graph);
|
||
|
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
|
||
|
value = 0xdeadbeef;
|
||
|
hr = IDirectMusicTool_GetMsgDeliveryType(tool, &value);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(value == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", value);
|
||
|
value = 0xdeadbeef;
|
||
|
hr = IDirectMusicTool_GetMediaTypeArraySize(tool, &value);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(value == 0, "got %#lx\n", value);
|
||
|
hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64);
|
||
|
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg);
|
||
|
ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicTool_Flush(tool, performance, &msg, 0);
|
||
|
todo_wine ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, NULL, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_AddPort(performance, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_NOTE_PMSG), (DMUS_PMSG **)¬e);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
note->bFlags = 0;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
note->mtDuration = 0;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
|
||
|
ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0,
|
||
|
"got %I64d\n", note->rtTime - note60.rtTime);
|
||
|
ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime);
|
||
|
check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
note->nOffset = 1000;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
|
||
|
ok(fabs(note->rtTime - note60.rtTime - scale_music_time(999, 120.0)) < 10.0,
|
||
|
"got %I64d\n", note->rtTime - note60.rtTime);
|
||
|
ok(note->mtTime - note60.mtTime == 999, "got %ld\n", note->mtTime - note60.mtTime);
|
||
|
check_dmus_note_pmsg(note, note60.mtTime + 999, 0, 1000, 60, 127, 0);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
note->mtDuration = 2;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
|
||
|
ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0,
|
||
|
"got %I64d\n", note->rtTime - note60.rtTime);
|
||
|
ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime);
|
||
|
check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 2, 60, 127, 0);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, ¬e60.mtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, note60.mtTime, ¬e60.rtTime);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
*note = note60;
|
||
|
note->mtDuration = 1;
|
||
|
hr = IDirectMusicTool_ProcessPMsg(tool, performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == DMUS_S_REQUEUE, "got %#lx\n", hr);
|
||
|
ok(fabs(note->rtTime - note60.rtTime - scale_music_time(1, 120.0)) < 10.0,
|
||
|
"got %I64d\n", note->rtTime - note60.rtTime);
|
||
|
ok(note->mtTime - note60.mtTime == 1, "got %ld\n", note->mtTime - note60.mtTime);
|
||
|
check_dmus_note_pmsg(note, note60.mtTime + 1, 0, 1, 60, 127, 0);
|
||
|
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
}
|
||
|
|
||
|
static void test_performance_graph(void)
|
||
|
{
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicGraph *graph, *tmp_graph;
|
||
|
IDirectMusicTool *tool, *tmp_tool;
|
||
|
DMUS_PMSG msg;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = test_tool_create(NULL, 0, &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* performance exposes a graph interface but it's not an actual toolgraph */
|
||
|
hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool);
|
||
|
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_RemoveTool(graph, tool);
|
||
|
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
|
||
|
|
||
|
/* test IDirectMusicGraph_StampPMsg usage */
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool != NULL, "got %p\n", msg.pTool);
|
||
|
check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
|
||
|
|
||
|
ok(!msg.dwSize, "got %ld\n", msg.dwSize);
|
||
|
ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
|
||
|
ok(!msg.mtTime, "got %ld\n", msg.mtTime);
|
||
|
ok(msg.dwFlags == DMUS_PMSGF_TOOL_QUEUE, "got %#lx\n", msg.dwFlags);
|
||
|
ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
|
||
|
ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
|
||
|
ok(!msg.dwType, "got %#lx\n", msg.dwType);
|
||
|
ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
|
||
|
ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
|
||
|
ok(!msg.punkUser, "got %p\n", msg.punkUser);
|
||
|
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool != NULL, "got %p\n", msg.pTool);
|
||
|
check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
|
||
|
|
||
|
IDirectMusicTool_Release(msg.pTool);
|
||
|
msg.pTool = NULL;
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
/* performance doesn't have a default embedded toolgraph */
|
||
|
hr = IDirectMusicPerformance_GetGraph(performance, &graph);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* test adding a graph to the performance */
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetGraph(performance, &tmp_graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tmp_graph == graph, "got %p\n", graph);
|
||
|
IDirectMusicGraph_Release(tmp_graph);
|
||
|
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
/* test IDirectMusicGraph_StampPMsg usage */
|
||
|
hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == graph, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool == tool, "got %p\n", msg.pTool);
|
||
|
|
||
|
ok(!msg.dwSize, "got %ld\n", msg.dwSize);
|
||
|
ok(!msg.rtTime, "got %I64d\n", msg.rtTime);
|
||
|
ok(!msg.mtTime, "got %ld\n", msg.mtTime);
|
||
|
ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags);
|
||
|
ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel);
|
||
|
ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID);
|
||
|
ok(!msg.dwType, "got %#lx\n", msg.dwType);
|
||
|
ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID);
|
||
|
ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID);
|
||
|
ok(!msg.punkUser, "got %p\n", msg.punkUser);
|
||
|
|
||
|
hr = IDirectMusicGraph_StampPMsg(graph, &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg.pGraph == NULL, "got %p\n", msg.pGraph);
|
||
|
ok(msg.pTool != NULL, "got %p\n", msg.pTool);
|
||
|
check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE);
|
||
|
|
||
|
IDirectMusicTool_Release(msg.pTool);
|
||
|
msg.pTool = NULL;
|
||
|
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
#define check_reference_time(a, b) check_reference_time_(__LINE__, a, b)
|
||
|
static void check_reference_time_(int line, REFERENCE_TIME time, double expect)
|
||
|
{
|
||
|
ok_(__FILE__, line)(llabs(time - (REFERENCE_TIME)expect) <= scale_music_time(1, 120) / 2.0,
|
||
|
"got %I64u, expected %f\n", time, expect);
|
||
|
}
|
||
|
|
||
|
static void test_performance_time(void)
|
||
|
{
|
||
|
IDirectMusicPerformance *performance;
|
||
|
REFERENCE_TIME init_time, time;
|
||
|
IReferenceClock *clock;
|
||
|
MUSIC_TIME music_time;
|
||
|
IDirectMusic *dmusic;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
|
||
|
ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
|
||
|
ok(time == 0, "got %I64d\n", time);
|
||
|
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, &music_time);
|
||
|
ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
|
||
|
ok(music_time == 0, "got %ld\n", music_time);
|
||
|
|
||
|
|
||
|
dmusic = NULL;
|
||
|
hr = IDirectMusicPerformance_Init(performance, &dmusic, NULL, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusic_GetMasterClock(dmusic, NULL, &clock);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusic_Release(dmusic);
|
||
|
hr = IReferenceClock_GetTime(clock, &init_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IReferenceClock_Release(clock);
|
||
|
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time - init_time <= 100 * 10000, "got %I64d\n", time - init_time);
|
||
|
init_time = time;
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(1, 120));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(1000, 120));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(2000, 120));
|
||
|
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 0, "got %ld\n", music_time);
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(1000, 120), &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 1000, "got %ld\n", music_time);
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(2000, 120), &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 2000, "got %ld\n", music_time);
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time - init_time <= 200 * 10000, "got %I64d\n", time - init_time);
|
||
|
ok(abs(music_time - music_time_from_reference(time - init_time, 120)) <= 1, "got %ld\n", music_time);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
|
||
|
}
|
||
|
|
||
|
static void test_performance_pmsg(void)
|
||
|
{
|
||
|
static const DWORD delivery_flags[] = {DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGF_TOOL_ATTIME};
|
||
|
static const DWORD message_types[] = {DMUS_PMSGT_MIDI, DMUS_PMSGT_USER};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicGraph *graph, *performance_graph;
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_PMSG *msg, *clone;
|
||
|
MUSIC_TIME music_time;
|
||
|
REFERENCE_TIME time;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
UINT i;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&performance_graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, 0, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG) - 1, &msg);
|
||
|
ok(hr == E_INVALIDARG, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
ok(!msg->rtTime, "got %I64d\n", msg->rtTime);
|
||
|
ok(!msg->mtTime, "got %ld\n", msg->mtTime);
|
||
|
ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags);
|
||
|
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
|
||
|
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
|
||
|
ok(!msg->dwType, "got %#lx\n", msg->dwType);
|
||
|
ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
|
||
|
ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
|
||
|
ok(!msg->punkUser, "got %p\n", msg->punkUser);
|
||
|
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
ok(!msg->rtTime, "got %I64d\n", msg->rtTime);
|
||
|
ok(!msg->mtTime, "got %ld\n", msg->mtTime);
|
||
|
ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags);
|
||
|
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
|
||
|
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
|
||
|
ok(!msg->pTool, "got %p\n", msg->pTool);
|
||
|
ok(!msg->pGraph, "got %p\n", msg->pGraph);
|
||
|
ok(!msg->dwType, "got %#lx\n", msg->dwType);
|
||
|
ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
|
||
|
ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
|
||
|
ok(!msg->punkUser, "got %p\n", msg->punkUser);
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == E_INVALIDARG, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, NULL, &clone);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
clone = NULL;
|
||
|
hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(clone != NULL, "got %p\n", clone);
|
||
|
|
||
|
msg->mtTime = 500;
|
||
|
msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE;
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == DMUS_E_ALREADY_SENT, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == DMUS_E_CANNOT_FREE, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, clone);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* SendPMsg skips all the tools unless messages are stamped beforehand */
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
msg->mtTime = 0;
|
||
|
msg->dwFlags = DMUS_PMSGF_MUSICTIME;
|
||
|
msg->dwType = DMUS_PMSGT_USER;
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 10, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
ok(!msg, "got %p\n", msg);
|
||
|
|
||
|
|
||
|
/* SendPMsg converts music time to reference time if it is missing */
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
msg->mtTime = 500;
|
||
|
msg->dwFlags = DMUS_PMSGF_MUSICTIME;
|
||
|
msg->dwType = DMUS_PMSGT_USER;
|
||
|
hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg != NULL, "got %p\n", msg);
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
|
||
|
ok(msg->mtTime == 500, "got %ld\n", msg->mtTime);
|
||
|
ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
|
||
|
ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
|
||
|
ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
|
||
|
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
|
||
|
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
|
||
|
ok(msg->pTool == tool, "got %p\n", msg->pTool);
|
||
|
ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph);
|
||
|
ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType);
|
||
|
ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
|
||
|
ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
|
||
|
ok(!msg->punkUser, "got %p\n", msg->punkUser);
|
||
|
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* SendPMsg converts reference time to music time if it is missing */
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
msg->rtTime = time;
|
||
|
msg->dwFlags = DMUS_PMSGF_REFTIME;
|
||
|
msg->dwType = DMUS_PMSGT_USER;
|
||
|
hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg != NULL, "got %p\n", msg);
|
||
|
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, msg->rtTime, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
|
||
|
ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime);
|
||
|
ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
|
||
|
ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
|
||
|
ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
|
||
|
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
|
||
|
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
|
||
|
ok(msg->pTool == tool, "got %p\n", msg->pTool);
|
||
|
ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph);
|
||
|
ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType);
|
||
|
ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID);
|
||
|
ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID);
|
||
|
ok(!msg->punkUser, "got %p\n", msg->punkUser);
|
||
|
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(delivery_flags); i++)
|
||
|
{
|
||
|
DWORD duration = 0;
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, &time, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
|
||
|
msg->rtTime = time + 150 * 10000;
|
||
|
msg->dwFlags = DMUS_PMSGF_REFTIME;
|
||
|
msg->dwType = DMUS_PMSGT_USER;
|
||
|
hr = IDirectMusicGraph_StampPMsg(performance_graph, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME);
|
||
|
msg->dwFlags |= delivery_flags[i];
|
||
|
|
||
|
duration -= GetTickCount();
|
||
|
hr = IDirectMusicPerformance_SendPMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
msg = NULL;
|
||
|
ret = test_tool_wait_message(tool, 1000, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg != NULL, "got %p\n", msg);
|
||
|
duration += GetTickCount();
|
||
|
|
||
|
if (msg) hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
switch (delivery_flags[i])
|
||
|
{
|
||
|
case DMUS_PMSGF_TOOL_IMMEDIATE: ok(duration <= 50, "got %lu\n", duration); break;
|
||
|
case DMUS_PMSGF_TOOL_QUEUE: ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break;
|
||
|
case DMUS_PMSGF_TOOL_ATTIME: ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
IDirectMusicGraph_Release(performance_graph);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
#define check_dmus_dirty_pmsg(a, b) check_dmus_dirty_pmsg_(__LINE__, a, b)
|
||
|
static void check_dmus_dirty_pmsg_(int line, DMUS_PMSG *msg, MUSIC_TIME music_time)
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize);
|
||
|
ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime);
|
||
|
ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | DMUS_PMSGF_TOOL_IMMEDIATE),
|
||
|
"got dwFlags %#lx\n", msg->dwFlags);
|
||
|
ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel);
|
||
|
ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID);
|
||
|
ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool);
|
||
|
ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph);
|
||
|
ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_DIRTY, "got dwType %#lx\n", msg->dwType);
|
||
|
ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID);
|
||
|
todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID);
|
||
|
ok_(__FILE__, line)(msg->punkUser == 0, "got punkUser %p\n", msg->punkUser);
|
||
|
}
|
||
|
|
||
|
#define check_dmus_notification_pmsg(a, b, c, d, e, f) check_dmus_notification_pmsg_(__LINE__, a, b, c, d, e, f)
|
||
|
static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, MUSIC_TIME music_time, DWORD flags,
|
||
|
const GUID *type, DWORD option, void *user)
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize);
|
||
|
ok_(__FILE__, line)(msg->rtTime > 0, "got rtTime %I64d\n", msg->rtTime);
|
||
|
ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime);
|
||
|
todo_wine_if(flags == DMUS_PMSGF_TOOL_ATTIME)
|
||
|
ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | flags),
|
||
|
"got dwFlags %#lx\n", msg->dwFlags);
|
||
|
ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel);
|
||
|
ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID);
|
||
|
if (flags == DMUS_PMSGF_TOOL_ATTIME)
|
||
|
{
|
||
|
todo_wine ok_(__FILE__, line)(msg->pTool == 0, "got pTool %p\n", msg->pTool);
|
||
|
ok_(__FILE__, line)(msg->pGraph == 0, "got pGraph %p\n", msg->pGraph);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool);
|
||
|
ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph);
|
||
|
}
|
||
|
ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTIFICATION, "got dwType %#lx\n", msg->dwType);
|
||
|
ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID);
|
||
|
todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID);
|
||
|
ok_(__FILE__, line)(msg->punkUser == (IUnknown *)user, "got punkUser %p\n", msg->punkUser);
|
||
|
|
||
|
ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type),
|
||
|
"got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType));
|
||
|
ok_(__FILE__, line)(msg->dwNotificationOption == option,
|
||
|
"got dwNotificationOption %#lx\n", msg->dwNotificationOption);
|
||
|
ok_(__FILE__, line)(!msg->dwField1, "got dwField1 %lu\n", msg->dwField1);
|
||
|
ok_(__FILE__, line)(!msg->dwField2, "got dwField2 %lu\n", msg->dwField2);
|
||
|
|
||
|
if (!IsEqualGUID(&msg->guidNotificationType, &GUID_NOTIFICATION_SEGMENT))
|
||
|
ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
|
||
|
else
|
||
|
{
|
||
|
check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState, TRUE, FALSE);
|
||
|
check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState8, TRUE, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void test_notification_pmsg(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
DMUS_PMSGT_NOTIFICATION,
|
||
|
DMUS_PMSGT_WAVE,
|
||
|
};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicSegmentState *state;
|
||
|
DMUS_NOTIFICATION_PMSG *notif;
|
||
|
MUSIC_TIME music_time, length;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicTrack *track;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_PMSG *msg;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* native needs a track or the segment will end immediately */
|
||
|
|
||
|
hr = test_track_create(&track, FALSE);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
|
||
|
/* native sends dirty / notification by batch of 1s, shorter length
|
||
|
* will cause all messages to be received immediately */
|
||
|
length = 10005870 / 6510;
|
||
|
hr = IDirectMusicSegment_SetLength(segment, length);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time + length);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 100, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
ok(!msg, "got %p\n", msg);
|
||
|
|
||
|
|
||
|
/* AddNotificationType is necessary to receive notification messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||
|
|
||
|
/* avoid discarding older notifications */
|
||
|
hr = IDirectMusicPerformance_SetNotificationHandle(performance, 0, 100000000);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE,
|
||
|
DMUS_NOTIFICATION_MUSICSTARTED, NULL);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGSTART, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGALMOSTEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time + length);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE,
|
||
|
DMUS_NOTIFICATION_MUSICSTOPPED, NULL);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* wait enough time for notifications to be delivered */
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 2000, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
ok(!msg, "got %p\n", msg);
|
||
|
|
||
|
|
||
|
/* notification messages are also queued for direct access */
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE,
|
||
|
DMUS_NOTIFICATION_MUSICSTARTED, NULL);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGSTART, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGALMOSTEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE,
|
||
|
DMUS_NOTIFICATION_MUSICSTOPPED, NULL);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicSegmentState_Release(state);
|
||
|
|
||
|
hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* RemoveNotificationType returns S_FALSE if already removed */
|
||
|
|
||
|
hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE);
|
||
|
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* Stop finishes segment immediately and skips notification messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGSTART, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_Stop(performance, NULL, NULL, 0, DMUS_SEGF_DEFAULT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
if (notif->dwNotificationOption == DMUS_NOTIFICATION_SEGALMOSTEND)
|
||
|
{
|
||
|
check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_IMMEDIATE,
|
||
|
&GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE,
|
||
|
&GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time + length);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
}
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGABORT, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got dwType %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 100, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
|
||
|
IDirectMusicSegmentState_Release(state);
|
||
|
|
||
|
|
||
|
/* CloseDown removes all notifications and notification messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT,
|
||
|
DMUS_NOTIFICATION_SEGSTART, state);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if);
|
||
|
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT);
|
||
|
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 50, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_dirty_pmsg(msg, music_time);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicSegmentState_Release(state);
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
static void test_wave_pmsg(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
DMUS_PMSGT_WAVE,
|
||
|
};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicLoader8 *loader;
|
||
|
IDirectMusicGraph *graph;
|
||
|
WCHAR test_wav[MAX_PATH];
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_WAVE_PMSG *wave;
|
||
|
MUSIC_TIME length;
|
||
|
DMUS_PMSG *msg;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
hr = IDirectMusicPerformance8_InitAudio((IDirectMusicPerformance8 *)performance, NULL, NULL, NULL,
|
||
|
DMUS_APATH_SHARED_STEREOPLUSREVERB, 64, DMUS_AUDIOF_ALL, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
load_resource(L"test.wav", test_wav);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicLoader8, (void **)&loader);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicLoader8_LoadObjectFromFile(loader, &CLSID_DirectMusicSegment,
|
||
|
&IID_IDirectMusicSegment, test_wav, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicLoader8_Release(loader);
|
||
|
|
||
|
|
||
|
length = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegment_GetLength(segment, &length);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(length == 1, "got %lu\n", length);
|
||
|
|
||
|
|
||
|
/* without Download, no DMUS_PMSGT_WAVE is sent */
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 100, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
ok(!msg, "got %p\n", msg);
|
||
|
|
||
|
|
||
|
/* a single DMUS_PMSGT_WAVE message is sent with punkUser set */
|
||
|
|
||
|
hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&wave);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(wave->dwType == DMUS_PMSGT_WAVE, "got %p\n", wave);
|
||
|
ok(!!wave->punkUser, "got %p\n", wave->punkUser);
|
||
|
ok(wave->rtStartOffset == 0, "got %I64d\n", wave->rtStartOffset);
|
||
|
ok(wave->rtDuration == 1000000, "got %I64d\n", wave->rtDuration);
|
||
|
ok(wave->lOffset == 0, "got %lu\n", wave->lOffset);
|
||
|
ok(wave->lVolume == 0, "got %lu\n", wave->lVolume);
|
||
|
ok(wave->lPitch == 0, "got %lu\n", wave->lPitch);
|
||
|
ok(wave->bFlags == 0, "got %#x\n", wave->bFlags);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)wave);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 100, &msg);
|
||
|
ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret);
|
||
|
ok(!msg, "got %p\n", msg);
|
||
|
|
||
|
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
static void test_sequence_track(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_MIDI,
|
||
|
DMUS_PMSGT_NOTE,
|
||
|
DMUS_PMSGT_CURVE,
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
};
|
||
|
static const LARGE_INTEGER zero = {0};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTrack *track;
|
||
|
IPersistStream *persist;
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_NOTE_PMSG *note;
|
||
|
IStream *stream;
|
||
|
DMUS_PMSG *msg;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
/* create a segment and load a simple RIFF stream */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMSG")
|
||
|
{
|
||
|
/* set a non-zero segment length, or nothing will be played */
|
||
|
DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000};
|
||
|
CHUNK_DATA(stream, "segh", head);
|
||
|
CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IPersistStream_Load(persist, stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
|
||
|
/* add a sequence track to our segment */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSeqTrack, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicTrack, (void **)&track);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
CHUNK_BEGIN(stream, "seqt")
|
||
|
{
|
||
|
DMUS_IO_SEQ_ITEM items[] =
|
||
|
{
|
||
|
{.mtTime = 0, .mtDuration = 500, .dwPChannel = 0, .bStatus = 0x90, .bByte1 = 60, .bByte2 = 120},
|
||
|
{.mtTime = 1000, .mtDuration = 200, .dwPChannel = 1, .bStatus = 0x90, .bByte1 = 50, .bByte2 = 100},
|
||
|
};
|
||
|
CHUNK_ARRAY(stream, "evtl", items);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IPersistStream_Load(persist, stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
|
||
|
|
||
|
/* now play the segment, and check produced messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_note_pmsg(note, 0, 0, 500, 60, 120, DMUS_NOTEF_NOTEON);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100, DMUS_NOTEF_NOTEON);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
#define check_dmus_patch_pmsg(a, b, c, d, e) check_dmus_patch_pmsg_(__LINE__, a, b, c, d, e)
|
||
|
static void check_dmus_patch_pmsg_(int line, DMUS_PATCH_PMSG *msg, MUSIC_TIME time, UINT chan,
|
||
|
UINT bank, UINT patch)
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
|
||
|
ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime);
|
||
|
ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
|
||
|
ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel);
|
||
|
ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
|
||
|
ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_PATCH, "got %#lx\n", msg->dwType);
|
||
|
ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
|
||
|
ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID);
|
||
|
ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
|
||
|
ok_(__FILE__, line)(msg->byInstrument == patch, "got byInstrument %u\n", msg->byInstrument);
|
||
|
ok_(__FILE__, line)(msg->byMSB == bank >> 8, "got byMSB %u\n", msg->byMSB);
|
||
|
ok_(__FILE__, line)(msg->byLSB == (bank & 0xff), "got byLSB %u\n", msg->byLSB);
|
||
|
}
|
||
|
|
||
|
static void test_band_track_play(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_MIDI,
|
||
|
DMUS_PMSGT_NOTE,
|
||
|
DMUS_PMSGT_SYSEX,
|
||
|
DMUS_PMSGT_NOTIFICATION,
|
||
|
DMUS_PMSGT_TEMPO,
|
||
|
DMUS_PMSGT_CURVE,
|
||
|
DMUS_PMSGT_TIMESIG,
|
||
|
DMUS_PMSGT_PATCH,
|
||
|
DMUS_PMSGT_TRANSPOSE,
|
||
|
DMUS_PMSGT_CHANNEL_PRIORITY,
|
||
|
DMUS_PMSGT_STOP,
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
DMUS_PMSGT_WAVE,
|
||
|
DMUS_PMSGT_LYRIC,
|
||
|
DMUS_PMSGT_SCRIPTLYRIC,
|
||
|
DMUS_PMSGT_USER,
|
||
|
};
|
||
|
DMUS_OBJECTDESC desc =
|
||
|
{
|
||
|
.dwSize = sizeof(DMUS_OBJECTDESC),
|
||
|
.dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH,
|
||
|
.guidClass = CLSID_DirectMusicCollection,
|
||
|
.guidObject = GUID_DefaultGMCollection,
|
||
|
.wszFileName = L"C:\\windows\\system32\\drivers\\gm.dls",
|
||
|
};
|
||
|
static const LARGE_INTEGER zero = {0};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IStream *stream, *loader_stream;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicLoader *loader;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTrack *track;
|
||
|
IPersistStream *persist;
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_PATCH_PMSG *patch;
|
||
|
DMUS_PMSG *msg;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
/* create a segment and load a simple RIFF stream */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMSG")
|
||
|
{
|
||
|
/* set a non-zero segment length, or nothing will be played */
|
||
|
DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000};
|
||
|
CHUNK_DATA(stream, "segh", head);
|
||
|
CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IPersistStream_Load(persist, stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
|
||
|
/* add a sequence track to our segment */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicTrack, (void **)&track);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMBT")
|
||
|
{
|
||
|
DMUS_IO_BAND_TRACK_HEADER head = {.bAutoDownload = TRUE};
|
||
|
|
||
|
CHUNK_DATA(stream, "bdth", head);
|
||
|
CHUNK_LIST(stream, "lbdl")
|
||
|
{
|
||
|
CHUNK_LIST(stream, "lbnd")
|
||
|
{
|
||
|
DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 0};
|
||
|
CHUNK_DATA(stream, "bdih", head);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMBD")
|
||
|
{
|
||
|
GUID guid = CLSID_DirectMusicBand;
|
||
|
CHUNK_DATA(stream, "guid", guid);
|
||
|
|
||
|
CHUNK_LIST(stream, "lbil")
|
||
|
{
|
||
|
CHUNK_LIST(stream, "lbin")
|
||
|
{
|
||
|
DMUS_IO_INSTRUMENT head = {.dwPatch = 1, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH};
|
||
|
CHUNK_DATA(stream, "bins", head);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
CHUNK_LIST(stream, "lbnd")
|
||
|
{
|
||
|
DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 1000};
|
||
|
CHUNK_DATA(stream, "bdih", head);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMBD")
|
||
|
{
|
||
|
GUID guid = CLSID_DirectMusicBand;
|
||
|
CHUNK_DATA(stream, "guid", guid);
|
||
|
|
||
|
CHUNK_LIST(stream, "lbil")
|
||
|
{
|
||
|
CHUNK_LIST(stream, "lbin")
|
||
|
{
|
||
|
DMUS_IO_INSTRUMENT head = {.dwPatch = 2, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH};
|
||
|
CHUNK_DATA(stream, "bins", head);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
CHUNK_LIST(stream, "lbin")
|
||
|
{
|
||
|
DMUS_IO_INSTRUMENT head = {.dwPatch = 3, .dwPChannel = 2, .dwFlags = DMUS_IO_INST_PATCH};
|
||
|
CHUNK_DATA(stream, "bins", head);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
/* band track requires the stream to implement IDirectMusicGetLoader */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicLoader8, (void **)&loader);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicLoader_SetObject(loader, &desc);
|
||
|
if (hr == DMUS_E_LOADER_FAILEDOPEN)
|
||
|
skip("Failed to open gm.dls, missing system SoundFont?\n");
|
||
|
else
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = test_loader_stream_create(stream, loader, &loader_stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicLoader8_Release(loader);
|
||
|
|
||
|
hr = IPersistStream_Load(persist, loader_stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IStream_Release(loader_stream);
|
||
|
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
|
||
|
|
||
|
/* now play the segment, and check produced messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_patch_pmsg(patch, 0, 1, 0, 1);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_patch_pmsg(patch, 1000, 2, 0, 3);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_patch_pmsg(patch, 1000, 1, 0, 2);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
#define check_dmus_tempo_pmsg(a, b, c) check_dmus_tempo_pmsg_(__LINE__, a, b, c)
|
||
|
static void check_dmus_tempo_pmsg_(int line, DMUS_TEMPO_PMSG *msg, MUSIC_TIME time, double tempo)
|
||
|
{
|
||
|
ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize);
|
||
|
ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime);
|
||
|
ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime);
|
||
|
ok_(__FILE__, line)(!msg->dwPChannel, "got dwPChannel %lu\n", msg->dwPChannel);
|
||
|
ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID);
|
||
|
ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_TEMPO, "got dwType %#lx\n", msg->dwType);
|
||
|
ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID);
|
||
|
ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %lu\n", msg->dwGroupID);
|
||
|
ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser);
|
||
|
ok_(__FILE__, line)(msg->dblTempo == tempo, "got tempo %f\n", msg->dblTempo);
|
||
|
}
|
||
|
|
||
|
static void test_tempo_track_play(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_MIDI,
|
||
|
DMUS_PMSGT_NOTE,
|
||
|
DMUS_PMSGT_SYSEX,
|
||
|
DMUS_PMSGT_NOTIFICATION,
|
||
|
DMUS_PMSGT_TEMPO,
|
||
|
DMUS_PMSGT_CURVE,
|
||
|
DMUS_PMSGT_TIMESIG,
|
||
|
DMUS_PMSGT_PATCH,
|
||
|
DMUS_PMSGT_TRANSPOSE,
|
||
|
DMUS_PMSGT_CHANNEL_PRIORITY,
|
||
|
DMUS_PMSGT_STOP,
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
DMUS_PMSGT_WAVE,
|
||
|
DMUS_PMSGT_LYRIC,
|
||
|
DMUS_PMSGT_SCRIPTLYRIC,
|
||
|
DMUS_PMSGT_USER,
|
||
|
};
|
||
|
static const LARGE_INTEGER zero = {0};
|
||
|
DMUS_IO_TEMPO_ITEM tempo_items[] =
|
||
|
{
|
||
|
{.lTime = 100, .dblTempo = 80},
|
||
|
{.lTime = 300, .dblTempo = 60},
|
||
|
{.lTime = 200, .dblTempo = 20},
|
||
|
{.lTime = 4000, .dblTempo = 50},
|
||
|
};
|
||
|
IDirectMusicPerformance *performance;
|
||
|
MUSIC_TIME music_time, next_time;
|
||
|
REFERENCE_TIME init_time, time;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTrack *track;
|
||
|
IPersistStream *persist;
|
||
|
IDirectMusicTool *tool;
|
||
|
DMUS_TEMPO_PMSG *tempo;
|
||
|
DMUS_TEMPO_PARAM param;
|
||
|
IStream *stream;
|
||
|
DMUS_PMSG *msg;
|
||
|
HRESULT hr;
|
||
|
DWORD ret;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
/* create a segment and load a simple RIFF stream */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
CHUNK_RIFF(stream, "DMSG")
|
||
|
{
|
||
|
/* set a non-zero segment length, or nothing will be played */
|
||
|
DMUS_IO_SEGMENT_HEADER head = {.mtLength = 1000};
|
||
|
CHUNK_DATA(stream, "segh", head);
|
||
|
CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment);
|
||
|
}
|
||
|
CHUNK_END;
|
||
|
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IPersistStream_Load(persist, stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
|
||
|
/* add a tempo track to our segment */
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicTempoTrack, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicTrack, (void **)&track);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
CHUNK_ARRAY(stream, "tetr", tempo_items);
|
||
|
hr = IStream_Seek(stream, zero, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IPersistStream_Load(persist, stream);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IPersistStream_Release(persist);
|
||
|
IStream_Release(stream);
|
||
|
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m);
|
||
|
ok(hr == DMUS_E_TRACK_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
memset(¶m, 0xcd, sizeof(param));
|
||
|
next_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 100, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 200, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 101, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 100, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 1, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 3700, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo);
|
||
|
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, ¶m);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(next_time == 0, "got next_time %lu\n", next_time);
|
||
|
ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime);
|
||
|
ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo);
|
||
|
|
||
|
|
||
|
/* now play the segment, and check produced messages */
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
/* the tempo track only takes effect after DMUS_PMSGT_DIRTY */
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
init_time = time;
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(1, 120));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(100, 120));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80));
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_reference_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20));
|
||
|
|
||
|
music_time = 0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 0, "got %ld\n", music_time);
|
||
|
music_time = 0xdeadbeef;
|
||
|
time = scale_music_time(100, 120) + scale_music_time(50, 80);
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 150, "got %ld\n", music_time);
|
||
|
music_time = 0xdeadbeef;
|
||
|
time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20);
|
||
|
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(music_time == 400, "got %ld\n", music_time);
|
||
|
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 2000, (DMUS_PMSG **)&tempo);
|
||
|
ok(!ret, "got %#lx\n", ret);
|
||
|
todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType);
|
||
|
if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests;
|
||
|
check_dmus_tempo_pmsg(tempo, 100, 80);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo);
|
||
|
todo_wine ok(!ret, "got %#lx\n", ret);
|
||
|
check_dmus_tempo_pmsg(tempo, 300, 60);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
ret = test_tool_wait_message(tool, 500, &msg);
|
||
|
todo_wine ok(!ret, "got %#lx\n", ret);
|
||
|
ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType);
|
||
|
hr = IDirectMusicPerformance_FreePMsg(performance, msg);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
skip_tests:
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
static void test_connect_to_collection(void)
|
||
|
{
|
||
|
IDirectMusicCollection *collection;
|
||
|
IDirectMusicSegment *segment;
|
||
|
IDirectMusicTrack *track;
|
||
|
void *param;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicCollection, (void **)&collection);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicTrack, (void **)&track);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
/* it is possible to connect the band track to another collection, but not to disconnect it */
|
||
|
hr = IDirectMusicTrack_IsParamSupported(track, &GUID_ConnectToDLSCollection);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, NULL);
|
||
|
todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, collection);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, NULL);
|
||
|
todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, ¶m);
|
||
|
ok(hr == DMUS_E_GET_UNSUPPORTED, "got %#lx\n", hr);
|
||
|
|
||
|
hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, NULL);
|
||
|
todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, collection);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
IDirectMusicCollection_Release(collection);
|
||
|
}
|
||
|
|
||
|
static void test_segment_state(void)
|
||
|
{
|
||
|
static const DWORD message_types[] =
|
||
|
{
|
||
|
DMUS_PMSGT_DIRTY,
|
||
|
DMUS_PMSGT_NOTIFICATION,
|
||
|
DMUS_PMSGT_WAVE,
|
||
|
};
|
||
|
IDirectMusicSegmentState *state, *tmp_state;
|
||
|
IDirectMusicSegment *segment, *tmp_segment;
|
||
|
IDirectMusicPerformance *performance;
|
||
|
IDirectMusicTrack *track;
|
||
|
IDirectMusicGraph *graph;
|
||
|
IDirectMusicTool *tool;
|
||
|
DWORD value, ret;
|
||
|
MUSIC_TIME time;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = test_track_create(&track, TRUE);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicPerformance, (void **)&performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicGraph, (void **)&graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_SetGraph(performance, graph);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicGraph_InsertTool(graph, tool, NULL, 0, -1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
IDirectMusicGraph_Release(graph);
|
||
|
|
||
|
|
||
|
hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER,
|
||
|
&IID_IDirectMusicSegment, (void **)&segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
check_track_state(track, inserted, FALSE);
|
||
|
hr = IDirectMusicSegment_InsertTrack(segment, track, 1);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_track_state(track, inserted, TRUE);
|
||
|
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_track_state(track, downloaded, TRUE);
|
||
|
hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
|
||
|
|
||
|
/* by default the segment length is 1 */
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegment_GetLength(segment, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
todo_wine ok(time == 1, "got %lu\n", time);
|
||
|
hr = IDirectMusicSegment_SetStartPoint(segment, 50);
|
||
|
ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetRepeats(segment, 10);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetLoopPoints(segment, 10, 70);
|
||
|
ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr);
|
||
|
|
||
|
/* Setting a larger length will cause PlayEx to be called multiple times,
|
||
|
* as native splits the segment into chunks and play each chunk separately */
|
||
|
hr = IDirectMusicSegment_SetLength(segment, 100);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetStartPoint(segment, 50);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetRepeats(segment, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetLoopPoints(segment, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
/* InitPlay returns a dummy segment state */
|
||
|
|
||
|
state = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicSegment_InitPlay(segment, &state, performance, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(state != NULL, "got %p\n", state);
|
||
|
ok(state != (void *)0xdeadbeef, "got %p\n", state);
|
||
|
check_track_state(track, initialized, FALSE);
|
||
|
|
||
|
tmp_segment = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
ok(tmp_segment == NULL, "got %p\n", tmp_segment);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 0, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetRepeats(state, &value);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 0xdeadbeef, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartTime(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == -1, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetSeek(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 0, "got %#lx\n", time);
|
||
|
|
||
|
|
||
|
/* PlaySegment returns a different, genuine segment state */
|
||
|
|
||
|
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
check_track_state(track, initialized, FALSE);
|
||
|
check_track_state(track, playing, FALSE);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0);
|
||
|
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
|
||
|
ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
tmp_state = state;
|
||
|
state = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(state != NULL, "got %p\n", state);
|
||
|
ok(state != (void *)0xdeadbeef, "got %p\n", state);
|
||
|
ok(state != tmp_state, "got %p\n", state);
|
||
|
IDirectMusicSegmentState_Release(tmp_state);
|
||
|
|
||
|
tmp_state = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
|
||
|
ok(hr == S_OK || broken(hr == DMUS_E_NOT_FOUND) /* sometimes on Windows */, "got %#lx\n", hr);
|
||
|
if (hr == S_OK)
|
||
|
{
|
||
|
ok(state == tmp_state, "got %p\n", tmp_state);
|
||
|
IDirectMusicSegmentState_Release(tmp_state);
|
||
|
}
|
||
|
|
||
|
tmp_state = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(state == tmp_state, "got %p\n", tmp_state);
|
||
|
IDirectMusicSegmentState_Release(tmp_state);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 71);
|
||
|
todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
check_track_state(track, initialized, TRUE);
|
||
|
|
||
|
|
||
|
/* The track can be removed from the segment */
|
||
|
hr = IDirectMusicSegment_RemoveTrack(segment, track);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
ret = test_track_wait_playing(track, 50);
|
||
|
ok(ret == 0, "got %#lx\n", ret);
|
||
|
|
||
|
hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0);
|
||
|
todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr);
|
||
|
|
||
|
|
||
|
tmp_segment = (void *)0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(tmp_segment == segment, "got %p\n", tmp_segment);
|
||
|
IDirectMusicSegment_Release(tmp_segment);
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 50, "got %lu\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetRepeats(state, &value);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 0xdeadbeef, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartTime(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 20, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
|
||
|
/* The seek value is also dependent on whether the tracks are playing.
|
||
|
* It is initially 0, then start_point right before playing, then length.
|
||
|
*/
|
||
|
hr = IDirectMusicSegmentState_GetSeek(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
todo_wine ok(time == 100, "got %#lx\n", time);
|
||
|
|
||
|
/* changing the segment values doesn't change the segment state */
|
||
|
|
||
|
hr = IDirectMusicSegment_SetStartPoint(segment, 0);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetRepeats(segment, 10);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
hr = IDirectMusicSegment_SetLoopPoints(segment, 50, 70);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartPoint(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 50, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetRepeats(state, &value);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 0xdeadbeef, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetStartTime(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
ok(time == 20, "got %#lx\n", time);
|
||
|
time = 0xdeadbeef;
|
||
|
hr = IDirectMusicSegmentState_GetSeek(state, &time);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
todo_wine ok(time == 100, "got %#lx\n", time);
|
||
|
|
||
|
IDirectMusicSegment_Release(segment);
|
||
|
|
||
|
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
check_track_state(track, initialized, TRUE);
|
||
|
check_track_state(track, playing, TRUE);
|
||
|
|
||
|
hr = IDirectMusicPerformance_CloseDown(performance);
|
||
|
ok(hr == S_OK, "got %#lx\n", hr);
|
||
|
|
||
|
check_track_state(track, downloaded, FALSE);
|
||
|
check_track_state(track, initialized, TRUE);
|
||
|
check_track_state(track, playing, FALSE);
|
||
|
|
||
|
|
||
|
IDirectMusicPerformance_Release(performance);
|
||
|
IDirectMusicTrack_Release(track);
|
||
|
IDirectMusicTool_Release(tool);
|
||
|
}
|
||
|
|
||
|
START_TEST(dmime)
|
||
|
{
|
||
|
CoInitialize(NULL);
|
||
|
|
||
|
if (missing_dmime())
|
||
|
{
|
||
|
skip("dmime not available\n");
|
||
|
CoUninitialize();
|
||
|
return;
|
||
|
}
|
||
|
test_COM_audiopath();
|
||
|
test_COM_audiopathconfig();
|
||
|
test_COM_graph();
|
||
|
test_COM_segment();
|
||
|
test_COM_segmentstate();
|
||
|
test_COM_track();
|
||
|
test_COM_performance();
|
||
|
test_audiopathconfig();
|
||
|
test_graph();
|
||
|
test_segment();
|
||
|
test_gettrack();
|
||
|
test_segment_param();
|
||
|
test_track();
|
||
|
test_parsedescriptor();
|
||
|
test_performance_InitAudio();
|
||
|
test_performance_createport();
|
||
|
test_performance_pchannel();
|
||
|
test_performance_tool();
|
||
|
test_performance_graph();
|
||
|
test_performance_time();
|
||
|
test_performance_pmsg();
|
||
|
test_notification_pmsg();
|
||
|
test_wave_pmsg();
|
||
|
test_sequence_track();
|
||
|
test_band_track_play();
|
||
|
test_tempo_track_play();
|
||
|
test_connect_to_collection();
|
||
|
test_segment_state();
|
||
|
|
||
|
CoUninitialize();
|
||
|
}
|