diff options
author | Evgeny Grechnikov | 2018-10-16 23:57:04 +0300 |
---|---|---|
committer | Evgeny Grechnikov | 2018-10-16 23:57:25 +0300 |
commit | d561fd8a833e885e0d7d622c55f793569c1c1b74 (patch) | |
tree | 40702f83cdb39636f5554c49b45fb641d41e2f3f /engines/lastexpress/data | |
parent | 84f948de917a75d3f0f1c4a42155a24ed1d1ca07 (diff) | |
download | scummvm-rg350-d561fd8a833e885e0d7d622c55f793569c1c1b74.tar.gz scummvm-rg350-d561fd8a833e885e0d7d622c55f793569c1c1b74.tar.bz2 scummvm-rg350-d561fd8a833e885e0d7d622c55f793569c1c1b74.zip |
LASTEXPRESS: dynamic adjusting of sound volume
Now it works just like in the original game,
including fading where it is applicable
(e.g. in a passengers list if closing the list while a sound is playing).
By the way, p2s sequence is known as http://oeis.org/A000265 ,
p1s is 4 - A007814, and p2s[i]/2**p1s[i] is just i/16.
It is time to get rid of these arrays.
Diffstat (limited to 'engines/lastexpress/data')
-rw-r--r-- | engines/lastexpress/data/snd.cpp | 85 | ||||
-rw-r--r-- | engines/lastexpress/data/snd.h | 7 |
2 files changed, 54 insertions, 38 deletions
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp index 4cff837193..7fb2c07706 100644 --- a/engines/lastexpress/data/snd.cpp +++ b/engines/lastexpress/data/snd.cpp @@ -342,9 +342,6 @@ static const int imaTable[1424] = { -20479, -28671, -32767, -32767, -32767, -32767 }; -static const int p1s[17] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4, 0 }; -static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1 }; - #pragma endregion // Last Express ADPCM is similar to MS IMA mono, but inverts its nibbles @@ -352,12 +349,13 @@ static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, class LastExpress_ADPCMStream : public Audio::ADPCMStream { public: - LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize, int32 filterId) : + LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize, uint32 volume) : Audio::ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) { - _currentFilterId = -1; - _nextFilterId = filterId; - _stepAdjust1 = 0; - _stepAdjust2 = 0; + _currentVolume = 0; + _nextVolume = volume; + _smoothChangeTarget = volume; + _volumeHoldBlocks = 0; + _running = true; } int readBuffer(int16 *buffer, const int numSamples) { @@ -369,24 +367,33 @@ public: assert(numSamples % 2 == 0); - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { + while (_running && samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { if (_blockPos[0] == _blockAlign) { // read block header _status.ima_ch[0].last = _stream->readSint16LE(); _status.ima_ch[0].stepIndex = _stream->readSint16LE() << 6; _blockPos[0] = 4; - // Get current filter - _currentFilterId = _nextFilterId; - //_nextFilterId = -1; // FIXME: the filter id should be recomputed based on the sound entry status for each block - - // No filter: skip decoding - if (_currentFilterId == -1) - break; - - // Compute step adjustment - _stepAdjust1 = p1s[_currentFilterId]; - _stepAdjust2 = p2s[_currentFilterId]; + // Smooth transition, if requested + // the original game clears kSoundFlagVolumeChanging here if _nextVolume == _smoothChangeTarget + if (_nextVolume != _smoothChangeTarget) { + if (_volumeHoldBlocks > 3) { + if (_nextVolume < _smoothChangeTarget) + ++_nextVolume; + else + --_nextVolume; + _volumeHoldBlocks = 0; + if (_nextVolume == 0) { + _running = false; + break; + } + } else { + _volumeHoldBlocks++; + } + } + + // Get current volume + _currentVolume = _nextVolume; } for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { @@ -397,26 +404,28 @@ public: idx = data >> 4; step = stepTable[idx + _status.ima_ch[0].stepIndex / 4]; sample = CLIP<int>(imaTable[idx + _status.ima_ch[0].stepIndex / 4] + _status.ima_ch[0].last, -32767, 32767); - buffer[samples] = (_stepAdjust2 * sample) >> _stepAdjust1; + buffer[samples] = (sample * _currentVolume) >> 4; // Second nibble idx = data & 0xF; _status.ima_ch[0].stepIndex = stepTable[idx + step / 4]; _status.ima_ch[0].last = CLIP(imaTable[idx + step / 4] + sample, -32767, 32767); - buffer[samples + 1] = (_stepAdjust2 * _status.ima_ch[0].last) >> _stepAdjust1; + buffer[samples + 1] = (_status.ima_ch[0].last * _currentVolume) >> 4; } } return samples; } - void setFilterId(int32 filterId) { _nextFilterId = filterId; } + void setVolume(uint32 newVolume) { _smoothChangeTarget = _nextVolume = newVolume; } + void setVolumeSmoothly(uint32 newVolume) { _smoothChangeTarget = newVolume; } private: - int32 _currentFilterId; - int32 _nextFilterId; // the sound filter id, -1 for none - int32 _stepAdjust1; - int32 _stepAdjust2; + uint32 _currentVolume; + uint32 _nextVolume; + uint32 _smoothChangeTarget; + uint32 _volumeHoldBlocks; // smooth change of volume keeps volume on hold for 4 blocks = 133ms for every value; this is the counter + bool _running; }; ////////////////////////////////////////////////////////////////////////// @@ -442,8 +451,8 @@ void SimpleSound::loadHeader(Common::SeekableReadStream *in) { _blockSize = _size / _blocks; } -LastExpress_ADPCMStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId) const { - return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize, filterId); +LastExpress_ADPCMStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, uint32 volume) const { + return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize, volume); } void SimpleSound::play(Audio::AudioStream *as, DisposeAfterUse::Flag autofreeStream) { @@ -461,7 +470,7 @@ StreamedSound::~StreamedSound() { _as = NULL; } -bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) { +bool StreamedSound::load(Common::SeekableReadStream *stream, uint32 volume) { if (!stream) return false; @@ -474,7 +483,7 @@ bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) { delete _as; } // Start decoding the input stream - _as = makeDecoder(stream, _size, filterId); + _as = makeDecoder(stream, _size, volume); // Start playing the decoded audio stream play(_as, DisposeAfterUse::NO); @@ -491,11 +500,18 @@ bool StreamedSound::isFinished() { return !g_system->getMixer()->isSoundHandleActive(_handle); } -void StreamedSound::setFilterId(int32 filterId) { +void StreamedSound::setVolume(uint32 newVolume) { + if (!_as) + return; + + _as->setVolume(newVolume); +} + +void StreamedSound::setVolumeSmoothly(uint32 newVolume) { if (!_as) return; - _as->setFilterId(filterId); + _as->setVolumeSmoothly(newVolume); } ////////////////////////////////////////////////////////////////////////// @@ -531,8 +547,7 @@ void AppendableSound::queueBuffer(Common::SeekableReadStream *bufferIn) { // Setup the ADPCM decoder uint32 sizeIn = (uint32)bufferIn->size(); - LastExpress_ADPCMStream *adpcm = makeDecoder(bufferIn, sizeIn); - adpcm->setFilterId(16); + LastExpress_ADPCMStream *adpcm = makeDecoder(bufferIn, sizeIn, kVolumeFull); // Queue the stream _as->queueAudioStream(adpcm); diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h index 23aae905ac..f6f2c5ec04 100644 --- a/engines/lastexpress/data/snd.h +++ b/engines/lastexpress/data/snd.h @@ -61,7 +61,7 @@ public: protected: void loadHeader(Common::SeekableReadStream *in); - LastExpress_ADPCMStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId = -1) const; + LastExpress_ADPCMStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, uint32 volume) const; void play(Audio::AudioStream *as, DisposeAfterUse::Flag autofreeStream); uint32 _size; ///< data size @@ -78,10 +78,11 @@ public: StreamedSound(); ~StreamedSound(); - bool load(Common::SeekableReadStream *stream, int32 filterId = -1); + bool load(Common::SeekableReadStream *stream, uint32 volume); virtual bool isFinished(); - void setFilterId(int32 filterId); + void setVolume(uint32 newVolume); + void setVolumeSmoothly(uint32 newVolume); private: LastExpress_ADPCMStream *_as; |