diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 5ab65df5c6a..586326e9d07 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -808,18 +808,17 @@ void AdlibDriver::unkOutput2(uint8 chan) { // including the two most significant frequency bit, and the octave - // set to zero. // - // This is very strange behaviour, and appears to be the cause of the - // bug where low-frequent notes are played at the beginning of a new - // sound. However, this is what the original does, and the bug does not - // seem to happen with current versions of the FMOPL code. + // This is very strange behaviour, and causes problems with the ancient + // FMOPL code we borrowed from AdPlug. I've added a workaround. See + // fmopl.cpp for more details. // - // Unfortunately, we cannot use more recent versions because of license - // incompatibilities. + // More recent versions of the MAME FMOPL don't seem to have this + // problem, but cannot currently be used because of licensing and + // performance issues. // // Ken Silverman's Adlib emulator (which can be found on his Web page - // http://www.advsys.net/ken - and as part of AdPlug) also seems to be - // proof against this particular bug, but is apparently not as feature - // complete as MAME's. + // immune, but is apparently not as feature complete as MAME's. writeOPL(0xB0 + chan, 0x20); } diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp index e8f65833c90..acf17d396bb 100644 --- a/sound/fmopl.cpp +++ b/sound/fmopl.cpp @@ -304,12 +304,41 @@ inline void OPL_KEYON(OPL_SLOT *SLOT) { inline void OPL_KEYOFF(OPL_SLOT *SLOT) { if( SLOT->evm > ENV_MOD_RR) { /* set envelope counter from envleope output */ - SLOT->evm = ENV_MOD_RR; - if( !(SLOT->evc & EG_DST) ) + + // WORKAROUND: The Kyra engine does something very strange when + // starting a new song. For each channel: + // + // * The release rate is set to "fastest". + // * Any note is keyed off. + // * A very low-frequency note is keyed on. + // + // Usually, what happens next is that the real notes is keyed + // on immediately, in which case there's no problem. + // + // However, if the note is again keyed off (because the channel + // begins on a rest rather than a note), the envelope counter + // was moved from the very lowest point on the attack curve to + // the very highest point on the release curve. + // + // Again, this might not be a problem, if the release rate is + // still set to "fastest". But in many cases, it had already + // been increased. And, possibly because of inaccuracies in the + // envelope generator, that would cause the note to "fade out" + // for quite a long time. + // + // What we really need is a way to find the correct starting + // point for the envelope counter, and that may be what the + // commented-out line below is meant to do. For now, simply + // handle the pathological case. + + if (SLOT->evm == ENV_MOD_AR && SLOT->evc == EG_AST) + SLOT->evc = EG_DED; + else if( !(SLOT->evc & EG_DST) ) //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<evc = EG_DST; SLOT->eve = EG_DED; SLOT->evs = SLOT->evsr; + SLOT->evm = ENV_MOD_RR; } }