Skip to content

Commit

Permalink
[#4] fix: improve handling of drum kit instruments
Browse files Browse the repository at this point in the history
This patch fixes an issue where Gothic 2 requires drum kits to function correctly but Gothic 1 behaves incorrectly when a drum kit is allowed to be chosen.

In particular, Gothic 1 assigns the same performance channel (channel 7) to both a melodic and a drum instrument. The drum instrument in this case is a metronome ("Metronom") which is irrelevant for music playback. Previously, if instruments with the drum kit flag considered), we would always choose the drum kit instead of the melodic instrument for that channel, which is definitely incorrect.

It turns out, however, that ignoring drum kits is not the correct behaviour, since Gothic 2 requires them to be chosen (e.g. for `MO_DayStd.sgt`).

To get around this conundrum, we now simply act as if instruments with the same performance channel override each other, so that the last instrument in the sequence wins. This way, both soundtracks choose the right instruments, even if they are drum kits.
  • Loading branch information
lmichaelis committed Sep 22, 2024
1 parent 1c37f63 commit 7b44736
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 13 deletions.
14 changes: 7 additions & 7 deletions src/Band.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ DmDlsInstrument* DmInstrument_getDlsInstrument(DmInstrument* slf) {
uint32_t patch = slf->patch & 0xFFU;

DmDlsInstrument* ins = NULL;
for (size_t i = 0; i < slf->dls->instrument_count; ++i) {
for (long long i = slf->dls->instrument_count; i >= 0; --i) {
ins = &slf->dls->instruments[i];

// TODO(lmichaelis): We need to ignore drum kits for now since I don't know how to handle them properly
if (ins->bank & DmDls_DRUM_KIT) {
continue;
}

// If it's the correct instrument, return it.
if (ins->bank == bank && ins->patch == patch) {
// TODO(lmichaelis): Dirty fix for drum kit problems. Instead of choosing the first valid DLS instrument, we
// chose the last valid one. This acts as if later instruments override previous ones and
// thus prevents problems where the same channel is re-used multiple times, specifically in
// Gothic 1, which assigns a drum kit and melodic instrument to the same channel. This works
// in conjunction with the TSF creation in Dm_createHydra to prevent drum kit issues in G1.
if ((ins->bank & 127) == bank && ins->patch == patch) {
return ins;
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/util/Tsf.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,14 @@ static DmResult Dm_createHydra(DmDls* dls, struct tsf_hydra* hydra, float** pcm,
uint32_t imod_ndx = 0;
uint32_t shdr_ndx = 0;
for (size_t i = 0; i < dls->instrument_count; ++i) {
DmDlsInstrument* ins = &dls->instruments[i];
// TODO(lmichaelis): Dirty fix for drum kit problems. We add the instruments in reverse, so that TSF always
// behaves as-if instruments later in the sequence override previous instruments. This allows
// Gothic 2 to use drum kits as intended and prevents Gothic 1 from playing from the
// Metronom.dls file when it shouldn't. This works in conjunction with the channel selection
// from DmInstrument_getDlsInstrument.
DmDlsInstrument* ins = &dls->instruments[dls->instrument_count - 1 - i];
uint32_t bank = ins->bank;

// Ignore drum kits for now.
if (ins->bank & DmDls_DRUM_KIT) {
bank = 999;
}

strncpy(hydra->phdrs[i].presetName, ins->info.inam, 19);
hydra->phdrs[i].bank = bank;
hydra->phdrs[i].preset = ins->patch;
Expand Down

0 comments on commit 7b44736

Please sign in to comment.