From 64198d7af191067e69662eb5a863b9e032728355 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 2 Mar 2013 21:44:09 +0000 Subject: [PATCH] lumps: Autogenerate optimized DMXGUS lump. Replace the current poor-quality handcrafted GUS configuration with a script that programatically generates an optimized configuration file based on statistical analysis of music from various popular WAD files. --- lumps/Makefile | 6 +- lumps/dmxgus/README | 36 ++++ lumps/dmxgus/check.py | 170 ----------------- lumps/dmxgus/config.py | 358 +++++++++++++++++++++++++++++++++++ lumps/dmxgus/gather_stats.py | 83 ++++++++ lumps/dmxgus/gen-ultramid | 174 +++++++++++++++++ lumps/dmxgus/stats.py | 26 +++ lumps/dmxgus/ultramid.ini | 239 ----------------------- 8 files changed, 682 insertions(+), 410 deletions(-) create mode 100644 lumps/dmxgus/README delete mode 100755 lumps/dmxgus/check.py create mode 100644 lumps/dmxgus/config.py create mode 100644 lumps/dmxgus/gather_stats.py create mode 100755 lumps/dmxgus/gen-ultramid create mode 100644 lumps/dmxgus/stats.py delete mode 100644 lumps/dmxgus/ultramid.ini diff --git a/lumps/Makefile b/lumps/Makefile index ffbee737..6dbcfa90 100644 --- a/lumps/Makefile +++ b/lumps/Makefile @@ -1,5 +1,5 @@ -all : freedoom.lmp freedm.lmp misc-lumps genmidi-lump +all : freedoom.lmp freedm.lmp misc-lumps genmidi-lump dmxgus.lmp misc-lumps: make -C cph/misc-lumps @@ -7,6 +7,9 @@ misc-lumps: genmidi-lump: make -C genmidi +dmxgus.lmp: + make -C dmxgus + freedoom.lmp: force echo $(VERSION) > freedoom.lmp @@ -18,4 +21,5 @@ force: clean: make -C cph/misc-lumps clean make -C genmidi clean + make -C dmxgus clean diff --git a/lumps/dmxgus/README b/lumps/dmxgus/README new file mode 100644 index 00000000..1986b2f3 --- /dev/null +++ b/lumps/dmxgus/README @@ -0,0 +1,36 @@ +The script in this directory generates the GUS config file +(ultramid.ini) which is included in the IWAD as a lump named DMXGUS or +DMXGUSC. + +The GUS config is mostly obsolete nowadays but it's still nice to +include anyway. The challenge is that each GUS card has a limited +amount of memory (256, 512, 768 or 1024KB). The GUS drivers come with +a complete set of patch files for all the General MIDI instruments, +but there is never enough RAM to fit all of them into the card's +memory. Patches must therefore be reused for multiple similar-sounding +instruments. + +The config file looks like this (short extract): + + 31, 24, 31, 31, 31, gtrharm + 32, 39, 32, 32, 32, acbass + 33, 39, 33, 33, 33, fngrbass + 34, 39, 34, 34, 34, pickbass + +The second to fifth columns are the configurations for different +memory sizes. In this example, instrument 31 reuses instrument 24's +patch for the 256KB configuration, but in the 512KB configuration +there is enough space to load it properly. + +The DMXGUS lumps used in the original Doom IWADs did not have a great +deal of attention paid to them, which lead some people to develop +optimized config files (see eg. GUS1M.WAD in idgames). The approach +taken here is to generate the configuration programatically: +statistics have been gathered about the use of different instruments +by analyzing the music found in various well-known WAD files. This is +used to prioritize which patches to load. + +The generated config is still not great and could do with some +improvement. To improve the config, the best thing to tweak is the +similarity groups in config.py. + diff --git a/lumps/dmxgus/check.py b/lumps/dmxgus/check.py deleted file mode 100755 index a395cabb..00000000 --- a/lumps/dmxgus/check.py +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 -# Contributors to the Freedoom project. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the freedoom project nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# -# Sanity check script for DMXGUS lump. -# Please run this script after making any changes to ultramid.ini. -# - -import sys -import re - -# These are the sizes (in bytes) of the patch files distributed -# with the GUS drivers. Having these means we can calculate the -# size in RAM (roughly) of the patch set for a given configuration -# and check it is within the limit. - -GUS_PATCH_SIZES = { - "acbass": 10829, "accordn": 19623, "acguitar": 52581, - "acpiano": 65259, "agogo": 27727, "agogohi": 7283, - "agogolo": 7283, "altosax": 11711, "applause": 60449, - "atmosphr": 63035, "aurora": 62503, "bagpipes": 16057, - "banjo": 64523, "barisax": 21739, "basslead": 53389, - "bassoon": 16723, "belltree": 64103, "blank": 3367, - "bongohi": 7233, "bongolo": 9201, "bottle": 25063, - "bowglass": 49691, "britepno": 72739, "cabasa": 17203, - "calliope": 46303, "carillon": 12089, "castinet": 12349, - "celeste": 20207, "cello": 18741, "charang": 90661, - "chiflead": 63381, "choir": 45353, "church": 4609, - "claps": 11719, "clarinet": 19161, "clave": 5035, - "clavinet": 3443, "cleangtr": 46027, "concrtna": 17981, - "congahi1": 8753, "congahi2": 9713, "congalo": 9713, - "contraba": 9723, "cowbell": 6645, "crystal": 60783, - "cuica1": 18995, "cuica2": 26017, "cymbell": 34815, - "cymchina": 48545, "cymcrsh1": 63353, "cymcrsh2": 62411, - "cymride1": 35655, "cymride2": 35655, "cymsplsh": 63353, - "distgtr": 38249, "doo": 17333, "echovox": 30287, - "englhorn": 24675, "epiano1": 15005, "epiano2": 44191, - "fantasia": 47229, "fiddle": 12309, "flute": 12383, - "fngrbass": 19797, "frenchrn": 28635, "freshair": 58307, - "fretless": 5605, "fx-blow": 57693, "fx-fret": 27631, - "ghostie": 63301, "glocken": 10695, "gtrharm": 10173, - "guiro1": 8561, "guiro2": 18821, "halopad": 60291, - "harmonca": 15301, "harp": 23927, "helicptr": 50327, - "highq": 3945, "hihatcl": 9453, "hihatop": 40417, - "hihatpd": 3925, "hitbrass": 63369, "homeorg": 2301, - "honky": 131905, "hrpschrd": 7709, "jazzgtr": 55923, - "jingles": 34219, "jungle": 27541, "kalimba": 4739, - "kick1": 9411, "kick2": 10377, "koto": 42079, - "lead5th": 13233, "maracas": 9433, "marcato": 122881, - "marimba": 4447, "metalpad": 60905, "metbell": 539, - "metclick": 539, "musicbox": 30947, "mutegtr": 34577, - "mutetrum": 19019, "nyguitar": 39211, "oboe": 9269, - "ocarina": 3537, "odguitar": 25845, "orchhit": 28751, - "percorg": 15435, "piccolo": 8945, "pickbass": 33213, - "pistol": 36595, "pizzcato": 40173, "polysyn": 60759, - "recorder": 5647, "reedorg": 3471, "revcym": 27391, - "rockorg": 60887, "santur": 43833, "sawwave": 54485, - "scratch1": 9091, "scratch2": 4883, "seashore": 62407, - "shakazul": 62589, "shaker": 6527, "shamisen": 26667, - "shannai": 20151, "sitar": 36979, "slap": 12031, - "slapbas1": 56133, "slapbas2": 41581, "slowstr": 36717, - "snare1": 17417, "snare2": 8503, "soundtrk": 40091, - "sprnosax": 14713, "sqrclick": 539, "sqrwave": 30439, - "startrak": 55085, "steeldrm": 24229, "stickrim": 6005, - "sticks": 8757, "surdo1": 19527, "surdo2": 19527, - "sweeper": 62745, "synbass1": 12627, "synbass2": 6191, - "synbras1": 61735, "synbras2": 60641, "synpiano": 11543, - "synstr1": 62763, "synstr2": 33165, "syntom": 61331, - "taiko": 37671, "tamborin": 18219, "telephon": 9157, - "tenorsax": 17367, "timbaleh": 10839, "timbalel": 19787, - "timpani": 14473, "tomhi1": 13467, "tomhi2": 13455, - "tomlo1": 13455, "tomlo2": 19527, "tommid1": 13455, - "tommid2": 13455, "toms": 13467, "tremstr": 122881, - "triangl1": 4781, "triangl2": 31901, "trombone": 26187, - "trumpet": 13621, "tuba": 11847, "tubebell": 18637, - "unicorn": 60505, "vibes": 21597, "vibslap": 19247, - "viola": 56465, "violin": 25061, "voices": 30287, - "voxlead": 30289, "warmpad": 36491, "whistle": 12053, - "whistle1": 4315, "whistle2": 2173, "woodblk": 7685, - "woodblk1": 5035, "woodblk2": 7685, "woodflut": 4191, - "xylophon": 19085 -} - -def patches_for_mapping(patches, mapping): - result = {} - - for pnum in mapping.values(): - patch = patches[pnum] - result[patch] = True - - return sorted(result.keys()) - -def patch_set_size(patch_set): - result = 0 - - for patch in patch_set: - result += GUS_PATCH_SIZES[patch] - - return result - -def print_patch_set(title, patch_set): - print "%s:" % title - - for patch in patch_set: - print "\t%-8s %i" % (patch, GUS_PATCH_SIZES[patch]) - - print "\t" + ("-" * 30) - print "\t%-8s %i" % ("TOTAL", patch_set_size(patch_set)) - -patches = {} -mappings = [ {}, {}, {}, {} ] - -f = open("ultramid.ini") - -for line in f: - line = line.strip() - if line.startswith("#"): - continue - - fields = re.split(r"\s*,\s*", line) - - instr = int(fields[0]) - patches[instr] = fields[5] - - for i in range(4): - mappings[i][instr] = int(fields[i + 1]) - -f.close() - -# Check mappings: - -MAPPING_SIZES = [ 256, 512, 768, 1024 ] - -for i in range(4): - patch_set = patches_for_mapping(patches, mappings[i]) - - if patch_set_size(patch_set) > MAPPING_SIZES[i] * 1024: - print >> sys.stderr, \ - "ERROR: Configuration for %iKB exceeds %iKB" % \ - (MAPPING_SIZES[i], MAPPING_SIZES[i]) - print_patch_set(MAPPING_SIZES[i], patch_set) - sys.exit(-1) - diff --git a/lumps/dmxgus/config.py b/lumps/dmxgus/config.py new file mode 100644 index 00000000..0453d78d --- /dev/null +++ b/lumps/dmxgus/config.py @@ -0,0 +1,358 @@ +# +# Copyright (c) 2013 Contributors to the Freedoom project. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the freedoom project nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# -------------------------------------------------------------- +# +# Config file for GUS config generator. +# + +# Names of GUS instrument files to use for playing MIDI. +# These are the names of the .pat files in the \ultrasnd\midi directory +# that are loaded into the card. + +GUS_INSTR_PATCHES = { + 0: "acpiano", # #001 - Acoustic Grand Piano + 1: "britepno", # #002 - Bright Acoustic Piano + 2: "synpiano", # #003 - Electric Grand Piano + 3: "honky", # #004 - Honky-tonk Piano + 4: "epiano1", # #005 - Electric Piano 1 + 5: "epiano2", # #006 - Electric Piano 2 + 6: "hrpschrd", # #007 - Harpsichord + 7: "clavinet", # #008 - Clavi + 8: "celeste", # #009 - Celesta + 9: "glocken", # #010 - Glockenspiel + 10: "musicbox", # #011 - Music Box + 11: "vibes", # #012 - Vibraphone + 12: "marimba", # #013 - Marimba + 13: "xylophon", # #014 - Xylophone + 14: "tubebell", # #015 - Tubular Bells + 15: "santur", # #016 - Dulcimer + 16: "homeorg", # #017 - Drawbar Organ + 17: "percorg", # #018 - Percussive Organ + 18: "rockorg", # #019 - Rock Organ + 19: "church", # #020 - Church Organ + 20: "reedorg", # #021 - Reed Organ + 21: "accordn", # #022 - Accordion + 22: "harmonca", # #023 - Harmonica + 23: "concrtna", # #024 - Tango Accordion + 24: "nyguitar", # #025 - Acoustic Guitar (nylon) + 25: "acguitar", # #026 - Acoustic Guitar (steel) + 26: "jazzgtr", # #027 - Electric Guitar (jazz) + 27: "cleangtr", # #028 - Electric Guitar (clean) + 28: "mutegtr", # #029 - Electric Guitar (muted) + 29: "odguitar", # #030 - Overdriven Guitar + 30: "distgtr", # #031 - Distortion Guitar + 31: "gtrharm", # #032 - Guitar harmonics + 32: "acbass", # #033 - Acoustic Bass + 33: "fngrbass", # #034 - Electric Bass (finger) + 34: "pickbass", # #035 - Electric Bass (pick) + 35: "fretless", # #036 - Fretless Bass + 36: "slapbas1", # #037 - Slap Bass 1 + 37: "slapbas2", # #038 - Slap Bass 2 + 38: "synbass1", # #039 - Synth Bass 1 + 39: "synbass2", # #040 - Synth Bass 2 + 40: "violin", # #041 - Violin + 41: "viola", # #042 - Viola + 42: "cello", # #043 - Cello + 43: "contraba", # #044 - Contrabass + 44: "tremstr", # #045 - Tremolo Strings + 45: "pizzcato", # #046 - Pizzicato Strings + 46: "harp", # #047 - Orchestral Harp + 47: "timpani", # #048 - Timpani + 48: "marcato", # #049 - String Ensemble 1 + 49: "slowstr", # #050 - String Ensemble 2 + 50: "synstr1", # #051 - SynthStrings 1 + 51: "synstr2", # #052 - SynthStrings 2 + 52: "choir", # #053 - Choir Aahs + 53: "doo", # #054 - Voice Oohs + 54: "voices", # #055 - Synth Voice + 55: "orchhit", # #056 - Orchestra Hit + 56: "trumpet", # #057 - Trumpet + 57: "trombone", # #058 - Trombone + 58: "tuba", # #059 - Tuba + 59: "mutetrum", # #060 - Muted Trumpet + 60: "frenchrn", # #061 - French Horn + 61: "hitbrass", # #062 - Brass Section + 62: "synbras1", # #063 - SynthBrass 1 + 63: "synbras2", # #064 - SynthBrass 2 + 64: "sprnosax", # #065 - Soprano Sax + 65: "altosax", # #066 - Alto Sax + 66: "tenorsax", # #067 - Tenor Sax + 67: "barisax", # #068 - Baritone Sax + 68: "oboe", # #069 - Oboe + 69: "englhorn", # #070 - English Horn + 70: "bassoon", # #071 - Bassoon + 71: "clarinet", # #072 - Clarinet + 72: "piccolo", # #073 - Piccolo + 73: "flute", # #074 - Flute + 74: "recorder", # #075 - Recorder + 75: "woodflut", # #076 - Pan Flute + 76: "bottle", # #077 - Blown Bottle + 77: "shakazul", # #078 - Shakuhachi + 78: "whistle", # #079 - Whistle + 79: "ocarina", # #080 - Ocarina + 80: "sqrwave", # #081 - Lead 1 (square) + 81: "sawwave", # #082 - Lead 2 (sawtooth) + 82: "calliope", # #083 - Lead 3 (calliope) + 83: "chiflead", # #084 - Lead 4 (chiff) + 84: "charang", # #085 - Lead 5 (charang) + 85: "voxlead", # #086 - Lead 6 (voice) + 86: "lead5th", # #087 - Lead 7 (fifths) + 87: "basslead", # #088 - Lead 8 (bass + lead) + 88: "fantasia", # #089 - Pad 1 (new age) + 89: "warmpad", # #090 - Pad 2 (warm) + 90: "polysyn", # #091 - Pad 3 (polysynth) + 91: "ghostie", # #092 - Pad 4 (choir) + 92: "bowglass", # #093 - Pad 5 (bowed) + 93: "metalpad", # #094 - Pad 6 (metallic) + 94: "halopad", # #095 - Pad 7 (halo) + 95: "sweeper", # #096 - Pad 8 (sweep) + 96: "aurora", # #097 - FX 1 (rain) + 97: "soundtrk", # #098 - FX 2 (soundtrack) + 98: "crystal", # #099 - FX 3 (crystal) + 99: "atmosphr", # #100 - FX 4 (atmosphere) + 100: "freshair", # #101 - FX 5 (brightness) + 101: "unicorn", # #102 - FX 6 (goblins) + 102: "echovox", # #103 - FX 7 (echoes) + 103: "startrak", # #104 - FX 8 (sci-fi) + 104: "sitar", # #105 - Sitar + 105: "banjo", # #106 - Banjo + 106: "shamisen", # #107 - Shamisen + 107: "koto", # #108 - Koto + 108: "kalimba", # #109 - Kalimba + 109: "bagpipes", # #110 - Bag pipe + 110: "fiddle", # #111 - Fiddle + 111: "shannai", # #112 - Shanai + 112: "carillon", # #113 - Tinkle Bell + 113: "agogo", # #114 - Agogo + 114: "steeldrm", # #115 - Steel Drums + 115: "woodblk", # #116 - Woodblock + 116: "taiko", # #117 - Taiko Drum + 117: "toms", # #118 - Melodic Tom + 118: "syntom", # #119 - Synth Drum + 119: "revcym", # #120 - Reverse Cymbal + 120: "fx-fret", # #121 - Guitar Fret Noise + 121: "fx-blow", # #122 - Breath Noise + 122: "seashore", # #123 - Seashore + 123: "jungle", # #124 - Bird Tweet + 124: "telephon", # #125 - Telephone Ring + 125: "helicptr", # #126 - Helicopter + 126: "applause", # #127 - Applause + 127: "pistol", # #128 - Gunshot + 128: "blank", + 162: "kick1", # #35 Acoustic Bass Drum + 163: "kick2", # #36 Bass Drum 1 + 164: "stickrim", # #37 Side Stick + 165: "snare1", # #38 Acoustic Snare + 166: "claps", # #39 Hand Clap + 167: "snare2", # #40 Electric Snare + 168: "tomlo2", # #41 Low Floor Tom + 169: "hihatcl", # #42 Closed Hi Hat + 170: "tomlo1", # #43 High Floor Tom + 171: "hihatpd", # #44 Pedal Hi-Hat + 172: "tommid2", # #45 Low Tom + 173: "hihatop", # #46 Open Hi-Hat + 174: "tommid1", # #47 Low-Mid Tom + 175: "tomhi2", # #48 Hi-Mid Tom + 176: "cymcrsh1", # #49 Crash Cymbal 1 + 177: "tomhi1", # #50 High Tom + 178: "cymride1", # #51 Ride Cymbal 1 + 179: "cymchina", # #52 Chinese Cymbal + 180: "cymbell", # #53 Ride Bell + 181: "tamborin", # #54 Tambourine + 182: "cymsplsh", # #55 Splash Cymbal + 183: "cowbell", # #56 Cowbell + 184: "cymcrsh2", # #57 Crash Cymbal 2 + 185: "vibslap", # #58 Vibraslap + 186: "cymride2", # #59 Ride Cymbal 2 + 187: "bongohi", # #60 Hi Bongo + 188: "bongolo", # #61 Low Bongo + 189: "congahi1", # #62 Mute Hi Conga + 190: "congahi2", # #63 Open Hi Conga + 191: "congalo", # #64 Low Conga + 192: "timbaleh", # #65 High Timbale + 193: "timbalel", # #66 Low Timbale + 194: "agogohi", # #67 High Agogo + 195: "agogolo", # #68 Low Agogo + 196: "cabasa", # #69 Cabasa + 197: "maracas", # #70 Maracas + 198: "whistle1", # #71 Short Whistle + 199: "whistle2", # #72 Long Whistle + 200: "guiro1", # #73 Short Guiro + 201: "guiro2", # #74 Long Guiro + 202: "clave", # #75 Claves + 203: "woodblk1", # #76 Hi Wood Block + 204: "woodblk2", # #77 Low Wood Block + 205: "cuica1", # #78 Mute Cuica + 206: "cuica2", # #79 Open Cuica + 207: "triangl1", # #80 Mute Triangle + 208: "triangl2", # #81 Open Triangle +} + +# These are the data sizes of the patch files distributed with the +# GUS drivers. These are used to calculate the size in RAM of the +# generated patch sets to check that they are within the limits. +# and check it is within the limit. + +PATCH_FILE_SIZES = { + "acbass": 5248, "accordn": 9616, "acguitar": 26080, + "acpiano": 32256, "agogo": 13696, "agogohi": 3488, + "agogolo": 3488, "altosax": 5616, "applause": 30064, + "atmosphr": 31360, "aurora": 31088, "bagpipes": 7760, + "banjo": 32016, "barisax": 10544, "basslead": 26496, + "bassoon": 8000, "belltree": 31888, "blank": 1520, + "bongohi": 3456, "bongolo": 4448, "bottle": 12368, + "bowglass": 24688, "britepno": 36000, "cabasa": 8448, + "calliope": 22992, "carillon": 5888, "castinet": 6016, + "celeste": 9936, "cello": 9120, "charang": 45056, + "chiflead": 31536, "choir": 22480, "church": 2144, + "claps": 5696, "clarinet": 9184, "clave": 2352, + "clavinet": 1440, "cleangtr": 22768, "concrtna": 8784, + "congahi1": 4224, "congahi2": 4704, "congalo": 4704, + "contraba": 4704, "cowbell": 3168, "crystal": 30224, + "cuica1": 9344, "cuica2": 12848, "cymbell": 17248, + "cymchina": 24112, "cymcrsh1": 31520, "cymcrsh2": 31040, + "cymride1": 17664, "cymride2": 17664, "cymsplsh": 31520, + "distgtr": 18848, "doo": 8464, "echovox": 14976, + "englhorn": 12096, "epiano1": 7344, "epiano2": 21936, + "fantasia": 23456, "fiddle": 5904, "flute": 6032, + "fngrbass": 9744, "frenchrn": 14128, "freshair": 28992, + "fretless": 2640, "fx-blow": 28688, "fx-fret": 13648, + "ghostie": 31488, "glocken": 5184, "gtrharm": 4928, + "guiro1": 4128, "guiro2": 9248, "halopad": 29984, + "harmonca": 7408, "harp": 11728, "helicptr": 25008, + "highq": 1808, "hihatcl": 4560, "hihatop": 20048, + "hihatpd": 1808, "hitbrass": 31520, "homeorg": 992, + "honky": 65680, "hrpschrd": 3584, "jazzgtr": 27712, + "jingles": 16944, "jungle": 13616, "kalimba": 2208, + "kick1": 4544, "kick2": 5024, "koto": 20832, + "lead5th": 6464, "maracas": 4560, "marcato": 61232, + "marimba": 2064, "metalpad": 30288, "metbell": 112, + "metclick": 112, "musicbox": 15312, "mutegtr": 17008, + "mutetrum": 9168, "nyguitar": 19200, "oboe": 3952, + "ocarina": 1616, "odguitar": 12640, "orchhit": 14208, + "percorg": 7520, "piccolo": 4320, "pickbass": 16416, + "pistol": 18144, "pizzcato": 19888, "polysyn": 30224, + "recorder": 2656, "reedorg": 1568, "revcym": 13536, + "rockorg": 30288, "santur": 21760, "sawwave": 27056, + "scratch1": 4384, "scratch2": 2288, "seashore": 31040, + "shakazul": 31136, "shaker": 3104, "shamisen": 13136, + "shannai": 9792, "sitar": 18288, "slap": 5856, + "slapbas1": 27872, "slapbas2": 20592, "slowstr": 18192, + "snare1": 8544, "snare2": 4096, "soundtrk": 19888, + "sprnosax": 7072, "sqrclick": 112, "sqrwave": 15056, + "startrak": 27376, "steeldrm": 11952, "stickrim": 2848, + "sticks": 4224, "surdo1": 9600, "surdo2": 9600, + "sweeper": 31216, "synbass1": 6160, "synbass2": 2928, + "synbras1": 30704, "synbras2": 30160, "synpiano": 5456, + "synstr1": 31216, "synstr2": 16416, "syntom": 30512, + "taiko": 18672, "tamborin": 8944, "telephon": 4416, + "tenorsax": 8448, "timbaleh": 5264, "timbalel": 9728, + "timpani": 7072, "tomhi1": 6576, "tomhi2": 6560, + "tomlo1": 6560, "tomlo2": 9600, "tommid1": 6560, + "tommid2": 6560, "toms": 6576, "tremstr": 61232, + "triangl1": 2224, "triangl2": 15792, "trombone": 12896, + "trumpet": 6608, "tuba": 5760, "tubebell": 9120, + "unicorn": 30096, "vibes": 10640, "vibslap": 9456, + "viola": 27952, "violin": 12160, "voices": 14976, + "voxlead": 14992, "warmpad": 18080, "whistle": 5872, + "whistle1": 2000, "whistle2": 928, "woodblk": 3680, + "woodblk1": 2352, "woodblk2": 3680, "woodflut": 1936, + "xylophon": 9376, +} + +# Groups of "similar sounding" instruments. The first instrument in each +# group is the "leader" and will be used as the fallback for other +# instruments in the group if they are not popular enough to be included. + +# These groups are based on inaccurate stereotypes about musical instruments. +# If you're looking to improve the config, here's where to start. + +SIMILAR_GROUPS = [ + # Pianos. + ('acpiano', 'britepno', 'synpiano', 'honky', 'epiano1', 'epiano2', + 'hrpschrd', 'clavinet', 'celeste', 'glocken'), + # Xylophone etc. + ('marimba', 'musicbox', 'vibes', 'xylophon', 'tubebell', 'santur', + 'kalimba'), + # Organs. + ('homeorg', 'percorg', 'rockorg', 'church', 'reedorg', 'accordn', + 'harmonca', 'concrtna'), + # Guitars. + ('nyguitar', 'acguitar', 'jazzgtr', 'cleangtr', 'mutegtr', 'odguitar', + 'distgtr', 'gtrharm'), + # Basses. + ('synbass2', 'acbass', 'fngrbass', 'pickbass', 'fretless', 'slapbas1', + 'slapbas2', 'synbass1'), + # Violin and similar string instruments. + ('violin', 'viola', 'cello', 'contraba', 'tremstr', 'pizzcato', 'harp', + 'timpani'), + # Other stringed (?) + ('marcato', 'slowstr', 'synstr1', 'synstr2', 'choir', 'doo', 'voices', + 'orchhit'), + # Trumpet and other brass. + ('trumpet', 'trombone', 'tuba', 'mutetrum', 'frenchrn', 'hitbrass', + 'synbras1', 'synbras2'), + # Reed instruments. + ('sprnosax', 'altosax', 'tenorsax', 'barisax', 'oboe', 'englhorn', + 'bassoon', 'clarinet'), + # Pipe instruments. + ('flute', 'piccolo', 'recorder', 'woodflut', 'bottle', 'shakazul', + 'whistle', 'ocarina', 'bagpipes', 'fiddle', 'shannai'), + # Leads. + ('sqrwave', 'sawwave', 'calliope', 'chiflead', 'charang', 'voxlead', + 'lead5th', 'basslead', 'sitar', 'banjo', 'shamisen', 'koto'), + # Special effects. Blank unless popular enough to appear. + ('blank','fantasia', 'warmpad', 'polysyn', 'ghostie', 'bowglass', + 'metalpad', 'halopad', 'sweeper', 'aurora', 'soundtrk', 'crystal', + 'atmosphr', 'freshair', 'unicorn', 'echovox', 'startrak', 'fx-fret', + 'fx-blow', 'seashore', 'jungle', 'telephon', 'helicptr', 'applause', + 'pistol'), + + # -- Percussion effects. This is probably where the current config is + # worst and in dire need of improvement. + + # Conga/kick + ('kick1', 'steeldrm', 'taiko', 'kick2', 'congahi1', 'congahi2', + 'congalo', 'clave'), + # Snare drums + ('snare1', 'stickrim', 'claps', 'snare2', 'tamborin', 'vibslap', + 'bongohi', 'bongolo', 'timbaleh', 'timbalel', 'maracas', 'woodblk1', + 'woodblk2'), + # Hi-hat + ('hihatpd', 'carillon', 'agogo', 'woodblk', 'hihatcl', 'hihatop', + 'cowbell', 'agogohi', 'agogolo', 'cabasa', 'whistle1', 'whistle2', + 'guiro1', 'guiro2', 'cuica1', 'cuica2', 'triangl1', 'triangl2'), + # Toms + ('tommid1', 'toms', 'syntom', 'tomlo2', 'tomlo1', 'tommid2', 'tomhi2', + 'tomhi1'), + # Cymbals. + ('cymcrsh1', 'revcym', 'cymride1', 'cymchina', 'cymbell', 'cymsplsh', + 'cymcrsh2', 'cymride2'), +] + diff --git a/lumps/dmxgus/gather_stats.py b/lumps/dmxgus/gather_stats.py new file mode 100644 index 00000000..997d1816 --- /dev/null +++ b/lumps/dmxgus/gather_stats.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# Copyright (c) 2013 Contributors to the Freedoom project. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the freedoom project nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ---------------------------------------------------------------------- +# +# Script to gather statistics from MIDI files about instrument usage. +# Generates stats.py which is used as input for the ultramid.ini +# generator script. +# +# This script requires python-midi; see here: +# https://github.com/vishnubob/python-midi +# + +import midi +import sys + +def get_instr_stats(filename): + """Get a set of instruments used by the specified MIDI file.""" + result = set() + midfile = midi.read_midifile(filename) + + for track in midfile: + for event in track: + if isinstance(event, midi.ProgramChangeEvent) \ + and event.channel != 9: + instr = event.data[0] + result.add(instr) + # Percussion: + if isinstance(event, midi.NoteOnEvent) \ + and event.channel == 9: + instr = event.data[0] + 128 + result.add(instr) + + return result + +total_stats = [0] * 217 + +for filename in sys.argv[1:]: + print "Processing %s" % filename + stats = get_instr_stats(filename) + print sorted(stats) + for instrument in stats: + total_stats[instrument] += 1 + +with open("stats.py", "w") as f: + f.write("# Instrument stats, autogenerated by gather_stats.py\n\n") + f.write("INSTRUMENT_STATS = [\n\t") + + for index, stat in enumerate(total_stats): + f.write("% 5i," % stat) + if (index % 10) == 9: + f.write("\n\t") + + f.write("\n]\n") + + diff --git a/lumps/dmxgus/gen-ultramid b/lumps/dmxgus/gen-ultramid new file mode 100755 index 00000000..eab8476b --- /dev/null +++ b/lumps/dmxgus/gen-ultramid @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# +# Copyright (c) 2013 Contributors to the Freedoom project. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the freedoom project nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ---------------------------------------------------------------------- +# +# Config file generator for the DMXGUS lump / config file. +# +# This script generates a GUS config file with instrument mappings for +# 256,512,768 and 1024KB cards. This is done automatically from the config +# in config.py. The instruments to include are selected using statistics +# processed from a collection of well-known Doom WAD files. +# + +import re +import sys + +import config +import stats + +def normalize_stats(stats): + """Normalize the gathered instrument statistics. + + Percussion instruments tend to be more widely used, which can give + them a disproportionate priority. Therefore, generate a "normalized" + set of statistics that adjust the percussion instruments to be + roughly equal to the main instruments. + """ + main_stats = stats[0:128] + perc_stats = stats[128:] + main_av = sum(main_stats) / len(main_stats) + perc_av = sum(perc_stats) / (len(perc_stats) - 35) + + def adjusted_priority(stat): + return (float(stat) * main_av) / perc_av + + adjusted_perc_stats = map(adjusted_priority, perc_stats) + + return main_stats + list(adjusted_perc_stats) + +def ranked_patches(): + """Get a list of GUS patches ranked by priority. + + This uses the gathered statistics about use of different instruments + in Doom WADs and orders them by benefit/cost ratio (where cost is + the size that the instrument file will occupy in RAM). + """ + adjusted_stats = normalize_stats(stats.INSTRUMENT_STATS) + result = [] + for instr_id, name in config.GUS_INSTR_PATCHES.items(): + priority = float(adjusted_stats[instr_id]) \ + / config.PATCH_FILE_SIZES[name] + result.append((priority, name)) + + return list(map(lambda x: x[1], reversed(sorted(result)))) + +def midi_instr_for_name(name): + """Given a GUS patch name, find the associated MIDI instrument.""" + for instr_id, instr_name in config.GUS_INSTR_PATCHES.items(): + if name == instr_name: + return instr_id + raise KeyError("Unknown instrument: %s" % name) + +def patchset_size(mapping): + """Given an instrument-instrument mapping patch set, calculate its + size. + """ + result = 0 + for i1, i2 in mapping.items(): + if i1 == i2: + name = config.GUS_INSTR_PATCHES[i1] + result += config.PATCH_FILE_SIZES[name] + return result + +def mapping_for_size(size): + """Select a set of patches for the given RAM size. + + Args: + size: Size in bytes of the GUS RAM. + Returns: + Dictionary mapping from instrument number to instrument number. + An instrument that maps to itself is included in the output. + """ + # Leave some extra space. The ultramid.ini distributed with the + # GUS drivers says this: + # The libraries are built in such a way as to leave 8K+32bytes + # after the patches are loaded for digital audio. + size -= 32*1024 + 8 + + # Get a list of patches sorted by decreasing priority. + patches = ranked_patches() + + # Start by processing the similarity groups and pointing all + # instruments in a group to their group leader. + result = {} + + for group in config.SIMILAR_GROUPS: + leader = group[0] + leader_index = midi_instr_for_name(leader) + for patch in group: + patch_index = midi_instr_for_name(patch) + result[patch_index] = leader_index + + # We now have a mapping that should cover every instrument with + # a fallback. Go through the patches in order of priority and add + # patches that will fit. + curr_size = patchset_size(result) + assert curr_size < size, \ + "Minimal config for %s will not fit in RAM!" % size + + for patch in patches: + patch_index = midi_instr_for_name(patch) + patch_size = config.PATCH_FILE_SIZES[patch] + + if result[patch_index] != patch_index \ + and curr_size + patch_size < size: + result[patch_index] = patch_index + curr_size += patch_size + + return result + +if len(sys.argv) != 2: + print "Usage: %s " % sys.argv[0] + sys.exit(1) + +mappings = ( + mapping_for_size(256 * 1024), + mapping_for_size(512 * 1024), + mapping_for_size(768 * 1024), + mapping_for_size(1024 * 1024) +) + +with open(sys.argv[1], "w") as output: + output.write("# Freedoom GUS config.\n" + "# Autogenerated by gen-ultramid\n\n") + + for instr_id, name in sorted(config.GUS_INSTR_PATCHES.items()): + line = "%i, %i, %i, %i, %i, %s" % ( + instr_id, + mappings[0][instr_id], + mappings[1][instr_id], + mappings[2][instr_id], + mappings[3][instr_id], + name + ) + + output.write(line + "\n") + + diff --git a/lumps/dmxgus/stats.py b/lumps/dmxgus/stats.py new file mode 100644 index 00000000..9a9da96f --- /dev/null +++ b/lumps/dmxgus/stats.py @@ -0,0 +1,26 @@ +# Instrument stats, autogenerated by gather_stats.py + +INSTRUMENT_STATS = [ + 40, 21, 7, 2, 9, 5, 22, 13, 26, 8, + 12, 24, 27, 10, 60, 16, 8, 6, 26, 26, + 6, 0, 0, 0, 13, 16, 4, 37, 49, 111, + 188, 21, 32, 67, 99, 40, 42, 25, 50, 39, + 9, 8, 15, 14, 41, 70, 56, 129, 198, 49, + 45, 33, 70, 8, 13, 33, 9, 6, 1, 0, + 32, 46, 18, 15, 3, 4, 2, 5, 13, 0, + 6, 12, 5, 18, 3, 6, 3, 1, 9, 16, + 68, 95, 19, 3, 11, 7, 3, 34, 25, 29, + 29, 14, 10, 20, 26, 29, 14, 17, 5, 15, + 31, 9, 8, 17, 9, 2, 4, 8, 12, 6, + 3, 1, 3, 2, 2, 4, 21, 15, 12, 34, + 13, 4, 8, 2, 1, 2, 1, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 6, 25, 1, 1, 7, + 0, 7, 2, 136, 313, 19, 206, 12, 249, 192, + 265, 197, 112, 184, 265, 152, 124, 251, 85, 168, + 193, 128, 75, 145, 24, 237, 25, 80, 27, 30, + 36, 30, 31, 14, 14, 4, 7, 42, 27, 0, + 1, 29, 17, 37, 11, 9, 2, 0, 33, 44, + 25, 5, 11, 12, 4, 2, 2, +] diff --git a/lumps/dmxgus/ultramid.ini b/lumps/dmxgus/ultramid.ini deleted file mode 100644 index 126e4c44..00000000 --- a/lumps/dmxgus/ultramid.ini +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright (c) 2012 -# Contributors to the Freedoom project. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the freedoom project nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# -# GUS patch mappings. -# -# This is a *terrible* configuration file. I threw it together in an -# hour just so that Freedoom would have a DMXGUS lump. It's based on -# inaccurate stereotypes, ignorance of musical instruments and wild -# guesses. So if you think you can improve it, feel free to do so. -# If you are a musician and are annoyed by this awful configuration -# or the comments within it, YHBT :-) -# -# Designed to use as few patches as possible to fit within a GUS -# with 256K of RAM, but no attempt has been made to improve this for -# the higher configurations! -# -# -# GM 256K 512K 768K 1024K patch name -#------------------------------------------------ -# "All pianos sound the same, right?" -0, 2, 2, 2, 2, acpiano -1, 2, 2, 2, 2, britepno -2, 2, 2, 2, 2, synpiano -3, 2, 2, 2, 2, honky -4, 2, 2, 2, 2, epiano1 -5, 2, 2, 2, 2, epiano2 -6, 2, 2, 2, 2, hrpschrd -7, 2, 2, 2, 2, clavinet -8, 2, 2, 2, 2, celeste -9, 2, 2, 2, 2, glocken -# Xylophone etc. -10, 13, 13, 13, 13, musicbox -11, 13, 13, 13, 13, vibes -12, 13, 13, 13, 13, marimba -13, 13, 13, 13, 13, xylophon -14, 13, 13, 13, 13, tubebell -15, 13, 13, 13, 13, santur -# "Organ? You mean like in a church?" -16, 16, 16, 16, 16, homeorg -17, 16, 16, 16, 16, percorg -18, 16, 16, 16, 16, rockorg -19, 16, 16, 16, 16, church -20, 16, 16, 16, 16, reedorg -21, 16, 16, 16, 16, accordn -22, 16, 16, 16, 16, harmonca -23, 16, 16, 16, 16, concrtna -# "Any guitar, I just want to be a rock star" -24, 30, 30, 30, 30, nyguitar -25, 30, 30, 30, 30, acguitar -26, 30, 30, 30, 30, jazzgtr -27, 30, 30, 30, 30, cleangtr -28, 30, 30, 30, 30, mutegtr -29, 30, 30, 30, 30, odguitar -30, 30, 30, 30, 30, distgtr -31, 30, 30, 30, 30, gtrharm -# Bass: -32, 35, 35, 35, 35, acbass -33, 35, 35, 35, 35, fngrbass -34, 35, 35, 35, 35, pickbass -35, 35, 35, 35, 35, fretless -36, 35, 35, 35, 35, slapbas1 -37, 35, 35, 35, 35, slapbas2 -38, 35, 35, 35, 35, synbass1 -39, 35, 35, 35, 35, synbass2 -# Violin: -40, 40, 40, 40, 40, violin -41, 40, 40, 40, 40, viola -42, 40, 40, 40, 40, cello -43, 40, 40, 40, 40, contraba -44, 40, 40, 40, 40, tremstr -45, 40, 40, 40, 40, pizzcato -46, 40, 40, 40, 40, harp -47, 40, 40, 40, 40, timpani -# Strings: -48, 55, 55, 55, 55, marcato -49, 55, 55, 55, 55, slowstr -50, 55, 55, 55, 55, synstr1 -51, 55, 55, 55, 55, synstr2 -52, 55, 55, 55, 55, choir -53, 55, 55, 55, 55, doo -54, 55, 55, 55, 55, voices -55, 55, 55, 55, 55, orchhit -# Trumpet: -56, 56, 56, 56, 56, trumpet -57, 56, 56, 56, 56, trombone -58, 56, 56, 56, 56, tuba -59, 56, 56, 56, 56, mutetrum -60, 56, 56, 56, 56, frenchrn -61, 56, 56, 56, 56, hitbrass -62, 56, 56, 56, 56, synbras1 -63, 56, 56, 56, 56, synbras2 -# Reed: -64, 71, 71, 71, 71, sprnosax -65, 71, 71, 71, 71, altosax -66, 71, 71, 71, 71, tenorsax -67, 71, 71, 71, 71, barisax -68, 71, 71, 71, 71, oboe -69, 71, 71, 71, 71, englhorn -70, 71, 71, 71, 71, bassoon -71, 71, 71, 71, 71, clarinet -# Pipe. Same thing as reed, right? -72, 71, 71, 71, 71, piccolo -73, 71, 71, 71, 71, flute -74, 71, 71, 71, 71, recorder -75, 71, 71, 71, 71, woodflut -76, 71, 71, 71, 71, bottle -77, 71, 71, 71, 71, shakazul -78, 71, 71, 71, 71, whistle -79, 71, 71, 71, 71, ocarina -# "Lead? You mean a lead guitar, right?" -80, 30, 30, 30, 30, sqrwave -81, 30, 30, 30, 30, sawwave -82, 30, 30, 30, 30, calliope -83, 30, 30, 30, 30, chiflead -84, 30, 30, 30, 30, charang -85, 30, 30, 30, 30, voxlead -86, 30, 30, 30, 30, lead5th -87, 30, 30, 30, 30, basslead -# Nobody really uses this shit: -88, 128, 128, 128, 128, fantasia -89, 128, 128, 128, 128, warmpad -90, 128, 128, 128, 128, polysyn -91, 128, 128, 128, 128, ghostie -92, 128, 128, 128, 128, bowglass -93, 128, 128, 128, 128, metalpad -94, 128, 128, 128, 128, halopad -95, 128, 128, 128, 128, sweeper -96, 128, 128, 128, 128, aurora -97, 128, 128, 128, 128, soundtrk -98, 128, 128, 128, 128, crystal -99, 128, 128, 128, 128, atmosphr -100, 128, 128, 128, 128, freshair -101, 128, 128, 128, 128, unicorn -102, 128, 128, 128, 128, echovox -103, 128, 128, 128, 128, startrak -# Lazy guesses at things these sound like: -104, 30, 30, 30, 30, sitar -105, 30, 30, 30, 30, banjo -106, 30, 30, 30, 30, shamisen -107, 30, 30, 30, 30, koto -108, 13, 13, 13, 13, kalimba -109, 71, 71, 71, 71, bagpipes -110, 71, 71, 71, 71, fiddle -111, 71, 71, 71, 71, Shannai -# Percussion. -112, 171, 171, 171, 171, carillon -113, 171, 171, 171, 171, agogo -114, 163, 163, 163, 163, steeldrm -115, 171, 171, 171, 171, woodblk -116, 163, 163, 163, 163, taiko -117, 174, 174, 174, 174, toms -118, 174, 174, 174, 174, syntom -119, 178, 178, 178, 178, revcym -# No. -120, 128, 128, 128, 128, fx-fret -121, 128, 128, 128, 128, fx-blow -122, 128, 128, 128, 128, seashore -123, 128, 128, 128, 128, jungle -124, 128, 128, 128, 128, telephon -125, 128, 128, 128, 128, helicptr -126, 128, 128, 128, 128, applause -127, 128, 128, 128, 128, pistol -128, 128, 128, 128, 128, blank -# Every percussion instrument ever invented is one of either: -# cymbal, tom, bass drum, snare or hi-hat. Everything else is -# just a variant on these themes. Correct? -162, 163, 163, 163, 163, kick1 -163, 163, 163, 163, 163, kick2 -164, 165, 165, 165, 165, stickrim -165, 165, 165, 165, 165, snare1 -166, 165, 165, 165, 165, claps -167, 165, 165, 165, 165, snare2 -168, 174, 174, 174, 174, tomlo2 -169, 171, 171, 171, 171, hihatcl -170, 174, 174, 174, 174, tomlo1 -171, 171, 171, 171, 171, hihatpd -172, 174, 174, 174, 174, tommid2 -173, 171, 171, 171, 171, hihatop -174, 174, 174, 174, 174, tommid1 -175, 174, 174, 174, 174, tomhi2 -176, 178, 178, 178, 178, cymcrsh1 -177, 174, 174, 174, 174, tomhi1 -178, 178, 178, 178, 178, cymride1 -179, 178, 178, 178, 178, cymchina -180, 178, 178, 178, 178, cymbell -181, 165, 165, 165, 165, tamborin -182, 178, 178, 178, 178, cymsplsh -183, 171, 171, 171, 171, cowbell -184, 178, 178, 178, 178, cymcrsh2 -185, 165, 165, 165, 165, vibslap -186, 178, 178, 178, 178, cymride2 -187, 165, 165, 165, 165, bongohi -188, 165, 165, 165, 165, bongolo -189, 163, 163, 163, 163, congahi1 -190, 163, 163, 163, 163, congahi2 -191, 163, 163, 163, 163, congalo -192, 165, 165, 165, 165, timbaleh -193, 165, 165, 165, 165, timbalel -194, 171, 171, 171, 171, agogohi -195, 171, 171, 171, 171, agogolo -196, 171, 171, 171, 171, cabasa -197, 165, 165, 165, 165, maracas -198, 171, 171, 171, 171, whistle1 -199, 171, 171, 171, 171, whistle2 -200, 171, 171, 171, 171, guiro1 -201, 171, 171, 171, 171, guiro2 -202, 163, 163, 163, 163, clave -203, 165, 165, 165, 165, woodblk1 -204, 165, 165, 165, 165, woodblk2 -205, 171, 171, 171, 171, cuica1 -206, 171, 171, 171, 171, cuica2 -207, 171, 171, 171, 171, triangl1 -208, 171, 171, 171, 171, triangl2