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
This commit is contained in:
Torbjörn Andersson 2006-08-03 13:11:16 +00:00
parent d304e7b476
commit 44dd6a386e

View File

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