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;