Littleboy bc298a58f5 LASTEXPRESS: Simplify SoundQueue::updateQueue()
- Remove useless cache code
 - Use helper function to get the proper sound entry
 - Fix crash on using an invalid entry
2011-07-08 22:03:34 -04:00

401 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "lastexpress/sound/queue.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/state.h"
#include "lastexpress/sound/entry.h"
#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
SoundQueue::SoundQueue(LastExpressEngine *engine) : _engine(engine) {
_state = 0;
_currentType = kSoundType16;
_flag = 0;
_subtitlesFlag = 0;
_currentSubtitle = NULL;
}
SoundQueue::~SoundQueue() {
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
SAFE_DELETE(*i);
_soundList.clear();
for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i)
SAFE_DELETE(*i);
_subtitles.clear();
_currentSubtitle = NULL;
// Zero passed pointers
_engine = NULL;
}
//////////////////////////////////////////////////////////////////////////
// Timer
//////////////////////////////////////////////////////////////////////////
void SoundQueue::handleTimer() {
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
SoundEntry *entry = (*i);
// When the entry has stopped playing, we remove his buffer
if (entry->isFinished()) {
entry->close();
SAFE_DELETE(entry);
i = _soundList.reverse_erase(i);
continue;
}
// Queue the entry data, applying filtering
entry->play();
}
}
//////////////////////////////////////////////////////////////////////////
// Sound queue management
//////////////////////////////////////////////////////////////////////////
void SoundQueue::addToQueue(SoundEntry *entry) {
_soundList.push_back(entry);
}
void SoundQueue::removeFromQueue(EntityIndex entity) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(entity);
if (entry)
entry->reset();
}
void SoundQueue::removeFromQueue(Common::String filename) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(filename);
if (entry)
entry->reset();
}
void SoundQueue::updateQueue() {
Common::StackLock locker(_mutex);
++_flag;
if (getSoundState() & kSoundState1) {
SoundEntry *entry = getEntry(kSoundType1);
if (!entry || getFlags()->flag_3 || (entry && entry->getTime() > getSound()->getLoopingSoundDuration())) {
getSound()->playLoopingSound(0x45);
} else {
if (getSound()->getData1() && getSound()->getData2() >= getSound()->getData1()) {
entry->update(getSound()->getData0());
getSound()->setData1(0);
}
}
}
for (Common::List<SoundEntry *>::iterator it = _soundList.begin(); it != _soundList.end(); ++it) {
SoundEntry *entry = *it;
// Original removes the entry data from the cache and sets the archive as not loaded
// and if the sound data buffer is not full, loads a new entry to be played based on
// its priority and filter id
if (!entry->updateSound() && !(entry->getStatus().status3 & 0x8)) {
entry->close();
SAFE_DELETE(entry);
it = _soundList.reverse_erase(it);
}
}
// Original update the current entry, loading another set of samples to be decoded
getFlags()->flag_3 = 0;
--_flag;
}
void SoundQueue::resetQueue() {
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getType() == kSoundType1) {
(*i)->reset();
break;
}
}
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getType() == kSoundType2) {
(*i)->reset();
break;
}
}
}
void SoundQueue::resetQueue(SoundType type1, SoundType type2) {
if (!type2)
type2 = type1;
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getType() != type1 && (*i)->getType() != type2)
(*i)->reset();
}
}
void SoundQueue::clearQueue() {
Common::StackLock locker(_mutex);
_flag |= 8;
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
SoundEntry *entry = (*i);
// Delete entry
entry->close();
SAFE_DELETE(entry);
i = _soundList.reverse_erase(i);
}
updateSubtitles();
}
//////////////////////////////////////////////////////////////////////////
// State
//////////////////////////////////////////////////////////////////////////
void SoundQueue::clearStatus() {
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
(*i)->setStatus((*i)->getStatus().status | kSoundStatusClosed);
}
//////////////////////////////////////////////////////////////////////////
// Entry management
//////////////////////////////////////////////////////////////////////////
void SoundQueue::setupEntry(SoundType type, EntityIndex index) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(type);
if (entry)
entry->setEntity(index);
}
void SoundQueue::processEntry(EntityIndex entity) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(entity);
if (entry) {
entry->update(0);
entry->setEntity(kEntityPlayer);
}
}
void SoundQueue::processEntry(SoundType type) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(type);
if (entry)
entry->update(0);
}
void SoundQueue::processEntry(Common::String filename) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(filename);
if (entry) {
entry->update(0);
entry->setEntity(kEntityPlayer);
}
}
void SoundQueue::processEntries() {
_state = 0;
processEntry(kSoundType1);
processEntry(kSoundType2);
}
SoundEntry *SoundQueue::getEntry(EntityIndex index) {
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getEntity() == index)
return *i;
}
return NULL;
}
SoundEntry *SoundQueue::getEntry(Common::String name) {
if (!name.contains('.'))
name += ".SND";
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getName2() == name)
return *i;
}
return NULL;
}
SoundEntry *SoundQueue::getEntry(SoundType type) {
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
if ((*i)->getType() == type)
return *i;
}
return NULL;
}
uint32 SoundQueue::getEntryTime(EntityIndex index) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(index);
if (entry)
return entry->getTime();
return 0;
}
bool SoundQueue::isBuffered(EntityIndex entity) {
Common::StackLock locker(_mutex);
return (getEntry(entity) != NULL);
}
bool SoundQueue::isBuffered(Common::String filename, bool testForEntity) {
Common::StackLock locker(_mutex);
SoundEntry *entry = getEntry(filename);
if (testForEntity)
return entry != NULL && entry->getEntity() != kEntityPlayer;
return (entry != NULL);
}
//////////////////////////////////////////////////////////////////////////
// Subtitles
//////////////////////////////////////////////////////////////////////////
void SoundQueue::updateSubtitles() {
Common::StackLock locker(_mutex);
uint32 index = 0;
SubtitleEntry *subtitle = NULL;
for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
uint32 current_index = 0;
SoundEntry *soundEntry = (*i)->getSoundEntry();
SoundStatus status = (SoundStatus)soundEntry->getStatus().status;
if (!(status & kSoundStatus_40)
|| status & kSoundStatus_180
|| soundEntry->getTime() == 0
|| (status & kSoundStatusFilter) < 6
|| ((getFlags()->nis & 0x8000) && soundEntry->getPriority() < 90)) {
current_index = 0;
} else {
current_index = soundEntry->getPriority() + (status & kSoundStatusFilter);
if (_currentSubtitle == (*i))
current_index += 4;
}
if (index < current_index) {
index = current_index;
subtitle = (*i);
}
}
if (_currentSubtitle == subtitle) {
if (subtitle)
subtitle->setupAndDraw();
return;
}
if (_subtitlesFlag & 1)
subtitle->drawOnScreen();
if (subtitle) {
subtitle->loadData();
subtitle->setupAndDraw();
}
}
//////////////////////////////////////////////////////////////////////////
// Savegame
//////////////////////////////////////////////////////////////////////////
void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) {
Common::StackLock locker(_mutex);
s.syncAsUint32LE(_state);
s.syncAsUint32LE(_currentType);
// Compute the number of entries to save
uint32 numEntries = count();
s.syncAsUint32LE(numEntries);
// Save or load each entry data
if (s.isSaving()) {
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
(*i)->saveLoadWithSerializer(s);
} else {
warning("[Sound::saveLoadWithSerializer] Loading not implemented");
s.skip(numEntries * 64);
}
}
// FIXME: We probably need another mutex here to protect during the whole savegame process
// as we could have removed an entry between the time we check the count and the time we
// save the entries
uint32 SoundQueue::count() {
Common::StackLock locker(_mutex);
uint32 numEntries = 0;
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
if ((*i)->getName2().matchString("NISSND?"))
++numEntries;
return numEntries;
}
//////////////////////////////////////////////////////////////////////////
// Debug
//////////////////////////////////////////////////////////////////////////
void SoundQueue::stopAllSound() {
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
(*i)->getSoundStream()->stop();
}
} // End of namespace LastExpress