NANCY: Sound manager improvements

The original engine stores sound information in at least four different types of structs, all of which can now be loaded and played back. Also implemented sound types, which will be configurable from the ScummVM interface, added the correct number of sound channels, and implemented sound fx in a couple of action record types.
This commit is contained in:
fracturehill 2021-02-20 20:22:13 +02:00 committed by Eugene Sandulenko
parent c73ea1b0cb
commit e4890a18fc
19 changed files with 301 additions and 144 deletions

View File

@ -66,6 +66,10 @@ void ActionManager::handleInput(NancyInput &input) {
shouldTrigger = true;
}
}
if (!shouldTrigger) {
_engine->sound->playSound(17); // Hardcoded by original engine
}
} else {
shouldTrigger = true;
}

View File

@ -28,7 +28,7 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/state/scene.h"
#include "engines/nancy/nancy.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/util.h"
#include "common/file.h"
@ -85,19 +85,9 @@ uint16 PlayPrimaryVideoChan0::readData(Common::SeekableReadStream &stream) {
UI::Textbox::assembleTextLine(rawText, text, 1500);
delete[] rawText;
stream.read(name, 10);
soundName = Common::String(name);
soundChannelID = stream.readUint16LE();
sound.read(stream, SoundManager::SoundDescription::kNormal);
stream.skip(8);
numRepeats = stream.readUint16LE();
stream.skip(4);
volume = stream.readUint16LE();
stream.skip(0x29);
stream.skip(0x23);
conditionalResponseCharacterID = stream.readByte();
goodbyeResponseCharacterID = stream.readByte();
numSceneChanges = stream.readByte();
@ -180,8 +170,8 @@ void PlayPrimaryVideoChan0::execute(NancyEngine *engine) {
case kBegin:
init();
registerGraphics();
engine->sound->loadSound(soundName, soundChannelID, numRepeats, volume);
engine->sound->pauseSound(soundChannelID, false);
engine->sound->loadSound(sound);
engine->sound->playSound(sound.channelID);
state = kRun;
// fall through
case kRun:
@ -205,7 +195,7 @@ void PlayPrimaryVideoChan0::execute(NancyEngine *engine) {
}
}
if (!engine->sound->isSoundPlaying(soundChannelID)) {
if (!engine->sound->isSoundPlaying(sound.channelID)) {
if (responses.size() == 0) {
// NPC has finished talking with no responses available, auto-advance to next scene
state = kActionTrigger;
@ -221,8 +211,11 @@ void PlayPrimaryVideoChan0::execute(NancyEngine *engine) {
if (pickedResponse != -1) {
// Player has picked response, play sound file and change state
sceneChange = responses[pickedResponse].sceneChange;
engine->sound->loadSound(responses[pickedResponse].soundName, soundChannelID, numRepeats, volume);
engine->sound->pauseSound(soundChannelID, false);
SoundManager::SoundDescription responseSound = sound;
responseSound.name = responses[pickedResponse].soundName;
// TODO this is probably not correct
engine->sound->loadSound(responseSound);
engine->sound->playSound(responseSound.channelID);
state = kActionTrigger;
}
}
@ -259,7 +252,7 @@ void PlayPrimaryVideoChan0::execute(NancyEngine *engine) {
engine->scene->setEventFlag(responses[pickedResponse].flagDesc.label, responses[pickedResponse].flagDesc.flag);
}
if (!engine->sound->isSoundPlaying(soundChannelID)) {
if (!engine->sound->isSoundPlaying(sound.channelID)) {
if (shouldPopScene) {
// Exit dialogue
engine->scene->popScene();
@ -326,6 +319,7 @@ void PlayPrimaryVideoChan0::addGoodbye(NancyEngine *engine) {
newResponse.text = file.readString();
// response is picked randomly
newResponse.sceneChange.sceneID = res.sceneIDs[engine->_rnd->getRandomNumber(3)];
newResponse.sceneChange.doNotStartSound = true;
file.close();
}

View File

@ -65,7 +65,7 @@ public:
PlayPrimaryVideoChan0(RenderObject &redrawFrom) : RenderObject(redrawFrom) {}
virtual ~PlayPrimaryVideoChan0();
virtual void init()override;
virtual void init() override;
virtual void updateGraphics() override;
virtual uint16 readData(Common::SeekableReadStream &stream) override;
@ -80,10 +80,7 @@ public:
// _screenPosition 0x2D
Common::String text; // 0x3D
Common::String soundName; // 0x619, TODO make a proper soundDesc struct
uint16 soundChannelID; // 0x623
uint16 numRepeats; // 0x62D
uint16 volume; // 0x633
SoundManager::SoundDescription sound; // 0x619
byte conditionalResponseCharacterID; // 0x65E
byte goodbyeResponseCharacterID; // 0x65F

View File

@ -28,7 +28,7 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/nancy.h"
#include "engines/nancy/graphics.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/input.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/util.h"
@ -493,7 +493,7 @@ void ShowInventoryItem::execute(NancyEngine *engine) {
break;
}
case kActionTrigger:
// TODO play sound
engine->sound->playSound(24); // Hardcoded by original engine
engine->scene->addItemToInventory(objectID);
setVisible(false);
hasHotspot = false;
@ -503,15 +503,7 @@ void ShowInventoryItem::execute(NancyEngine *engine) {
}
uint16 PlayDigiSoundAndDie::readData(Common::SeekableReadStream &stream) {
char str[10];
stream.read(str, 10);
filename = Common::String(str);
id = stream.readSint16LE();
stream.skip(4);
numLoops = stream.readUint16LE();
stream.skip(4);
volume = stream.readUint16LE();
stream.skip(6);
sound.read(stream, SoundManager::SoundDescription::kDIGI);
SceneChange::readData(stream);
return 0x2B;
}
@ -519,12 +511,12 @@ uint16 PlayDigiSoundAndDie::readData(Common::SeekableReadStream &stream) {
void PlayDigiSoundAndDie::execute(NancyEngine *engine) {
switch (state) {
case kBegin:
engine->sound->loadSound(filename, id, numLoops, volume);
engine->sound->pauseSound(id, false);
engine->sound->loadSound(sound);
engine->sound->playSound(sound.channelID);
state = kRun;
break;
case kRun:
if (!engine->sound->isSoundPlaying(id)) {
if (!engine->sound->isSoundPlaying(sound.channelID)) {
state = kActionTrigger;
}
break;

View File

@ -27,6 +27,8 @@
#include "engines/nancy/commontypes.h"
#include "engines/nancy/renderobject.h"
#include "engines/nancy/sound.h"
#include "common/stream.h"
#include "common/array.h"
#include "common/str.h"
@ -349,10 +351,7 @@ public:
virtual void execute(Nancy::NancyEngine *engine) override;
// TODO subclass into Play and Stop (?)
Common::String filename;
int16 id = -1; // 0xA
uint16 numLoops = 0; // 0x10
uint16 volume = 0; // 0x16, maximum is 65?
SoundManager::SoundDescription sound;
// ...
// SceneChange elements at 0x1E
};

View File

@ -28,7 +28,7 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/util.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/cursor.h"
#include "engines/nancy/input.h"
#include "engines/nancy/graphics.h"
@ -212,13 +212,7 @@ uint16 PlaySecondaryMovie::readData(Common::SeekableReadStream &stream) {
}
triggerFlags.readData(stream);
stream.read(name, 10);
soundName = Common::String(name);
soundChannel = stream.readUint16LE();
stream.skip(0xE);
soundVolume = stream.readUint16LE();
stream.skip(6);
sound.read(stream, SoundManager::SoundDescription::kNormal);
SceneChange::readData(stream);
uint16 numVideoDescs = stream.readUint16LE();
@ -276,8 +270,8 @@ void PlaySecondaryMovie::execute(NancyEngine *engine) {
case kBegin:
init();
registerGraphics();
if (soundName != "NO SOUND") {
engine->sound->loadSound(soundName, soundChannel, 1, soundVolume);
if (sound.name != "NO SOUND") {
engine->sound->loadSound(sound);
}
state = kRun;
// fall through
@ -300,8 +294,8 @@ void PlaySecondaryMovie::execute(NancyEngine *engine) {
_screenPosition = videoDescs[activeFrame].destRect;
// Start sound if any
if (soundName != "NO SOUND") {
engine->sound->pauseSound(soundChannel, false);
if (sound.name != "NO SOUND") {
engine->sound->playSound(sound.channelID);
}
setVisible(true);

View File

@ -104,9 +104,7 @@ public:
FlagAtFrame frameFlags[15]; // 0x26
EventFlagsDesc triggerFlags; // 0x80
Common::String soundName; // 0xA8
uint16 soundChannel = 0; // 0xB2
uint16 soundVolume = 0; // 0xC2
SoundManager::SoundDescription sound; // 0xA8
// SceneChange data at 0xCA
Common::Array<SecondaryVideoDesc> videoDescs; // 0xD4

View File

@ -24,7 +24,7 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/video.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/iff.h"
#include "engines/nancy/state/scene.h"
@ -270,7 +270,7 @@ bool NancyConsole::Cmd_playAudio(int argc, const char **argv) {
return true;
}
Audio::AudioStream *stream = makeHISStream(f, DisposeAfterUse::YES);
Audio::AudioStream *stream = SoundManager::makeHISStream(f, DisposeAfterUse::YES);
if (!stream) {
debugPrintf("Failed to load '%s.his'\n", argv[1]);

View File

@ -14,8 +14,7 @@ MODULE_OBJS = \
ui/viewport.o \
state/logo.o \
state/map.o \
state/scene.o\
audio.o \
state/scene.o \
console.o \
cursor.o \
decompress.o \
@ -27,6 +26,7 @@ MODULE_OBJS = \
nancy.o \
renderobject.o \
resource.o \
sound.o \
video.o
# This module can be built as a plugin

View File

@ -26,9 +26,9 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/iff.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/input.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/state/map.h"
#include "engines/nancy/graphics.h"
#include "engines/nancy/cursor.h"
@ -248,6 +248,16 @@ Common::SeekableReadStream *NancyEngine::getBootChunkStream(const Common::String
else return nullptr;
}
void NancyEngine::stopAndUnloadSpecificSounds() {
// TODO missing if
sound->stopSound(logo->MSNDchannelID);
for (uint i = 0; i < 10; ++i) {
sound->stopSound(i);
}
}
void NancyEngine::clearBootChunks() {
for (auto const& i : _bootChunks) {
delete i._value;

View File

@ -124,6 +124,9 @@ public:
// Chunks found in BOOT get extracted and cached at startup, this function lets other classes access them
Common::SeekableReadStream *getBootChunkStream(const Common::String &name);
// Used for state switching
void stopAndUnloadSpecificSounds();
void setGameState(GameState state);
GameState getGameState() const { return _gameFlow.minGameState; }

View File

@ -20,7 +20,7 @@
*
*/
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/nancy.h"
#include "common/system.h"
@ -122,7 +122,7 @@ bool readHISHeader(Common::SeekableReadStream *stream, SoundType &type, uint16 &
return true;
}
Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
Audio::SeekableAudioStream *SoundManager::makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
char buf[22];
stream->read(buf, 22);
@ -176,52 +176,159 @@ Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, Di
return Audio::makeVorbisStream(subStream, DisposeAfterUse::YES);
}
void SoundManager::SoundDescription::read(Common::SeekableReadStream &stream, Type type) {
char buf[10];
stream.read(buf, 10);
name = buf;
if (type == SoundDescription::kScene) {
stream.skip(4);
}
channelID = stream.readUint16LE();
// The difference between these is a couple members found at the same position
// whose purpose I don't understand, so for now just skip them
switch (type) {
case kNormal:
stream.skip(8);
break;
case kMenu:
stream.skip(6);
break;
case kScene:
// fall through
case kDIGI:
stream.skip(4);
break;
}
numLoops = stream.readUint16LE();
if (stream.readUint16LE() != 0) { // loop indefinitely
numLoops = 0;
}
stream.skip(2);
volume = stream.readUint16LE();
stream.skip(6);
}
SoundManager::SoundManager(NancyEngine *engine) :
_engine(engine) {
_mixer = _engine->_system->getMixer();
initSoundChannels();
}
void SoundManager::loadSound(Common::String &name, int16 id, uint16 numLoops, uint16 volume) {
if (_mixer->isSoundHandleActive(handles[id])) {
_mixer->stopHandle(handles[id]);
}
Common::SeekableReadStream *mSnd = SearchMan.createReadStreamForMember(name + ".his");
if (mSnd) {
Audio::RewindableAudioStream *aStr = makeHISStream(mSnd, DisposeAfterUse::YES);
if (aStr) {
Audio::AudioStream *aStrLoop = Audio::makeLoopingAudioStream(aStr, numLoops);
_engine->_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &handles[id], aStrLoop, -1, volume * 255 / 100);
_engine->_system->getMixer()->pauseHandle(handles[id], true);
names[id] = name;
}
}
SoundManager::~SoundManager() {
stopAllSounds();
}
void SoundManager::pauseSound(int16 id, bool pause) {
if (id < 0 || id > 20)
uint16 SoundManager::loadSound(const SoundDescription &description) {
if (_mixer->isSoundHandleActive(_channels[description.channelID].handle)) {
_mixer->stopHandle(_channels[description.channelID].handle);
}
delete _channels[description.channelID].stream;
_channels[description.channelID].stream = nullptr;
_channels[description.channelID].name = description.name;
_channels[description.channelID].numLoops = description.numLoops;
_channels[description.channelID].volume = description.volume;
Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(description.name + ".his");
if (file) {
_channels[description.channelID].stream = makeHISStream(file, DisposeAfterUse::YES);
}
return description.channelID;
}
void SoundManager::playSound(uint16 channelID) {
if (channelID > 32 || _channels[channelID].stream == 0)
return;
_engine->_system->getMixer()->pauseHandle(handles[id], pause);
_channels[channelID].stream->seek(0);
_mixer->playStream( _channels[channelID].type,
&_channels[channelID].handle,
Audio::makeLoopingAudioStream(_channels[channelID].stream, _channels[channelID].numLoops),
channelID,
_channels[channelID].volume * 255 / 100,
0, DisposeAfterUse::NO);
}
void SoundManager::stopSound(int16 id) {
if (isSoundPlaying(id)) {
_mixer->stopHandle(handles[id]);
void SoundManager::pauseSound(uint16 channelID, bool pause) {
if (channelID > 32)
return;
if (isSoundPlaying(channelID)) {
_engine->_system->getMixer()->pauseHandle(_channels[channelID].handle, pause);
}
names[id] = Common::String();
}
bool SoundManager::isSoundPlaying(int16 id) {
if (id >= 0 && id < 20) {
return _mixer->isSoundHandleActive(handles[id]);
void SoundManager::stopSound(uint16 channelID) {
if (channelID > 32)
return;
if (isSoundPlaying(channelID)) {
_mixer->stopHandle(_channels[channelID].handle);
}
return false;
_channels[channelID].name = Common::String();
delete _channels[channelID].stream;
_channels[channelID].stream = nullptr;
}
bool SoundManager::isSoundPlaying(uint16 channelID) {
if (channelID > 32)
return false;
return _mixer->isSoundHandleActive(_channels[channelID].handle);
}
// Returns whether the exception was skipped
void SoundManager::stopAllSounds() {
_mixer->stopAll();
for (uint i = 0; i < 32; ++i) {
stopSound(i);
}
}
void SoundManager::initSoundChannels() {
// Original engine hardcoded these and so do we
_channels[7].type = Audio::Mixer::kSpeechSoundType;
_channels[8].type = Audio::Mixer::kSpeechSoundType;
_channels[30].type = Audio::Mixer::kSpeechSoundType;
_channels[0].type = Audio::Mixer::kMusicSoundType;
_channels[1].type = Audio::Mixer::kMusicSoundType;
_channels[2].type = Audio::Mixer::kMusicSoundType;
_channels[27].type = Audio::Mixer::kMusicSoundType;
_channels[28].type = Audio::Mixer::kMusicSoundType;
_channels[29].type = Audio::Mixer::kMusicSoundType;
_channels[19].type = Audio::Mixer::kMusicSoundType;
_channels[3].type = Audio::Mixer::kSFXSoundType;
_channels[4].type = Audio::Mixer::kSFXSoundType;
_channels[5].type = Audio::Mixer::kSFXSoundType;
_channels[6].type = Audio::Mixer::kSFXSoundType;
_channels[20].type = Audio::Mixer::kSFXSoundType;
_channels[21].type = Audio::Mixer::kSFXSoundType;
_channels[25].type = Audio::Mixer::kSFXSoundType;
_channels[26].type = Audio::Mixer::kSFXSoundType;
_channels[24].type = Audio::Mixer::kSFXSoundType;
_channels[23].type = Audio::Mixer::kSFXSoundType;
_channels[22].type = Audio::Mixer::kSFXSoundType;
_channels[31].type = Audio::Mixer::kSFXSoundType;
_channels[18].type = Audio::Mixer::kSFXSoundType;
_channels[17].type = Audio::Mixer::kSFXSoundType;
_channels[9].type = Audio::Mixer::kPlainSoundType;
_channels[10].type = Audio::Mixer::kPlainSoundType;
_channels[11].type = Audio::Mixer::kPlainSoundType;
_channels[12].type = Audio::Mixer::kPlainSoundType;
_channels[13].type = Audio::Mixer::kPlainSoundType;
_channels[14].type = Audio::Mixer::kPlainSoundType;
_channels[15].type = Audio::Mixer::kPlainSoundType;
_channels[16].type = Audio::Mixer::kPlainSoundType;
}
} // End of namespace Nancy

View File

@ -20,8 +20,8 @@
*
*/
#ifndef NANCY_AUDIO_H
#define NANCY_AUDIO_H
#ifndef NANCY_SOUND_H
#define NANCY_SOUND_H
#include "common/types.h"
#include "common/str.h"
@ -40,28 +40,53 @@ namespace Nancy {
class NancyEngine;
Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
class SoundManager {
public:
enum SoundLoopType { kLoop = 0, kOneShot = 1 };
SoundManager(NancyEngine *engine);
~SoundManager() =default;
// Combines four different structs in one
struct SoundDescription {
enum Type { kNormal, kMenu, kDIGI, kScene };
void loadSound(Common::String &name, int16 id, uint16 numLoops = 0, uint16 volume = 60);
void pauseSound(int16 id, bool pause);
void stopSound(int16 id);
bool isSoundPlaying(int16 id);
Common::String name;
uint16 channelID;
uint16 numLoops;
uint16 volume;
void read(Common::SeekableReadStream &stream, Type type);
};
SoundManager(NancyEngine *engine);
~SoundManager();
// Load a sound into a channel without starting it
uint16 loadSound(const SoundDescription &description);
void playSound(uint16 channelID);
void pauseSound(uint16 channelID, bool pause);
bool isSoundPlaying(uint16 channelID);
// Stop playing a sound and unload it from the channel
void stopSound(uint16 channelID);
void stopAllSounds();
private:
static Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
protected:
struct Channel {
Common::String name;
Audio::Mixer::SoundType type;
uint16 numLoops = 0;
uint volume = 0;
Audio::SeekableAudioStream *stream = nullptr;
Audio::SoundHandle handle;
};
void initSoundChannels();
NancyEngine *_engine;
Audio::Mixer *_mixer;
Audio::SoundHandle handles[20];
Common::String names[20];
Channel _channels[32];
};
} // End of namespace Nancy
#endif // NANCY_AUDIO_H
#endif // NANCY_SOUND_H

View File

@ -24,7 +24,7 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/input.h"
#include "common/error.h"
@ -66,13 +66,24 @@ void Logo::init() {
}
void Logo::startSound() {
Common::SeekableReadStream *msnd = _engine->getBootChunkStream("MSND");
char name[10];
msnd->seek(0);
msnd->read(name, 10);
Common::String sname(name);
_engine->sound->loadSound(sname, 0);
_engine->sound->pauseSound(0, false);
SoundManager::SoundDescription desc;
desc.read(*_engine->getBootChunkStream("MSND"), SoundManager::SoundDescription::kMenu);
_engine->sound->loadSound(desc);
MSNDchannelID = desc.channelID;
desc.read(*_engine->getBootChunkStream("BUOK"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
desc.read(*_engine->getBootChunkStream("BUDE"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
desc.read(*_engine->getBootChunkStream("BULS"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
desc.read(*_engine->getBootChunkStream("GLOB"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
desc.read(*_engine->getBootChunkStream("CURT"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
desc.read(*_engine->getBootChunkStream("CANT"), SoundManager::SoundDescription::kNormal);
_engine->sound->loadSound(desc);
_engine->sound->playSound(MSNDchannelID);
_startTicks = _engine->_system->getMillis();
_state = kRun;

View File

@ -46,6 +46,8 @@ public:
void process();
uint MSNDchannelID; // This definitely shouldn't be here
private:
void init();
void startSound();

View File

@ -25,7 +25,7 @@
#include "engines/nancy/state/scene.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/input.h"
#include "engines/nancy/nancy.h"
#include "engines/nancy/util.h"
@ -73,13 +73,10 @@ void Map::init() {
// Load the audio
chunk->seek(0x18 + _mapID * 0x20, SEEK_SET);
chunk->read(name, 10);
n = Common::String(name);
uint16 channel = chunk->readUint16LE();
chunk->skip(0xA);
uint16 volume = chunk->readUint16LE();
_engine->sound->loadSound(n, channel, 0, volume);
_engine->sound->pauseSound(channel, false);
SoundManager::SoundDescription sound;
sound.read(*chunk, SoundManager::SoundDescription::kMenu);
_engine->sound->loadSound(sound);
_engine->sound->playSound(sound.channelID);
for (uint i = 0; i < 4; ++i) {
chunk->seek(0x162 + i * 16, SEEK_SET);
@ -133,6 +130,7 @@ void Map::run() {
// TODO handle map button as well
if (input.input & NancyInput::kLeftMouseButtonUp) {
stopSound();
_engine->setGameState(NancyEngine::kScene);
_engine->scene->changeScene(loc.scenes[_mapID].sceneID, loc.scenes[_mapID].frameID, loc.scenes[_mapID].verticalOffset, false);
_state = kInit;
@ -142,6 +140,14 @@ void Map::run() {
}
}
void Map::stopSound() {
Common::SeekableReadStream *chunk = _engine->getBootChunkStream("MAP");
SoundManager::SoundDescription sound;
chunk->seek(0x18 + _mapID * 0x20, SEEK_SET);
sound.read(*chunk, SoundManager::SoundDescription::kMenu);
_engine->sound->stopSound(sound.channelID);
}
void Map::registerGraphics() {
_viewport.registerGraphics();
_label.registerGraphics();

View File

@ -89,6 +89,7 @@ private:
void init();
void run();
void stopSound();
void registerGraphics();

View File

@ -26,7 +26,7 @@
#include "engines/nancy/iff.h"
#include "engines/nancy/action/actionmanager.h"
#include "engines/nancy/input.h"
#include "engines/nancy/audio.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/graphics.h"
#include "engines/nancy/cursor.h"
#include "engines/nancy/time.h"
@ -55,9 +55,9 @@ void Scene::process() {
case kStartSound:
_state = kRun;
if (!_sceneState._doNotStartSound) {
_engine->sound->stopAllSounds();
_engine->sound->loadSound(_sceneState.summary.audioFile, _sceneState.summary.audioID, 0, _sceneState.summary.audioVolume);
_engine->sound->pauseSound(_sceneState.summary.audioID, false);
_engine->stopAndUnloadSpecificSounds();
_engine->sound->loadSound(_sceneState.summary.sound);
_engine->sound->playSound(_sceneState.summary.sound.channelID);
}
// fall through
case kRun:
@ -85,6 +85,20 @@ void Scene::popScene() {
_sceneState.isScenePushed = false;
}
void Scene::pauseSceneSpecificSounds() {
// TODO missing if, same condition as the one in NancyEngine::stopAndUnloadSpecificSounds
for (uint i = 0; i < 10; ++i) {
_engine->sound->pauseSound(i, true);
}
}
void Scene::unpauseSceneSpecificSounds() {
for (uint i = 0; i < 10; ++i) {
_engine->sound->pauseSound(i, false);
}
}
void Scene::addItemToInventory(uint16 id) {
_flags.items[id] = kTrue;
if (_flags.heldItem == id) {
@ -245,6 +259,7 @@ void Scene::run() {
}
registerGraphics();
unpauseSceneSpecificSounds();
return;
}
@ -305,12 +320,7 @@ void Scene::readSceneSummary(Common::SeekableReadStream &stream) {
stream.seek(3, SEEK_CUR);
_sceneState.summary.videoFormat = stream.readUint16LE();
stream.read(buf, 10);
buf[9] = 0;
_sceneState.summary.audioFile = Common::String(buf);
_sceneState.summary.audioID = stream.readSint16LE();
stream.skip(0xE);
_sceneState.summary.audioVolume = stream.readUint16LE();
_sceneState.summary.sound.read(stream, SoundManager::SoundDescription::kScene);
stream.seek(0x72);
_sceneState.summary.verticalScrollDelta = stream.readUint16LE();
@ -332,6 +342,7 @@ bool Scene::changeGameState() {
_timers.pushedPlayTime = _engine->getTotalPlayTime();
_engine->setGameState(_gameStateRequested);
_gameStateRequested = NancyEngine::kScene;
pauseSceneSpecificSounds();
return true;
}

View File

@ -33,6 +33,7 @@
#include "engines/nancy/time.h"
#include "engines/nancy/commontypes.h"
#include "engines/nancy/nancy.h"
#include "engines/nancy/sound.h"
#include "common/scummsys.h"
#include "common/array.h"
@ -64,19 +65,18 @@ class Scene {
friend class Nancy::NancyConsole;
public:
struct SceneSummary { // SSUM
Common::String description; // 0x00
Common::String videoFile; // 0x32
Common::String description; // 0x00
Common::String videoFile; // 0x32
//
uint16 videoFormat; // 0x3E, value is 1 or 2
Common::String audioFile; // 0x40
int16 audioID; // 0x4A
uint16 audioVolume; // 0x5A
uint16 videoFormat; // 0x3E, value is 1 or 2
Common::String audioFile;
SoundManager::SoundDescription sound; // 0x40
//
uint16 verticalScrollDelta; // 0x72
uint16 horizontalEdgeSize; // 0x74
uint16 verticalEdgeSize; // 0x76
Time slowMoveTimeDelta; // 0x78
Time fastMoveTimeDelta; // 0x7A
uint16 verticalScrollDelta; // 0x72
uint16 horizontalEdgeSize; // 0x74
uint16 verticalEdgeSize; // 0x76
Time slowMoveTimeDelta; // 0x78
Time fastMoveTimeDelta; // 0x7A
// byte unknown7C enum with 4 values
//
};
@ -97,6 +97,9 @@ public:
void pushScene();
void popScene();
void pauseSceneSpecificSounds();
void unpauseSceneSpecificSounds();
void addItemToInventory(uint16 id);
void removeItemFromInventory(uint16 id, bool pickUp = true);
int16 getHeldItem() { return _flags.heldItem; }