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 | 49 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 410fb59089e..ada20431d57 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -327,7 +327,7 @@ struct preset
fluid_preset_t *fluid_preset;
- struct instrument *instrument; + struct synth *synth; };
struct event @@ -637,7 +637,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); } @@ -1783,13 +1782,29 @@ 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) + { + fluid_preset = NULL; + 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; @@ -1802,6 +1817,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; }
@@ -1817,7 +1833,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); } @@ -1850,9 +1869,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; } @@ -1869,7 +1891,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;
@@ -1886,19 +1907,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))) { @@ -1916,12 +1924,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 | 48 +++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 30 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index ada20431d57..e23fff4bdb1 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,35 +287,25 @@ struct instrument struct synth *synth; };
-static void instrument_addref(struct instrument *instrument) -{ - InterlockedIncrement(&instrument->ref); -} - -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 @@ -429,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) @@ -741,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; @@ -768,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; }
@@ -791,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; }
@@ -935,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 | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index e23fff4bdb1..1d2661cf8a9 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1785,6 +1785,12 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui else if (instrument->patch == ((preset->bank << 8) | preset->patch)) break; }
+ if (&instrument->entry == &synth->instruments && preset->bank == 128) + { + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) + if (instrument->patch == 0x80000000) break; + } + if (&instrument->entry == &synth->instruments) { fluid_preset = NULL;
From: Anton Baskanov baskanov@gmail.com
Fixes hanging notes that occur when noteon gets reordered with noteoff. --- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 1d2661cf8a9..c3bc8a4362a 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -977,7 +977,7 @@ static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface,
EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) - if (next_event->position >= event->position) break; + if (next_event->position > event->position) break; list_add_before(&next_event->entry, &event->entry); LeaveCriticalSection(&This->cs); }
From: Anton Baskanov baskanov@gmail.com
Different time values can map to the same position. --- dlls/dmsynth/synth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c3bc8a4362a..3f1760fcb90 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -322,6 +322,7 @@ struct preset struct event { struct list entry; + REFERENCE_TIME time; LONGLONG position; BYTE midi[3]; }; @@ -973,11 +974,12 @@ static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, { if (!(event = calloc(1, sizeof(*event)))) return E_OUTOFMEMORY; memcpy(event->midi, data, head->cbEvent); + event->time = time + head->rtDelta; event->position = position;
EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) - if (next_event->position > event->position) break; + if (next_event->time > event->time) break; list_add_before(&next_event->entry, &event->entry); LeaveCriticalSection(&This->cs); }
From: Anton Baskanov baskanov@gmail.com
Fixes missing lower notes of some instruments (e.g. Acoustic Grand Piano). --- dlls/dmsynth/synth.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 3f1760fcb90..e03235563e3 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1499,6 +1499,11 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION
/* SF2 / FluidSynth use 0.1% as "Sustain Level" unit, DLS2 uses percent, meaning is also reversed */ if (gen == GEN_MODENVSUSTAIN || gen == GEN_VOLENVSUSTAIN) value = 1000 - conn->lScale * 10 / 65536.; + /* SF2 / FluidSynth use timecents per key number unit, DLS2 uses timecents + * per 128 key number units, value is also inverted. */ + else if (gen == GEN_KEYTOMODENVHOLD || gen == GEN_KEYTOMODENVDECAY + || gen == GEN_KEYTOVOLENVHOLD || gen == GEN_KEYTOVOLENVDECAY) + value = -conn->lScale / 128. / 65536.; /* FIXME: SF2 and FluidSynth use 1200 * log2(f / 8.176) for absolute freqs, * whereas DLS2 uses (1200 * log2(f / 440.) + 6900) * 65536. The values * are very close but not strictly identical and we may need a conversion. @@ -1587,6 +1592,11 @@ static void add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION
/* SF2 / FluidSynth use 0.1% as "Sustain Level" unit, DLS2 uses percent, meaning is also reversed */ if (gen == GEN_MODENVSUSTAIN || gen == GEN_VOLENVSUSTAIN) value = 1000 - conn->lScale * 10 / 65536.; + /* SF2 / FluidSynth use timecents per key number unit, DLS2 uses timecents + * per 128 key number units, value is also inverted. */ + else if (gen == GEN_KEYTOMODENVHOLD || gen == GEN_KEYTOMODENVDECAY + || gen == GEN_KEYTOVOLENVHOLD || gen == GEN_KEYTOVOLENVDECAY) + value = -conn->lScale / 128. / 65536.; /* FIXME: SF2 and FluidSynth use 1200 * log2(f / 8.176) for absolute freqs, * whereas DLS2 uses (1200 * log2(f / 440.) + 6900) * 65536. The values * are very close but not strictly identical and we may need a conversion.
From: Anton Baskanov baskanov@gmail.com
Fixes decay time of some instruments (e.g. Acoustic Grand Piano). --- dlls/dmsynth/synth.c | 115 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 11 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index e03235563e3..c926683100e 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -334,6 +334,17 @@ struct voice struct wave *wave; };
+struct fixup +{ + struct list entry; + int dst; + int src; + int flags; + + int fixup_dst; + float amount; +}; + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -1411,6 +1422,30 @@ static int synth_preset_get_num(fluid_preset_t *fluid_preset) return preset->patch; }
+static void add_fixup(struct list *fixups, int dst, int src, int flags, int fixup_dst, float amount) +{ + struct fixup *fixup; + + LIST_FOR_EACH_ENTRY(fixup, fixups, struct fixup, entry) + { + if (fixup->dst == dst && fixup->src == src && fixup->flags == flags) + break; + } + + if (&fixup->entry == fixups) + { + if (!(fixup = calloc(1, sizeof(struct fixup)))) + return; + fixup->dst = dst; + fixup->src = src; + fixup->flags = flags; + list_add_tail(fixups, &fixup->entry); + } + + fixup->fixup_dst = fixup_dst; + fixup->amount = amount; +} + static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) { switch (conn->usDestination) @@ -1442,7 +1477,8 @@ static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) } }
-static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION *conn) +static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, struct list *fixups, + const CONNECTION *conn) { double value; UINT gen; @@ -1512,6 +1548,23 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION else value = conn->lScale / 65536.; fluid_voice_gen_set(fluid_voice, gen, value);
+ /* SF2 / FluidSynth use key 60 as zero, DSL2 uses key 0. */ + switch (gen) + { + case GEN_KEYTOMODENVHOLD: + add_fixup(fixups, gen, FLUID_MOD_NONE, 0, GEN_MODENVHOLD, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOMODENVDECAY: + add_fixup(fixups, gen, FLUID_MOD_NONE, 0, GEN_MODENVDECAY, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOVOLENVHOLD: + add_fixup(fixups, gen, FLUID_MOD_NONE, 0, GEN_VOLENVHOLD, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOVOLENVDECAY: + add_fixup(fixups, gen, FLUID_MOD_NONE, 0, GEN_VOLENVDECAY, conn->lScale * 60. / 128. / 65536.); + break; + } + return TRUE; }
@@ -1549,7 +1602,8 @@ static BOOL mod_from_connection(USHORT source, USHORT transform, UINT *fluid_sou return TRUE; }
-static void add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION *conn) +static void add_mod_from_connection(fluid_voice_t *fluid_voice, struct list *fixups, + const CONNECTION *conn) { UINT src1 = FLUID_MOD_NONE, flags1 = 0, src2 = FLUID_MOD_NONE, flags2 = 0; fluid_mod_t *mod; @@ -1607,10 +1661,27 @@ static void add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION
fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_OVERWRITE); delete_fluid_mod(mod); + + /* SF2 / FluidSynth use key 60 as zero, DSL2 uses key 0. */ + switch (gen) + { + case GEN_KEYTOMODENVHOLD: + add_fixup(fixups, gen, src1, flags1, GEN_MODENVHOLD, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOMODENVDECAY: + add_fixup(fixups, gen, src1, flags1, GEN_MODENVDECAY, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOVOLENVHOLD: + add_fixup(fixups, gen, src1, flags1, GEN_VOLENVHOLD, conn->lScale * 60. / 128. / 65536.); + break; + case GEN_KEYTOVOLENVDECAY: + add_fixup(fixups, gen, src1, flags1, GEN_VOLENVDECAY, conn->lScale * 60. / 128. / 65536.); + break; + } }
-static void add_voice_connections(fluid_voice_t *fluid_voice, const CONNECTIONLIST *list, - const CONNECTION *connections) +static void add_voice_connections(fluid_voice_t *fluid_voice, struct list *fixups, + const CONNECTIONLIST *list, const CONNECTION *connections) { UINT i;
@@ -1618,13 +1689,13 @@ static void add_voice_connections(fluid_voice_t *fluid_voice, const CONNECTIONLI { const CONNECTION *conn = connections + i;
- if (set_gen_from_connection(fluid_voice, conn)) continue; + if (set_gen_from_connection(fluid_voice, fixups, conn)) continue;
- add_mod_from_connection(fluid_voice, conn); + add_mod_from_connection(fluid_voice, fixups, conn); } }
-static void set_default_voice_connections(fluid_voice_t *fluid_voice) +static void set_default_voice_connections(fluid_voice_t *fluid_voice, struct list *fixups) { const CONNECTION connections[] = { @@ -1776,7 +1847,7 @@ static void set_default_voice_connections(fluid_voice_t *fluid_voice) fluid_voice_gen_set(fluid_voice, GEN_VELOCITY, -1.); fluid_voice_gen_set(fluid_voice, GEN_SCALETUNE, 100.0);
- add_voice_connections(fluid_voice, &list, connections); + add_voice_connections(fluid_voice, fixups, &list, connections); }
static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) @@ -1813,9 +1884,12 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui
LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) { + struct list fixups = LIST_INIT(fixups); struct articulation *articulation; struct wave *wave = region->wave; struct voice *voice; + struct fixup *fixup; + void *next;
if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; @@ -1850,7 +1924,7 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui voice->wave = wave; wave_addref(voice->wave);
- set_default_voice_connections(fluid_voice); + set_default_voice_connections(fluid_voice, &fixups); if (region->wave_sample.cSampleLoops) { WLOOP *loop = region->wave_loops; @@ -1871,9 +1945,28 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui 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); + add_voice_connections(fluid_voice, &fixups, &articulation->list, articulation->connections); LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) - add_voice_connections(fluid_voice, &articulation->list, articulation->connections); + add_voice_connections(fluid_voice, &fixups, &articulation->list, articulation->connections); + LIST_FOR_EACH_ENTRY_SAFE(fixup, next, &fixups, struct fixup, entry) + { + fluid_mod_t *mod; + if (!fixup->flags && fixup->src == FLUID_MOD_NONE) + { + fluid_voice_gen_incr(fluid_voice, fixup->fixup_dst, fixup->amount); + } + else if ((mod = new_fluid_mod())) + { + fluid_mod_set_source1(mod, fixup->src, fixup->flags); + fluid_mod_set_source2(mod, FLUID_MOD_NONE, 0); + fluid_mod_set_dest(mod, fixup->fixup_dst); + fluid_mod_set_amount(mod, fixup->amount); + fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_ADD); + delete_fluid_mod(mod); + } + list_remove(&fixup->entry); + free(fixup); + } fluid_synth_start_voice(synth->fluid_synth, fluid_voice); LeaveCriticalSection(&synth->cs); return FLUID_OK;