dmxgus: Change instrument order to work around DMX.

The DMX sound library used by Vanilla Doom has a bug where instruments
referencing other instruments as stand-ins can only reference
instruments listed earlier in the file. Actually, the instrument
references are just arbitrary cross-reference tags and the first
instrument to use that tag is used for all instruments with that tag.
This behavior can have some strange effects; more information can be
found on David Flater's page: <http://www.flaterco.com/kb/DOOM/DMXGUS/>

This has consequences for Freedoom's GENMIDI generation, particularly
as Chocolate Doom now emulates this behavior. To avoid assigning the
wrong instrument mappings, change the ordering of instruments in the
output file, so that "leader" instruments always appear earlier in the
file than instruments that reference them.
This commit is contained in:
Simon Howard 2016-07-12 21:35:36 -04:00
parent f069cc2ee3
commit 6198796e95

View file

@ -43,6 +43,14 @@ import sys
import config
import stats
HEADER_TEXT = """
# Freedoom GUS config.
# Autogenerated by the gen-ultramid script.
# Please do not manually edit this file!
# The ordering of entries in this file is significant, to work around a
# bug in Doom's DMX sound library.
"""
def normalize_stats(stats):
"""Normalize the gathered instrument statistics.
@ -154,6 +162,39 @@ def mapping_for_size(size):
return result
def instrument_patches(mappings):
"""Returns list of MIDI instruments in an appropriate order for output.
The ordering in the output file is important, because of a bug in the
DMX sound library; when patches are shared between instruments it is
only possible to refer to instruments listed earlier in the file.
Args:
mappings: List of mappings from instrument ID to leader instrument.
Yields:
A tuple containing each MIDI instrument number and patch file name
to load.
"""
done_instr_ids = set()
# Make multiple passes until we've done all the instruments.
while len(done_instr_ids) < len(config.GUS_INSTR_PATCHES):
made_progress = False
for instr_id, name in sorted(config.GUS_INSTR_PATCHES.items()):
for mapping in mappings:
mapped_instr_id = mapping[instr_id]
if (instr_id != mapped_instr_id and
mapped_instr_id not in done_instr_ids):
break
else:
if instr_id not in done_instr_ids:
yield instr_id, name
done_instr_ids.add(instr_id)
made_progress = True
assert made_progress, (
"infinite loop while producing patches list")
if len(sys.argv) != 2:
print("Usage: %s <filename>" % sys.argv[0])
sys.exit(1)
@ -166,11 +207,9 @@ mappings = (
)
with open(sys.argv[1], "w") as output:
output.write("# Freedoom GUS config.\n"
"# Autogenerated by the gen-ultramid script.\n"
"# Please do not manually edit this file!\n")
output.write(HEADER_TEXT.lstrip())
for instr_id, name in sorted(config.GUS_INSTR_PATCHES.items()):
for instr_id, name in instrument_patches(mappings):
line = "%i, %i, %i, %i, %i, %s" % (
instr_id,
mappings[0][instr_id],