EMI: Move handling of pooled sounds to EMISound.

This commit is contained in:
Joni Vähämäki 2014-07-20 00:21:24 +03:00
parent 9ee420b0d0
commit 007067c7ad
7 changed files with 214 additions and 46 deletions

View File

@ -365,8 +365,8 @@ void Lua_V2::IsSoundPlaying() {
}
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
if (sound && sound->_track) {
if (sound->_track->isPlaying()) {
if (sound) {
if (sound->isPlaying()) {
pushbool(true);
return;
}
@ -454,8 +454,8 @@ void Lua_V2::GetSoundVolume() {
return;
}
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
if (sound && sound->_track) {
lua_pushnumber(sound->_track->getVolume());
if (sound) {
lua_pushnumber(sound->getVolume());
} else {
warning("Lua_V2::GetSoundVolume: can't find sound track");
lua_pushnumber(Audio::Mixer::kMaxMixerVolume);

View File

@ -21,78 +21,85 @@
*/
#include "common/str.h"
#include "engines/grim/emi/sound/emisound.h"
#include "engines/grim/emi/poolsound.h"
#include "engines/grim/resource.h"
namespace Grim {
PoolSound::PoolSound() : _filename(""), _track(nullptr) {
PoolSound::PoolSound() : _filename(""), _loaded(false), _soundId(0) {
}
PoolSound::PoolSound(const Common::String &filename) : _filename(""), _track(nullptr) {
PoolSound::PoolSound(const Common::String &filename) : _filename(""), _loaded(false), _soundId(0) {
openFile(filename);
}
// Called when the engine restarts or Lua code calls FreeSound
PoolSound::~PoolSound() {
if (!_track)
return;
_track->stop();
delete _track;
if (_loaded) {
g_emiSound->freeLoadedSound(_soundId);
}
}
void PoolSound::setVolume(int volume) {
if (!_track) {
warning("PoolSound::setVolume: no track found");
return;
if (_loaded) {
g_emiSound->setLoadedSoundVolume(_soundId, volume);
}
_track->setVolume(volume);
}
void PoolSound::setBalance(int balance) {
if (!_track) {
warning("PoolSound::setBalance: no track found");
return;
if (_loaded) {
g_emiSound->setLoadedSoundPan(_soundId, balance);
}
_track->setBalance(balance);
}
void PoolSound::play(bool looping) {
if (!_track)
return;
_track->setLooping(looping);
_track->play();
if (_loaded) {
g_emiSound->playLoadedSound(_soundId);
}
}
void PoolSound::stop() {
if (!_track)
return;
_track->stop();
if (_loaded) {
g_emiSound->stopLoadedSound(_soundId);
}
}
int PoolSound::getVolume() {
if (_loaded) {
return g_emiSound->getLoadedSoundVolume(_soundId);
}
return 0;
}
bool PoolSound::isPlaying() {
if (_loaded) {
return g_emiSound->getLoadedSoundStatus(_soundId);
}
return false;
}
void PoolSound::openFile(const Common::String &filename) {
_filename = filename;
_track = new AIFFTrack(Audio::Mixer::kSFXSoundType, DisposeAfterUse::NO);
if (!_track->openSound(filename, filename)) {
_loaded = g_emiSound->loadSfx(filename.c_str(), _soundId);
if (!_loaded) {
warning("Could not open PoolSound file %s", filename.c_str());
delete _track;
_track = nullptr;
return;
}
}
void PoolSound::saveState(SaveGame *state) {
if (_track && _track->isStreamOpen()) {
state->writeBool(true);
state->writeString(_filename);
} else {
state->writeBool(false);
}
state->writeBool(_loaded);
state->writeLESint32(_soundId);
}
void PoolSound::restoreState(SaveGame *state) {
bool hasStream = state->readBool();
if (hasStream)
openFile(state->readString());
if (state->saveMinorVersion() >= 21) {
_loaded = state->readBool();
_soundId = state->readLESint32();
} else {
bool hasStream = state->readBool();
if (hasStream)
openFile(state->readString());
}
}
}

View File

@ -23,8 +23,8 @@
#ifndef GRIM_POOLSOUND_H
#define GRIM_POOLSOUND_H
#include "common/endian.h"
#include "engines/grim/pool.h"
#include "engines/grim/emi/sound/aifftrack.h"
namespace Grim {
@ -39,12 +39,17 @@ public:
void setVolume(int volume);
void setBalance(int balance);
void stop();
int getVolume();
bool isPlaying();
void saveState(SaveGame *state);
void restoreState(SaveGame *state);
static int32 getStaticTag() { return MKTAG('A','I','F','F'); }
AIFFTrack *_track;
private:
Common::String _filename;
int _soundId;
bool _loaded;
};
}

View File

@ -41,7 +41,7 @@ public:
bool openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start = nullptr) override;
bool isPlaying() override;
bool isStreamOpen() { return _stream != NULL; }
void setLooping(bool looping);
void setLooping(bool looping) override;
bool play() override;
Audio::Timestamp getPos() override;
private:

View File

@ -62,6 +62,7 @@ EMISound::EMISound(int fps) {
}
_curMusicState = -1;
_musicChannel = -1;
_curTrackId = 0;
_callbackFps = fps;
vimaInit(imuseDestTable);
initMusicTable();
@ -71,6 +72,7 @@ EMISound::EMISound(int fps) {
EMISound::~EMISound() {
g_system->getTimerManager()->removeTimerProc(timerHandler);
freeAllChannels();
freeLoadedSounds();
delete[] _channels;
delete[] _musicTable;
}
@ -102,6 +104,13 @@ void EMISound::freeAllChannels() {
}
}
void EMISound::freeLoadedSounds() {
for (TrackMap::iterator it = _preloadedTrackMap.begin(); it != _preloadedTrackMap.end(); ++it) {
delete it->_value;
}
_preloadedTrackMap.clear();
}
bool EMISound::startVoice(const char *soundName, int volume, int pan) {
return startSound(soundName, Audio::Mixer::kSpeechSoundType, volume, pan);
}
@ -175,13 +184,108 @@ void EMISound::setPan(const char *soundName, int pan) {
}
}
bool EMISound::loadSfx(const char *soundName, int &id) {
Common::StackLock lock(_mutex);
SoundTrack *track = initTrack(soundName, Audio::Mixer::kSFXSoundType);
if (track) {
id = _curTrackId++;
_preloadedTrackMap[id] = track;
return true;
} else {
return false;
}
}
void EMISound::playLoadedSound(int id) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
it->_value->play();
} else {
warning("EMISound::playLoadedSound called with invalid sound id");
}
}
void EMISound::setLoadedSoundLooping(int id, bool looping) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
it->_value->setLooping(looping);
} else {
warning("EMISound::setLoadedSoundLooping called with invalid sound id");
}
}
void EMISound::stopLoadedSound(int id) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
it->_value->stop();
} else {
warning("EMISound::stopLoadedSound called with invalid sound id");
}
}
void EMISound::freeLoadedSound(int id) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
delete it->_value;
_preloadedTrackMap.erase(it);
} else {
warning("EMISound::freeLoadedSound called with invalid sound id");
}
}
void EMISound::setLoadedSoundVolume(int id, int volume) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
it->_value->setVolume(volume);
} else {
warning("EMISound::setLoadedSoundVolume called with invalid sound id");
}
}
void EMISound::setLoadedSoundPan(int id, int pan) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
it->_value->setBalance(pan);
} else {
warning("EMISound::setLoadedSoundPan called with invalid sound id");
}
}
bool EMISound::getLoadedSoundStatus(int id) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
return it->_value->isPlaying();
}
warning("EMISound::getLoadedSoundStatus called with invalid sound id");
return false;
}
int EMISound::getLoadedSoundVolume(int id) {
Common::StackLock lock(_mutex);
TrackMap::iterator it = _preloadedTrackMap.find(id);
if (it != _preloadedTrackMap.end()) {
return it->_value->getVolume();
}
warning("EMISound::getLoadedSoundVolume called with invalid sound id");
return false;
}
SoundTrack *EMISound::initTrack(const Common::String &soundName, Audio::Mixer::SoundType soundType, const Audio::Timestamp *start) const {
SoundTrack *track;
if (soundName.hasSuffix(".scx")) {
Common::String soundNameLower(soundName);
soundNameLower.toLowercase();
if (soundNameLower.hasSuffix(".scx")) {
track = new SCXTrack(soundType);
} else if (soundName.hasSuffix(".m4b")) {
} else if (soundNameLower.hasSuffix(".m4b")) {
track = new MP3Track(soundType);
} else if (soundName.hasSuffix(".aif")) {
} else if (soundNameLower.hasSuffix(".aif")) {
track = new AIFFTrack(soundType);
} else {
track = new VimaTrack();
@ -531,12 +635,26 @@ void EMISound::updateTrack(SoundTrack *track) {
}
}
void EMISound::flushTracks() {
Common::StackLock lock(_mutex);
for (int i = 0; i < NUM_CHANNELS; i++) {
SoundTrack *track = _channels[i];
if (track == nullptr)
continue;
if (!track->isPlaying()) {
freeChannel(i);
}
}
}
void EMISound::restoreState(SaveGame *savedState) {
Common::StackLock lock(_mutex);
// Clear any current music
flushStack();
setMusicState(0);
freeAllChannels();
freeLoadedSounds();
// Actually load:
savedState->beginSection('SOUN');
_musicPrefix = savedState->readString();
@ -599,6 +717,17 @@ void EMISound::restoreState(SaveGame *savedState) {
_channels[i] = restoreTrack(savedState);
}
}
// Preloaded sounds:
if (savedState->saveMinorVersion() >= 21) {
_curTrackId = savedState->readLESint32();
uint32 numLoaded = savedState->readLEUint32();
for (uint32 i = 0; i < numLoaded; ++i) {
int id = savedState->readLESint32();
_preloadedTrackMap[id] = restoreTrack(savedState);
}
}
savedState->endSection();
}
@ -633,6 +762,16 @@ void EMISound::saveState(SaveGame *savedState) {
saveTrack(_channels[i], savedState);
}
}
// Preloaded sounds:
savedState->writeLESint32(_curTrackId);
uint32 numLoaded = _preloadedTrackMap.size();
savedState->writeLEUint32(numLoaded);
for (TrackMap::iterator it = _preloadedTrackMap.begin(); it != _preloadedTrackMap.end(); ++it) {
savedState->writeLESint32(it->_key);
saveTrack(it->_value, savedState);
}
savedState->endSection();
}

View File

@ -27,6 +27,7 @@
#include "common/str.h"
#include "common/stack.h"
#include "common/mutex.h"
#include "common/hashmap.h"
namespace Grim {
@ -60,6 +61,9 @@ class EMISound {
Common::Stack<StackEntry> _stateStack;
Common::Mutex _mutex;
typedef Common::HashMap<int, SoundTrack *> TrackMap;
TrackMap _preloadedTrackMap;
static void timerHandler(void *refConf);
void removeItem(SoundTrack *item);
int32 getFreeChannel();
@ -78,6 +82,16 @@ public:
void setVolume(const char *soundName, int volume);
void setPan(const char *soundName, int pan); /* pan: 0 .. 127 */
bool loadSfx(const char *soundName, int &id);
void playLoadedSound(int id);
void setLoadedSoundLooping(int id, bool looping);
void stopLoadedSound(int id);
void freeLoadedSound(int id);
void setLoadedSoundVolume(int id, int volume);
void setLoadedSoundPan(int id, int pan);
bool getLoadedSoundStatus(int id);
int getLoadedSoundVolume(int id);
void setMusicState(int stateId);
void selectMusicSet(int setId);
@ -98,7 +112,9 @@ public:
private:
int _curMusicState;
int _callbackFps;
int _curTrackId;
void freeAllChannels();
void freeLoadedSounds();
SoundTrack *initTrack(const Common::String &soundName, Audio::Mixer::SoundType soundType, const Audio::Timestamp *start = nullptr) const;
bool startSound(const char *soundName, Audio::Mixer::SoundType soundType, int volume, int pan);
void saveTrack(SoundTrack *track, SaveGame *savedState);

View File

@ -86,6 +86,7 @@ public:
Common::String getSoundName();
void setSoundName(const Common::String &name);
virtual bool hasLooped() { return false; }
virtual void setLooping(bool looping) { }
bool isPaused() const { return _paused; }
Audio::Mixer::SoundType getSoundType() const { return _soundType; }
};