diff options
author | Torbjörn Andersson | 2012-11-18 14:30:17 +0100 |
---|---|---|
committer | Torbjörn Andersson | 2012-11-18 14:30:17 +0100 |
commit | 4f18a92f5a91eb502518846771bc8e82ff7da20a (patch) | |
tree | d1fedadd0e83ce1e6bf766967af799121ca9a2c5 /engines/scumm/player_v5m.cpp | |
parent | f3c9b218065357ef0178e4d68143deada86b6ed0 (diff) | |
download | scummvm-rg350-4f18a92f5a91eb502518846771bc8e82ff7da20a.tar.gz scummvm-rg350-4f18a92f5a91eb502518846771bc8e82ff7da20a.tar.bz2 scummvm-rg350-4f18a92f5a91eb502518846771bc8e82ff7da20a.zip |
SCUMM: Prevent music channels from drifting out of sync in Mac MI1
In looped music, prevent the music channels from drifting out of
sync over time. This was noticeable after a few minutes in the
SCUMM Bar. We do this by extending the last note (which is just
zeroes, so we didn't even use to play it) so that it has the
exact number of samples needed to make all channels the exact
same length. (This is calculated when the music is loaded, so it
does not need any extra data in the save games, thankfully.)
As a result, the getNextNote() is now responsible for converting
the duration to number of samples (out of necessity) and for
converting the note to a pitch modifier (out of symmetry). I made
several false starts before I realized how much easier it would
be this way.
Diffstat (limited to 'engines/scumm/player_v5m.cpp')
-rw-r--r-- | engines/scumm/player_v5m.cpp | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/engines/scumm/player_v5m.cpp b/engines/scumm/player_v5m.cpp index 20519097bd..d59cf9ade2 100644 --- a/engines/scumm/player_v5m.cpp +++ b/engines/scumm/player_v5m.cpp @@ -119,7 +119,7 @@ bool Player_V5M::loadMusic(const byte *ptr) { uint32 len = READ_BE_UINT32(ptr + 4); uint32 instrument = READ_BE_UINT32(ptr + 8); - _channel[i]._length = len - 24; + _channel[i]._length = len - 20; _channel[i]._data = ptr + 12; _channel[i]._looped = (READ_BE_UINT32(ptr + len - 8) == MKTAG('L', 'o', 'o', 'p')); _channel[i]._pos = 0; @@ -147,10 +147,30 @@ bool Player_V5M::loadMusic(const byte *ptr) { } resource.close(); + + // The last note of each channel is just zeroes. We will adjust this + // note so that all the channels end at the same time. + + uint32 samples[3]; + uint32 maxSamples = 0; + for (i = 0; i < 3; i++) { + samples[i] = 0; + for (uint j = 0; j < _channel[i]._length; j += 4) { + samples[i] += durationToSamples(READ_BE_UINT16(&_channel[i]._data[j])); + } + if (samples[i] > maxSamples) { + maxSamples = samples[i]; + } + } + + for (i = 0; i < 3; i++) { + _lastNoteSamples[i] = maxSamples - samples[i]; + } + return true; } -bool Player_V5M::getNextNote(int ch, uint16 &duration, byte ¬e, byte &velocity) { +bool Player_V5M::getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity) { _channel[ch]._instrument.newNote(); if (_channel[ch]._pos >= _channel[ch]._length) { if (!_channel[ch]._looped) { @@ -163,10 +183,16 @@ bool Player_V5M::getNextNote(int ch, uint16 &duration, byte ¬e, byte &velocit // MI1 Lookout music, where I was hearing problems. _channel[ch]._pos = 0; } - duration = READ_BE_UINT16(&_channel[ch]._data[_channel[ch]._pos]); - note = _channel[ch]._data[_channel[ch]._pos + 2]; + uint16 duration = READ_BE_UINT16(&_channel[ch]._data[_channel[ch]._pos]); + byte note = _channel[ch]._data[_channel[ch]._pos + 2]; + samples = durationToSamples(duration); + pitchModifier = noteToPitchModifier(note, &_channel[ch]._instrument); velocity = _channel[ch]._data[_channel[ch]._pos + 3]; _channel[ch]._pos += 4; + + if (_channel[ch]._pos >= _channel[ch]._length) { + samples = _lastNoteSamples[ch]; + } return true; } |