/* 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 "audio/audiostream.h" #include "audio/mixer.h" #include "audio/decoders/raw.h" #include "common/config-manager.h" #include "common/textconsole.h" #include "common/substream.h" #include "backends/audiocd/audiocd.h" #include "drascula/drascula.h" namespace Drascula { void DrasculaEngine::syncSoundSettings() { // Sync the engine with the config manager bool mute = false; if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); // We need to handle the speech mute separately here. This is because the // engine code should be able to rely on all speech sounds muted when the // user specified subtitles only mode, which results in "speech_mute" to // be set to "true". The global mute setting has precedence over the // speech mute setting though. bool speechMute = mute; if (!speechMute) speechMute = ConfMan.getBool("speech_mute"); _mixer->muteSoundType(Audio::Mixer::kPlainSoundType, mute); _mixer->muteSoundType(Audio::Mixer::kSFXSoundType, mute); _mixer->muteSoundType(Audio::Mixer::kSpeechSoundType, speechMute); _mixer->muteSoundType(Audio::Mixer::kMusicSoundType, mute); int voiceVolume = ConfMan.getInt("speech_volume"); int musicVolume = ConfMan.getInt("music_volume"); // If the music and voice volume are correct, don't change anything. // Otherwise compute the master volume using an approximation of sqrt(max) * 16 which would result in the master // volume being the same value as the max of music and voice. if (_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) != voiceVolume || _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) != musicVolume) { int masterVolume = MAX(musicVolume, voiceVolume) * 2 / 3 + 86; _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, masterVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, voiceVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, voiceVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, musicVolume); } } int DrasculaEngine::updateVolume(int prevVolume, int prevVolumeY) { prevVolumeY += 10; if (_mouseY < prevVolumeY && prevVolume < 15) prevVolume++; if (_mouseY > prevVolumeY && prevVolume > 0) prevVolume--; return prevVolume; } void DrasculaEngine::volumeControls() { if (_lang == kSpanish && currentChapter != 6) loadPic(95, tableSurface); copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface); updateScreen(73, 63, 73, 63, 177, 97, screenSurface); setCursor(kCursorCrosshair); showCursor(); // The engine has three volume controls: master, SFx/Speech and Music. // ScummVM doesn't have a master volume, so we abuse the kPlainSoundType to store it. // In drascula, we only use the kMusicSoundType and kSpeechSoundType to play sounds. // For consistency with the ScummVM options dialog we also set the kSFXSoundType volume // to the same value as the kMusicSoundType value, but we don't actually use it. // The engines uses masterVolume, voiceVolume and musicVolume between 0 and 15. // We store in the mixer: // - masterVolume * 16 in kPlainSoundType // - (masterVolume + 1) * (voiceVolume + 1) - 1 in both kSpeechSoundType and kSFXSoundType // - (masterVolume + 1) * (musicVolume + 1) - 1 in kMusicSoundType while (!shouldQuit()) { int masterVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16), 0, 15); int voiceVolume = CLIP(((_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) + 1) / (masterVolume + 1) - 1), 0, 15); int musicVolume = CLIP(((_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 1) / (masterVolume + 1) - 1), 0, 15); int masterVolumeY = 72 + 61 - masterVolume * 4; int voiceVolumeY = 72 + 61 - voiceVolume * 4; int musicVolumeY = 72 + 61 - musicVolume * 4; updateRoom(); copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface); copyBackground(183, 56, 82, masterVolumeY, 39, 2 + masterVolume * 4, tableSurface, screenSurface); copyBackground(183, 56, 138, voiceVolumeY, 39, 2 + voiceVolume * 4, tableSurface, screenSurface); copyBackground(183, 56, 194, musicVolumeY, 39, 2 + musicVolume * 4, tableSurface, screenSurface); updateScreen(); updateEvents(); // we're ignoring keypresses, so just empty the keyboard buffer while (getScan()) ; if (_rightMouseButton == 1) { // Clear this to avoid going straight to the inventory _rightMouseButton = 0; delay(100); break; } if (_leftMouseButton == 1) { delay(100); if (_mouseX > 80 && _mouseX < 121) { masterVolume = updateVolume(masterVolume, masterVolumeY); _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, masterVolume * 16); } if (_mouseX > 136 && _mouseX < 178) voiceVolume = updateVolume(voiceVolume, voiceVolumeY); if (_mouseX > 192 && _mouseX < 233) musicVolume = updateVolume(musicVolume, musicVolumeY); voiceVolume = (masterVolume + 1) * (voiceVolume + 1) - 1; _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, voiceVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, voiceVolume); ConfMan.setInt("speech_volume", voiceVolume); ConfMan.setInt("sfx_volume", voiceVolume); musicVolume = (masterVolume + 1) * (musicVolume + 1) - 1; _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, musicVolume); ConfMan.setInt("music_volume", musicVolume); } } if (_lang == kSpanish && currentChapter != 6) loadPic(974, tableSurface); selectVerb(kVerbNone); updateEvents(); } void DrasculaEngine::playSound(int soundNum) { char file[20]; sprintf(file, "s%i.als", soundNum); playFile(file); } void DrasculaEngine::finishSound() { delay(1); while (soundIsActive()) _system->delayMillis(10); } void DrasculaEngine::playMusic(int p) { _system->getAudioCDManager()->stop(); _system->getAudioCDManager()->play(p - 1, 1, 0, 0); } void DrasculaEngine::stopMusic() { _system->getAudioCDManager()->stop(); } void DrasculaEngine::updateMusic() { _system->getAudioCDManager()->update(); } int DrasculaEngine::musicStatus() { return _system->getAudioCDManager()->isPlaying(); } void DrasculaEngine::stopSound() { _mixer->stopHandle(_soundHandle); } void DrasculaEngine::MusicFadeout() { int org_vol = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType); while (!shouldQuit()) { int vol = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType); vol -= 10; if (vol < 0) vol = 0; _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol); if (vol == 0) break; updateEvents(); _system->updateScreen(); _system->delayMillis(50); } _system->getAudioCDManager()->stop(); _system->delayMillis(100); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, org_vol); } void DrasculaEngine::playFile(const char *fname) { Common::SeekableReadStream *stream = _archives.open(fname); if (stream) { int startOffset = 32; int soundSize = stream->size() - 64; if (!strcmp(fname, "3.als") && soundSize == 145166 && _lang != kSpanish) { // WORKAROUND: File 3.als with English speech files has a big silence at // its beginning and end. We seek past the silence at the beginning, // and ignore the silence at the end // Fixes bug #2111815 - "DRASCULA: Voice delayed" startOffset = 73959; soundSize = soundSize - startOffset - 26306; } Common::SeekableReadStream *subStream = new Common::SeekableSubReadStream( stream, startOffset, startOffset + soundSize, DisposeAfterUse::YES); if (!subStream) { warning("playFile: Out of memory"); delete stream; return; } Audio::AudioStream *sound = Audio::makeRawStream(subStream, 11025, Audio::FLAG_UNSIGNED); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, sound); } else warning("playFile: Could not open %s", fname); } bool DrasculaEngine::soundIsActive() { return _mixer->isSoundHandleActive(_soundHandle); } } // End of namespace Drascula