/* ScummVM - Scumm Interpreter * Copyright (C) 2001 Ludvig Strigeus * Copyright (C) 2001-2003 The ScummVM project * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ */ #include "stdafx.h" #include "scumm/scumm.h" #include "scumm/saveload.h" #include "scumm/instrument.h" #include "sound/mididrv.h" static bool _native_mt32 = false; static const byte mt32_to_gm[128] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 0, 2, 4, 4, 5, 3, 16, 17, 18, 16, 16, 19, 20, 21, // 0x 6, 6, 6, 7, 7, 7, 8, 112, 62, 62, 63, 63, 38, 38, 39, 39, // 1x 88, 95, 52, 98, 97, 99, 14, 54, 102, 96, 53, 102, 81, 100, 14, 80, // 2x 48, 48, 49, 45, 41, 40, 42, 42, 43, 46, 45, 24, 25, 28, 27, 104, // 3x 32, 32, 34, 33, 36, 37, 35, 35, 79, 73, 72, 72, 74, 75, 64, 65, // 4x 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, 57, 60, 60, 58, 61, // 5x 61, 11, 11, 98, 14, 9, 14, 13, 12, 107, 107, 77, 78, 78, 76, 76, // 6x 47, 117, 127, 118, 118, 116, 115, 119, 115, 112, 55, 124, 123, 0, 14, 117 // 7x }; static struct { char *name; byte program; } roland_to_gm_map [] = { // Monkey Island 2 instruments // TODO: Complete { "badspit ", 62 }, { "Big Drum ", 116 }, { "burp ", 58 }, // { "dinkfall ", ??? }, // { "Fire Pit ", ??? }, { "foghorn ", 60 }, { "glop ", 39 }, // { "jacob's la", ??? }, { "LeshBass ", 33 }, // { "lowsnort ", ??? }, { "ML explosn", 127 }, { "ReggaeBass", 32 }, // { "rope fall ", ??? }, { "rumble ", 89 }, { "SdTrk Bend", 97 }, // { "snort ", ??? }, { "spitting ", 62 }, { "Swell 1 ", 95 }, { "Swell 2 ", 95 }, { "thnderclap", 127 } // Fate of Atlantis instruments // TODO: Build // { "*aah! ", ??? }, // { "*ooh! ", ??? }, // { "*ShotFar4 ", ??? }, // { "*splash3 ", ??? }, // { "*torpedo5 ", ??? }, // { "*whip3 ", ??? }, // { "*woodknock", ??? }, // { "35 lavabub", ??? }, // { "49 bzzt! ", ??? }, // { "applause ", ??? }, // { "Arabongo ", ??? }, // { "Big Drum ", ??? }, // DUPLICATE (todo: confirm) // { "bodythud1 ", ??? }, // { "boneKLOK2 ", ??? }, // { "boom10 ", ??? }, // { "boom11 ", ??? }, // { "boom15 ", ??? }, // { "boxclik1a ", ??? }, // { "brassbonk3", ??? }, // { "carstart ", ??? }, // { "cb tpt 2 ", ??? }, // { "cell door ", ??? }, // { "chains ", ??? }, // { "crash ", ??? }, // { "crsrt/idl3", ??? }, // { "Fire Pit ", ??? }, // DUPLICATE (todo: confirm) // { "Fzooom ", ??? }, // { "Fzooom 2 ", ??? }, // { "ghostwhosh", ??? }, // { "glasssmash", ??? }, // { "gloop2 ", ??? }, // { "gunShotNea", ??? }, // { "idoorclse ", ??? }, // { "knife ", ??? }, // { "lavacmbl4 ", ??? }, // { "Mellow Str", ??? }, // { "mtlheater1", ??? }, // { "pachinko5 ", ??? }, // { "Ping1 ", ??? }, // { "rockcrunch", ??? }, // { "rumble ", ??? }, // DUPLICATE (todo: confirm) // { "runngwatr ", ??? }, // { "scrape2 ", ??? }, // { "snakeHiss ", ??? }, // { "snort ", ??? }, // DUPLICATE (todo: confirm) // { "spindle4 ", ??? }, // { "splash2 ", ??? }, // { "squirel ", ??? }, // { "steam3 ", ??? }, // { "stonwheel6", ??? }, // { "street ", ??? }, // { "trickle4 ", ??? } }; class Instrument_Program : public InstrumentInternal { private: byte _program; bool _mt32; public: Instrument_Program (byte program, bool mt32); Instrument_Program (Serializer *s); void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->program (_program, _mt32); } bool is_valid() { return (_program < 128); } operator int() { return (_program < 128) ? _program : 255; } }; class Instrument_Adlib : public InstrumentInternal { private: struct { byte flags_1; byte oplvl_1; byte atdec_1; byte sustrel_1; byte waveform_1; byte flags_2; byte oplvl_2; byte atdec_2; byte sustrel_2; byte waveform_2; byte feedback; byte flags_a; struct { byte a,b,c,d,e,f,g,h; } extra_a; byte flags_b; struct { byte a,b,c,d,e,f,g,h; } extra_b; byte duration; } _instrument; public: Instrument_Adlib (byte *data); Instrument_Adlib (Serializer *s); void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->adlib ((byte *) &_instrument); } bool is_valid() { return true; } }; class Instrument_Roland : public InstrumentInternal { private: struct RolandInstrument { byte roland_id; byte device_id; byte model_id; byte command; byte address[3]; struct { byte name[10]; byte partial_struct12; byte partial_struct34; byte partial_mute; byte env_mode; } common; struct { byte wg_pitch_coarse; byte wg_pitch_fine; byte wg_pitch_keyfollow; byte wg_pitch_bender_sw; byte wg_waveform_pcm_bank; byte wg_pcm_wave_num; byte wg_pulse_width; byte wg_pw_velo_sens; byte p_env_depth; byte p_evn_velo_sens; byte p_env_time_keyf; byte p_env_time[4]; byte p_env_level[3]; byte p_env_sustain_level; byte end_level; byte p_lfo_rate; byte p_lfo_depth; byte p_lfo_mod_sens; byte tvf_cutoff_freq; byte tvf_resonance; byte tvf_keyfollow; byte tvf_bias_point_dir; byte tvf_bias_level; byte tvf_env_depth; byte tvf_env_velo_sens; byte tvf_env_depth_keyf; byte tvf_env_time_keyf; byte tvf_env_time[5]; byte tvf_env_level[3]; byte tvf_env_sustain_level; byte tva_level; byte tva_velo_sens; byte tva_bias_point_1; byte tva_bias_level_1; byte tva_bias_point_2; byte tva_bias_level_2; byte tva_env_time_keyf; byte tva_env_time_v_follow; byte tva_env_time[5]; byte tva_env_level[3]; byte tva_env_sustain_level; } partial[4]; byte checksum; } GNUPACK; RolandInstrument _instrument; char _instrument_name [11]; uint8 getEquivalentGM(); public: Instrument_Roland (byte *data); Instrument_Roland (Serializer *s); void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->roland ((byte *) &_instrument); } bool is_valid() { return (_native_mt32 ? true : (_instrument_name[0] != '\0')); } }; //////////////////////////////////////// // // Instrument class members // //////////////////////////////////////// void Instrument::nativeMT32 (bool native) { _native_mt32 = native; } void Instrument::clear() { if (_instrument) delete _instrument; _instrument = NULL; _type = itNone; } void Instrument::program (byte prog, bool mt32) { clear(); if (prog > 127) return; _type = itProgram; _instrument = new Instrument_Program (prog, mt32); } void Instrument::adlib (byte *instrument) { clear(); if (!instrument) return; _type = itAdlib; _instrument = new Instrument_Adlib (instrument); } void Instrument::roland (byte *instrument) { clear(); if (!instrument) return; _type = itRoland; _instrument = new Instrument_Roland (instrument); } void Instrument::saveOrLoad (Serializer *s) { if (s->isSaving()) { s->saveByte (_type); if (_instrument) _instrument->saveOrLoad (s); } else { clear(); _type = s->loadByte(); switch (_type) { case itNone: break; case itProgram: _instrument = new Instrument_Program (s); break; case itAdlib: _instrument = new Instrument_Adlib (s); break; case itRoland: _instrument = new Instrument_Roland (s); break; default: warning ("No known instrument classification #%d", (int) _type); _type = itNone; } } } //////////////////////////////////////// // // Instrument_Program class members // //////////////////////////////////////// Instrument_Program::Instrument_Program (byte program, bool mt32) : _program (program), _mt32 (mt32) { if (program > 127) _program = 255; } Instrument_Program::Instrument_Program (Serializer *s) { _program = 255; if (!s->isSaving()) saveOrLoad (s); } void Instrument_Program::saveOrLoad (Serializer *s) { if (s->isSaving()) { s->saveByte (_program); s->saveByte (_mt32 ? 1 : 0); } else { _program = s->loadByte(); _mt32 = (s->loadByte() > 0); } } void Instrument_Program::send (MidiChannel *mc) { if (_program > 127) return; if (_native_mt32) // if (mc->device()->mt32device()) mc->programChange (_mt32 ? _program : _program /*gm_to_mt32 [_program]*/); else mc->programChange (_mt32 ? mt32_to_gm [_program] : _program); } //////////////////////////////////////// // // Instrument_Adlib class members // //////////////////////////////////////// Instrument_Adlib::Instrument_Adlib (byte *data) { memcpy (&_instrument, data, sizeof (_instrument)); } Instrument_Adlib::Instrument_Adlib (Serializer *s) { if (!s->isSaving()) saveOrLoad (s); else memset (&_instrument, 0, sizeof (_instrument)); } void Instrument_Adlib::saveOrLoad (Serializer *s) { if (s->isSaving()) s->saveBytes (&_instrument, sizeof (_instrument)); else s->loadBytes (&_instrument, sizeof (_instrument)); } void Instrument_Adlib::send (MidiChannel *mc) { mc->sysEx_customInstrument ('ADL ', (byte *) &_instrument); } //////////////////////////////////////// // // Instrument_Roland class members // //////////////////////////////////////// Instrument_Roland::Instrument_Roland (byte *data) { memcpy (&_instrument, data, sizeof (_instrument)); memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name)); _instrument_name[10] = '\0'; if (!_native_mt32 && getEquivalentGM() >= 128) { warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name); _instrument_name[0] = '\0'; } } Instrument_Roland::Instrument_Roland (Serializer *s) { _instrument_name[0] = '\0'; if (!s->isSaving()) saveOrLoad (s); else memset (&_instrument, 0, sizeof (_instrument)); } void Instrument_Roland::saveOrLoad (Serializer *s) { if (s->isSaving()) { s->saveBytes (&_instrument, sizeof (_instrument)); } else { s->loadBytes (&_instrument, sizeof (_instrument)); memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name)); _instrument_name[10] = '\0'; if (!_native_mt32 && getEquivalentGM() >= 128) { debug (2, "MT-32 custom instrument \"%s\" not supported", _instrument_name); _instrument_name[0] = '\0'; } } // end if } void Instrument_Roland::send (MidiChannel *mc) { if (_native_mt32) { if (mc->getNumber() > 7) return; _instrument.device_id = mc->getNumber(); // Remap instrument to appropriate address space. int address = 0x008000; _instrument.address[0] = (address >> 14) & 0x7F; _instrument.address[1] = (address >> 7) & 0x7F; _instrument.address[2] = (address ) & 0x7F; // Recompute the checksum. byte checksum = 0; byte *ptr = (byte *) &_instrument + 4; int i; for (i = 4; i < sizeof (_instrument) - 1; ++i) checksum -= *ptr++; _instrument.checksum = checksum & 0x7F; mc->device()->sysEx ((byte *) &_instrument, sizeof (_instrument)); } else { // Convert to a GM program change. byte program = getEquivalentGM(); if (program < 128) mc->programChange (program); } } uint8 Instrument_Roland::getEquivalentGM() { byte i; for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) { if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10)) return roland_to_gm_map[i].program; } return 255; }