From c5409b2d7b1480934d4622b9b7e83928f53abc3a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Thu, 21 Jan 2010 16:24:47 +0000 Subject: SCI: Add MT-32 to GM mapping svn-id: r47416 --- engines/sci/sound/softseq/map-mt32-to-gm.h | 552 +++++++++++++++++++++++++++++ engines/sci/sound/softseq/midi.cpp | 224 +++++++++++- 2 files changed, 768 insertions(+), 8 deletions(-) create mode 100644 engines/sci/sound/softseq/map-mt32-to-gm.h (limited to 'engines/sci/sound') 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(keyshift, 0, 48) - 24; + _pitchBendRange[i] = CLIP(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]); + } + } } } -- cgit v1.2.3