267 lines
6.9 KiB
C++
267 lines
6.9 KiB
C++
/* 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "kyra/sound/sound_intern.h"
|
|
#include "kyra/sound/drivers/pc_base.h"
|
|
|
|
#include "common/system.h"
|
|
#include "common/config-manager.h"
|
|
|
|
|
|
namespace Kyra {
|
|
|
|
// Kyra 1 sound triggers. Most noticeably, these are used towards the end of
|
|
// the game, in the castle, to cycle between different songs. The same music is
|
|
// used in other places throughout the game, but the player is less likely to
|
|
// spend enough time there to notice.
|
|
|
|
const int SoundPC_v1::_kyra1SoundTriggers[] = {
|
|
0, 4, 5, 3
|
|
};
|
|
|
|
const int SoundPC_v1::_kyra1NumSoundTriggers = ARRAYSIZE(SoundPC_v1::_kyra1SoundTriggers);
|
|
|
|
SoundPC_v1::SoundPC_v1(KyraEngine_v1 *vm, Audio::Mixer *mixer, kType type)
|
|
: Sound(vm, mixer), _driver(nullptr), _trackEntries(), _soundDataPtr(nullptr), _type(type), _version(-1) {
|
|
memset(_trackEntries, 0, sizeof(_trackEntries));
|
|
|
|
_soundTriggers = nullptr;
|
|
_numSoundTriggers = 0;
|
|
_sfxPlayingSound = -1;
|
|
_soundFileLoaded.clear();
|
|
_currentResourceSet = 0;
|
|
memset(&_resInfo, 0, sizeof(_resInfo));
|
|
|
|
switch (vm->game()) {
|
|
case GI_LOL:
|
|
_version = (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) ? 3 : 4;
|
|
break;
|
|
case GI_KYRA2:
|
|
_version = 4;
|
|
break;
|
|
case GI_KYRA1:
|
|
_version = 3;
|
|
_soundTriggers = _kyra1SoundTriggers;
|
|
_numSoundTriggers = _kyra1NumSoundTriggers;
|
|
break;
|
|
case GI_EOB2:
|
|
_version = 2;
|
|
break;
|
|
case GI_EOB1:
|
|
_version = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_EOB
|
|
// Correct the type to someting we support. NullSound is treated as a silent AdLib driver.
|
|
if (_type != kAdLib && _type != kPCSpkr && _type != kPCjr)
|
|
_type = kAdLib;
|
|
_driver = (type == kAdLib) ? (_version > 0 ? PCSoundDriver::createAdLib(mixer, _version) : nullptr) : PCSoundDriver::createPCSpk(mixer, _type == kPCjr);
|
|
#else
|
|
_type = kAdLib;
|
|
if (_version > 0)
|
|
_driver = PCSoundDriver::createAdLib(mixer, _version);
|
|
#endif
|
|
assert(_driver);
|
|
}
|
|
|
|
SoundPC_v1::~SoundPC_v1() {
|
|
delete _driver;
|
|
delete[] _soundDataPtr;
|
|
for (int i = 0; i < 3; i++)
|
|
initAudioResourceInfo(i, nullptr);
|
|
}
|
|
|
|
bool SoundPC_v1::init() {
|
|
_driver->initDriver();
|
|
return true;
|
|
}
|
|
|
|
void SoundPC_v1::process() {
|
|
int trigger = _driver->getSoundTrigger();
|
|
|
|
if (trigger < _numSoundTriggers) {
|
|
int soundId = _soundTriggers[trigger];
|
|
|
|
if (soundId)
|
|
playTrack(soundId);
|
|
} else {
|
|
warning("Unknown sound trigger %d", trigger);
|
|
// TODO: At this point, we really want to clear the trigger...
|
|
}
|
|
}
|
|
|
|
void SoundPC_v1::updateVolumeSettings() {
|
|
bool mute = false;
|
|
if (ConfMan.hasKey("mute"))
|
|
mute = ConfMan.getBool("mute");
|
|
|
|
int newMusicVolume = mute ? 0 : ConfMan.getInt("music_volume");
|
|
//newMusicVolume = (newMusicVolume * 145) / Audio::Mixer::kMaxMixerVolume + 110;
|
|
newMusicVolume = CLIP(newMusicVolume, 0, 255);
|
|
|
|
int newSfxVolume = mute ? 0 : ConfMan.getInt("sfx_volume");
|
|
//newSfxVolume = (newSfxVolume * 200) / Audio::Mixer::kMaxMixerVolume + 55;
|
|
newSfxVolume = CLIP(newSfxVolume, 0, 255);
|
|
|
|
_driver->setMusicVolume(newMusicVolume);
|
|
_driver->setSfxVolume(newSfxVolume);
|
|
}
|
|
|
|
void SoundPC_v1::playTrack(uint8 track) {
|
|
if (_musicEnabled) {
|
|
// WORKAROUND: There is a bug in the Kyra 1 "Pool of Sorrow"
|
|
// music which causes the channels to get progressively out of
|
|
// sync for each loop. To avoid that, we declare that all four
|
|
// of the song channels have to jump "in sync".
|
|
|
|
if (track == 4 && _soundFileLoaded.equalsIgnoreCase("KYRA1B.ADL"))
|
|
_driver->setSyncJumpMask(0x000F);
|
|
else
|
|
_driver->setSyncJumpMask(0);
|
|
play(track, 0xFF);
|
|
}
|
|
}
|
|
|
|
void SoundPC_v1::haltTrack() {
|
|
play(0, 0);
|
|
play(0, 0);
|
|
//_vm->_system->delayMillis(3 * 60);
|
|
}
|
|
|
|
bool SoundPC_v1::isPlaying() const {
|
|
return _driver->isChannelPlaying(0);
|
|
}
|
|
|
|
void SoundPC_v1::playSoundEffect(uint16 track, uint8 volume) {
|
|
if (_sfxEnabled)
|
|
play(track, volume);
|
|
}
|
|
|
|
void SoundPC_v1::play(uint8 track, uint8 volume) {
|
|
uint16 soundId = 0;
|
|
|
|
if (_version == 4)
|
|
soundId = READ_LE_UINT16(&_trackEntries[track<<1]);
|
|
else
|
|
soundId = _trackEntries[track];
|
|
|
|
if ((soundId == 0xFFFF && _version == 4) || (soundId == 0xFF && _version < 4) || !_soundDataPtr)
|
|
return;
|
|
|
|
_driver->startSound(soundId, volume);
|
|
}
|
|
|
|
void SoundPC_v1::beginFadeOut() {
|
|
play(_version > 2 ? 1 : 15, 0xFF);
|
|
}
|
|
|
|
int SoundPC_v1::checkTrigger() {
|
|
return _driver->getSoundTrigger();
|
|
}
|
|
|
|
void SoundPC_v1::resetTrigger() {
|
|
_driver->resetSoundTrigger();
|
|
}
|
|
|
|
void SoundPC_v1::initAudioResourceInfo(int set, void *info) {
|
|
if (set >= kMusicIntro && set <= kMusicFinale) {
|
|
delete _resInfo[set];
|
|
_resInfo[set] = info ? new SoundResourceInfo_PC(*(SoundResourceInfo_PC*)info) : nullptr;
|
|
}
|
|
}
|
|
|
|
void SoundPC_v1::selectAudioResourceSet(int set) {
|
|
if (set >= kMusicIntro && set <= kMusicFinale) {
|
|
if (_resInfo[set])
|
|
_currentResourceSet = set;
|
|
}
|
|
}
|
|
|
|
bool SoundPC_v1::hasSoundFile(uint file) const {
|
|
if (file < res()->fileListSize)
|
|
return (res()->fileList[file] != nullptr);
|
|
return false;
|
|
}
|
|
|
|
void SoundPC_v1::loadSoundFile(uint file) {
|
|
if (_version == 1 && (_type == kPCSpkr || _type == kPCjr))
|
|
file += 1;
|
|
if (file < res()->fileListSize)
|
|
internalLoadFile(res()->fileList[file]);
|
|
}
|
|
|
|
void SoundPC_v1::loadSoundFile(const Common::Path &file) {
|
|
internalLoadFile(file);
|
|
}
|
|
|
|
void SoundPC_v1::internalLoadFile(const Common::Path &file) {
|
|
Common::Path path(file);
|
|
path.appendInPlace((_version == 1) ? ".DAT" : (_type == kPCSpkr ? ".SND" : ".ADL"));
|
|
if (_soundFileLoaded == path)
|
|
return;
|
|
|
|
if (_soundDataPtr)
|
|
haltTrack();
|
|
|
|
uint8 *fileData = nullptr; uint32 fileSize = 0;
|
|
|
|
fileData = _vm->resource()->fileData(path, &fileSize);
|
|
if (!fileData) {
|
|
warning("Couldn't find music file: '%s'", path.toString().c_str());
|
|
return;
|
|
}
|
|
|
|
playSoundEffect(0);
|
|
playSoundEffect(0);
|
|
|
|
_driver->stopAllChannels();
|
|
|
|
int soundDataSize = fileSize;
|
|
uint8 *p = fileData;
|
|
|
|
if (_version == 4) {
|
|
memcpy(_trackEntries, p, 500);
|
|
p += 500;
|
|
soundDataSize -= 500;
|
|
} else {
|
|
memcpy(_trackEntries, p, 120);
|
|
p += 120;
|
|
soundDataSize -= 120;
|
|
}
|
|
|
|
uint8 *oldData = _soundDataPtr;
|
|
_soundDataPtr = new uint8[soundDataSize];
|
|
assert(_soundDataPtr);
|
|
|
|
memcpy(_soundDataPtr, p, soundDataSize);
|
|
_driver->setSoundData(_soundDataPtr, soundDataSize);
|
|
|
|
delete[] fileData;
|
|
delete[] oldData;
|
|
|
|
_soundFileLoaded = path;
|
|
}
|
|
|
|
} // End of namespace Kyra
|