diff options
author | Evgeny Grechnikov | 2018-10-20 16:35:23 +0300 |
---|---|---|
committer | Evgeny Grechnikov | 2018-10-20 16:35:23 +0300 |
commit | af580eaa853b2434c0d237cff49f7f273444a06d (patch) | |
tree | 295dd4dfb9fadb348bd46bdc8512e16b19555c58 | |
parent | 9f7ae73a7b7318311e5cc52d36e451cacfba8a02 (diff) | |
download | scummvm-rg350-af580eaa853b2434c0d237cff49f7f273444a06d.tar.gz scummvm-rg350-af580eaa853b2434c0d237cff49f7f273444a06d.tar.bz2 scummvm-rg350-af580eaa853b2434c0d237cff49f7f273444a06d.zip |
LASTEXPRESS: save/load sound state
Warning: breaks compatibility with previous savefiles.
They were mostly broken anyway, locking any NPC who
waited for kActionEndSound when savefile was created.
-rw-r--r-- | engines/lastexpress/data/snd.cpp | 52 | ||||
-rw-r--r-- | engines/lastexpress/data/snd.h | 2 | ||||
-rw-r--r-- | engines/lastexpress/game/savegame.cpp | 4 | ||||
-rw-r--r-- | engines/lastexpress/game/savegame.h | 5 | ||||
-rw-r--r-- | engines/lastexpress/sound/entry.cpp | 224 | ||||
-rw-r--r-- | engines/lastexpress/sound/entry.h | 21 | ||||
-rw-r--r-- | engines/lastexpress/sound/queue.cpp | 65 | ||||
-rw-r--r-- | engines/lastexpress/sound/queue.h | 7 | ||||
-rw-r--r-- | engines/lastexpress/sound/sound.cpp | 10 |
9 files changed, 216 insertions, 174 deletions
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp index 835a1ab8fb..d9d193ecf3 100644 --- a/engines/lastexpress/data/snd.cpp +++ b/engines/lastexpress/data/snd.cpp @@ -363,6 +363,11 @@ public: return !_running || (!_looped && Audio::ADPCMStream::endOfData()); } + void seekToBlock(uint32 block) { + reset(); + _stream->seek(_startpos + _blockAlign * block); + } + int readBuffer(int16 *buffer, const int numSamples) { int samples = 0; // Temporary data @@ -384,22 +389,15 @@ public: _status.ima_ch[0].stepIndex = _stream->readSint16LE() << 6; _blockPos[0] = 4; - // Smooth transition, if requested - // the original game clears kSoundFlagVolumeChanging here if _nextVolume == _smoothChangeTarget - if (_nextVolume != _smoothChangeTarget) { - if (_volumeHoldBlocks > 3) { - if (_nextVolume < _smoothChangeTarget) - ++_nextVolume; - else - --_nextVolume; - _volumeHoldBlocks = 0; - if (_nextVolume == 0) { - _running = false; - break; - } - } else { - _volumeHoldBlocks++; - } + // sanity check against broken stream + if ((unsigned)_status.ima_ch[0].stepIndex >= ARRAYSIZE(stepTable) * 4) { + // the original game sets kSoundFlagDecodeError here and stops playing + _status.ima_ch[0].stepIndex = 0; + } + + if (!smoothVolumeChangeStep()) { + _running = false; + break; } // Get current volume @@ -436,6 +434,21 @@ private: uint32 _smoothChangeTarget; uint32 _volumeHoldBlocks; // smooth change of volume keeps volume on hold for 4 blocks = 133ms for every value; this is the counter bool _running, _looped; + + bool smoothVolumeChangeStep() { + if (_nextVolume == _smoothChangeTarget) + return true; // the original game clears kSoundFlagVolumeChanging here + if (_volumeHoldBlocks <= 3) { + _volumeHoldBlocks++; + return true; + } + if (_nextVolume < _smoothChangeTarget) + ++_nextVolume; + else + --_nextVolume; + _volumeHoldBlocks = 0; + return (_nextVolume != 0); + } }; ////////////////////////////////////////////////////////////////////////// @@ -444,7 +457,6 @@ private: SimpleSound::SimpleSound() : _size(0), _blocks(0), _blockSize(0) {} SimpleSound::~SimpleSound() { - stop(); } // Stop the sound @@ -480,11 +492,12 @@ uint32 SimpleSound::getTimeMS() { StreamedSound::StreamedSound() : _as(NULL), _loaded(false) {} StreamedSound::~StreamedSound() { + stop(); // should execute before disposal of _as, so don't move in ~SimpleSound delete _as; _as = NULL; } -bool StreamedSound::load(Common::SeekableReadStream *stream, uint32 volume, bool looped) { +bool StreamedSound::load(Common::SeekableReadStream *stream, uint32 volume, bool looped, uint32 startBlock) { if (!stream) return false; @@ -498,6 +511,8 @@ bool StreamedSound::load(Common::SeekableReadStream *stream, uint32 volume, bool } // Start decoding the input stream _as = makeDecoder(stream, _size, volume, looped); + if (startBlock) + _as->seekToBlock(startBlock); // Start playing the decoded audio stream play(_as, DisposeAfterUse::NO); @@ -546,6 +561,7 @@ AppendableSound::AppendableSound() : SimpleSound() { AppendableSound::~AppendableSound() { finish(); + stop(); _as = NULL; } diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h index 9672167a97..8358370581 100644 --- a/engines/lastexpress/data/snd.h +++ b/engines/lastexpress/data/snd.h @@ -80,7 +80,7 @@ public: StreamedSound(); ~StreamedSound(); - bool load(Common::SeekableReadStream *stream, uint32 volume, bool looped); + bool load(Common::SeekableReadStream *stream, uint32 volume, bool looped, uint32 startBlock = 0); virtual bool isFinished(); void setVolume(uint32 newVolume); diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 8b45835fc7..97fd67e533 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -40,8 +40,6 @@ namespace LastExpress { -#define DISABLE_COMPRESSION 1 - // Names of savegames static const struct { const char *saveFile; @@ -730,7 +728,7 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { writeValue(ser, "inventory", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveLoadWithSerializer), 7 * 32); writeValue(ser, "objects", WRAP_SYNC_FUNCTION(getObjects(), Objects, saveLoadWithSerializer), 5 * 128); writeValue(ser, "entities", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveLoadWithSerializer), 1262 * 40); - writeValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer), 3 * 4 + getSoundQueue()->count() * 64); + writeValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer), 3 * 4 + getSoundQueue()->count() * 68); writeValue(ser, "savepoints", WRAP_SYNC_FUNCTION(getSavePoints(), SavePoints, saveLoadWithSerializer), 128 * 16 + 4 + getSavePoints()->count() * 16); _savegame->process(); diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index f374e18a44..6c3105b8c0 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -79,8 +79,11 @@ namespace LastExpress { +// our own hack until compression code will be confirmed stable +#define DISABLE_COMPRESSION 1 + // Savegame signatures -#define SAVEGAME_SIGNATURE 0x12001200 // 301994496 +#define SAVEGAME_SIGNATURE (0x12001200 ^ DISABLE_COMPRESSION) // 301994496 #define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 // 3865110112 #define WRAP_SYNC_FUNCTION(instance, className, method) \ diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index 8d9a496fe1..d73642d92a 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -46,6 +46,7 @@ SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) { _tag = kSoundTagNone; _blockCount = 0; + _startTime = 0; _stream = NULL; @@ -82,11 +83,12 @@ void SoundEntry::open(Common::String name, SoundFlag flag, int priority) { } void SoundEntry::close() { + if (_soundStream) { + delete _soundStream; // stops the sound in destructor + _soundStream = NULL; + _stream = NULL; // disposed by _soundStream + } _status |= kSoundFlagClosed; - // Loop until ready - // _status |= kSoundFlagCloseRequested; - //while (!(_status & kSoundFlagClosed) && !(getSoundQueue()->getFlag() & 8) && (getSoundQueue()->getFlag() & 1)) - // ; // empty loop body // The original game remove the entry from the cache here, // but since we are called from within an iterator loop @@ -106,34 +108,41 @@ void SoundEntry::close() { } } -void SoundEntry::play() { +void SoundEntry::play(uint32 startTime) { + if (_status & kSoundFlagClosed) + return; // failed to load sound file + if (!_stream) error("[SoundEntry::play] stream has been disposed"); // Prepare sound stream - if (!_soundStream) - _soundStream = new StreamedSound(); + if (_soundStream) + error("[SoundEntry::play] already playing"); + + // BUG: the original game never checks for sound type when loading subtitles. + // NIS files and LNK files have the same base name, + // so without extra caution NIS subtitles would be loaded for LNK sounds as well. + // The original game instead separates calls to play() and setSubtitles() + // and does not call setSubtitles() for linked-after sounds. + // Unfortunately, that does not work well with save/load. + if ((_status & kSoundTypeMask) != kSoundTypeLink && (_status & kSoundTypeMask) != kSoundTypeConcert) { + // Get subtitles name + uint32 size = (_name.size() > 4 ? _name.size() - 4 : _name.size()); + setSubtitles(Common::String(_name.c_str(), size)); + } + + _soundStream = new StreamedSound(); _stream->seek(0); // Load the stream and start playing - _soundStream->load(_stream, _status & kSoundVolumeMask, (_status & kSoundFlagLooped) != 0); -} - -bool SoundEntry::isFinished() { - if (!_stream) - return true; - - if (!_soundStream) - return false; + _soundStream->load(_stream, _status & kSoundVolumeMask, (_status & kSoundFlagLooped) != 0, startTime); - // TODO check that all data has been queued - return _soundStream->isFinished(); + _status |= kSoundFlagPlaying; } void SoundEntry::setupTag(SoundFlag flag) { switch (flag & kSoundTypeMask) { - default: case kSoundTypeNormal: _tag = getSoundQueue()->generateNextTag(); break; @@ -160,7 +169,7 @@ void SoundEntry::setupTag(SoundFlag flag) { previous->fade(); } - _tag = kSoundTagIntro; + _tag = kSoundTagWalla; } break; @@ -199,14 +208,18 @@ void SoundEntry::setupTag(SoundFlag flag) { _tag = kSoundTagMenu; } break; + + default: + assert(false); + break; } } void SoundEntry::setupStatus(SoundFlag flag) { _status = flag; - if ((_status & kSoundVolumeMask) == kVolumeNone) - _status |= kSoundFlagMuteRequested; + // set the flag for the case that our savefiles + // will be ever loaded by the original game if (!(_status & kSoundFlagLooped)) _status |= kSoundFlagCloseOnDataEnd; } @@ -222,6 +235,14 @@ void SoundEntry::loadStream(Common::String name) { if (!_stream) _status = kSoundFlagClosed; + + // read total count of sound blocks for the case that our savefiles + // will be ever loaded by the original game + if (_stream) { + _stream->readUint32LE(); + _blockCount = _stream->readUint16LE(); + _status |= kSoundFlagHeaderProcessed; + } } void SoundEntry::setVolumeSmoothly(SoundFlag newVolume) { @@ -246,59 +267,46 @@ void SoundEntry::setVolumeSmoothly(SoundFlag newVolume) { } bool SoundEntry::update() { - assert(_name.size() < 16); + if (_soundStream && _soundStream->isFinished()) + _status |= kSoundFlagClosed; - bool result; - char sub[16]; + if (_status & kSoundFlagClosed) + return false; - if (_status & kSoundFlagClosed) { - result = false; + if (_status & kSoundFlagDelayedActivate) { + // counter overflow is processed correctly + if (_engine->_system->getMillis() - _initTimeMS >= _activateDelayMS) { + _status &= ~kSoundFlagDelayedActivate; + play(); + } } else { - if (_status & kSoundFlagDelayedActivate) { - // counter overflow is processed correctly - if (_engine->_system->getMillis() - _initTimeMS >= _activateDelayMS) { - _status &= ~kSoundFlagDelayedActivate; - play(); - - // drop .SND extension - strcpy(sub, _name.c_str()); - int l = _name.size(); - if (l > 4) - sub[l - 4] = 0; - showSubtitle(sub); - } - } else { - if (!(getSoundQueue()->getFlag() & 0x20)) { - if (!(_status & kSoundFlagFixedVolume)) { - if (_entity) { - if (_entity < 0x80) { - setVolume(getSound()->getSoundFlag(_entity)); - } + if (!(getSoundQueue()->getFlag() & 0x20)) { + if (!(_status & kSoundFlagFixedVolume)) { + if (_entity) { + if (_entity < 0x80) { + setVolume(getSound()->getSoundFlag(_entity)); } } } - //if (_status & kSoundFlagHasUnreadData && !(_status & kSoundFlagMute) && v1->soundBuffer) - // Sound_FillSoundBuffer(v1); } - result = true; + //if (_status & kSoundFlagHasUnreadData && !(_status & kSoundFlagMute) && v1->soundBuffer) + // Sound_FillSoundBuffer(v1); } - return result; + return true; } void SoundEntry::setVolume(SoundFlag newVolume) { assert((newVolume & kSoundVolumeMask) == newVolume); - if (newVolume) { - if (getSoundQueue()->getFlag() & 0x20 && _tag != kSoundTagNIS && _tag != kSoundTagLink) - setVolumeSmoothly(newVolume); - else - _status = newVolume + (_status & ~kSoundVolumeMask); - } else { + if (newVolume == kVolumeNone) { _volumeWithoutNIS = 0; - _status |= kSoundFlagMuteRequested; - _status &= ~(kSoundFlagVolumeChanging | kSoundVolumeMask); + } else if (getSoundQueue()->getFlag() & 0x20 && _tag != kSoundTagNIS && _tag != kSoundTagLink) { + setVolumeSmoothly(newVolume); + return; } + + _status = (_status & ~kSoundVolumeMask) | newVolume; if (_soundStream) _soundStream->setVolume(_status & kSoundVolumeMask); } @@ -324,24 +332,7 @@ void SoundEntry::initDelayedActivate(unsigned activateDelay) { _status |= kSoundFlagDelayedActivate; } -void SoundEntry::kill() { - _status |= kSoundFlagClosed; - _entity = kEntityPlayer; - - if (_stream) { - if (!_soundStream) { - SAFE_DELETE(_stream); - } else { - // the original stream will be disposed - _soundStream->stop(); - SAFE_DELETE(_soundStream); - } - - _stream = NULL; - } -} - -void SoundEntry::showSubtitle(Common::String filename) { +void SoundEntry::setSubtitles(Common::String filename) { _subtitle = new SubtitleEntry(_engine); _subtitle->load(filename, this); @@ -354,32 +345,79 @@ void SoundEntry::showSubtitle(Common::String filename) { } void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) { - assert(_name.size() <= 16); + if (s.isLoading()) { + // load the fields + uint32 blocksLeft; - if (_name.matchString("NISSND?") && ((_status & kSoundTypeMask) != kSoundTypeMenu)) { s.syncAsUint32LE(_status); s.syncAsUint32LE(_tag); - s.syncAsUint32LE(_blockCount); // field_8; + s.syncAsUint32LE(blocksLeft); + s.syncAsUint32LE(_startTime); + uint32 unused; + s.syncAsUint32LE(unused); + s.syncAsUint32LE(unused); + s.syncAsUint32LE(_entity); + + uint32 activateDelay; + s.syncAsUint32LE(activateDelay); + s.syncAsUint32LE(_priority); + + char name[16]; + s.syncBytes((byte *)name, 16); // _linkAfter name, should be always empty for entries in savefile + s.syncBytes((byte *)name, 16); // real name + name[15] = 0; + + // load the sound + _blockCount = blocksLeft + _startTime; + + // if we are loading a savefile from the original game + // and this savefile has been saved at a bizarre moment, + // we can see transient flags here. + // Let's pretend that the IRQ handler has run once. + if (_status & kSoundFlagPlayRequested) + _status |= kSoundFlagPlaying; + if (_status & (kSoundFlagCloseRequested | kSoundFlagFading)) + _status |= kSoundFlagClosed; + _status &= kSoundVolumeMask + | kSoundFlagPlaying + | kSoundFlagClosed + | kSoundFlagCloseOnDataEnd + | kSoundFlagLooped + | kSoundFlagDelayedActivate + | kSoundFlagHasSubtitles + | kSoundFlagFixedVolume + | kSoundFlagHeaderProcessed + | kSoundTypeMask; + + loadStream(name); // also sets _name + if (_status & kSoundFlagPlaying) + play((_status & kSoundFlagLooped) ? 0 : _startTime); // also loads subtitles + + _initTimeMS = _engine->_system->getMillis(); + _activateDelayMS = activateDelay * 1000 / 30; + + } else { + assert(_name.size() < 16); + assert(needSaving()); + // we can save our flags as is + // the original game can reconstruct kSoundFlagMute, kSoundFlagCyclicBuffer, kSoundFlagHasUnreadData, + // and we set other important flags correctly + s.syncAsUint32LE(_status); + s.syncAsUint32LE(_tag); uint32 time = getTime(); + uint32 blocksLeft = _blockCount - time; + s.syncAsUint32LE(blocksLeft); s.syncAsUint32LE(time); uint32 unused = 0; s.syncAsUint32LE(unused); s.syncAsUint32LE(unused); s.syncAsUint32LE(_entity); - if (s.isLoading()) { - uint32 delta; - s.syncAsUint32LE(delta); - _initTimeMS = _engine->_system->getMillis(); - _activateDelayMS = delta * 1000 / 15; - } else { - uint32 deltaMS = _initTimeMS + _activateDelayMS - _engine->_system->getMillis(); - if (deltaMS > 0x8000000u) // sanity check against overflow - deltaMS = 0; - uint32 delta = deltaMS * 15 / 1000; - s.syncAsUint32LE(delta); - } - + uint32 deltaMS = _initTimeMS + _activateDelayMS - _engine->_system->getMillis(); + if (deltaMS > 0x8000000u) // sanity check against overflow + deltaMS = 0; + uint32 delta = deltaMS * 30 / 1000; + s.syncAsUint32LE(delta); s.syncAsUint32LE(_priority); char name[16] = {0}; diff --git a/engines/lastexpress/sound/entry.h b/engines/lastexpress/sound/entry.h index cb12214d4a..998d1e53e8 100644 --- a/engines/lastexpress/sound/entry.h +++ b/engines/lastexpress/sound/entry.h @@ -96,9 +96,13 @@ public: void open(Common::String name, SoundFlag flag, int priority); void close(); - void play(); - void kill(); - bool isFinished(); + // startTime is measured in sound ticks, 30Hz timer + // [used for restoring the entry from savefile] + void play(uint32 startTime = 0); + void kill() { + _entity = kEntityPlayer; // no kActionEndSound notifications + close(); + } void setVolumeSmoothly(SoundFlag newVolume); // setVolumeSmoothly() treats kVolumeNone in a special way; // fade() terminates the stream after the transition @@ -110,18 +114,20 @@ public: void initDelayedActivate(unsigned activateDelay); // Subtitles - void showSubtitle(Common::String filename); + void setSubtitles(Common::String filename); // Serializable void saveLoadWithSerializer(Common::Serializer &ser); // Accessors - void addStatusFlag(SoundFlag flag) { _status |= flag; } void setEntity(EntityIndex entity) { _entity = entity; } + bool needSaving() const { + return (_name != "NISSND?" && (_status & kSoundTypeMask) != kSoundTypeMenu); + } uint32 getStatus() { return _status; } int32 getTag() { return _tag; } - uint32 getTime() { return _soundStream ? (_soundStream->getTimeMS() * 30 / 1000) : 0; } + uint32 getTime() { return _soundStream ? (_soundStream->getTimeMS() * 30 / 1000) + _startTime : 0; } EntityIndex getEntity() { return _entity; } uint32 getPriority() { return _priority; } const Common::String& getName(){ return _name; } @@ -138,9 +144,10 @@ private: uint32 _status; int32 _tag; // member of SoundTag for special sounds, unique value for normal sounds //byte *_bufferStart, *_bufferEnd, *_decodePointer, *_buffer, *_readPointer; - // the original game uses uint32 _blocksLeft, _time instead of _totalBlocks + // the original game uses uint32 _blocksLeft, _time instead of _blockCount // we ask the backend for sound time uint32 _blockCount; + uint32 _startTime; //uint32 _bufferSize; //union { uint32 _streamPos; enum StreamCloseReason _streamCloseReason; }; Common::SeekableReadStream *_stream; // The file stream diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index 3a10a7a89b..58b11f2402 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -79,8 +79,6 @@ void SoundQueue::stop(Common::String filename) { } void SoundQueue::updateQueue() { - ++_flag; - if (getAmbientState() & kAmbientSoundEnabled) { SoundEntry *entry = getEntry(kSoundTagAmbient); if (!entry || getFlags()->flag_3 || (entry && entry->getTime() > getSound()->getAmbientSoundDuration())) { @@ -100,32 +98,23 @@ void SoundQueue::updateQueue() { // 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 + // its priority and volume if (!entry->update() && !(entry->getStatus() & kSoundFlagKeepAfterFinish)) { entry->close(); SAFE_DELETE(entry); it = _soundList.reverse_erase(it); - continue; - } - - // When the entry has stopped playing, we remove his buffer - if (entry->isFinished()) { - entry->close(); - SAFE_DELETE(entry); - it = _soundList.reverse_erase(it); - continue; } } // Original update the current entry, loading another set of samples to be decoded getFlags()->flag_3 = false; - - --_flag; } void SoundQueue::stopAmbient() { + _ambientState = 0; + for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { if ((*i)->getTag() == kSoundTagAmbient) { (*i)->kill(); @@ -141,12 +130,12 @@ void SoundQueue::stopAmbient() { } } -void SoundQueue::stopAllExcept(SoundTag type1, SoundTag type2) { - if (!type2) - type2 = type1; +void SoundQueue::stopAllExcept(SoundTag tag1, SoundTag tag2) { + if (!tag2) + tag2 = tag1; for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->getTag() != type1 && (*i)->getTag() != type2) + if ((*i)->getTag() != tag1 && (*i)->getTag() != tag2) (*i)->kill(); } } @@ -160,7 +149,7 @@ void SoundQueue::destroyAllSound() { error("[SoundQueue::destroyAllSound] Invalid entry found in sound queue"); // Delete entry - entry->close(); + entry->kill(); SAFE_DELETE(entry); i = _soundList.reverse_erase(i); @@ -174,7 +163,7 @@ void SoundQueue::destroyAllSound() { ////////////////////////////////////////////////////////////////////////// void SoundQueue::stopAll() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->addStatusFlag(kSoundFlagClosed); + (*i)->close(); } ////////////////////////////////////////////////////////////////////////// @@ -194,8 +183,8 @@ void SoundQueue::fade(EntityIndex entity) { } } -void SoundQueue::fade(SoundTag type) { - SoundEntry *entry = getEntry(type); +void SoundQueue::fade(SoundTag tag) { + SoundEntry *entry = getEntry(tag); if (entry) entry->fade(); } @@ -236,9 +225,9 @@ SoundEntry *SoundQueue::getEntry(Common::String name) { return NULL; } -SoundEntry *SoundQueue::getEntry(SoundTag type) { +SoundEntry *SoundQueue::getEntry(SoundTag tag) { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->getTag() == type) + if ((*i)->getTag() == tag) return *i; } @@ -321,24 +310,22 @@ void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsUint32LE(_ambientState); s.syncAsUint32LE(_currentTag); - // Compute the number of entries to save - uint32 numEntries = count(); - s.syncAsUint32LE(numEntries); - // Save or load each entry data if (s.isSaving()) { + // Compute the number of entries to save + uint32 numEntries = count(); + s.syncAsUint32LE(numEntries); + for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->saveLoadWithSerializer(s); + if ((*i)->needSaving()) + (*i)->saveLoadWithSerializer(s); } else { - warning("[Sound::saveLoadWithSerializer] Loading not implemented"); - - uint32 unusedDataSize = numEntries * 64; - if (s.isLoading()) { - byte *empty = (byte *)malloc(unusedDataSize); - s.syncBytes(empty, unusedDataSize); - free(empty); - } else { - s.skip(unusedDataSize); + uint32 numEntries; + s.syncAsUint32LE(numEntries); + for (uint32 i = 0; i < numEntries; i++) { + SoundEntry* entry = new SoundEntry(_engine); + entry->saveLoadWithSerializer(s); + addToQueue(entry); } } } @@ -347,7 +334,7 @@ void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) { uint32 SoundQueue::count() { uint32 numEntries = 0; for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - if ((*i)->getName().matchString("NISSND?")) + if ((*i)->needSaving()) ++numEntries; return numEntries; diff --git a/engines/lastexpress/sound/queue.h b/engines/lastexpress/sound/queue.h index df8c945ee9..63ff091d80 100644 --- a/engines/lastexpress/sound/queue.h +++ b/engines/lastexpress/sound/queue.h @@ -46,7 +46,7 @@ public: void stop(EntityIndex entity); void updateQueue(); void stopAmbient(); - void stopAllExcept(SoundTag type1, SoundTag type2 = kSoundTagNone); + void stopAllExcept(SoundTag tag1, SoundTag tag2 = kSoundTagNone); void destroyAllSound(); // State @@ -58,10 +58,10 @@ public: // Entries void assignNISLink(EntityIndex index); void fade(EntityIndex entity); - void fade(SoundTag type); + void fade(SoundTag tag); void fade(Common::String filename); void endAmbient(); - SoundEntry *getEntry(SoundTag type); + SoundEntry *getEntry(SoundTag tag); SoundEntry *getEntry(EntityIndex index); SoundEntry *getEntry(Common::String name); uint32 getEntryTime(EntityIndex index); @@ -96,7 +96,6 @@ private: // State & shared data int _ambientState; int32 _currentTag; - // TODO: this seems to be a synchronization flag for the sound timer uint32 _flag; // Entries diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp index 597edd3b11..013a166ea8 100644 --- a/engines/lastexpress/sound/sound.cpp +++ b/engines/lastexpress/sound/sound.cpp @@ -137,7 +137,7 @@ void SoundManager::playSound(EntityIndex entity, Common::String filename, SoundF if (_queue->isBuffered(entity) && entity && entity < kEntityTrain) _queue->stop(entity); - SoundFlag currentFlag = (flag == kSoundVolumeEntityDefault) ? getSoundFlag(entity) : (SoundFlag)(flag | 0x80000); + SoundFlag currentFlag = (flag == kSoundVolumeEntityDefault) ? getSoundFlag(entity) : (SoundFlag)(flag | kSoundFlagFixedVolume); // Add .SND at the end of the filename if needed if (!filename.contains('.')) @@ -164,12 +164,6 @@ bool SoundManager::playSoundWithSubtitles(Common::String filename, uint32 flag, if (activateDelay) { entry->initDelayedActivate(activateDelay); } else { - // Get subtitles name - uint32 size = filename.size(); - while (filename.size() > size - 4) - filename.deleteLastChar(); - - entry->showSubtitle(filename); entry->play(); } @@ -323,7 +317,7 @@ void SoundManager::playSteam(CityIndex index) { // Get the new sound entry and show subtitles SoundEntry *entry = _queue->getEntry(kSoundTagAmbient); if (entry) - entry->showSubtitle(cities[index]); + entry->setSubtitles(cities[index]); } void SoundManager::playFightSound(byte action, byte a4) { |