aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Špalek2009-10-12 22:27:23 +0000
committerRobert Špalek2009-10-12 22:27:23 +0000
commite77928440307f0d8a765e32100e031989ad25ff5 (patch)
tree970e4c758de39c9c5f97bc6557428a0363a07101
parentd306e1219e606f5af6b3dd37556f1ba1ecb5ed51 (diff)
downloadscummvm-rg350-e77928440307f0d8a765e32100e031989ad25ff5.tar.gz
scummvm-rg350-e77928440307f0d8a765e32100e031989ad25ff5.tar.bz2
scummvm-rg350-e77928440307f0d8a765e32100e031989ad25ff5.zip
Sound effects are now correctly played.
Dubbing is not yet played. svn-id: r45000
-rw-r--r--engines/draci/animation.cpp15
-rw-r--r--engines/draci/animation.h3
-rw-r--r--engines/draci/draci.cpp12
-rw-r--r--engines/draci/draci.h4
-rw-r--r--engines/draci/game.cpp7
-rw-r--r--engines/draci/sound.cpp122
-rw-r--r--engines/draci/sound.h57
7 files changed, 205 insertions, 15 deletions
diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp
index c3ae4a8f12..37ef609ea4 100644
--- a/engines/draci/animation.cpp
+++ b/engines/draci/animation.cpp
@@ -39,6 +39,7 @@ Animation::Animation(DraciEngine *vm, int index) : _vm(vm) {
_paused = false;
_tick = _vm->_system->getMillis();
_currentFrame = 0;
+ _hasChangedFrame = true;
_callback = &Animation::doNothing;
}
@@ -97,6 +98,8 @@ void Animation::nextFrame(bool force) {
// Fetch new frame and mark it dirty
markDirtyRect(surface);
+
+ _hasChangedFrame = true;
}
}
@@ -129,6 +132,15 @@ void Animation::drawFrame(Surface *surface) {
// Draw frame
frame->drawReScaled(surface, false, _displacement);
}
+
+ const SoundSample *sample = _samples[_currentFrame];
+ if (_hasChangedFrame && sample) {
+ debugC(3, kDraciSoundDebugLevel,
+ "Playing sample on animation %d, frame %d: %d+%d at %dHz",
+ _id, _currentFrame, sample->_offset, sample->_length, sample->_frequency);
+ _vm->_sound->playSound(sample, Audio::Mixer::kMaxChannelVolume, false);
+ }
+ _hasChangedFrame = false;
}
void Animation::setID(int id) {
@@ -162,6 +174,9 @@ bool Animation::isPlaying() const {
void Animation::setPlaying(bool playing) {
_tick = _vm->_system->getMillis();
_playing = playing;
+
+ // When restarting an animation, allow playing sounds.
+ _hasChangedFrame |= playing;
}
bool Animation::isPaused() const {
diff --git a/engines/draci/animation.h b/engines/draci/animation.h
index 8dc596406d..ceebf04261 100644
--- a/engines/draci/animation.h
+++ b/engines/draci/animation.h
@@ -130,6 +130,7 @@ private:
uint _currentFrame;
uint _z;
+ bool _hasChangedFrame;
Displacement _displacement;
@@ -145,7 +146,7 @@ private:
* object doesn't own these pointers, but they are stored in the
* cache.
*/
- Common::List<const SoundSample *> _samples;
+ Common::Array<const SoundSample *> _samples;
AnimationCallback _callback;
diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp
index 1868460fcf..8fc7046d86 100644
--- a/engines/draci/draci.cpp
+++ b/engines/draci/draci.cpp
@@ -62,6 +62,9 @@ const char *stringsPath = "RETEZCE.DFW";
const char *soundsPath = "CD2.SAM";
const char *dubbingPath = "CD.SAM";
+const uint kSoundsFrequency = 13000;
+const uint kDubbingFrequency = 22000;
+
DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst) {
// Put your engine in a sane state, but do nothing big yet;
@@ -79,6 +82,7 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc)
Common::addDebugChannel(kDraciArchiverDebugLevel, "archiver", "BAR archiver debug info");
Common::addDebugChannel(kDraciLogicDebugLevel, "logic", "Game logic debug info");
Common::addDebugChannel(kDraciAnimationDebugLevel, "animation", "Animation debug info");
+ Common::addDebugChannel(kDraciSoundDebugLevel, "sound", "Sound debug info");
// Don't forget to register your random source
g_eventRec.registerRandomSource(_rnd, "draci");
@@ -109,8 +113,9 @@ int DraciEngine::init() {
_itemImagesArchive = new BArchive(itemImagesPath);
_stringsArchive = new BArchive(stringsPath);
- _soundsArchive = new SoundArchive(soundsPath);
- _dubbingArchive = new SoundArchive(dubbingPath);
+ _soundsArchive = new SoundArchive(soundsPath, kSoundsFrequency);
+ _dubbingArchive = new SoundArchive(dubbingPath, kDubbingFrequency);
+ _sound = new Sound(_mixer);
// Load the game's fonts
_smallFont = new Font(kFontSmall);
@@ -298,6 +303,7 @@ DraciEngine::~DraciEngine() {
delete _soundsArchive;
delete _dubbingArchive;
+ delete _sound;
// Remove all of our debug levels here
Common::clearAllDebugChannels();
@@ -337,7 +343,7 @@ void DraciEngine::pauseEngineIntern(bool pause) {
void DraciEngine::syncSoundSettings() {
Engine::syncSoundSettings();
- // TODO: update our volumes
+ _sound->setVolume();
}
const char *DraciEngine::getSavegameFile(int saveGameIdx) {
diff --git a/engines/draci/draci.h b/engines/draci/draci.h
index d5683d5516..6ef339de33 100644
--- a/engines/draci/draci.h
+++ b/engines/draci/draci.h
@@ -66,6 +66,7 @@ public:
Game *_game;
Script *_script;
AnimationManager *_anims;
+ Sound *_sound;
Font *_smallFont;
Font *_bigFont;
@@ -99,7 +100,8 @@ enum {
kDraciBytecodeDebugLevel = 1 << 1,
kDraciArchiverDebugLevel = 1 << 2,
kDraciLogicDebugLevel = 1 << 3,
- kDraciAnimationDebugLevel = 1 << 4
+ kDraciAnimationDebugLevel = 1 << 4,
+ kDraciSoundDebugLevel = 1 << 5
};
// Macro to simulate lround() for non-C99 compilers
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index d5701c3eae..ff15483cc7 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -1157,7 +1157,7 @@ int Game::loadAnimation(uint animNum, uint z) {
uint scaledWidth = animationReader.readUint16LE();
uint scaledHeight = animationReader.readUint16LE();
byte mirror = animationReader.readByte();
- uint sample = animationReader.readUint16LE();
+ int sample = animationReader.readUint16LE() - 1;
uint freq = animationReader.readUint16LE();
uint delay = animationReader.readUint16LE();
@@ -1301,6 +1301,11 @@ void Game::enterNewRoom(bool force_reload) {
}
debugC(1, kDraciLogicDebugLevel, "Entering room %d using gate %d", _newRoom, _newGate);
+ // TODO: maybe wait till all sounds end instead of stopping them.
+ // In any case, make sure all sounds are stopped before we deallocate
+ // their memory by clearing the cache.
+ _vm->_sound->stopAll();
+
// Clear archives
_vm->_roomsArchive->clearCache();
_vm->_spritesArchive->clearCache();
diff --git a/engines/draci/sound.cpp b/engines/draci/sound.cpp
index 8f734d1afb..2d2cbcf74d 100644
--- a/engines/draci/sound.cpp
+++ b/engines/draci/sound.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "common/config-manager.h"
#include "common/debug.h"
#include "common/file.h"
#include "common/str.h"
@@ -31,6 +32,9 @@
#include "draci/sound.h"
#include "draci/draci.h"
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+
namespace Draci {
void SoundArchive::openArchive(const Common::String &path) {
@@ -129,9 +133,9 @@ void SoundArchive::clearCache() {
*
* Loads individual samples from an archive to memory on demand.
*/
-const SoundSample *SoundArchive::getSample(uint i, uint freq) {
+const SoundSample *SoundArchive::getSample(int i, uint freq) {
// Check whether requested file exists
- if (i >= _sampleCount) {
+ if (i < 0 || i >= (int) _sampleCount) {
return NULL;
}
@@ -150,12 +154,122 @@ const SoundSample *SoundArchive::getSample(uint i, uint freq) {
debugC(3, kDraciArchiverDebugLevel, "Cached sample %d from archive %s",
i, _path.c_str());
}
- _samples[i]._frequency = freq;
+ _samples[i]._frequency = freq ? freq : _defaultFreq;
return _samples + i;
}
-} // End of namespace Draci
+Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) {
+
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ _handles[i].type = kFreeHandle;
+
+ setVolume();
+}
+
+SndHandle *Sound::getHandle() {
+ for (int i = 0; i < SOUND_HANDLES; i++) {
+ if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle)) {
+ debugC(5, kDraciSoundDebugLevel, "Handle %d has finished playing", i);
+ _handles[i].type = kFreeHandle;
+ }
+ }
+
+ for (int i = 0; i < SOUND_HANDLES; i++) {
+ if (_handles[i].type == kFreeHandle)
+ return &_handles[i];
+ }
+
+ error("Sound::getHandle(): Too many sound handles");
+
+ return NULL; // for compilers that don't support NORETURN
+}
+
+void Sound::playSoundBuffer(Audio::SoundHandle *handle, const SoundSample &buffer, int volume,
+ sndHandleType handleType, bool loop) {
+
+ // Don't use FLAG_AUTOFREE, because our caching system deletes samples by itself.
+ byte flags = Audio::Mixer::FLAG_UNSIGNED;
+
+ if (loop)
+ flags |= Audio::Mixer::FLAG_LOOP;
+
+ const Audio::Mixer::SoundType soundType = (handleType == kVoiceHandle) ?
+ Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType;
+
+ _mixer->playRaw(soundType, handle, buffer._data,
+ buffer._length, buffer._frequency, flags, -1, volume);
+}
+
+void Sound::playSound(const SoundSample *buffer, int volume, bool loop) {
+ if (!buffer)
+ return;
+ SndHandle *handle = getHandle();
+
+ handle->type = kEffectHandle;
+ playSoundBuffer(&handle->handle, *buffer, 2 * volume, handle->type, loop);
+}
+
+void Sound::pauseSound() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kEffectHandle)
+ _mixer->pauseHandle(_handles[i].handle, true);
+}
+
+void Sound::resumeSound() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kEffectHandle)
+ _mixer->pauseHandle(_handles[i].handle, false);
+}
+
+void Sound::stopSound() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kEffectHandle) {
+ _mixer->stopHandle(_handles[i].handle);
+ _handles[i].type = kFreeHandle;
+ }
+}
+
+void Sound::playVoice(const SoundSample *buffer) {
+ if (!buffer)
+ return;
+ SndHandle *handle = getHandle();
+
+ handle->type = kVoiceHandle;
+ playSoundBuffer(&handle->handle, *buffer, Audio::Mixer::kMaxChannelVolume, handle->type, false);
+}
+
+void Sound::pauseVoice() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kVoiceHandle)
+ _mixer->pauseHandle(_handles[i].handle, true);
+}
+void Sound::resumeVoice() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kVoiceHandle)
+ _mixer->pauseHandle(_handles[i].handle, false);
+}
+void Sound::stopVoice() {
+ for (int i = 0; i < SOUND_HANDLES; i++)
+ if (_handles[i].type == kVoiceHandle) {
+ _mixer->stopHandle(_handles[i].handle);
+ _handles[i].type = kFreeHandle;
+ }
+}
+void Sound::stopAll() {
+ stopVoice();
+ stopSound();
+}
+
+void Sound::setVolume() {
+ const int soundVolume = ConfMan.getInt("sfx_volume");
+ const int speechVolume = ConfMan.getInt("speech_volume");
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, speechVolume);
+ // TODO: make sure this sound settings works
+}
+
+} // End of namespace Draci
diff --git a/engines/draci/sound.h b/engines/draci/sound.h
index b9429a70a7..86d92f1bf7 100644
--- a/engines/draci/sound.h
+++ b/engines/draci/sound.h
@@ -28,6 +28,7 @@
#include "common/str.h"
#include "common/file.h"
+#include "sound/mixer.h"
namespace Draci {
@@ -48,10 +49,8 @@ struct SoundSample {
class SoundArchive {
public:
- SoundArchive() : _path(), _samples(NULL), _sampleCount(0), _opened(false), _f(NULL) {}
-
- SoundArchive(const Common::String &path) :
- _path(), _samples(NULL), _sampleCount(0), _opened(false), _f(NULL) {
+ SoundArchive(const Common::String &path, uint defaultFreq) :
+ _path(), _samples(NULL), _sampleCount(0), _defaultFreq(defaultFreq), _opened(false), _f(NULL) {
openArchive(path);
}
@@ -69,16 +68,64 @@ public:
void clearCache();
- const SoundSample *getSample(uint i, uint freq);
+ const SoundSample *getSample(int i, uint freq);
private:
Common::String _path; ///< Path to file
SoundSample *_samples; ///< Internal array of files
uint _sampleCount; ///< Number of files in archive
+ uint _defaultFreq; ///< The default sampling frequency of the archived samples
bool _opened; ///< True if the archive is opened, false otherwise
Common::File *_f; ///< Opened file
};
+#define SOUND_HANDLES 10
+
+enum sndHandleType {
+ kFreeHandle,
+ kEffectHandle,
+ kVoiceHandle
+};
+
+struct SndHandle {
+ Audio::SoundHandle handle;
+ sndHandleType type;
+};
+
+// Taken from engines/saga/sound.h and simplified (in particular, removed
+// decompression until we support compressed files too).
+class Sound {
+public:
+
+ Sound(Audio::Mixer *mixer);
+ ~Sound() {}
+
+ void playSound(const SoundSample *buffer, int volume, bool loop);
+ void pauseSound();
+ void resumeSound();
+ void stopSound();
+
+ void playVoice(const SoundSample *buffer);
+ void pauseVoice();
+ void resumeVoice();
+ void stopVoice();
+
+ void stopAll();
+
+ void setVolume();
+
+ private:
+
+ void playSoundBuffer(Audio::SoundHandle *handle, const SoundSample &buffer, int volume,
+ sndHandleType handleType, bool loop);
+
+ SndHandle *getHandle();
+
+ Audio::Mixer *_mixer;
+
+ SndHandle _handles[SOUND_HANDLES];
+};
+
} // End of namespace Draci
#endif // DRACI_SOUND_H