xref: /reactos/dll/directx/wine/dmusic/port.c (revision 0623a6f8)
1 /*
2  * IDirectMusicPort Implementation
3  *
4  * Copyright (C) 2003-2004 Rok Mandeljc
5  * Copyright (C) 2012 Christian Costa
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <assert.h>
23 #include "dmusic_private.h"
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
26 
27 typedef struct SynthPortImpl {
28     IDirectMusicPort IDirectMusicPort_iface;
29     IDirectMusicPortDownload IDirectMusicPortDownload_iface;
30     IDirectMusicThru IDirectMusicThru_iface;
31     IKsControl IKsControl_iface;
32     LONG ref;
33     IDirectMusic8Impl *parent;
34     IDirectSound *dsound;
35     IDirectSoundBuffer *dsbuffer;
36     IReferenceClock *pLatencyClock;
37     IDirectMusicSynth *synth;
38     IDirectMusicSynthSink *synth_sink;
39     BOOL active;
40     DMUS_PORTCAPS caps;
41     DMUS_PORTPARAMS params;
42     int nrofgroups;
43     DMUSIC_PRIVATE_CHANNEL_GROUP group[1];
44 } SynthPortImpl;
45 
46 static inline IDirectMusicDownloadedInstrumentImpl* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface)
47 {
48     return CONTAINING_RECORD(iface, IDirectMusicDownloadedInstrumentImpl, IDirectMusicDownloadedInstrument_iface);
49 }
50 
51 static inline SynthPortImpl *impl_from_SynthPortImpl_IDirectMusicPort(IDirectMusicPort *iface)
52 {
53     return CONTAINING_RECORD(iface, SynthPortImpl, IDirectMusicPort_iface);
54 }
55 
56 static inline SynthPortImpl *impl_from_SynthPortImpl_IDirectMusicPortDownload(IDirectMusicPortDownload *iface)
57 {
58     return CONTAINING_RECORD(iface, SynthPortImpl, IDirectMusicPortDownload_iface);
59 }
60 
61 static inline SynthPortImpl *impl_from_SynthPortImpl_IDirectMusicThru(IDirectMusicThru *iface)
62 {
63     return CONTAINING_RECORD(iface, SynthPortImpl, IDirectMusicThru_iface);
64 }
65 
66 static inline SynthPortImpl *impl_from_IKsControl(IKsControl *iface)
67 {
68     return CONTAINING_RECORD(iface, SynthPortImpl, IKsControl_iface);
69 }
70 
71 /* IDirectMusicDownloadedInstrument IUnknown part follows: */
72 static HRESULT WINAPI IDirectMusicDownloadedInstrumentImpl_QueryInterface(IDirectMusicDownloadedInstrument *iface, REFIID riid, VOID **ret_iface)
73 {
74     TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
75 
76     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicDownloadedInstrument))
77     {
78         IDirectMusicDownloadedInstrument_AddRef(iface);
79         *ret_iface = iface;
80         return S_OK;
81     }
82 
83     WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);
84 
85     return E_NOINTERFACE;
86 }
87 
88 static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_AddRef(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface)
89 {
90     IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface);
91     ULONG ref = InterlockedIncrement(&This->ref);
92 
93     TRACE("(%p)->(): new ref = %u\n", iface, ref);
94 
95     return ref;
96 }
97 
98 static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_Release(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface)
99 {
100     IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface);
101     ULONG ref = InterlockedDecrement(&This->ref);
102 
103     TRACE("(%p)->(): new ref = %u\n", iface, ref);
104 
105     if (!ref)
106     {
107         HeapFree(GetProcessHeap(), 0, This->data);
108         HeapFree(GetProcessHeap(), 0, This);
109         DMUSIC_UnlockModule();
110     }
111 
112     return ref;
113 }
114 
115 static const IDirectMusicDownloadedInstrumentVtbl DirectMusicDownloadedInstrument_Vtbl = {
116     IDirectMusicDownloadedInstrumentImpl_QueryInterface,
117     IDirectMusicDownloadedInstrumentImpl_AddRef,
118     IDirectMusicDownloadedInstrumentImpl_Release
119 };
120 
121 static inline IDirectMusicDownloadedInstrumentImpl* unsafe_impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface)
122 {
123     if (!iface)
124         return NULL;
125     assert(iface->lpVtbl == &DirectMusicDownloadedInstrument_Vtbl);
126 
127     return impl_from_IDirectMusicDownloadedInstrument(iface);
128 }
129 
130 static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDownloadedInstrument **instrument)
131 {
132     IDirectMusicDownloadedInstrumentImpl *object;
133 
134     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
135     if (!object)
136     {
137         *instrument = NULL;
138         return E_OUTOFMEMORY;
139     }
140 
141     object->IDirectMusicDownloadedInstrument_iface.lpVtbl = &DirectMusicDownloadedInstrument_Vtbl;
142     object->ref = 1;
143 
144     *instrument = &object->IDirectMusicDownloadedInstrument_iface;
145     DMUSIC_LockModule();
146 
147     return S_OK;
148 }
149 
150 /* SynthPortImpl IDirectMusicPort IUnknown part follows: */
151 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_QueryInterface(LPDIRECTMUSICPORT iface, REFIID riid, LPVOID *ret_iface)
152 {
153     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
154 
155     TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
156 
157     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDirectMusicPort))
158         *ret_iface = &This->IDirectMusicPort_iface;
159     else if (IsEqualGUID(riid, &IID_IDirectMusicPortDownload))
160         *ret_iface = &This->IDirectMusicPortDownload_iface;
161     else if (IsEqualGUID(riid, &IID_IDirectMusicThru))
162         *ret_iface = &This->IDirectMusicThru_iface;
163     else if (IsEqualGUID(riid, &IID_IKsControl))
164         *ret_iface = &This->IKsControl_iface;
165     else {
166         WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
167         *ret_iface = NULL;
168         return E_NOINTERFACE;
169     }
170 
171     IUnknown_AddRef((IUnknown*)*ret_iface);
172 
173     return S_OK;
174 }
175 
176 static ULONG WINAPI SynthPortImpl_IDirectMusicPort_AddRef(LPDIRECTMUSICPORT iface)
177 {
178     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
179     ULONG ref = InterlockedIncrement(&This->ref);
180 
181     TRACE("(%p)->(): new ref = %u\n", This, ref);
182 
183     DMUSIC_LockModule();
184 
185     return ref;
186 }
187 
188 static ULONG WINAPI SynthPortImpl_IDirectMusicPort_Release(LPDIRECTMUSICPORT iface)
189 {
190     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
191     ULONG ref = InterlockedDecrement(&This->ref);
192 
193     TRACE("(%p)->(): new ref = %u\n", This, ref);
194 
195     if (!ref)
196     {
197         dmusic_remove_port(This->parent, iface);
198         IDirectMusicSynth_Activate(This->synth, FALSE);
199         IDirectMusicSynth_Close(This->synth);
200         IDirectMusicSynth_Release(This->synth);
201         IDirectMusicSynthSink_Release(This->synth_sink);
202         IReferenceClock_Release(This->pLatencyClock);
203         if (This->dsbuffer)
204            IDirectSoundBuffer_Release(This->dsbuffer);
205         if (This->dsound)
206            IDirectSound_Release(This->dsound);
207         HeapFree(GetProcessHeap(), 0, This);
208     }
209 
210     DMUSIC_UnlockModule();
211 
212     return ref;
213 }
214 
215 /* SynthPortImpl IDirectMusicPort interface follows: */
216 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_PlayBuffer(LPDIRECTMUSICPORT iface, LPDIRECTMUSICBUFFER buffer)
217 {
218     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
219     HRESULT hr;
220     REFERENCE_TIME time;
221     LPBYTE data;
222     DWORD size;
223 
224     TRACE("(%p/%p)->(%p)\n", iface, This, buffer);
225 
226     if (!buffer)
227         return E_POINTER;
228 
229     hr = IDirectMusicBuffer_GetStartTime(buffer, &time);
230 
231     if (SUCCEEDED(hr))
232         hr = IDirectMusicBuffer_GetRawBufferPtr(buffer, &data);
233 
234     if (SUCCEEDED(hr))
235         hr = IDirectMusicBuffer_GetUsedBytes(buffer, &size);
236 
237     if (SUCCEEDED(hr))
238         hr = IDirectMusicSynth_PlayBuffer(This->synth, time, data, size);
239 
240     return hr;
241 }
242 
243 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetReadNotificationHandle(LPDIRECTMUSICPORT iface, HANDLE event)
244 {
245     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
246 
247     FIXME("(%p/%p)->(%p): stub\n", iface, This, event);
248 
249     return S_OK;
250 }
251 
252 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Read(LPDIRECTMUSICPORT iface, LPDIRECTMUSICBUFFER buffer)
253 {
254     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
255 
256     FIXME("(%p/%p)->(%p): stub\n", iface, This, buffer);
257 
258     return S_OK;
259 }
260 
261 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DownloadInstrument(LPDIRECTMUSICPORT iface, IDirectMusicInstrument* instrument, IDirectMusicDownloadedInstrument** downloaded_instrument, DMUS_NOTERANGE* note_ranges, DWORD num_note_ranges)
262 {
263     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
264     IDirectMusicInstrumentImpl *instrument_object;
265     HRESULT ret;
266     BOOL free;
267     HANDLE download;
268     DMUS_DOWNLOADINFO *info;
269     DMUS_OFFSETTABLE *offset_table;
270     DMUS_INSTRUMENT *instrument_info;
271     BYTE *data;
272     ULONG offset;
273     ULONG nb_regions;
274     ULONG size;
275     ULONG i;
276 
277     TRACE("(%p/%p)->(%p, %p, %p, %d)\n", iface, This, instrument, downloaded_instrument, note_ranges, num_note_ranges);
278 
279     if (!instrument || !downloaded_instrument || (num_note_ranges && !note_ranges))
280         return E_POINTER;
281 
282     instrument_object = impl_from_IDirectMusicInstrument(instrument);
283 
284     nb_regions = instrument_object->header.cRegions;
285     size = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions) + sizeof(DMUS_INSTRUMENT) + sizeof(DMUS_REGION) * nb_regions;
286 
287     data = HeapAlloc(GetProcessHeap(), 0, size);
288     if (!data)
289         return E_OUTOFMEMORY;
290 
291     info = (DMUS_DOWNLOADINFO*)data;
292     offset_table = (DMUS_OFFSETTABLE*)(data + sizeof(DMUS_DOWNLOADINFO));
293     offset = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions);
294 
295     info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2;
296     info->dwDLId = 0;
297     info->dwNumOffsetTableEntries = 1 + instrument_object->header.cRegions;
298     info->cbSize = size;
299 
300     offset_table->ulOffsetTable[0] = offset;
301     instrument_info = (DMUS_INSTRUMENT*)(data + offset);
302     offset += sizeof(DMUS_INSTRUMENT);
303     instrument_info->ulPatch = MIDILOCALE2Patch(&instrument_object->header.Locale);
304     instrument_info->ulFirstRegionIdx = 1;
305     instrument_info->ulGlobalArtIdx = 0; /* FIXME */
306     instrument_info->ulFirstExtCkIdx = 0; /* FIXME */
307     instrument_info->ulCopyrightIdx = 0; /* FIXME */
308     instrument_info->ulFlags = 0; /* FIXME */
309 
310     for (i = 0;  i < nb_regions; i++)
311     {
312         DMUS_REGION *region = (DMUS_REGION*)(data + offset);
313 
314         offset_table->ulOffsetTable[1 + i] = offset;
315         offset += sizeof(DMUS_REGION);
316         region->RangeKey = instrument_object->regions[i].header.RangeKey;
317         region->RangeVelocity = instrument_object->regions[i].header.RangeVelocity;
318         region->fusOptions = instrument_object->regions[i].header.fusOptions;
319         region->usKeyGroup = instrument_object->regions[i].header.usKeyGroup;
320         region->ulRegionArtIdx = 0; /* FIXME */
321         region->ulNextRegionIdx = i != (nb_regions - 1) ? (i + 2) : 0;
322         region->ulFirstExtCkIdx = 0; /* FIXME */
323         region->WaveLink = instrument_object->regions[i].wave_link;
324         region->WSMP = instrument_object->regions[i].wave_sample;
325         region->WLOOP[0] = instrument_object->regions[i].wave_loop;
326     }
327 
328     ret = IDirectMusicSynth8_Download(This->synth, &download, (VOID*)data, &free);
329 
330     if (SUCCEEDED(ret))
331         ret = DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(downloaded_instrument);
332 
333     if (SUCCEEDED(ret))
334     {
335         IDirectMusicDownloadedInstrumentImpl *downloaded_object = impl_from_IDirectMusicDownloadedInstrument(*downloaded_instrument);
336 
337         downloaded_object->data = data;
338         downloaded_object->downloaded = TRUE;
339     }
340 
341     *downloaded_instrument = NULL;
342     HeapFree(GetProcessHeap(), 0, data);
343 
344     return E_FAIL;
345 }
346 
347 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_UnloadInstrument(LPDIRECTMUSICPORT iface, IDirectMusicDownloadedInstrument *downloaded_instrument)
348 {
349     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
350     IDirectMusicDownloadedInstrumentImpl *downloaded_object = unsafe_impl_from_IDirectMusicDownloadedInstrument(downloaded_instrument);
351 
352     TRACE("(%p/%p)->(%p)\n", iface, This, downloaded_instrument);
353 
354     if (!downloaded_instrument)
355         return E_POINTER;
356 
357     if (!downloaded_object->downloaded)
358         return DMUS_E_NOT_DOWNLOADED_TO_PORT;
359 
360     HeapFree(GetProcessHeap(), 0, downloaded_object->data);
361     downloaded_object->data = NULL;
362     downloaded_object->downloaded = FALSE;
363 
364     return S_OK;
365 }
366 
367 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetLatencyClock(LPDIRECTMUSICPORT iface, IReferenceClock** clock)
368 {
369     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
370 
371     TRACE("(%p/%p)->(%p)\n", iface, This, clock);
372 
373     *clock = This->pLatencyClock;
374     IReferenceClock_AddRef(*clock);
375 
376     return S_OK;
377 }
378 
379 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetRunningStats(LPDIRECTMUSICPORT iface, LPDMUS_SYNTHSTATS stats)
380 {
381     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
382 
383     FIXME("(%p/%p)->(%p): stub\n", iface, This, stats);
384 
385     return S_OK;
386 }
387 
388 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Compact(LPDIRECTMUSICPORT iface)
389 {
390     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
391 
392     FIXME("(%p/%p)->(): stub\n", iface, This);
393 
394     return S_OK;
395 }
396 
397 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetCaps(LPDIRECTMUSICPORT iface, LPDMUS_PORTCAPS port_caps)
398 {
399     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
400 
401     TRACE("(%p/%p)->(%p)\n", iface, This, port_caps);
402 
403     *port_caps = This->caps;
404 
405     return S_OK;
406 }
407 
408 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DeviceIoControl(LPDIRECTMUSICPORT iface, DWORD io_control_code, LPVOID in_buffer, DWORD in_buffer_size,
409                                                            LPVOID out_buffer, DWORD out_buffer_size, LPDWORD bytes_returned, LPOVERLAPPED overlapped)
410 {
411     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
412 
413     FIXME("(%p/%p)->(%d, %p, %d, %p, %d, %p, %p): stub\n", iface, This, io_control_code, in_buffer, in_buffer_size, out_buffer, out_buffer_size, bytes_returned, overlapped);
414 
415     return S_OK;
416 }
417 
418 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetNumChannelGroups(LPDIRECTMUSICPORT iface, DWORD channel_groups)
419 {
420     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
421 
422     FIXME("(%p/%p)->(%d): semi-stub\n", iface, This, channel_groups);
423 
424     This->nrofgroups = channel_groups;
425 
426     return S_OK;
427 }
428 
429 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetNumChannelGroups(LPDIRECTMUSICPORT iface, LPDWORD channel_groups)
430 {
431     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
432 
433     TRACE("(%p/%p)->(%p)\n", iface, This, channel_groups);
434 
435     *channel_groups = This->nrofgroups;
436 
437     return S_OK;
438 }
439 
440 static HRESULT WINAPI synth_dmport_Activate(IDirectMusicPort *iface, BOOL active)
441 {
442     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
443 
444     FIXME("(%p/%p)->(%d): semi-stub\n", iface, This, active);
445 
446     if (This->active == active)
447         return S_FALSE;
448 
449     if (active) {
450         /* Acquire the dsound */
451         if (!This->dsound) {
452             IDirectSound_AddRef(This->parent->dsound);
453             This->dsound = This->parent->dsound;
454         }
455         IDirectSound_AddRef(This->dsound);
456     } else {
457         /* Release the dsound */
458         IDirectSound_Release(This->dsound);
459         IDirectSound_Release(This->parent->dsound);
460         if (This->dsound == This->parent->dsound)
461             This->dsound = NULL;
462     }
463 
464     This->active = active;
465 
466     return S_OK;
467 }
468 
469 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetChannelPriority(LPDIRECTMUSICPORT iface, DWORD channel_group, DWORD channel, DWORD priority)
470 {
471     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
472 
473     FIXME("(%p/%p)->(%d, %d, %d): semi-stub\n", iface, This, channel_group, channel, priority);
474 
475     if (channel > 16)
476     {
477         WARN("isn't there supposed to be 16 channels (no. %d requested)?! (faking as it is ok)\n", channel);
478         /*return E_INVALIDARG;*/
479     }
480 
481     return S_OK;
482 }
483 
484 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetChannelPriority(LPDIRECTMUSICPORT iface, DWORD channel_group, DWORD channel, LPDWORD priority)
485 {
486     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
487 
488     TRACE("(%p/%p)->(%u, %u, %p)\n", iface, This, channel_group, channel, priority);
489 
490     *priority = This->group[channel_group - 1].channel[channel].priority;
491 
492     return S_OK;
493 }
494 
495 static HRESULT WINAPI synth_dmport_SetDirectSound(IDirectMusicPort *iface, IDirectSound *dsound,
496         IDirectSoundBuffer *dsbuffer)
497 {
498     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
499 
500     FIXME("(%p/%p)->(%p, %p): semi-stub\n", iface, This, dsound, dsbuffer);
501 
502     if (This->active)
503         return DMUS_E_DSOUND_ALREADY_SET;
504 
505     if (This->dsound) {
506         if (This->dsound != This->parent->dsound)
507             ERR("Not the same dsound in the port (%p) and parent dmusic (%p), expect trouble!\n",
508                     This->dsound, This->parent->dsound);
509         if (!IDirectSound_Release(This->parent->dsound))
510             This->parent->dsound = NULL;
511     }
512     if (This->dsbuffer)
513         IDirectSound_Release(This->dsbuffer);
514 
515     This->dsound = dsound;
516     This->dsbuffer = dsbuffer;
517 
518     if (This->dsound)
519         IDirectSound_AddRef(This->dsound);
520     if (This->dsbuffer)
521         IDirectSound_AddRef(This->dsbuffer);
522 
523     return S_OK;
524 }
525 
526 static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetFormat(LPDIRECTMUSICPORT iface, LPWAVEFORMATEX pWaveFormatEx, LPDWORD pdwWaveFormatExSize, LPDWORD pdwBufferSize)
527 {
528 	SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface);
529 	WAVEFORMATEX format;
530 	FIXME("(%p, %p, %p, %p): stub\n", This, pWaveFormatEx, pdwWaveFormatExSize, pdwBufferSize);
531 
532 	if (pWaveFormatEx == NULL)
533 	{
534 		if (pdwWaveFormatExSize)
535 			*pdwWaveFormatExSize = sizeof(format);
536 		else
537 			return E_POINTER;
538 	}
539 	else
540 	{
541 		if (pdwWaveFormatExSize == NULL)
542 			return E_POINTER;
543 
544 		/* Just fill this in with something that will not crash Direct Sound for now. */
545 		/* It won't be used anyway until Performances are completed */
546 		format.wFormatTag = WAVE_FORMAT_PCM;
547 		format.nChannels = 2; /* This->params.dwAudioChannels; */
548 		format.nSamplesPerSec = 44100; /* This->params.dwSampleRate; */
549 		format.wBitsPerSample = 16;	/* FIXME: check this */
550 		format.nBlockAlign = (format.wBitsPerSample * format.nChannels) / 8;
551 		format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
552 		format.cbSize = 0;
553 
554 		if (*pdwWaveFormatExSize >= sizeof(format))
555 		{
556 			CopyMemory(pWaveFormatEx, &format, min(sizeof(format), *pdwWaveFormatExSize));
557 			*pdwWaveFormatExSize = sizeof(format);	/* FIXME check if this is set */
558 		}
559 		else
560 			return E_POINTER;	/* FIXME find right error */
561 	}
562 
563 	if (pdwBufferSize)
564 		*pdwBufferSize = 44100 * 2 * 2;
565 	else
566 		return E_POINTER;
567 
568 	return S_OK;
569 }
570 
571 static const IDirectMusicPortVtbl SynthPortImpl_DirectMusicPort_Vtbl = {
572     /**** IDirectMusicPort IUnknown part methods ***/
573     SynthPortImpl_IDirectMusicPort_QueryInterface,
574     SynthPortImpl_IDirectMusicPort_AddRef,
575     SynthPortImpl_IDirectMusicPort_Release,
576     /**** IDirectMusicPort methods ***/
577     SynthPortImpl_IDirectMusicPort_PlayBuffer,
578     SynthPortImpl_IDirectMusicPort_SetReadNotificationHandle,
579     SynthPortImpl_IDirectMusicPort_Read,
580     SynthPortImpl_IDirectMusicPort_DownloadInstrument,
581     SynthPortImpl_IDirectMusicPort_UnloadInstrument,
582     SynthPortImpl_IDirectMusicPort_GetLatencyClock,
583     SynthPortImpl_IDirectMusicPort_GetRunningStats,
584     SynthPortImpl_IDirectMusicPort_Compact,
585     SynthPortImpl_IDirectMusicPort_GetCaps,
586     SynthPortImpl_IDirectMusicPort_DeviceIoControl,
587     SynthPortImpl_IDirectMusicPort_SetNumChannelGroups,
588     SynthPortImpl_IDirectMusicPort_GetNumChannelGroups,
589     synth_dmport_Activate,
590     SynthPortImpl_IDirectMusicPort_SetChannelPriority,
591     SynthPortImpl_IDirectMusicPort_GetChannelPriority,
592     synth_dmport_SetDirectSound,
593     SynthPortImpl_IDirectMusicPort_GetFormat
594 };
595 
596 /* SynthPortImpl IDirectMusicPortDownload IUnknown part follows: */
597 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_QueryInterface(LPDIRECTMUSICPORTDOWNLOAD iface, REFIID riid, LPVOID *ret_iface)
598 {
599     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
600 
601     TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
602 
603     return IDirectMusicPort_QueryInterface(&This->IDirectMusicPort_iface, riid, ret_iface);
604 }
605 
606 static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_AddRef (LPDIRECTMUSICPORTDOWNLOAD iface)
607 {
608     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
609 
610     TRACE("(%p/%p)->()\n", iface, This);
611 
612     return IDirectMusicPort_AddRef(&This->IDirectMusicPort_iface);
613 }
614 
615 static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_Release(LPDIRECTMUSICPORTDOWNLOAD iface)
616 {
617     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
618 
619     TRACE("(%p/%p)->()\n", iface, This);
620 
621     return IDirectMusicPort_Release(&This->IDirectMusicPort_iface);
622 }
623 
624 /* SynthPortImpl IDirectMusicPortDownload Interface follows: */
625 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetBuffer(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD DLId, IDirectMusicDownload** IDMDownload)
626 {
627     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
628 
629     FIXME("(%p/%p)->(%u, %p): stub\n", iface, This, DLId, IDMDownload);
630 
631     if (!IDMDownload)
632         return E_POINTER;
633 
634     return DMUSIC_CreateDirectMusicDownloadImpl(&IID_IDirectMusicDownload, (LPVOID*)IDMDownload, NULL);
635 }
636 
637 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_AllocateBuffer(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD size, IDirectMusicDownload** IDMDownload)
638 {
639     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
640 
641     FIXME("(%p/%p)->(%u, %p): stub\n", iface, This, size, IDMDownload);
642 
643     return S_OK;
644 }
645 
646 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetDLId(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD* start_DLId, DWORD count)
647 {
648     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
649 
650     FIXME("(%p/%p)->(%p, %u): stub\n", iface, This, start_DLId, count);
651 
652     return S_OK;
653 }
654 
655 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetAppend (LPDIRECTMUSICPORTDOWNLOAD iface, DWORD* append)
656 {
657     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
658 
659     FIXME("(%p/%p)->(%p): stub\n", iface, This, append);
660 
661     return S_OK;
662 }
663 
664 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Download(LPDIRECTMUSICPORTDOWNLOAD iface, IDirectMusicDownload* IDMDownload)
665 {
666     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
667 
668     FIXME("(%p/%p)->(%p): stub\n", iface, This, IDMDownload);
669 
670     return S_OK;
671 }
672 
673 static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Unload(LPDIRECTMUSICPORTDOWNLOAD iface, IDirectMusicDownload* IDMDownload)
674 {
675     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPortDownload(iface);
676 
677     FIXME("(%p/%p)->(%p): stub\n", iface, This, IDMDownload);
678 
679     return S_OK;
680 }
681 
682 static const IDirectMusicPortDownloadVtbl SynthPortImpl_DirectMusicPortDownload_Vtbl = {
683     /*** IDirectMusicPortDownload IUnknown part methods ***/
684     SynthPortImpl_IDirectMusicPortDownload_QueryInterface,
685     SynthPortImpl_IDirectMusicPortDownload_AddRef,
686     SynthPortImpl_IDirectMusicPortDownload_Release,
687     /*** IDirectMusicPortDownload methods ***/
688     SynthPortImpl_IDirectMusicPortDownload_GetBuffer,
689     SynthPortImpl_IDirectMusicPortDownload_AllocateBuffer,
690     SynthPortImpl_IDirectMusicPortDownload_GetDLId,
691     SynthPortImpl_IDirectMusicPortDownload_GetAppend,
692     SynthPortImpl_IDirectMusicPortDownload_Download,
693     SynthPortImpl_IDirectMusicPortDownload_Unload
694 };
695 
696 /* SynthPortImpl IDirectMusicThru IUnknown part follows: */
697 static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_QueryInterface(LPDIRECTMUSICTHRU iface, REFIID riid, LPVOID *ret_iface)
698 {
699     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicThru(iface);
700 
701     TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
702 
703     return IDirectMusicPort_QueryInterface(&This->IDirectMusicPort_iface, riid, ret_iface);
704 }
705 
706 static ULONG WINAPI SynthPortImpl_IDirectMusicThru_AddRef(LPDIRECTMUSICTHRU iface)
707 {
708     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicThru(iface);
709 
710     TRACE("(%p/%p)->()\n", iface, This);
711 
712     return IDirectMusicPort_AddRef(&This->IDirectMusicPort_iface);
713 }
714 
715 static ULONG WINAPI SynthPortImpl_IDirectMusicThru_Release(LPDIRECTMUSICTHRU iface)
716 {
717     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicThru(iface);
718 
719     TRACE("(%p/%p)->()\n", iface, This);
720 
721     return IDirectMusicPort_Release(&This->IDirectMusicPort_iface);
722 }
723 
724 /*  SynthPortImpl IDirectMusicThru Interface follows: */
725 static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_ThruChannel(LPDIRECTMUSICTHRU iface, DWORD source_channel_group, DWORD source_channel, DWORD destination_channel_group,
726                                                        DWORD destination_channel, LPDIRECTMUSICPORT destination_port)
727 {
728     SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicThru(iface);
729 
730     FIXME("(%p/%p)->(%d, %d, %d, %d, %p): stub\n", iface, This, source_channel_group, source_channel, destination_channel_group, destination_channel, destination_port);
731 
732     return S_OK;
733 }
734 
735 static const IDirectMusicThruVtbl SynthPortImpl_DirectMusicThru_Vtbl = {
736     /*** IDirectMusicThru IUnknown part methods */
737     SynthPortImpl_IDirectMusicThru_QueryInterface,
738     SynthPortImpl_IDirectMusicThru_AddRef,
739     SynthPortImpl_IDirectMusicThru_Release,
740     /*** IDirectMusicThru methods ***/
741     SynthPortImpl_IDirectMusicThru_ThruChannel
742 };
743 
744 static HRESULT WINAPI IKsControlImpl_QueryInterface(IKsControl *iface, REFIID riid,
745         void **ret_iface)
746 {
747     SynthPortImpl *This = impl_from_IKsControl(iface);
748 
749     return IDirectMusicPort_QueryInterface(&This->IDirectMusicPort_iface, riid, ret_iface);
750 }
751 
752 static ULONG WINAPI IKsControlImpl_AddRef(IKsControl *iface)
753 {
754     SynthPortImpl *This = impl_from_IKsControl(iface);
755 
756     return IDirectMusicPort_AddRef(&This->IDirectMusicPort_iface);
757 }
758 
759 static ULONG WINAPI IKsControlImpl_Release(IKsControl *iface)
760 {
761     SynthPortImpl *This = impl_from_IKsControl(iface);
762 
763     return IDirectMusicPort_Release(&This->IDirectMusicPort_iface);
764 }
765 
766 static HRESULT WINAPI IKsControlImpl_KsProperty(IKsControl *iface, KSPROPERTY *prop,
767         ULONG prop_len, void *data, ULONG data_len, ULONG *ret_len)
768 {
769     TRACE("(%p)->(%p, %u, %p, %u, %p)\n", iface, prop, prop_len, data, data_len, ret_len);
770     TRACE("prop = %s - %u - %u\n", debugstr_guid(&prop->u.s.Set), prop->u.s.Id, prop->u.s.Flags);
771 
772     if (prop->u.s.Flags != KSPROPERTY_TYPE_GET)
773     {
774         FIXME("prop flags %u not yet supported\n", prop->u.s.Flags);
775         return S_FALSE;
776     }
777 
778     if (data_len <  sizeof(DWORD))
779         return E_NOT_SUFFICIENT_BUFFER;
780 
781     FIXME("Unknown property %s\n", debugstr_guid(&prop->u.s.Set));
782     *(DWORD*)data = FALSE;
783     *ret_len = sizeof(DWORD);
784 
785     return S_OK;
786 }
787 
788 static HRESULT WINAPI IKsControlImpl_KsMethod(IKsControl *iface, KSMETHOD *method,
789         ULONG method_len, void *data, ULONG data_len, ULONG *ret_len)
790 {
791     FIXME("(%p)->(%p, %u, %p, %u, %p): stub\n", iface, method, method_len, data, data_len, ret_len);
792 
793     return E_NOTIMPL;
794 }
795 
796 static HRESULT WINAPI IKsControlImpl_KsEvent(IKsControl *iface, KSEVENT *event, ULONG event_len,
797         void *data, ULONG data_len, ULONG *ret_len)
798 {
799     FIXME("(%p)->(%p, %u, %p, %u, %p): stub\n", iface, event, event_len, data, data_len, ret_len);
800 
801     return E_NOTIMPL;
802 }
803 
804 static const IKsControlVtbl ikscontrol_vtbl = {
805     IKsControlImpl_QueryInterface,
806     IKsControlImpl_AddRef,
807     IKsControlImpl_Release,
808     IKsControlImpl_KsProperty,
809     IKsControlImpl_KsMethod,
810     IKsControlImpl_KsEvent
811 };
812 
813 HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params,
814         DMUS_PORTCAPS *port_caps, IDirectMusicPort **port)
815 {
816     SynthPortImpl *obj;
817     HRESULT hr = E_FAIL;
818     int i;
819 
820     TRACE("(%p, %p, %p)\n", port_params, port_caps, port);
821 
822     *port = NULL;
823 
824     obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SynthPortImpl));
825     if (!obj)
826         return E_OUTOFMEMORY;
827 
828     obj->IDirectMusicPort_iface.lpVtbl = &SynthPortImpl_DirectMusicPort_Vtbl;
829     obj->IDirectMusicPortDownload_iface.lpVtbl = &SynthPortImpl_DirectMusicPortDownload_Vtbl;
830     obj->IDirectMusicThru_iface.lpVtbl = &SynthPortImpl_DirectMusicThru_Vtbl;
831     obj->IKsControl_iface.lpVtbl = &ikscontrol_vtbl;
832     obj->ref = 1;
833     obj->parent = parent;
834     obj->active = FALSE;
835     obj->params = *port_params;
836     obj->caps = *port_caps;
837 
838     hr = DMUSIC_CreateReferenceClockImpl(&IID_IReferenceClock, (LPVOID*)&obj->pLatencyClock, NULL);
839     if (hr != S_OK)
840     {
841         HeapFree(GetProcessHeap(), 0, obj);
842         return hr;
843     }
844 
845     if (SUCCEEDED(hr))
846         hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth, (void**)&obj->synth);
847 
848     if (SUCCEEDED(hr))
849         hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink, (void**)&obj->synth_sink);
850 
851     if (SUCCEEDED(hr))
852         hr = IDirectMusicSynth_SetMasterClock(obj->synth, obj->pLatencyClock);
853 
854     if (SUCCEEDED(hr))
855         hr = IDirectMusicSynthSink_SetMasterClock(obj->synth_sink, obj->pLatencyClock);
856 
857     if (SUCCEEDED(hr))
858         hr = IDirectMusicSynth_SetSynthSink(obj->synth, obj->synth_sink);
859 
860     if (SUCCEEDED(hr))
861         hr = IDirectMusicSynth_Open(obj->synth, port_params);
862 
863     if (0)
864     {
865         if (port_params->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS) {
866             obj->nrofgroups = port_params->dwChannelGroups;
867             /* Setting default priorities */
868             for (i = 0; i < obj->nrofgroups; i++) {
869                 TRACE ("Setting default channel priorities on channel group %i\n", i + 1);
870                 obj->group[i].channel[0].priority = DAUD_CHAN1_DEF_VOICE_PRIORITY;
871                 obj->group[i].channel[1].priority = DAUD_CHAN2_DEF_VOICE_PRIORITY;
872                 obj->group[i].channel[2].priority = DAUD_CHAN3_DEF_VOICE_PRIORITY;
873                 obj->group[i].channel[3].priority = DAUD_CHAN4_DEF_VOICE_PRIORITY;
874                 obj->group[i].channel[4].priority = DAUD_CHAN5_DEF_VOICE_PRIORITY;
875                 obj->group[i].channel[5].priority = DAUD_CHAN6_DEF_VOICE_PRIORITY;
876                 obj->group[i].channel[6].priority = DAUD_CHAN7_DEF_VOICE_PRIORITY;
877                 obj->group[i].channel[7].priority = DAUD_CHAN8_DEF_VOICE_PRIORITY;
878                 obj->group[i].channel[8].priority = DAUD_CHAN9_DEF_VOICE_PRIORITY;
879                 obj->group[i].channel[9].priority = DAUD_CHAN10_DEF_VOICE_PRIORITY;
880                 obj->group[i].channel[10].priority = DAUD_CHAN11_DEF_VOICE_PRIORITY;
881                 obj->group[i].channel[11].priority = DAUD_CHAN12_DEF_VOICE_PRIORITY;
882                 obj->group[i].channel[12].priority = DAUD_CHAN13_DEF_VOICE_PRIORITY;
883                 obj->group[i].channel[13].priority = DAUD_CHAN14_DEF_VOICE_PRIORITY;
884                 obj->group[i].channel[14].priority = DAUD_CHAN15_DEF_VOICE_PRIORITY;
885                 obj->group[i].channel[15].priority = DAUD_CHAN16_DEF_VOICE_PRIORITY;
886             }
887         }
888     }
889 
890     if (SUCCEEDED(hr)) {
891         *port = &obj->IDirectMusicPort_iface;
892         return S_OK;
893     }
894 
895     if (obj->synth)
896         IDirectMusicSynth_Release(obj->synth);
897     if (obj->synth_sink)
898         IDirectMusicSynthSink_Release(obj->synth_sink);
899     if (obj->pLatencyClock)
900         IReferenceClock_Release(obj->pLatencyClock);
901     HeapFree(GetProcessHeap(), 0, obj);
902 
903     return hr;
904 }
905 
906 HRESULT midi_out_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params,
907         DMUS_PORTCAPS *port_caps, IDirectMusicPort **port)
908 {
909     FIXME("(%p, %p, %p): stub\n", port_params, port_caps, port);
910 
911     return E_NOTIMPL;
912 }
913 
914 HRESULT midi_in_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params,
915         DMUS_PORTCAPS *port_caps, IDirectMusicPort **port)
916 {
917     FIXME("(%p, %p, %p): stub\n", port_params, port_caps, port);
918 
919     return E_NOTIMPL;
920 }
921