diff options
-rw-r--r-- | engines/sci/sound/audio32.cpp | 109 | ||||
-rw-r--r-- | engines/sci/sound/audio32.h | 12 |
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. */ |