-- v2: 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 | 12 +- 2 files changed, 122 insertions(+), 119 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 0916e64f4a6..ff78f7cbe4e 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; + if (instrument_info->ulCopyrightIdx) + { + DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT *)(data + offsets[instrument_info->ulCopyrightIdx]); + TRACE("Copyright = '%s'\n", (char *)copyright->byCopyright); + } }
- /* 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->ulFirstExtCkIdx) FIXME("Instrument extensions not implemented\n");
- 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 = 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;
- TRACE("Processing download type DMUS_DOWNLOADINFO_WAVE\n"); + list_add_tail(&This->instruments, &instrument->entry); + *ret_handle = instrument;
- 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); - } + return S_OK; +}
- 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; +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);
- TRACE("Processing download type DMUS_DOWNLOADINFO_INSTRUMENT2\n"); + FIXME("(%p)->(%p, %p, %p): stub\n", This, ret_handle, data, free);
- 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); - } - } - - 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 E_NOTIMPL; + 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..8d8879cfe41 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1113,7 +1113,7 @@ static void test_IDirectMusicSynth(void) can_free = 0xdeadbeef; wave_handle = NULL; hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); - ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); todo_wine ok(!!wave_handle, "got %p\n", wave_handle); todo_wine ok(can_free == FALSE, "got %u\n", can_free);
@@ -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 | 6 +- 2 files changed, 121 insertions(+), 5 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index ff78f7cbe4e..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 E_NOTIMPL; + 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 8d8879cfe41..64a81e33b43 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1113,8 +1113,8 @@ static void test_IDirectMusicSynth(void) can_free = 0xdeadbeef; wave_handle = NULL; hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(!!wave_handle, "got %p\n", wave_handle); + ok(hr == S_OK, "got %#lx\n", hr); + 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 | 99 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 9256c62654b..748d6fc63ee 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;
v2: Add some sanity checks for flexible arrays and expected struct lengths.
I get consistent test crashes with commit "dmsynth: Implement IDirectMusicSynth_(Download|Unload) for instruments." No crashes with the full MR `0024:fixme:dmsynth:synth_Download (00D634B0)->(0068FCD4, 00D62DBC, 6AAF3540): stub 0024:fixme:dmsynth:synth_Download Download type DMUS_DOWNLOADINFO_WAVE not yet supported dmusic.c:1146: Test failed: got 0x80004001 0024:fixme:dmsynth:synth_Download (00D634B0)->(0068FCD4, 00D62DBC, 6AAF3540): stub 0024:fixme:dmsynth:synth_Download Download type DMUS_DOWNLOADINFO_WAVE not yet supported dmusic.c:1148: Test failed: got 0x80004001 dmusic.c:1152: Test failed: got 0x88781120 dmusic.c:1153: Test failed: got DEADBEEF wine: Unhandled page fault on read access to DEADBEEF at address 00408C8C (thread 0024), starting debugger... Unhandled exception: page fault on read access to 0xdeadbeef in wow64 32-bit code (0x00408c8c). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b EIP:00408c8c ESP:0068fd00 EBP:0068fd78 EFLAGS:00010202( R- -- I - - - ) EAX:deadbeef EBX:88781120 ECX:7bc0c33c EDX:00000000 ESI:0068fd34 EDI:0068fd50 Stack dump: 0x0068fd00: 00000000 0040d499 deadbeef 0040de28 0x0068fd10: 0068fd44 00000015 0068fd38 7bc49d1a 0x0068fd20: 7bc69520 003566a0 00000001 00000001 0x0068fd30: 00d62db0 deadbeef 00d62dbc 00d62f2c 0x0068fd40: deadbeef 00000040 00d62450 00d6265c 0x0068fd50: 00000000 cccccccc cccccccc cccccccc Backtrace: =>0 0x00408c8c test_port_download+0xa0d() [/home/michi/work/wine/dlls/dmusic/tests/dmusic.c:1154] in dmusic_test (0x0068fd78) 1 0x00408c8c func_dmusic+0x147c() [/home/michi/work/wine/dlls/dmusic/tests/dmusic.c:1341] in dmusic_test (0x0068fd78) 2 0x00409863 run_test+0xf3(name=<register EDI not accessible in this frame>) [/home/michi/work/wine/include/wine/test.h:707] in dmusic_test (0x0068fe18) 3 0x0040a890 main+0x240(argc=<couldn't compute location>, argv=<couldn't compute location>) [/home/michi/work/wine/include/wine/test.h:824] in dmusic_test (0x0068fee8) 4 0x0040a604 mainCRTStartup+0x74() [/home/michi/work/wine/dlls/msvcrt/crt_main.c:60] in dmusic_test (0x0068ff30) 5 0x7b828a70 in kernel32 (+0x28a70) (0x0068ff48) 6 0x7bc59627 in ntdll (+0x59627) (0x0068ff5c) 7 0x7bc59e48 in ntdll (+0x59e48) (0x0068ffec) 0x00408c8c func_dmusic+0x147c [/home/michi/work/wine/dlls/dmusic/tests/dmusic.c:1341] in dmusic_test: mov (%eax), %edx 1341 test_synthport(); `