diff options
| author | Walter van Niftrik | 2010-01-21 16:24:47 +0000 | 
|---|---|---|
| committer | Walter van Niftrik | 2010-01-21 16:24:47 +0000 | 
| commit | c5409b2d7b1480934d4622b9b7e83928f53abc3a (patch) | |
| tree | e9c18bdbd3c474fe7b142370ae8bcaa9f539cd04 | |
| parent | d5dfb7ef0a9132ce4041f10c30883a2fb0584963 (diff) | |
| download | scummvm-rg350-c5409b2d7b1480934d4622b9b7e83928f53abc3a.tar.gz scummvm-rg350-c5409b2d7b1480934d4622b9b7e83928f53abc3a.tar.bz2 scummvm-rg350-c5409b2d7b1480934d4622b9b7e83928f53abc3a.zip  | |
SCI: Add MT-32 to GM mapping
svn-id: r47416
| -rw-r--r-- | engines/sci/sound/softseq/map-mt32-to-gm.h | 552 | ||||
| -rw-r--r-- | engines/sci/sound/softseq/midi.cpp | 224 | 
2 files changed, 768 insertions, 8 deletions
diff --git a/engines/sci/sound/softseq/map-mt32-to-gm.h b/engines/sci/sound/softseq/map-mt32-to-gm.h new file mode 100644 index 0000000000..d87ab777d7 --- /dev/null +++ b/engines/sci/sound/softseq/map-mt32-to-gm.h @@ -0,0 +1,552 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +/* Patch not mapped */ +#define MIDI_UNMAPPED 0xff +/* Patch mapped to rhythm key */ +#define MIDI_MAPPED_TO_RHYTHM 0xfe + +struct Mt32ToGmMap { +	const char *name; +	uint8 gmInstr; +	uint8 gmRhythmKey; +}; + +static const char *GmInstrumentNames[] = { +	/*000*/  "Acoustic Grand Piano", +	/*001*/  "Bright Acoustic Piano", +	/*002*/  "Electric Grand Piano", +	/*003*/  "Honky-tonk Piano", +	/*004*/  "Electric Piano 1", +	/*005*/  "Electric Piano 2", +	/*006*/  "Harpsichord", +	/*007*/  "Clavinet", +	/*008*/  "Celesta", +	/*009*/  "Glockenspiel", +	/*010*/  "Music Box", +	/*011*/  "Vibraphone", +	/*012*/  "Marimba", +	/*013*/  "Xylophone", +	/*014*/  "Tubular Bells", +	/*015*/  "Dulcimer", +	/*016*/  "Drawbar Organ", +	/*017*/  "Percussive Organ", +	/*018*/  "Rock Organ", +	/*019*/  "Church Organ", +	/*020*/  "Reed Organ", +	/*021*/  "Accordion", +	/*022*/  "Harmonica", +	/*023*/  "Tango Accordion", +	/*024*/  "Acoustic Guitar (nylon)", +	/*025*/  "Acoustic Guitar (steel)", +	/*026*/  "Electric Guitar (jazz)", +	/*027*/  "Electric Guitar (clean)", +	/*028*/  "Electric Guitar (muted)", +	/*029*/  "Overdriven Guitar", +	/*030*/  "Distortion Guitar", +	/*031*/  "Guitar Harmonics", +	/*032*/  "Acoustic Bass", +	/*033*/  "Electric Bass (finger)", +	/*034*/  "Electric Bass (pick)", +	/*035*/  "Fretless Bass", +	/*036*/  "Slap Bass 1", +	/*037*/  "Slap Bass 2", +	/*038*/  "Synth Bass 1", +	/*039*/  "Synth Bass 2", +	/*040*/  "Violin", +	/*041*/  "Viola", +	/*042*/  "Cello", +	/*043*/  "Contrabass", +	/*044*/  "Tremolo Strings", +	/*045*/  "Pizzicato Strings", +	/*046*/  "Orchestral Harp", +	/*047*/  "Timpani", +	/*048*/  "String Ensemble 1", +	/*049*/  "String Ensemble 2", +	/*050*/  "SynthStrings 1", +	/*051*/  "SynthStrings 2", +	/*052*/  "Choir Aahs", +	/*053*/  "Voice Oohs", +	/*054*/  "Synth Voice", +	/*055*/  "Orchestra Hit", +	/*056*/  "Trumpet", +	/*057*/  "Trombone", +	/*058*/  "Tuba", +	/*059*/  "Muted Trumpet", +	/*060*/  "French Horn", +	/*061*/  "Brass Section", +	/*062*/  "SynthBrass 1", +	/*063*/  "SynthBrass 2", +	/*064*/  "Soprano Sax", +	/*065*/  "Alto Sax", +	/*066*/  "Tenor Sax", +	/*067*/  "Baritone Sax", +	/*068*/  "Oboe", +	/*069*/  "English Horn", +	/*070*/  "Bassoon", +	/*071*/  "Clarinet", +	/*072*/  "Piccolo", +	/*073*/  "Flute", +	/*074*/  "Recorder", +	/*075*/  "Pan Flute", +	/*076*/  "Blown Bottle", +	/*077*/  "Shakuhachi", +	/*078*/  "Whistle", +	/*079*/  "Ocarina", +	/*080*/  "Lead 1 (square)", +	/*081*/  "Lead 2 (sawtooth)", +	/*082*/  "Lead 3 (calliope)", +	/*083*/  "Lead 4 (chiff)", +	/*084*/  "Lead 5 (charang)", +	/*085*/  "Lead 6 (voice)", +	/*086*/  "Lead 7 (fifths)", +	/*087*/  "Lead 8 (bass+lead)", +	/*088*/  "Pad 1 (new age)", +	/*089*/  "Pad 2 (warm)", +	/*090*/  "Pad 3 (polysynth)", +	/*091*/  "Pad 4 (choir)", +	/*092*/  "Pad 5 (bowed)", +	/*093*/  "Pad 6 (metallic)", +	/*094*/  "Pad 7 (halo)", +	/*095*/  "Pad 8 (sweep)", +	/*096*/  "FX 1 (rain)", +	/*097*/  "FX 2 (soundtrack)", +	/*098*/  "FX 3 (crystal)", +	/*099*/  "FX 4 (atmosphere)", +	/*100*/  "FX 5 (brightness)", +	/*101*/  "FX 6 (goblins)", +	/*102*/  "FX 7 (echoes)", +	/*103*/  "FX 8 (sci-fi)", +	/*104*/  "Sitar", +	/*105*/  "Banjo", +	/*106*/  "Shamisen", +	/*107*/  "Koto", +	/*108*/  "Kalimba", +	/*109*/  "Bag pipe", +	/*110*/  "Fiddle", +	/*111*/  "Shannai", +	/*112*/  "Tinkle Bell", +	/*113*/  "Agogo", +	/*114*/  "Steel Drums", +	/*115*/  "Woodblock", +	/*116*/  "Taiko Drum", +	/*117*/  "Melodic Tom", +	/*118*/  "Synth Drum", +	/*119*/  "Reverse Cymbal", +	/*120*/  "Guitar Fret Noise", +	/*121*/  "Breath Noise", +	/*122*/  "Seashore", +	/*123*/  "Bird Tweet", +	/*124*/  "Telephone Ring", +	/*125*/  "Helicopter", +	/*126*/  "Applause", +	/*127*/  "Gunshot" +}; + +/* The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI */ +static const char *GmPercussionNames[] = { +	/*00*/  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +	/*10*/  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +	/*20*/  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +	/*30*/  0, 0, 0, 0, +	/* The preceeding percussions are not covered by the GM standard */ +	/*34*/  "Acoustic Bass Drum", +	/*35*/  "Bass Drum 1", +	/*36*/  "Side Stick", +	/*37*/  "Acoustic Snare", +	/*38*/  "Hand Clap", +	/*39*/  "Electric Snare", +	/*40*/  "Low Floor Tom", +	/*41*/  "Closed Hi-Hat", +	/*42*/  "High Floor Tom", +	/*43*/  "Pedal Hi-Hat", +	/*44*/  "Low Tom", +	/*45*/  "Open Hi-Hat", +	/*46*/  "Low-Mid Tom", +	/*47*/  "Hi-Mid Tom", +	/*48*/  "Crash Cymbal 1", +	/*49*/  "High Tom", +	/*50*/  "Ride Cymbal 1", +	/*51*/  "Chinese Cymbal", +	/*52*/  "Ride Bell", +	/*53*/  "Tambourine", +	/*54*/  "Splash Cymbal", +	/*55*/  "Cowbell", +	/*56*/  "Crash Cymbal 2", +	/*57*/  "Vibraslap", +	/*58*/  "Ride Cymbal 2", +	/*59*/  "Hi Bongo", +	/*60*/  "Low Bongo", +	/*61*/  "Mute Hi Conga", +	/*62*/  "Open Hi Conga", +	/*63*/  "Low Conga", +	/*64*/  "High Timbale", +	/*65*/  "Low Timbale", +	/*66*/  "High Agogo", +	/*67*/  "Low Agogo", +	/*68*/  "Cabasa", +	/*69*/  "Maracas", +	/*70*/  "Short Whistle", +	/*71*/  "Long Whistle", +	/*72*/  "Short Guiro", +	/*73*/  "Long Guiro", +	/*74*/  "Claves", +	/*75*/  "Hi Wood Block", +	/*76*/  "Low Wood Block", +	/*77*/  "Mute Cuica", +	/*78*/  "Open Cuica", +	/*79*/  "Mute Triangle", +	/*80*/  "Open Triangle" +}; + +/******************************************* + * Fancy instrument mappings begin here... * + *******************************************/ + + +static const Mt32ToGmMap Mt32PresetTimbreMaps[] = { +	/*000*/  {"AcouPiano1", 0, MIDI_UNMAPPED}, +	/*001*/  {"AcouPiano2", 1, MIDI_UNMAPPED}, +	/*002*/  {"AcouPiano3", 0, MIDI_UNMAPPED}, +	/*003*/  {"ElecPiano1", 4, MIDI_UNMAPPED}, +	/*004*/  {"ElecPiano2", 5, MIDI_UNMAPPED}, +	/*005*/  {"ElecPiano3", 4, MIDI_UNMAPPED}, +	/*006*/  {"ElecPiano4", 5, MIDI_UNMAPPED}, +	/*007*/  {"Honkytonk ", 3, MIDI_UNMAPPED}, +	/*008*/  {"Elec Org 1", 16, MIDI_UNMAPPED}, +	/*009*/  {"Elec Org 2", 17, MIDI_UNMAPPED}, +	/*010*/  {"Elec Org 3", 18, MIDI_UNMAPPED}, +	/*011*/  {"Elec Org 4", 18, MIDI_UNMAPPED}, +	/*012*/  {"Pipe Org 1", 19, MIDI_UNMAPPED}, +	/*013*/  {"Pipe Org 2", 19, MIDI_UNMAPPED}, +	/*014*/  {"Pipe Org 3", 20, MIDI_UNMAPPED}, +	/*015*/  {"Accordion ", 21, MIDI_UNMAPPED}, +	/*016*/  {"Harpsi 1  ", 6, MIDI_UNMAPPED}, +	/*017*/  {"Harpsi 2  ", 6, MIDI_UNMAPPED}, +	/*018*/  {"Harpsi 3  ", 6, MIDI_UNMAPPED}, +	/*019*/  {"Clavi 1   ", 7, MIDI_UNMAPPED}, +	/*020*/  {"Clavi 2   ", 7, MIDI_UNMAPPED}, +	/*021*/  {"Clavi 3   ", 7, MIDI_UNMAPPED}, +	/*022*/  {"Celesta 1 ", 8, MIDI_UNMAPPED}, +	/*023*/  {"Celesta 2 ", 8, MIDI_UNMAPPED}, +	/*024*/  {"Syn Brass1", 62, MIDI_UNMAPPED}, +	/*025*/  {"Syn Brass2", 63, MIDI_UNMAPPED}, +	/*026*/  {"Syn Brass3", 62, MIDI_UNMAPPED}, +	/*027*/  {"Syn Brass4", 63, MIDI_UNMAPPED}, +	/*028*/  {"Syn Bass 1", 38, MIDI_UNMAPPED}, +	/*029*/  {"Syn Bass 2", 39, MIDI_UNMAPPED}, +	/*030*/  {"Syn Bass 3", 38, MIDI_UNMAPPED}, +	/*031*/  {"Syn Bass 4", 39, MIDI_UNMAPPED}, +	/*032*/  {"Fantasy   ", 88, MIDI_UNMAPPED}, +	/*033*/  {"Harmo Pan ", 89, MIDI_UNMAPPED}, +	/*034*/  {"Chorale   ", 52, MIDI_UNMAPPED}, +	/*035*/  {"Glasses   ", 98, MIDI_UNMAPPED}, +	/*036*/  {"Soundtrack", 97, MIDI_UNMAPPED}, +	/*037*/  {"Atmosphere", 99, MIDI_UNMAPPED}, +	/*038*/  {"Warm Bell ", 89, MIDI_UNMAPPED}, +	/*039*/  {"Funny Vox ", 85, MIDI_UNMAPPED}, +	/*040*/  {"Echo Bell ", 39, MIDI_UNMAPPED}, +	/*041*/  {"Ice Rain  ", 101, MIDI_UNMAPPED}, +	/*042*/  {"Oboe 2001 ", 68, MIDI_UNMAPPED}, +	/*043*/  {"Echo Pan  ", 87, MIDI_UNMAPPED}, +	/*044*/  {"DoctorSolo", 86, MIDI_UNMAPPED}, +	/*045*/  {"Schooldaze", 103, MIDI_UNMAPPED}, +	/*046*/  {"BellSinger", 88, MIDI_UNMAPPED}, +	/*047*/  {"SquareWave", 80, MIDI_UNMAPPED}, +	/*048*/  {"Str Sect 1", 48, MIDI_UNMAPPED}, +	/*049*/  {"Str Sect 2", 48, MIDI_UNMAPPED}, +	/*050*/  {"Str Sect 3", 49, MIDI_UNMAPPED}, +	/*051*/  {"Pizzicato ", 45, MIDI_UNMAPPED}, +	/*052*/  {"Violin 1  ", 40, MIDI_UNMAPPED}, +	/*053*/  {"Violin 2  ", 40, MIDI_UNMAPPED}, +	/*054*/  {"Cello 1   ", 42, MIDI_UNMAPPED}, +	/*055*/  {"Cello 2   ", 42, MIDI_UNMAPPED}, +	/*056*/  {"Contrabass", 43, MIDI_UNMAPPED}, +	/*057*/  {"Harp 1    ", 46, MIDI_UNMAPPED}, +	/*058*/  {"Harp 2    ", 46, MIDI_UNMAPPED}, +	/*059*/  {"Guitar 1  ", 24, MIDI_UNMAPPED}, +	/*060*/  {"Guitar 2  ", 25, MIDI_UNMAPPED}, +	/*061*/  {"Elec Gtr 1", 26, MIDI_UNMAPPED}, +	/*062*/  {"Elec Gtr 2", 27, MIDI_UNMAPPED}, +	/*063*/  {"Sitar     ", 104, MIDI_UNMAPPED}, +	/*064*/  {"Acou Bass1", 32, MIDI_UNMAPPED}, +	/*065*/  {"Acou Bass2", 33, MIDI_UNMAPPED}, +	/*066*/  {"Elec Bass1", 34, MIDI_UNMAPPED}, +	/*067*/  {"Elec Bass2", 39, MIDI_UNMAPPED}, +	/*068*/  {"Slap Bass1", 36, MIDI_UNMAPPED}, +	/*069*/  {"Slap Bass2", 37, MIDI_UNMAPPED}, +	/*070*/  {"Fretless 1", 35, MIDI_UNMAPPED}, +	/*071*/  {"Fretless 2", 35, MIDI_UNMAPPED}, +	/*072*/  {"Flute 1   ", 73, MIDI_UNMAPPED}, +	/*073*/  {"Flute 2   ", 73, MIDI_UNMAPPED}, +	/*074*/  {"Piccolo 1 ", 72, MIDI_UNMAPPED}, +	/*075*/  {"Piccolo 2 ", 72, MIDI_UNMAPPED}, +	/*076*/  {"Recorder  ", 74, MIDI_UNMAPPED}, +	/*077*/  {"Panpipes  ", 75, MIDI_UNMAPPED}, +	/*078*/  {"Sax 1     ", 64, MIDI_UNMAPPED}, +	/*079*/  {"Sax 2     ", 65, MIDI_UNMAPPED}, +	/*080*/  {"Sax 3     ", 66, MIDI_UNMAPPED}, +	/*081*/  {"Sax 4     ", 67, MIDI_UNMAPPED}, +	/*082*/  {"Clarinet 1", 71, MIDI_UNMAPPED}, +	/*083*/  {"Clarinet 2", 71, MIDI_UNMAPPED}, +	/*084*/  {"Oboe      ", 68, MIDI_UNMAPPED}, +	/*085*/  {"Engl Horn ", 69, MIDI_UNMAPPED}, +	/*086*/  {"Bassoon   ", 70, MIDI_UNMAPPED}, +	/*087*/  {"Harmonica ", 22, MIDI_UNMAPPED}, +	/*088*/  {"Trumpet 1 ", 56, MIDI_UNMAPPED}, +	/*089*/  {"Trumpet 2 ", 56, MIDI_UNMAPPED}, +	/*090*/  {"Trombone 1", 57, MIDI_UNMAPPED}, +	/*091*/  {"Trombone 2", 57, MIDI_UNMAPPED}, +	/*092*/  {"Fr Horn 1 ", 60, MIDI_UNMAPPED}, +	/*093*/  {"Fr Horn 2 ", 60, MIDI_UNMAPPED}, +	/*094*/  {"Tuba      ", 58, MIDI_UNMAPPED}, +	/*095*/  {"Brs Sect 1", 61, MIDI_UNMAPPED}, +	/*096*/  {"Brs Sect 2", 61, MIDI_UNMAPPED}, +	/*097*/  {"Vibe 1    ", 11, MIDI_UNMAPPED}, +	/*098*/  {"Vibe 2    ", 11, MIDI_UNMAPPED}, +	/*099*/  {"Syn Mallet", 15, MIDI_UNMAPPED}, +	/*100*/  {"Wind Bell ", 88, MIDI_UNMAPPED}, +	/*101*/  {"Glock     ", 9, MIDI_UNMAPPED}, +	/*102*/  {"Tube Bell ", 14, MIDI_UNMAPPED}, +	/*103*/  {"Xylophone ", 13, MIDI_UNMAPPED}, +	/*104*/  {"Marimba   ", 12, MIDI_UNMAPPED}, +	/*105*/  {"Koto      ", 107, MIDI_UNMAPPED}, +	/*106*/  {"Sho       ", 111, MIDI_UNMAPPED}, +	/*107*/  {"Shakuhachi", 77, MIDI_UNMAPPED}, +	/*108*/  {"Whistle 1 ", 78, MIDI_UNMAPPED}, +	/*109*/  {"Whistle 2 ", 78, MIDI_UNMAPPED}, +	/*110*/  {"BottleBlow", 76, MIDI_UNMAPPED}, +	/*111*/  {"BreathPipe", 121, MIDI_UNMAPPED}, +	/*112*/  {"Timpani   ", 47, MIDI_UNMAPPED}, +	/*113*/  {"MelodicTom", 117, MIDI_UNMAPPED}, +	/*114*/  {"Deep Snare", MIDI_MAPPED_TO_RHYTHM, 37}, +	/*115*/  {"Elec Perc1", 115, MIDI_UNMAPPED}, /* ? */ +	/*116*/  {"Elec Perc2", 118, MIDI_UNMAPPED}, /* ? */ +	/*117*/  {"Taiko     ", 116, MIDI_UNMAPPED}, +	/*118*/  {"Taiko Rim ", 118, MIDI_UNMAPPED}, +	/*119*/  {"Cymbal    ", MIDI_MAPPED_TO_RHYTHM, 50}, +	/*120*/  {"Castanets ", MIDI_UNMAPPED, MIDI_UNMAPPED}, +	/*121*/  {"Triangle  ", 112, MIDI_UNMAPPED}, +	/*122*/  {"Orche Hit ", 55, MIDI_UNMAPPED}, +	/*123*/  {"Telephone ", 124, MIDI_UNMAPPED}, +	/*124*/  {"Bird Tweet", 123, MIDI_UNMAPPED}, +	/*125*/  {"OneNoteJam", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? */ +	/*126*/  {"WaterBells", 98, MIDI_UNMAPPED}, +	/*127*/  {"JungleTune", MIDI_UNMAPPED, MIDI_UNMAPPED} /* ? */ +}; + +static const Mt32ToGmMap Mt32RhythmTimbreMaps[] = { +	/*00*/  {"Acou BD   ", MIDI_MAPPED_TO_RHYTHM, 34}, +	/*01*/  {"Acou SD   ", MIDI_MAPPED_TO_RHYTHM, 37}, +	/*02*/  {"Acou HiTom", 117, 49}, +	/*03*/  {"AcouMidTom", 117, 46}, +	/*04*/  {"AcouLowTom", 117, 40}, +	/*05*/  {"Elec SD   ", MIDI_MAPPED_TO_RHYTHM, 39}, +	/*06*/  {"Clsd HiHat", MIDI_MAPPED_TO_RHYTHM, 41}, +	/*07*/  {"OpenHiHat1", MIDI_MAPPED_TO_RHYTHM, 45}, +	/*08*/  {"Crash Cym ", MIDI_MAPPED_TO_RHYTHM, 48}, +	/*09*/  {"Ride Cym  ", MIDI_MAPPED_TO_RHYTHM, 50}, +	/*10*/  {"Rim Shot  ", MIDI_MAPPED_TO_RHYTHM, 36}, +	/*11*/  {"Hand Clap ", MIDI_MAPPED_TO_RHYTHM, 38}, +	/*12*/  {"Cowbell   ", MIDI_MAPPED_TO_RHYTHM, 55}, +	/*13*/  {"Mt HiConga", MIDI_MAPPED_TO_RHYTHM, 61}, +	/*14*/  {"High Conga", MIDI_MAPPED_TO_RHYTHM, 62}, +	/*15*/  {"Low Conga ", MIDI_MAPPED_TO_RHYTHM, 63}, +	/*16*/  {"Hi Timbale", MIDI_MAPPED_TO_RHYTHM, 64}, +	/*17*/  {"LowTimbale", MIDI_MAPPED_TO_RHYTHM, 65}, +	/*18*/  {"High Bongo", MIDI_MAPPED_TO_RHYTHM, 59}, +	/*19*/  {"Low Bongo ", MIDI_MAPPED_TO_RHYTHM, 60}, +	/*20*/  {"High Agogo", 113, 66}, +	/*21*/  {"Low Agogo ", 113, 67}, +	/*22*/  {"Tambourine", MIDI_MAPPED_TO_RHYTHM, 53}, +	/*23*/  {"Claves    ", MIDI_MAPPED_TO_RHYTHM, 74}, +	/*24*/  {"Maracas   ", MIDI_MAPPED_TO_RHYTHM, 69}, +	/*25*/  {"SmbaWhis L", 78, 71}, +	/*26*/  {"SmbaWhis S", 78, 70}, +	/*27*/  {"Cabasa    ", MIDI_MAPPED_TO_RHYTHM, 68}, +	/*28*/  {"Quijada   ", MIDI_MAPPED_TO_RHYTHM, 72}, +	/*29*/  {"OpenHiHat2", MIDI_MAPPED_TO_RHYTHM, 43} +}; + +static const uint8 Mt32PresetRhythmKeymap[] = { +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, 34, 34, 36, 37, 38, 39, +	40, 41, 42, 43, 44, 45, 46, 47, 48, 49, +	50, MIDI_UNMAPPED, MIDI_UNMAPPED, 53, MIDI_UNMAPPED, 55, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, 59, +	60, 61, 62, 63, 64, 65, 66, 67, 68, 69, +	70, 71, 72, MIDI_UNMAPPED, 74, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, +	MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED, MIDI_UNMAPPED +}; + +/* +++ - Don't change unless you've got a good reason +   ++  - Looks good, sounds ok +   +   - Not too bad, but is it right? +   ?   - Where do I map this one? +   ??  - Any good ideas? +   ??? - I'm clueless? +   R   - Rhythm... */ +static const Mt32ToGmMap Mt32MemoryTimbreMaps[] = { +	{"AccPnoKA2 ", 1, MIDI_UNMAPPED},     /* ++ (KQ1) */ +	{"Acou BD   ", MIDI_MAPPED_TO_RHYTHM, 34},   /* R (PQ2) */ +	{"Acou SD   ", MIDI_MAPPED_TO_RHYTHM, 37},   /* R (PQ2) */ +	{"AcouPnoKA ", 0, MIDI_UNMAPPED},     /* ++ (KQ1) */ +	{"BASS      ", 32, MIDI_UNMAPPED},    /* + (LSL3) */ +	{"BASSOONPCM", 70, MIDI_UNMAPPED},    /* + (CB) */ +	{"BEACH WAVE", 122, MIDI_UNMAPPED},   /* + (LSL3) */ +	{"BagPipes  ", 109, MIDI_UNMAPPED}, +	{"BassPizzMS", 45, MIDI_UNMAPPED},    /* ++ (HQ) */ +	{"BassoonKA ", 70, MIDI_UNMAPPED},    /* ++ (KQ1) */ +	{"Bell    MS", 112, MIDI_UNMAPPED},   /* ++ (iceMan) */ +	{"Bells   MS", 112, MIDI_UNMAPPED},   /* + (HQ) */ +	{"Big Bell  ", 14, MIDI_UNMAPPED},    /* + (CB) */ +	{"Bird Tweet", 123, MIDI_UNMAPPED}, +	{"BrsSect MS", 61, MIDI_UNMAPPED},    /* +++ (iceMan) */ +	{"CLAPPING  ", 126, MIDI_UNMAPPED},   /* ++ (LSL3) */ +	{"Cabasa    ", MIDI_MAPPED_TO_RHYTHM, 68},   /* R (HBoG) */ +	{"Calliope  ", 82, MIDI_UNMAPPED},    /* +++ (HQ) */ +	{"CelticHarp", 46, MIDI_UNMAPPED},    /* ++ (CoC) */ +	{"Chicago MS", 1, MIDI_UNMAPPED},     /* ++ (iceMan) */ +	{"Chop      ", 117, MIDI_UNMAPPED}, +	{"Chorale MS", 52, MIDI_UNMAPPED},    /* + (CoC) */ +	{"ClarinetMS", 71, MIDI_UNMAPPED}, +	{"Claves    ", MIDI_MAPPED_TO_RHYTHM, 74},   /* R (PQ2) */ +	{"Claw    MS", 118, MIDI_UNMAPPED},    /* + (HQ) */ +	{"ClockBell ", 14, MIDI_UNMAPPED},    /* + (CB) */ +	{"ConcertCym", MIDI_MAPPED_TO_RHYTHM, 54},   /* R ? (KQ1) */ +	{"Conga   MS", MIDI_MAPPED_TO_RHYTHM, 63},   /* R (HQ) */ +	{"CoolPhone ", 124, MIDI_UNMAPPED},   /* ++ (LSL3) */ +	{"CracklesMS", 115, MIDI_UNMAPPED}, /* ? (CoC, HQ) */ +	{"CreakyD MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ??? (KQ1) */ +	{"Cricket   ", 120, MIDI_UNMAPPED}, /* ? (CB) */ +	{"CrshCymbMS", MIDI_MAPPED_TO_RHYTHM, 56},   /* R +++ (iceMan) */ +	{"CstlGateMS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (HQ) */ +	{"CymSwellMS", MIDI_MAPPED_TO_RHYTHM, 54},   /* R ? (CoC, HQ) */ +	{"CymbRollKA", MIDI_MAPPED_TO_RHYTHM, 56},   /* R ? (KQ1) */ +	{"Cymbal Lo ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* R ? (LSL3) */ +	{"card      ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (HBoG) */ +	{"DirtGtr MS", 30, MIDI_UNMAPPED},    /* + (iceMan) */ +	{"DirtGtr2MS", 29, MIDI_UNMAPPED},    /* + (iceMan) */ +	{"E Bass  MS", 33, MIDI_UNMAPPED},    /* + (SQ3) */ +	{"ElecBassMS", 33, MIDI_UNMAPPED}, +	{"ElecGtr MS", 27, MIDI_UNMAPPED},    /* ++ (iceMan) */ +	{"EnglHornMS", 69, MIDI_UNMAPPED}, +	{"FantasiaKA", 88, MIDI_UNMAPPED}, +	{"Fantasy   ", 99, MIDI_UNMAPPED},    /* + (PQ2) */ +	{"Fantasy2MS", 99, MIDI_UNMAPPED},    /* ++ (CoC, HQ) */ +	{"Filter  MS", 95, MIDI_UNMAPPED},    /* +++ (iceMan) */ +	{"Filter2 MS", 95, MIDI_UNMAPPED},    /* ++ (iceMan) */ +	{"Flame2  MS", 121, MIDI_UNMAPPED},   /* ? (HQ) */ +	{"Flames  MS", 121, MIDI_UNMAPPED},   /* ? (HQ) */ +	{"Flute   MS", 73, MIDI_UNMAPPED},    /* +++ (HQ) */ +	{"FogHorn MS", 58, MIDI_UNMAPPED}, +	{"FrHorn1 MS", 60, MIDI_UNMAPPED},    /* +++ (HQ) */ +	{"FunnyTrmp ", 56, MIDI_UNMAPPED},    /* ++ (CB) */ +	{"GameSnd MS", 80, MIDI_UNMAPPED}, +	{"Glock   MS", 9, MIDI_UNMAPPED},     /* +++ (HQ) */ +	{"Gunshot   ", 127, MIDI_UNMAPPED},   /* +++ (CB) */ +	{"Hammer  MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (HQ) */ +	{"Harmonica2", 22, MIDI_UNMAPPED},    /* +++ (CB) */ +	{"Harpsi 1  ", 6, MIDI_UNMAPPED},     /* + (HBoG) */ +	{"Harpsi 2  ", 6, MIDI_UNMAPPED},     /* +++ (CB) */ +	{"Heart   MS", 116, MIDI_UNMAPPED},   /* ? (iceMan) */ +	{"Horse1  MS", 115, MIDI_UNMAPPED},   /* ? (CoC, HQ) */ +	{"Horse2  MS", 115, MIDI_UNMAPPED},   /* ? (CoC, HQ) */ +	{"InHale  MS", 121, MIDI_UNMAPPED},   /* ++ (iceMan) */ +	{"KNIFE     ", 120, MIDI_UNMAPPED},   /* ? (LSL3) */ +	{"KenBanjo  ", 105, MIDI_UNMAPPED},   /* +++ (CB) */ +	{"Kiss    MS", 25, MIDI_UNMAPPED},    /* ++ (HQ) */ +	{"KongHit   ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ??? (KQ1) */ +	{"Koto      ", 107, MIDI_UNMAPPED},   /* +++ (PQ2) */ +	{"Laser   MS", 81, MIDI_UNMAPPED},    /* ?? (HQ) */ +	{"Meeps   MS", 62, MIDI_UNMAPPED},    /* ? (HQ) */ +	{"MTrak   MS", 62, MIDI_UNMAPPED},    /* ?? (iceMan) */ +	{"MachGun MS", 127, MIDI_UNMAPPED},   /* ? (iceMan) */ +	{"OCEANSOUND", 122, MIDI_UNMAPPED},   /* + (LSL3) */ +	{"Oboe 2001 ", 68, MIDI_UNMAPPED},    /* + (PQ2) */ +	{"Ocean   MS", 122, MIDI_UNMAPPED},   /* + (iceMan) */ +	{"PPG 2.3 MS", 75, MIDI_UNMAPPED},    /* ? (iceMan) */ +	{"PianoCrank", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (CB) */ +	{"PicSnareMS", MIDI_MAPPED_TO_RHYTHM, 39},   /* R ? (iceMan) */ +	{"PiccoloKA ", 72, MIDI_UNMAPPED},    /* +++ (KQ1) */ +	{"PinkBassMS", 39, MIDI_UNMAPPED}, +	{"Pizz2     ", 45, MIDI_UNMAPPED},    /* ++ (CB) */ +	{"Portcullis", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (KQ1) */ +	{"Raspbry MS", 81, MIDI_UNMAPPED},    /* ? (HQ) */ +	{"RatSqueek ", 72, MIDI_UNMAPPED},    /* ? (CB, CoC) */ +	{"Record78  ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* +++ (CB) */ +	{"RecorderMS", 74, MIDI_UNMAPPED},    /* +++ (CoC) */ +	{"Red Baron ", 125, MIDI_UNMAPPED},   /* ? (CB) */ +	{"ReedPipMS ", 20, MIDI_UNMAPPED},    /* +++ (Coc) */ +	{"RevCymb MS", 119, MIDI_UNMAPPED}, +	{"RifleShot ", 127, MIDI_UNMAPPED},   /* + (CB) */ +	{"RimShot MS", MIDI_MAPPED_TO_RHYTHM, 36},   /* R */ +	{"SHOWER    ", 52, MIDI_UNMAPPED},    /* ? (LSL3) */ +	{"SQ Bass MS", 32, MIDI_UNMAPPED},    /* + (SQ3) */ +	{"ShakuVibMS", 79, MIDI_UNMAPPED},    /* + (iceMan) */ +	{"SlapBassMS", 36, MIDI_UNMAPPED},    /* +++ (iceMan) */ +	{"Snare   MS", MIDI_MAPPED_TO_RHYTHM, 37},   /* R (HQ) */ +	{"Some Birds", 123, MIDI_UNMAPPED},   /* + (CB) */ +	{"Sonar   MS", 78, MIDI_UNMAPPED},    /* ? (iceMan) */ +	{"Soundtrk2 ", 97, MIDI_UNMAPPED},    /* +++ (CB) */ +	{"Soundtrack", 97, MIDI_UNMAPPED},    /* ++ (CoC) */ +	{"SqurWaveMS", 80, MIDI_UNMAPPED}, +	{"StabBassMS", 34, MIDI_UNMAPPED},    /* + (iceMan) */ +	{"SteelDrmMS", 114, MIDI_UNMAPPED},   /* +++ (iceMan) */ +	{"StrSect1MS", 48, MIDI_UNMAPPED},    /* ++ (HQ) */ +	{"String  MS", 45, MIDI_UNMAPPED},    /* + (CoC) */ +	{"Syn-Choir ", 91, MIDI_UNMAPPED}, +	{"Syn Brass4", 63, MIDI_UNMAPPED},    /* ++ (PQ2) */ +	{"SynBass MS", 38, MIDI_UNMAPPED}, +	{"SwmpBackgr", 120, MIDI_UNMAPPED},    /* ?? (CB,HQ) */ +	{"T-Bone2 MS", 57, MIDI_UNMAPPED},    /* +++ (HQ) */ +	{"Taiko     ", 116, 34},      /* +++ (Coc) */ +	{"Taiko Rim ", 118, 36},      /* +++ (LSL3) */ +	{"Timpani1  ", 47, MIDI_UNMAPPED},    /* +++ (CB) */ +	{"Tom     MS", 117, 47},      /* +++ (iceMan) */ +	{"Toms    MS", 117, 47},      /* +++ (CoC, HQ) */ +	{"Tpt1prtl  ", 56, MIDI_UNMAPPED},    /* +++ (KQ1) */ +	{"TriangleMS", 112, 80},      /* R (CoC) */ +	{"Trumpet 1 ", 56, MIDI_UNMAPPED},    /* +++ (CoC) */ +	{"Type    MS", 114, MIDI_UNMAPPED},   /* ? (iceMan) */ +	{"WaterBells", 98, MIDI_UNMAPPED},    /* + (PQ2) */ +	{"WaterFallK", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (KQ1) */ +	{"Whiporill ", 123, MIDI_UNMAPPED},   /* + (CB) */ +	{"Wind      ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (CB) */ +	{"Wind    MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (HQ, iceMan) */ +	{"Wind2   MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (CoC) */ +	{"Woodpecker", 115, MIDI_UNMAPPED},   /* ? (CB) */ +	{"WtrFall MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (CoC, HQ, iceMan) */ +	{0, 0, 0} +}; + +} // End of namespace Sci diff --git a/engines/sci/sound/softseq/midi.cpp b/engines/sci/sound/softseq/midi.cpp index 7951387762..d32d0c529b 100644 --- a/engines/sci/sound/softseq/midi.cpp +++ b/engines/sci/sound/softseq/midi.cpp @@ -31,6 +31,7 @@  #include "sci/resource.h"  #include "sci/sound/softseq/mididriver.h" +#include "sci/sound/softseq/map-mt32-to-gm.h"  namespace Sci { @@ -63,6 +64,11 @@ private:  	void readMt32Patch(const byte *data, int size);  	void readMt32DrvData(); +	void mapMt32ToGm(byte *data, size_t size); +	uint8 lookupGmInstrument(const char *iname); +	uint8 lookupGmRhythmKey(const char *iname); +	uint8 getGmInstrument(const Mt32ToGmMap &Mt32Ins); +  	void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream *str, int len, bool noDelay);  	void sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay);  	void setMt32Volume(byte volume); @@ -83,7 +89,7 @@ private:  		uint8 hold;  		uint8 volume; -		Channel() : mappedPatch(0xff), patch(0xff), velocityMapIdx(0), playing(false), +		Channel() : mappedPatch(MIDI_UNMAPPED), patch(MIDI_UNMAPPED), velocityMapIdx(0), playing(false),  			keyShift(0), volAdjust(0), pan(0x80), hold(0), volume(0x7f) { }  	}; @@ -101,6 +107,11 @@ private:  	uint8 _patchMap[128];  	uint8 _velocityMapIdx[128];  	uint8 _velocityMap[4][128]; + +	// These are extensions used for our own MT-32 to GM mapping +	uint8 _pitchBendRange[128]; +	uint8 _percussionVelocityScale[128]; +  	byte _goodbyeMsg[20];  	byte _sysExBuf[kMaxSysExSize];  }; @@ -123,14 +134,28 @@ MidiPlayer_Midi::~MidiPlayer_Midi() {  }  void MidiPlayer_Midi::noteOn(int channel, int note, int velocity) { +	uint8 patch = _channels[channel].mappedPatch; +  	if (channel == MIDI_RHYTHM_CHANNEL) { -		note = _percussionMap[note]; -		if (note == 0xff) +		if (_percussionMap[note] == MIDI_UNMAPPED) { +			debugC(kDebugLevelSound, "[Midi] Percussion instrument %i is unmapped", note);  			return; -	} else { -		if (_channels[channel].mappedPatch == 0xff) +		} + +		note = _percussionMap[note]; +		// Scale velocity; +		velocity = velocity * _percussionVelocityScale[note] / 127; +	} else if (patch >= 128) { +		if (patch == MIDI_UNMAPPED)  			return; +		// Map to rhythm +		channel = MIDI_RHYTHM_CHANNEL; +		note = patch - 128; + +		// Scale velocity; +		velocity = velocity * _percussionVelocityScale[note] / 127; +	} else {  		int8 keyshift = _keyShift[channel];  		int shiftNote = note + keyshift; @@ -210,12 +235,13 @@ void MidiPlayer_Midi::setPatch(int channel, int patch) {  	_channels[channel].patch = patch;  	_channels[channel].velocityMapIdx = _velocityMapIdx[patch]; -	if (_channels[channel].mappedPatch == 0xff) +	if (_channels[channel].mappedPatch == MIDI_UNMAPPED)  		resetVol = true;  	_channels[channel].mappedPatch = _patchMap[patch]; -	if (_patchMap[patch] == 0xff) { +	if (_patchMap[patch] == MIDI_UNMAPPED) { +		debugC(kDebugLevelSound, "[Midi] Channel %i set to unmapped patch %i", channel, patch);  		_driver->send(0xb0 | channel, 0x7b, 0);  		_driver->send(0xb0 | channel, 0x40, 0);  		return; @@ -233,6 +259,10 @@ void MidiPlayer_Midi::setPatch(int channel, int patch) {  		controlChange(channel, 0x07, _channels[channel].volume);  	} +	uint8 bendRange = _pitchBendRange[patch]; +	if (bendRange != MIDI_UNMAPPED) +		_driver->setPitchBendRange(channel, bendRange); +  	_driver->send(0xc0 | channel, _patchMap[patch], 0);  } @@ -539,6 +569,151 @@ void MidiPlayer_Midi::readMt32DrvData() {  	}  } +byte MidiPlayer_Midi::lookupGmInstrument(const char *iname) { +	int i = 0; + +	while (Mt32MemoryTimbreMaps[i].name) { +		if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0) +			return getGmInstrument(Mt32MemoryTimbreMaps[i]); +		i++; +	} +	return MIDI_UNMAPPED; +} + +byte MidiPlayer_Midi::lookupGmRhythmKey(const char *iname) { +	int i = 0; + +	while (Mt32MemoryTimbreMaps[i].name) { +		if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0) +			return Mt32MemoryTimbreMaps[i].gmRhythmKey; +		i++; +	} +	return MIDI_UNMAPPED; +} + +uint8 MidiPlayer_Midi::getGmInstrument(const Mt32ToGmMap &Mt32Ins) { +	if (Mt32Ins.gmInstr == MIDI_MAPPED_TO_RHYTHM) +		return Mt32Ins.gmRhythmKey + 0x80; +	else +		return Mt32Ins.gmInstr; +} + +void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) { +	// FIXME: Clean this up +	int memtimbres, patches; +	uint8 group, number, keyshift, finetune, bender_range; +	uint8 *patchpointer; +	uint32 pos; +	int i; + +	for (i = 0; i < 128; i++) { +		_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[i]); +		_pitchBendRange[i] = 12; +	} + +	for (i = 0; i < 128; i++) +		_percussionMap[i] = Mt32PresetRhythmKeymap[i]; + +	memtimbres = *(data + 0x1eb); +	pos = 0x1ec + memtimbres * 0xf6; + +	if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xabcd)) { +		patches = 96; +		pos += 2 + 8 * 48; +	} else +		patches = 48; + +	debugC(kDebugLevelSound, "[MT32-to-GM] %d MT-32 Patches detected", patches); +	debugC(kDebugLevelSound, "[MT32-to-GM] %d MT-32 Memory Timbres", memtimbres); + +	debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping patches.."); + +	for (i = 0; i < patches; i++) { +		char name[11]; + +		if (i < 48) +			patchpointer = data + 0x6b + 8 * i; +		else +			patchpointer = data + 0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2; + +		group = *patchpointer; +		number = *(patchpointer + 1); +		keyshift = *(patchpointer + 2); +		finetune = *(patchpointer + 3); +		bender_range = *(patchpointer + 4); + +		debugCN(kDebugLevelSound, "  [%03d] ", i); + +		switch (group) { +		case 1: +			number += 64; +			// Fall through +		case 0: +			_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[number]); +			debugCN(kDebugLevelSound, "%s -> ", Mt32PresetTimbreMaps[number].name); +			break; +		case 2: +			strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10); +			name[10] = 0; +			_patchMap[i] = lookupGmInstrument(name); +			debugCN(kDebugLevelSound, "%s -> ", name); +			break; +		case 3: +			_patchMap[i] = getGmInstrument(Mt32RhythmTimbreMaps[number]); +			debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number].name); +			break; +		default: +			break; +		} + +		if (_patchMap[i] == MIDI_UNMAPPED) { +			debugC(kDebugLevelSound, "[Unmapped]"); +		} else { +			if (_patchMap[i] >= 128) { +				debugC(kDebugLevelSound, "%s [Rhythm]", GmPercussionNames[_patchMap[i] - 128]); +			} else { +				debugC(kDebugLevelSound, "%s", GmInstrumentNames[_patchMap[i]]); +			} +		} + +		_keyShift[i] = CLIP<uint8>(keyshift, 0, 48) - 24; +		_pitchBendRange[i] = CLIP<uint8>(bender_range, 0, 24); +	} + +	if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xdcba)) { +		debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping percussion.."); + +		for (i = 0; i < 64 ; i++) { +			number = *(data + pos + 4 * i + 2); + +			debugCN(kDebugLevelSound, "  [%03d] ", i + 23); + +			if (number < 64) { +				char name[11]; +				strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10); +				name[10] = 0; +				debugCN(kDebugLevelSound, "%s -> ", name); +				_percussionMap[i + 23] = lookupGmRhythmKey(name); +			} else { +				if (number < 94) { +					debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number - 64].name); +					_percussionMap[i + 23] = Mt32RhythmTimbreMaps[number - 64].gmRhythmKey; +				} else { +					debugCN(kDebugLevelSound, "[Key  %03i] -> ", number); +					_percussionMap[i + 23] = MIDI_UNMAPPED; +				} +			} + +			if (_percussionMap[i + 23] == MIDI_UNMAPPED) +				debugC(kDebugLevelSound, "[Unmapped]"); +			else +				debugC(kDebugLevelSound, "%s", GmPercussionNames[_percussionMap[i + 23]]); + +			_percussionVelocityScale[i + 23] = *(data + pos + 4 * i + 3) * 127 / 100; +		} +	} +} +  void MidiPlayer_Midi::setMt32Volume(byte volume) {  	sendMt32SysEx(0x100016, &volume, 1);  } @@ -567,6 +742,8 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {  		_keyShift[i] = 0;  		_volAdjust[i] = 0;  		_velocityMapIdx[i] = 0; +		_pitchBendRange[i] = MIDI_UNMAPPED; +		_percussionVelocityScale[i] = 127;  	}  	Resource *res = NULL; @@ -592,6 +769,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {  		res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);  		if (res && isMt32GmPatch(res->data, res->size)) { +			// There is a GM patch  			readMt32GmPatch(res->data, res->size);  			// Detect the format of patch 1, so that we know what play mask to use @@ -601,7 +779,37 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {  			else  				_isOldPatchFormat = !isMt32GmPatch(res->data, res->size);  		} else { -			warning("MT-32 to GM translation not yet supported"); +			// No GM patch found, map instruments using MT-32 patch + +			warning("Game has no native support for General MIDI, applying auto-mapping"); + +			// Modify velocity map to make low velocity notes a little louder +			for (uint i = 1; i < 0x40; i++) +				_velocityMap[0][i] = 0x20 + (i - 1) / 2; + +			res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0); + +			if (res) { +				if (!isMt32GmPatch(res->data, res->size)) +					mapMt32ToGm(res->data, res->size); +				else +					error("MT-32 patch has wrong type"); +			} else { +				// No MT-32 patch present, try to read from MT32.DRV +				Common::File f; + +				if (f.open("MT32.DRV")) { +					int size = f.size(); + +					assert(size >= 70); + +					f.seek(0x29); + +					// Read AdLib->MT-32 patch map +					for (int i = 0; i < 48; i++) +						_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[f.readByte() & 0x7f]); +				} +			}  		}  	}  | 
