mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
NANCY: Add initial sound support
Added a sound manager and hooked the Logo and Scene classes to it; also implemented the PlayDigiSoundAndDie action record. As a result the first part of the intro and some of the sounds in the first area can now play properly.
This commit is contained in:
committed by
Eugene Sandulenko
parent
e12f6b6753
commit
f4d8368bd4
@@ -26,6 +26,9 @@
|
||||
#include "engines/nancy/logic.h"
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/audio.h"
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
@@ -71,6 +74,7 @@ void HotMultiframeSceneChange::execute(NancyEngine *engine) {
|
||||
switch (state) {
|
||||
case kBegin:
|
||||
// turn main rendering on
|
||||
state = kRun;
|
||||
// fall through
|
||||
case kRun:
|
||||
hasHotspot = false;
|
||||
@@ -97,6 +101,7 @@ void Hot1FrSceneChange::execute(NancyEngine *engine) {
|
||||
switch (state) {
|
||||
case kBegin:
|
||||
hotspot = hotspotDesc.coords;
|
||||
state = kRun;
|
||||
// fall through
|
||||
case kRun:
|
||||
if (hotspotDesc.frameID == engine->playState.currentViewFrame) {
|
||||
@@ -469,7 +474,34 @@ uint16 ShowInventoryItem::readData(Common::SeekableReadStream &stream) {
|
||||
}
|
||||
|
||||
uint16 PlayDigiSoundAndDie::readData(Common::SeekableReadStream &stream) {
|
||||
return readRaw(stream, 0x2B); // TODO
|
||||
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);
|
||||
SceneChange::readData(stream);
|
||||
return 0x2B;
|
||||
}
|
||||
|
||||
void PlayDigiSoundAndDie::execute(NancyEngine *engine){
|
||||
switch (state) {
|
||||
case kBegin:
|
||||
engine->sound->loadSound(filename, id, numLoops, volume);
|
||||
state = kRun;
|
||||
break;
|
||||
case kRun:
|
||||
if (!engine->sound->isSoundPlaying(id)) {
|
||||
state = kEnd;
|
||||
}
|
||||
break;
|
||||
case kEnd:
|
||||
SceneChange::execute(engine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 PlaySoundPanFrameAnchorAndDie::readData(Common::SeekableReadStream &stream) {
|
||||
|
||||
@@ -337,10 +337,18 @@ public:
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
};
|
||||
|
||||
class PlayDigiSoundAndDie : public ActionRecord {
|
||||
class PlayDigiSoundAndDie : public SceneChange {
|
||||
public:
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
virtual void execute(NancyEngine *engine) override;
|
||||
// TODO subclass into Play and Stop (?)
|
||||
|
||||
Common::String filename;
|
||||
int16 id = -1; // 0xA
|
||||
uint16 numLoops = 0; // 0x10
|
||||
uint16 volume = 0; // 0x16, between 0 and 60
|
||||
// ...
|
||||
// SceneChange elements at 0x1E
|
||||
};
|
||||
|
||||
class PlaySoundPanFrameAnchorAndDie : public ActionRecord {
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/audio.h"
|
||||
#include "engines/nancy/nancy.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/stream.h"
|
||||
@@ -172,4 +176,52 @@ Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, Di
|
||||
return Audio::makeVorbisStream(subStream, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
SoundManager::SoundManager(NancyEngine *engine) :
|
||||
_engine(engine) {
|
||||
_mixer = _engine->_system->getMixer();
|
||||
}
|
||||
|
||||
// Combine load and play until i find a reason not to
|
||||
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 / 60);
|
||||
names[id] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::stopSound(int16 id) {
|
||||
if (isSoundPlaying(id)) {
|
||||
_mixer->stopHandle(handles[id]);
|
||||
}
|
||||
names[id] = Common::String();
|
||||
}
|
||||
|
||||
bool SoundManager::isSoundPlaying(int16 id) {
|
||||
if (id >= 0 && id < 20) {
|
||||
return _mixer->isSoundHandleActive(handles[id]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns whether the exception was skipped
|
||||
bool SoundManager::stopAllSounds(Common::String *except) {
|
||||
bool ret = false;
|
||||
for (uint i = 0; i < 20; ++i) {
|
||||
if (except == nullptr || names[i] != *except) {
|
||||
stopSound(i);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // End of namespace Nancy
|
||||
+26
-4
@@ -23,6 +23,11 @@
|
||||
#ifndef NANCY_AUDIO_H
|
||||
#define NANCY_AUDIO_H
|
||||
|
||||
#include "common/types.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
@@ -31,14 +36,31 @@ namespace Audio {
|
||||
class SeekableAudioStream;
|
||||
}
|
||||
|
||||
namespace DisposeAfterUse {
|
||||
enum Flag;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void loadSound(Common::String &name, int16 id, uint16 numLoops = 0, uint16 volume = 60);
|
||||
void stopSound(int16 id);
|
||||
bool isSoundPlaying(int16 id);
|
||||
bool stopAllSounds(Common::String *except = nullptr);
|
||||
|
||||
private:
|
||||
NancyEngine *_engine;
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
Audio::SoundHandle handles[20];
|
||||
Common::String names[20];
|
||||
};
|
||||
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_AUDIO_H
|
||||
@@ -42,9 +42,12 @@ SceneSummary::SceneSummary(Common::SeekableReadStream *stream) {
|
||||
stream->seek(3, SEEK_CUR);
|
||||
videoFormat = stream->readUint16LE();
|
||||
|
||||
stream->read(buf, 9);
|
||||
stream->read(buf, 10);
|
||||
buf[9] = 0;
|
||||
audioFile = Common::String(buf);
|
||||
audioID = stream->readSint16LE();
|
||||
stream->skip(0xE);
|
||||
audioVolume = stream->readUint16LE();
|
||||
|
||||
stream->seek(0x72);
|
||||
verticalScrollDelta = stream->readUint16LE();
|
||||
|
||||
@@ -45,6 +45,8 @@ struct SceneSummary {
|
||||
//
|
||||
uint16 videoFormat; // 0x3E, value is 1 or 2
|
||||
Common::String audioFile; // 0x40
|
||||
int16 audioID; // 0x4A
|
||||
uint16 audioVolume; // 0x5A
|
||||
//
|
||||
uint16 verticalScrollDelta; // 0x72
|
||||
uint16 horizontalEdgeSize; // 0x74
|
||||
|
||||
@@ -63,15 +63,12 @@ void LogoSequence::init() {
|
||||
}
|
||||
|
||||
void LogoSequence::startSound() {
|
||||
Common::SeekableReadStream *mSnd = SearchMan.createReadStreamForMember(_engine->_menuSound.name + ".his");
|
||||
if (mSnd) {
|
||||
Audio::RewindableAudioStream *aStr = makeHISStream(mSnd, DisposeAfterUse::YES);
|
||||
if (aStr) {
|
||||
Audio::AudioStream *aStrLoop = Audio::makeLoopingAudioStream(aStr, 0);
|
||||
Audio::SoundHandle handle;
|
||||
_engine->_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &handle, aStrLoop);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
_startTicks = _engine->_system->getMillis();
|
||||
_state = kRun;
|
||||
|
||||
+3
-10
@@ -29,6 +29,7 @@
|
||||
#include "engines/nancy/scene.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/audio.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/random.h"
|
||||
@@ -77,6 +78,7 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
|
||||
sceneManager = new SceneManager(this);
|
||||
graphics = new GraphicsManager(this);
|
||||
input = new InputManager(this);
|
||||
sound = new SoundManager(this);
|
||||
|
||||
launchConsole = false;
|
||||
}
|
||||
@@ -90,6 +92,7 @@ NancyEngine::~NancyEngine() {
|
||||
delete logic;
|
||||
delete sceneManager;
|
||||
delete input;
|
||||
delete sound;
|
||||
}
|
||||
|
||||
GUI::Debugger *NancyEngine::getDebugger() {
|
||||
@@ -184,7 +187,6 @@ void NancyEngine::bootGameEngine() {
|
||||
if (!boot->load())
|
||||
error("Failed to load boot script");
|
||||
preloadCals(*boot);
|
||||
readSound(*boot, "MSND", _menuSound);
|
||||
|
||||
addBootChunk("BSUM", boot->getChunkStream("BSUM"));
|
||||
readBootSummary(*boot);
|
||||
@@ -323,15 +325,6 @@ void NancyEngine::readImageList(const IFF &boot, const Common::String &prefix, I
|
||||
}
|
||||
}
|
||||
|
||||
void NancyEngine::readSound(const IFF &boot, const Common::String &name, NancyEngine::Sound &sound) {
|
||||
Common::SeekableReadStream *stream = boot.getChunkStream(name);
|
||||
|
||||
if (!stream)
|
||||
error("Failed to read BOOT %s", name.c_str());
|
||||
|
||||
sound.name = readFilename(stream);
|
||||
}
|
||||
|
||||
class NancyEngine_v0 : public NancyEngine {
|
||||
public:
|
||||
NancyEngine_v0(OSystem *syst, const NancyGameDescription *gd) : NancyEngine(syst, gd) { }
|
||||
|
||||
@@ -69,6 +69,7 @@ class SceneManager;
|
||||
class Logic;
|
||||
class GraphicsManager;
|
||||
class InputManager;
|
||||
class SoundManager;
|
||||
|
||||
class NancyEngine : public Engine {
|
||||
public:
|
||||
@@ -115,6 +116,7 @@ public:
|
||||
SceneManager *sceneManager;
|
||||
GraphicsManager *graphics;
|
||||
InputManager *input;
|
||||
SoundManager *sound;
|
||||
|
||||
// Contains all player data
|
||||
PlayState playState;
|
||||
@@ -138,10 +140,6 @@ protected:
|
||||
uint16 height;
|
||||
};
|
||||
|
||||
struct Sound {
|
||||
Common::String name;
|
||||
};
|
||||
|
||||
enum GameState {
|
||||
kBoot,
|
||||
kPartnerLogo, // v2 only
|
||||
@@ -173,12 +171,10 @@ protected:
|
||||
ImageList _objects;
|
||||
uint16 _firstSceneID;
|
||||
int32 _fontSize;
|
||||
Sound _menuSound;
|
||||
GameFlow _gameFlow;
|
||||
|
||||
void preloadCals(const IFF &boot);
|
||||
void readImageList(const IFF &boot, const Common::String &prefix, ImageList &list);
|
||||
void readSound(const IFF &boot, const Common::String &name, Sound &sound);
|
||||
Common::String readFilename(Common::ReadStream *stream) const;
|
||||
|
||||
virtual uint getFilenameLen() const = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "engines/nancy/logic.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/audio.h"
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "common/rect.h"
|
||||
@@ -49,8 +50,13 @@ void SceneManager::process() {
|
||||
load();
|
||||
break;
|
||||
case kStartSound:
|
||||
// TODO
|
||||
break;
|
||||
// Stop all sounds, unless the new scene's background music matches the last one's;
|
||||
// in that case, stop everything except the background music
|
||||
if (!_engine->sound->stopAllSounds(¤tScene.audioFile)) {
|
||||
_engine->sound->loadSound(currentScene.audioFile, currentScene.audioID, 0, currentScene.audioVolume);
|
||||
}
|
||||
_state = kRun;
|
||||
// fall through
|
||||
case kRun:
|
||||
run();
|
||||
break;
|
||||
@@ -202,7 +208,7 @@ void SceneManager::load() {
|
||||
_engine->playState.lastDrawnViewFrame = -1;
|
||||
_engine->input->setPointerBitmap(0, 0, false);
|
||||
|
||||
_state = kRun; // TODO temp, is actually StartSound
|
||||
_state = kStartSound; // TODO temp, is actually StartSound
|
||||
}
|
||||
|
||||
void SceneManager::run() {
|
||||
|
||||
Reference in New Issue
Block a user