Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/sound/base_sound_buffer.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseSound, false)
//////////////////////////////////////////////////////////////////////////
BaseSound::BaseSound(BaseGame *inGame) : BaseClass(inGame) {
_sound = nullptr;
_soundFilename = nullptr;
_soundType = TSoundType::SOUND_SFX;
_soundStreamed = false;
_soundLooping = false;
_soundPlaying = false;
_soundPaused = false;
_soundFreezePaused = false;
_soundPosition = 0;
_soundPrivateVolume = 0;
_soundLoopStart = 0;
_sFXType = SFX_NONE;
_sFXParam1 = _sFXParam2 = _sFXParam3 = _sFXParam4 = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseSound::~BaseSound() {
if (_sound) {
_game->_soundMgr->removeSound(_sound);
}
_sound = nullptr;
SAFE_DELETE_ARRAY(_soundFilename);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setSound(const char *filename, TSoundType type, bool streamed, uint32 initialPrivateVolume) {
if (_sound) {
_game->_soundMgr->removeSound(_sound);
_sound = nullptr;
}
SAFE_DELETE_ARRAY(_soundFilename);
_sound = _game->_soundMgr->addSound(filename, type, streamed, initialPrivateVolume);
if (_sound) {
size_t nameSize = strlen(filename) + 1;
_soundFilename = new char[nameSize];
Common::strcpy_s(_soundFilename, nameSize, filename);
_soundType = type;
_soundStreamed = streamed;
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setSoundSimple() {
_sound = _game->_soundMgr->addSound(_soundFilename, _soundType, _soundStreamed);
if (_sound) {
if (_soundPosition) {
_sound->setPosition(_soundPosition);
}
_sound->_looping = _soundLooping;
_sound->setPrivateVolume(_soundPrivateVolume);
_sound->_loopStart = _soundLoopStart;
_sound->_freezePaused = _soundFreezePaused;
if (_soundPlaying) {
return _sound->resume();
} else {
return STATUS_OK;
}
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseSound::getLength() {
if (_sound) {
return _sound->getLength();
} else {
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::play(bool looping) {
if (_sound) {
_soundPaused = false;
return _sound->play(looping, _soundPosition);
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::stop() {
if (_sound) {
_soundPaused = false;
return _sound->stop();
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::pause(bool freezePaused) {
if (_sound) {
_soundPaused = true;
if (freezePaused) {
_sound->_freezePaused = true;
}
return _sound->pause();
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::resume() {
if (_sound && _soundPaused) {
_soundPaused = false;
return _sound->resume();
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::persist(BasePersistenceManager *persistMgr) {
if (persistMgr->getIsSaving() && _sound) {
_soundPlaying = _sound->isPlaying();
_soundLooping = _sound->_looping;
_soundPrivateVolume = _sound->_privateVolume;
if (_soundPlaying) {
_soundPosition = _sound->getPosition();
}
_soundLoopStart = _sound->_loopStart;
_soundFreezePaused = _sound->_freezePaused;
}
if (persistMgr->getIsSaving()) {
_sFXType = SFX_NONE;
_sFXParam1 = _sFXParam2 = _sFXParam3 = _sFXParam4 = 0;
}
persistMgr->transferPtr(TMEMBER_PTR(_game));
persistMgr->transferCharPtr(TMEMBER(_soundFilename));
persistMgr->transferBool(TMEMBER(_soundLooping));
persistMgr->transferBool(TMEMBER(_soundPaused));
persistMgr->transferBool(TMEMBER(_soundFreezePaused));
persistMgr->transferBool(TMEMBER(_soundPlaying));
persistMgr->transferUint32(TMEMBER(_soundPosition));
persistMgr->transferSint32(TMEMBER(_soundPrivateVolume));
persistMgr->transferBool(TMEMBER(_soundStreamed));
persistMgr->transferSint32(TMEMBER_INT(_soundType));
persistMgr->transferUint32(TMEMBER(_soundLoopStart));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::isPlaying() {
return _sound && _sound->isPlaying();
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::isPaused() {
return _sound && _soundPaused;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setPositionTime(uint32 time) {
if (!_sound) {
return STATUS_FAILED;
}
_soundPosition = time;
bool ret = _sound->setPosition(_soundPosition);
if (_sound->isPlaying()) {
_soundPosition = 0;
}
return ret;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseSound::getPositionTime() {
if (!_sound) {
return 0;
}
if (!_sound->isPlaying()) {
return 0;
} else {
return _sound->getPosition();
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setVolume(int volume) {
if (!_sound) {
return STATUS_FAILED;
} else {
return _sound->setPrivateVolume(volume);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setPrivateVolume(int volume) {
if (!_sound) {
return STATUS_FAILED;
} else {
_sound->_privateVolume = volume;
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
int BaseSound::getVolume() {
if (!_sound) {
return 0;
} else {
return _sound->_privateVolume;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setLoopStart(uint32 pos) {
if (!_sound) {
return STATUS_FAILED;
} else {
_sound->setLoopStart(pos);
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::setPan(float pan) {
if (_sound) {
return _sound->setPan(pan);
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSound::applyFX(TSFXType type, float param1, float param2, float param3, float param4) {
if (!_sound) {
return STATUS_OK;
}
if (type != _sFXType || param1 != _sFXParam1 || param2 != _sFXParam2 || param3 != _sFXParam3 || param4 != _sFXParam4) {
bool ret = _sound->applyFX(type, param1, param2, param3, param4);
_sFXType = type;
_sFXParam1 = param1;
_sFXParam2 = param2;
_sFXParam3 = param3;
_sFXParam4 = param4;
return ret;
}
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,85 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SOUND_H
#define WINTERMUTE_BASE_SOUND_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/dctypes.h" // Added by ClassView
#include "engines/wintermute/persistent.h"
#include "audio/mixer.h"
namespace Wintermute {
class BaseSoundBuffer;
class BaseSound : public BaseClass {
public:
bool setPan(float pan);
int32 _soundPrivateVolume;
int getVolume();
bool setVolume(int volume);
bool setPrivateVolume(int volume);
bool setLoopStart(uint32 pos);
uint32 getPositionTime();
bool setPositionTime(uint32 time);
bool _soundPaused;
bool _soundFreezePaused;
bool isPlaying();
bool isPaused();
bool _soundPlaying;
bool _soundLooping;
uint32 _soundLoopStart;
uint32 _soundPosition;
DECLARE_PERSISTENT(BaseSound, BaseClass)
bool resume();
bool pause(bool freezePaused = false);
bool stop();
bool play(bool looping = false);
uint32 getLength();
bool _soundStreamed;
TSoundType _soundType;
char *_soundFilename;
bool setSoundSimple();
bool setSound(const char *filename, TSoundType type = TSoundType::SOUND_SFX, bool streamed = false, uint32 initialPrivateVolume = 100);
BaseSound(BaseGame *inGame);
~BaseSound() override;
bool applyFX(TSFXType type = SFX_NONE, float param1 = 0, float param2 = 0, float param3 = 0, float param4 = 0);
TSFXType _sFXType;
float _sFXParam1;
float _sFXParam2;
float _sFXParam3;
float _sFXParam4;
private:
BaseSoundBuffer *_sound;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,322 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/sound/base_sound_buffer.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/dcgf.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#ifdef USE_VORBIS
#include "audio/decoders/vorbis.h"
#endif
#include "audio/decoders/wave.h"
#include "audio/decoders/raw.h"
#include "common/system.h"
#include "common/substream.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
BaseSoundBuffer::BaseSoundBuffer(BaseGame *inGame) : BaseClass(inGame) {
_stream = nullptr;
_handle = nullptr;
_streamed = false;
_filename = nullptr;
_privateVolume = 100;
_volume = 255;
_pan = 0;
_looping = false;
_loopStart = 0;
_startPos = 0;
_type = TSoundType::SOUND_SFX;
_freezePaused = false;
}
//////////////////////////////////////////////////////////////////////////
BaseSoundBuffer::~BaseSoundBuffer() {
stop();
if (_handle) {
g_system->getMixer()->stopHandle(*_handle);
SAFE_DELETE(_handle);
}
SAFE_DELETE(_stream);
SAFE_DELETE_ARRAY(_filename);
}
//////////////////////////////////////////////////////////////////////////
void BaseSoundBuffer::setStreaming(bool streamed, uint32 numBlocks, uint32 blockSize) {
_streamed = streamed;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::loadFromFile(const char *filename, bool forceReload) {
if (_handle) {
g_system->getMixer()->stopHandle(*_handle);
SAFE_DELETE(_handle);
}
SAFE_DELETE(_stream);
// Load a file, but avoid having the File-manager handle the disposal of it.
Common::SeekableReadStream *file = _game->_fileManager->openFile(filename, true, false);
if (!file) {
_game->LOG(0, "Error opening sound file '%s'", filename);
return STATUS_FAILED;
}
Common::String strFilename(filename);
strFilename.toLowercase();
if (strFilename.hasSuffix(".ogg")) {
#ifdef USE_VORBIS
_stream = Audio::makeVorbisStream(file, DisposeAfterUse::YES);
#else
error("BSoundBuffer::loadFromFile - Ogg Vorbis not supported by this version of ScummVM (please report as this shouldn't trigger)");
#endif
} else if (strFilename.hasSuffix(".wav")) {
int waveSize, waveRate;
byte waveFlags;
uint16 waveType;
if (Audio::loadWAVFromStream(*file, waveSize, waveRate, waveFlags, &waveType)) {
if (waveType == 1) {
// We need to wrap the file in a substream to make sure the size is right.
file = new Common::SeekableSubReadStream(file, file->pos(), waveSize + file->pos(), DisposeAfterUse::YES);
_stream = Audio::makeRawStream(file, waveRate, waveFlags, DisposeAfterUse::YES);
} else {
error("BSoundBuffer::loadFromFile - WAVE not supported yet for %s with type %d", filename, waveType);
}
}
} else {
error("BSoundBuffer::loadFromFile - Unknown filetype for %s", filename);
}
if (!_stream) {
_game->LOG(0, "BSoundBuffer::koadFromFile - Error while loading '%s'", filename);
return STATUS_FAILED;
}
BaseUtils::setString(&_filename, filename);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::play(bool looping, uint32 startSample) {
if (_handle) {
g_system->getMixer()->stopHandle(*_handle);
SAFE_DELETE(_handle);
}
// Store the loop-value for save-games.
setLooping(looping);
if (_stream) {
_stream->seek(startSample);
_handle = new Audio::SoundHandle;
Audio::Mixer::SoundType type = Audio::Mixer::SoundType::kPlainSoundType;
if (_type == TSoundType::SOUND_SFX) {
type = Audio::Mixer::SoundType::kSFXSoundType;
} else if (_type == TSoundType::SOUND_MUSIC) {
type = Audio::Mixer::SoundType::kMusicSoundType;
} else if (_type == TSoundType::SOUND_SPEECH) {
type = Audio::Mixer::SoundType::kSpeechSoundType;
}
if (_looping) {
if (_loopStart != 0) {
Audio::AudioStream *loopStream = new Audio::SubLoopingAudioStream(_stream, 0, Audio::Timestamp((_loopStart * 1000) / _stream->getRate(), _stream->getRate()), _stream->getLength(), DisposeAfterUse::NO);
g_system->getMixer()->playStream(type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES);
} else {
Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO);
g_system->getMixer()->playStream(type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES);
}
} else {
g_system->getMixer()->playStream(type, _handle, _stream, -1, _volume, _pan, DisposeAfterUse::NO);
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseSoundBuffer::setLooping(bool looping) {
_looping = looping;
if (isPlaying()) {
// This warning is here, to see if this is ever the case.
warning("BSoundBuffer::SetLooping(%d) - won't change a playing sound", looping); // TODO
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::resume() {
// If the sound was paused while active:
if (_stream && _handle) {
g_system->getMixer()->pauseHandle(*_handle, false);
} else if (_stream) { // Otherwise we come from a savegame, and thus have no handle
play(_looping, _startPos);
} else {
warning("BaseSoundBuffer::resume - Called without a handle or a stream");
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::stop() {
if (_stream && _handle) {
g_system->getMixer()->stopHandle(*_handle);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::pause() {
if (_stream && _handle) {
g_system->getMixer()->pauseHandle(*_handle, true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseSoundBuffer::getLength() {
if (_stream) {
uint32 len = _stream->getLength().msecs();
return len;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void BaseSoundBuffer::setType(TSoundType type) {
_type = type;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::setVolume(int volume) {
volume = (float)volume / 100.0f * _privateVolume;
_volume = (volume * Audio::Mixer::kMaxChannelVolume) / 100;
if (_stream && _handle) {
g_system->getMixer()->setChannelVolume(*_handle, (byte)(_volume));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::setPrivateVolume(int volume) {
_privateVolume = volume;
return setVolume(volume);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::isPlaying() {
if (_stream && _handle) {
return _freezePaused || g_system->getMixer()->isSoundHandleActive(*_handle);
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseSoundBuffer::getPosition() {
if (_stream && _handle) {
uint32 pos = g_system->getMixer()->getSoundElapsedTime(*_handle);
return pos;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::setPosition(uint32 pos) {
if (_stream) {
_stream->seek(pos);
} else {
if (isPlaying()) {
warning("BaseSoundBuffer::SetPosition - not implemented for playing sounds yet.");
}
}
_startPos = pos;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::setLoopStart(uint32 pos) {
_loopStart = pos;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::setPan(float pan) {
pan = MAX(pan, -1.0f);
pan = MIN(pan, 1.0f);
_pan = (int8)(pan * 127);
if (_handle) {
g_system->getMixer()->setChannelBalance(*_handle, _pan);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundBuffer::applyFX(TSFXType type, float param1, float param2, float param3, float param4) {
// TODO
switch (type) {
case SFX_ECHO:
warning("BaseSoundBuffer::ApplyFX(SFX_ECHO, %f, %f, %f, %f) - not implemented yet", param1, param2, param3, param4);
break;
case SFX_REVERB:
warning("BaseSoundBuffer::ApplyFX(SFX_REVERB, %f, %f, %f, %f) - not implemented yet", param1, param2, param3, param4);
break;
default:
break;
}
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,94 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SOUNDBUFFER_H
#define WINTERMUTE_BASE_SOUNDBUFFER_H
#include "engines/wintermute/base/base.h"
#include "audio/mixer.h"
#include "common/stream.h"
namespace Audio {
class SeekableAudioStream;
class SoundHandle;
}
namespace Wintermute {
class BaseSoundBuffer : public BaseClass {
public:
BaseSoundBuffer(BaseGame *inGame);
~BaseSoundBuffer() override;
bool pause();
bool play(bool looping = false, uint32 startSample = 0);
bool resume();
bool stop();
bool isPlaying();
void setLooping(bool looping);
uint32 getPosition();
bool setPosition(uint32 pos);
uint32 getLength();
bool setLoopStart(uint32 pos);
uint32 getLoopStart() const {
return _loopStart;
}
bool setPan(float pan);
bool setPrivateVolume(int colume);
bool setVolume(int colume);
void setType(TSoundType type);
bool loadFromFile(const char *filename, bool forceReload = false);
void setStreaming(bool streamed, uint32 numBlocks = 0, uint32 blockSize = 0);
bool applyFX(TSFXType type, float param1, float param2, float param3, float param4);
bool _freezePaused;
uint32 _loopStart;
TSoundType _type;
bool _looping;
char *_filename;
bool _streamed;
int32 _privateVolume;
Audio::SeekableAudioStream *_stream;
Audio::SoundHandle *_handle;
int32 _volume;
uint32 _startPos;
int8 _pan;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,310 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/utils/path_util.h"
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/sound/base_sound_buffer.h"
#include "engines/wintermute/wintermute.h"
#include "common/config-manager.h"
#include "audio/mixer.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//IMPLEMENT_PERSISTENT(BaseSoundMgr, true)
//////////////////////////////////////////////////////////////////////////
BaseSoundMgr::BaseSoundMgr(BaseGame *inGame) : BaseClass(inGame) {
_soundAvailable = false;
_volumeMaster = 100;
}
//////////////////////////////////////////////////////////////////////////
BaseSoundMgr::~BaseSoundMgr() {
saveSettings();
cleanup();
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::cleanup() {
for (int32 i = 0; i < _sounds.getSize(); i++) {
delete _sounds[i];
}
_sounds.removeAll();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseSoundMgr::saveSettings() {
if (_soundAvailable) {
ConfMan.setInt("master_volume_percent", _volumeMaster);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::initialize() {
_soundAvailable = false;
if (!g_system->getMixer()->isReady()) {
return STATUS_FAILED;
}
g_engine->syncSoundSettings();
_volumeMaster = (ConfMan.hasKey("master_volume_percent") ? ConfMan.getInt("master_volume_percent") : 100);
_soundAvailable = true;
setMasterVolumePercent(_volumeMaster);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::initLoop() {
if (!_soundAvailable) {
return STATUS_OK;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
BaseSoundBuffer *BaseSoundMgr::addSound(const char *filename, TSoundType type, bool streamed, uint32 initialPrivateVolume) {
if (!_soundAvailable) {
return nullptr;
}
if (!filename || filename[0] == '\0') {
// At least one game, Bickadoodle, calls playSound with an empty filename, see #6594
BaseEngine::LOG(0, "addSound called with empty filename");
}
BaseSoundBuffer *sound;
Common::String useFilename = filename;
useFilename.toLowercase();
// try to switch WAV to OGG file (if available)
if (useFilename.hasSuffix(".wav")) {
Common::String oggFilename = useFilename;
oggFilename.erase(oggFilename.size() - 4);
oggFilename = oggFilename + ".ogg";
if (_game->_fileManager->hasFile(oggFilename)) {
useFilename = oggFilename;
}
}
sound = new BaseSoundBuffer(_game);
if (!sound) {
return nullptr;
}
sound->setStreaming(streamed);
sound->setType(type);
bool res = sound->loadFromFile(useFilename.c_str());
if (DID_FAIL(res)) {
_game->LOG(res, "Error loading sound '%s'", useFilename.c_str());
delete sound;
return nullptr;
}
// sound starts with user defined instead of 100% volume (of the global setting)
sound->setPrivateVolume(initialPrivateVolume);
// register sound
_sounds.add(sound);
return sound;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::addSound(BaseSoundBuffer *sound, TSoundType type) {
if (!sound) {
return STATUS_FAILED;
}
// register sound
_sounds.add(sound);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::removeSound(BaseSoundBuffer *sound) {
for (int32 i = 0; i < _sounds.getSize(); i++) {
if (_sounds[i] == sound) {
delete _sounds[i];
_sounds.removeAt(i);
return STATUS_OK;
}
}
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::setVolume(TSoundType type, int volume) {
if (!_soundAvailable) {
return STATUS_OK;
}
switch (type) {
case TSoundType::SOUND_SFX:
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, (volume * Audio::Mixer::kMaxChannelVolume) / 100);
ConfMan.setInt("sfx_volume", g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSFXSoundType));
break;
case TSoundType::SOUND_SPEECH:
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, (volume * Audio::Mixer::kMaxChannelVolume) / 100);
ConfMan.setInt("speech_volume", g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType));
break;
case TSoundType::SOUND_MUSIC:
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, (volume * Audio::Mixer::kMaxChannelVolume) / 100);
ConfMan.setInt("music_volume", g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType));
break;
default:
break;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::setVolumePercent(TSoundType type, byte percent) {
return setVolume(type, percent);
}
//////////////////////////////////////////////////////////////////////////
byte BaseSoundMgr::getVolumePercent(TSoundType type) {
int volume = 0;
switch (type) {
case TSoundType::SOUND_SFX:
volume = ConfMan.getInt("sfx_volume") * 100 / Audio::Mixer::kMaxChannelVolume;
break;
case TSoundType::SOUND_SPEECH:
volume = ConfMan.getInt("speech_volume") * 100 / Audio::Mixer::kMaxChannelVolume;
break;
case TSoundType::SOUND_MUSIC:
volume = ConfMan.getInt("music_volume") * 100 / Audio::Mixer::kMaxChannelVolume;
break;
default:
break;
}
return (byte)volume;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::setMasterVolumePercent(byte percent) {
_volumeMaster = percent;
for (int32 i = 0; i < _sounds.getSize(); i++) {
_sounds[i]->setVolume(percent);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
byte BaseSoundMgr::getMasterVolumePercent() {
return _volumeMaster;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::pauseAll(bool includingMusic) {
for (int32 i = 0; i < _sounds.getSize(); i++) {
if (_sounds[i]->isPlaying() && (_sounds[i]->_type != TSoundType::SOUND_MUSIC || includingMusic)) {
_sounds[i]->pause();
_sounds[i]->_freezePaused = true;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSoundMgr::resumeAll() {
for (int32 i = 0; i < _sounds.getSize(); i++) {
if (_sounds[i]->_freezePaused) {
_sounds[i]->resume();
_sounds[i]->_freezePaused = false;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
float BaseSoundMgr::posToPan(int x, int y) {
/*
* This is tricky to do right. Scenes could be scrolling (thus bigger than rendering width)
* and even then objects that emit sound could be "outside" the scene.
*
* As a compromise, the range where panning is applied is defined from
* (-0.5 * width) .. 0 .. (+1.5 * width).
*
* Because the sound library might simply ignore values out of range, extreme
* values are truncated.
*/
float width = (float)_game->_renderer->getWidth();
float relPos = ((float)x + (0.5f * width)) / (width * 2.0f);
// saturate
if (relPos < 0.0f) {
relPos = 0.0f;
}
if (relPos > 1.0f) {
relPos = 1.0f;
}
float minPan = -1.0f;
float maxPan = 1.0f;
return minPan + relPos * (maxPan - minPan);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,66 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SOUNDMGR_H
#define WINTERMUTE_BASE_SOUNDMGR_H
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base.h"
#include "audio/mixer.h"
#include "common/array.h"
namespace Wintermute {
class BaseSoundBuffer;
class BaseSoundMgr : public BaseClass {
public:
float posToPan(int x, int y);
bool resumeAll();
bool pauseAll(bool includingMusic = true);
bool cleanup();
//DECLARE_PERSISTENT(BaseSoundMgr, BaseClass)
byte getMasterVolumePercent();
byte getMasterVolume();
bool setMasterVolumePercent(byte percent);
byte getVolumePercent(TSoundType type);
bool setVolumePercent(TSoundType type, byte percent);
bool setVolume(TSoundType type, int volume);
int32 _volumeMaster;
bool removeSound(BaseSoundBuffer *sound);
BaseSoundBuffer *addSound(const char *filename, TSoundType type = TSoundType::SOUND_SFX, bool streamed = false, uint32 initialPrivateVolume = 100);
bool addSound(BaseSoundBuffer *sound, TSoundType type = TSoundType::SOUND_SFX);
bool initLoop();
bool initialize();
bool _soundAvailable;
BaseSoundMgr(BaseGame *inGame);
~BaseSoundMgr() override;
BaseArray<BaseSoundBuffer *> _sounds;
void saveSettings();
};
} // End of namespace Wintermute
#endif