synth.c 20.7 KB
Newer Older
1 2
/*
 * IDirectMusicSynth8 Implementation
3
 *
4
 * Copyright (C) 2003-2004 Rok Mandeljc
5
 * Copyright (C) 2012 Christian Costa
6
 *
7 8 9 10
 * This program 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.
11 12 13
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
16
 *
17 18 19
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22 23
#define COBJMACROS

24 25
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
26 27 28 29
#include "objbase.h"
#include "initguid.h"
#include "dmksctrl.h"

30
#include "dmsynth_private.h"
31

32
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
33

34 35 36 37 38
static inline IDirectMusicSynth8Impl *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IDirectMusicSynth8_iface);
}

39
/* IDirectMusicSynth8Impl IUnknown part: */
40
static HRESULT WINAPI IDirectMusicSynth8Impl_QueryInterface(LPDIRECTMUSICSYNTH8 iface, REFIID riid, LPVOID *ret_iface)
41
{
42
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);
43

44
    TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
45

46 47 48 49 50 51 52 53 54 55 56 57 58
    if (IsEqualIID (riid, &IID_IUnknown) ||
        IsEqualIID (riid, &IID_IDirectMusicSynth) ||
        IsEqualIID (riid, &IID_IDirectMusicSynth8))
    {
        IUnknown_AddRef(iface);
        *ret_iface = iface;
        return S_OK;
    }
    else if (IsEqualIID(riid, &IID_IKsControl))
    {
        IUnknown_AddRef(iface);
        *ret_iface = &This->IKsControl_iface;
        return S_OK;
59 60
    }

61 62 63 64 65
    *ret_iface = NULL;

    WARN("(%p)->(%s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);

    return E_NOINTERFACE;
66 67
}

68 69
static ULONG WINAPI IDirectMusicSynth8Impl_AddRef(LPDIRECTMUSICSYNTH8 iface)
{
70 71
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);
    ULONG ref = InterlockedIncrement(&This->ref);
72

73
    TRACE("(%p)->(): new ref = %u\n", This, ref);
74

75
    return ref;
76 77
}

78 79
static ULONG WINAPI IDirectMusicSynth8Impl_Release(LPDIRECTMUSICSYNTH8 iface)
{
80 81
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);
    ULONG ref = InterlockedDecrement(&This->ref);
82

83
    TRACE("(%p)->(): new ref = %u\n", This, ref);
84

85 86 87 88
    if (!ref) {
        if (This->pLatencyClock)
            IReferenceClock_Release(This->pLatencyClock);
        HeapFree(GetProcessHeap(), 0, This);
89
        DMSYNTH_UnlockModule();
90 91 92
    }

    return ref;
93 94
}

95
/* IDirectMusicSynth8Impl IDirectMusicSynth part: */
96 97 98 99 100 101 102
static HRESULT WINAPI IDirectMusicSynth8Impl_Open(LPDIRECTMUSICSYNTH8 iface, LPDMUS_PORTPARAMS pPortParams)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p): stub\n", This, pPortParams);

    return S_OK;
103 104
}

105 106 107 108 109 110 111
static HRESULT WINAPI IDirectMusicSynth8Impl_Close(LPDIRECTMUSICSYNTH8 iface)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(): stub\n", This);

    return S_OK;
112 113
}

114 115 116 117
static HRESULT WINAPI IDirectMusicSynth8Impl_SetNumChannelGroups(LPDIRECTMUSICSYNTH8 iface, DWORD groups)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

Andrey Gusev's avatar
Andrey Gusev committed
118
    FIXME("(%p)->(%d): stub\n", This, groups);
119 120

    return S_OK;
121 122
}

123 124 125
static HRESULT WINAPI IDirectMusicSynth8Impl_Download(LPDIRECTMUSICSYNTH8 iface, LPHANDLE hDownload, LPVOID data, LPBOOL free)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);
126
    LPBYTE buffer = data;
127 128 129
    DMUS_DOWNLOADINFO *info = (DMUS_DOWNLOADINFO*)buffer;
    ULONG *offsets = ((DMUS_OFFSETTABLE*)(buffer + sizeof(DMUS_DOWNLOADINFO)))->ulOffsetTable;
    LPBYTE object = buffer + sizeof(DMUS_DOWNLOADINFO) + info->dwNumOffsetTableEntries * sizeof(ULONG);
130 131 132

    FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, data, free);

133 134
    /* FIXME: Currently we only dump data which is very useful to known how native dmusic behave and debug builtin dmusic */

135
    if (!hDownload || !free)
136 137 138 139 140 141 142 143 144 145 146
        return E_POINTER;

    if (TRACE_ON(dmsynth))
    {
        TRACE("Dump DMUS_DOWNLOADINFO struct:\n");
        TRACE(" - dwDLType                = %u\n", info->dwDLType);
        TRACE(" - dwDLId                  = %u\n", info->dwDLId);
        TRACE(" - dwNumOffsetTableEntries = %u\n", info->dwNumOffsetTableEntries);
        TRACE(" - cbSize                  = %u\n", info->cbSize);
    }

147
    /* The struct should have at least one offset corresponding to the download object itself */
148 149 150 151 152 153 154 155 156 157 158 159 160
    if (!info->dwNumOffsetTableEntries)
    {
        FIXME("Offset table is empty\n");
        return DMUS_E_BADOFFSETTABLE;
    }

    /* First offset should point to the download object */
    if ((buffer + offsets[0]) != object)
    {
        FIXME("Object is not at the beginning\n");
        return DMUS_E_BADOFFSETTABLE;
    }

161 162 163 164 165 166
    if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT)
    {
        FIXME("Download type DMUS_DOWNLOADINFO_INSTRUMENT not yet supported\n");
    }
    else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVE)
    {
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
        DMUS_WAVE *wave = (DMUS_WAVE*)object;
        DMUS_WAVEDATA *wave_data;

        TRACE("Processing download type DMUS_DOWNLOADINFO_WAVE\n");

        if (TRACE_ON(dmsynth))
        {
            TRACE("Dump DMUS_WAVE struct\n");
            TRACE(" - ulFirstExtCkIdx   = %u\n", wave->ulFirstExtCkIdx);
            TRACE(" - ulCopyrightIdx    = %u\n", wave->ulCopyrightIdx);
            TRACE(" - ulWaveDataIdx     = %u\n", wave->ulWaveDataIdx);
            TRACE(" - WaveformatEx:\n");
            TRACE("   - wFormatTag      = %u\n", wave->WaveformatEx.wFormatTag);
            TRACE("   - nChannels       = %u\n", wave->WaveformatEx.nChannels);
            TRACE("   - nSamplesPerSec  = %u\n", wave->WaveformatEx.nSamplesPerSec);
            TRACE("   - nAvgBytesPerSec = %u\n", wave->WaveformatEx.nAvgBytesPerSec);
            TRACE("   - nBlockAlign     = %u\n", wave->WaveformatEx.nBlockAlign);
            TRACE("   - wBitsPerSample  = %u\n", wave->WaveformatEx.wBitsPerSample);
            TRACE("   - cbSize          = %u\n", wave->WaveformatEx.cbSize);

            if (wave->ulCopyrightIdx)
            {
                DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT*)(buffer + offsets[wave->ulCopyrightIdx]);
                TRACE("Copyright = '%s'\n",  (char*)copyright->byCopyright);
            }

            wave_data = (DMUS_WAVEDATA*)(buffer + offsets[wave->ulWaveDataIdx]);
            TRACE("Found %u bytes of wave data\n", wave_data->cbSize);
        }
196 197 198
    }
    else if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2)
    {
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
        DMUS_INSTRUMENT *instrument = (DMUS_INSTRUMENT*)object;
        ULONG nb_regions = 0;

        TRACE("Processing download type DMUS_DOWNLOADINFO_INSTRUMENT2\n");

        if (TRACE_ON(dmsynth))
        {
            TRACE("Dump DMUS_INSTRUMENT struct\n");
            TRACE(" - ulPatch          = %u\n", instrument->ulPatch);
            TRACE(" - ulFirstRegionIdx = %u\n", instrument->ulFirstRegionIdx);
            TRACE(" - ulGlobalArtIdx   = %u\n", instrument->ulGlobalArtIdx);
            TRACE(" - ulFirstExtCkIdx  = %u\n", instrument->ulFirstExtCkIdx);
            TRACE(" - ulCopyrightIdx   = %u\n", instrument->ulCopyrightIdx);
            TRACE(" - ulFlags          = %u\n", instrument->ulFlags);

            if (instrument->ulCopyrightIdx)
            {
                DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT*)(buffer + offsets[instrument->ulCopyrightIdx]);
                TRACE("Copyright = '%s'\n",  (char*)copyright->byCopyright);
            }
        }

        if (instrument->ulFirstRegionIdx)
        {
            ULONG region_idx = instrument->ulFirstRegionIdx;

            while (region_idx)
            {
                DMUS_REGION *region = (DMUS_REGION*)(buffer + offsets[region_idx]);

                region_idx = region->ulNextRegionIdx;
                nb_regions++;
            }
        }

        TRACE("Number of regions = %u\n", nb_regions);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    }
    else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVEARTICULATION)
    {
        FIXME("Download type DMUS_DOWNLOADINFO_WAVEARTICULATION not yet supported\n");
    }
    else if (info->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE)
    {
        FIXME("Download type DMUS_DOWNLOADINFO_STREAMINGWAVE not yet supported\n");
    }
    else if (info->dwDLType == DMUS_DOWNLOADINFO_ONESHOTWAVE)
    {
        FIXME("Download type DMUS_DOWNLOADINFO_ONESHOTWAVE not yet supported\n");
    }
    else
    {
        WARN("Unknown download type %u\n", info->dwDLType);
        return DMUS_E_UNKNOWNDOWNLOAD;
    }

254
    return S_OK;
255 256
}

257 258 259 260 261 262 263
static HRESULT WINAPI IDirectMusicSynth8Impl_Unload(LPDIRECTMUSICSYNTH8 iface, HANDLE hDownload, HRESULT (CALLBACK* lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, lpFreeHandle, hUserData);

    return S_OK;
264 265
}

266 267 268 269 270 271 272
static HRESULT WINAPI IDirectMusicSynth8Impl_PlayBuffer(LPDIRECTMUSICSYNTH8 iface, REFERENCE_TIME rt, LPBYTE buffer, DWORD size)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(0x%s, %p, %u): stub\n", This, wine_dbgstr_longlong(rt), buffer, size);

    return S_OK;
273 274
}

275 276 277 278 279 280 281
static HRESULT WINAPI IDirectMusicSynth8Impl_GetRunningStats(LPDIRECTMUSICSYNTH8 iface, LPDMUS_SYNTHSTATS stats)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p): stub\n", This, stats);

    return S_OK;
282 283
}

284 285 286 287 288 289 290 291 292
static HRESULT WINAPI IDirectMusicSynth8Impl_GetPortCaps(LPDIRECTMUSICSYNTH8 iface, LPDMUS_PORTCAPS caps)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    TRACE("(%p)->(%p)\n", This, caps);

    *caps = This->pCaps;

    return S_OK;
293 294
}

295 296 297 298 299 300 301
static HRESULT WINAPI IDirectMusicSynth8Impl_SetMasterClock(LPDIRECTMUSICSYNTH8 iface, IReferenceClock* clock)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p): stub\n", This, clock);

    return S_OK;
302 303
}

304 305 306 307
static HRESULT WINAPI IDirectMusicSynth8Impl_GetLatencyClock(LPDIRECTMUSICSYNTH8 iface, IReferenceClock** clock)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

308 309 310 311 312
    TRACE("(%p)->(%p)\n", iface, clock);

    if (!clock)
        return E_POINTER;

313
    if (!This->synth_sink)
314
        return DMUS_E_NOSYNTHSINK;
315 316

    *clock = This->pLatencyClock;
317
    IReferenceClock_AddRef(This->pLatencyClock);
318 319

    return S_OK;
320 321
}

322 323 324 325 326 327 328 329 330
static HRESULT WINAPI IDirectMusicSynth8Impl_Activate(LPDIRECTMUSICSYNTH8 iface, BOOL enable)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    TRACE("(%p)->(%d)\n", This, enable);

    This->fActive = enable;

    return S_OK;
331 332
}

333 334 335 336
static HRESULT WINAPI IDirectMusicSynth8Impl_SetSynthSink(LPDIRECTMUSICSYNTH8 iface, IDirectMusicSynthSink* synth_sink)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

337
    TRACE("(%p)->(%p)\n", iface, synth_sink);
338

339
    This->synth_sink = synth_sink;
340

341 342 343
    if (synth_sink)
        return IDirectMusicSynthSink_GetLatencyClock(synth_sink, &This->pLatencyClock);

344
    return S_OK;
345 346
}

347 348 349 350 351 352 353
static HRESULT WINAPI IDirectMusicSynth8Impl_Render(LPDIRECTMUSICSYNTH8 iface, short* buffer, DWORD length, LONGLONG position)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p, %d, 0x%s): stub\n", This, buffer, length, wine_dbgstr_longlong(position));

    return S_OK;
354 355
}

356 357 358 359 360 361 362 363
static HRESULT WINAPI IDirectMusicSynth8Impl_SetChannelPriority(LPDIRECTMUSICSYNTH8 iface, DWORD channel_group, DWORD channel, DWORD priority)
{
    /* IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); */

    /* Silenced because of too many messages - 1000 groups * 16 channels ;=) */
    /* FIXME("(%p)->(%ld, %ld, %ld): stub\n", This, channel_group, channel, priority); */

    return S_OK;
364 365
}

366 367 368 369 370 371 372
static HRESULT WINAPI IDirectMusicSynth8Impl_GetChannelPriority(LPDIRECTMUSICSYNTH8 iface, DWORD channel_group, DWORD channel, LPDWORD priority)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%d, %d, %p): stub\n", This, channel_group, channel, priority);

    return S_OK;
373 374
}

375 376 377 378 379 380 381
static HRESULT WINAPI IDirectMusicSynth8Impl_GetFormat(LPDIRECTMUSICSYNTH8 iface, LPWAVEFORMATEX wave_format, LPDWORD wave_format_size)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p, %p): stub\n", This, wave_format, wave_format_size);

    return S_OK;
382 383
}

384 385
static HRESULT WINAPI IDirectMusicSynth8Impl_GetAppend(LPDIRECTMUSICSYNTH8 iface, DWORD* append)
{
386
    TRACE("(%p)->(%p)\n", iface, append);
387

388 389
    /* We don't need extra space at the end of buffers passed to us for now */
    *append = 0;
390 391

    return S_OK;
392 393
}

394
/* IDirectMusicSynth8Impl IDirectMusicSynth8 part: */
395 396 397 398 399 400 401 402 403 404
static HRESULT WINAPI IDirectMusicSynth8Impl_PlayVoice(LPDIRECTMUSICSYNTH8 iface, REFERENCE_TIME ref_time, DWORD voice_id, DWORD channel_group, DWORD channel,
                                                       DWORD dwDLId, LONG prPitch, LONG vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(0x%s, %d, %d, %d, %d, %i, %i,0x%s, 0x%s, 0x%s): stub\n",
          This, wine_dbgstr_longlong(ref_time), voice_id, channel_group, channel, dwDLId, prPitch, vrVolume,
          wine_dbgstr_longlong(stVoiceStart), wine_dbgstr_longlong(stLoopStart), wine_dbgstr_longlong(stLoopEnd));

    return S_OK;
405 406
}

407 408 409 410 411 412 413
static HRESULT WINAPI IDirectMusicSynth8Impl_StopVoice(LPDIRECTMUSICSYNTH8 iface, REFERENCE_TIME ref_time, DWORD voice_id)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(0x%s, %d): stub\n", This, wine_dbgstr_longlong(ref_time), voice_id);

    return S_OK;
414 415
}

416 417 418 419 420 421 422
static HRESULT WINAPI IDirectMusicSynth8Impl_GetVoiceState(LPDIRECTMUSICSYNTH8 iface, DWORD dwVoice[], DWORD cbVoice, DMUS_VOICE_STATE dwVoiceState[])
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%p, %d, %p): stub\n", This, dwVoice, cbVoice, dwVoiceState);

    return S_OK;
423 424
}

425 426 427 428 429 430 431
static HRESULT WINAPI IDirectMusicSynth8Impl_Refresh(LPDIRECTMUSICSYNTH8 iface, DWORD download_id, DWORD flags)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%d, %d): stub\n", This, download_id, flags);

    return S_OK;
432 433
}

434 435 436 437 438 439 440
static HRESULT WINAPI IDirectMusicSynth8Impl_AssignChannelToBuses(LPDIRECTMUSICSYNTH8 iface, DWORD channel_group, DWORD channel, LPDWORD pdwBuses, DWORD cBuses)
{
    IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface);

    FIXME("(%p)->(%d, %d, %p, %d): stub\n", This, channel_group, channel, pdwBuses, cBuses);

    return S_OK;
441 442
}

443
static const IDirectMusicSynth8Vtbl DirectMusicSynth8_Vtbl = {
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
	IDirectMusicSynth8Impl_QueryInterface,
	IDirectMusicSynth8Impl_AddRef,
	IDirectMusicSynth8Impl_Release,
	IDirectMusicSynth8Impl_Open,
	IDirectMusicSynth8Impl_Close,
	IDirectMusicSynth8Impl_SetNumChannelGroups,
	IDirectMusicSynth8Impl_Download,
	IDirectMusicSynth8Impl_Unload,
	IDirectMusicSynth8Impl_PlayBuffer,
	IDirectMusicSynth8Impl_GetRunningStats,
	IDirectMusicSynth8Impl_GetPortCaps,
	IDirectMusicSynth8Impl_SetMasterClock,
	IDirectMusicSynth8Impl_GetLatencyClock,
	IDirectMusicSynth8Impl_Activate,
	IDirectMusicSynth8Impl_SetSynthSink,
	IDirectMusicSynth8Impl_Render,
	IDirectMusicSynth8Impl_SetChannelPriority,
	IDirectMusicSynth8Impl_GetChannelPriority,
	IDirectMusicSynth8Impl_GetFormat,
	IDirectMusicSynth8Impl_GetAppend,
	IDirectMusicSynth8Impl_PlayVoice,
	IDirectMusicSynth8Impl_StopVoice,
	IDirectMusicSynth8Impl_GetVoiceState,
	IDirectMusicSynth8Impl_Refresh,
	IDirectMusicSynth8Impl_AssignChannelToBuses
};

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
static inline IDirectMusicSynth8Impl *impl_from_IKsControl(IKsControl *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IKsControl_iface);
}

static HRESULT WINAPI DMSynthImpl_IKsControl_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj)
{
    IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynth8Impl_QueryInterface(&This->IDirectMusicSynth8_iface, riid, ppobj);
}

static ULONG WINAPI DMSynthImpl_IKsControl_AddRef(IKsControl* iface)
{
    IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynth8Impl_AddRef(&This->IDirectMusicSynth8_iface);
}

static ULONG WINAPI DMSynthImpl_IKsControl_Release(IKsControl* iface)
{
    IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynth8Impl_Release(&This->IDirectMusicSynth8_iface);
}

static HRESULT WINAPI DMSynthImpl_IKsControl_KsProperty(IKsControl* iface, PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData,
                                                        ULONG DataLength, ULONG* BytesReturned)
{
500
    TRACE("(%p)->(%p, %u, %p, %u, %p)\n", iface, Property, PropertyLength, PropertyData, DataLength, BytesReturned);
501

502
    TRACE("Property = %s - %u - %u\n", debugstr_guid(&Property->u.s.Set), Property->u.s.Id, Property->u.s.Flags);
503

504
    if (Property->u.s.Flags != KSPROPERTY_TYPE_GET)
505
    {
506
        FIXME("Property flags %u not yet supported\n", Property->u.s.Flags);
507 508 509 510
        return S_FALSE;
    }

    if (DataLength <  sizeof(DWORD))
511
        return E_NOT_SUFFICIENT_BUFFER;
512

513
    if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_INSTRUMENT2))
514 515 516 517
    {
        *(DWORD*)PropertyData = TRUE;
        *BytesReturned = sizeof(DWORD);
    }
518
    else if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_DLS2))
519 520 521 522
    {
        *(DWORD*)PropertyData = TRUE;
        *BytesReturned = sizeof(DWORD);
    }
523
    else if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_GM_Hardware))
524 525 526 527
    {
        *(DWORD*)PropertyData = FALSE;
        *BytesReturned = sizeof(DWORD);
    }
528
    else if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_GS_Hardware))
529 530 531 532
    {
        *(DWORD*)PropertyData = FALSE;
        *BytesReturned = sizeof(DWORD);
    }
533
    else if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_XG_Hardware))
534 535 536 537 538 539
    {
        *(DWORD*)PropertyData = FALSE;
        *BytesReturned = sizeof(DWORD);
    }
    else
    {
540
        FIXME("Unknown property %s\n", debugstr_guid(&Property->u.s.Set));
541 542 543 544 545
        *(DWORD*)PropertyData = FALSE;
        *BytesReturned = sizeof(DWORD);
    }

    return S_OK;
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
}

static HRESULT WINAPI DMSynthImpl_IKsControl_KsMethod(IKsControl* iface, PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData,
                                                      ULONG DataLength, ULONG* BytesReturned)
{
    FIXME("(%p)->(%p, %u, %p, %u, %p): stub\n", iface, Method, MethodLength, MethodData, DataLength, BytesReturned);

    return E_NOTIMPL;
}

static HRESULT WINAPI DMSynthImpl_IKsControl_KsEvent(IKsControl* iface, PKSEVENT Event, ULONG EventLength, LPVOID EventData,
                                                     ULONG DataLength, ULONG* BytesReturned)
{
    FIXME("(%p)->(%p, %u, %p, %u, %p): stub\n", iface, Event, EventLength, EventData, DataLength, BytesReturned);

    return E_NOTIMPL;
}


static const IKsControlVtbl DMSynthImpl_IKsControl_Vtbl = {
    DMSynthImpl_IKsControl_QueryInterface,
    DMSynthImpl_IKsControl_AddRef,
    DMSynthImpl_IKsControl_Release,
    DMSynthImpl_IKsControl_KsProperty,
    DMSynthImpl_IKsControl_KsMethod,
    DMSynthImpl_IKsControl_KsEvent
};

574
/* for ClassFactory */
575
HRESULT WINAPI DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj)
576 577 578 579 580 581
{
    static const WCHAR descrW[] = {'M','i','c','r','o','s','o','f','t',' ',
        'S','y','n','t','h','e','s','i','z','e','r',0};
    IDirectMusicSynth8Impl *obj;
    HRESULT hr;

582
    TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604

    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
    if (NULL == obj) {
        *ppobj = NULL;
        return E_OUTOFMEMORY;
    }
    obj->IDirectMusicSynth8_iface.lpVtbl = &DirectMusicSynth8_Vtbl;
    obj->IKsControl_iface.lpVtbl = &DMSynthImpl_IKsControl_Vtbl;
    obj->ref = 1;
    /* fill in caps */
    obj->pCaps.dwSize = sizeof(DMUS_PORTCAPS);
    obj->pCaps.dwFlags = DMUS_PC_DLS | DMUS_PC_SOFTWARESYNTH | DMUS_PC_DIRECTSOUND | DMUS_PC_DLS2 | DMUS_PC_AUDIOPATH | DMUS_PC_WAVE;
    obj->pCaps.guidPort = CLSID_DirectMusicSynth;
    obj->pCaps.dwClass = DMUS_PC_OUTPUTCLASS;
    obj->pCaps.dwType = DMUS_PORT_USER_MODE_SYNTH;
    obj->pCaps.dwMemorySize = DMUS_PC_SYSTEMMEMORY;
    obj->pCaps.dwMaxChannelGroups = 1000;
    obj->pCaps.dwMaxVoices = 1000;
    obj->pCaps.dwMaxAudioChannels = 2;
    obj->pCaps.dwEffectFlags = DMUS_EFFECT_REVERB;
    strcpyW(obj->pCaps.wszDescription, descrW);

605
    DMSYNTH_LockModule();
606 607
    hr = IDirectMusicSynth8_QueryInterface(&obj->IDirectMusicSynth8_iface, riid, ppobj);
    IDirectMusicSynth8_Release(&obj->IDirectMusicSynth8_iface);
608

609
    return hr;
610
}