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) {  | 
