diff options
Diffstat (limited to 'engines/scumm')
| -rw-r--r-- | engines/scumm/POTFILES | 3 | ||||
| -rw-r--r-- | engines/scumm/actor.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/configure.engine | 5 | ||||
| -rw-r--r-- | engines/scumm/detection.cpp | 26 | ||||
| -rw-r--r-- | engines/scumm/detection_tables.h | 7 | ||||
| -rw-r--r-- | engines/scumm/gfx.cpp | 13 | ||||
| -rw-r--r-- | engines/scumm/he/script_v100he.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/he/script_v70he.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/he/script_v72he.cpp | 4 | ||||
| -rw-r--r-- | engines/scumm/imuse_digi/dimuse_sndmgr.cpp | 13 | ||||
| -rw-r--r-- | engines/scumm/insane/insane_enemy.cpp | 1 | ||||
| -rw-r--r-- | engines/scumm/module.mk | 33 | ||||
| -rw-r--r-- | engines/scumm/players/player_ad.cpp | 959 | ||||
| -rw-r--r-- | engines/scumm/players/player_ad.h | 190 | ||||
| -rw-r--r-- | engines/scumm/players/player_apple2.cpp (renamed from engines/scumm/player_apple2.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_apple2.h (renamed from engines/scumm/player_apple2.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_mac.cpp (renamed from engines/scumm/player_mac.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_mac.h (renamed from engines/scumm/player_mac.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_mod.cpp (renamed from engines/scumm/player_mod.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_mod.h (renamed from engines/scumm/player_mod.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_nes.cpp (renamed from engines/scumm/player_nes.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_nes.h (renamed from engines/scumm/player_nes.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_pce.cpp (renamed from engines/scumm/player_pce.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_pce.h (renamed from engines/scumm/player_pce.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_sid.cpp (renamed from engines/scumm/player_sid.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_sid.h (renamed from engines/scumm/player_sid.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_towns.cpp (renamed from engines/scumm/player_towns.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_towns.h (renamed from engines/scumm/player_towns.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_v1.cpp (renamed from engines/scumm/player_v1.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v1.h (renamed from engines/scumm/player_v1.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2.cpp (renamed from engines/scumm/player_v2.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2.h (renamed from engines/scumm/player_v2.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2a.cpp (renamed from engines/scumm/player_v2a.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2a.h (renamed from engines/scumm/player_v2a.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2base.cpp (renamed from engines/scumm/player_v2base.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2base.h (renamed from engines/scumm/player_v2base.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2cms.cpp (renamed from engines/scumm/player_v2cms.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v2cms.h (renamed from engines/scumm/player_v2cms.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v3a.cpp (renamed from engines/scumm/player_v3a.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v3a.h (renamed from engines/scumm/player_v3a.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v3m.cpp (renamed from engines/scumm/player_v3m.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v3m.h (renamed from engines/scumm/player_v3m.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/players/player_v4a.cpp (renamed from engines/scumm/player_v4a.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v4a.h (renamed from engines/scumm/player_v4a.h) | 4 | ||||
| -rw-r--r-- | engines/scumm/players/player_v5m.cpp (renamed from engines/scumm/player_v5m.cpp) | 2 | ||||
| -rw-r--r-- | engines/scumm/players/player_v5m.h (renamed from engines/scumm/player_v5m.h) | 6 | ||||
| -rw-r--r-- | engines/scumm/saveload.cpp | 101 | ||||
| -rw-r--r-- | engines/scumm/saveload.h | 2 | ||||
| -rw-r--r-- | engines/scumm/script_v5.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/script_v6.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/scumm-md5.h | 4 | ||||
| -rw-r--r-- | engines/scumm/scumm.cpp | 36 | ||||
| -rw-r--r-- | engines/scumm/scumm.h | 10 | ||||
| -rw-r--r-- | engines/scumm/sound.cpp | 26 | ||||
| -rw-r--r-- | engines/scumm/vars.cpp | 6 |
55 files changed, 1369 insertions, 190 deletions
diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES new file mode 100644 index 0000000000..6034320259 --- /dev/null +++ b/engines/scumm/POTFILES @@ -0,0 +1,3 @@ +engines/scumm/dialogs.cpp +engines/scumm/help.cpp +engines/scumm/scumm.cpp diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 5c148a7b57..4e14473921 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -1485,7 +1485,7 @@ void ScummEngine::playActorSounds() { int sound; for (i = 1; i < _numActors; i++) { - if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom() && _actors[i]->_sound) { + if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom()) { _currentScript = 0xFF; if (_game.version == 0) { sound = v0ActorSounds[i - 1] & 0x3F; diff --git a/engines/scumm/configure.engine b/engines/scumm/configure.engine new file mode 100644 index 0000000000..e1de788061 --- /dev/null +++ b/engines/scumm/configure.engine @@ -0,0 +1,5 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine scumm "SCUMM" yes "scumm_7_8 he" "v0-v6 games" +add_engine scumm_7_8 "v7 & v8 games" yes +add_engine he "HE71+ games" yes diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 170ca0993c..aa7e60930a 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -1223,8 +1223,8 @@ const char *ScummMetaEngine::getOriginalCopyright() const { } namespace Scumm { - extern bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion); -} +bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion); +} // End of namespace Scumm int ScummMetaEngine::getMaximumSaveSlot() const { return 99; } @@ -1262,25 +1262,21 @@ void ScummMetaEngine::removeSaveState(const char *target, int slot) const { } SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int slot) const { - Common::String filename = ScummEngine::makeSavegameName(target, slot, false); - Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename); - - if (!in) - return SaveStateDescriptor(); - Common::String saveDesc; - Scumm::getSavegameName(in, saveDesc, 0); // FIXME: heversion?!? - delete in; + Graphics::Surface *thumbnail = nullptr; + SaveStateMetaInfos infos; + memset(&infos, 0, sizeof(infos)); + SaveStateMetaInfos *infoPtr = &infos; - // TODO: Cleanup - Graphics::Surface *thumbnail = ScummEngine::loadThumbnailFromSlot(target, slot); + // FIXME: heversion?!? + if (!ScummEngine::querySaveMetaInfos(target, slot, 0, saveDesc, thumbnail, infoPtr)) { + return SaveStateDescriptor(); + } SaveStateDescriptor desc(slot, saveDesc); desc.setThumbnail(thumbnail); - SaveStateMetaInfos infos; - memset(&infos, 0, sizeof(infos)); - if (ScummEngine::loadInfosFromSlot(target, slot, &infos)) { + if (infoPtr) { int day = (infos.date >> 24) & 0xFF; int month = (infos.date >> 16) & 0xFF; int year = infos.date & 0xFFFF; diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index aaf84c1471..6717ea9b06 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -299,7 +299,11 @@ static const GameSettings gameVariantsTable[] = { // Changed o_getResourceSize to cover all resource types {"farm", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, - {"puttzoo", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "", 0, GID_PUTTZOO, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 72", 0, GID_PUTTZOO, 6, 72, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 98.5", 0, GID_PUTTZOO, 6, 98, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 99", 0, GID_PUTTZOO, 6, 99, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 100", 0, GID_PUTTZOO, 6, 100, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Added VAR_PLATFORM variable {"jungle", "", 0, GID_HEGAME, 6, 74, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, @@ -860,6 +864,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "puttzoo", "Zoo Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "Putt-Putt Saves the Zoo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "game", kGenHEPC, Common::EN_ANY, Common::kPlatformIOS, 0 }, + { "puttzoo", "pp3_unlocked", kGenHEPC, Common::EN_ANY, Common::kPlatformWindows, 0 }, { "SamsFunShop", "SamsFunShop", kGenHEPC, UNK_LANG, UNK, 0 }, { "SamsFunShop", "Sam's FunShop", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 4c1fdaf673..1bb4a28f65 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -1769,11 +1769,8 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const // Check whether lights are turned on or not const bool lightsOn = _vm->isLightOn(); - if (_vm->_game.features & GF_SMALL_HEADER) { + if ((_vm->_game.features & GF_SMALL_HEADER) || _vm->_game.version == 8) { smap_ptr = ptr; - } else if (_vm->_game.version == 8) { - // Skip to the BSTR->WRAP->OFFS chunk - smap_ptr = ptr + 24; } else { smap_ptr = _vm->findResource(MKTAG('S','M','A','P'), ptr); assert(smap_ptr); @@ -1887,8 +1884,14 @@ bool Gdi::drawStrip(byte *dstPtr, VirtScreen *vs, int x, int y, const int width, smapLen = READ_LE_UINT32(smap_ptr); if (stripnr * 4 + 4 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 4); + } else if (_vm->_game.version == 8) { + smapLen = READ_BE_UINT32(smap_ptr + 4); + // Skip to the BSTR->WRAP->OFFS chunk + smap_ptr += 24; + if (stripnr * 4 + 8 < smapLen) + offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 8); } else { - smapLen = READ_BE_UINT32(smap_ptr); + smapLen = READ_BE_UINT32(smap_ptr + 4); if (stripnr * 4 + 8 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 8); } diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index 6d030bb125..c26e3f57ea 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -2148,7 +2148,7 @@ void ScummEngine_v100he::o100_systemOps() { break; case 132: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 133: quitGame(); diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp index adb2fcac2e..9259e0db2f 100644 --- a/engines/scumm/he/script_v70he.cpp +++ b/engines/scumm/he/script_v70he.cpp @@ -309,7 +309,7 @@ void ScummEngine_v70he::o70_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 7c5221e146..cfa2be7275 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -158,7 +158,7 @@ int ScummEngine_v72he::readArray(int array, int idx2, int idx1) { ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || @@ -1199,7 +1199,7 @@ void ScummEngine_v72he::o72_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp index abd0d68e56..26e248fbca 100644 --- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -443,11 +443,13 @@ ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::openSound(int32 soundId, const char } else if (soundName[0] == 0) { if (sound->bundle->decompressSampleByIndex(soundId, 0, 0x2000, &ptr, 0, header_outside) == 0 || ptr == NULL) { closeSound(sound); + free(ptr); return NULL; } } else { if (sound->bundle->decompressSampleByName(soundName, 0, 0x2000, &ptr, header_outside) == 0 || ptr == NULL) { closeSound(sound); + free(ptr); return NULL; } } @@ -667,15 +669,18 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (scumm_stricmp(fileName, soundDesc->lastFileName) != 0) { int32 offs = 0, len = 0; Common::SeekableReadStream *cmpFile; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) uint8 soundMode = 0; +#endif sprintf(fileName, "%s_reg%03d.fla", soundDesc->name, region); cmpFile = soundDesc->bundle->getFile(fileName, offs, len); if (len) { #ifndef USE_FLAC error("FLAC library compiled support needed"); -#endif +#else soundMode = 3; +#endif } if (!len) { sprintf(fileName, "%s_reg%03d.ogg", soundDesc->name, region); @@ -683,8 +688,9 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (len) { #ifndef USE_VORBIS error("Vorbis library compiled support needed"); -#endif +#else soundMode = 2; +#endif } } if (!len) { @@ -693,8 +699,9 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (len) { #ifndef USE_MAD error("Mad library compiled support needed"); -#endif +#else soundMode = 1; +#endif } } assert(len); diff --git a/engines/scumm/insane/insane_enemy.cpp b/engines/scumm/insane/insane_enemy.cpp index 3876966fd1..d711b63342 100644 --- a/engines/scumm/insane/insane_enemy.cpp +++ b/engines/scumm/insane/insane_enemy.cpp @@ -1519,6 +1519,7 @@ void Insane::chooseEnemyWeaponAnim(int32 buttons) { case INV_BOOT: case INV_HAND: case INV_DUST: + // fallthrough default: switchEnemyWeapon(); } diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 28884d7f78..d43db1e5f1 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -35,22 +35,23 @@ MODULE_OBJS := \ midiparser_ro.o \ object.o \ palette.o \ - player_apple2.o \ - player_mac.o \ - player_mod.o \ - player_nes.o \ - player_pce.o \ - player_sid.o \ - player_towns.o \ - player_v1.o \ - player_v2.o \ - player_v2a.o \ - player_v2base.o \ - player_v2cms.o \ - player_v3a.o \ - player_v3m.o \ - player_v4a.o \ - player_v5m.o \ + players/player_ad.o \ + players/player_apple2.o \ + players/player_mac.o \ + players/player_mod.o \ + players/player_nes.o \ + players/player_pce.o \ + players/player_sid.o \ + players/player_towns.o \ + players/player_v1.o \ + players/player_v2.o \ + players/player_v2a.o \ + players/player_v2base.o \ + players/player_v2cms.o \ + players/player_v3a.o \ + players/player_v3m.o \ + players/player_v4a.o \ + players/player_v5m.o \ resource_v2.o \ resource_v3.o \ resource_v4.o \ diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp new file mode 100644 index 0000000000..20630e1cb9 --- /dev/null +++ b/engines/scumm/players/player_ad.cpp @@ -0,0 +1,959 @@ +/* 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/players/player_ad.h" +#include "scumm/imuse/imuse.h" +#include "scumm/scumm.h" +#include "scumm/resource.h" + +#include "audio/fmopl.h" + +#include "common/textconsole.h" +#include "common/config-manager.h" + +namespace Scumm { + +#define AD_CALLBACK_FREQUENCY 472 + +Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer) + : _vm(scumm), _mixer(mixer), _rate(mixer->getOutputRate()) { + _opl2 = OPL::Config::create(); + if (!_opl2->init(_rate)) { + error("Could not initialize OPL2 emulator"); + } + + _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY; + _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY; + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; + + memset(_registerBackUpTable, 0, sizeof(_registerBackUpTable)); + writeReg(0x01, 0x00); + writeReg(0xBD, 0x00); + writeReg(0x08, 0x00); + writeReg(0x01, 0x20); + + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _engineMusicTimer = 0; + _soundPlaying = -1; + + _curOffset = 0; + + _sfxTimer = 4; + _rndSeed = 1; + + memset(_channels, 0, sizeof(_channels)); + memset(_sfxResource, 0, sizeof(_sfxResource)); + memset(_sfxPriority, 0, sizeof(_sfxPriority)); +} + +Player_AD::~Player_AD() { + _mixer->stopHandle(_soundHandle); + + stopAllSounds(); + Common::StackLock lock(_mutex); + delete _opl2; + _opl2 = 0; +} + +void Player_AD::setMusicVolume(int vol) { + // HACK: We ignore the parameter and set up the volume specified in the + // config manager. This allows us to differentiate between music and sfx + // volume changes. + setupVolume(); +} + +void Player_AD::startSound(int sound) { + Common::StackLock lock(_mutex); + + // Query the sound resource + const byte *res = _vm->getResourceAddress(rtSound, sound); + + if (res[2] == 0x80) { + // Stop the current sounds + stopAllSounds(); + + // Lock the new music resource + _soundPlaying = sound; + _vm->_res->lock(rtSound, _soundPlaying); + + // Start the new music resource + _resource = res; + startMusic(); + } else { + // Only try to start a sfx when no music is playing. + if (_soundPlaying == -1) { + const byte priority = res[0]; + const byte channel = res[1]; + + // Check for out of bounds access + if (channel >= 3) { + warning("AdLib sfx resource %d uses channel %d", sound, channel); + return; + } + + // Check whether the channel is free or the priority of the new + // sfx resource is above the old one. + if (_channels[channel * 3 + 0].state + || _channels[channel * 3 + 1].state + || _channels[channel * 3 + 2].state) { + if (_sfxPriority[channel] > priority) { + return; + } + } + + // Lock the new resource + _sfxResource[channel] = sound; + _sfxPriority[channel] = priority; + _vm->_res->lock(rtSound, sound); + + // Start the actual sfx resource + _resource = res; + startSfx(); + } + } + + // Setup the sound volume + setupVolume(); +} + +void Player_AD::stopSound(int sound) { + Common::StackLock lock(_mutex); + + if (sound == _soundPlaying) { + stopAllSounds(); + } else { + for (int i = 0; i < 3; ++i) { + if (_sfxResource[i] == sound) { + if (_channels[i * 3 + 0].state + || _channels[i * 3 + 1].state + || _channels[i * 3 + 2].state) { + // Unlock the sound resource + _vm->_res->unlock(rtSound, sound); + + // Stop the actual sfx playback + _channels[i * 3 + 0].state = 0; + _channels[i * 3 + 1].state = 0; + _channels[i * 3 + 2].state = 0; + clearChannel(i * 3 + 0); + clearChannel(i * 3 + 1); + clearChannel(i * 3 + 2); + } + } + } + } +} + +void Player_AD::stopAllSounds() { + Common::StackLock lock(_mutex); + + // Unlock the music resource if present + if (_soundPlaying != -1) { + _vm->_res->unlock(rtSound, _soundPlaying); + _soundPlaying = -1; + } + + // Stop the music playback + _curOffset = 0; + + // Unloack all used sfx resources + for (int i = 0; i < 3; ++i) { + if (_channels[i * 3 + 0].state || _channels[i * 3 + 1].state || _channels[i * 3 + 2].state) { + _vm->_res->unlock(rtSound, _sfxResource[i]); + } + } + + // Reset all the sfx channels + for (int i = 0; i < 9; ++i) { + _channels[i].state = 0; + clearChannel(i); + } + + writeReg(0xBD, 0x00); +} + +int Player_AD::getMusicTimer() { + return _engineMusicTimer; +} + +int Player_AD::getSoundStatus(int sound) const { + return (sound == _soundPlaying); +} + +void Player_AD::saveLoadWithSerializer(Serializer *ser) { + Common::StackLock lock(_mutex); + + if (ser->getVersion() < VER(95)) { + IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL); + dummyImuse->save_or_load(ser, _vm, false); + delete dummyImuse; + return; + } + + // TODO: Be nicer than the original and save the data to continue the + // currently played sound resources on load? +} + +int Player_AD::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + + int len = numSamples; + + while (len > 0) { + if (!_samplesTillCallback) { + // Run the update callback for music or sfx depending on which is + // active. + if (_curOffset) { + updateMusic(); + } else { + updateSfx(); + } + + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= AD_CALLBACK_FREQUENCY) { + ++_samplesTillCallback; + _samplesTillCallbackRemainder -= AD_CALLBACK_FREQUENCY; + } + } + + const int samplesToRead = MIN(len, _samplesTillCallback); + _opl2->readBuffer(buffer, samplesToRead); + + buffer += samplesToRead; + len -= samplesToRead; + _samplesTillCallback -= samplesToRead; + } + + return numSamples; +} + +void Player_AD::setupVolume() { + // Setup the correct volume + int soundVolumeMusic = CLIP<int>(ConfMan.getInt("music_volume"), 0, Audio::Mixer::kMaxChannelVolume); + int soundVolumeSfx = CLIP<int>(ConfMan.getInt("sfx_volume"), 0, Audio::Mixer::kMaxChannelVolume); + if (ConfMan.hasKey("mute")) { + if (ConfMan.getBool("mute")) { + soundVolumeMusic = 0; + soundVolumeSfx = 0; + } + } + + // In case a music is being played set the music volume. Set the sfx + // volume otherwise. This is safe because in the latter case either + // sfx are playing or there is no sound being played at all. + if (_soundPlaying != -1) { + _mixer->setChannelVolume(_soundHandle, soundVolumeMusic); + } else { + _mixer->setChannelVolume(_soundHandle, soundVolumeSfx); + } +} + +void Player_AD::writeReg(int r, int v) { + if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) { + _registerBackUpTable[r] = v; + } + _opl2->writeReg(r, v); +} + +uint8 Player_AD::readReg(int r) const { + if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) { + return _registerBackUpTable[r]; + } else { + return 0; + } +} + +void Player_AD::setupChannel(const uint channel, const byte *instrOffset) { + instrOffset += 2; + writeReg(0xC0 + channel, *instrOffset++); + setupOperator(_operatorOffsetTable[channel * 2 + 0], instrOffset); + setupOperator(_operatorOffsetTable[channel * 2 + 1], instrOffset); +} + +void Player_AD::setupOperator(const uint opr, const byte *&instrOffset) { + writeReg(0x20 + opr, *instrOffset++); + writeReg(0x40 + opr, *instrOffset++); + writeReg(0x60 + opr, *instrOffset++); + writeReg(0x80 + opr, *instrOffset++); + writeReg(0xE0 + opr, *instrOffset++); +} + +const int Player_AD::_operatorOffsetTable[18] = { + 0, 3, 1, 4, + 2, 5, 8, 11, + 9, 12, 10, 13, + 16, 19, 17, 20, + 18, 21 +}; + +// Music + +void Player_AD::startMusic() { + memset(_instrumentOffset, 0, sizeof(_instrumentOffset)); + memset(_channelLastEvent, 0, sizeof(_channelLastEvent)); + memset(_channelFrequency, 0, sizeof(_channelFrequency)); + memset(_channelB0Reg, 0, sizeof(_channelB0Reg)); + + _voiceChannels = 0; + uint instruments = _resource[10]; + for (uint i = 0; i < instruments; ++i) { + const int instrIndex = _resource[11 + i] - 1; + if (0 <= instrIndex && instrIndex < 16) { + _instrumentOffset[instrIndex] = i * 16 + 16 + 3; + _voiceChannels |= _resource[_instrumentOffset[instrIndex] + 13]; + } + } + + if (_voiceChannels) { + _mdvdrState = 0x20; + _voiceChannels = 6; + } else { + _mdvdrState = 0; + _voiceChannels = 9; + } + + _curOffset = 0x93; + // TODO: is this the same for Loom? + _nextEventTimer = 40; + _engineMusicTimer = 0; + _internalMusicTimer = 0; + _musicTimer = 0; + + writeReg(0xBD, _mdvdrState); + + const bool isLoom = (_vm->_game.id == GID_LOOM); + _timerLimit = isLoom ? 473 : 256; + _musicTicks = _resource[3] * (isLoom ? 2 : 1); + _loopFlag = (_resource[4] == 0); + _musicLoopStart = READ_LE_UINT16(_resource + 5); +} + +void Player_AD::updateMusic() { + _musicTimer += _musicTicks; + if (_musicTimer < _timerLimit) { + return; + } + _musicTimer -= _timerLimit; + + ++_internalMusicTimer; + if (_internalMusicTimer > 120) { + _internalMusicTimer = 0; + ++_engineMusicTimer; + } + + --_nextEventTimer; + if (_nextEventTimer) { + return; + } + + while (true) { + uint command = _resource[_curOffset++]; + if (command == 0xFF) { + // META EVENT + // Get the command number. + command = _resource[_curOffset++]; + if (command == 47) { + // End of track + if (_loopFlag) { + // In case the track is looping jump to the start. + _curOffset = _musicLoopStart; + _nextEventTimer = 0; + } else { + // Otherwise completely stop playback. + stopAllSounds(); + } + return; + } else if (command == 88) { + // This is proposedly a debug information insertion. The CMS + // player code handles this differently, but is still using + // the same resources... + _curOffset += 5; + } else if (command == 81) { + // Change tempo. This is used exclusively in Loom. + const uint timing = _resource[_curOffset + 2] | (_resource[_curOffset + 1] << 8); + _musicTicks = 0x73000 / timing; + command = _resource[_curOffset++]; + _curOffset += command; + } else { + // In case an unknown meta event occurs just skip over the + // data by using the length supplied. + command = _resource[_curOffset++]; + _curOffset += command; + } + } else { + if (command >= 0x90) { + // NOTE ON + // Extract the channel number and save it in command. + command -= 0x90; + + const uint instrOffset = _instrumentOffset[command]; + if (instrOffset) { + if (_resource[instrOffset + 13] != 0) { + setupRhythm(_resource[instrOffset + 13], instrOffset); + } else { + int channel = findFreeChannel(); + if (channel != -1) { + noteOff(channel); + setupChannel(channel, instrOffset); + _channelLastEvent[channel] = command + 0x90; + _channelFrequency[channel] = _resource[_curOffset]; + setupFrequency(channel, _resource[_curOffset]); + } + } + } + } else { + // NOTE OFF + const uint note = _resource[_curOffset]; + command += 0x10; + + // Find the output channel which plays the note. + uint channel = 0xFF; + for (uint i = 0; i < _voiceChannels; ++i) { + if (_channelFrequency[i] == note && _channelLastEvent[i] == command) { + channel = i; + break; + } + } + + if (channel != 0xFF) { + // In case a output channel playing the note was found, + // stop it. + noteOff(channel); + } else { + // In case there is no such note this will disable the + // rhythm instrument played on the channel. + command -= 0x90; + const uint instrOffset = _instrumentOffset[command]; + if (instrOffset && _resource[instrOffset + 13] != 0) { + const uint rhythmInstr = _resource[instrOffset + 13]; + if (rhythmInstr < 6) { + _mdvdrState &= _mdvdrTable[rhythmInstr] ^ 0xFF; + writeReg(0xBD, _mdvdrState); + } + } + } + } + + _curOffset += 2; + } + + // In case there is a delay till the next event stop handling. + if (_resource[_curOffset] != 0) { + break; + } + ++_curOffset; + } + + _nextEventTimer = _resource[_curOffset++]; + if (_nextEventTimer & 0x80) { + _nextEventTimer -= 0x80; + _nextEventTimer <<= 7; + _nextEventTimer |= _resource[_curOffset++]; + } + + _nextEventTimer >>= (_vm->_game.id == GID_LOOM) ? 2 : 1; + if (!_nextEventTimer) { + _nextEventTimer = 1; + } +} + +void Player_AD::noteOff(uint channel) { + _channelLastEvent[channel] = 0; + writeReg(0xB0 + channel, _channelB0Reg[channel] & 0xDF); +} + +int Player_AD::findFreeChannel() { + for (uint i = 0; i < _voiceChannels; ++i) { + if (!_channelLastEvent[i]) { + return i; + } + } + + return -1; +} + +void Player_AD::setupFrequency(uint channel, int8 frequency) { + frequency -= 31; + if (frequency < 0) { + frequency = 0; + } + + uint octave = 0; + while (frequency >= 12) { + frequency -= 12; + ++octave; + } + + const uint noteFrequency = _noteFrequencies[frequency]; + octave <<= 2; + octave |= noteFrequency >> 8; + octave |= 0x20; + writeReg(0xA0 + channel, noteFrequency & 0xFF); + _channelB0Reg[channel] = octave; + writeReg(0xB0 + channel, octave); +} + +void Player_AD::setupRhythm(uint rhythmInstr, uint instrOffset) { + if (rhythmInstr == 1) { + setupChannel(6, instrOffset); + writeReg(0xA6, _resource[instrOffset++]); + writeReg(0xB6, _resource[instrOffset] & 0xDF); + _mdvdrState |= 0x10; + writeReg(0xBD, _mdvdrState); + } else if (rhythmInstr < 6) { + const byte *secondOperatorOffset = _resource + instrOffset + 8; + setupOperator(_rhythmOperatorTable[rhythmInstr], secondOperatorOffset); + writeReg(0xA0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++]); + writeReg(0xB0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++] & 0xDF); + writeReg(0xC0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset]); + _mdvdrState |= _mdvdrTable[rhythmInstr]; + writeReg(0xBD, _mdvdrState); + } +} + +const uint Player_AD::_noteFrequencies[12] = { + 0x200, 0x21E, 0x23F, 0x261, + 0x285, 0x2AB, 0x2D4, 0x300, + 0x32E, 0x35E, 0x390, 0x3C7 +}; + +const uint Player_AD::_mdvdrTable[6] = { + 0x00, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + +const uint Player_AD::_rhythmOperatorTable[6] = { + 0x00, 0x00, 0x14, 0x12, 0x15, 0x11 +}; + +const uint Player_AD::_rhythmChannelTable[6] = { + 0x00, 0x00, 0x07, 0x08, 0x08, 0x07 +}; + +// SFX + +void Player_AD::startSfx() { + writeReg(0xBD, 0x00); + + // The second byte of the resource defines the logical channel where + // the sound effect should be played. + const int startChannel = _resource[1] * 3; + + // Clear the channel. + _channels[startChannel + 0].state = 0; + _channels[startChannel + 1].state = 0; + _channels[startChannel + 2].state = 0; + + clearChannel(startChannel + 0); + clearChannel(startChannel + 1); + clearChannel(startChannel + 2); + + // Set up the first channel to pick up playback. + _channels[startChannel].currentOffset = _channels[startChannel].startOffset = _resource + 2; + _channels[startChannel].state = 1; + + // Scan for the start of the other channels and set them up if required. + int curChannel = startChannel + 1; + const byte *bufferPosition = _resource + 2; + uint8 command = 0; + while ((command = *bufferPosition) != 0xFF) { + switch (command) { + case 1: + // INSTRUMENT DEFINITION + bufferPosition += 15; + break; + + case 2: + // NOTE DEFINITION + bufferPosition += 11; + break; + + case 0x80: + // LOOP + bufferPosition += 1; + break; + + default: + // START OF CHANNEL + bufferPosition += 1; + _channels[curChannel].currentOffset = bufferPosition; + _channels[curChannel].startOffset = bufferPosition; + _channels[curChannel].state = 1; + ++curChannel; + break; + } + } +} + +void Player_AD::updateSfx() { + if (--_sfxTimer) { + return; + } + _sfxTimer = 4; + + for (int i = 0; i <= 9; ++i) { + if (!_channels[i].state) { + continue; + } + + updateChannel(i); + } +} + +void Player_AD::clearChannel(int channel) { + writeReg(0xA0 + channel, 0x00); + writeReg(0xB0 + channel, 0x00); +} + +void Player_AD::updateChannel(int channel) { + if (_channels[channel].state == 1) { + parseSlot(channel); + } else { + updateSlot(channel); + } +} + +void Player_AD::parseSlot(int channel) { + while (true) { + const byte *curOffset = _channels[channel].currentOffset; + + switch (*curOffset) { + case 1: + // INSTRUMENT DEFINITION + ++curOffset; + _channels[channel].instrumentData[0] = *(curOffset + 0); + _channels[channel].instrumentData[1] = *(curOffset + 2); + _channels[channel].instrumentData[2] = *(curOffset + 9); + _channels[channel].instrumentData[3] = *(curOffset + 8); + _channels[channel].instrumentData[4] = *(curOffset + 4); + _channels[channel].instrumentData[5] = *(curOffset + 3); + _channels[channel].instrumentData[6] = 0; + + setupChannel(channel, curOffset); + + writeReg(0xA0 + channel, *(curOffset + 0)); + writeReg(0xB0 + channel, *(curOffset + 1) & 0xDF); + + _channels[channel].currentOffset += 15; + break; + + case 2: + // NOTE DEFINITION + ++curOffset; + _channels[channel].state = 2; + noteOffOn(channel); + parseNote(channel, 0, curOffset); + parseNote(channel, 1, curOffset); + return; + + case 0x80: + // LOOP + _channels[channel].currentOffset = _channels[channel].startOffset; + break; + + default: + // START OF CHANNEL + // When we encounter a start of another channel while playback + // it means that the current channel is finished. Thus, we will + // stop it. + clearChannel(channel); + _channels[channel].state = 0; + + // If no channel of the sound effect is playing anymore, unlock + // the resource. + channel /= 3; + if (!_channels[channel + 0].state + && !_channels[channel + 1].state + && !_channels[channel + 2].state) { + _vm->_res->unlock(rtSound, _sfxResource[channel]); + } + return; + } + } +} + +void Player_AD::updateSlot(int channel) { + const byte *curOffset = _channels[channel].currentOffset + 1; + + for (int num = 0; num <= 1; ++num, curOffset += 5) { + if (!(*curOffset & 0x80)) { + continue; + } + + const int note = channel * 2 + num; + bool updateNote = false; + + if (_notes[note].state == 2) { + if (!--_notes[note].sustainTimer) { + updateNote = true; + } + } else { + updateNote = processNoteEnvelope(note, _notes[note].instrumentValue); + + if (_notes[note].bias) { + writeRegisterSpecial(note, _notes[note].bias - _notes[note].instrumentValue, *curOffset & 0x07); + } else { + writeRegisterSpecial(note, _notes[note].instrumentValue, *curOffset & 0x07); + } + } + + if (updateNote) { + if (processNote(note, curOffset)) { + if (!(*curOffset & 0x08)) { + _channels[channel].currentOffset += 11; + _channels[channel].state = 1; + continue; + } else if (*curOffset & 0x10) { + noteOffOn(channel); + } + + _notes[note].state = -1; + processNote(note, curOffset); + } + } + + if ((*curOffset & 0x20) && !--_notes[note].playTime) { + _channels[channel].currentOffset += 11; + _channels[channel].state = 1; + } + } +} + +void Player_AD::parseNote(int channel, int num, const byte *offset) { + if (num) { + offset += 5; + } + + if (*offset & 0x80) { + const int note = channel * 2 + num; + _notes[note].state = -1; + processNote(note, offset); + _notes[note].playTime = 0; + + if (*offset & 0x20) { + _notes[note].playTime = (*(offset + 4) >> 4) * 118; + _notes[note].playTime += (*(offset + 4) & 0x0F) * 8; + } + } +} + +bool Player_AD::processNote(int note, const byte *offset) { + if (++_notes[note].state == 4) { + return true; + } + + const int instrumentDataOffset = *offset & 0x07; + _notes[note].bias = _noteBiasTable[instrumentDataOffset]; + + uint8 instrumentDataValue = 0; + if (_notes[note].state == 0) { + instrumentDataValue = _channels[note / 2].instrumentData[instrumentDataOffset]; + } + + uint8 noteInstrumentValue = readRegisterSpecial(note, instrumentDataValue, instrumentDataOffset); + if (_notes[note].bias) { + noteInstrumentValue = _notes[note].bias - noteInstrumentValue; + } + _notes[note].instrumentValue = noteInstrumentValue; + + if (_notes[note].state == 2) { + _notes[note].sustainTimer = _numStepsTable[*(offset + 3) >> 4]; + + if (*offset & 0x40) { + _notes[note].sustainTimer = (((getRnd() << 8) * _notes[note].sustainTimer) >> 16) + 1; + } + } else { + int timer1, timer2; + if (_notes[note].state == 3) { + timer1 = *(offset + 3) & 0x0F; + timer2 = 0; + } else { + timer1 = *(offset + _notes[note].state + 1) >> 4; + timer2 = *(offset + _notes[note].state + 1) & 0x0F; + } + + int adjustValue = ((_noteAdjustTable[timer2] * _noteAdjustScaleTable[instrumentDataOffset]) >> 16) - noteInstrumentValue; + setupNoteEnvelopeState(note, _numStepsTable[timer1], adjustValue); + } + + return false; +} + +void Player_AD::noteOffOn(int channel) { + const uint8 regValue = readReg(0xB0 | channel); + writeReg(0xB0 | channel, regValue & 0xDF); + writeReg(0xB0 | channel, regValue | 0x20); +} + +void Player_AD::writeRegisterSpecial(int note, uint8 value, int offset) { + if (offset == 6) { + return; + } + + // Division by 2 extracts the channel number out of the note. + note /= 2; + + uint8 regNum; + if (_useOperatorTable[offset]) { + regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2]; + } else { + regNum = _channelOffsetTable[note]; + } + + regNum += _baseRegisterTable[offset]; + + uint8 regValue = readReg(regNum) & (~_registerMaskTable[offset]); + regValue |= value << _registerShiftTable[offset]; + + writeReg(regNum, regValue); +} + +uint8 Player_AD::readRegisterSpecial(int note, uint8 defaultValue, int offset) { + if (offset == 6) { + return 0; + } + + // Division by 2 extracts the channel number out of the note. + note /= 2; + + uint8 regNum; + if (_useOperatorTable[offset]) { + regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2]; + } else { + regNum = _channelOffsetTable[note]; + } + + regNum += _baseRegisterTable[offset]; + + uint8 regValue; + if (defaultValue) { + regValue = defaultValue; + } else { + regValue = readReg(regNum); + } + + regValue &= _registerMaskTable[offset]; + regValue >>= _registerShiftTable[offset]; + + return regValue; +} + +void Player_AD::setupNoteEnvelopeState(int note, int steps, int adjust) { + _notes[note].preIncrease = 0; + if (ABS(adjust) > steps) { + _notes[note].preIncrease = 1; + _notes[note].adjust = adjust / steps; + _notes[note].envelope.stepIncrease = ABS(adjust % steps); + } else { + _notes[note].adjust = adjust; + _notes[note].envelope.stepIncrease = ABS(adjust); + } + + _notes[note].envelope.step = steps; + _notes[note].envelope.stepCounter = 0; + _notes[note].envelope.timer = steps; +} + +bool Player_AD::processNoteEnvelope(int note, int &instrumentValue) { + if (_notes[note].preIncrease) { + instrumentValue += _notes[note].adjust; + } + + _notes[note].envelope.stepCounter += _notes[note].envelope.stepIncrease; + if (_notes[note].envelope.stepCounter >= _notes[note].envelope.step) { + _notes[note].envelope.stepCounter -= _notes[note].envelope.step; + + if (_notes[note].adjust < 0) { + --instrumentValue; + } else { + ++instrumentValue; + } + } + + if (--_notes[note].envelope.timer) { + return false; + } else { + return true; + } +} + +uint8 Player_AD::getRnd() { + if (_rndSeed & 1) { + _rndSeed >>= 1; + _rndSeed ^= 0xB8; + } else { + _rndSeed >>= 1; + } + + return _rndSeed; +} + +const uint Player_AD::_noteBiasTable[7] = { + 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x00 +}; + +const uint Player_AD::_numStepsTable[16] = { + 1, 4, 6, 8, + 10, 14, 18, 24, + 36, 64, 100, 160, + 240, 340, 600, 1200 +}; + +const uint Player_AD::_noteAdjustScaleTable[7] = { + 255, 7, 63, 15, 63, 15, 63 +}; + +const uint Player_AD::_noteAdjustTable[16] = { + 0, 4369, 8738, 13107, + 17476, 21845, 26214, 30583, + 34952, 39321, 43690, 48059, + 52428, 46797, 61166, 65535 +}; + +const bool Player_AD::_useOperatorTable[7] = { + false, false, true, true, true, true, false +}; + +const uint Player_AD::_channelOffsetTable[11] = { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 8, 7 +}; + +const uint Player_AD::_channelOperatorOffsetTable[7] = { + 0, 0, 1, 1, 0, 0, 0 +}; + +const uint Player_AD::_baseRegisterTable[7] = { + 0xA0, 0xC0, 0x40, 0x20, 0x40, 0x20, 0x00 +}; + +const uint Player_AD::_registerMaskTable[7] = { + 0xFF, 0x0E, 0x3F, 0x0F, 0x3F, 0x0F, 0x00 +}; + +const uint Player_AD::_registerShiftTable[7] = { + 0, 1, 0, 0, 0, 0, 0 +}; + +} // End of namespace Scumm diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h new file mode 100644 index 0000000000..fbb65fbe24 --- /dev/null +++ b/engines/scumm/players/player_ad.h @@ -0,0 +1,190 @@ +/* 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_PLAYERS_PLAYER_AD_H +#define SCUMM_PLAYERS_PLAYER_AD_H + +#include "scumm/music.h" + +#include "audio/audiostream.h" +#include "audio/mixer.h" + +#include "common/mutex.h" + +namespace OPL { +class OPL; +} + +namespace Scumm { + +class ScummEngine; + +/** + * Sound output for v3/v4 AdLib data. + */ +class Player_AD : public MusicEngine, public Audio::AudioStream { +public: + Player_AD(ScummEngine *scumm, Audio::Mixer *mixer); + virtual ~Player_AD(); + + // MusicEngine API + virtual void setMusicVolume(int vol); + virtual void startSound(int sound); + virtual void stopSound(int sound); + virtual void stopAllSounds(); + virtual int getMusicTimer(); + virtual int getSoundStatus(int sound) const; + + virtual void saveLoadWithSerializer(Serializer *ser); + + // AudioStream API + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return false; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _rate; } + +private: + ScummEngine *const _vm; + Common::Mutex _mutex; + Audio::Mixer *const _mixer; + const int _rate; + Audio::SoundHandle _soundHandle; + void setupVolume(); + + OPL::OPL *_opl2; + + int _samplesPerCallback; + int _samplesPerCallbackRemainder; + int _samplesTillCallback; + int _samplesTillCallbackRemainder; + + int _soundPlaying; + int _engineMusicTimer; + + // AdLib register utilities + uint8 _registerBackUpTable[256]; + void writeReg(int r, int v); + uint8 readReg(int r) const; + + // Instrument setup + void setupChannel(const uint channel, uint instrOffset) { + setupChannel(channel, _resource + instrOffset); + } + void setupChannel(const uint channel, const byte *instrOffset); + void setupOperator(const uint opr, const byte *&instrOffset); + static const int _operatorOffsetTable[18]; + + // Sound data + const byte *_resource; + + // Music handling + void startMusic(); + void updateMusic(); + void noteOff(uint channel); + int findFreeChannel(); + void setupFrequency(uint channel, int8 frequency); + void setupRhythm(uint rhythmInstr, uint instrOffset); + + uint _timerLimit; + uint _musicTicks; + uint _musicTimer; + uint _internalMusicTimer; + bool _loopFlag; + uint _musicLoopStart; + uint _instrumentOffset[16]; + uint _channelLastEvent[9]; + uint _channelFrequency[9]; + uint _channelB0Reg[9]; + + uint _mdvdrState; + uint _voiceChannels; + + uint _curOffset; + uint _nextEventTimer; + + static const uint _noteFrequencies[12]; + static const uint _mdvdrTable[6]; + static const uint _rhythmOperatorTable[6]; + static const uint _rhythmChannelTable[6]; + + // SFX handling + void startSfx(); + void updateSfx(); + void clearChannel(int channel); + void updateChannel(int channel); + void parseSlot(int channel); + void updateSlot(int channel); + void parseNote(int channel, int num, const byte *offset); + bool processNote(int note, const byte *offset); + void noteOffOn(int channel); + void writeRegisterSpecial(int note, uint8 value, int offset); + uint8 readRegisterSpecial(int note, uint8 defaultValue, int offset); + void setupNoteEnvelopeState(int note, int steps, int adjust); + bool processNoteEnvelope(int note, int &instrumentValue); + + int _sfxTimer; + + int _sfxResource[3]; + int _sfxPriority[3]; + + struct Channel { + int state; + const byte *currentOffset; + const byte *startOffset; + uint8 instrumentData[7]; + } _channels[11]; + + uint8 _rndSeed; + uint8 getRnd(); + + struct Note { + int state; + int playTime; + int sustainTimer; + int instrumentValue; + int bias; + int preIncrease; + int adjust; + + struct Envelope { + int stepIncrease; + int step; + int stepCounter; + int timer; + } envelope; + } _notes[22]; + + static const uint _noteBiasTable[7]; + static const uint _numStepsTable[16]; + static const uint _noteAdjustScaleTable[7]; + static const uint _noteAdjustTable[16]; + static const bool _useOperatorTable[7]; + static const uint _channelOffsetTable[11]; + static const uint _channelOperatorOffsetTable[7]; + static const uint _baseRegisterTable[7]; + static const uint _registerMaskTable[7]; + static const uint _registerShiftTable[7]; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/player_apple2.cpp b/engines/scumm/players/player_apple2.cpp index 58e4f78a94..87b8100f22 100644 --- a/engines/scumm/player_apple2.cpp +++ b/engines/scumm/players/player_apple2.cpp @@ -21,7 +21,7 @@ */ #include "engines/engine.h" -#include "scumm/player_apple2.h" +#include "scumm/players/player_apple2.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_apple2.h b/engines/scumm/players/player_apple2.h index e1ec9d8946..9930a4f95d 100644 --- a/engines/scumm/player_apple2.h +++ b/engines/scumm/players/player_apple2.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_APPLEII_H -#define SCUMM_PLAYER_APPLEII_H +#ifndef SCUMM_PLAYERS_PLAYER_APPLEII_H +#define SCUMM_PLAYERS_PLAYER_APPLEII_H #include "common/mutex.h" #include "common/scummsys.h" diff --git a/engines/scumm/player_mac.cpp b/engines/scumm/players/player_mac.cpp index a60736df5e..281eec5336 100644 --- a/engines/scumm/player_mac.cpp +++ b/engines/scumm/players/player_mac.cpp @@ -24,7 +24,7 @@ #include "common/translation.h" #include "engines/engine.h" #include "gui/message.h" -#include "scumm/player_mac.h" +#include "scumm/players/player_mac.h" #include "scumm/resource.h" #include "scumm/scumm.h" #include "scumm/imuse/imuse.h" diff --git a/engines/scumm/player_mac.h b/engines/scumm/players/player_mac.h index 09307b4e57..7f9f42c34e 100644 --- a/engines/scumm/player_mac.h +++ b/engines/scumm/players/player_mac.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_MAC_H -#define SCUMM_PLAYER_MAC_H +#ifndef SCUMM_PLAYERS_PLAYER_MAC_H +#define SCUMM_PLAYERS_PLAYER_MAC_H #include "common/scummsys.h" #include "common/util.h" diff --git a/engines/scumm/player_mod.cpp b/engines/scumm/players/player_mod.cpp index 6411f0a17a..abaa8c1fc5 100644 --- a/engines/scumm/player_mod.cpp +++ b/engines/scumm/players/player_mod.cpp @@ -21,7 +21,7 @@ */ -#include "scumm/player_mod.h" +#include "scumm/players/player_mod.h" #include "audio/mixer.h" #include "audio/rate.h" #include "audio/decoders/raw.h" diff --git a/engines/scumm/player_mod.h b/engines/scumm/players/player_mod.h index 619d83541d..d4a5b16fca 100644 --- a/engines/scumm/player_mod.h +++ b/engines/scumm/players/player_mod.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_MOD_H -#define SCUMM_PLAYER_MOD_H +#ifndef SCUMM_PLAYERS_PLAYER_MOD_H +#define SCUMM_PLAYERS_PLAYER_MOD_H #include "scumm/scumm.h" #include "audio/audiostream.h" diff --git a/engines/scumm/player_nes.cpp b/engines/scumm/players/player_nes.cpp index a6ffc9ed86..f55f1f9edd 100644 --- a/engines/scumm/player_nes.cpp +++ b/engines/scumm/players/player_nes.cpp @@ -23,7 +23,7 @@ #ifndef DISABLE_NES_APU #include "engines/engine.h" -#include "scumm/player_nes.h" +#include "scumm/players/player_nes.h" #include "scumm/scumm.h" #include "audio/mixer.h" diff --git a/engines/scumm/player_nes.h b/engines/scumm/players/player_nes.h index be1617e0f6..f0b3e79aad 100644 --- a/engines/scumm/player_nes.h +++ b/engines/scumm/players/player_nes.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_NES_H -#define SCUMM_PLAYER_NES_H +#ifndef SCUMM_PLAYERS_PLAYER_NES_H +#define SCUMM_PLAYERS_PLAYER_NES_H #include "common/scummsys.h" #include "scumm/music.h" diff --git a/engines/scumm/player_pce.cpp b/engines/scumm/players/player_pce.cpp index 8d886ee008..6d6e2fcde5 100644 --- a/engines/scumm/player_pce.cpp +++ b/engines/scumm/players/player_pce.cpp @@ -29,7 +29,7 @@ */ #include <math.h> -#include "player_pce.h" +#include "scumm/players/player_pce.h" #include "common/endian.h" // PCE sound engine is only used by Loom, which requires 16bit color support diff --git a/engines/scumm/player_pce.h b/engines/scumm/players/player_pce.h index 427fb1ace6..ca2eddf58c 100644 --- a/engines/scumm/player_pce.h +++ b/engines/scumm/players/player_pce.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_PCE_H -#define SCUMM_PLAYER_PCE_H +#ifndef SCUMM_PLAYERS_PLAYER_PCE_H +#define SCUMM_PLAYERS_PLAYER_PCE_H #include "common/scummsys.h" #include "common/mutex.h" diff --git a/engines/scumm/player_sid.cpp b/engines/scumm/players/player_sid.cpp index 7a609364e5..1b97ad16d4 100644 --- a/engines/scumm/player_sid.cpp +++ b/engines/scumm/players/player_sid.cpp @@ -23,7 +23,7 @@ #ifndef DISABLE_SID #include "engines/engine.h" -#include "scumm/player_sid.h" +#include "scumm/players/player_sid.h" #include "scumm/scumm.h" #include "audio/mixer.h" diff --git a/engines/scumm/player_sid.h b/engines/scumm/players/player_sid.h index 12e3573575..a48ec793cd 100644 --- a/engines/scumm/player_sid.h +++ b/engines/scumm/players/player_sid.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_SID_H -#define SCUMM_PLAYER_SID_H +#ifndef SCUMM_PLAYERS_PLAYER_SID_H +#define SCUMM_PLAYERS_PLAYER_SID_H #include "common/mutex.h" #include "common/scummsys.h" diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/players/player_towns.cpp index 33e3e40e39..acbdbc7fb6 100644 --- a/engines/scumm/player_towns.cpp +++ b/engines/scumm/players/player_towns.cpp @@ -22,7 +22,7 @@ #include "scumm/sound.h" -#include "scumm/player_towns.h" +#include "scumm/players/player_towns.h" namespace Scumm { diff --git a/engines/scumm/player_towns.h b/engines/scumm/players/player_towns.h index 5c76d7c6c7..2369b7da5f 100644 --- a/engines/scumm/player_towns.h +++ b/engines/scumm/players/player_towns.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_TOWNS_H -#define SCUMM_PLAYER_TOWNS_H +#ifndef SCUMM_PLAYERS_PLAYER_TOWNS_H +#define SCUMM_PLAYERS_PLAYER_TOWNS_H #include "scumm/scumm.h" #include "scumm/imuse/imuse.h" diff --git a/engines/scumm/player_v1.cpp b/engines/scumm/players/player_v1.cpp index 8e784e9866..0fa1ee9361 100644 --- a/engines/scumm/player_v1.cpp +++ b/engines/scumm/players/player_v1.cpp @@ -22,7 +22,7 @@ #include "engines/engine.h" -#include "scumm/player_v1.h" +#include "scumm/players/player_v1.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v1.h b/engines/scumm/players/player_v1.h index 9e6063adc9..ccd24c39df 100644 --- a/engines/scumm/player_v1.h +++ b/engines/scumm/players/player_v1.h @@ -20,10 +20,10 @@ * */ -#ifndef SCUMM_PLAYER_V1_H -#define SCUMM_PLAYER_V1_H +#ifndef SCUMM_PLAYERS_PLAYER_V1_H +#define SCUMM_PLAYERS_PLAYER_V1_H -#include "scumm/player_v2.h" +#include "scumm/players/player_v2.h" namespace Scumm { diff --git a/engines/scumm/player_v2.cpp b/engines/scumm/players/player_v2.cpp index 6910f5e0db..2429af2d8c 100644 --- a/engines/scumm/player_v2.cpp +++ b/engines/scumm/players/player_v2.cpp @@ -20,7 +20,7 @@ * */ -#include "scumm/player_v2.h" +#include "scumm/players/player_v2.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v2.h b/engines/scumm/players/player_v2.h index d932585b8e..33878ff08b 100644 --- a/engines/scumm/player_v2.h +++ b/engines/scumm/players/player_v2.h @@ -20,10 +20,10 @@ * */ -#ifndef SCUMM_PLAYER_V2_H -#define SCUMM_PLAYER_V2_H +#ifndef SCUMM_PLAYERS_PLAYER_V2_H +#define SCUMM_PLAYERS_PLAYER_V2_H -#include "scumm/player_v2base.h" +#include "scumm/players/player_v2base.h" namespace Scumm { diff --git a/engines/scumm/player_v2a.cpp b/engines/scumm/players/player_v2a.cpp index 07fc77b301..aeccb8b7cb 100644 --- a/engines/scumm/player_v2a.cpp +++ b/engines/scumm/players/player_v2a.cpp @@ -21,7 +21,7 @@ */ #include "engines/engine.h" -#include "scumm/player_v2a.h" +#include "scumm/players/player_v2a.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v2a.h b/engines/scumm/players/player_v2a.h index fe20b43846..12193635f2 100644 --- a/engines/scumm/player_v2a.h +++ b/engines/scumm/players/player_v2a.h @@ -20,12 +20,12 @@ * */ -#ifndef SCUMM_PLAYER_V2A_H -#define SCUMM_PLAYER_V2A_H +#ifndef SCUMM_PLAYERS_PLAYER_V2A_H +#define SCUMM_PLAYERS_PLAYER_V2A_H #include "common/scummsys.h" #include "scumm/music.h" -#include "scumm/player_mod.h" +#include "scumm/players/player_mod.h" class Mixer; diff --git a/engines/scumm/player_v2base.cpp b/engines/scumm/players/player_v2base.cpp index 0d3ad4b1b3..75f1518989 100644 --- a/engines/scumm/player_v2base.cpp +++ b/engines/scumm/players/player_v2base.cpp @@ -20,7 +20,7 @@ * */ -#include "scumm/player_v2base.h" +#include "scumm/players/player_v2base.h" #include "scumm/scumm.h" #define FREQ_HZ 236 // Don't change! diff --git a/engines/scumm/player_v2base.h b/engines/scumm/players/player_v2base.h index eb9ed941ca..32bde95ddc 100644 --- a/engines/scumm/player_v2base.h +++ b/engines/scumm/players/player_v2base.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_V2BASE_H -#define SCUMM_PLAYER_V2BASE_H +#ifndef SCUMM_PLAYERS_PLAYER_V2BASE_H +#define SCUMM_PLAYERS_PLAYER_V2BASE_H #include "common/scummsys.h" #include "common/mutex.h" diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/players/player_v2cms.cpp index c1242e0645..8e903bf9d2 100644 --- a/engines/scumm/player_v2cms.cpp +++ b/engines/scumm/players/player_v2cms.cpp @@ -20,7 +20,7 @@ * */ -#include "scumm/player_v2cms.h" +#include "scumm/players/player_v2cms.h" #include "scumm/scumm.h" #include "audio/mididrv.h" #include "audio/mixer.h" diff --git a/engines/scumm/player_v2cms.h b/engines/scumm/players/player_v2cms.h index 905c7c141e..fe42720215 100644 --- a/engines/scumm/player_v2cms.h +++ b/engines/scumm/players/player_v2cms.h @@ -20,10 +20,10 @@ * */ -#ifndef SCUMM_PLAYER_V2CMS_H -#define SCUMM_PLAYER_V2CMS_H +#ifndef SCUMM_PLAYERS_PLAYER_V2CMS_H +#define SCUMM_PLAYERS_PLAYER_V2CMS_H -#include "scumm/player_v2base.h" // for channel_data +#include "scumm/players/player_v2base.h" // for channel_data class CMSEmulator; diff --git a/engines/scumm/player_v3a.cpp b/engines/scumm/players/player_v3a.cpp index 472cd1252b..ca0eedc90a 100644 --- a/engines/scumm/player_v3a.cpp +++ b/engines/scumm/players/player_v3a.cpp @@ -22,7 +22,7 @@ #include "engines/engine.h" -#include "scumm/player_v3a.h" +#include "scumm/players/player_v3a.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v3a.h b/engines/scumm/players/player_v3a.h index 9449664e9b..3f84a74e51 100644 --- a/engines/scumm/player_v3a.h +++ b/engines/scumm/players/player_v3a.h @@ -20,12 +20,12 @@ * */ -#ifndef SCUMM_PLAYER_V3A_H -#define SCUMM_PLAYER_V3A_H +#ifndef SCUMM_PLAYERS_PLAYER_V3A_H +#define SCUMM_PLAYERS_PLAYER_V3A_H #include "common/scummsys.h" #include "scumm/music.h" -#include "scumm/player_mod.h" +#include "scumm/players/player_mod.h" class Mixer; diff --git a/engines/scumm/player_v3m.cpp b/engines/scumm/players/player_v3m.cpp index bf65ec797f..e30e31aff9 100644 --- a/engines/scumm/player_v3m.cpp +++ b/engines/scumm/players/player_v3m.cpp @@ -91,7 +91,7 @@ #include "common/translation.h" #include "engines/engine.h" #include "gui/message.h" -#include "scumm/player_v3m.h" +#include "scumm/players/player_v3m.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v3m.h b/engines/scumm/players/player_v3m.h index 359bab32a9..615d736035 100644 --- a/engines/scumm/player_v3m.h +++ b/engines/scumm/players/player_v3m.h @@ -20,14 +20,14 @@ * */ -#ifndef SCUMM_PLAYER_V3M_H -#define SCUMM_PLAYER_V3M_H +#ifndef SCUMM_PLAYERS_PLAYER_V3M_H +#define SCUMM_PLAYERS_PLAYER_V3M_H #include "common/scummsys.h" #include "common/util.h" #include "common/mutex.h" #include "scumm/music.h" -#include "scumm/player_mac.h" +#include "scumm/players/player_mac.h" #include "audio/audiostream.h" #include "audio/mixer.h" diff --git a/engines/scumm/player_v4a.cpp b/engines/scumm/players/player_v4a.cpp index e791736f0e..59f49625c3 100644 --- a/engines/scumm/player_v4a.cpp +++ b/engines/scumm/players/player_v4a.cpp @@ -21,7 +21,7 @@ */ #include "engines/engine.h" -#include "scumm/player_v4a.h" +#include "scumm/players/player_v4a.h" #include "scumm/scumm.h" #include "common/file.h" diff --git a/engines/scumm/player_v4a.h b/engines/scumm/players/player_v4a.h index d01c70f295..c8c7b63ed2 100644 --- a/engines/scumm/player_v4a.h +++ b/engines/scumm/players/player_v4a.h @@ -20,8 +20,8 @@ * */ -#ifndef SCUMM_PLAYER_V4A_H -#define SCUMM_PLAYER_V4A_H +#ifndef SCUMM_PLAYERS_PLAYER_V4A_H +#define SCUMM_PLAYERS_PLAYER_V4A_H #include "common/scummsys.h" #include "common/util.h" diff --git a/engines/scumm/player_v5m.cpp b/engines/scumm/players/player_v5m.cpp index 500f3bbc40..77b6d52a3c 100644 --- a/engines/scumm/player_v5m.cpp +++ b/engines/scumm/players/player_v5m.cpp @@ -76,7 +76,7 @@ #include "common/translation.h" #include "engines/engine.h" #include "gui/message.h" -#include "scumm/player_v5m.h" +#include "scumm/players/player_v5m.h" #include "scumm/scumm.h" namespace Scumm { diff --git a/engines/scumm/player_v5m.h b/engines/scumm/players/player_v5m.h index b2079ee331..e3a457f8af 100644 --- a/engines/scumm/player_v5m.h +++ b/engines/scumm/players/player_v5m.h @@ -20,14 +20,14 @@ * */ -#ifndef SCUMM_PLAYER_V5M_H -#define SCUMM_PLAYER_V5M_H +#ifndef SCUMM_PLAYERS_PLAYER_V5M_H +#define SCUMM_PLAYERS_PLAYER_V5M_H #include "common/scummsys.h" #include "common/util.h" #include "common/mutex.h" #include "scumm/music.h" -#include "scumm/player_mac.h" +#include "scumm/players/player_mac.h" #include "audio/audiostream.h" #include "audio/mixer.h" diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 13e2500eef..848e288589 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -30,7 +30,7 @@ #include "scumm/charset.h" #include "scumm/imuse_digi/dimuse.h" #include "scumm/imuse/imuse.h" -#include "scumm/player_towns.h" +#include "scumm/players/player_towns.h" #include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" @@ -636,100 +636,83 @@ bool ScummEngine::getSavegameName(int slot, Common::String &desc) { return result; } -bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion) { - SaveGameHeader hdr; - +namespace { +bool loadAndCheckSaveGameHeader(Common::InSaveFile *in, int heversion, SaveGameHeader &hdr, Common::String *error = nullptr) { if (!loadSaveGameHeader(in, hdr)) { - desc = "Invalid savegame"; + if (error) { + *error = "Invalid savegame"; + } return false; } - if (hdr.ver > CURRENT_VER) + if (hdr.ver > CURRENT_VER) { hdr.ver = TO_LE_32(hdr.ver); + } + if (hdr.ver < VER(7) || hdr.ver > CURRENT_VER) { - desc = "Invalid version"; + if (error) { + *error = "Invalid version"; + } return false; } // We (deliberately) broke HE savegame compatibility at some point. if (hdr.ver < VER(57) && heversion >= 60) { - desc = "Unsupported version"; + if (error) { + *error = "Unsupported version"; + } return false; } hdr.name[sizeof(hdr.name) - 1] = 0; - desc = hdr.name; return true; } +} // End of anonymous namespace -Graphics::Surface *ScummEngine::loadThumbnailFromSlot(const char *target, int slot) { - Common::SeekableReadStream *in; +bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion) { SaveGameHeader hdr; - if (slot < 0) - return 0; - - Common::String filename = ScummEngine::makeSavegameName(target, slot, false); - if (!(in = g_system->getSavefileManager()->openForLoading(filename))) { - return 0; - } - - if (!loadSaveGameHeader(in, hdr)) { - delete in; - return 0; + if (!loadAndCheckSaveGameHeader(in, heversion, hdr, &desc)) { + return false; } - if (hdr.ver > CURRENT_VER) - hdr.ver = TO_LE_32(hdr.ver); - if (hdr.ver < VER(52)) { - delete in; - return 0; - } + desc = hdr.name; + return true; +} - Graphics::Surface *thumb = 0; - if (Graphics::checkThumbnailHeader(*in)) { - thumb = Graphics::loadThumbnail(*in); +bool ScummEngine::querySaveMetaInfos(const char *target, int slot, int heversion, Common::String &desc, Graphics::Surface *&thumbnail, SaveStateMetaInfos *&timeInfos) { + if (slot < 0) { + return false; } - delete in; - return thumb; -} - -bool ScummEngine::loadInfosFromSlot(const char *target, int slot, SaveStateMetaInfos *stuff) { - Common::SeekableReadStream *in; SaveGameHeader hdr; + const Common::String filename = ScummEngine::makeSavegameName(target, slot, false); + Common::ScopedPtr<Common::SeekableReadStream> in(g_system->getSavefileManager()->openForLoading(filename)); - if (slot < 0) - return 0; - - Common::String filename = makeSavegameName(target, slot, false); - if (!(in = g_system->getSavefileManager()->openForLoading(filename))) { + if (!in) { return false; } - if (!loadSaveGameHeader(in, hdr)) { - delete in; + if (!loadAndCheckSaveGameHeader(in.get(), heversion, hdr)) { return false; } - if (hdr.ver > CURRENT_VER) - hdr.ver = TO_LE_32(hdr.ver); - if (hdr.ver < VER(56)) { - delete in; - return false; - } + desc = hdr.name; - if (!Graphics::skipThumbnail(*in)) { - delete in; - return false; - } + if (hdr.ver > VER(52)) { + if (Graphics::checkThumbnailHeader(*in)) { + thumbnail = Graphics::loadThumbnail(*in); + } - if (!loadInfos(in, stuff)) { - delete in; - return false; + if (hdr.ver > VER(57)) { + if (!loadInfos(in.get(), timeInfos)) { + return false; + } + } else { + timeInfos = nullptr; + } } - delete in; return true; } @@ -783,7 +766,7 @@ bool ScummEngine::loadInfos(Common::SeekableReadStream *file, SaveStateMetaInfos return true; } -void ScummEngine::saveInfos(Common::WriteStream* file) { +void ScummEngine::saveInfos(Common::WriteStream *file) { SaveInfoSection section; section.type = MKTAG('I','N','F','O'); section.version = INFOSECTION_VERSION; diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 7b2ff91ad3..c34be5816d 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 94 +#define CURRENT_VER 95 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index 2d4c326b68..3da7000ae9 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -27,7 +27,7 @@ #include "scumm/scumm_v3.h" #include "scumm/scumm_v5.h" #include "scumm/sound.h" -#include "scumm/player_towns.h" +#include "scumm/players/player_towns.h" #include "scumm/util.h" #include "scumm/verbs.h" diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index a75e864e7a..6983c51f30 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -394,7 +394,7 @@ ScummEngine_v6::ArrayHeader *ScummEngine_v6::getArray(int array) { int ScummEngine_v6::readArray(int array, int idx, int base) { ArrayHeader *ah = getArray(array); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); // WORKAROUND bug #645711. This is clearly a script bug, as this script diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index f5609f1b03..ae80f306af 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Sat Aug 3 16:52:02 2013 + This file was generated by the md5table tool on Fri Sep 27 05:44:12 2013 DO NOT EDIT MANUALLY! */ @@ -121,6 +121,7 @@ static const MD5Table md5table[] = { { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "Floppy", "Floppy", 7932, Common::EN_ANY, Common::kPlatformDOS }, { "27b2ef1653089fe5b897d9cc89ce784f", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformAmiga }, + { "288fb75b24389733c29fa107fe8d44e8", "catalog", "HE CUP", "Preview", 10795148, Common::EN_USA, Common::kPlatformUnknown }, { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "FM-TOWNS", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, { "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformDOS }, { "28f07458f1b6c24e118a1ea056827701", "lost", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -344,6 +345,7 @@ static const MD5Table md5table[] = { { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformDOS }, { "79b05f628586837e7166e82b2279bb50", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, + { "7b4ee071eecadc2d8cd0c3509110825c", "puttzoo", "HE 100", "Remastered", -1, Common::EN_ANY, Common::kPlatformWindows }, { "7bad72e332a59f9fcc1d437f4edad32a", "puttcircus", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "7c2e76087027eeee9c8f8985f93a1cc5", "freddi4", "", "Demo", 13584, Common::EN_ANY, Common::kPlatformUnknown }, { "7c8100e360e8ef05f88069d4cfa0afd1", "puttrace", "HE 99", "Demo", 13108, Common::EN_GRB, Common::kPlatformWindows }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 6fddf4ba77..39fbae8147 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -45,25 +45,26 @@ #include "scumm/imuse_digi/dimuse.h" #include "scumm/smush/smush_mixer.h" #include "scumm/smush/smush_player.h" -#include "scumm/player_towns.h" +#include "scumm/players/player_towns.h" #include "scumm/insane/insane.h" #include "scumm/he/animation_he.h" #include "scumm/he/intern_he.h" #include "scumm/he/logic_he.h" #include "scumm/he/sound_he.h" #include "scumm/object.h" -#include "scumm/player_nes.h" -#include "scumm/player_sid.h" -#include "scumm/player_pce.h" -#include "scumm/player_apple2.h" -#include "scumm/player_v1.h" -#include "scumm/player_v2.h" -#include "scumm/player_v2cms.h" -#include "scumm/player_v2a.h" -#include "scumm/player_v3a.h" -#include "scumm/player_v3m.h" -#include "scumm/player_v4a.h" -#include "scumm/player_v5m.h" +#include "scumm/players/player_ad.h" +#include "scumm/players/player_nes.h" +#include "scumm/players/player_sid.h" +#include "scumm/players/player_pce.h" +#include "scumm/players/player_apple2.h" +#include "scumm/players/player_v1.h" +#include "scumm/players/player_v2.h" +#include "scumm/players/player_v2cms.h" +#include "scumm/players/player_v2a.h" +#include "scumm/players/player_v3a.h" +#include "scumm/players/player_v3m.h" +#include "scumm/players/player_v4a.h" +#include "scumm/players/player_v5m.h" #include "scumm/resource.h" #include "scumm/he/resource_he.h" #include "scumm/scumm_v0.h" @@ -1841,6 +1842,15 @@ void ScummEngine::setupMusic(int midi) { _musicEngine = _townsPlayer = new Player_Towns_v1(this, _mixer); if (!_townsPlayer->init()) error("Failed to initialize FM-Towns audio driver"); + } else if (_game.platform == Common::kPlatformDOS && (_sound->_musicType == MDT_ADLIB) && (_game.id == GID_LOOM || _game.id == GID_INDY3)) { + // For Indy3 DOS and Loom DOS we use an implementation of the original + // AD player when AdLib is selected. This fixes sound effects in those + // games (see for example bug #2027877 "INDY3: Non-Looping Sound + // Effects"). The player itself is also used in Monkey Island DOS + // EGA/VGA. However, we support multi MIDI for that game and we cannot + // support this with the Player_AD code at the moment. The reason here + // is that multi MIDI is supported internally by our iMuse output. + _musicEngine = new Player_AD(this, _mixer); } else if (_game.version >= 3 && _game.heversion <= 62) { MidiDriver *nativeMidiDriver = 0; MidiDriver *adlibMidiDriver = 0; diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 021378c554..7d3a01b895 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -240,6 +240,7 @@ enum ScummGameId { GID_FBEAR, GID_PUTTMOON, GID_FUNPACK, + GID_PUTTZOO, GID_FREDDI3, GID_BIRTHDAYRED, GID_BIRTHDAYYELLOW, @@ -625,15 +626,10 @@ public: // thumbnail + info stuff public: - Graphics::Surface *loadThumbnailFromSlot(int slot) { - return loadThumbnailFromSlot(_targetName.c_str(), slot); - } - static Graphics::Surface *loadThumbnailFromSlot(const char *target, int slot); - - static bool loadInfosFromSlot(const char *target, int slot, SaveStateMetaInfos *stuff); + static bool querySaveMetaInfos(const char *target, int slot, int heversion, Common::String &desc, Graphics::Surface *&thumbnail, SaveStateMetaInfos *&timeInfos); protected: - void saveInfos(Common::WriteStream* file); + void saveInfos(Common::WriteStream *file); static bool loadInfos(Common::SeekableReadStream *file, SaveStateMetaInfos *stuff); protected: diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 3f6290f8fc..071805752b 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -30,7 +30,7 @@ #include "scumm/file.h" #include "scumm/imuse/imuse.h" #include "scumm/imuse_digi/dimuse.h" -#include "scumm/player_towns.h" +#include "scumm/players/player_towns.h" #include "scumm/resource.h" #include "scumm/scumm.h" #include "scumm/sound.h" @@ -470,8 +470,10 @@ static int compareMP3OffsetTable(const void *a, const void *b) { void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle *handle) { int num = 0, i; - int size = 0; int id = -1; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) + int size = 0; +#endif Common::ScopedPtr<ScummFile> file; if (_vm->_game.id == GID_CMI) { @@ -562,10 +564,14 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle num = result->num_tags; } offset = result->new_offset; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) size = result->compressed_size; +#endif } else { offset += 8; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) size = -1; +#endif } file.reset(new ScummFile()); @@ -1930,7 +1936,6 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { // 8 bytes MTrk header // 7 bytes MIDI tempo sysex // + some default instruments - byte *ptr; if (_game.features & GF_OLD_BUNDLE) { ad_size -= 4; _fileHandle->seek(ad_offs + 4, SEEK_SET); @@ -1938,10 +1943,17 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { ad_size -= 6; _fileHandle->seek(ad_offs, SEEK_SET); } - ptr = (byte *) calloc(ad_size, 1); - _fileHandle->read(ptr, ad_size); - convertADResource(_res, _game, idx, ptr, ad_size); - free(ptr); + // For games using AD except Indy3 and Loom we are using our iMuse + // implementation. See output initialization in + // ScummEngine::setupMusic for more information. + if (_game.id != GID_INDY3 && _game.id != GID_LOOM) { + byte *ptr = (byte *)calloc(ad_size, 1); + _fileHandle->read(ptr, ad_size); + convertADResource(_res, _game, idx, ptr, ad_size); + free(ptr); + } else { + _fileHandle->read(_res->createResource(rtSound, idx, ad_size), ad_size); + } return 1; } else if (ro_offs != 0) { _fileHandle->seek(ro_offs - 2, SEEK_SET); diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 77c7daa0df..9c90d7575d 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -714,6 +714,12 @@ void ScummEngine_v99he::resetScummVars() { VAR(140) = 0; #endif } + + if (_game.id == GID_PUTTZOO && _game.heversion == 100 && _game.platform == Common::kPlatformWindows) { + // Specific to Nimbus Games version. + VAR(156) = 1; + VAR(157) = 0; + } } #endif |
