[PATCH v3 0/5] MR4375: dmsynth: Various fixes 2
-- v3: dmsynth: Use FLUID_MOD_KEY for CONN_SRC_KEYNUMBER. dmsynth: Fall back to the Standard drum set when there is no matching instrument or region. dmsynth: Factor out instrument and region search. dmsynth: Get rid of instrument reference counting. dmsynth: Move instrument search to synth_preset_noteon(). https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
From: Anton Baskanov <baskanov(a)gmail.com> This allows loaded instruments to take effect without a subsequent program change. In particular, when there is no program change at all, this allows the default Acoustic Grand Piano or Standard drum set to play. As a side effect, this disables FluidSynth fallback logic for missing presets. --- dlls/dmsynth/synth.c | 53 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 51271e48b2a..d11ca0f2f5d 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -288,11 +288,6 @@ struct instrument struct synth *synth; }; -static void instrument_addref(struct instrument *instrument) -{ - InterlockedIncrement(&instrument->ref); -} - static void instrument_release(struct instrument *instrument) { ULONG ref = InterlockedDecrement(&instrument->ref); @@ -327,7 +322,7 @@ struct preset fluid_preset_t *fluid_preset; - struct instrument *instrument; + struct synth *synth; }; struct event @@ -637,7 +632,6 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) LIST_FOR_EACH_ENTRY_SAFE(preset, next, &This->presets, struct preset, entry) { list_remove(&preset->entry); - instrument_release(preset->instrument); delete_fluid_preset(preset->fluid_preset); free(preset); } @@ -1785,13 +1779,28 @@ static void set_default_voice_connections(fluid_voice_t *fluid_voice) static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) { struct preset *preset = fluid_preset_get_data(fluid_preset); - struct instrument *instrument = preset->instrument; - struct synth *synth = instrument->synth; + struct synth *synth = preset->synth; + struct instrument *instrument; fluid_voice_t *fluid_voice; struct region *region; TRACE("(%p, %p, %u, %u, %u)\n", fluid_preset, fluid_synth, chan, key, vel); + EnterCriticalSection(&synth->cs); + + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) + { + if (preset->bank == 128 && instrument->patch == (0x80000000 | preset->patch)) break; + else if (instrument->patch == ((preset->bank << 8) | preset->patch)) break; + } + + if (&instrument->entry == &synth->instruments) + { + WARN("Could not find instrument with patch %#x\n", preset->patch); + LeaveCriticalSection(&synth->cs); + return FLUID_FAILED; + } + LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) { struct articulation *articulation; @@ -1804,6 +1813,7 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, wave->fluid_sample, chan, key, vel))) { WARN("Failed to allocate FluidSynth voice\n"); + LeaveCriticalSection(&synth->cs); return FLUID_FAILED; } @@ -1819,7 +1829,10 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui if (&voice->entry == &synth->voices) { if (!(voice = calloc(1, sizeof(struct voice)))) + { + LeaveCriticalSection(&synth->cs); return FLUID_FAILED; + } voice->fluid_voice = fluid_voice; list_add_tail(&synth->voices, &voice->entry); } @@ -1852,9 +1865,12 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) add_voice_connections(fluid_voice, &articulation->list, articulation->connections); fluid_synth_start_voice(synth->fluid_synth, fluid_voice); + LeaveCriticalSection(&synth->cs); return FLUID_OK; } + LeaveCriticalSection(&synth->cs); + WARN("Failed to find instrument matching note / velocity\n"); return FLUID_FAILED; } @@ -1871,7 +1887,6 @@ static const char *synth_sfont_get_name(fluid_sfont_t *fluid_sfont) static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int bank, int patch) { struct synth *synth = fluid_sfont_get_data(fluid_sfont); - struct instrument *instrument; fluid_preset_t *fluid_preset; struct preset *preset; @@ -1888,19 +1903,6 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba } } - LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) - { - if (bank == 128 && instrument->patch == (0x80000000 | patch)) break; - else if (instrument->patch == ((bank << 8) | patch)) break; - } - - if (&instrument->entry == &synth->instruments) - { - WARN("Could not find instrument with patch %#x\n", patch); - LeaveCriticalSection(&synth->cs); - return NULL; - } - if (!(fluid_preset = new_fluid_preset(fluid_sfont, synth_preset_get_name, synth_preset_get_bank, synth_preset_get_num, synth_preset_noteon, synth_preset_free))) { @@ -1918,12 +1920,11 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba preset->bank = bank; preset->patch = patch; preset->fluid_preset = fluid_preset; - preset->instrument = instrument; + preset->synth = synth; fluid_preset_set_data(fluid_preset, preset); - instrument_addref(instrument); list_add_tail(&synth->presets, &preset->entry); - TRACE("Created fluid_preset %p for instrument %p\n", fluid_preset, instrument); + TRACE("Created fluid_preset %p\n", fluid_preset); LeaveCriticalSection(&synth->cs); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmsynth/synth.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index d11ca0f2f5d..05f5b0e354e 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -277,7 +277,6 @@ static void region_destroy(struct region *region) struct instrument { struct list entry; - LONG ref; UINT id; UINT patch; @@ -288,30 +287,25 @@ struct instrument struct synth *synth; }; -static void instrument_release(struct instrument *instrument) +static void instrument_destroy(struct instrument *instrument) { - ULONG ref = InterlockedDecrement(&instrument->ref); + struct articulation *articulation; + struct region *region; + void *next; - if (!ref) + LIST_FOR_EACH_ENTRY_SAFE(region, next, &instrument->regions, struct region, entry) { - struct articulation *articulation; - struct region *region; - void *next; - - LIST_FOR_EACH_ENTRY_SAFE(region, next, &instrument->regions, struct region, entry) - { - list_remove(®ion->entry); - region_destroy(region); - } - - LIST_FOR_EACH_ENTRY_SAFE(articulation, next, &instrument->articulations, struct articulation, entry) - { - list_remove(&articulation->entry); - free(articulation); - } + list_remove(®ion->entry); + region_destroy(region); + } - free(instrument); + LIST_FOR_EACH_ENTRY_SAFE(articulation, next, &instrument->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); } + + free(instrument); } struct preset @@ -424,7 +418,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) LIST_FOR_EACH_ENTRY_SAFE(instrument, next, &This->instruments, struct instrument, entry) { list_remove(&instrument->entry); - instrument_release(instrument); + instrument_destroy(instrument); } LIST_FOR_EACH_ENTRY_SAFE(wave, next, &This->waves, struct wave, entry) @@ -736,7 +730,6 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * if (instrument_info->ulFirstExtCkIdx) FIXME("Instrument extensions not implemented\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; @@ -763,7 +756,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * if (!(region->wave = synth_find_wave_from_id(This, region->wave_link.ulTableIndex))) { free(region); - instrument_release(instrument); + instrument_destroy(instrument); return DMUS_E_BADWAVELINK; } @@ -786,7 +779,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * return S_OK; error: - instrument_release(instrument); + instrument_destroy(instrument); return E_OUTOFMEMORY; } @@ -930,7 +923,7 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, list_remove(&instrument->entry); LeaveCriticalSection(&This->cs); - instrument_release(instrument); + instrument_destroy(instrument); return S_OK; } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmsynth/synth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c4a19607544..ec9785c4218 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1814,6 +1814,8 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui EnterCriticalSection(&synth->cs); find_region(synth, preset->bank, preset->patch, key, vel, &instrument, ®ion); + if (!region && preset->bank == 128) + find_region(synth, preset->bank, 0, key, vel, &instrument, ®ion); if (!instrument) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
From: Anton Baskanov <baskanov(a)gmail.com> --- dlls/dmsynth/synth.c | 149 +++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 05f5b0e354e..c4a19607544 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1411,6 +1411,35 @@ static int synth_preset_get_num(fluid_preset_t *fluid_preset) return preset->patch; } +static void find_region(struct synth *synth, int bank, int patch, int key, int vel, + struct instrument **out_instrument, struct region **out_region) +{ + struct instrument *instrument; + struct region *region; + + *out_instrument = NULL; + *out_region = NULL; + + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) + { + if (bank == 128 && instrument->patch == (0x80000000 | patch)) break; + else if (instrument->patch == ((bank << 8) | patch)) break; + } + + if (&instrument->entry == &synth->instruments) + return; + + *out_instrument = instrument; + + LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) + { + if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; + if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; + *out_region = region; + break; + } +} + static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) { switch (conn->usDestination) @@ -1773,99 +1802,93 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui { struct preset *preset = fluid_preset_get_data(fluid_preset); struct synth *synth = preset->synth; + struct articulation *articulation; struct instrument *instrument; fluid_voice_t *fluid_voice; struct region *region; + struct voice *voice; + struct wave *wave; TRACE("(%p, %p, %u, %u, %u)\n", fluid_preset, fluid_synth, chan, key, vel); EnterCriticalSection(&synth->cs); - LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) - { - if (preset->bank == 128 && instrument->patch == (0x80000000 | preset->patch)) break; - else if (instrument->patch == ((preset->bank << 8) | preset->patch)) break; - } + find_region(synth, preset->bank, preset->patch, key, vel, &instrument, ®ion); - if (&instrument->entry == &synth->instruments) + if (!instrument) { WARN("Could not find instrument with patch %#x\n", preset->patch); LeaveCriticalSection(&synth->cs); return FLUID_FAILED; } + if (!region) + { + WARN("Failed to find instrument matching note / velocity\n"); + LeaveCriticalSection(&synth->cs); + return FLUID_FAILED; + } - LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) + wave = region->wave; + + if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, wave->fluid_sample, chan, key, vel))) { - struct articulation *articulation; - struct wave *wave = region->wave; - struct voice *voice; + WARN("Failed to allocate FluidSynth voice\n"); + LeaveCriticalSection(&synth->cs); + return FLUID_FAILED; + } - if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; - if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; + LIST_FOR_EACH_ENTRY(voice, &synth->voices, struct voice, entry) + { + if (voice->fluid_voice == fluid_voice) + { + wave_release(voice->wave); + break; + } + } - if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, wave->fluid_sample, chan, key, vel))) + if (&voice->entry == &synth->voices) + { + if (!(voice = calloc(1, sizeof(struct voice)))) { - WARN("Failed to allocate FluidSynth voice\n"); LeaveCriticalSection(&synth->cs); return FLUID_FAILED; } + voice->fluid_voice = fluid_voice; + list_add_tail(&synth->voices, &voice->entry); + } - LIST_FOR_EACH_ENTRY(voice, &synth->voices, struct voice, entry) - { - if (voice->fluid_voice == fluid_voice) - { - wave_release(voice->wave); - break; - } - } + voice->wave = wave; + wave_addref(voice->wave); - if (&voice->entry == &synth->voices) - { - if (!(voice = calloc(1, sizeof(struct voice)))) - { - LeaveCriticalSection(&synth->cs); - return FLUID_FAILED; - } - voice->fluid_voice = fluid_voice; - list_add_tail(&synth->voices, &voice->entry); - } + set_default_voice_connections(fluid_voice); + if (region->wave_sample.cSampleLoops) + { + WLOOP *loop = region->wave_loops; - voice->wave = wave; - wave_addref(voice->wave); + if (loop->ulType == WLOOP_TYPE_FORWARD) + fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_DURING_RELEASE); + else if (loop->ulType == WLOOP_TYPE_RELEASE) + fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_UNTIL_RELEASE); + else + FIXME("Unsupported loop type %lu\n", loop->ulType); - set_default_voice_connections(fluid_voice); - if (region->wave_sample.cSampleLoops) - { - WLOOP *loop = region->wave_loops; - - if (loop->ulType == WLOOP_TYPE_FORWARD) - fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_DURING_RELEASE); - else if (loop->ulType == WLOOP_TYPE_RELEASE) - fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_UNTIL_RELEASE); - else - FIXME("Unsupported loop type %lu\n", loop->ulType); - - /* When copy_data is TRUE, fluid_sample_set_sound_data() adds - * 8-frame padding around the sample data. Offset the loop points - * to compensate for this. */ - fluid_voice_gen_set(fluid_voice, GEN_STARTLOOPADDROFS, 8 + loop->ulStart); - fluid_voice_gen_set(fluid_voice, GEN_ENDLOOPADDROFS, 8 + loop->ulStart + loop->ulLength); - } - fluid_voice_gen_set(fluid_voice, GEN_OVERRIDEROOTKEY, region->wave_sample.usUnityNote); - fluid_voice_gen_set(fluid_voice, GEN_FINETUNE, region->wave_sample.sFineTune); - LIST_FOR_EACH_ENTRY(articulation, &instrument->articulations, struct articulation, entry) - add_voice_connections(fluid_voice, &articulation->list, articulation->connections); - LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) - add_voice_connections(fluid_voice, &articulation->list, articulation->connections); - fluid_synth_start_voice(synth->fluid_synth, fluid_voice); - LeaveCriticalSection(&synth->cs); - return FLUID_OK; + /* When copy_data is TRUE, fluid_sample_set_sound_data() adds + * 8-frame padding around the sample data. Offset the loop points + * to compensate for this. */ + fluid_voice_gen_set(fluid_voice, GEN_STARTLOOPADDROFS, 8 + loop->ulStart); + fluid_voice_gen_set(fluid_voice, GEN_ENDLOOPADDROFS, 8 + loop->ulStart + loop->ulLength); } + fluid_voice_gen_set(fluid_voice, GEN_OVERRIDEROOTKEY, region->wave_sample.usUnityNote); + fluid_voice_gen_set(fluid_voice, GEN_FINETUNE, region->wave_sample.sFineTune); + LIST_FOR_EACH_ENTRY(articulation, &instrument->articulations, struct articulation, entry) + add_voice_connections(fluid_voice, &articulation->list, articulation->connections); + LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) + add_voice_connections(fluid_voice, &articulation->list, articulation->connections); + fluid_synth_start_voice(synth->fluid_synth, fluid_voice); LeaveCriticalSection(&synth->cs); - WARN("Failed to find instrument matching note / velocity\n"); - return FLUID_FAILED; + return FLUID_OK; } static void synth_preset_free(fluid_preset_t *fluid_preset) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
From: Anton Baskanov <baskanov(a)gmail.com> Fixes incorrect EG key number scale and offset that caused missing lower notes of some instruments (e.g. Acoustic Grand Piano). --- dlls/dmsynth/synth.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index ec9785c4218..bbe77e43cc9 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1483,17 +1483,6 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION { if (!gen_from_connection(conn, &gen)) return FALSE; } - else if (conn->usSource == CONN_SRC_KEYNUMBER) - { - switch (conn->usDestination) - { - case CONN_DST_EG2_HOLDTIME: gen = GEN_KEYTOMODENVHOLD; break; - case CONN_DST_EG2_DECAYTIME: gen = GEN_KEYTOMODENVDECAY; break; - case CONN_DST_EG1_HOLDTIME: gen = GEN_KEYTOVOLENVHOLD; break; - case CONN_DST_EG1_DECAYTIME: gen = GEN_KEYTOVOLENVDECAY; break; - default: return FALSE; - } - } else if (conn->usSource == CONN_SRC_LFO) { switch (conn->usDestination) @@ -1588,10 +1577,6 @@ static void add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION case MAKELONG(CONN_SRC_LFO, CONN_DST_FILTER_CUTOFF): gen = GEN_MODLFOTOFILTERFC; break; case MAKELONG(CONN_SRC_EG2, CONN_DST_FILTER_CUTOFF): gen = GEN_MODENVTOFILTERFC; break; case MAKELONG(CONN_SRC_LFO, CONN_DST_GAIN): gen = GEN_MODLFOTOVOL; break; - case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_HOLDTIME): gen = GEN_KEYTOMODENVHOLD; break; - case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_DECAYTIME): gen = GEN_KEYTOMODENVDECAY; break; - case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_HOLDTIME): gen = GEN_KEYTOVOLENVHOLD; break; - case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_DECAYTIME): gen = GEN_KEYTOVOLENVDECAY; break; } if (conn->usControl != CONN_SRC_NONE && gen != -1) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
v3: - dropped event ordering commits - added fallback for missing drum regions - use modulators with FLUID_MOD_KEY instead of the special generators -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4375#note_52348
On Wed Nov 15 09:26:10 2023 +0000, Anton Baskanov wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/4375/diffs?diff_id=83621&start_sha=0ff26da7a1c059cedcfc8cb3a3c3d486b023c3b6#898da1162f66a862545683e41dd74655e665af7c_347_336) Turns out not only can we use modulators with FLUID_MOD_KEY instead of the special generators, but it also uses the correct scaling and offset without any additional fixups. Updated the request.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/4375#note_52349
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
Unrelated test failure in win.c -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4375#note_52405
This merge request was approved by Michael Stefaniuc. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4375
participants (4)
-
Anton Baskanov -
Anton Baskanov (@baskanov) -
Michael Stefaniuc (@mstefani) -
Rémi Bernon