aboutsummaryrefslogtreecommitdiff
path: root/engines/lastexpress/data
diff options
context:
space:
mode:
authorEvgeny Grechnikov2018-10-16 23:57:04 +0300
committerEvgeny Grechnikov2018-10-16 23:57:25 +0300
commitd561fd8a833e885e0d7d622c55f793569c1c1b74 (patch)
tree40702f83cdb39636f5554c49b45fb641d41e2f3f /engines/lastexpress/data
parent84f948de917a75d3f0f1c4a42155a24ed1d1ca07 (diff)
downloadscummvm-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.cpp85
-rw-r--r--engines/lastexpress/data/snd.h7
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;