[Scummvm-cvs-logs] scummvm master -> 4522d182d44134d48ed0de86863f21a128f5f593

lordhoto lordhoto at gmail.com
Thu Sep 20 17:30:50 CEST 2012


This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
b5aaa1d7bc SCUMM: Don't play SBL effects in MI2 mac.
6c9f9f8356 SCUMM: Extend comment about SysEx manufacturer 0x97.
58f542d434 SCUMM: Implement support for Monkey Island 2 Mac music.
6ea51e8c45 SCUMM: Implement support for special sfx in MI2 Mac.
c3f37fb187 SCUMM: Always use the Mac sound output for MI2 Mac.
4522d182d4 Merge pull request #279 from lordhoto/mi2-mac-sound


Commit: b5aaa1d7bcc84f33076744ed0f44c7b4c306a329
    https://github.com/scummvm/scummvm/commit/b5aaa1d7bcc84f33076744ed0f44c7b4c306a329
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2012-09-19T16:59:50-07:00

Commit Message:
SCUMM: Don't play SBL effects in MI2 mac.

The original does not do this either.

Changed paths:
    engines/scumm/sound.cpp



diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 1dc026a..15701f1 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -248,7 +248,10 @@ void Sound::playSound(int soundID) {
 		_mixer->playStream(Audio::Mixer::kSFXSoundType, NULL, stream, soundID);
 	}
 	// Support for sampled sound effects in Monkey Island 1 and 2
-	else if (_vm->_game.platform != Common::kPlatformFMTowns && READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
+	else if (_vm->_game.platform != Common::kPlatformFMTowns
+	         // The Macintosh version of MI2 just ignores SBL effects.
+	         && (_vm->_game.platform != Common::kPlatformMacintosh && _vm->_game.id != GID_MONKEY2)
+	         && READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
 		debugC(DEBUG_SOUND, "Using SBL sound effect");
 
 		// SBL resources essentially contain VOC sound data.


Commit: 6c9f9f83561de8430f968638189c3fa823af932c
    https://github.com/scummvm/scummvm/commit/6c9f9f83561de8430f968638189c3fa823af932c
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2012-09-19T16:59:51-07:00

Commit Message:
SCUMM: Extend comment about SysEx manufacturer 0x97.

Changed paths:
    engines/scumm/imuse/imuse_player.cpp



diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 53ccfb3..0cab9ef 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -386,6 +386,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


Commit: 58f542d4342a3dc92e0bb6f7847493d32d1594ea
    https://github.com/scummvm/scummvm/commit/58f542d4342a3dc92e0bb6f7847493d32d1594ea
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2012-09-19T17:12:41-07:00

Commit Message:
SCUMM: Implement support for Monkey Island 2 Mac music.

This is a initial RE of the audio output Monkey Island 2 Mac uses. Support
for special sound effects is not in there yet.

Changed paths:
  A engines/scumm/imuse/mac_m68k.cpp
  A engines/scumm/imuse/mac_m68k.h
    engines/scumm/imuse/imuse.cpp
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_player.cpp
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/module.mk
    engines/scumm/scumm.cpp



diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 27a72c2..016ba89 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -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;
@@ -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;
 
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index 3b0d36e..846e2d7 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -204,6 +204,7 @@ protected:
 
 	bool _isMT32;
 	bool _isMIDI;
+	bool _supportsPercussion;
 
 protected:
 	// Player part
@@ -458,6 +459,7 @@ protected:
 	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);
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 0cab9ef..3a9c42a 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -78,6 +78,7 @@ Player::Player() :
 	_speed(128),
 	_isMT32(false),
 	_isMIDI(false),
+	_supportsPercussion(false),
 	_se(0),
 	_vol_chan(0) {
 }
@@ -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;
@@ -1011,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);
 	}
 }
 
diff --git a/engines/scumm/imuse/mac_m68k.cpp b/engines/scumm/imuse/mac_m68k.cpp
new file mode 100644
index 0000000..9d6bdd0
--- /dev/null
+++ b/engines/scumm/imuse/mac_m68k.cpp
@@ -0,0 +1,505 @@
+/* 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.
+ */
+
+#include "scumm/imuse/mac_m68k.h"
+
+#include "common/util.h"
+#include "common/macresman.h"
+#include "common/stream.h"
+
+namespace Scumm {
+
+MacM68kDriver::MacM68kDriver(Audio::Mixer *mixer)
+	: MidiDriver_Emulated(mixer) {
+}
+
+MacM68kDriver::~MacM68kDriver() {
+}
+
+int MacM68kDriver::open() {
+	if (_isOpen) {
+		return MERR_ALREADY_OPEN;
+	}
+
+	const int error = MidiDriver_Emulated::open();
+	if (error) {
+		return error;
+	}
+
+	for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
+		_channels[i].init(this, i);
+	}
+
+	memset(_voiceChannels, 0, sizeof(_voiceChannels));
+	_lastUsedVoiceChannel = 0;
+
+	loadAllInstruments();
+
+	_pitchTable[116] = 1664510;
+	_pitchTable[117] = 1763487;
+	_pitchTable[118] = 1868350;
+	_pitchTable[119] = 1979447;
+	_pitchTable[120] = 2097152;
+	_pitchTable[121] = 2221855;
+	_pitchTable[122] = 2353973;
+	_pitchTable[123] = 2493948;
+	_pitchTable[124] = 2642246;
+	_pitchTable[125] = 2799362;
+	_pitchTable[126] = 2965820;
+	_pitchTable[127] = 3142177;
+	for (int i = 115; i >= 0; --i) {
+		_pitchTable[i] = _pitchTable[i + 12] / 2;
+	}
+
+	_volumeTable = new byte[8192];
+	for (int i = 0; i < 32; ++i) {
+		for (int j = 0; j < 256; ++j) {
+			_volumeTable[i * 256 + j] = ((-128 + j) * _volumeBaseTable[i]) / 127 - 128;
+		}
+	}
+
+	_mixBuffer = 0;
+	_mixBufferLength = 0;
+
+	// We set the output sound type to music here to allow sound volume
+	// adjustment. The drawback here is that we can not control the music and
+	// sfx separately here. But the AdLib output has the same issue so it
+	// should not be that bad.
+	_mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+	return 0;
+}
+
+void MacM68kDriver::close() {
+	if (!_isOpen) {
+		return;
+	}
+
+	_mixer->stopHandle(_mixerSoundHandle);
+	_isOpen = false;
+	for (InstrumentMap::iterator i = _instruments.begin(); i != _instruments.end(); ++i) {
+		delete[] i->_value.data;
+	}
+	_instruments.clear();
+	delete[] _volumeTable;
+	_volumeTable = 0;
+	delete[] _mixBuffer;
+	_mixBuffer = 0;
+	_mixBufferLength = 0;
+}
+
+void MacM68kDriver::send(uint32 d) {
+	assert(false);
+}
+
+void MacM68kDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
+}
+
+MidiChannel *MacM68kDriver::allocateChannel() {
+	for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
+		if (_channels[i].allocate()) {
+			return &_channels[i];
+		}
+	}
+
+	return 0;
+}
+
+MacM68kDriver::Instrument MacM68kDriver::getInstrument(int idx) const {
+	InstrumentMap::const_iterator i = _instruments.find(idx);
+	if (i != _instruments.end()) {
+		return i->_value;
+	} else {
+		return _defaultInstrument;
+	}
+}
+
+void MacM68kDriver::generateSamples(int16 *buf, int len) {
+	int silentChannels = 0;
+
+	if (_mixBufferLength < len) {
+		delete[] _mixBuffer;
+
+		_mixBufferLength = len;
+		_mixBuffer = new int[_mixBufferLength];
+		assert(_mixBuffer);
+	}
+	memset(_mixBuffer, 0, sizeof(int) * _mixBufferLength);
+
+	for (int i = 0; i < kChannelCount; ++i) {
+		OutputChannel &out = _voiceChannels[i].out;
+		if (out.isFinished) {
+			++silentChannels;
+			continue;
+		}
+
+		byte *volumeTable = &_volumeTable[(out.volume / 4) * 256];
+		int *buffer = _mixBuffer;
+
+		int samplesLeft = len;
+		while (samplesLeft) {
+			out.subPos += out.pitchModifier;
+			while (out.subPos >= 0x10000) {
+				out.subPos -= 0x10000;
+				out.instrument++;
+			}
+
+			if (out.instrument >= out.end) {
+				if (!out.start) {
+					break;
+				}
+
+				out.instrument = out.start;
+				out.subPos = 0;
+			}
+
+			*buffer++ += volumeTable[*out.instrument];
+			--samplesLeft;
+		}
+
+		if (samplesLeft) {
+			out.isFinished = true;
+			while (samplesLeft--) {
+				*buffer++ += 0x80;
+			}
+		}
+	}
+
+	const int *buffer = _mixBuffer;
+	const int silenceAdd = silentChannels << 7;
+	while (len--) {
+		*buf++ = (((*buffer++ + silenceAdd) >> 3) << 8) ^ 0x8000;
+	}
+}
+
+void MacM68kDriver::loadAllInstruments() {
+	Common::MacResManager resource;
+	if (resource.open("iMUSE Setups")) {
+		for (int i = 0x3E7; i < 0x468; ++i) {
+			Common::SeekableReadStream *stream = resource.getResource(MKTAG('s', 'n', 'd', ' '), i);
+			if (stream) {
+				addInstrument(i, stream);
+				delete stream;
+			}
+		}
+
+		for (int i = 0x7D0; i < 0x8D0; ++i) {
+			Common::SeekableReadStream *stream = resource.getResource(MKTAG('s', 'n', 'd', ' '), i);
+			if (stream) {
+				addInstrument(i, stream);
+				delete stream;
+			}
+		}
+
+		InstrumentMap::iterator inst = _instruments.find(kDefaultInstrument);
+		if (inst != _instruments.end()) {
+			_defaultInstrument = inst->_value;
+		} else {
+			error("MacM68kDriver::loadAllInstruments: Could not load default instrument");
+		}
+	} else {
+		error("MacM68kDriver::loadAllInstruments: Could not load \"iMUSE Setups\"");
+	}
+}
+
+void MacM68kDriver::addInstrument(int idx, Common::SeekableReadStream *data) {
+	// We parse the "SND" files manually here, since we need special data
+	// from their header and need to work on them raw while mixing.
+	data->skip(2);
+	int count = data->readUint16BE();
+	data->skip(2 * (3 * count));
+	count = data->readUint16BE();
+	data->skip(2 * (4 * count));
+
+	Instrument inst;
+	// Skip (optional) pointer to data
+	data->skip(4);
+	inst.length        = data->readUint32BE();
+	inst.sampleRate    = data->readUint32BE();
+	inst.loopStart     = data->readUint32BE();
+	inst.loopEnd       = data->readUint32BE();
+	// Skip encoding
+	data->skip(1);
+	inst.baseFrequency = data->readByte();
+
+	inst.data = new byte[inst.length];
+	assert(inst.data);
+	data->read(inst.data, inst.length);
+	_instruments[idx] = inst;
+}
+
+void MacM68kDriver::setPitch(OutputChannel *out, int frequency) {
+	out->frequency = frequency;
+	out->isFinished = false;
+
+	const int pitchIdx = (frequency >> 7) + 60 - out->baseFrequency;
+	assert(pitchIdx >= 0);
+
+	const int low7Bits = frequency & 0x7F;
+	if (low7Bits) {
+		out->pitchModifier = _pitchTable[pitchIdx] + (((_pitchTable[pitchIdx + 1] - _pitchTable[pitchIdx]) * low7Bits) >> 7);
+	} else {
+		out->pitchModifier = _pitchTable[pitchIdx];
+	}
+}
+
+void MacM68kDriver::VoiceChannel::off() {
+	if (out.start) {
+		out.isFinished = true;
+	}
+
+	part->removeVoice(this);
+	part = 0;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::release() {
+	_allocated = false;
+	while (_voice) {
+		_voice->off();
+	}
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::send(uint32 b) {
+	uint8 type = b & 0xF0;
+	uint8 p1 = (b >> 8) & 0xFF;
+	uint8 p2 = (b >> 16) & 0xFF;
+
+	switch (type) {
+	case 0x80:
+		noteOff(p1);
+		break;
+
+	case 0x90:
+		if (p2) {
+			noteOn(p1, p2);
+		} else {
+			noteOff(p1);
+		}
+		break;
+
+	case 0xB0:
+		controlChange(p1, p2);
+		break;
+
+	case 0xE0:
+		pitchBend((p1 | (p2 << 7)) - 0x2000);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::noteOff(byte note) {
+	for (VoiceChannel *i = _voice; i; i = i->next) {
+		if (i->note == note) {
+			if (_sustain) {
+				i->sustainNoteOff = true;
+			} else {
+				i->off();
+			}
+		}
+	}
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::noteOn(byte note, byte velocity) {
+	// Do not start a not unless there is an instrument set up
+	if (!_instrument.data) {
+		return;
+	}
+
+	// Allocate a voice channel
+	VoiceChannel *voice = _owner->allocateVoice(_priority);
+	if (!voice) {
+		return;
+	}
+	addVoice(voice);
+
+	voice->note = note;
+	// This completly ignores the note's volume, but is in accordance
+	// to the original.
+	voice->out.volume = _volume;
+
+	// Set up the instrument data
+	voice->out.baseFrequency = _instrument.baseFrequency;
+	voice->out.soundStart    = _instrument.data;
+	voice->out.soundEnd      = _instrument.data + _instrument.length;
+	if (_instrument.loopEnd && _instrument.loopEnd - 12 > _instrument.loopStart) {
+		voice->out.loopStart = _instrument.data + _instrument.loopStart;
+		voice->out.loopEnd   = _instrument.data + _instrument.loopEnd;
+	} else {
+		voice->out.loopStart = 0;
+		voice->out.loopEnd   = voice->out.soundEnd;
+	}
+
+	voice->out.start = voice->out.loopStart;
+	voice->out.end   = voice->out.loopEnd;
+
+	// Set up the pitch
+	_owner->setPitch(&voice->out, (note << 7) + _pitchBend);
+
+	// Set up the sample position
+	voice->out.instrument = voice->out.soundStart;
+	voice->out.subPos = 0;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::programChange(byte program) {
+	_instrument = _owner->getInstrument(program + kProgramChangeBase);
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::pitchBend(int16 bend) {
+	_pitchBend = (bend * _pitchBendFactor) >> 6;
+	for (VoiceChannel *i = _voice; i; i = i->next) {
+		_owner->setPitch(&i->out, (i->note << 7) + _pitchBend);
+	}
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::controlChange(byte control, byte value) {
+	switch (control) {
+	// volume change
+	case 7:
+		_volume = value;
+		for (VoiceChannel *i = _voice; i; i = i->next) {
+			i->out.volume = value;
+			i->out.isFinished = false;
+		}
+		break;
+
+	// sustain
+	case 64:
+		_sustain = value;
+		if (!_sustain) {
+			for (VoiceChannel *i = _voice; i; i = i->next) {
+				if (i->sustainNoteOff) {
+					i->off();
+				}
+			}
+		}
+		break;
+
+	// all notes off
+	case 123:
+		for (VoiceChannel *i = _voice; i; i = i->next) {
+			i->off();
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::pitchBendFactor(byte value) {
+	_pitchBendFactor = value;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::priority(byte value) {
+	_priority = value;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::sysEx_customInstrument(uint32 type, const byte *instr) {
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::init(MacM68kDriver *owner, byte channel) {
+	_owner = owner;
+	_number = channel;
+	_allocated = false;
+}
+
+bool MacM68kDriver::MidiChannel_MacM68k::allocate() {
+	if (_allocated) {
+		return false;
+	}
+
+	_allocated = true;
+	_voice = 0;
+	_priority = 0;
+	memset(&_instrument, 0, sizeof(_instrument));
+	_pitchBend = 0;
+	_pitchBendFactor = 0;
+	_volume = 0;
+	return true;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::addVoice(VoiceChannel *voice) {
+	voice->next = _voice;
+	voice->prev = 0;
+	voice->part = this;
+	if (_voice) {
+		_voice->prev = voice;
+	}
+	_voice = voice;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::removeVoice(VoiceChannel *voice) {
+	VoiceChannel *i = _voice;
+	while (i && i != voice) {
+		i = i->next;
+	}
+
+	if (i) {
+		if (i->next) {
+			i->next->prev = i->prev;
+		}
+
+		if (i->prev) {
+			i->prev->next = i->next;
+		} else {
+			_voice = i->next;
+		}
+	}
+}
+
+MacM68kDriver::VoiceChannel *MacM68kDriver::allocateVoice(int priority) {
+	VoiceChannel *channel = 0;
+	for (int i = 0; i < kChannelCount; ++i) {
+		if (++_lastUsedVoiceChannel == kChannelCount) {
+			_lastUsedVoiceChannel = 0;
+		}
+
+		VoiceChannel *cur = &_voiceChannels[_lastUsedVoiceChannel];
+		if (!cur->part) {
+			memset(cur, 0, sizeof(*cur));
+			return cur;
+		} else if (!cur->next) {
+			if (cur->part->_priority <= priority) {
+				priority = cur->part->_priority;
+				channel = cur;
+			}
+		}
+	}
+
+	if (channel) {
+		channel->off();
+		memset(channel, 0, sizeof(*channel));
+	}
+
+	return channel;
+}
+
+const int MacM68kDriver::_volumeBaseTable[32] = {
+	  0,   0,   1,   1,   2,   3,   5,   6,
+	  8,  11,  13,  16,  19,  22,  26,  30,
+	 34,  38,  43,  48,  53,  58,  64,  70,
+	 76,  83,  89,  96, 104, 111, 119, 127
+};
+
+} // End of namespace Scumm
diff --git a/engines/scumm/imuse/mac_m68k.h b/engines/scumm/imuse/mac_m68k.h
new file mode 100644
index 0000000..a8686e7
--- /dev/null
+++ b/engines/scumm/imuse/mac_m68k.h
@@ -0,0 +1,176 @@
+/* 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.
+ */
+
+#ifndef SCUMM_IMUSE_MAC_M68K_H
+#define SCUMM_IMUSE_MAC_M68K_H
+
+#include "audio/softsynth/emumidi.h"
+
+#include "common/hashmap.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Scumm {
+
+class MacM68kDriver : public MidiDriver_Emulated {
+	friend class MidiChannel_MacM68k;
+public:
+	MacM68kDriver(Audio::Mixer *mixer);
+	~MacM68kDriver();
+
+	virtual int open();
+	virtual void close();
+
+	virtual void send(uint32 d);
+	virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);
+
+	virtual MidiChannel *allocateChannel();
+	virtual MidiChannel *getPercussionChannel() { return 0; }
+
+	virtual bool isStereo() const { return false; }
+	virtual int getRate() const {
+		// The original is using a frequency of approx. 22254.54546 here.
+		// To be precise it uses the 16.16 fixed point value 0x56EE8BA3.
+		return 22254;
+	}
+
+protected:
+	virtual void generateSamples(int16 *buf, int len);
+	virtual void onTimer() {}
+
+private:
+	int *_mixBuffer;
+	int _mixBufferLength;
+
+	struct Instrument {
+		uint length;
+		uint sampleRate;
+		uint loopStart;
+		uint loopEnd;
+		int baseFrequency;
+
+		byte *data;
+	};
+
+	enum {
+		kDefaultInstrument = 0x3E7,
+		kProgramChangeBase = 0x3E8
+	};
+
+	Instrument getInstrument(int idx) const;
+	typedef Common::HashMap<int, Instrument> InstrumentMap;
+	InstrumentMap _instruments;
+	Instrument _defaultInstrument;
+	void loadAllInstruments();
+	void addInstrument(int idx, Common::SeekableReadStream *data);
+
+	struct OutputChannel {
+		int pitchModifier;
+
+		const byte *instrument;
+		uint subPos;
+
+		const byte *start;
+		const byte *end;
+
+		const byte *soundStart;
+		const byte *soundEnd;
+		const byte *loopStart;
+		const byte *loopEnd;
+
+		int frequency;
+		int volume;
+
+		bool isFinished;
+
+		int baseFrequency;
+	};
+
+	void setPitch(OutputChannel *out, int frequency);
+	int _pitchTable[128];
+
+	byte *_volumeTable;
+	static const int _volumeBaseTable[32];
+
+	class MidiChannel_MacM68k;
+
+	struct VoiceChannel {
+		MidiChannel_MacM68k *part;
+		VoiceChannel *prev, *next;
+		int channel;
+		int note;
+		bool sustainNoteOff;
+		OutputChannel out;
+
+		void off();
+	};
+
+	class MidiChannel_MacM68k : public MidiChannel {
+		friend class MacM68kDriver;
+	public:
+		virtual MidiDriver *device() { return _owner; }
+		virtual byte getNumber() { return _number; }
+		virtual void release();
+
+		virtual void send(uint32 b);
+		virtual void noteOff(byte note);
+		virtual void noteOn(byte note, byte velocity);
+		virtual void programChange(byte program);
+		virtual void pitchBend(int16 bend);
+		virtual void controlChange(byte control, byte value);
+		virtual void pitchBendFactor(byte value);
+		virtual void priority(byte value);
+		virtual void sysEx_customInstrument(uint32 type, const byte *instr);
+
+		void init(MacM68kDriver *owner, byte channel);
+		bool allocate();
+
+		void addVoice(VoiceChannel *voice);
+		void removeVoice(VoiceChannel *voice);
+	private:
+		MacM68kDriver *_owner;
+		bool _allocated;
+		int _number;
+
+		VoiceChannel *_voice;
+		int _priority;
+		int _sustain;
+		Instrument _instrument;
+		int _pitchBend;
+		int _pitchBendFactor;
+		int _volume;
+	};
+
+	MidiChannel_MacM68k _channels[32];
+
+	enum {
+		kChannelCount = 8
+	};
+	VoiceChannel _voiceChannels[kChannelCount];
+	int _lastUsedVoiceChannel;
+	VoiceChannel *allocateVoice(int priority);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index 85ffc86..8f230eb 100644
--- a/engines/scumm/imuse/sysex_scumm.cpp
+++ b/engines/scumm/imuse/sysex_scumm.cpp
@@ -71,7 +71,7 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
 			part->set_pri(buf[2]);
 			part->volume(buf[3]);
 			part->set_pan(buf[4]);
-			part->_percussion = player->_isMIDI ? ((buf[5] & 0x80) > 0) : false;
+			part->_percussion = player->_supportsPercussion ? ((buf[5] & 0x80) > 0) : false;
 			part->set_transpose(buf[5]);
 			part->set_detune(buf[6]);
 			part->pitchBendFactor(buf[7]);
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 1f219f5..8499c9b 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -27,6 +27,7 @@ MODULE_OBJS := \
 	imuse/imuse_part.o \
 	imuse/imuse_player.o \
 	imuse/instrument.o \
+	imuse/mac_m68k.o \
 	imuse/pcspk.o \
 	imuse/sysex_samnmax.o \
 	imuse/sysex_scumm.o \
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index d0f46f3..02c2584 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -73,6 +73,7 @@
 #include "scumm/util.h"
 #include "scumm/verbs.h"
 #include "scumm/imuse/pcspk.h"
+#include "scumm/imuse/mac_m68k.h"
 
 #include "backends/audiocd/audiocd.h"
 
@@ -1841,7 +1842,11 @@ void ScummEngine::setupMusic(int midi) {
 		if (nativeMidiDriver != NULL && _native_mt32)
 			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 		bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB);
-		if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
+		if (_game.platform == Common::kPlatformMacintosh && _game.id == GID_MONKEY2) {
+			adlibMidiDriver = new MacM68kDriver(_mixer);
+			// The Mac driver is never MT-32.
+			_native_mt32 = false;
+		} else if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
 			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
 			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
 		} else if (_sound->_musicType == MDT_PCSPK) {


Commit: 6ea51e8c4564004ce995f4a8e1c80fdd76562c8f
    https://github.com/scummvm/scummvm/commit/6ea51e8c4564004ce995f4a8e1c80fdd76562c8f
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2012-09-19T17:13:03-07:00

Commit Message:
SCUMM: Implement support for special sfx in MI2 Mac.

This also increases the savegame version, since it introduces a new
Instrument subclass.

Changed paths:
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/instrument.cpp
    engines/scumm/imuse/instrument.h
    engines/scumm/imuse/mac_m68k.cpp
    engines/scumm/imuse/mac_m68k.h
    engines/scumm/saveload.h



diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 73e7704..d4e4740 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -27,6 +27,7 @@
 #include "common/util.h"
 #include "scumm/imuse/imuse_internal.h"
 #include "scumm/saveload.h"
+#include "scumm/scumm.h"
 
 namespace Scumm {
 
@@ -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);
 }
diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp
index 11bb4e7..61c73b1 100644
--- a/engines/scumm/imuse/instrument.cpp
+++ b/engines/scumm/imuse/instrument.cpp
@@ -278,6 +278,21 @@ private:
 	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
@@ -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);
@@ -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;
@@ -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
diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h
index a855c64..7e09e86 100644
--- a/engines/scumm/imuse/instrument.h
+++ b/engines/scumm/imuse/instrument.h
@@ -52,7 +52,8 @@ public:
 		itProgram = 1,
 		itAdLib = 2,
 		itRoland = 3,
-		itPcSpk = 4
+		itPcSpk = 4,
+		itMacSfx = 5
 	};
 
 	Instrument() : _type(0), _instrument(0) { }
@@ -72,6 +73,7 @@ public:
 	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); }
diff --git a/engines/scumm/imuse/mac_m68k.cpp b/engines/scumm/imuse/mac_m68k.cpp
index 9d6bdd0..4d7a6a6 100644
--- a/engines/scumm/imuse/mac_m68k.cpp
+++ b/engines/scumm/imuse/mac_m68k.cpp
@@ -111,6 +111,7 @@ void MacM68kDriver::send(uint32 d) {
 }
 
 void MacM68kDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
+	assert(false);
 }
 
 MidiChannel *MacM68kDriver::allocateChannel() {
@@ -416,6 +417,10 @@ void MacM68kDriver::MidiChannel_MacM68k::priority(byte value) {
 }
 
 void MacM68kDriver::MidiChannel_MacM68k::sysEx_customInstrument(uint32 type, const byte *instr) {
+	assert(instr);
+	if (type == 'MAC ') {
+		_instrument = _owner->getInstrument(*instr + kSysExBase);
+	}
 }
 
 void MacM68kDriver::MidiChannel_MacM68k::init(MacM68kDriver *owner, byte channel) {
diff --git a/engines/scumm/imuse/mac_m68k.h b/engines/scumm/imuse/mac_m68k.h
index a8686e7..59e2f68 100644
--- a/engines/scumm/imuse/mac_m68k.h
+++ b/engines/scumm/imuse/mac_m68k.h
@@ -74,7 +74,8 @@ private:
 
 	enum {
 		kDefaultInstrument = 0x3E7,
-		kProgramChangeBase = 0x3E8
+		kProgramChangeBase = 0x3E8,
+		kSysExBase         = 0x7D0
 	};
 
 	Instrument getInstrument(int idx) const;
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index d5f7ea5..a640bc1 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 92
+#define CURRENT_VER 93
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead


Commit: c3f37fb1870fb946692b6d67e6d32d2958be2b3a
    https://github.com/scummvm/scummvm/commit/c3f37fb1870fb946692b6d67e6d32d2958be2b3a
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2012-09-19T19:07:18-07:00

Commit Message:
SCUMM: Always use the Mac sound output for MI2 Mac.

Formerly it wasn't used when the user selected a MIDI output in the options.
Thanks to clone2727 for noticing.

Changed paths:
    engines/scumm/scumm.cpp



diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 02c2584..7b37517 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1836,21 +1836,31 @@ void ScummEngine::setupMusic(int midi) {
 	} else if (_game.version >= 3 && _game.heversion <= 62) {
 		MidiDriver *nativeMidiDriver = 0;
 		MidiDriver *adlibMidiDriver = 0;
-
-		if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK)
-			nativeMidiDriver = MidiDriver::createMidi(dev);
-		if (nativeMidiDriver != NULL && _native_mt32)
-			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 		bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB);
+		bool useOnlyNative = false;
+
 		if (_game.platform == Common::kPlatformMacintosh && _game.id == GID_MONKEY2) {
-			adlibMidiDriver = new MacM68kDriver(_mixer);
+			// We setup this driver as native MIDI driver to avoid playback
+			// of the Mac music via a selected MIDI device.
+			nativeMidiDriver = new MacM68kDriver(_mixer);
 			// The Mac driver is never MT-32.
 			_native_mt32 = false;
-		} else if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
-			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
-			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
-		} else if (_sound->_musicType == MDT_PCSPK) {
-			adlibMidiDriver = new PcSpkDriver(_mixer);
+			// Ignore non-native drivers. This also ignores the multi MIDI setting.
+			useOnlyNative = true;
+		} else if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK) {
+			nativeMidiDriver = MidiDriver::createMidi(dev);
+		}
+
+		if (nativeMidiDriver != NULL && _native_mt32)
+			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+		if (!useOnlyNative) {
+			if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
+				adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
+				adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
+			} else if (_sound->_musicType == MDT_PCSPK) {
+				adlibMidiDriver = new PcSpkDriver(_mixer);
+			}
 		}
 
 		_imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver);


Commit: 4522d182d44134d48ed0de86863f21a128f5f593
    https://github.com/scummvm/scummvm/commit/4522d182d44134d48ed0de86863f21a128f5f593
Author: Johannes Schickel (lordhoto at gmail.com)
Date: 2012-09-20T08:29:03-07:00

Commit Message:
Merge pull request #279 from lordhoto/mi2-mac-sound

Add support for Monkey Island 2 Mac sound.

Changed paths:
  A engines/scumm/imuse/mac_m68k.cpp
  A engines/scumm/imuse/mac_m68k.h
    engines/scumm/imuse/imuse.cpp
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/imuse_player.cpp
    engines/scumm/imuse/instrument.cpp
    engines/scumm/imuse/instrument.h
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/module.mk
    engines/scumm/saveload.h
    engines/scumm/scumm.cpp
    engines/scumm/sound.cpp









More information about the Scummvm-git-logs mailing list