From 0ea6650837cce3007f0820acd17518f9809fd4a7 Mon Sep 17 00:00:00 2001 From: athrxx Date: Mon, 1 Apr 2019 00:55:17 +0200 Subject: KYRA: (EOB2/Amiga) - implement proper sound file loading (also fix some sound related bugs) --- engines/kyra/engine/chargen.cpp | 6 +- engines/kyra/engine/darkmoon.cpp | 90 ++++++++++++++++++++++ engines/kyra/engine/darkmoon.h | 10 +++ engines/kyra/engine/eob.cpp | 33 +++++++++ engines/kyra/engine/eob.h | 3 + engines/kyra/engine/eobcommon.cpp | 6 ++ engines/kyra/engine/eobcommon.h | 7 ++ engines/kyra/engine/scene_eob.cpp | 10 ++- engines/kyra/engine/sprites_eob.cpp | 5 +- engines/kyra/resource/staticres_eob.cpp | 18 ++++- engines/kyra/sound/drivers/audiomaster2.cpp | 111 ++++++++++++++++++---------- engines/kyra/sound/sound.h | 5 ++ engines/kyra/sound/sound_amiga_eob.cpp | 74 +++++++------------ engines/kyra/sound/sound_intern.h | 9 +-- 14 files changed, 285 insertions(+), 102 deletions(-) diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp index 2ae9682ed2..7a4c9672c6 100644 --- a/engines/kyra/engine/chargen.cpp +++ b/engines/kyra/engine/chargen.cpp @@ -634,16 +634,20 @@ int CharacterGenerator::alignmentMenu(int cClass) { } int CharacterGenerator::getInput(Button *buttonList) { + if (_vm->gameFlags().platform == Common::kPlatformAmiga) + return _vm->checkInput(buttonList, false, 0); + if (_vm->game() == GI_EOB1 && _vm->sound()->checkTrigger()) { _vm->sound()->resetTrigger(); _vm->snd_playSong(20); - } else if (_vm->game() == GI_EOB2 && _vm->gameFlags().platform != Common::kPlatformAmiga && !_vm->sound()->isPlaying()) { + } else if (_vm->game() == GI_EOB2 && !_vm->sound()->isPlaying()) { // WORKAROUND for EOB II: The original implements the same sound trigger check as in EOB I. // However, Westwood seems to have forgotten to set the trigger at the end of the AdLib song, // so that the music will not loop. We simply check whether the sound driver is still playing. _vm->delay(3 * _vm->_tickLength); _vm->snd_playSong(13); } + return _vm->checkInput(buttonList, false, 0); } diff --git a/engines/kyra/engine/darkmoon.cpp b/engines/kyra/engine/darkmoon.cpp index 8d621b9bc9..efe66a4d43 100644 --- a/engines/kyra/engine/darkmoon.cpp +++ b/engines/kyra/engine/darkmoon.cpp @@ -37,6 +37,11 @@ DarkMoonEngine::DarkMoonEngine(OSystem *system, const GameFlags &flags) : EoBCor _utilMenuStrings = _ascii2SjisTables = _ascii2SjisTables2 = 0; _npcShpData = _dscDoorType5Offs = _hornSounds = 0; _dreamSteps = 0; + + _amigaSoundMapExtra = _amigaSoundFiles2 = 0; + _amigaSoundIndex1 = 0; + _amigaSoundIndex2 = 0; + _amigaCurSoundIndex = 0; } DarkMoonEngine::~DarkMoonEngine() { @@ -415,6 +420,91 @@ bool DarkMoonEngine::restParty_extraAbortCondition() { return true; } +void DarkMoonEngine::snd_loadAmigaSounds(int level, int sub) { + if (_flags.platform != Common::kPlatformAmiga) + return; + + int fileNum = _amigaSoundIndex2[level]; + if (fileNum != _amigaCurSoundFile) { + for (int i = 52; i < 68; ++i) { + if (_amigaSoundMap[i]) { + _sound->unloadSoundFile(_amigaSoundMap[i]); + _amigaSoundMap[i] = 0; + } + } + + _sound->loadSoundFile(_amigaSoundFiles2[fileNum]); + _amigaCurSoundFile = fileNum; + + int mapCnt = 0; + for (int i = 0; i < fileNum + 1; ) { + if (!_amigaSoundMapExtra[mapCnt++][0]) + i++; + } + + for (int i = 52; i < 68; ++i) { + if (!_amigaSoundMapExtra[mapCnt][0]) { + _amigaSoundMap[i] = 0; + break; + } + _amigaSoundMap[i] = _amigaSoundMapExtra[mapCnt++]; + } + } + + if (level == 10 || (level == 8 && sub)) + return; + + uint16 sndIndex = 0; + + for (int i = 0; i != level; ) { + int8 val = _amigaSoundIndex1[sndIndex++]; + if (val == -1) + i++; + } + + if (sub) + sndIndex += 4; + + if (_amigaCurSoundIndex) { + for (int i = 0; i < 4; ++i) { + int8 valCur = _amigaSoundIndex1[_amigaCurSoundIndex + i]; + int8 valNew = _amigaSoundIndex1[sndIndex + i]; + if (valCur < 0) + continue; + + if (i < 2) { + for (int ii = 1; ii < 5; ++ii) + _sound->unloadSoundFile(Common::String::format("%s%d", _amigaLevelSoundList2[valCur], ii)); + } else { + if (valCur != valNew) + _sound->unloadSoundFile(Common::String::format("%s.SAM", _amigaLevelSoundList1[valCur])); + _sound->unloadSoundFile(Common::String::format("%s1", _amigaLevelSoundList2[valCur])); + } + } + } + + for (int i = 0; i < 4; ++i) { + int8 valCur = _amigaCurSoundIndex ? _amigaSoundIndex1[_amigaCurSoundIndex + i] : -5; + int8 valNew = _amigaSoundIndex1[sndIndex + i]; + + if (valNew >= 0 && valNew != valCur) { + if (i < 2 && valCur >= 0 && _amigaCurSoundIndex) + _sound->unloadSoundFile(Common::String::format("%s.SAM", _amigaLevelSoundList1[_amigaSoundIndex1[_amigaCurSoundIndex]])); + _sound->loadSoundFile(Common::String::format("%s.CPS", _amigaLevelSoundList1[valNew])); + assert(_amigaLevelSoundList2[valNew]); + _amigaSoundMap[36 + i] = _amigaLevelSoundList2[valNew][0] ? _amigaLevelSoundList2[valNew] : 0; + } else if (valNew == -2) { + _amigaSoundMap[36 + i] = 0; + } else if (valNew == -3) { + _amigaSoundMap[36 + i] = _amigaSoundMap[35 + i]; + } + } + + _sound->loadSoundFile(Common::String::format(sub ? "LEVEL%da.SAM" : "LEVEL%d.SAM", level)); + + _amigaCurSoundIndex = sndIndex; +} + void DarkMoonEngine::useHorn(int charIndex, int weaponSlot) { int v = _items[_characters[charIndex].inventory[weaponSlot]].value - 1; _txt->printMessage(_hornStrings[v]); diff --git a/engines/kyra/engine/darkmoon.h b/engines/kyra/engine/darkmoon.h index 71bfc75370..b3a69d254a 100644 --- a/engines/kyra/engine/darkmoon.h +++ b/engines/kyra/engine/darkmoon.h @@ -115,6 +115,16 @@ private: void restParty_npc(); bool restParty_extraAbortCondition(); + // Sound + void snd_loadAmigaSounds(int level, int sub); + + const char *const *_amigaSoundFiles2; + const char *const *_amigaSoundMapExtra; + const int8 *_amigaSoundIndex1; + const uint8 *_amigaSoundIndex2; + + int _amigaCurSoundIndex; + // misc void useHorn(int charIndex, int weaponSlot); bool checkPartyStatusExtra(); diff --git a/engines/kyra/engine/eob.cpp b/engines/kyra/engine/eob.cpp index f2d06e0a59..dc653fa38e 100644 --- a/engines/kyra/engine/eob.cpp +++ b/engines/kyra/engine/eob.cpp @@ -513,6 +513,39 @@ void EoBEngine::turnUndeadAutoHit() { sparkEffectOffensive(); } +void EoBEngine::snd_loadAmigaSounds(int level, int) { + if (_flags.platform != Common::kPlatformAmiga || level == _amigaCurSoundFile) + return; + + if (_amigaCurSoundFile != -1) { + _sound->unloadSoundFile(Common::String::format("L%dM1A1", _amigaCurSoundFile)); + _sound->unloadSoundFile(Common::String::format("L%dM2A1", _amigaCurSoundFile)); + + for (int i = 1; i < 5; ++i) { + _sound->unloadSoundFile(Common::String::format("L%dM1M%d", _amigaCurSoundFile, i)); + _sound->unloadSoundFile(Common::String::format("L%dM2M%d", _amigaCurSoundFile, i)); + } + + for (int i = 0; i < 2; ++i) { + if (_amigaLevelSoundList1[_amigaCurSoundFile * 2 + i][0]) + _sound->unloadSoundFile(_amigaLevelSoundList1[_amigaCurSoundFile * 2 + i]); + if (_amigaLevelSoundList2[_amigaCurSoundFile * 2 + i][0]) + _sound->unloadSoundFile(_amigaLevelSoundList2[_amigaCurSoundFile * 2 + i]); + } + } + + for (int i = 0; i < 2; ++i) { + if (_amigaLevelSoundList1[level * 2 + i][0]) + _sound->loadSoundFile(Common::String::format("%s.CPS", _amigaLevelSoundList1[level * 2 + i])); + if (_amigaLevelSoundList2[level * 2 + i][0]) + _sound->loadSoundFile(Common::String::format("%s.CPS", _amigaLevelSoundList2[level * 2 + i])); + } + + _sound->loadSoundFile(Common::String::format("LEVELSAM%d.CPS", level)); + + _amigaCurSoundFile = level; +} + bool EoBEngine::checkPartyStatusExtra() { _screen->copyPage(0, 10); int cd = _screen->curDimIndex(); diff --git a/engines/kyra/engine/eob.h b/engines/kyra/engine/eob.h index de98a91899..efb6c47b30 100644 --- a/engines/kyra/engine/eob.h +++ b/engines/kyra/engine/eob.h @@ -109,6 +109,9 @@ private: const char *const *_turnUndeadString; + // Sound + void snd_loadAmigaSounds(int level, int); + // Misc bool checkPartyStatusExtra(); int resurrectionSelectDialogue(); diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp index 16f9088945..153d17971f 100644 --- a/engines/kyra/engine/eobcommon.cpp +++ b/engines/kyra/engine/eobcommon.cpp @@ -221,6 +221,9 @@ EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags) : KyraRpgE _mnNumWord = _numSpells = _mageSpellListSize = _spellLevelsMageSize = _spellLevelsClericSize = 0; _inventorySlotsX = _slotValidationFlags = _encodeMonsterShpTable = 0; _cgaMappingDefault = _cgaMappingAlt = _cgaMappingInv = _cgaLevelMappingIndex = _cgaMappingItemsL = _cgaMappingItemsS = _cgaMappingThrown = _cgaMappingIcons = _cgaMappingDeco = 0; + _amigaLevelSoundList1 = _amigaLevelSoundList2 = 0; + _amigaSoundMap = 0; + _amigaCurSoundFile = -1; memset(_cgaMappingLevel, 0, sizeof(_cgaMappingLevel)); memset(_expRequirementTables, 0, sizeof(_expRequirementTables)); memset(_saveThrowTables, 0, sizeof(_saveThrowTables)); @@ -322,6 +325,9 @@ EoBCoreEngine::~EoBCoreEngine() { delete[] _menuDefs; _menuDefs = 0; + delete[] _amigaSoundMap; + _amigaSoundMap = 0; + delete _inf; _inf = 0; delete _timer; diff --git a/engines/kyra/engine/eobcommon.h b/engines/kyra/engine/eobcommon.h index 3566ea4345..c4340a2348 100644 --- a/engines/kyra/engine/eobcommon.h +++ b/engines/kyra/engine/eobcommon.h @@ -1180,6 +1180,13 @@ protected: void snd_playSoundEffect(int id, int volume=0xFF); void snd_stopSound(); void snd_fadeOut(int speed = 160); + virtual void snd_loadAmigaSounds(int level, int sub) = 0; + + const char **_amigaSoundMap; + const char *const *_amigaLevelSoundList1; + const char *const *_amigaLevelSoundList2; + + int _amigaCurSoundFile; // keymap static const char *const kKeymapName; diff --git a/engines/kyra/engine/scene_eob.cpp b/engines/kyra/engine/scene_eob.cpp index 7f3c464939..110bf0d12c 100644 --- a/engines/kyra/engine/scene_eob.cpp +++ b/engines/kyra/engine/scene_eob.cpp @@ -222,13 +222,15 @@ Common::String EoBCoreEngine::initLevelData(int sub) { } } - if (_flags.gameID == GI_EOB2) { + if (_flags.platform == Common::kPlatformAmiga) { + delay(3 * _tickLength); + snd_loadAmigaSounds(_currentLevel, sub); + if (_flags.gameID == GI_EOB2) + pos += 13; + } else if (_flags.gameID == GI_EOB2) { delay(3 * _tickLength); _sound->loadSoundFile((const char *)pos); pos += 13; - } else if (_flags.platform == Common::kPlatformAmiga) { - delay(3 * _tickLength); - _sound->loadSoundFile(_currentLevel); } releaseDoorShapes(); diff --git a/engines/kyra/engine/sprites_eob.cpp b/engines/kyra/engine/sprites_eob.cpp index f7e65f2133..17a5f555ed 100644 --- a/engines/kyra/engine/sprites_eob.cpp +++ b/engines/kyra/engine/sprites_eob.cpp @@ -1038,7 +1038,10 @@ bool EoBCoreEngine::updateMonsterTryDistanceAttack(EoBMonsterInPlay *m) { if (s < 20) { monsterSpellCast(m, s); } else if (s == 20) { - snd_processEnvironmentalSoundEffect(103, m->block); + if (_flags.platform == Common::kPlatformAmiga) + snd_processEnvironmentalSoundEffect(39, _currentBlock + 1); + else + snd_processEnvironmentalSoundEffect(103, m->block); _txt->printMessage(_monsterSpecAttStrings[0]); for (int i = 0; i < 6; i++) statusAttack(i, 4, _monsterSpecAttStrings[1], 1, 5, 9, 1); diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp index 90a8b904e4..c0ec2431b6 100644 --- a/engines/kyra/resource/staticres_eob.cpp +++ b/engines/kyra/resource/staticres_eob.cpp @@ -468,9 +468,18 @@ void EoBCoreEngine::initStaticResource() { void *sndInfo_finale = 0; if (_flags.platform == Common::kPlatformAmiga) { - const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp); const char *const *map = _staticres->loadStrings(kEoBBaseSoundMap, temp2); - SoundResourceInfo_AmigaEoB ingame(files, temp, map, temp2); + _amigaSoundMap = new const char*[temp2]; + for (int i = 0; i < temp2; ++i) { + assert(map[i]); + _amigaSoundMap[i] = map[i][0] ? map[i] : 0; + } + + _amigaLevelSoundList1 = _staticres->loadStrings(kEoBBaseLevelSounds1, temp); + _amigaLevelSoundList2 = _staticres->loadStrings(kEoBBaseLevelSounds2, temp); + + const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp); + SoundResourceInfo_AmigaEoB ingame(files, temp, _amigaSoundMap, temp2); sndInfo_ingame = &ingame; files = _staticres->loadStrings(kEoBBaseSoundFilesIntro, temp); SoundResourceInfo_AmigaEoB intro(files, temp, 0, 0); @@ -1356,6 +1365,11 @@ void DarkMoonEngine::initStaticResource() { _monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1; _monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2; + _amigaSoundMapExtra = _staticres->loadStrings(kEoB2SoundMapExtra, temp); + _amigaSoundFiles2 = _staticres->loadStrings(kEoB2SoundFilesIngame2, temp); + _amigaSoundIndex1 = (const int8*)_staticres->loadRawData(kEoB2SoundIndex1, temp); + _amigaSoundIndex2 = _staticres->loadRawData(kEoB2SoundIndex2, temp); + static const char *const errorSlotNoNameString[3] = { " You must specify\r a name for your\r save game!", " Spielst[nde m]ssen\r einen Namen haben!", diff --git a/engines/kyra/sound/drivers/audiomaster2.cpp b/engines/kyra/sound/drivers/audiomaster2.cpp index dbc6f30424..7db98879ad 100644 --- a/engines/kyra/sound/drivers/audiomaster2.cpp +++ b/engines/kyra/sound/drivers/audiomaster2.cpp @@ -292,12 +292,13 @@ private: class AudioMaster2ResourceManager { public: - AudioMaster2ResourceManager(AudioMaster2Internal *driver, Common::Mutex *mutex); + AudioMaster2ResourceManager(AudioMaster2Internal *driver, Common::Mutex &mutex); ~AudioMaster2ResourceManager(); void loadResourceFile(Common::SeekableReadStream *data); void initResource(SoundResource *resource); + void deinitResource(SoundResource *resource); void releaseResource(const Common::String &resName); void stopChain(); @@ -314,12 +315,12 @@ private: void linkToChain(SoundResource *resource, SoundResource::Mode mode); SoundResource *_chainPlaying; - SoundResource *_chainInactive; + SoundResource *_chainStorage; uint16 _masterVolume[3]; AudioMaster2Internal *_driver; - Common::Mutex *_mutex; + Common::Mutex &_mutex; }; class AudioMaster2IFFLoader : public Common::IFFParser { @@ -456,11 +457,16 @@ void SoundResource::loadName(Common::ReadStream *stream, uint32 size) { void SoundResource::open() { _refCnt++; + debugC(8, kDebugLevelSound, "SoundResource::open(): '%s', type '%s', new refCount: '%d'", _name.c_str(), (_type == 1) ? "SMUS" : (_type == 2 ? "INST" : "8SVX"), _refCnt); } void SoundResource::close() { - if (--_refCnt <= 0) + _refCnt--; + debugC(8, kDebugLevelSound, "SoundResource::close(): '%s', type '%s', new refCount: '%d' %s", _name.c_str(), (_type == 1) ? "SMUS" : (_type == 2 ? "INST" : "8SVX"), _refCnt, _refCnt <= 0 ? "--> RELEASED" : ""); + if (_refCnt == 0) { + _res->deinitResource(this); release(); + } } const Common::String &SoundResource::getName() const { @@ -656,6 +662,7 @@ void SoundResourceINST::loadSamples(Common::ReadStream *stream, uint32 size) { } else { // This will come up quite often in EOB II. But never with intruments that are actually used. No need to bother the user with a warning here. debugC(9, kDebugLevelSound, "SoundResourceINST::loadInstrument(): Samples resource '%s' not found for '%s'.", data, _name.c_str()); + _samplesResource = 0; } delete[] data; @@ -760,11 +767,7 @@ void SoundResourceSMUS::prepare() { _playFlags = 0; for (Common::Array::iterator trk = _tracks.begin(); trk != _tracks.end(); ++trk) { (*trk)->_dataCur = (*trk)->_dataStart; - - for (Common::Array::iterator instr = _instruments.begin(); instr != _instruments.end(); ++instr) { - (*trk)->setInstrument(*instr); - break; - } + (*trk)->setInstrument(*_instruments.begin()); if (!(*trk)->_instrument) error("SoundResourceSMUS::prepare():: Unable to assign default instrument to track (resource files loaded in the wrong order?)"); @@ -864,7 +867,7 @@ const uint16 SoundResourceSMUS::_durationTable[64] = { 0x8700, 0x4380, 0x21c0, 0x10e0, 0x0870, 0x0438, 0x021c, 0x010e }; -AudioMaster2ResourceManager::AudioMaster2ResourceManager(AudioMaster2Internal *driver, Common::Mutex *mutex) : _driver(driver), _mutex(mutex), _chainPlaying(0), _chainInactive(0) { +AudioMaster2ResourceManager::AudioMaster2ResourceManager(AudioMaster2Internal *driver, Common::Mutex &mutex) : _driver(driver), _mutex(mutex), _chainPlaying(0), _chainStorage(0) { memset(_masterVolume, 0, sizeof(_masterVolume)); } @@ -898,6 +901,36 @@ void AudioMaster2ResourceManager::initResource(SoundResource *resource) { linkToChain(res, SoundResource::kIdle); } +void AudioMaster2ResourceManager::deinitResource(SoundResource *resource) { + Common::StackLock lock(_mutex); + + SoundResource *prev = 0; + for (SoundResource *cur = _chainPlaying; cur; cur = cur->_next) { + if (cur == resource) { + if (prev) + prev->_next = cur->_next; + else + _chainPlaying = cur->_next; + cur->_next = 0; + return; + } + prev = cur; + } + + prev = 0; + for (SoundResource *cur = _chainStorage; cur; cur = cur->_next) { + if (cur == resource) { + if (prev) + prev->_next = cur->_next; + else + _chainStorage = cur->_next; + cur->_next = 0; + return; + } + prev = cur; + } +} + void AudioMaster2ResourceManager::releaseResource(const Common::String &resName) { stopChain(); @@ -910,7 +943,7 @@ void AudioMaster2ResourceManager::releaseResource(const Common::String &resName) } void AudioMaster2ResourceManager::stopChain() { - Common::StackLock lock(*_mutex); + Common::StackLock lock(_mutex); SoundResource *cur = _chainPlaying; while (cur) { @@ -922,21 +955,19 @@ void AudioMaster2ResourceManager::stopChain() { } void AudioMaster2ResourceManager::flush() { - stopChain(); + Common::StackLock lock(_mutex); - Common::StackLock lock(*_mutex); + stopChain(); - for (SoundResource *res = _chainPlaying; _chainPlaying; res = _chainPlaying) { - _chainPlaying = res->_next; - res->_next = 0; - res->setPlayStatus(false); + while (_chainPlaying) { + SoundResource *res = _chainPlaying; + deinitResource(res); res->close(); } - for (SoundResource *res = _chainInactive; _chainInactive; res = _chainInactive) { - _chainInactive = res->_next; - res->_next = 0; - res->setPlayStatus(false); + while (_chainStorage) { + SoundResource *res = _chainStorage; + deinitResource(res); res->close(); } } @@ -961,7 +992,7 @@ SoundResource *AudioMaster2ResourceManager::getResource(const Common::String &re void AudioMaster2ResourceManager::setMasterVolume(int type, int volume) { assert(type == 1 || type == 2 || type == 4); - Common::StackLock lock(*_mutex); + Common::StackLock lock(_mutex); _masterVolume[type >> 1] = volume & 0xFFFF; @@ -970,7 +1001,7 @@ void AudioMaster2ResourceManager::setMasterVolume(int type, int volume) { res->setMasterVolume(volume); } - for (SoundResource *res = _chainInactive; res; res = res->_next) { + for (SoundResource *res = _chainStorage; res; res = res->_next) { if (res->getType() == type) res->setMasterVolume(volume); } @@ -988,13 +1019,13 @@ void AudioMaster2ResourceManager::interrupt(AudioMaster2IOManager *io) { cur = cur->_next; } else if (prev) { prev->_next = cur->_next; - cur->_next = _chainInactive; - _chainInactive = cur; + cur->_next = _chainStorage; + _chainStorage = cur; cur = prev->_next; } else { _chainPlaying = cur->_next; - cur->_next = _chainInactive; - _chainInactive = cur; + cur->_next = _chainStorage; + _chainStorage = cur; cur = _chainPlaying; } } @@ -1012,11 +1043,11 @@ SoundResource *AudioMaster2ResourceManager::retrieveFromChain(const Common::Stri const char *srchStr = resName.c_str(); uint32 srchDepth = strlen(srchStr); + Common::StackLock lock(_mutex); + SoundResource *cur = _chainPlaying; SoundResource *prev = 0; - Common::StackLock lock(*_mutex); - while (cur) { if (!scumm_strnicmp(cur->getName().c_str(), srchStr, srchDepth)) { if (prev) @@ -1030,7 +1061,7 @@ SoundResource *AudioMaster2ResourceManager::retrieveFromChain(const Common::Stri cur = cur->_next; } - cur = _chainInactive; + cur = _chainStorage; prev = 0; while (cur) { @@ -1038,7 +1069,7 @@ SoundResource *AudioMaster2ResourceManager::retrieveFromChain(const Common::Stri if (prev) prev->_next = cur->_next; else - _chainInactive = cur->_next; + _chainStorage = cur->_next; cur->_next = 0; return cur; } @@ -1051,13 +1082,13 @@ SoundResource *AudioMaster2ResourceManager::retrieveFromChain(const Common::Stri void AudioMaster2ResourceManager::linkToChain(SoundResource *resource, SoundResource::Mode mode) { + Common::StackLock lock(_mutex); + if (resource->getType() == 1) { stopChain(); resource->prepare(); } - Common::StackLock lock(*_mutex); - if (mode == SoundResource::kRestart) { resource->setPlayStatus(true); resource->_next = _chainPlaying; @@ -1067,8 +1098,8 @@ void AudioMaster2ResourceManager::linkToChain(SoundResource *resource, SoundReso _driver->sync(resource); } else { - resource->_next = _chainInactive; - _chainInactive = resource; + resource->_next = _chainStorage; + _chainStorage = resource; } } @@ -1203,13 +1234,13 @@ bool AudioMaster2Internal::init() { return true; _io = new AudioMaster2IOManager(); - _res = new AudioMaster2ResourceManager(this, &_mutex); + _res = new AudioMaster2ResourceManager(this, _mutex); + startPaula(); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - startPaula(); - _ready = true; return true; @@ -1290,9 +1321,9 @@ void AudioMaster2Internal::sync(SoundResource *res) { if (res->getType() != 1) return; - SoundResourceSMUS *smus = static_cast(res); - Common::StackLock lock(_mutex); + + SoundResourceSMUS *smus = static_cast(res); _io->_tempo = smus->getTempo(); smus->setSync(_io->_sync); } diff --git a/engines/kyra/sound/sound.h b/engines/kyra/sound/sound.h index 871263cf65..6c45d8b59b 100644 --- a/engines/kyra/sound/sound.h +++ b/engines/kyra/sound/sound.h @@ -160,6 +160,11 @@ public: */ virtual void loadSoundFile(Common::String file) = 0; + /** + * Unload a specifc sound file that has been loaded before. + */ + virtual void unloadSoundFile(Common::String file) {} + /** * Load a sound file for playing sound * effects from. diff --git a/engines/kyra/sound/sound_amiga_eob.cpp b/engines/kyra/sound/sound_amiga_eob.cpp index 444c85995c..f572c11c43 100644 --- a/engines/kyra/sound/sound_amiga_eob.cpp +++ b/engines/kyra/sound/sound_amiga_eob.cpp @@ -30,7 +30,7 @@ namespace Kyra { SoundAmiga_EoB::SoundAmiga_EoB(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), - _vm(vm), _driver(0), _currentResourceSet(-1), _currentFile(-1), _levelSoundList1(0), _levelSoundList2(0), _ready(false) { + _vm(vm), _driver(0), _currentResourceSet(-1), _ready(false) { _fileBuffer = new uint8[64000]; memset(_resInfo, 0, sizeof(_resInfo)); } @@ -51,11 +51,8 @@ bool SoundAmiga_EoB::init() { if (!_driver->init()) return false; - int temp = 0; - _levelSoundList1 = _vm->staticres()->loadStrings(kEoBBaseLevelSounds1, temp); - _levelSoundList2 = _vm->staticres()->loadStrings(kEoBBaseLevelSounds2, temp); - _ready = true; + return true; } @@ -78,29 +75,12 @@ void SoundAmiga_EoB::selectAudioResourceSet(int set) { _currentResourceSet = set; } -void SoundAmiga_EoB::loadSoundFile(uint file) { - if (_vm->gameFlags().platform != Common::kPlatformAmiga || _currentResourceSet != kMusicIngame || !_ready) - return; - - unloadLevelSounds(); - - for (int i = 0; i < 2; ++i) { - if (_levelSoundList1[file * 2 + i][0]) - loadSoundFile(Common::String::format("%s.CPS", _levelSoundList1[file * 2 + i])); - if (_levelSoundList2[file * 2 + i][0]) - loadSoundFile(Common::String::format("%s.CPS", _levelSoundList2[file * 2 + i])); - } - - loadSoundFile(Common::String::format("LEVELSAM%d.CPS", file)); - - _currentFile = file; -} - void SoundAmiga_EoB::loadSoundFile(Common::String file) { if (!_ready) return; Common::SeekableReadStream *in = _vm->resource()->createReadStream(file); + debugC(6, kDebugLevelSound, "SoundAmiga_EoB::loadSoundFile(): Attempting to load sound file '%s'...%s", file.c_str(), in ? "SUCCESS" : "FILE NOT FOUND"); if (!in) return; @@ -139,6 +119,13 @@ void SoundAmiga_EoB::loadSoundFile(Common::String file) { delete[] buf; } +void SoundAmiga_EoB::unloadSoundFile(Common::String file) { + if (!_ready) + return; + debugC(5, kDebugLevelSound, "SoundAmiga_EoB::unloadSoundFile(): Attempting to free resource '%s'...%s", file.c_str(), _driver->stopSound(file) ? "SUCCESS" : "FAILURE"); + _driver->flushResource(file); +} + void SoundAmiga_EoB::playTrack(uint8 track) { if (!_musicEnabled || !_ready) return; @@ -191,21 +178,32 @@ void SoundAmiga_EoB::playSoundEffect(uint8 track, uint8 volume) { if (!_resInfo[_currentResourceSet]->soundList || track >= 120 || !_sfxEnabled) return; + if (_vm->game() == GI_EOB2 && track == 2) { + beginFadeOut(60); + return; + } + Common::String newSound = _resInfo[_currentResourceSet]->soundList[track]; + const char *suffix = (_vm->game() == GI_EOB1) ? "1.SAM" : ((track > 51 && track < 68) ? ".SMUS" : ".SAM"); if (!newSound.empty()) { if (volume == 255) { - if (_driver->startSound(newSound + "1.SAM")) { - _lastSound = newSound + "1.SAM"; + if (_driver->startSound(newSound + suffix)) { + _lastSound = newSound + suffix; return; } else { volume = 1; } } - if (volume > 0 && volume < 5) { - newSound = Common::String::format("%s%d", newSound.c_str(), volume); - _driver->startSound(newSound); + if (volume > 0 && volume < 5) + newSound = Common::String::format("%s%d", newSound.c_str(), volume); + + if (!_driver->startSound(newSound)) { + // WORKAROUND for wrongly named resources. This applies to at least 'BLADE' in the EOB II dungeons (instead of 'BLADE1'). + newSound = _resInfo[_currentResourceSet]->soundList[track]; + if (_driver->startSound(newSound)) + debugC(5, kDebugLevelSound, "SoundAmiga_EoB::playSoundEffect(): Triggered workaround for wrongly named resource: '%s'", newSound.c_str()); } _lastSound = newSound; @@ -216,6 +214,7 @@ void SoundAmiga_EoB::beginFadeOut(int delay) { _driver->fadeOut(delay); while (_driver->isFading() && !_vm->shouldQuit()) _vm->delay(5); + haltTrack(); } void SoundAmiga_EoB::updateVolumeSettings() { @@ -234,23 +233,4 @@ int SoundAmiga_EoB::checkTrigger() { return _driver->getPlayDuration(); } -void SoundAmiga_EoB::unloadLevelSounds() { - if (_currentFile != -1) { - _driver->flushResource(Common::String::format("L%dM1A1", _currentFile)); - _driver->flushResource(Common::String::format("L%dM2A1", _currentFile)); - - for (int i = 1; i < 5; ++i) { - _driver->flushResource(Common::String::format("L%dM1M%d", _currentFile, i)); - _driver->flushResource(Common::String::format("L%dM2M%d", _currentFile, i)); - } - - for (int i = 0; i < 2; ++i) { - if (_levelSoundList1[_currentFile * 2 + i][0]) - _driver->flushResource(_levelSoundList1[_currentFile * 2 + i]); - if (_levelSoundList2[_currentFile * 2 + i][0]) - _driver->flushResource(_levelSoundList2[_currentFile * 2 + i]); - } - } -} - } // End of namespace Kyra diff --git a/engines/kyra/sound/sound_intern.h b/engines/kyra/sound/sound_intern.h index fbf19d742e..57afb26ab5 100644 --- a/engines/kyra/sound/sound_intern.h +++ b/engines/kyra/sound/sound_intern.h @@ -417,8 +417,9 @@ public: void initAudioResourceInfo(int set, void *info); void selectAudioResourceSet(int set); bool hasSoundFile(uint file) const { return false; } - void loadSoundFile(uint file); + void loadSoundFile(uint) {} void loadSoundFile(Common::String file); + void unloadSoundFile(Common::String file); void playTrack(uint8 track); void haltTrack(); void playSoundEffect(uint8 track, uint8 volume = 0xFF); @@ -428,8 +429,6 @@ public: int checkTrigger(); private: - void unloadLevelSounds(); - uint8 *_fileBuffer; KyraEngine_v1 *_vm; @@ -438,10 +437,6 @@ private: Common::String _lastSound; int _currentResourceSet; - int _currentFile; - - const char *const *_levelSoundList1; - const char *const *_levelSoundList2; bool _ready; }; -- cgit v1.2.3