Skip to content

Commit

Permalink
Merge pull request #279 from lordhoto/mi2-mac-sound
Browse files Browse the repository at this point in the history
Add support for Monkey Island 2 Mac sound.
  • Loading branch information
lordhoto committed Sep 20, 2012
2 parents 0677871 + c3f37fb commit 4522d18
Show file tree
Hide file tree
Showing 13 changed files with 839 additions and 14 deletions.
41 changes: 40 additions & 1 deletion engines/scumm/imuse/imuse.cpp
Expand Up @@ -164,7 +164,7 @@ bool IMuseInternal::isMT32(int sound) {
return true;

case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2
return true;
return false;

case MKTAG('G', 'M', 'D', ' '):
return false;
Expand Down Expand Up @@ -226,6 +226,45 @@ bool IMuseInternal::isMIDI(int sound) {
return false;
}

bool IMuseInternal::supportsPercussion(int sound) {
byte *ptr = g_scumm->_res->_types[rtSound][sound]._address;
if (ptr == NULL)
return false;

uint32 tag = READ_BE_UINT32(ptr);
switch (tag) {
case MKTAG('A', 'D', 'L', ' '):
case MKTAG('A', 'S', 'F', 'X'): // Special AD class for old AdLib sound effects
case MKTAG('S', 'P', 'K', ' '):
return false;

case MKTAG('A', 'M', 'I', ' '):
case MKTAG('R', 'O', 'L', ' '):
return true;

case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2
// This is MIDI, i.e. uses MIDI style program changes, but without a
// special percussion channel.
return false;

case MKTAG('G', 'M', 'D', ' '):
case MKTAG('M', 'I', 'D', 'I'): // Occurs in Sam & Max
return true;
}

// Old style 'RO' has equivalent properties to 'ROL'
if (ptr[0] == 'R' && ptr[1] == 'O')
return true;
// Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
// FIXME: Right now we're pretending it's GM.
if (ptr[4] == 'S' && ptr[5] == 'O')
return true;

error("Unknown music type: '%c%c%c%c'", (char)tag >> 24, (char)tag >> 16, (char)tag >> 8, (char)tag);

return false;
}

MidiDriver *IMuseInternal::getBestMidiDriver(int sound) {
MidiDriver *driver = NULL;

Expand Down
2 changes: 2 additions & 0 deletions engines/scumm/imuse/imuse_internal.h
Expand Up @@ -204,6 +204,7 @@ class Player : public MidiDriver_BASE {

bool _isMT32;
bool _isMIDI;
bool _supportsPercussion;

protected:
// Player part
Expand Down Expand Up @@ -458,6 +459,7 @@ class IMuseInternal : public IMuse {
byte *findStartOfSound(int sound, int ct = (kMThd | kFORM));
bool isMT32(int sound);
bool isMIDI(int sound);
bool supportsPercussion(int sound);
int get_queue_sound_status(int sound) const;
void handle_marker(uint id, byte data);
int get_channel_volume(uint a);
Expand Down
13 changes: 12 additions & 1 deletion engines/scumm/imuse/imuse_part.cpp
Expand Up @@ -27,6 +27,7 @@
#include "common/util.h"
#include "scumm/imuse/imuse_internal.h"
#include "scumm/saveload.h"
#include "scumm/scumm.h"

namespace Scumm {

Expand Down Expand Up @@ -365,7 +366,17 @@ void Part::set_instrument(uint b) {
_bank = (byte)(b >> 8);
if (_bank)
error("Non-zero instrument bank selection. Please report this");
_instrument.program((byte)b, _player->isMT32());
// HACK: Horrible hack to allow tracing of program change source.
// The Mac version of Monkey Island 2 uses a different program "bank"
// when it gets program change events through the iMuse SysEx handler.
// We emulate this by introducing a special instrument, which sets
// the instrument via sysEx_customInstrument. This seems to be
// exclusively used for special sound effects like the "spit" sound.
if (g_scumm->_game.id == GID_MONKEY2 && g_scumm->_game.platform == Common::kPlatformMacintosh) {
_instrument.macSfx(b);
} else {
_instrument.program((byte)b, _player->isMT32());
}
if (clearToTransmit())
_instrument.send(_mc);
}
Expand Down
5 changes: 5 additions & 0 deletions engines/scumm/imuse/imuse_player.cpp
Expand Up @@ -78,6 +78,7 @@ Player::Player() :
_speed(128),
_isMT32(false),
_isMIDI(false),
_supportsPercussion(false),
_se(0),
_vol_chan(0) {
}
Expand All @@ -103,6 +104,7 @@ bool Player::startSound(int sound, MidiDriver *midi) {

_isMT32 = _se->isMT32(sound);
_isMIDI = _se->isMIDI(sound);
_supportsPercussion = _se->supportsPercussion(sound);

_parts = NULL;
_active = true;
Expand Down Expand Up @@ -386,6 +388,8 @@ void Player::sysEx(const byte *p, uint16 len) {
// SysEx manufacturer 0x97 has been spotted in the
// Monkey Island 2 AdLib music, so don't make this a
// fatal error. See bug #1481383.
// The Macintosh version of Monkey Island 2 simply
// ignores these SysEx events too.
if (a == 0)
warning("Unknown SysEx manufacturer 0x00 0x%02X 0x%02X", p[0], p[1]);
else
Expand Down Expand Up @@ -1009,6 +1013,7 @@ void Player::fixAfterLoad() {
_parser->jumpToTick(_music_tick); // start_seq_sound already switched tracks
_isMT32 = _se->isMT32(_id);
_isMIDI = _se->isMIDI(_id);
_supportsPercussion = _se->supportsPercussion(_id);
}
}

Expand Down
60 changes: 60 additions & 0 deletions engines/scumm/imuse/instrument.cpp
Expand Up @@ -278,6 +278,21 @@ class Instrument_PcSpk : public InstrumentInternal {
byte _instrument[23];
};

class Instrument_MacSfx : public InstrumentInternal {
private:
byte _program;

public:
Instrument_MacSfx(byte program);
Instrument_MacSfx(Serializer *s);
void saveOrLoad(Serializer *s);
void send(MidiChannel *mc);
void copy_to(Instrument *dest) { dest->macSfx(_program); }
bool is_valid() {
return (_program < 128);
}
};

////////////////////////////////////////
//
// Instrument class members
Expand Down Expand Up @@ -326,6 +341,14 @@ void Instrument::pcspk(const byte *instrument) {
_instrument = new Instrument_PcSpk(instrument);
}

void Instrument::macSfx(byte prog) {
clear();
if (prog > 127)
return;
_type = itMacSfx;
_instrument = new Instrument_MacSfx(prog);
}

void Instrument::saveOrLoad(Serializer *s) {
if (s->isSaving()) {
s->saveByte(_type);
Expand All @@ -349,6 +372,9 @@ void Instrument::saveOrLoad(Serializer *s) {
case itPcSpk:
_instrument = new Instrument_PcSpk(s);
break;
case itMacSfx:
_instrument = new Instrument_MacSfx(s);
break;
default:
warning("No known instrument classification #%d", (int)_type);
_type = itNone;
Expand Down Expand Up @@ -528,4 +554,38 @@ void Instrument_PcSpk::send(MidiChannel *mc) {
mc->sysEx_customInstrument('SPK ', (byte *)&_instrument);
}

////////////////////////////////////////
//
// Instrument_MacSfx class members
//
////////////////////////////////////////

Instrument_MacSfx::Instrument_MacSfx(byte program) :
_program(program) {
if (program > 127) {
_program = 255;
}
}

Instrument_MacSfx::Instrument_MacSfx(Serializer *s) {
_program = 255;
if (!s->isSaving()) {
saveOrLoad(s);
}
}

void Instrument_MacSfx::saveOrLoad(Serializer *s) {
if (s->isSaving()) {
s->saveByte(_program);
} else {
_program = s->loadByte();
}
}

void Instrument_MacSfx::send(MidiChannel *mc) {
if (_program > 127) {
return;
}
mc->sysEx_customInstrument('MAC ', &_program);
}
} // End of namespace Scumm
4 changes: 3 additions & 1 deletion engines/scumm/imuse/instrument.h
Expand Up @@ -52,7 +52,8 @@ class Instrument {
itProgram = 1,
itAdLib = 2,
itRoland = 3,
itPcSpk = 4
itPcSpk = 4,
itMacSfx = 5
};

Instrument() : _type(0), _instrument(0) { }
Expand All @@ -72,6 +73,7 @@ class Instrument {
void adlib(const byte *instrument);
void roland(const byte *instrument);
void pcspk(const byte *instrument);
void macSfx(byte program);

byte getType() { return _type; }
bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
Expand Down

0 comments on commit 4522d18

Please sign in to comment.