-- 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().
From: Anton Baskanov baskanov@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);
From: Anton Baskanov baskanov@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; } }
From: Anton Baskanov baskanov@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) {
From: Anton Baskanov baskanov@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)
From: Anton Baskanov baskanov@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)
v3: - dropped event ordering commits - added fallback for missing drum regions - use modulators with FLUID_MOD_KEY instead of the special generators
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.
This merge request was approved by Rémi Bernon.
Unrelated test failure in win.c
This merge request was approved by Michael Stefaniuc.