From 85e35943fe27b99a91d97eace3072117c2073f69 Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Wed, 7 Jun 2017 20:59:34 -0500 Subject: SCI32: Implement kLock & kDoAudio(1) for SCI32 1. Unlocking all resources of a type using a resource ID of -1 is gone in SCI32; 2. Audio locks need to be serialized starting in GK2 for the game's modified kDoAudio(1) call; 3. Audio locks in SCI3 must work more like SSCI, since at least Lighthouse's `BackMusic::fade` method will attempt to unlock audio that was never locked by a script. In SSCI (and now in ScummVM too) this is a no-op; previously in ScummVM, it would remove Audio32's own lock on the audio resource, resulting in a use-after-free; 4. kDoAudio(1) starting in GK2 returns the number of active *not-in-memory* channels being played, not the total number of active channels. Fixes Trac#9675. --- engines/sci/sound/audio32.cpp | 47 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'engines/sci/sound/audio32.cpp') diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp index b61bbd9a4e..f47002bb59 100644 --- a/engines/sci/sound/audio32.cpp +++ b/engines/sci/sound/audio32.cpp @@ -354,6 +354,20 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) { #pragma mark - #pragma mark Channel management +uint8 Audio32::getNumUnlockedChannels() const { + Common::StackLock lock(_mutex); + + uint8 numChannels = 0; + for (uint i = 0; i < _numActiveChannels; ++i) { + const AudioChannel &channel = getChannel(i); + if (!channel.robot && Common::find(_lockedResourceIds.begin(), _lockedResourceIds.end(), channel.id) == _lockedResourceIds.end()) { + ++numChannels; + } + } + + return numChannels; +} + int16 Audio32::findChannelByArgs(int argc, const reg_t *argv, const int startIndex, const reg_t soundNode) const { // NOTE: argc/argv are already reduced by one in our engine because // this call is always made from a subop, so no reduction for the @@ -420,6 +434,21 @@ int16 Audio32::findChannelById(const ResourceId resourceId, const reg_t soundNod return kNoExistingChannel; } +void Audio32::lockResource(const ResourceId resourceId, const bool lock) { + Common::StackLock slock(_mutex); + + LockList::iterator it = Common::find(_lockedResourceIds.begin(), _lockedResourceIds.end(), resourceId); + if (it != _lockedResourceIds.end()) { + if (!lock) { + _lockedResourceIds.erase(it); + } + } else { + if (lock) { + _lockedResourceIds.push_back(resourceId); + } + } +} + void Audio32::freeUnusedChannels() { Common::StackLock lock(_mutex); for (int channelIndex = 0; channelIndex < _numActiveChannels; ++channelIndex) { @@ -1037,10 +1066,6 @@ bool Audio32::hasSignal() const { reg_t Audio32::kernelPlay(const bool autoPlay, const int argc, const reg_t *const argv) { Common::StackLock lock(_mutex); - if (argc == 0) { - return make_reg(0, _numActiveChannels); - } - const int16 channelIndex = findChannelByArgs(argc, argv, 0, NULL_REG); ResourceId resourceId; bool loop; @@ -1214,6 +1239,20 @@ void Audio32::printAudioList(Console *con) const { channel.stopChannelOnFade ? ", stopping" : ""); } } + + if (g_sci->_features->hasSci3Audio()) { + con->debugPrintf("\nLocks: "); + if (_lockedResourceIds.size()) { + const char *separator = ""; + for (LockList::const_iterator it = _lockedResourceIds.begin(); it != _lockedResourceIds.end(); ++it) { + con->debugPrintf("%s%s", separator, it->toString().c_str()); + separator = ", "; + } + } else { + con->debugPrintf("none"); + } + con->debugPrintf("\n"); + } } } // End of namespace Sci -- cgit v1.2.3