diff options
-rw-r--r-- | engines/scumm/imuse/pcspk.cpp | 27 | ||||
-rw-r--r-- | engines/scumm/imuse/pcspk.h | 3 |
2 files changed, 29 insertions, 1 deletions
diff --git a/engines/scumm/imuse/pcspk.cpp b/engines/scumm/imuse/pcspk.cpp index ceecc3515e..6eaf7ad168 100644 --- a/engines/scumm/imuse/pcspk.cpp +++ b/engines/scumm/imuse/pcspk.cpp @@ -47,6 +47,12 @@ int PcSpkDriver::open() { _effectTimer = 0; _randBase = 1; + // We need to take care we only send note frequencies, when the internal + // settings actually changed, thus we need some extra state to keep track + // of that. + _lastActiveChannel = 0; + _lastActiveOut = 0; + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); return 0; } @@ -120,6 +126,8 @@ void PcSpkDriver::onTimer() { output((_activeChannel->_out.note << 7) + _activeChannel->_pitchBend + _activeChannel->_out.unk60 + _activeChannel->_out.unkE); } else { _pcSpk.stop(); + _lastActiveChannel = 0; + _lastActiveOut = 0; } } @@ -135,6 +143,8 @@ void PcSpkDriver::updateNote() { if (_activeChannel == 0 || _activeChannel->_tl == 0) { _pcSpk.stop(); + _lastActiveChannel = 0; + _lastActiveOut = 0; } else { output(_activeChannel->_pitchBend + (_activeChannel->_out.note << 7)); } @@ -147,7 +157,15 @@ void PcSpkDriver::output(uint16 out) { byte shift = _outputTable1[v1]; uint16 indexBase = _outputTable2[v1] << 5; uint16 frequency = _frequencyTable[(indexBase + v2) / 2] >> shift; - _pcSpk.play(Audio::PCSpeaker::kWaveFormSquare, 1193180 / frequency, -1); + + // Only output in case the active channel changed or the frequency changed. + // This is not faithful to the original. Since our timings differ we would + // get distorted sound otherwise though. + if (_lastActiveChannel != _activeChannel || _lastActiveOut != out) { + _pcSpk.play(Audio::PCSpeaker::kWaveFormSquare, 1193180 / frequency, -1); + _lastActiveChannel = _activeChannel; + _lastActiveOut = out; + } } void PcSpkDriver::MidiChannel_PcSpk::init(PcSpkDriver *owner, byte channel) { @@ -249,6 +267,13 @@ void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) { _out.unk60 = 0; _out.active = 1; + // In case we get a note on event on the last active channel, we reset the + // last active channel, thus we assure the frequency is correctly set, even + // when the same note was sent. + if (_owner->_lastActiveChannel == this) { + _owner->_lastActiveChannel = 0; + _owner->_lastActiveOut = 0; + } _owner->updateNote(); _out.unkC += PcSpkDriver::getEffectModifier(_instrument[3] + ((velocity & 0xFE) << 4)); diff --git a/engines/scumm/imuse/pcspk.h b/engines/scumm/imuse/pcspk.h index 3b63ec8199..3f70160988 100644 --- a/engines/scumm/imuse/pcspk.h +++ b/engines/scumm/imuse/pcspk.h @@ -145,6 +145,9 @@ private: MidiChannel_PcSpk _channels[6]; MidiChannel_PcSpk *_activeChannel; + MidiChannel_PcSpk *_lastActiveChannel; + uint16 _lastActiveOut; + static const byte _outInstrumentData[1024]; static const byte _outputTable1[]; static const byte _outputTable2[]; |