From 44dd6a386e9342e4088125fef680b1232da35692 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Thu, 3 Aug 2006 13:11:16 +0000 Subject: Committed my own patch #1533833 (minus one line that was left over from an earlier experimental version) after discussing it with LordHoto. This works around a bug in the "Pool of Sorrow" Adlib data which caused the channels to drift more and more out of sync for each time the music looped. The patch forces the channels involved to jump in sync. As with all such workarounds, it may cause regressions. But it shouldn't. svn-id: r23659 --- engines/kyra/sound_adlib.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 48945cab9c..786595061b 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -73,6 +73,8 @@ public: bool endOfData() const { return false; } int getRate() const { return _mixer->getOutputRate(); } + void setSyncJumpMask(uint16 mask) { _syncJumpMask = mask; } + private: struct OpcodeEntry { typedef int (AdlibDriver::*DriverOpcode)(va_list &list); @@ -127,6 +129,7 @@ private: // unk41 - Sound-effect. Used for primaryEffect2() struct Channel { + bool lock; // New to ScummVM uint8 opExtraLevel2; uint8 *dataptr; uint8 duration; @@ -378,6 +381,8 @@ private: static const uint8 _unkTable2_3[]; static const uint8 _unkTables[][32]; + uint16 _syncJumpMask; + Common::Mutex _mutex; Audio::Mixer *_mixer; @@ -421,6 +426,8 @@ AdlibDriver::AdlibDriver(Audio::Mixer *mixer) { _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; _samplesTillCallback = 0; _samplesTillCallbackRemainder = 0; + + _syncJumpMask = 0; } AdlibDriver::~AdlibDriver() { @@ -628,6 +635,11 @@ void AdlibDriver::setupPrograms() { unkOutput2(chan); } + // What we have set up now is, probably, the controlling + // channel for the sound. It is assumed that this program will + // set up all the other channels it needs, clearing their locks + // along the way. + ++_lastProcessed; _lastProcessed &= 0x0F; } @@ -670,7 +682,29 @@ void AdlibDriver::setupPrograms() { void AdlibDriver::executePrograms() { // Each channel runs its own program. There are ten channels: One for // each Adlib channel (0-8), plus one "control channel" (9) which is - // the one that tells the other channels what to do. + // the one that tells the other channels what to do. + + // This is where we ensure that channels that are made to jump "in + // sync" do so. + + if (_syncJumpMask) { + bool forceUnlock = true; + + for (_curChannel = 9; _curChannel >= 0; --_curChannel) { + if ((_syncJumpMask & (1 << _curChannel)) == 0) + continue; + + if (_channels[_curChannel].dataptr && !_channels[_curChannel].lock) { + forceUnlock = false; + } + } + + if (forceUnlock) { + for (_curChannel = 9; _curChannel >= 0; --_curChannel) + if (_syncJumpMask & (1 << _curChannel)) + _channels[_curChannel].lock = false; + } + } for (_curChannel = 9; _curChannel >= 0; --_curChannel) { int result = 1; @@ -678,6 +712,10 @@ void AdlibDriver::executePrograms() { if (!_channels[_curChannel].dataptr) { continue; } + + if (_channels[_curChannel].lock && (_syncJumpMask & (1 << _curChannel))) { + continue; + } Channel &channel = _channels[_curChannel]; _curRegOffset = _regOffset[_curChannel]; @@ -784,6 +822,7 @@ void AdlibDriver::initChannel(Channel &channel) { channel.primaryEffect = 0; channel.secondaryEffect = 0; channel.spacing1 = 1; + channel.lock = false; } void AdlibDriver::noteOff(Channel &channel) { @@ -1246,6 +1285,8 @@ int AdlibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; int16 add = READ_LE_UINT16(dataptr); dataptr += 2; dataptr += add; + if (_syncJumpMask & (1 << (&channel - _channels))) + channel.lock = true; return 0; } @@ -2195,8 +2236,18 @@ void SoundAdlibPC::loadMusicFile(const char *file) { } void SoundAdlibPC::playTrack(uint8 track) { - if (_musicEnabled) + if (_musicEnabled) { + // WORKAROUND: There is a bug in the Kyra 1 "Pool of Sorrow" + // music which causes the channels to get progressively out of + // sync for each loop. To avoid that, we declare that all four + // of the song channels have to jump "in sync". + + if (track == 4 && _soundFileLoaded == "KYRA1B") + _driver->setSyncJumpMask(0x000F); + else + _driver->setSyncJumpMask(0); play(track); + } } void SoundAdlibPC::haltTrack() { -- cgit v1.2.3