MYST3: Implement ambient cues

This commit is contained in:
Bastien Bouclet 2014-03-01 09:09:54 +01:00
parent 8fafca1949
commit c2160f0a7d
5 changed files with 115 additions and 6 deletions

View File

@ -21,13 +21,16 @@
*/
#include "engines/myst3/ambient.h"
#include "engines/myst3/database.h"
#include "engines/myst3/myst3.h"
#include "engines/myst3/state.h"
#include "engines/myst3/sound.h"
namespace Myst3 {
Ambient::Ambient(Myst3Engine *vm) :
_vm(vm) {
_vm(vm),
_cueStartFrame(0) {
_cueSheet.reset();
}
@ -113,7 +116,61 @@ void Ambient::setCueSheet(uint32 id, int32 volume, int32 heading, int32 headingA
_cueSheet.headingAngle = headingAngle;
}
uint16 Ambient::delayForCue(uint32 id) {
const AmbientCue &cue = _vm->_db->getAmbientCue(id);
// Return a delay in frames inside the bounds
return _vm->_rnd->getRandomNumberRng(cue.minFrames, cue.maxFrames);
}
uint32 Ambient::nextCueSound(uint32 id) {
static uint32 lastId = 0;
const AmbientCue &cue = _vm->_db->getAmbientCue(id);
// Only one sound, no way it can be different from the previous one
if (cue.tracks.size() == 1) {
return cue.tracks[0];
}
// Make sure the new random sound is different from the last one
uint32 soundId;
do {
uint index = _vm->_rnd->getRandomNumber(cue.tracks.size() - 1);
soundId = cue.tracks[index];
} while (soundId == lastId);
lastId = soundId;
return soundId;
}
void Ambient::updateCue() {
if (_cueSheet.id) {
if (!_cueStartFrame) {
_cueStartFrame = _vm->_state->getFrameCount() + delayForCue(_cueSheet.id);
}
if (_vm->_state->getFrameCount() >= _cueStartFrame) {
_cueStartFrame = 0;
uint32 soundId = nextCueSound(_cueSheet.id);
uint heading;
if (_cueSheet.heading == 32766) {
heading = _vm->_rnd->getRandomNumberRng(0, 359);
} else {
heading = _cueSheet.heading;
}
_vm->_sound->playCue(soundId, _cueSheet.volume, heading, _cueSheet.headingAngle);
}
}
}
void Ambient::applySounds(uint32 fadeOutDelay) {
// Reset the random sounds
_cueStartFrame = 0;
if (!_cueSheet.id) {
_vm->_sound->stopCue();
}
// TODO
}

View File

@ -40,7 +40,9 @@ public:
void scaleVolume(uint32 volume);
void addSound(uint32 id, int32 volume, int32 heading, int32 headingAngle, int32 u1, int32 u2);
void setCueSheet(uint32 id, int32 volume, int32 heading, int32 headingAngle);
void updateCue();
uint32 _scriptAge;
uint32 _scriptRoom;
@ -70,8 +72,13 @@ private:
}
};
uint16 delayForCue(uint32 id);
uint32 nextCueSound(uint32 id);
Common::Array<AmbientSound> _sounds;
AmbientSound _cueSheet;
uint32 _cueStartFrame;
};
} /* namespace Myst3 */

View File

@ -967,7 +967,7 @@ void Database::loadAmbientCues(Common::ReadStreamEndian *s) {
}
const AmbientCue& Database::getAmbientCue(uint16 id) {
if (_ambientCues.contains(id))
if (!_ambientCues.contains(id))
error("Unable to find an ambient cue with id %d", id);
return _ambientCues.getVal(id);

View File

@ -20,6 +20,7 @@
*
*/
#include "engines/myst3/ambient.h"
#include "engines/myst3/database.h"
#include "engines/myst3/myst3.h"
#include "engines/myst3/sound.h"
@ -49,17 +50,33 @@ void Sound::playEffect(uint32 id, uint32 volume, uint16 heading, uint16 attenuat
channel->play(id, volume, heading, attenuation, 0, 0, 0, kEffect);
}
void Sound::playCue(uint32 id, uint32 volume, uint16 heading, uint16 attenuation) {
SoundChannel *channel = _channels[13];
channel->play(id, volume, heading, attenuation, 0, 0, 0, kCue);
}
void Sound::stopCue(uint32 fadeDelay) {
SoundChannel *channel = _channels[13];
if (fadeDelay == 0) {
channel->stop();
} else {
channel->fade(0, -1, 0, fadeDelay);
}
}
SoundChannel *Sound::getChannelForSound(uint32 id, SoundType priority) {
// if the sound is already playing, return that channel
for (uint i = 0; i < kNumChannels; i++)
for (uint i = 0; i < kNumChannels - 1; i++)
if (_channels[i]->_id == id && _channels[i]->_playing)
return _channels[i];
// else return the first available channel
for (uint i = 0; i < kNumChannels; i++)
for (uint i = 0; i < kNumChannels - 1; i++)
if (!_channels[i]->_playing)
return _channels[i];
// Channel number 13 is reserved for cue sounds
error("No available channel for sound %d", id);
}
@ -68,6 +85,7 @@ void Sound::update() {
_channels[i]->update();
_vm->runBackgroundSoundScriptsFromNode(_vm->_state->getLocationNode());
_vm->_ambient->updateCue();
}
SoundChannel::SoundChannel(Myst3Engine *vm) :
@ -151,4 +169,25 @@ void SoundChannel::update() {
}
}
void SoundChannel::stop() {
if (!_playing)
return; // Nothing to do
_playing = g_system->getMixer()->isSoundHandleActive(_handle);
if (_playing) {
g_system->getMixer()->stopHandle(_handle);
_playing = false;
}
_stream = 0;
}
void SoundChannel::fade(uint32 targetVolume, int32 targetHeading, int32 targetAttenuation, uint32 fadeDelay) {
//TODO: Implement this mock
if (targetVolume == 0) {
stop();
}
}
} /* namespace Myst3 */

View File

@ -32,7 +32,7 @@ class Myst3Engine;
enum SoundType {
kUnk0,
kUnk1,
kUnk2,
kCue,
kEffect,
kMusic
};
@ -43,7 +43,9 @@ public:
virtual ~SoundChannel();
void play(uint32 id, uint32 volume, uint16 heading, uint16 attenuation, uint unk1, uint unk2, uint unk3, SoundType type);
void fade(uint32 targetVolume, int32 targetHeading, int32 targetAttenuation, uint32 fadeDelay);
void update();
void stop();
uint32 _id;
bool _playing;
@ -66,10 +68,14 @@ public:
virtual ~Sound();
void playEffect(uint32 id, uint32 volume, uint16 heading = 0, uint16 attenuation = 0);
void playCue(uint32 id, uint32 volume, uint16 heading, uint16 attenuation);
void stopCue(uint32 fadeDelay);
void update();
private:
static const uint kNumChannels = 13;
static const uint kNumChannels = 14;
Myst3Engine *_vm;
SoundChannel *_channels[kNumChannels];