NANCY: Common sound handling changes

SoundManager is now responsible for loading and storing all common sounds (sounds with their own BOOT chunk). All playSound() calls with a hardcoded channel ID now use the chunk name instead. Also fixed some sound inaccuracies when switching between states.
This commit is contained in:
fracturehill 2021-04-03 22:52:33 +03:00
parent a8a7f0ee57
commit 9bb543a69e
14 changed files with 91 additions and 54 deletions

View File

@ -64,7 +64,7 @@ void ActionManager::handleInput(NancyInput &input) {
}
if (!shouldTrigger) {
g_nancy->_sound->playSound(17); // Hardcoded by original engine
g_nancy->_sound->playSound("CANT");
}
} else {
shouldTrigger = true;

View File

@ -398,7 +398,7 @@ void ShowInventoryItem::execute() {
break;
}
case kActionTrigger:
g_nancy->_sound->playSound(24); // Hardcoded by original engine
g_nancy->_sound->playSound("BUOK");
NancySceneState.addItemToInventory(_objectID);
setVisible(false);
_hasHotspot = false;

View File

@ -317,25 +317,11 @@ void NancyEngine::bootGameEngine() {
"CLOK", "SPEC"
};
Common::String persistentSounds[] = {
"BUOK", "BUDE", "BULS", "GLOB", "CURT",
"CANT"
};
SoundDescription desc;
for (auto const &n : names) {
addBootChunk(n, boot->getChunkStream(n));
}
// Persistent sounds that are used across the engine. These originally get loaded inside Logo
for (auto const &s : persistentSounds) {
Common::SeekableReadStream *str = g_nancy->getBootChunkStream(s);
if (str) {
desc.read(*str, SoundDescription::kNormal);
g_nancy->_sound->loadSound(desc);
}
}
_sound->loadCommonSounds();
delete boot;

View File

@ -215,6 +215,36 @@ SoundManager::SoundManager() {
initSoundChannels();
}
void SoundManager::loadCommonSounds() {
// Persistent sounds that are used across the engine. These originally get loaded inside Logo
Common::String chunkNames[] = {
"CANT", // channel 17
"CURT", // channel 18
"GLOB", // channel 20
"BULS", // channel 22
"BUDE", // channel 23
"BUOK", // channel 24
};
Common::SeekableReadStream *chunk = nullptr;
for (auto const &s : chunkNames) {
chunk = g_nancy->getBootChunkStream(s);
if (chunk) {
SoundDescription &desc = _commonSounds.getOrCreateVal(s);
desc.read(*chunk, SoundDescription::kNormal);
g_nancy->_sound->loadSound(desc);
}
}
// Menu sound is special since it's stored differently and can be
// unloaded and loaded again
chunk = g_nancy->getBootChunkStream("MSND"); // channel 28
if (chunk) {
SoundDescription &desc = _commonSounds.getOrCreateVal("MSND");
desc.read(*chunk, SoundDescription::kMenu);
}
}
SoundManager::~SoundManager() {
stopAllSounds();
}
@ -262,6 +292,16 @@ void SoundManager::playSound(const SoundDescription &description) {
}
}
void SoundManager::playSound(const Common::String &chunkName) {
const SoundDescription &desc = _commonSounds[chunkName];
if (!isSoundPlaying(desc)) {
loadSound(desc);
}
playSound(desc);
}
void SoundManager::pauseSound(uint16 channelID, bool pause) {
if (channelID > 31)
return;
@ -277,6 +317,10 @@ void SoundManager::pauseSound(const SoundDescription &description, bool pause) {
}
}
void SoundManager::pauseSound(const Common::String &chunkName, bool pause) {
pauseSound(_commonSounds[chunkName], pause);
}
bool SoundManager::isSoundPlaying(uint16 channelID) const {
if (channelID > 31)
return false;
@ -292,6 +336,10 @@ bool SoundManager::isSoundPlaying(const SoundDescription &description) const {
}
}
bool SoundManager::isSoundPlaying(const Common::String &chunkName) const {
return isSoundPlaying(_commonSounds[chunkName]);
}
void SoundManager::stopSound(uint16 channelID) {
if (channelID > 31)
return;
@ -310,6 +358,10 @@ void SoundManager::stopSound(const SoundDescription &description) {
}
}
void SoundManager::stopSound(const Common::String &chunkName) {
stopSound(_commonSounds[chunkName]);
}
// Returns whether the exception was skipped
void SoundManager::stopAllSounds() {
for (uint i = 0; i < 31; ++i) {
@ -323,6 +375,8 @@ void SoundManager::stopAndUnloadSpecificSounds() {
for (uint i = 0; i < 10; ++i) {
stopSound(i);
}
stopSound(_commonSounds["MSND"]);
}
void SoundManager::initSoundChannels() {

View File

@ -23,6 +23,8 @@
#ifndef NANCY_SOUND_H
#define NANCY_SOUND_H
#include "engines/nancy/commontypes.h"
#include "audio/mixer.h"
namespace Common {
@ -36,27 +38,32 @@ class SeekableAudioStream;
namespace Nancy {
class NancyEngine;
struct SoundDescription;
class SoundManager {
public:
SoundManager();
~SoundManager();
void loadCommonSounds();
// Load a sound into a channel without starting it
void loadSound(const SoundDescription &description);
void playSound(uint16 channelID);
void playSound(const SoundDescription &description);
void playSound(const Common::String &chunkName);
void pauseSound(uint16 channelID, bool pause);
void pauseSound(const SoundDescription &description, bool pause);
void pauseSound(const Common::String &chunkName, bool pause);
bool isSoundPlaying(uint16 channelID) const;
bool isSoundPlaying(const SoundDescription &description) const;
bool isSoundPlaying(const Common::String &chunkName) const;
void stopSound(uint16 channelID);
void stopSound(const SoundDescription &description);
void stopSound(const Common::String &chunkName);
void stopAllSounds();
// Used when changing scenes
@ -78,6 +85,7 @@ protected:
Audio::Mixer *_mixer;
Channel _channels[32];
Common::HashMap<Common::String, SoundDescription> _commonSounds;
};
} // End of namespace Nancy

View File

@ -73,6 +73,8 @@ void Credits::init() {
_text._drawSurface.create(_fullTextSurface, src);
_text.init();
g_nancy->_sound->stopSound("MSND");
g_nancy->_sound->loadSound(_sound);
g_nancy->_sound->playSound(_sound);

View File

@ -66,16 +66,13 @@ void Help::init() {
_hotspot.right = chunk->readUint16LE();
_hotspot.bottom = chunk->readUint16LE();
chunk = g_nancy->getBootChunkStream("MSND");
chunk->seek(0);
_sound.read(*chunk, SoundDescription::kMenu);
_state = kBegin;
}
void Help::begin() {
g_nancy->_sound->loadSound(_sound);
g_nancy->_sound->playSound(_sound);
if (!g_nancy->_sound->isSoundPlaying("MSND")) {
g_nancy->_sound->playSound("MSND");
}
_image.registerGraphics();
_image.setVisible(true);
@ -89,14 +86,14 @@ void Help::run() {
NancyInput input = g_nancy->_input->getInput();
if (_hotspot.contains(input.mousePos) && input.input & NancyInput::kLeftMouseButtonUp) {
g_nancy->_sound->playSound(0x18); // Hardcoded by original engine
g_nancy->_sound->playSound("BUOK");
_state = kWaitForSound;
}
}
void Help::waitForSound() {
if (!g_nancy->_sound->isSoundPlaying(18)) {
g_nancy->_sound->stopSound(_sound);
if (!g_nancy->_sound->isSoundPlaying("BUOK")) {
g_nancy->_sound->stopSound("BUOK");
g_nancy->setToPreviousState();
}
}

View File

@ -53,7 +53,6 @@ private:
State _state;
UI::FullScreenImage _image;
Common::Rect _hotspot; // Can be an array, but isn't in nancy1
SoundDescription _sound;
};
#define NancyHelpState Nancy::State::Help::instance()

View File

@ -50,7 +50,6 @@ void Logo::process() {
}
void Logo::onStateExit() {
g_nancy->_sound->stopSound(_msnd);
destroy();
}
@ -65,9 +64,7 @@ void Logo::init() {
}
void Logo::startSound() {
_msnd.read(*g_nancy->getBootChunkStream("MSND"), SoundDescription::kMenu);
g_nancy->_sound->loadSound(_msnd);
g_nancy->_sound->playSound(_msnd);
g_nancy->_sound->playSound("MSND");
_startTicks = g_nancy->getTotalPlayTime();
_state = kRun;
@ -83,9 +80,6 @@ void Logo::stop() {
// The original engine checks for N+D and N+C key combos here.
// For the N+C key combo it looks for some kind of cheat file
// to initialize the game state with.
g_nancy->_sound->stopSound(_msnd);
g_nancy->setState(NancyState::kScene);
}

View File

@ -80,10 +80,9 @@ void Map::init() {
// Load the audio
chunk->seek(0x18 + _mapID * 0x20, SEEK_SET);
SoundDescription sound;
sound.read(*chunk, SoundDescription::kMenu);
g_nancy->_sound->loadSound(sound);
g_nancy->_sound->playSound(0x14);
_sound.read(*chunk, SoundDescription::kMenu);
g_nancy->_sound->loadSound(_sound);
g_nancy->_sound->playSound("GLOB");
_locations.clear();
@ -126,8 +125,8 @@ void Map::init() {
}
void Map::run() {
if (!g_nancy->_sound->isSoundPlaying(0x14) && !g_nancy->_sound->isSoundPlaying(0x13)) {
g_nancy->_sound->playSound(0x13);
if (!g_nancy->_sound->isSoundPlaying("GLOB") && !g_nancy->_sound->isSoundPlaying(_sound)) {
g_nancy->_sound->playSound(_sound);
}
NancyInput input = g_nancy->_input->getInput();
@ -159,22 +158,18 @@ void Map::run() {
}
void Map::onStateExit() {
Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MAP");
SoundDescription sound;
chunk->seek(0x18 + _mapID * 0x20, SEEK_SET);
sound.read(*chunk, SoundDescription::kMenu);
g_nancy->_sound->stopSound(sound);
g_nancy->_sound->stopSound(_sound);
if (_pickedLocationID != -1) {
auto &loc = _locations[_pickedLocationID];
NancySceneState.changeScene(loc.scenes[_mapID].sceneID, loc.scenes[_mapID].frameID, loc.scenes[_mapID].verticalOffset, false);
_pickedLocationID = -1;
g_nancy->_sound->playSound(0x18);
g_nancy->_sound->playSound("BUOK");
}
// The two sounds play at the same time if a location was picked
g_nancy->_sound->playSound(0x14);
g_nancy->_sound->playSound("GLOB");
_mapButtonClicked = false;

View File

@ -100,6 +100,7 @@ private:
Nancy::UI::Viewport _viewport;
MapLabel _label;
MapButton _button;
SoundDescription _sound;
State _state;
uint16 _mapID;

View File

@ -121,6 +121,7 @@ void Scene::onStateEnter() {
g_nancy->setTotalPlayTime((uint32)_timers.pushedPlayTime);
unpauseSceneSpecificSounds();
g_nancy->_sound->stopSound("MSND");
}
}

View File

@ -60,7 +60,7 @@ void MenuButton::init() {
void MenuButton::onClick() {
NancySceneState.requestStateChange(NancyState::kMainMenu);
g_nancy->_sound->playSound(0x18);
g_nancy->_sound->playSound("GLOB");
setVisible(true);
}
@ -80,7 +80,7 @@ void HelpButton::init() {
void HelpButton::onClick() {
NancySceneState.requestStateChange(NancyState::kHelp);
g_nancy->_sound->playSound(0x18);
g_nancy->_sound->playSound("GLOB");
setVisible(true);
}

View File

@ -118,13 +118,13 @@ void InventoryBox::handleInput(NancyInput &input) {
g_nancy->_cursorManager->setCursorType(CursorManager::kHotspotArrow);
if (input.input & NancyInput::kLeftMouseButtonUp) {
NancySceneState.addItemToInventory(NancySceneState.getHeldItem());
g_nancy->_sound->playSound(0x16);
g_nancy->_sound->playSound("BULS");
}
} else if (_itemHotspots[i].itemID != -1) {
g_nancy->_cursorManager->setCursorType(CursorManager::kHotspotArrow);
if (input.input & NancyInput::kLeftMouseButtonUp) {
NancySceneState.removeItemFromInventory(_itemHotspots[i].itemID);
g_nancy->_sound->playSound(0x18);
g_nancy->_sound->playSound("GLOB");
}
}
break;
@ -242,7 +242,7 @@ void InventoryBox::Shades::updateGraphics() {
if (!_soundTriggered) {
_soundTriggered = true;
g_nancy->_sound->playSound(0x12);
g_nancy->_sound->playSound("CURT");
}
}
} else {
@ -252,7 +252,7 @@ void InventoryBox::Shades::updateGraphics() {
if (!_soundTriggered) {
_soundTriggered = true;
g_nancy->_sound->playSound(0x12);
g_nancy->_sound->playSound("CURT");
}
}
}