aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/imuse/instrument.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-20 20:57:26 +0000
committerMax Horn2006-02-20 20:57:26 +0000
commit81e8a2860ee066d6b863bf80bb99a592dec4cbe0 (patch)
tree3b6cd7038ccdb1767717ea2fc66f53202089f198 /engines/scumm/imuse/instrument.cpp
parent9cec516e514ac76e7a3e69fdec16e79a2486c85f (diff)
downloadscummvm-rg350-81e8a2860ee066d6b863bf80bb99a592dec4cbe0.tar.gz
scummvm-rg350-81e8a2860ee066d6b863bf80bb99a592dec4cbe0.tar.bz2
scummvm-rg350-81e8a2860ee066d6b863bf80bb99a592dec4cbe0.zip
Moved iMUSE code to the new directory engines/scumm/imuse/
svn-id: r20801
Diffstat (limited to 'engines/scumm/imuse/instrument.cpp')
-rw-r--r--engines/scumm/imuse/instrument.cpp462
1 files changed, 462 insertions, 0 deletions
diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp
new file mode 100644
index 0000000000..16d89c5ed2
--- /dev/null
+++ b/engines/scumm/imuse/instrument.cpp
@@ -0,0 +1,462 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "common/stdafx.h"
+#include "scumm/scumm.h"
+#include "scumm/saveload.h"
+#include "scumm/imuse/instrument.h"
+#include "sound/mididrv.h"
+
+namespace Scumm {
+
+static bool _native_mt32 = false;
+
+static struct {
+ const 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 ", ??? }
+};
+
+const byte Instrument::_gmRhythmMap[35] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, 40, 41, 66, 47,
+ 65, 48, 56};
+ // This emulates the percussion bank setup LEC used with the MT-32,
+ // where notes 24 - 34 were assigned instruments without reverb.
+ // It also fixes problems on GS devices that map sounds to these
+ // notes by default.
+
+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) &&
+ ((_native_mt32 == _mt32) || _native_mt32
+ ? (MidiDriver::_gmToMt32[_program] < 128)
+ : (MidiDriver::_mt32ToGm[_program] < 128)); }
+};
+
+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;
+
+ byte program = _program;
+ if (_native_mt32 != _mt32)
+ program = _native_mt32 ? MidiDriver::_gmToMt32 [program] : MidiDriver::_mt32ToGm [program];
+ if (program < 128)
+ mc->programChange (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) {
+ debug (0, "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() > 8)
+ 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 < (int)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;
+}
+
+} // End of namespace Scumm