mirror of
https://github.com/freedoom/freedoom.git
synced 2025-09-02 16:25:47 -04:00
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.
This commit is contained in:
parent
184be5bf61
commit
64198d7af1
8 changed files with 682 additions and 410 deletions
|
@ -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:
|
misc-lumps:
|
||||||
make -C cph/misc-lumps
|
make -C cph/misc-lumps
|
||||||
|
@ -7,6 +7,9 @@ misc-lumps:
|
||||||
genmidi-lump:
|
genmidi-lump:
|
||||||
make -C genmidi
|
make -C genmidi
|
||||||
|
|
||||||
|
dmxgus.lmp:
|
||||||
|
make -C dmxgus
|
||||||
|
|
||||||
freedoom.lmp: force
|
freedoom.lmp: force
|
||||||
echo $(VERSION) > freedoom.lmp
|
echo $(VERSION) > freedoom.lmp
|
||||||
|
|
||||||
|
@ -18,4 +21,5 @@ force:
|
||||||
clean:
|
clean:
|
||||||
make -C cph/misc-lumps clean
|
make -C cph/misc-lumps clean
|
||||||
make -C genmidi clean
|
make -C genmidi clean
|
||||||
|
make -C dmxgus clean
|
||||||
|
|
||||||
|
|
36
lumps/dmxgus/README
Normal file
36
lumps/dmxgus/README
Normal file
|
@ -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.
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
358
lumps/dmxgus/config.py
Normal file
358
lumps/dmxgus/config.py
Normal file
|
@ -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'),
|
||||||
|
]
|
||||||
|
|
83
lumps/dmxgus/gather_stats.py
Normal file
83
lumps/dmxgus/gather_stats.py
Normal file
|
@ -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")
|
||||||
|
|
||||||
|
|
174
lumps/dmxgus/gen-ultramid
Executable file
174
lumps/dmxgus/gen-ultramid
Executable file
|
@ -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 <filename>" % 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")
|
||||||
|
|
||||||
|
|
26
lumps/dmxgus/stats.py
Normal file
26
lumps/dmxgus/stats.py
Normal file
|
@ -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,
|
||||||
|
]
|
|
@ -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
|
|
Loading…
Add table
Add a link
Reference in a new issue