aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2017-06-16 17:03:37 -0500
committerColin Snover2017-06-18 21:41:48 -0500
commitdc9522eae09ea740a5b1458dc1f6ffeff4032532 (patch)
treed929795f2e159d7ad0f652553ef07d7b0b132d87
parenteb68a94527314919d71289ccc07e651e18ddca98 (diff)
downloadscummvm-rg350-dc9522eae09ea740a5b1458dc1f6ffeff4032532.tar.gz
scummvm-rg350-dc9522eae09ea740a5b1458dc1f6ffeff4032532.tar.bz2
scummvm-rg350-dc9522eae09ea740a5b1458dc1f6ffeff4032532.zip
SCI32: Fix Audio32 mix volumes
The previous code for attenuating audio channels was not accurate, so samples were quieter than they were supposed to be when mixed together. Robots were also being mixed without attenuation, which was incorrect.
-rw-r--r--engines/sci/sound/audio32.cpp109
-rw-r--r--engines/sci/sound/audio32.h12
2 files changed, 79 insertions, 42 deletions
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index f47002bb59..753d7d4bbb 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -175,6 +175,35 @@ int Audio32::writeAudioInternal(Audio::AudioStream *const sourceStream, Audio::R
return samplesWritten;
}
+int16 Audio32::getNumChannelsToMix() const {
+ Common::StackLock lock(_mutex);
+ int16 numChannels = 0;
+ for (int16 channelIndex = 0; channelIndex < _numActiveChannels; ++channelIndex) {
+ const AudioChannel &channel = getChannel(channelIndex);
+ if (channelShouldMix(channel)) {
+ ++numChannels;
+ }
+ }
+ return numChannels;
+}
+
+bool Audio32::channelShouldMix(const AudioChannel &channel) const {
+ if (channel.pausedAtTick ||
+ (channel.robot && (_robotAudioPaused || channel.stream->endOfStream()))) {
+
+ return false;
+ }
+
+ if (channel.fadeStartTick) {
+ const uint32 fadeElapsed = g_sci->getTickCount() - channel.fadeStartTick;
+ if (fadeElapsed > channel.fadeDuration && channel.stopChannelOnFade) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
// In earlier versions of SCI32 engine, audio mixing is
// split into three different functions.
//
@@ -227,50 +256,52 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
// callback.
memset(buffer, 0, numSamples * sizeof(Audio::st_sample_t));
- // This emulates the attenuated mixing mode of SSCI
- // engine, which reduces the volume of the target
- // buffer when each new channel is mixed in.
- // Instead of manipulating the content of the target
- // buffer when mixing (which would either require
- // modification of RateConverter or an expensive second
- // pass against the entire target buffer), we just
- // scale the volume for each channel in advance, with
- // the earliest (lowest) channel having the highest
- // amount of attenuation (lowest volume).
- uint8 attenuationAmount;
- uint8 attenuationStepAmount;
+ // This emulates the attenuated mixing mode of SSCI engine, which reduces
+ // the volume of the target buffer when each new channel is mixed in.
+ // Instead of manipulating the content of the target buffer when mixing
+ // (which would either require modification of RateConverter or an expensive
+ // second pass against the entire target buffer), we just scale the volume
+ // for each channel in advance, with the earliest (lowest) channel having
+ // the highest amount of attenuation (lowest volume).
+ int8 attenuationAmount;
+ int8 attenuationStepAmount;
if (_useModifiedAttenuation) {
- // channel | divisor
- // 0 | 0 (>> 0)
- // 1 | 4 (>> 2)
- // 2 | 8...
- attenuationAmount = _numActiveChannels * 2;
+ // Divides samples in target buffer by 4, and samples in source buffer
+ // by 0, when adding each channel to the output buffer.
+ // 1 channel: 0 >>0
+ // 2 channels: 0 >>2, 1 >>0
+ // 3 channels: 0 >>4, 1 >>2, 2 >>0
+ // 4 channels: 0 >>6, 1 >>4, 2 >>2, 3 >>0 ...
+ // Attenuation amounts are shift values.
+ attenuationAmount = (getNumChannelsToMix() - 1) * 2;
attenuationStepAmount = 2;
} else {
- // channel | divisor
- // 0 | 2 (>> 1)
- // 1 | 4 (>> 2)
- // 2 | 6...
- if (!playOnlyMonitoredChannel && _numActiveChannels > 1) {
- attenuationAmount = _numActiveChannels + 1;
- attenuationStepAmount = 1;
- } else {
- attenuationAmount = 0;
- attenuationStepAmount = 0;
- }
+ // Divides samples in both target & source buffers by 2 when adding each
+ // channel to the output buffer.
+ // 1 channel: 0 >>0
+ // 2 channels: 0 >>1, 1 >>1
+ // 3 channels: 0 >>2, 1 >>2, 2 >>1
+ // 4 channels: 0 >>3, 1 >>3, 2 >>2, 3 >>1 ...
+ // Attenuation amounts are shift values.
+ attenuationAmount = getNumChannelsToMix() - 1;
+ attenuationStepAmount = 1;
}
int maxSamplesWritten = 0;
+ bool firstChannelWritten = false;
for (int16 channelIndex = 0; channelIndex < _numActiveChannels; ++channelIndex) {
- attenuationAmount -= attenuationStepAmount;
-
const AudioChannel &channel = getChannel(channelIndex);
if (channel.pausedAtTick || (channel.robot && _robotAudioPaused)) {
continue;
}
+ if (channel.robot && channel.stream->endOfStream()) {
+ stop(channelIndex--);
+ continue;
+ }
+
// Channel finished fading and had the
// stopChannelOnFade flag set, so no longer exists
if (channel.fadeStartTick && processFade(channelIndex)) {
@@ -278,18 +309,6 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
continue;
}
- if (channel.robot) {
- if (channel.stream->endOfStream()) {
- stop(channelIndex--);
- } else {
- const int channelSamplesWritten = writeAudioInternal(channel.stream, channel.converter, buffer, numSamples, kMaxVolume, kMaxVolume, channel.loop);
- if (channelSamplesWritten > maxSamplesWritten) {
- maxSamplesWritten = channelSamplesWritten;
- }
- }
- continue;
- }
-
Audio::st_volume_t leftVolume, rightVolume;
if (channel.pan == -1 || !isStereo()) {
@@ -303,8 +322,14 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
}
if (!playOnlyMonitoredChannel && _attenuatedMixing) {
+ assert(attenuationAmount >= 0);
leftVolume >>= attenuationAmount;
rightVolume >>= attenuationAmount;
+ if (!_useModifiedAttenuation && !firstChannelWritten) {
+ firstChannelWritten = true;
+ } else {
+ attenuationAmount -= attenuationStepAmount;
+ }
}
if (channelIndex == _monitoredChannelIndex) {
diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h
index 27f7e8f3a1..510fbc1605 100644
--- a/engines/sci/sound/audio32.h
+++ b/engines/sci/sound/audio32.h
@@ -190,6 +190,18 @@ public:
private:
/**
+ * Determines the number of channels that will be mixed together during a
+ * call to readBuffer.
+ */
+ int16 getNumChannelsToMix() const;
+
+ /**
+ * Determines whether or not the given audio channel will be mixed into the
+ * output stream.
+ */
+ bool channelShouldMix(const AudioChannel &channel) const;
+
+ /**
* Mixes audio from the given source stream into the
* target buffer using the given rate converter.
*/