NANCY: Implement PlaySoundPanFrameAnchorAndDie action record

Implemented the PlaySoundPanFrameAnchorAndDie action record
type and added support for panning audio to the sound manager.
This commit is contained in:
Kaloyan Chehlarski 2021-05-07 10:47:31 +03:00
parent 5b58e92270
commit 3013d07e81
8 changed files with 71 additions and 16 deletions

View File

@ -516,7 +516,15 @@ void PlayDigiSoundAndDie::execute() {
}
void PlaySoundPanFrameAnchorAndDie::readData(Common::SeekableReadStream &stream) {
stream.skip(0x20);
_sound.read(stream, SoundDescription::kDIGI);
stream.skip(2);
}
void PlaySoundPanFrameAnchorAndDie::execute() {
g_nancy->_sound->loadSound(_sound, true);
g_nancy->_sound->playSound(_sound);
g_nancy->_sound->calculatePanForAllSounds();
_isDone = true;
}
void PlaySoundMultiHS::readData(Common::SeekableReadStream &stream) {

View File

@ -457,10 +457,12 @@ protected:
virtual Common::String getRecordTypeName() const override { return "PlayDigiSoundAndDie"; }
};
class PlaySoundPanFrameAnchorAndDie : public Unimplemented {
class PlaySoundPanFrameAnchorAndDie : public ActionRecord {
public:
virtual void readData(Common::SeekableReadStream &stream) override;
virtual void execute() override;
SoundDescription _sound;
protected:
virtual Common::String getRecordTypeName() const override { return "PlaySoundPanFrameAnchorAndDie"; }
};

View File

@ -97,7 +97,9 @@ void SoundDescription::read(Common::SeekableReadStream &stream, Type type) {
}
stream.skip(2);
volume = stream.readUint16LE();
stream.skip(6);
stream.skip(2);
panAnchorFrame = stream.readUint16LE();
stream.skip(2);
}
} // End of namespace Nancy

View File

@ -118,6 +118,7 @@ struct SoundDescription {
uint16 channelID = 0;
uint16 numLoops = 0;
uint16 volume = 0;
uint16 panAnchorFrame = 0;
void read(Common::SeekableReadStream &stream, Type type);
};

View File

@ -30,6 +30,8 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/state/scene.h"
namespace Nancy {
enum SoundType {
@ -284,7 +286,7 @@ SoundManager::~SoundManager() {
stopAllSounds();
}
void SoundManager::loadSound(const SoundDescription &description) {
void SoundManager::loadSound(const SoundDescription &description, bool panning) {
if (description.name == "NO SOUND") {
return;
}
@ -293,13 +295,16 @@ void SoundManager::loadSound(const SoundDescription &description) {
_mixer->stopHandle(_channels[description.channelID].handle);
}
delete _channels[description.channelID].stream;
_channels[description.channelID].stream = nullptr;
Channel &chan = _channels[description.channelID];
_channels[description.channelID].name = description.name;
_channels[description.channelID].numLoops = description.numLoops;
_channels[description.channelID].volume = description.volume;
delete chan.stream;
chan.stream = nullptr;
chan.name = description.name;
chan.numLoops = description.numLoops;
chan.volume = description.volume;
chan.panAnchorFrame = description.panAnchorFrame;
chan.isPanning = panning;
Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(description.name + (g_nancy->getGameType() == kGameTypeVampire ? ".dwd" : ".his"));
if (file) {
@ -404,6 +409,28 @@ void SoundManager::stopAllSounds() {
}
}
void SoundManager::calculatePanForAllSounds() {
uint16 viewportFrameID = NancySceneState.getSceneInfo().frameID;
const State::Scene::SceneSummary &sceneSummary = NancySceneState.getSceneSummary();
for (uint i = 0; i < 31; ++i) {
Channel &chan = _channels[i];
if (chan.isPanning) {
switch (sceneSummary.totalViewAngle) {
case 180:
_mixer->setChannelBalance(chan.handle, CLIP<int32>((viewportFrameID - chan.panAnchorFrame) * sceneSummary.soundPanPerFrame * 364, -32768, 32767) / 256);
break;
case 360:
// TODO
_mixer->setChannelBalance(chan.handle, 0);
break;
default:
_mixer->setChannelBalance(chan.handle, 0);
break;
}
}
}
}
void SoundManager::stopAndUnloadSpecificSounds() {
// TODO missing if

View File

@ -47,7 +47,7 @@ public:
void loadCommonSounds();
// Load a sound into a channel without starting it
void loadSound(const SoundDescription &description);
void loadSound(const SoundDescription &description, bool panning = false);
void playSound(uint16 channelID);
void playSound(const SoundDescription &description);
@ -65,6 +65,8 @@ public:
void stopSound(const SoundDescription &description);
void stopSound(const Common::String &chunkName);
void stopAllSounds();
void calculatePanForAllSounds();
// Used when changing scenes
void stopAndUnloadSpecificSounds();
@ -77,6 +79,8 @@ protected:
Audio::Mixer::SoundType type;
uint16 numLoops = 0;
uint volume = 0;
uint16 panAnchorFrame = 0;
bool isPanning = false;
Audio::SeekableAudioStream *stream = nullptr;
Audio::SoundHandle handle;
};

View File

@ -70,8 +70,11 @@ void Scene::SceneSummary::read(Common::SeekableReadStream &stream) {
sound.read(stream, SoundDescription::kScene);
ser.skip(6);
ser.syncAsByte(dontWrap);
ser.skip(9);
ser.syncAsUint16LE(dontWrap);
ser.syncAsUint16LE(soundWrapAroundPan);
ser.syncAsUint16LE(soundPanPerFrame);
ser.syncAsUint16LE(totalViewAngle);
ser.syncAsUint16LE(horizontalScrollDelta);
ser.syncAsUint16LE(verticalScrollDelta);
ser.syncAsUint16LE(horizontalEdgeSize);
ser.syncAsUint16LE(verticalEdgeSize);
@ -567,6 +570,14 @@ void Scene::run() {
// Update the UI elements and handle input
NancyInput input = g_nancy->_input->getInput();
_viewport.handleInput(input);
_sceneState.currentScene.verticalOffset = _viewport.getCurVerticalScroll();
if (_sceneState.currentScene.frameID != _viewport.getCurFrame()) {
_sceneState.currentScene.frameID = _viewport.getCurFrame();
g_nancy->_sound->calculatePanForAllSounds();
}
_actionManager.handleInput(input);
_menuButton->handleInput(input);
_helpButton->handleInput(input);
@ -585,9 +596,6 @@ void Scene::run() {
requestStateChange(NancyState::kHelp);
}
_sceneState.currentScene.frameID = _viewport.getCurFrame();
_sceneState.currentScene.verticalOffset = _viewport.getCurVerticalScroll();
// Handle invisible map button
for (uint i = 0; i < ARRAYSIZE(g_nancy->getConstants().mapAccessSceneIDs); ++i) {
if (g_nancy->getConstants().mapAccessSceneIDs[i] == -1) {

View File

@ -95,7 +95,10 @@ public:
SoundDescription sound;
//
NancyFlag dontWrap;
//
uint16 soundWrapAroundPan;
uint16 soundPanPerFrame;
uint16 totalViewAngle;
uint16 horizontalScrollDelta;
uint16 verticalScrollDelta;
uint16 horizontalEdgeSize;
uint16 verticalEdgeSize;