-- v3: dmsynth: Implement IDirectMusicSynth_Download for instrument articulations. dmsynth: Implement IDirectMusicSynth_Download for instrument regions. dmsynth: Implement IDirectMusicSynth_(Download|Unload) for waves. dmsynth: Implement IDirectMusicSynth_(Download|Unload) for instruments. dmusic: Avoid passing invalid handle to IDirectMusicSynth_Unload. dmsynth/tests: Test IDirectMusicSynth_Unload.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/tests/dmsynth.c | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-)
diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 897af33bf80..cb4e68fd56c 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -830,6 +830,22 @@ static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD b } }
+static BOOL unload_called; + +static HRESULT CALLBACK test_unload_callback(HANDLE handle, HANDLE user_data) +{ + ok(!!handle, "got %p\n", handle); + ok(user_data == (HANDLE)0xdeadbeef, "got %p\n", user_data); + unload_called = TRUE; + return E_FAIL; +} + +static HRESULT CALLBACK test_unload_no_callback(HANDLE handle, HANDLE user_data) +{ + ok(0, "unexpected %s\n", __func__); + return E_FAIL; +} + static void test_IDirectMusicSynth(void) { static const UINT RENDER_ITERATIONS = 8; @@ -943,7 +959,7 @@ static void test_IDirectMusicSynth(void) IDirectMusicBuffer *buffer; DWORD format_size, written; IDirectMusicSynth *synth; - HANDLE wave_file, handle; + HANDLE wave_file, wave_handle, instrument_handle; IReferenceClock *clock; BOOL can_free = FALSE; REFERENCE_TIME time; @@ -1095,17 +1111,17 @@ static void test_IDirectMusicSynth(void) wave_download.samples[i] = i;
can_free = 0xdeadbeef; - handle = (HANDLE)0xdeadbeef; - hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free); + wave_handle = NULL; + hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - ok(handle != 0, "got %p\n", handle); + todo_wine ok(!!wave_handle, "got %p\n", wave_handle); todo_wine ok(can_free == FALSE, "got %u\n", can_free);
can_free = 0xdeadbeef; - handle = (HANDLE)0xdeadbeef; - hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free); + instrument_handle = NULL; + hr = IDirectMusicSynth_Download(synth, &instrument_handle, &instrument_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - ok(handle != 0, "got %p\n", handle); + todo_wine ok(!!instrument_handle, "got %p\n", instrument_handle); todo_wine ok(can_free == TRUE, "got %u\n", can_free);
/* add a MIDI note to a buffer and play it */ @@ -1133,15 +1149,32 @@ static void test_IDirectMusicSynth(void) CloseHandle(wave_file); trace("Rendered samples to %s\n", debugstr_w(temp_file));
+ hr = IDirectMusicSynth_Activate(synth, FALSE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynth_SetSynthSink(synth, NULL); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(sink); ok(ref == 1, "got %lu\n", ref); + + hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!unload_called, "callback called\n"); + hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(unload_called, "callback not called\n"); + hr = IDirectMusicSynth_Close(synth); ok(hr == S_OK, "got %#lx\n", hr);
+ hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + IDirectMusicSynth_Release(synth);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmusic/port.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 94ab970ae76..95a02704a5f 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -707,6 +707,7 @@ static HRESULT WINAPI synth_port_download_Unload(IDirectMusicPortDownload *iface } }
+ if (!handle) return S_OK; return IDirectMusicSynth_Unload(This->synth, handle, NULL, NULL); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 229 ++++++++++++++++++----------------- dlls/dmsynth/tests/dmsynth.c | 10 +- 2 files changed, 121 insertions(+), 118 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 0916e64f4a6..701fe122e60 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -28,6 +28,35 @@
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
+static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) +{ + TRACE("DMUS_INSTRUMENT:\n"); + TRACE(" - ulPatch = %lu\n", instrument->ulPatch); + TRACE(" - ulFirstRegionIdx = %lu\n", instrument->ulFirstRegionIdx); + TRACE(" - ulGlobalArtIdx = %lu\n", instrument->ulGlobalArtIdx); + TRACE(" - ulFirstExtCkIdx = %lu\n", instrument->ulFirstExtCkIdx); + TRACE(" - ulCopyrightIdx = %lu\n", instrument->ulCopyrightIdx); + TRACE(" - ulFlags = %lu\n", instrument->ulFlags); +} + +struct instrument +{ + struct list entry; + LONG ref; + UINT id; + + UINT patch; + UINT flags; + + struct synth *synth; +}; + +static void instrument_release(struct instrument *instrument) +{ + ULONG ref = InterlockedDecrement(&instrument->ref); + if (!ref) free(instrument); +} + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -39,6 +68,8 @@ struct synth BOOL active; BOOL open; IDirectMusicSynthSink *sink; + + struct list instruments; };
static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -92,7 +123,19 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface)
TRACE("(%p): new ref = %lu\n", This, ref);
- if (!ref) free(This); + if (!ref) + { + struct instrument *instrument; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(instrument, next, &This->instruments, struct instrument, entry) + { + list_remove(&instrument->entry); + instrument_release(instrument); + } + + free(This); + }
return ref; } @@ -207,134 +250,80 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; }
-static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownload, - void *data, BOOL *free) +static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, + BYTE *data, HANDLE *ret_handle) { - struct synth *This = impl_from_IDirectMusicSynth8(iface); - LPBYTE buffer = data; - 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); - - FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, data, free); - - /* FIXME: Currently we only dump data which is very useful to known how native dmusic behave and debug builtin dmusic */ - - if (!hDownload || !free) - return E_POINTER; + DMUS_INSTRUMENT *instrument_info = (DMUS_INSTRUMENT *)(data + offsets[0]); + struct instrument *instrument;
if (TRACE_ON(dmsynth)) { - TRACE("Dump DMUS_DOWNLOADINFO struct:\n"); - TRACE(" - dwDLType = %lu\n", info->dwDLType); - TRACE(" - dwDLId = %lu\n", info->dwDLId); - TRACE(" - dwNumOffsetTableEntries = %lu\n", info->dwNumOffsetTableEntries); - TRACE(" - cbSize = %lu\n", info->cbSize); - } + dump_dmus_instrument(instrument_info);
- /* The struct should have at least one offset corresponding to the download object itself */ - 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; + if (instrument_info->ulCopyrightIdx) + { + DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT *)(data + offsets[instrument_info->ulCopyrightIdx]); + TRACE("Copyright = '%s'\n", (char *)copyright->byCopyright); + } }
- if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT) - { - FIXME("Download type DMUS_DOWNLOADINFO_INSTRUMENT not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVE) - { - DMUS_WAVE *wave = (DMUS_WAVE*)object; - DMUS_WAVEDATA *wave_data; + if (instrument_info->ulFirstExtCkIdx) FIXME("Instrument extensions not implemented\n");
- TRACE("Processing download type DMUS_DOWNLOADINFO_WAVE\n"); + if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; + instrument->ref = 1; + instrument->id = info->dwDLId; + instrument->patch = instrument_info->ulPatch; + instrument->flags = instrument_info->ulFlags; + instrument->synth = This;
- if (TRACE_ON(dmsynth)) - { - TRACE("Dump DMUS_WAVE struct\n"); - TRACE(" - ulFirstExtCkIdx = %lu\n", wave->ulFirstExtCkIdx); - TRACE(" - ulCopyrightIdx = %lu\n", wave->ulCopyrightIdx); - TRACE(" - ulWaveDataIdx = %lu\n", wave->ulWaveDataIdx); - TRACE(" - WaveformatEx:\n"); - TRACE(" - wFormatTag = %u\n", wave->WaveformatEx.wFormatTag); - TRACE(" - nChannels = %u\n", wave->WaveformatEx.nChannels); - TRACE(" - nSamplesPerSec = %lu\n", wave->WaveformatEx.nSamplesPerSec); - TRACE(" - nAvgBytesPerSec = %lu\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); - } + list_add_tail(&This->instruments, &instrument->entry); + *ret_handle = instrument;
- wave_data = (DMUS_WAVEDATA*)(buffer + offsets[wave->ulWaveDataIdx]); - TRACE("Found %lu bytes of wave data\n", wave_data->cbSize); - } - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2) - { - DMUS_INSTRUMENT *instrument = (DMUS_INSTRUMENT*)object; - ULONG nb_regions = 0; + return S_OK; +}
- TRACE("Processing download type DMUS_DOWNLOADINFO_INSTRUMENT2\n"); +static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_handle, void *data, BOOL *ret_free) +{ + struct synth *This = impl_from_IDirectMusicSynth8(iface); + DMUS_DOWNLOADINFO *info = data; + ULONG *offsets = (ULONG *)(info + 1);
- if (TRACE_ON(dmsynth)) - { - TRACE("Dump DMUS_INSTRUMENT struct\n"); - TRACE(" - ulPatch = %lu\n", instrument->ulPatch); - TRACE(" - ulFirstRegionIdx = %lu\n", instrument->ulFirstRegionIdx); - TRACE(" - ulGlobalArtIdx = %lu\n", instrument->ulGlobalArtIdx); - TRACE(" - ulFirstExtCkIdx = %lu\n", instrument->ulFirstExtCkIdx); - TRACE(" - ulCopyrightIdx = %lu\n", instrument->ulCopyrightIdx); - TRACE(" - ulFlags = %lu\n", instrument->ulFlags); - - if (instrument->ulCopyrightIdx) - { - DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT*)(buffer + offsets[instrument->ulCopyrightIdx]); - TRACE("Copyright = '%s'\n", (char*)copyright->byCopyright); - } - } + FIXME("(%p)->(%p, %p, %p): stub\n", This, ret_handle, data, free);
- if (instrument->ulFirstRegionIdx) - { - ULONG region_idx = instrument->ulFirstRegionIdx; + if (!ret_handle || !data || !ret_free) return E_POINTER; + *ret_handle = 0; + *ret_free = TRUE;
- while (region_idx) - { - DMUS_REGION *region = (DMUS_REGION*)(buffer + offsets[region_idx]); + if (TRACE_ON(dmsynth)) + { + TRACE("Dump DMUS_DOWNLOADINFO struct:\n"); + TRACE(" - dwDLType = %lu\n", info->dwDLType); + TRACE(" - dwDLId = %lu\n", info->dwDLId); + TRACE(" - dwNumOffsetTableEntries = %lu\n", info->dwNumOffsetTableEntries); + TRACE(" - cbSize = %lu\n", info->cbSize); + }
- region_idx = region->ulNextRegionIdx; - nb_regions++; - } - } + if (!info->dwNumOffsetTableEntries) return DMUS_E_BADOFFSETTABLE; + if (((BYTE *)data + offsets[0]) != (BYTE *)(offsets + info->dwNumOffsetTableEntries)) return DMUS_E_BADOFFSETTABLE;
- TRACE("Number of regions = %lu\n", nb_regions); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVEARTICULATION) + switch (info->dwDLType) { + case DMUS_DOWNLOADINFO_INSTRUMENT: + case DMUS_DOWNLOADINFO_INSTRUMENT2: + return synth_download_instrument(This, info, offsets, data, ret_handle); + case DMUS_DOWNLOADINFO_WAVE: + FIXME("Download type DMUS_DOWNLOADINFO_WAVE not yet supported\n"); + return S_OK; + case DMUS_DOWNLOADINFO_WAVEARTICULATION: FIXME("Download type DMUS_DOWNLOADINFO_WAVEARTICULATION not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE) - { + return E_NOTIMPL; + case DMUS_DOWNLOADINFO_STREAMINGWAVE: FIXME("Download type DMUS_DOWNLOADINFO_STREAMINGWAVE not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_ONESHOTWAVE) - { + return E_NOTIMPL; + case DMUS_DOWNLOADINFO_ONESHOTWAVE: FIXME("Download type DMUS_DOWNLOADINFO_ONESHOTWAVE not yet supported\n"); - } - else - { + return E_NOTIMPL; + default: WARN("Unknown download type %lu\n", info->dwDLType); return DMUS_E_UNKNOWNDOWNLOAD; } @@ -342,14 +331,26 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownloa return S_OK; }
-static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, - HRESULT (CALLBACK *lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData) +static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, + HRESULT (CALLBACK *callback)(HANDLE, HANDLE), HANDLE user_data) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct instrument *instrument;
- FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, lpFreeHandle, hUserData); + TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); + if (callback) FIXME("Unload callbacks not implemented\n");
- return S_OK; + LIST_FOR_EACH_ENTRY(instrument, &This->instruments, struct instrument, entry) + { + if (instrument == handle) + { + list_remove(&instrument->entry); + instrument_release(instrument); + return S_OK; + } + } + + return E_FAIL; }
static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, @@ -742,6 +743,8 @@ HRESULT synth_create(IUnknown **ret_iface) obj->caps.dwEffectFlags = DMUS_EFFECT_REVERB; lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer");
+ list_init(&obj->instruments); + TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index cb4e68fd56c..e7f6f232011 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1121,8 +1121,8 @@ static void test_IDirectMusicSynth(void) instrument_handle = NULL; hr = IDirectMusicSynth_Download(synth, &instrument_handle, &instrument_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(!!instrument_handle, "got %p\n", instrument_handle); - todo_wine ok(can_free == TRUE, "got %u\n", can_free); + ok(!!instrument_handle, "got %p\n", instrument_handle); + ok(can_free == TRUE, "got %u\n", can_free);
/* add a MIDI note to a buffer and play it */ hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); @@ -1158,11 +1158,11 @@ static void test_IDirectMusicSynth(void) ok(ref == 1, "got %lu\n", ref);
hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); - ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); ok(!unload_called, "callback called\n"); hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); ok(hr == S_OK, "got %#lx\n", hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 120 ++++++++++++++++++++++++++++++++++- dlls/dmsynth/tests/dmsynth.c | 4 +- 2 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 701fe122e60..b1397b20006 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -39,6 +39,41 @@ static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) TRACE(" - ulFlags = %lu\n", instrument->ulFlags); }
+static void dump_dmus_wave(DMUS_WAVE *wave) +{ + TRACE("DMUS_WAVE:\n"); + TRACE(" - ulFirstExtCkIdx = %lu\n", wave->ulFirstExtCkIdx); + TRACE(" - ulCopyrightIdx = %lu\n", wave->ulCopyrightIdx); + TRACE(" - ulWaveDataIdx = %lu\n", wave->ulWaveDataIdx); + TRACE(" - WaveformatEx:\n"); + TRACE(" - wFormatTag = %u\n", wave->WaveformatEx.wFormatTag); + TRACE(" - nChannels = %u\n", wave->WaveformatEx.nChannels); + TRACE(" - nSamplesPerSec = %lu\n", wave->WaveformatEx.nSamplesPerSec); + TRACE(" - nAvgBytesPerSec = %lu\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); +} + +struct wave +{ + struct list entry; + LONG ref; + UINT id; + + WAVEFORMATEX format; + UINT sample_count; + short samples[]; +}; + +C_ASSERT(sizeof(struct wave) == offsetof(struct wave, samples[0])); + +static void wave_release(struct wave *wave) +{ + ULONG ref = InterlockedDecrement(&wave->ref); + if (!ref) free(wave); +} + struct instrument { struct list entry; @@ -70,6 +105,7 @@ struct synth IDirectMusicSynthSink *sink;
struct list instruments; + struct list waves; };
static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -126,6 +162,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) if (!ref) { struct instrument *instrument; + struct wave *wave; void *next;
LIST_FOR_EACH_ENTRY_SAFE(instrument, next, &This->instruments, struct instrument, entry) @@ -134,6 +171,12 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) instrument_release(instrument); }
+ LIST_FOR_EACH_ENTRY_SAFE(wave, next, &This->waves, struct wave, entry) + { + list_remove(&wave->entry); + wave_release(wave); + } + free(This); }
@@ -282,6 +325,68 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * return S_OK; }
+static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, + BYTE *data, HANDLE *ret_handle) +{ + DMUS_WAVE *wave_info = (DMUS_WAVE *)(data + offsets[0]); + DMUS_WAVEDATA *wave_data = (DMUS_WAVEDATA *)(data + offsets[wave_info->ulWaveDataIdx]); + struct wave *wave; + UINT sample_count; + + if (TRACE_ON(dmsynth)) + { + dump_dmus_wave(wave_info); + + if (wave_info->ulCopyrightIdx) + { + DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT *)(data + offsets[wave_info->ulCopyrightIdx]); + TRACE("Copyright = '%s'\n", (char *)copyright->byCopyright); + } + + TRACE("Found %lu bytes of wave data\n", wave_data->cbSize); + } + + if (wave_info->ulFirstExtCkIdx) FIXME("Wave extensions not implemented\n"); + if (wave_info->WaveformatEx.wFormatTag != WAVE_FORMAT_PCM) return DMUS_E_NOTPCM; + + sample_count = wave_data->cbSize / wave_info->WaveformatEx.nBlockAlign; + if (!(wave = calloc(1, offsetof(struct wave, samples[sample_count])))) return E_OUTOFMEMORY; + wave->ref = 1; + wave->id = info->dwDLId; + wave->format = wave_info->WaveformatEx; + wave->sample_count = sample_count; + + if (wave_info->WaveformatEx.nBlockAlign == 1) + { + while (sample_count--) + { + short sample = (wave_data->byData[sample_count] - 0x80) << 8; + wave->samples[sample_count] = sample; + } + } + else if (wave_info->WaveformatEx.nBlockAlign == 2) + { + while (sample_count--) + { + short sample = ((short *)wave_data->byData)[sample_count]; + wave->samples[sample_count] = sample; + } + } + else if (wave_info->WaveformatEx.nBlockAlign == 4) + { + while (sample_count--) + { + short sample = ((UINT *)wave_data->byData)[sample_count] >> 16; + wave->samples[sample_count] = sample; + } + } + + list_add_tail(&This->waves, &wave->entry); + *ret_handle = wave; + + return S_OK; +} + static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_handle, void *data, BOOL *ret_free) { struct synth *This = impl_from_IDirectMusicSynth8(iface); @@ -312,8 +417,7 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_hand case DMUS_DOWNLOADINFO_INSTRUMENT2: return synth_download_instrument(This, info, offsets, data, ret_handle); case DMUS_DOWNLOADINFO_WAVE: - FIXME("Download type DMUS_DOWNLOADINFO_WAVE not yet supported\n"); - return S_OK; + return synth_download_wave(This, info, offsets, data, ret_handle); case DMUS_DOWNLOADINFO_WAVEARTICULATION: FIXME("Download type DMUS_DOWNLOADINFO_WAVEARTICULATION not yet supported\n"); return E_NOTIMPL; @@ -336,6 +440,7 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, { struct synth *This = impl_from_IDirectMusicSynth8(iface); struct instrument *instrument; + struct wave *wave;
TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); if (callback) FIXME("Unload callbacks not implemented\n"); @@ -350,6 +455,16 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, } }
+ LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) + { + if (wave == handle) + { + list_remove(&wave->entry); + wave_release(wave); + return S_OK; + } + } + return E_FAIL; }
@@ -744,6 +859,7 @@ HRESULT synth_create(IUnknown **ret_iface) lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer");
list_init(&obj->instruments); + list_init(&obj->waves);
TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index e7f6f232011..64a81e33b43 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1114,7 +1114,7 @@ static void test_IDirectMusicSynth(void) wave_handle = NULL; hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(!!wave_handle, "got %p\n", wave_handle); + ok(!!wave_handle, "got %p\n", wave_handle); todo_wine ok(can_free == FALSE, "got %u\n", can_free);
can_free = 0xdeadbeef; @@ -1162,7 +1162,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!unload_called, "callback called\n"); hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); ok(hr == S_OK, "got %#lx\n", hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 126 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index b1397b20006..9256c62654b 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -39,6 +39,40 @@ static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) TRACE(" - ulFlags = %lu\n", instrument->ulFlags); }
+static void dump_dmus_region(DMUS_REGION *region) +{ + UINT i; + + TRACE("DMUS_REGION:\n"); + TRACE(" - RangeKey = %u - %u\n", region->RangeKey.usLow, region->RangeKey.usHigh); + TRACE(" - RangeVelocity = %u - %u\n", region->RangeVelocity.usLow, region->RangeVelocity.usHigh); + TRACE(" - fusOptions = %#x\n", region->fusOptions); + TRACE(" - usKeyGroup = %u\n", region->usKeyGroup); + TRACE(" - ulRegionArtIdx = %lu\n", region->ulRegionArtIdx); + TRACE(" - ulNextRegionIdx = %lu\n", region->ulNextRegionIdx); + TRACE(" - ulFirstExtCkIdx = %lu\n", region->ulFirstExtCkIdx); + TRACE(" - WaveLink:\n"); + TRACE(" - fusOptions = %#x\n", region->WaveLink.fusOptions); + TRACE(" - usPhaseGroup = %u\n", region->WaveLink.usPhaseGroup); + TRACE(" - ulChannel = %lu\n", region->WaveLink.ulChannel); + TRACE(" - ulTableIndex = %lu\n", region->WaveLink.ulTableIndex); + TRACE(" - WSMP:\n"); + TRACE(" - cbSize = %lu\n", region->WSMP.cbSize); + TRACE(" - usUnityNote = %u\n", region->WSMP.usUnityNote); + TRACE(" - sFineTune = %u\n", region->WSMP.sFineTune); + TRACE(" - lAttenuation = %lu\n", region->WSMP.lAttenuation); + TRACE(" - fulOptions = %#lx\n", region->WSMP.fulOptions); + TRACE(" - cSampleLoops = %lu\n", region->WSMP.cSampleLoops); + for (i = 0; i < region->WSMP.cSampleLoops; i++) + { + TRACE(" - WLOOP[%u]:\n", i); + TRACE(" - cbSize = %lu\n", region->WLOOP[i].cbSize); + TRACE(" - ulType = %#lx\n", region->WLOOP[i].ulType); + TRACE(" - ulStart = %lu\n", region->WLOOP[i].ulStart); + TRACE(" - ulLength = %lu\n", region->WLOOP[i].ulLength); + } +} + static void dump_dmus_wave(DMUS_WAVE *wave) { TRACE("DMUS_WAVE:\n"); @@ -68,12 +102,38 @@ struct wave
C_ASSERT(sizeof(struct wave) == offsetof(struct wave, samples[0]));
+static void wave_addref(struct wave *wave) +{ + InterlockedIncrement(&wave->ref); +} + static void wave_release(struct wave *wave) { ULONG ref = InterlockedDecrement(&wave->ref); if (!ref) free(wave); }
+struct region +{ + struct list entry; + + RGNRANGE key_range; + RGNRANGE vel_range; + UINT flags; + UINT group; + + struct wave *wave; + WAVELINK wave_link; + WSMPL wave_sample; + WLOOP wave_loops[]; +}; + +static void region_destroy(struct region *region) +{ + wave_release(region->wave); + free(region); +} + struct instrument { struct list entry; @@ -82,6 +142,7 @@ struct instrument
UINT patch; UINT flags; + struct list regions;
struct synth *synth; }; @@ -89,7 +150,20 @@ struct instrument static void instrument_release(struct instrument *instrument) { ULONG ref = InterlockedDecrement(&instrument->ref); - if (!ref) free(instrument); + + if (!ref) + { + struct region *region; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(region, next, &instrument->regions, struct region, entry) + { + list_remove(®ion->entry); + region_destroy(region); + } + + free(instrument); + } }
struct synth @@ -293,11 +367,31 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; }
+static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) +{ + struct wave *wave; + + LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) + { + if (wave->id == id) + { + wave_addref(wave); + return wave; + } + } + + WARN("Failed to find wave with id %#lx\n", id); + return NULL; +} + static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, BYTE *data, HANDLE *ret_handle) { DMUS_INSTRUMENT *instrument_info = (DMUS_INSTRUMENT *)(data + offsets[0]); struct instrument *instrument; + DMUS_REGION *region_info; + struct region *region; + ULONG index;
if (TRACE_ON(dmsynth)) { @@ -317,12 +411,42 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument->id = info->dwDLId; instrument->patch = instrument_info->ulPatch; instrument->flags = instrument_info->ulFlags; + list_init(&instrument->regions); instrument->synth = This;
+ for (index = instrument_info->ulFirstRegionIdx; index; index = region_info->ulNextRegionIdx) + { + region_info = (DMUS_REGION *)(data + offsets[index]); + if (TRACE_ON(dmsynth)) dump_dmus_region(region_info); + if (region_info->ulFirstExtCkIdx) FIXME("Region extensions not implemented\n"); + + if (!(region = calloc(1, offsetof(struct region, wave_loops[region_info->WSMP.cSampleLoops])))) goto error; + region->key_range = region_info->RangeKey; + region->vel_range = region_info->RangeVelocity; + region->flags = region_info->fusOptions; + region->group = region_info->usKeyGroup; + region->wave_link = region_info->WaveLink; + region->wave_sample = region_info->WSMP; + memcpy(region->wave_loops, region_info->WLOOP, region_info->WSMP.cSampleLoops * sizeof(WLOOP)); + + if (!(region->wave = synth_find_wave_from_id(This, region->wave_link.ulTableIndex))) + { + free(region); + instrument_release(instrument); + return DMUS_E_BADWAVELINK; + } + + list_add_tail(&instrument->regions, ®ion->entry); + } + list_add_tail(&This->instruments, &instrument->entry); *ret_handle = instrument;
return S_OK; + +error: + instrument_release(instrument); + return E_OUTOFMEMORY; }
static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 101 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 9256c62654b..a3243d4b683 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -73,6 +73,26 @@ static void dump_dmus_region(DMUS_REGION *region) } }
+static void dump_connectionlist(CONNECTIONLIST *list) +{ + CONNECTION *connections = (CONNECTION *)(list + 1); + UINT i; + + TRACE("CONNECTIONLIST:\n"); + TRACE(" - cbSize = %lu", list->cbSize); + TRACE(" - cConnections = %lu", list->cConnections); + + for (i = 0; i < list->cConnections; i++) + { + TRACE("- CONNECTION[%u]:\n", i); + TRACE(" - usSource = %u\n", connections[i].usSource); + TRACE(" - usControl = %u\n", connections[i].usControl); + TRACE(" - usDestination = %u\n", connections[i].usDestination); + TRACE(" - usTransform = %u\n", connections[i].usTransform); + TRACE(" - lScale = %lu\n", connections[i].lScale); + } +} + static void dump_dmus_wave(DMUS_WAVE *wave) { TRACE("DMUS_WAVE:\n"); @@ -113,6 +133,15 @@ static void wave_release(struct wave *wave) if (!ref) free(wave); }
+struct articulation +{ + struct list entry; + CONNECTIONLIST list; + CONNECTION connections[]; +}; + +C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connections[0])); + struct region { struct list entry; @@ -122,6 +151,8 @@ struct region UINT flags; UINT group;
+ struct list articulations; + struct wave *wave; WAVELINK wave_link; WSMPL wave_sample; @@ -130,6 +161,15 @@ struct region
static void region_destroy(struct region *region) { + struct articulation *articulation; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(articulation, next, ®ion->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + wave_release(region->wave); free(region); } @@ -143,6 +183,7 @@ struct instrument UINT patch; UINT flags; struct list regions; + struct list articulations;
struct synth *synth; }; @@ -153,6 +194,7 @@ static void instrument_release(struct instrument *instrument)
if (!ref) { + struct articulation *articulation; struct region *region; void *next;
@@ -162,6 +204,12 @@ static void instrument_release(struct instrument *instrument) region_destroy(region); }
+ LIST_FOR_EACH_ENTRY_SAFE(articulation, next, &instrument->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + free(instrument); } } @@ -367,6 +415,47 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; }
+static HRESULT synth_download_articulation2(struct synth *This, ULONG *offsets, BYTE *data, + UINT index, struct list *articulations) +{ + DMUS_ARTICULATION2 *articulation_info; + struct articulation *articulation; + CONNECTION *connections; + CONNECTIONLIST *list; + UINT size; + + for (; index; index = articulation_info->ulNextArtIdx) + { + articulation_info = (DMUS_ARTICULATION2 *)(data + offsets[index]); + list = (CONNECTIONLIST *)(data + offsets[articulation_info->ulArtIdx]); + connections = (CONNECTION *)list + 1; + + if (TRACE_ON(dmsynth)) dump_connectionlist(list); + if (articulation_info->ulFirstExtCkIdx) FIXME("Articulation extensions not implemented\n"); + if (list->cbSize != sizeof(*list)) return DMUS_E_BADARTICULATION; + + size = offsetof(struct articulation, connections[list->cConnections]); + if (!(articulation = calloc(1, size))) return E_OUTOFMEMORY; + articulation->list = *list; + memcpy(articulation->connections, connections, list->cConnections * sizeof(*connections)); + list_add_tail(articulations, &articulation->entry); + } + + return S_OK; +} + +static HRESULT synth_download_articulation(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, BYTE *data, + UINT index, struct list *list) +{ + if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2) + return synth_download_articulation2(This, offsets, data, index, list); + else + { + FIXME("DMUS_ARTICPARAMS support not implemented\n"); + return S_OK; + } +} + static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) { struct wave *wave; @@ -412,6 +501,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument->patch = instrument_info->ulPatch; instrument->flags = instrument_info->ulFlags; list_init(&instrument->regions); + list_init(&instrument->articulations); instrument->synth = This;
for (index = instrument_info->ulFirstRegionIdx; index; index = region_info->ulNextRegionIdx) @@ -428,6 +518,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * region->wave_link = region_info->WaveLink; region->wave_sample = region_info->WSMP; memcpy(region->wave_loops, region_info->WLOOP, region_info->WSMP.cSampleLoops * sizeof(WLOOP)); + list_init(®ion->articulations);
if (!(region->wave = synth_find_wave_from_id(This, region->wave_link.ulTableIndex))) { @@ -437,8 +528,16 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * }
list_add_tail(&instrument->regions, ®ion->entry); + + if (region_info->ulRegionArtIdx && FAILED(synth_download_articulation(This, info, offsets, data, + region_info->ulRegionArtIdx, ®ion->articulations))) + goto error; }
+ if (FAILED(synth_download_articulation(This, info, offsets, data, + instrument_info->ulGlobalArtIdx, &instrument->articulations))) + goto error; + list_add_tail(&This->instruments, &instrument->entry); *ret_handle = instrument;
@@ -517,7 +616,7 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_hand DMUS_DOWNLOADINFO *info = data; ULONG *offsets = (ULONG *)(info + 1);
- FIXME("(%p)->(%p, %p, %p): stub\n", This, ret_handle, data, free); + TRACE("(%p)->(%p, %p, %p)\n", This, ret_handle, data, free);
if (!ret_handle || !data || !ret_free) return E_POINTER; *ret_handle = 0;
Thanks for catching this, it should be fixed now.
About your other question on #winehackers, refcounts are useful to keep waves referenced from the instrument regions, which is necessary to avoid deleting them on Unload, if they are unloaded before the instruments (this is actually checked in the test, and the unload callback -which we don't implement- for the wave is only called after the last reference to it, from the instrument, is released).
For the instruments, it's not very useful yet as there's only a single reference, but it will be useful later, when they are returned as FluidSynth soundfont presets.
This merge request was approved by Michael Stefaniuc.