-- v4: dmloader: Mark cached objects as loaded. dmsynth: Don't leak modulators. dmsynth: Free the allocated presets manually. dmsynth: Remove useless private data checks. dmsynth: Create one FluidSynth sample per wave. dmsynth: Use generators to set root key and fine tune. dmsynth: Keep track of voice/wave mapping.
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmsynth/synth.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index a4196f29a8a..aee76af5302 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -320,6 +320,13 @@ struct event BYTE midi[3]; };
+struct voice +{ + struct list entry; + fluid_voice_t *fluid_voice; + struct wave *wave; +}; + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -336,6 +343,7 @@ struct synth struct list instruments; struct list waves; struct list events; + struct list voices;
fluid_settings_t *fluid_settings; fluid_sfont_t *fluid_sfont; @@ -584,6 +592,8 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct voice *voice; + void *next;
TRACE("(%p)\n", This);
@@ -597,6 +607,14 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) fluid_synth_remove_sfont(This->fluid_synth, This->fluid_sfont); delete_fluid_synth(This->fluid_synth); This->fluid_synth = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(voice, next, &This->voices, struct voice, entry) + { + list_remove(&voice->entry); + wave_release(voice->wave); + free(voice); + } + This->open = FALSE; LeaveCriticalSection(&This->cs);
@@ -1742,6 +1760,7 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui { struct articulation *articulation; struct wave *wave = region->wave; + struct voice *voice;
if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; @@ -1763,6 +1782,29 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui return FLUID_FAILED; }
+ LIST_FOR_EACH_ENTRY(voice, &synth->voices, struct voice, entry) + { + if (voice->fluid_voice == fluid_voice) + { + wave_release(voice->wave); + break; + } + } + + if (&voice->entry == &synth->voices) + { + if (!(voice = calloc(1, sizeof(struct voice)))) + { + delete_fluid_sample(fluid_sample); + return FLUID_FAILED; + } + voice->fluid_voice = fluid_voice; + list_add_tail(&synth->voices, &voice->entry); + } + + voice->wave = wave; + wave_addref(voice->wave); + set_default_voice_connections(fluid_voice); if (region->wave_sample.cSampleLoops) { @@ -1885,6 +1927,7 @@ HRESULT synth_create(IUnknown **ret_iface) list_init(&obj->instruments); list_init(&obj->waves); list_init(&obj->events); + list_init(&obj->voices);
if (!(obj->fluid_settings = new_fluid_settings())) goto failed; if (!(obj->fluid_sfont = new_fluid_sfont(synth_sfont_get_name, synth_sfont_get_preset,
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmsynth/synth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index aee76af5302..556947fc30a 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1739,7 +1739,6 @@ static void set_default_voice_connections(fluid_voice_t *fluid_voice) fluid_voice_gen_set(fluid_voice, GEN_KEYNUM, -1.); fluid_voice_gen_set(fluid_voice, GEN_VELOCITY, -1.); fluid_voice_gen_set(fluid_voice, GEN_SCALETUNE, 100.0); - fluid_voice_gen_set(fluid_voice, GEN_OVERRIDEROOTKEY, -1.);
add_voice_connections(fluid_voice, &list, connections); } @@ -1773,7 +1772,6 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui
fluid_sample_set_sound_data(fluid_sample, wave->samples, NULL, wave->sample_count, wave->format.nSamplesPerSec, TRUE); - fluid_sample_set_pitch(fluid_sample, region->wave_sample.usUnityNote, region->wave_sample.sFineTune);
if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, fluid_sample, chan, key, vel))) { @@ -1823,6 +1821,8 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui 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)
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmsynth/synth.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 556947fc30a..f936d51e02e 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -209,6 +209,8 @@ struct wave LONG ref; UINT id;
+ fluid_sample_t *fluid_sample; + WAVEFORMATEX format; UINT sample_count; short samples[]; @@ -224,7 +226,11 @@ static void wave_addref(struct wave *wave) static void wave_release(struct wave *wave) { ULONG ref = InterlockedDecrement(&wave->ref); - if (!ref) free(wave); + if (!ref) + { + delete_fluid_sample(wave->fluid_sample); + free(wave); + } }
struct articulation @@ -825,6 +831,16 @@ static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, } }
+ if (!(wave->fluid_sample = new_fluid_sample())) + { + WARN("Failed to allocate FluidSynth sample\n"); + free(wave); + return FLUID_FAILED; + } + + fluid_sample_set_sound_data(wave->fluid_sample, wave->samples, NULL, wave->sample_count, + wave->format.nSamplesPerSec, TRUE); + EnterCriticalSection(&This->cs); list_add_tail(&This->waves, &wave->entry); LeaveCriticalSection(&This->cs); @@ -1747,7 +1763,6 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui { struct instrument *instrument = fluid_preset_get_data(fluid_preset); struct synth *synth = instrument->synth; - fluid_sample_t *fluid_sample; fluid_voice_t *fluid_voice; struct region *region;
@@ -1764,19 +1779,9 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue;
- if (!(fluid_sample = new_fluid_sample())) - { - WARN("Failed to allocate FluidSynth sample\n"); - return FLUID_FAILED; - } - - fluid_sample_set_sound_data(fluid_sample, wave->samples, NULL, wave->sample_count, - wave->format.nSamplesPerSec, TRUE); - - if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, fluid_sample, chan, key, vel))) + if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, wave->fluid_sample, chan, key, vel))) { WARN("Failed to allocate FluidSynth voice\n"); - delete_fluid_sample(fluid_sample); return FLUID_FAILED; }
@@ -1792,10 +1797,7 @@ 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)))) - { - delete_fluid_sample(fluid_sample); return FLUID_FAILED; - } voice->fluid_voice = fluid_voice; list_add_tail(&synth->voices, &voice->entry); }
From: Anton Baskanov baskanov@gmail.com
We always set the data. --- dlls/dmsynth/synth.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index f936d51e02e..6d747980cbd 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1398,7 +1398,6 @@ static int synth_preset_get_num(fluid_preset_t *fluid_preset)
TRACE("(%p)\n", fluid_preset);
- if (!instrument) return 0; return instrument->patch; }
@@ -1768,8 +1767,6 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui
TRACE("(%p, %p, %u, %u, %u)\n", fluid_preset, fluid_synth, chan, key, vel);
- if (!instrument) return FLUID_FAILED; - LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) { struct articulation *articulation; @@ -1857,8 +1854,6 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba
TRACE("(%p, %d, %d)\n", fluid_sfont, bank, patch);
- if (!synth) return NULL; - EnterCriticalSection(&synth->cs);
LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry)
From: Anton Baskanov baskanov@gmail.com
FluidSynth never calls synth_preset_free(), causing preset and instrument leaks. --- dlls/dmsynth/synth.c | 69 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 6d747980cbd..b3c624b5b6b 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -319,6 +319,17 @@ static void instrument_release(struct instrument *instrument) } }
+struct preset +{ + struct list entry; + int bank; + int patch; + + fluid_preset_t *fluid_preset; + + struct instrument *instrument; +}; + struct event { struct list entry; @@ -350,6 +361,7 @@ struct synth struct list waves; struct list events; struct list voices; + struct list presets;
fluid_settings_t *fluid_settings; fluid_sfont_t *fluid_sfont; @@ -598,6 +610,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct preset *preset; struct voice *voice; void *next;
@@ -621,6 +634,14 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) free(voice); }
+ 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); + } + This->open = FALSE; LeaveCriticalSection(&This->cs);
@@ -1394,11 +1415,11 @@ static int synth_preset_get_bank(fluid_preset_t *fluid_preset)
static int synth_preset_get_num(fluid_preset_t *fluid_preset) { - struct instrument *instrument = fluid_preset_get_data(fluid_preset); + struct preset *preset = fluid_preset_get_data(fluid_preset);
TRACE("(%p)\n", fluid_preset);
- return instrument->patch; + return preset->patch; }
static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) @@ -1760,7 +1781,8 @@ 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 instrument *instrument = fluid_preset_get_data(fluid_preset); + struct preset *preset = fluid_preset_get_data(fluid_preset); + struct instrument *instrument = preset->instrument; struct synth *synth = instrument->synth; fluid_voice_t *fluid_voice; struct region *region; @@ -1836,9 +1858,6 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui
static void synth_preset_free(fluid_preset_t *fluid_preset) { - struct instrument *instrument = fluid_preset_get_data(fluid_preset); - fluid_preset_set_data(fluid_preset, NULL); - if (instrument) instrument_release(instrument); }
static const char *synth_sfont_get_name(fluid_sfont_t *fluid_sfont) @@ -1851,11 +1870,21 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba struct synth *synth = fluid_sfont_get_data(fluid_sfont); struct instrument *instrument; fluid_preset_t *fluid_preset; + struct preset *preset;
TRACE("(%p, %d, %d)\n", fluid_sfont, bank, patch);
EnterCriticalSection(&synth->cs);
+ LIST_FOR_EACH_ENTRY(preset, &synth->presets, struct preset, entry) + { + if (preset->bank == bank && preset->patch == patch) + { + LeaveCriticalSection(&synth->cs); + return preset->fluid_preset; + } + } + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) { if (bank == 128 && instrument->patch == (0x80000000 | patch)) break; @@ -1864,18 +1893,35 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba
if (&instrument->entry == &synth->instruments) { - fluid_preset = NULL; WARN("Could not find instrument with patch %#x\n", patch); + LeaveCriticalSection(&synth->cs); + return NULL; } - else if ((fluid_preset = new_fluid_preset(fluid_sfont, synth_preset_get_name, synth_preset_get_bank, + + 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))) { - fluid_preset_set_data(fluid_preset, instrument); - instrument_addref(instrument); + LeaveCriticalSection(&synth->cs); + return NULL; + }
- TRACE("Created fluid_preset %p for instrument %p\n", fluid_preset, instrument); + if (!(preset = calloc(1, sizeof(struct preset)))) + { + delete_fluid_preset(fluid_preset); + LeaveCriticalSection(&synth->cs); + return NULL; }
+ preset->bank = bank; + preset->patch = patch; + preset->fluid_preset = fluid_preset; + preset->instrument = instrument; + 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); + LeaveCriticalSection(&synth->cs);
return fluid_preset; @@ -1925,6 +1971,7 @@ HRESULT synth_create(IUnknown **ret_iface) list_init(&obj->waves); list_init(&obj->events); list_init(&obj->voices); + list_init(&obj->presets);
if (!(obj->fluid_settings = new_fluid_settings())) goto failed; if (!(obj->fluid_sfont = new_fluid_sfont(synth_sfont_get_name, synth_sfont_get_preset,
From: Anton Baskanov baskanov@gmail.com
--- dlls/dmsynth/synth.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index b3c624b5b6b..410fb59089e 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1607,6 +1607,7 @@ static void add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION fluid_mod_set_amount(mod, value);
fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_OVERWRITE); + delete_fluid_mod(mod); }
static void add_voice_connections(fluid_voice_t *fluid_voice, const CONNECTIONLIST *list,
From: Anton Baskanov baskanov@gmail.com
Otherwise, the object won't be found in the cache and will leak on release. --- dlls/dmloader/loader.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 78b9790dff3..49fae09cc7f 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -433,12 +433,14 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE pObjectEntry = calloc(1, sizeof(*pObjectEntry)); DM_STRUCT_INIT(&pObjectEntry->Desc); DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->Desc.dwValidData |= DMUS_OBJ_LOADED; pObjectEntry->pObject = pObject; list_add_head(&This->cache, &pObjectEntry->entry); } else { DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->Desc.dwValidData |= DMUS_OBJ_LOADED; pObjectEntry->pObject = pObject; } TRACE(": filled in cache entry\n");
On Wed Nov 8 12:26:23 2023 +0000, Rémi Bernon wrote:
Eh, looking at next commit I understand now. This is silly that they have a free callback but never call it... looks like the same for the sfont (although we apparently own it).
`synth_sfont_free` is not called because we remove the sfont before calling `delete_fluid_synth`.
On Thu Nov 9 05:37:49 2023 +0000, Anton Baskanov wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/4339/diffs?diff_id=82472&start_sha=e8614085a496ea27fcc149f7bfbba1f3f3eb299a#898da1162f66a862545683e41dd74655e665af7c_452_447)
Done.
On Thu Nov 9 05:37:50 2023 +0000, Anton Baskanov wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/4339/diffs?diff_id=82472&start_sha=e8614085a496ea27fcc149f7bfbba1f3f3eb299a#898da1162f66a862545683e41dd74655e665af7c_449_447)
Done.
On Thu Nov 9 05:37:52 2023 +0000, Anton Baskanov wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/4339/diffs?diff_id=82472&start_sha=e8614085a496ea27fcc149f7bfbba1f3f3eb299a#898da1162f66a862545683e41dd74655e665af7c_464_447)
Done.
I plan to decouple instruments from presets so that a downloaded instrument takes effect immediately without a program change. It should also fix the issue with presets keeping instruments alive.
c4f42a68f09842a00daaff108992ff369b416cd0 somehow breaks in-game music in FF VIII after the first time a track is played (for instance after transitioning out and back in a zone), I think you should drop it for now.