From a0326ecd1c5231d7767b7c20beb8d77e64852de2 Mon Sep 17 00:00:00 2001 From: D G Turner Date: Thu, 15 Jul 2021 11:36:05 +0100 Subject: [PATCH] AGI: Modify Volume to use ScummVM GUI as maximum range for Script Volume This change simplifies the AGI engine volume handling by using the music and sound fx volumes set in the ScummVM GUI as the maximum levels which can be set by the scripts. This avoids the complexity of synchronising changes between these and the scripts (which only had a single 16 step volume range which is inverted in meaning by quite a large number of fangames). This still allows the game scripts to adjust the volumes, but only within the maximum range set in the Launcher / GMM. This avoids issues such as https://bugs.scummvm.org/ticket/10732 where users complained about extremely loud output in some cases. --- engines/agi/agi.cpp | 7 ++-- engines/agi/agi.h | 3 +- engines/agi/global.cpp | 80 ++++++++++++---------------------------- engines/agi/saveload.cpp | 3 +- 4 files changed, 28 insertions(+), 65 deletions(-) diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 925e5609f95..86df9b49c86 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -175,8 +175,7 @@ int AgiEngine::agiInit() { // Reset in-game timer inGameTimerReset(); - // Sync volume settings from ScummVM system settings - setVolumeViaSystemSetting(); + applyVolumeToMixer(); return ec; } @@ -378,7 +377,7 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas _instructionCounter = 0; resetGetVarSecondsHeuristic(); - _setVolumeBrokenFangame = false; // for further study see AgiEngine::setVolumeViaScripts() + _setVolumeBrokenFangame = false; // for further study see AgiEngine::applyVolumeToMixer() _playTimeInSecondsAdjust = 0; _lastUsedPlayTimeInCycles = 0; @@ -530,7 +529,7 @@ Common::Error AgiEngine::go() { void AgiEngine::syncSoundSettings() { Engine::syncSoundSettings(); - setVolumeViaSystemSetting(); + applyVolumeToMixer(); } // WORKAROUND: diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 504f52e5f85..42860f5d04f 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -875,8 +875,7 @@ public: void setVar(int16 varNr, byte newValue); private: - void setVolumeViaScripts(byte newVolume); - void setVolumeViaSystemSetting(); + void applyVolumeToMixer(); public: void syncSoundSettings() override; diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp index 46f50bc7386..c5f5c3100e3 100644 --- a/engines/agi/global.cpp +++ b/engines/agi/global.cpp @@ -60,7 +60,7 @@ void AgiEngine::setVar(int16 varNr, byte newValue) { setVarSecondsTrigger(newValue); break; case VM_VAR_VOLUME: - setVolumeViaScripts(newValue); + applyVolumeToMixer(); break; default: break; @@ -85,11 +85,11 @@ byte AgiEngine::getVar(int16 varNr) { return _game.vars[varNr]; } -// sets volume based on script value -// 0 - maximum volume -// 15 - mute -void AgiEngine::setVolumeViaScripts(byte newVolume) { - newVolume = CLIP(newVolume, 0, 15); +// sets volume to mixer using game variable for volume where 0 is maximum volume to 15 being mute +void AgiEngine::applyVolumeToMixer() { + debug(2, "applyVolumeToMixer() volume: %d _veryFirstInitialCycle: %d getFeatures(): %d gameId: %d", _game.vars[VM_VAR_VOLUME], _veryFirstInitialCycle, getFeatures(), getGameID()); + + byte gameVolume = CLIP(_game.vars[VM_VAR_VOLUME], 0, 15); if (_veryFirstInitialCycle) { // WORKAROUND: @@ -102,10 +102,9 @@ void AgiEngine::setVolumeViaScripts(byte newVolume) { // See bug #7035 if (getFeatures() & GF_FANMADE) { // We only check for fan games, Sierra always did it properly of course - if (newVolume == 15) { - // Volume gets set to mute at the start? - // Probably broken fan game detected, set flag - debug("Broken volume in fan game detected, enabling workaround"); + if (gameVolume == 15) { + // Volume gets set to mute at the start? Probably broken fan game detected so set flag + debug(1, "Broken volume in fan game detected, enabling workaround"); _setVolumeBrokenFangame = true; } } @@ -114,61 +113,28 @@ void AgiEngine::setVolumeViaScripts(byte newVolume) { if (!_setVolumeBrokenFangame) { // In AGI 15 is mute, 0 is loudest // Some fan games set this incorrectly as 15 for loudest, 0 for mute - newVolume = 15 - newVolume; // turn volume around + gameVolume = 15 - gameVolume; // turn volume around } - int scummVMVolume = newVolume * Audio::Mixer::kMaxMixerVolume / 15; - bool scummVMMute = false; + int musicVolume = ConfMan.getInt("music_volume"); + int soundEffectVolume = ConfMan.getInt("sfx_volume"); - // Set ScummVM setting - // We do not set "mute". In case "mute" is set, we will not apply the scripts wishes - ConfMan.setInt("music_volume", scummVMVolume); - ConfMan.setInt("sfx_volume", scummVMVolume); + musicVolume *= gameVolume; + musicVolume /= 15; - if (ConfMan.hasKey("mute")) - scummVMMute = ConfMan.getBool("mute"); + soundEffectVolume *= gameVolume; + soundEffectVolume /= 15; - if (!scummVMMute) { - // Also change volume directly - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolume); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolume); - } -} + musicVolume = CLIP(musicVolume, 0, Audio::Mixer::kMaxMixerVolume); + soundEffectVolume = CLIP(soundEffectVolume, 0, Audio::Mixer::kMaxMixerVolume); -void AgiEngine::setVolumeViaSystemSetting() { - int scummVMVolumeMusic = ConfMan.getInt("music_volume"); - int scummVMVolumeSfx = ConfMan.getInt("sfx_volume"); - bool scummVMMute = false; - int internalVolume = 0; - - if (ConfMan.hasKey("mute")) - scummVMMute = ConfMan.getBool("mute"); - - // Clip user system setting - scummVMVolumeMusic = CLIP(scummVMVolumeMusic, 0, Audio::Mixer::kMaxMixerVolume); - scummVMVolumeSfx = CLIP(scummVMVolumeSfx, 0, Audio::Mixer::kMaxMixerVolume); - - if (scummVMMute) { - scummVMVolumeMusic = 0; - scummVMVolumeSfx = 0; + bool soundIsMuted = false; + if (ConfMan.hasKey("mute")) { + soundIsMuted = ConfMan.getBool("mute"); } - // Now actually set it - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolumeSfx); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolumeMusic); - - // Take lowest volume to the scripts - if (scummVMVolumeMusic < scummVMVolumeSfx) { - internalVolume = scummVMVolumeMusic; - } else { - internalVolume = scummVMVolumeSfx; - } - // Change it to 0-15 range - internalVolume = (internalVolume + 1) * 15 / Audio::Mixer::kMaxMixerVolume; - // Reverse it - internalVolume = 15 - internalVolume; - // Put it into the VM variable. Directly set it, otherwise it would call a volume set call - _game.vars[VM_VAR_VOLUME] = internalVolume; + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundIsMuted ? 0 : musicVolume); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundIsMuted ? 0 : soundEffectVolume); } void AgiEngine::resetGetVarSecondsHeuristic() { diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index b1ecf190e46..52b49de9f86 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -753,8 +753,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { // copy everything over (we should probably only copy over the remaining parts of the screen w/o play screen _gfx->copyDisplayToScreen(); - // Sync volume settings from ScummVM system settings, so that VM volume variable is overwritten - setVolumeViaSystemSetting(); + applyVolumeToMixer(); return errOK; }