From e3aad13cd75e800e6890868c2a625da4cfd774d6 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 22 Jun 2014 16:51:27 +0200 Subject: SCUMM: Change channel/slot (re)allocation strategy in AD player. This makes sure that always the channel/slot with the lowest priority is reallocated in case none is free. This fixes some music oddities in Indy3. --- engines/scumm/players/player_ad.cpp | 67 ++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'engines/scumm') diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp index a8d9dbfc6a..ba75bdd922 100644 --- a/engines/scumm/players/player_ad.cpp +++ b/engines/scumm/players/player_ad.cpp @@ -302,37 +302,41 @@ void Player_AD::setupVolume() { } int Player_AD::allocateHWChannel(int priority, SfxSlot *owner) { - // First pass: Check whether there's any unallocated channel + // We always reaLlocate the channel with the lowest priority in case none + // is free. + int channel = -1; + int minPrio = priority; + for (int i = 0; i < _numHWChannels; ++i) { if (!_hwChannels[i].allocated) { - _hwChannels[i].allocated = true; - _hwChannels[i].priority = priority; - _hwChannels[i].sfxOwner = owner; - return i; + channel = i; + break; } - } - // Second pass: Reassign channels based on priority - for (int i = 0; i < _numHWChannels; ++i) { // We don't allow SFX to reallocate their own channels. Otherwise we // would call stopSfx in the midst of startSfx and that can lead to // horrible states... - if (_hwChannels[i].priority <= priority && (!owner || _hwChannels[i].sfxOwner != owner)) { - // In case the HW channel belongs to a SFX we will completely - // stop playback of that SFX. - // TODO: Maybe be more fine grained in the future and allow - // detachment of individual channels of a SFX? - if (_hwChannels[i].sfxOwner) { - stopSfx(_hwChannels[i].sfxOwner); - } - _hwChannels[i].allocated = true; - _hwChannels[i].priority = priority; - _hwChannels[i].sfxOwner = owner; - return i; + if (_hwChannels[i].priority <= minPrio && (!owner || _hwChannels[i].sfxOwner != owner)) { + minPrio = _hwChannels[i].priority; + channel = i; + } + } + + if (channel != -1) { + // In case the HW channel belongs to a SFX we will completely + // stop playback of that SFX. + // TODO: Maybe be more fine grained in the future and allow + // detachment of individual channels of a SFX? + if (_hwChannels[channel].allocated && _hwChannels[channel].sfxOwner) { + stopSfx(_hwChannels[channel].sfxOwner); } + + _hwChannels[channel].allocated = true; + _hwChannels[channel].priority = priority; + _hwChannels[channel].sfxOwner = owner; } - return -1; + return channel; } void Player_AD::freeHWChannel(int channel) { @@ -762,23 +766,26 @@ const uint Player_AD::_rhythmChannelTable[6] = { // SFX Player_AD::SfxSlot *Player_AD::allocateSfxSlot(int priority) { - // First pass: Check whether there's a unused slot + // We always reaLlocate the slot with the lowest priority in case none is + // free. + SfxSlot *sfx = nullptr; + int minPrio = priority; + for (int i = 0; i < ARRAYSIZE(_sfx); ++i) { if (_sfx[i].resource == -1) { return &_sfx[i]; + } else if (_sfx[i].priority <= minPrio) { + minPrio = _sfx[i].priority; + sfx = &_sfx[i]; } } - // Second pass: Look for a slot with lower priority - for (int i = 0; i < ARRAYSIZE(_sfx); ++i) { - if (_sfx[i].priority <= priority) { - // Stop the old sfx - stopSfx(&_sfx[i]); - return &_sfx[i]; - } + // In case we reallocate a slot stop the old one. + if (sfx) { + stopSfx(sfx); } - return nullptr; + return sfx; } bool Player_AD::startSfx(SfxSlot *sfx, const byte *resource) { -- cgit v1.2.3