Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

instrument.cpp

/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/scumm/imuse/instrument.cpp $
 * $Id: instrument.cpp 30944 2008-02-23 22:50:18Z sev $
 */


#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:

#include "common/pack-start.h"      // START STRUCT PACKING

      struct AdlibInstrument {
            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;
      } PACKED_STRUCT;

#include "common/pack-end.h"  // END STRUCT PACKING

      AdlibInstrument _instrument;

public:
      Instrument_Adlib(const 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:

#include "common/pack-start.h"      // START STRUCT PACKING

      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;
      } PACKED_STRUCT;

#include "common/pack-end.h"  // END STRUCT PACKING

      RolandInstrument _instrument;

      char _instrument_name [11];

      uint8 getEquivalentGM();

public:
      Instrument_Roland(const 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(const byte *instrument) {
      clear();
      if (!instrument)
            return;
      _type = itAdlib;
      _instrument = new Instrument_Adlib(instrument);
}

void Instrument::roland(const 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(const 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(const 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

Generated by  Doxygen 1.6.0   Back to index