diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp index 016ba89e7b14..b69ce552bc86 100644 --- a/engines/scumm/imuse/imuse.cpp +++ b/engines/scumm/imuse/imuse.cpp @@ -363,7 +363,7 @@ void IMuseInternal::pause(bool paused) { _paused = paused; } -int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm) { +int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad) { Common::StackLock lock(_mutex, "IMuseInternal::save_or_load()"); const SaveLoadEntry mainEntries[] = { MKLINE(IMuseInternal, _queue_end, sleUint8, VER(8)), @@ -440,7 +440,16 @@ int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm) { for (i = 0; i < 8; ++i) ser->saveLoadEntries(0, volumeFaderEntries); - if (ser->isLoading()) { + // Normally, we have to fix up the data structures after loading a + // saved game. But there are cases where we don't. For instance, The + // Macintosh version of Monkey Island 1 used to convert the Mac0 music + // resources to General MIDI and play it through iMUSE as a rough + // approximation. Now it has its own player, but old savegame still + // have the iMUSE data in them. We have to skip that data, using a + // dummy iMUSE object, but since the resource is no longer recognizable + // to iMUSE, the fixup fails hard. So yes, this is a bit of a hack. + + if (ser->isLoading() && fixAfterLoad) { // Load all sounds that we need fix_players_after_load(scumm); fix_parts_after_load(); diff --git a/engines/scumm/imuse/imuse.h b/engines/scumm/imuse/imuse.h index 23449e470b22..cce53092296a 100644 --- a/engines/scumm/imuse/imuse.h +++ b/engines/scumm/imuse/imuse.h @@ -62,7 +62,7 @@ class IMuse : public MusicEngine { public: virtual void on_timer(MidiDriver *midi) = 0; virtual void pause(bool paused) = 0; - virtual int save_or_load(Serializer *ser, ScummEngine *scumm) = 0; + virtual int save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad = true) = 0; virtual bool get_sound_active(int sound) const = 0; virtual int32 doCommand(int numargs, int args[]) = 0; virtual int clear_queue() = 0; diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h index 846e2d754585..6be564a517f8 100644 --- a/engines/scumm/imuse/imuse_internal.h +++ b/engines/scumm/imuse/imuse_internal.h @@ -518,7 +518,7 @@ class IMuseInternal : public IMuse { public: // IMuse interface void pause(bool paused); - int save_or_load(Serializer *ser, ScummEngine *scumm); + int save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad = true); bool get_sound_active(int sound) const; int32 doCommand(int numargs, int args[]); uint32 property(int prop, uint32 value); diff --git a/engines/scumm/player_mac.cpp b/engines/scumm/player_mac.cpp index 7b0f671f6d3b..cd1df51938df 100644 --- a/engines/scumm/player_mac.cpp +++ b/engines/scumm/player_mac.cpp @@ -26,6 +26,7 @@ #include "gui/message.h" #include "scumm/player_mac.h" #include "scumm/scumm.h" +#include "scumm/imuse/imuse.h" namespace Scumm { @@ -101,7 +102,8 @@ void Player_Mac::saveLoadWithSerializer(Serializer *ser) { Common::StackLock lock(_mutex); if (ser->getVersion() < VER(94)) { if (_vm->_game.id == GID_MONKEY && ser->isLoading()) { - // TODO: Skip old iMUSE save/load information + IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL); + dummyImuse->save_or_load(ser, _vm, false); } } else { static const SaveLoadEntry musicEntries[] = { @@ -109,6 +111,12 @@ void Player_Mac::saveLoadWithSerializer(Serializer *ser) { MKEND() }; + // Note: This will fail slightly when loading a savegame if + // the mixer output rate has changed, because the pitch + // modifier and remaining samples were calculated from it. As + // a result, the first note to be played will be out of tune, + // and the channels will probably be slightly out of sync. + static const SaveLoadEntry channelEntries[] = { MKLINE(Channel, _pos, sleUint16, VER(94)), MKLINE(Channel, _pitchModifier, sleInt32, VER(94)),