[Scummvm-git-logs] scummvm master -> 85befa9c13c0cf953e63f79e67b605a00d5e8fa4
sev-
noreply at scummvm.org
Sun Jun 21 13:17:43 UTC 2026
This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
ccbcb756b0 AUDIO: Fix constness
acab1a9175 AUDIO: Input stream always works with int16
d440280f0e SCI32: Don't use Audio::st_sample_t for AudioStream instances
a6d828135f AUDIO: Add support for 32-bit sample size
b9cca6360e AUDIO: RateConverter now supports unclamped mixing
424681dca2 AUDIO: Make sample clamping optional
995c360cfc AUDIO: Don't clamp muted channels
85befa9c13 AUDIO: Template-optimize convert methods
Commit: ccbcb756b0e98088d456843186175015704f28f7
https://github.com/scummvm/scummvm/commit/ccbcb756b0e98088d456843186175015704f28f7
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Fix constness
Changed paths:
audio/mixer.cpp
audio/mixer.h
audio/mixer_intern.h
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 4791628bbac..51ea508d56f 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -98,7 +98,7 @@ public:
*
* @return volume
*/
- byte getVolume();
+ byte getVolume() const;
/**
* Sets the channel's balance setting.
@@ -112,7 +112,7 @@ public:
*
* @return balance
*/
- int8 getBalance();
+ int8 getBalance() const;
/**
* Sets the channel's left fader level.
@@ -126,7 +126,7 @@ public:
*
* @return The channel's left fader level.
*/
- uint8 getFaderL();
+ uint8 getFaderL() const;
/**
* Sets the channel's right fader level.
@@ -140,7 +140,7 @@ public:
*
* @return The channel's right fader level.
*/
- uint8 getFaderR();
+ uint8 getFaderR() const;
/**
* Set the channel's sample rate.
@@ -154,7 +154,7 @@ public:
*
* @return The current sample rate of the channel.
*/
- uint32 getRate();
+ uint32 getRate() const;
/**
* Reset the sample rate of the channel back to its
@@ -171,7 +171,7 @@ public:
/**
* Queries how long the channel has been playing.
*/
- Timestamp getElapsedTime();
+ Timestamp getElapsedTime() const;
/**
* Replaces the channel's stream with a version that loops indefinitely.
@@ -425,7 +425,7 @@ void MixerImpl::setChannelVolume(SoundHandle handle, byte volume) {
_channels[index]->setVolume(volume);
}
-byte MixerImpl::getChannelVolume(SoundHandle handle) {
+byte MixerImpl::getChannelVolume(SoundHandle handle) const {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
@@ -443,7 +443,7 @@ void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) {
_channels[index]->setBalance(balance);
}
-int8 MixerImpl::getChannelBalance(SoundHandle handle) {
+int8 MixerImpl::getChannelBalance(SoundHandle handle) const {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
@@ -461,7 +461,7 @@ void MixerImpl::setChannelFaderL(SoundHandle handle, uint8 faderL) {
_channels[index]->setFaderL(faderL);
}
-uint8 MixerImpl::getChannelFaderL(SoundHandle handle) {
+uint8 MixerImpl::getChannelFaderL(SoundHandle handle) const {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
@@ -479,7 +479,7 @@ void MixerImpl::setChannelFaderR(SoundHandle handle, uint8 faderR) {
_channels[index]->setFaderR(faderR);
}
-uint8 MixerImpl::getChannelFaderR(SoundHandle handle) {
+uint8 MixerImpl::getChannelFaderR(SoundHandle handle) const {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
@@ -497,7 +497,7 @@ void MixerImpl::setChannelRate(SoundHandle handle, uint32 rate) {
_channels[index]->setRate(rate);
}
-uint32 MixerImpl::getChannelRate(SoundHandle handle) {
+uint32 MixerImpl::getChannelRate(SoundHandle handle) const {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
@@ -515,11 +515,11 @@ void MixerImpl::resetChannelRate(SoundHandle handle) {
_channels[index]->resetRate();
}
-uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) {
+uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) const {
return getElapsedTime(handle).msecs();
}
-Timestamp MixerImpl::getElapsedTime(SoundHandle handle) {
+Timestamp MixerImpl::getElapsedTime(SoundHandle handle) const {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
@@ -569,7 +569,7 @@ void MixerImpl::pauseHandle(SoundHandle handle, bool paused) {
_channels[index]->pause(paused);
}
-bool MixerImpl::isSoundIDActive(int id) {
+bool MixerImpl::isSoundIDActive(int id) const {
Common::StackLock lock(_mutex);
#ifdef ENABLE_EVENTRECORDER
@@ -582,7 +582,7 @@ bool MixerImpl::isSoundIDActive(int id) {
return false;
}
-int MixerImpl::getSoundID(SoundHandle handle) {
+int MixerImpl::getSoundID(SoundHandle handle) const {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
if (_channels[index] && _channels[index]->getHandle()._val == handle._val)
@@ -590,7 +590,7 @@ int MixerImpl::getSoundID(SoundHandle handle) {
return 0;
}
-bool MixerImpl::isSoundHandleActive(SoundHandle handle) {
+bool MixerImpl::isSoundHandleActive(SoundHandle handle) const {
Common::StackLock lock(_mutex);
#ifdef ENABLE_EVENTRECORDER
@@ -601,7 +601,7 @@ bool MixerImpl::isSoundHandleActive(SoundHandle handle) {
return _channels[index] && _channels[index]->getHandle()._val == handle._val;
}
-bool MixerImpl::hasActiveChannelOfType(SoundType type) {
+bool MixerImpl::hasActiveChannelOfType(SoundType type) const {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++)
if (_channels[i] && _channels[i]->getType() == type)
@@ -660,7 +660,7 @@ void Channel::setVolume(const byte volume) {
updateChannelVolumes();
}
-byte Channel::getVolume() {
+byte Channel::getVolume() const {
return _volume;
}
@@ -669,7 +669,7 @@ void Channel::setBalance(const int8 balance) {
updateChannelVolumes();
}
-int8 Channel::getBalance() {
+int8 Channel::getBalance() const {
return _balance;
}
@@ -678,7 +678,7 @@ void Channel::setFaderL(uint8 faderL) {
updateChannelVolumes();
}
-uint8 Channel::getFaderL() {
+uint8 Channel::getFaderL() const {
return _faderL;
}
@@ -687,7 +687,7 @@ void Channel::setFaderR(uint8 faderR) {
updateChannelVolumes();
}
-uint8 Channel::getFaderR() {
+uint8 Channel::getFaderR() const {
return _faderR;
}
@@ -696,7 +696,7 @@ void Channel::setRate(uint32 rate) {
_converter->setInputRate(rate);
}
-uint32 Channel::getRate() {
+uint32 Channel::getRate() const {
if (_converter)
return _converter->getInputRate();
@@ -756,7 +756,7 @@ void Channel::pause(bool paused) {
}
}
-Timestamp Channel::getElapsedTime() {
+Timestamp Channel::getElapsedTime() const {
const uint32 rate = _mixer->getOutputRate();
uint32 delta = 0;
diff --git a/audio/mixer.h b/audio/mixer.h
index 4e34879c23a..2c6c35f07b2 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -192,7 +192,7 @@ public:
*
* @return True if the sound is active.
*/
- virtual bool isSoundIDActive(int id) = 0;
+ virtual bool isSoundIDActive(int id) const = 0;
/**
* Get the sound ID for the given handle.
@@ -201,7 +201,7 @@ public:
*
* @return Sound ID if the sound is active.
*/
- virtual int getSoundID(SoundHandle handle) = 0;
+ virtual int getSoundID(SoundHandle handle) const = 0;
/**
* Check whether a sound with the given handle is active.
@@ -210,7 +210,7 @@ public:
*
* @return True if the sound is active.
*/
- virtual bool isSoundHandleActive(SoundHandle handle) = 0;
+ virtual bool isSoundHandleActive(SoundHandle handle) const = 0;
/**
@@ -243,7 +243,7 @@ public:
*
* @return The channel volume.
*/
- virtual byte getChannelVolume(SoundHandle handle) = 0;
+ virtual byte getChannelVolume(SoundHandle handle) const = 0;
/**
* Set the channel balance for the given handle.
@@ -261,7 +261,7 @@ public:
*
* @return The channel balance.
*/
- virtual int8 getChannelBalance(SoundHandle handle) = 0;
+ virtual int8 getChannelBalance(SoundHandle handle) const = 0;
/**
* Set the channel's left fader level for the given handle.
@@ -278,7 +278,7 @@ public:
*
* @return The channel's left fader level.
*/
- virtual uint8 getChannelFaderL(SoundHandle handle) = 0;
+ virtual uint8 getChannelFaderL(SoundHandle handle) const = 0;
/**
* Set the channel's right fader level for the given handle.
@@ -295,7 +295,7 @@ public:
*
* @return The channel's right fader level.
*/
- virtual uint8 getChannelFaderR(SoundHandle handle) = 0;
+ virtual uint8 getChannelFaderR(SoundHandle handle) const = 0;
/**
* Set the sample rate for the given handle.
@@ -312,7 +312,7 @@ public:
*
* @return The current sample rate of the channel.
*/
- virtual uint32 getChannelRate(SoundHandle handle) = 0;
+ virtual uint32 getChannelRate(SoundHandle handle) const = 0;
/**
* Reset the sample rate of the channel back to its
@@ -325,12 +325,12 @@ public:
/**
* Get an approximation of for how long the channel has been playing.
*/
- virtual uint32 getSoundElapsedTime(SoundHandle handle) = 0;
+ virtual uint32 getSoundElapsedTime(SoundHandle handle) const = 0;
/**
* Get an approximation of for how long the channel has been playing.
*/
- virtual Timestamp getElapsedTime(SoundHandle handle) = 0;
+ virtual Timestamp getElapsedTime(SoundHandle handle) const = 0;
/**
* Replace the channel's stream with a version that loops indefinitely.
@@ -347,7 +347,7 @@ public:
*
* @return True if any channels of the specified type are active.
*/
- virtual bool hasActiveChannelOfType(SoundType type) = 0;
+ virtual bool hasActiveChannelOfType(SoundType type) const = 0;
/**
* Set the volume for the given sound type.
diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h
index 409315c3c6f..c46a43825ac 100644
--- a/audio/mixer_intern.h
+++ b/audio/mixer_intern.h
@@ -106,32 +106,32 @@ public:
void pauseID(int id, bool paused) override;
void pauseHandle(SoundHandle handle, bool paused) override;
- bool isSoundIDActive(int id) override;
- int getSoundID(SoundHandle handle) override;
+ bool isSoundIDActive(int id) const override;
+ int getSoundID(SoundHandle handle) const override;
- bool isSoundHandleActive(SoundHandle handle) override;
+ bool isSoundHandleActive(SoundHandle handle) const override;
void muteSoundType(SoundType type, bool mute) override;
bool isSoundTypeMuted(SoundType type) const override;
void setChannelVolume(SoundHandle handle, byte volume) override;
- byte getChannelVolume(SoundHandle handle) override;
+ byte getChannelVolume(SoundHandle handle) const override;
void setChannelBalance(SoundHandle handle, int8 balance) override;
- int8 getChannelBalance(SoundHandle handle) override;
+ int8 getChannelBalance(SoundHandle handle) const override;
void setChannelFaderL(SoundHandle handle, uint8 scaleL) override;
- uint8 getChannelFaderL(SoundHandle handle) override;
+ uint8 getChannelFaderL(SoundHandle handle) const override;
void setChannelFaderR(SoundHandle handle, uint8 scaleR) override;
- uint8 getChannelFaderR(SoundHandle handle) override;
+ uint8 getChannelFaderR(SoundHandle handle) const override;
void setChannelRate(SoundHandle handle, uint32 rate) override;
- uint32 getChannelRate(SoundHandle handle) override;
+ uint32 getChannelRate(SoundHandle handle) const override;
void resetChannelRate(SoundHandle handle) override;
- uint32 getSoundElapsedTime(SoundHandle handle) override;
- Timestamp getElapsedTime(SoundHandle handle) override;
+ uint32 getSoundElapsedTime(SoundHandle handle) const override;
+ Timestamp getElapsedTime(SoundHandle handle) const override;
void loopChannel(SoundHandle handle) override;
- bool hasActiveChannelOfType(SoundType type) override;
+ bool hasActiveChannelOfType(SoundType type) const override;
void setVolumeForSoundType(SoundType type, int volume) override;
int getVolumeForSoundType(SoundType type) const override;
Commit: acab1a917526161c6bb2780ea62a9289f7c32be7
https://github.com/scummvm/scummvm/commit/acab1a917526161c6bb2780ea62a9289f7c32be7
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Input stream always works with int16
So make it explicit in code.
Changed paths:
audio/rate.cpp
diff --git a/audio/rate.cpp b/audio/rate.cpp
index 4638f827270..9ae4d3eb3cf 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -60,10 +60,10 @@ private:
* but only until some point (depends largely on cache size, target
* processor and various other factors), at which it will decrease again.
*/
- st_sample_t _buffer[512];
+ int16 _buffer[512];
/** Current position inside the buffer */
- const st_sample_t *_bufferPos;
+ const int16 *_bufferPos;
/** Size of data currently loaded into the buffer */
int _bufferSize;
@@ -75,10 +75,10 @@ private:
frac_t _outPosFrac;
/** Last sample(s) in the input stream (left/right channel) */
- st_sample_t _inLastL, _inLastR;
-
+ int16 _inLastL, _inLastR;
+
/** Current sample(s) in the input stream (left/right channel) */
- st_sample_t _inCurL, _inCurR;
+ int16 _inCurL, _inCurR;
int copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
int simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
@@ -141,7 +141,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStr
}
// Mix the data into the output buffer
- st_sample_t inL, inR;
+ int16 inL, inR;
inL = *_bufferPos++;
inR = (inStereo ? *_bufferPos++ : inL);
_bufferSize -= (inStereo ? 2 : 1);
@@ -201,7 +201,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioS
}
} while (_outPos >= 0);
- st_sample_t inL, inR;
+ int16 inL, inR;
inL = *_bufferPos++;
inR = (inStereo ? *_bufferPos++ : inL);
@@ -269,10 +269,10 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(A
// still space in the output buffer.
while (_outPosFrac < (frac_t)FRAC_ONE_LOW && outBuffer < outEnd) {
// Interpolate
- st_sample_t inL, inR;
- inL = (st_sample_t)(_inLastL + (((_inCurL - _inLastL) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
+ int16 inL, inR;
+ inL = (int16)(_inLastL + (((_inCurL - _inLastL) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
inR = (inStereo ?
- (st_sample_t)(_inLastR + (((_inCurR - _inLastR) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
+ (int16)(_inLastR + (((_inCurR - _inLastR) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
inL);
st_sample_t outL, outR;
Commit: d440280f0ef0c5ae13d5cf6d0654ab7601b138e9
https://github.com/scummvm/scummvm/commit/d440280f0ef0c5ae13d5cf6d0654ab7601b138e9
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
SCI32: Don't use Audio::st_sample_t for AudioStream instances
AudioStream always works with int16 so make it explicit. The only
exception here is Audio32::writeAudioInternal() where the targetBuffer
actually is expected to be of type Audio::st_sample_t but that is just
Audio32 class taking advantage of an existing converter. It could easily
take byte or void pointer as input.
Changed paths:
engines/sci/sound/audio32.cpp
engines/sci/sound/audio32.h
engines/sci/video/robot_decoder.cpp
engines/sci/video/robot_decoder.h
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index b81df60a01f..0b21070ec7c 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -232,7 +232,7 @@ Audio32::~Audio32() {
#pragma mark -
#pragma mark AudioStream implementation
-int Audio32::writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, Audio::st_sample_t *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume) {
+int Audio32::writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, int16 *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume) {
const int samplePairsToRead = numSamples >> 1;
const int samplePairsWritten = converter.convert(sourceStream, targetBuffer, samplePairsToRead, leftVolume, rightVolume);
return samplePairsWritten << 1;
@@ -289,7 +289,7 @@ bool Audio32::channelShouldMix(const AudioChannel &channel) const {
// do all audio processing in real time, and we have streams, and we do not need
// to completely fill the audio buffer, the functionality of all these original
// functions is combined here and simplified.
-int Audio32::readBuffer(Audio::st_sample_t *const buffer, const int numSamples) {
+int Audio32::readBuffer(int16 *const buffer, const int numSamples) {
Common::StackLock lock(_mutex);
if (_pausedAtTick != 0 || _numActiveChannels == 0) {
@@ -307,7 +307,7 @@ int Audio32::readBuffer(Audio::st_sample_t *const buffer, const int numSamples)
// The caller of `readBuffer` is a rate converter, which reuses (without
// clearing) an intermediate buffer, so we need to zero the intermediate
// buffer to prevent mixing into audio data from the last callback.
- memset(buffer, 0, numSamples * sizeof(Audio::st_sample_t));
+ memset(buffer, 0, numSamples * sizeof(int16));
// This emulates the attenuated mixing mode of SSCI engine, which reduces
// the volume of the target buffer when each new channel is mixed in.
@@ -413,12 +413,12 @@ int Audio32::readBuffer(Audio::st_sample_t *const buffer, const int numSamples)
if (numSamples > (int)_monitoredBuffer.size()) {
_monitoredBuffer.resize(numSamples);
}
- memset(_monitoredBuffer.data(), 0, _monitoredBuffer.size() * sizeof(Audio::st_sample_t));
+ memset(_monitoredBuffer.data(), 0, _monitoredBuffer.size() * sizeof(int16));
_numMonitoredSamples = writeAudioInternal(*channel.stream, *channel.converter, _monitoredBuffer.data(), numSamples, leftVolume, rightVolume);
- Audio::st_sample_t *sourceBuffer = _monitoredBuffer.data();
- Audio::st_sample_t *targetBuffer = buffer;
- const Audio::st_sample_t *const end = _monitoredBuffer.data() + _numMonitoredSamples;
+ int16 *sourceBuffer = _monitoredBuffer.data();
+ int16 *targetBuffer = buffer;
+ const int16 *const end = _monitoredBuffer.data() + _numMonitoredSamples;
while (sourceBuffer != end) {
Audio::clampedAdd(*targetBuffer++, *sourceBuffer++);
}
@@ -1203,11 +1203,11 @@ bool Audio32::hasSignal() const {
return false;
}
- const Audio::st_sample_t *buffer = _monitoredBuffer.data();
- const Audio::st_sample_t *const end = _monitoredBuffer.data() + _numMonitoredSamples;
+ const int16 *buffer = _monitoredBuffer.data();
+ const int16 *const end = _monitoredBuffer.data() + _numMonitoredSamples;
while (buffer != end) {
- const Audio::st_sample_t sample = *buffer++;
+ const int16 sample = *buffer++;
if (sample > 1280 || sample < -1280) {
return true;
}
diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h
index cfa8691d027..ee095294dea 100644
--- a/engines/sci/sound/audio32.h
+++ b/engines/sci/sound/audio32.h
@@ -196,7 +196,7 @@ private:
#pragma mark -
#pragma mark AudioStream implementation
public:
- int readBuffer(Audio::st_sample_t *buffer, const int numSamples) override;
+ int readBuffer(int16 *buffer, const int numSamples) override;
bool isStereo() const override { return true; }
int getRate() const override { return _mixer->getOutputRate(); }
bool endOfData() const override { return _numActiveChannels == 0; }
@@ -219,7 +219,7 @@ private:
* Mixes audio from the given source stream into the target buffer using the
* given rate converter.
*/
- int writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, Audio::st_sample_t *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume);
+ int writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, int16 *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume);
#pragma mark -
#pragma mark Channel management
@@ -627,7 +627,7 @@ private:
* The data buffer holding decompressed audio data for the channel that will
* be monitored for an audio signal.
*/
- Common::Array<Audio::st_sample_t> _monitoredBuffer;
+ Common::Array<int16> _monitoredBuffer;
/**
* The number of valid audio samples in the signal monitoring buffer.
diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp
index 7db361bd8fa..0da109dc2fa 100644
--- a/engines/sci/video/robot_decoder.cpp
+++ b/engines/sci/video/robot_decoder.cpp
@@ -299,7 +299,7 @@ RobotAudioStream::StreamState RobotAudioStream::getStatus() const {
return status;
}
-int RobotAudioStream::readBuffer(Audio::st_sample_t *outBuffer, int numSamples) {
+int RobotAudioStream::readBuffer(int16 *outBuffer, int numSamples) {
Common::StackLock lock(_mutex);
if (_waiting) {
@@ -307,7 +307,7 @@ int RobotAudioStream::readBuffer(Audio::st_sample_t *outBuffer, int numSamples)
}
assert(!((_writeHeadAbs - _readHeadAbs) & 1));
- const int maxNumSamples = (_writeHeadAbs - _readHeadAbs) / sizeof(Audio::st_sample_t);
+ const int maxNumSamples = (_writeHeadAbs - _readHeadAbs) / sizeof(int16);
numSamples = MIN(numSamples, maxNumSamples);
if (!numSamples) {
@@ -316,22 +316,22 @@ int RobotAudioStream::readBuffer(Audio::st_sample_t *outBuffer, int numSamples)
interpolateMissingSamples(numSamples);
- Audio::st_sample_t *inBuffer = (Audio::st_sample_t *)(_loopBuffer + _readHead);
+ int16 *inBuffer = (int16 *)(_loopBuffer + _readHead);
assert(!((_loopBufferSize - _readHead) & 1));
- const int numSamplesToEnd = (_loopBufferSize - _readHead) / sizeof(Audio::st_sample_t);
+ const int numSamplesToEnd = (_loopBufferSize - _readHead) / sizeof(int16);
int numSamplesToRead = MIN(numSamples, numSamplesToEnd);
Common::copy(inBuffer, inBuffer + numSamplesToRead, outBuffer);
if (numSamplesToRead < numSamples) {
- inBuffer = (Audio::st_sample_t *)_loopBuffer;
+ inBuffer = (int16 *)_loopBuffer;
outBuffer += numSamplesToRead;
numSamplesToRead = numSamples - numSamplesToRead;
Common::copy(inBuffer, inBuffer + numSamplesToRead, outBuffer);
}
- const int32 numBytes = numSamples * sizeof(Audio::st_sample_t);
+ const int32 numBytes = numSamples * sizeof(int16);
_readHead += numBytes;
if (_readHead > _loopBufferSize) {
diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h
index 226854c54f4..2df4985546c 100644
--- a/engines/sci/video/robot_decoder.h
+++ b/engines/sci/video/robot_decoder.h
@@ -433,7 +433,7 @@ private:
#pragma mark -
#pragma mark RobotAudioStream - AudioStream implementation
public:
- int readBuffer(Audio::st_sample_t *outBuffer, int numSamples) override;
+ int readBuffer(int16 *outBuffer, int numSamples) override;
bool isStereo() const override { return false; };
int getRate() const override { return 22050; };
bool endOfData() const override {
Commit: a6d828135f33c467e9823d790a5af4148f2c0549
https://github.com/scummvm/scummvm/commit/a6d828135f33c467e9823d790a5af4148f2c0549
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Add support for 32-bit sample size
- RateConverter now accepts 32-bit input (although still with max 24-bit
values)
- make clampedAdd suited for 8-24 bit samples
Changed paths:
audio/mixer.cpp
audio/mixer.h
audio/mixer_intern.h
audio/rate.cpp
audio/rate.h
engines/sci/sound/audio32.cpp
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 51ea508d56f..174fd8f515d 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -49,12 +49,13 @@ public:
* Mixes the channel's samples into the given buffer.
*
* @param data buffer where to mix the data
- * @param len number of sample *pairs*. So a value of
- * 10 means that the buffer contains twice 10 sample, each
- * 16 bits, for a total of 40 bytes.
+ * @param len number of sample *pairs*. So a value of 10
+ * in stereo and 16-bit samples means that the
+ * buffer contains twice 10 sample, each 16 bits,
+ * for a total of 40 bytes.
* @return number of sample pairs processed (which can still be silence!)
*/
- int mix(int16 *data, uint len);
+ int mix(byte *data, uint len);
/**
* Queries whether the channel is still playing or not.
@@ -226,8 +227,9 @@ private:
#pragma mark --- Mixer ---
#pragma mark -
-MixerImpl::MixerImpl(uint sampleRate, bool stereo, uint outBufSize)
- : _mutex(), _sampleRate(sampleRate), _stereo(stereo), _outBufSize(outBufSize), _mixerReady(false), _handleSeed(0), _soundTypeSettings() {
+MixerImpl::MixerImpl(uint sampleRate, bool stereo, uint outBufSize, uint outBytesPerSample)
+ : _mutex(), _sampleRate(sampleRate), _stereo(stereo), _outBufSize(outBufSize), _outBytesPerSample(outBytesPerSample)
+ , _mixerReady(false), _handleSeed(0), _soundTypeSettings() {
assert(sampleRate > 0);
@@ -258,6 +260,10 @@ uint MixerImpl::getOutputBufSize() const {
return _outBufSize;
}
+uint MixerImpl::getOutputBytesPerSample() const {
+ return _outBytesPerSample;
+}
+
void MixerImpl::insertChannel(SoundHandle *handle, Channel *chan) {
int index = -1;
for (int i = 0; i != NUM_CHANNELS; i++) {
@@ -333,22 +339,16 @@ int MixerImpl::mixCallback(byte *samples, uint len) {
Common::StackLock lock(_mutex);
- int16 *buf = (int16 *)samples;
-
// Since the mixer callback has been called, the mixer must be ready...
_mixerReady = true;
- // zero the buf
- memset(buf, 0, len);
+ // zero the sample buffer
+ memset(samples, 0, len);
- // we store 16-bit samples
- if (_stereo) {
- assert(len % 4 == 0);
- len >>= 2;
- } else {
- assert(len % 2 == 0);
- len >>= 1;
- }
+ // we store samples of size defined by the backend
+ const uint bytesPerFrame = _outBytesPerSample * (_stereo ? 2 : 1);
+ assert(len % bytesPerFrame == 0);
+ len /= bytesPerFrame;
// mix all channels
int res = 0, tmp;
@@ -358,7 +358,7 @@ int MixerImpl::mixCallback(byte *samples, uint len) {
delete _channels[i];
_channels[i] = nullptr;
} else if (!_channels[i]->isPaused()) {
- tmp = _channels[i]->mix(buf, len);
+ tmp = _channels[i]->mix(samples, len);
if (tmp > res)
res = tmp;
@@ -793,7 +793,7 @@ void Channel::loop() {
}
}
-int Channel::mix(int16 *data, uint len) {
+int Channel::mix(byte *data, uint len) {
assert(_stream);
assert(_converter);
@@ -802,7 +802,7 @@ int Channel::mix(int16 *data, uint len) {
_samplesConsumed = _samplesDecoded;
_mixerTimeStamp = g_system->getMillis(true);
_pauseTime = 0;
- res = _converter->convert(*_stream, data, len, _volL, _volR);
+ res = _converter->convert(*_stream, data, _mixer->getOutputBytesPerSample(), len, _volL, _volR);
_samplesDecoded += res;
}
diff --git a/audio/mixer.h b/audio/mixer.h
index 2c6c35f07b2..7ec1745683f 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -390,6 +390,15 @@ public:
* @return The number of samples processed at each audio callback.
*/
virtual uint getOutputBufSize() const = 0;
+
+ /**
+ * Return the output sample size of the system.
+ *
+ * The return value is measured in bytes.
+ *
+ * @return The output sample size is bytes.
+ */
+ virtual uint getOutputBytesPerSample() const = 0;
};
/** @} */
diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h
index c46a43825ac..8201736692a 100644
--- a/audio/mixer_intern.h
+++ b/audio/mixer_intern.h
@@ -66,6 +66,7 @@ private:
const uint _sampleRate;
const bool _stereo;
uint _outBufSize;
+ const uint _outBytesPerSample;
bool _mixerReady;
uint32 _handleSeed;
@@ -82,7 +83,7 @@ private:
public:
- MixerImpl(uint sampleRate, bool stereo = true, uint outBufSize = 0);
+ MixerImpl(uint sampleRate, bool stereo = true, uint outBufSize = 0, uint outBytesPerSample = 2);
~MixerImpl();
bool isReady() const override { Common::StackLock lock(_mutex); return _mixerReady; }
@@ -139,6 +140,7 @@ public:
uint getOutputRate() const override;
bool getOutputStereo() const override;
uint getOutputBufSize() const override;
+ uint getOutputBytesPerSample() const override;
protected:
void insertChannel(SoundHandle *handle, Channel *chan);
diff --git a/audio/rate.cpp b/audio/rate.cpp
index 9ae4d3eb3cf..80d876cf5d4 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -80,10 +80,16 @@ private:
/** Current sample(s) in the input stream (left/right channel) */
int16 _inCurL, _inCurR;
+ template<typename st_sample_t>
int copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
+ template<typename st_sample_t>
int simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
+ template<typename st_sample_t>
int interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
+ template<typename st_sample_t>
+ int convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR);
+
// keep a single printConvertType shared across all RateConverter_Impl specializations.
// PrintContext must be trivially destructible: it lives in a function-scope static and
// is torn down after the OSystem (and its memory pool that backs Common::String) is gone.
@@ -110,7 +116,7 @@ public:
RateConverter_Impl(st_rate_t inputRate, st_rate_t outputRate);
virtual ~RateConverter_Impl() {}
- int convert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) override;
+ int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) override;
void setInputRate(st_rate_t inputRate) override { _inRate = inputRate; }
void setOutputRate(st_rate_t outputRate) override { _outRate = outputRate; }
@@ -122,6 +128,7 @@ public:
};
template<bool inStereo, bool outStereo, bool reverseStereo>
+template<typename st_sample_t>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -170,6 +177,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStr
}
template<bool inStereo, bool outStereo, bool reverseStereo>
+template<typename st_sample_t>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -231,6 +239,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioS
}
template<bool inStereo, bool outStereo, bool reverseStereo>
+template<typename st_sample_t>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -315,20 +324,30 @@ RateConverter_Impl<inStereo, outStereo, reverseStereo>::RateConverter_Impl(st_ra
_bufferPos(nullptr) {}
template<bool inStereo, bool outStereo, bool reverseStereo>
-int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
+template<typename st_sample_t>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
assert(input.isStereo() == inStereo);
if (_inRate == _outRate) {
- return copyConvert(input, outBuffer, numSamples, volL, volR);
+ return copyConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
} else {
if ((_inRate % _outRate) == 0 && (_inRate < 65536)) {
- return simpleConvert(input, outBuffer, numSamples, volL, volR);
+ return simpleConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
} else {
- return interpolateConvert(input, outBuffer, numSamples, volL, volR);
+ return interpolateConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
}
}
}
+template<bool inStereo, bool outStereo, bool reverseStereo>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
+ if (outBytesPerSample == sizeof(int32)) {
+ return convertForType<int32>(input, outBuffer, numSamples, volL, volR);
+ } else {
+ return convertForType<int16>(input, outBuffer, numSamples, volL, volR);
+ }
+}
+
RateConverter *makeRateConverter(st_rate_t inRate, st_rate_t outRate, bool inStereo, bool outStereo, bool reverseStereo) {
if (inStereo) {
if (outStereo) {
diff --git a/audio/rate.h b/audio/rate.h
index 4fc0213038d..1a61d07c854 100644
--- a/audio/rate.h
+++ b/audio/rate.h
@@ -35,34 +35,34 @@ namespace Audio {
class AudioStream;
-typedef int16 st_sample_t;
typedef uint16 st_volume_t;
typedef uint32 st_size_t;
typedef uint32 st_rate_t;
-/* Minimum and maximum values a sample can hold. */
-enum {
- ST_SAMPLE_MAX = 0x7fffL,
- ST_SAMPLE_MIN = (-ST_SAMPLE_MAX - 1L)
-};
+// This assumes that 'a' and 'b' are 24-bit samples at most
+template <typename T>
+static inline void clampedAdd(T& a, int b) {
+ constexpr unsigned long long highestBit = 1ULL << (sizeof(T) * 8 - 1);
+ constexpr int maxVal = (int)(highestBit - 1);
+ constexpr int minVal = ~maxVal;
-static inline void clampedAdd(int16& a, int b) {
int val;
#ifdef OUTPUT_UNSIGNED_AUDIO
- val = (a ^ 0x8000) + b;
+ constexpr int signMask = (int)highestBit;
+ val = ((int)a ^ signMask) + b;
#else
- val = a + b;
+ val = (int)a + b;
#endif
- if (val > ST_SAMPLE_MAX)
- val = ST_SAMPLE_MAX;
- else if (val < ST_SAMPLE_MIN)
- val = ST_SAMPLE_MIN;
+ if (val > maxVal)
+ val = maxVal;
+ else if (val < minVal)
+ val = minVal;
#ifdef OUTPUT_UNSIGNED_AUDIO
- a = ((int16)val) ^ 0x8000;
+ a = (T)(val ^ signMask);
#else
- a = val;
+ a = (T)val;
#endif
}
@@ -79,16 +79,17 @@ public:
/**
* Convert the provided AudioStream to the target sample rate.
- *
- * @param input The AudioStream to read data from.
- * @param outBuffer The buffer that the resampled audio will be written to. Must have size of at least @p numSamples.
- * @param numSamples The desired number of samples to be written into the buffer.
- * @param vol_l Volume for left channel.
- * @param vol_r Volume for right channel.
- *
+ *
+ * @param input The AudioStream to read data from.
+ * @param outBuffer The buffer that the resampled audio will be written to. Must have size of at least @p numSamples.
+ * @param outBytesPerSample The size of each output sample in bytes (e.g. sizeof(int16) or sizeof(int32)).
+ * @param numSamples The desired number of samples to be written into the buffer.
+ * @param vol_l Volume for left channel.
+ * @param vol_r Volume for right channel.
+ *
* @return Number of sample pairs written into the buffer.
*/
- virtual int convert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) = 0;
+ virtual int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) = 0;
virtual void setInputRate(st_rate_t inputRate) = 0;
virtual void setOutputRate(st_rate_t outputRate) = 0;
@@ -98,7 +99,7 @@ public:
/**
* Does the internal buffer still have some leftover data?
- *
+ *
* @return True if we need to drain, false otherwise
*/
virtual bool needsDraining() const = 0;
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index 0b21070ec7c..ce160284650 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -234,7 +234,7 @@ Audio32::~Audio32() {
int Audio32::writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, int16 *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume) {
const int samplePairsToRead = numSamples >> 1;
- const int samplePairsWritten = converter.convert(sourceStream, targetBuffer, samplePairsToRead, leftVolume, rightVolume);
+ const int samplePairsWritten = converter.convert(sourceStream, (byte *)targetBuffer, sizeof(int16), samplePairsToRead, leftVolume, rightVolume);
return samplePairsWritten << 1;
}
Commit: b9cca6360ead999587371787f87276247dc583fb
https://github.com/scummvm/scummvm/commit/b9cca6360ead999587371787f87276247dc583fb
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: RateConverter now supports unclamped mixing
Changed paths:
audio/mixer.cpp
audio/rate.cpp
audio/rate.h
engines/sci/sound/audio32.cpp
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 174fd8f515d..015812d90ce 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -802,7 +802,7 @@ int Channel::mix(byte *data, uint len) {
_samplesConsumed = _samplesDecoded;
_mixerTimeStamp = g_system->getMillis(true);
_pauseTime = 0;
- res = _converter->convert(*_stream, data, _mixer->getOutputBytesPerSample(), len, _volL, _volR);
+ res = _converter->convert(*_stream, data, _mixer->getOutputBytesPerSample(), len, _volL, _volR, MIX_CLAMPED_ADD);
_samplesDecoded += res;
}
diff --git a/audio/rate.cpp b/audio/rate.cpp
index 80d876cf5d4..b115f63c1e9 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -80,14 +80,14 @@ private:
/** Current sample(s) in the input stream (left/right channel) */
int16 _inCurL, _inCurR;
- template<typename st_sample_t>
+ template<typename st_sample_t, MixMode mixMode>
int copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
- template<typename st_sample_t>
+ template<typename st_sample_t, MixMode mixMode>
int simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
- template<typename st_sample_t>
+ template<typename st_sample_t, MixMode mixMode>
int interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
- template<typename st_sample_t>
+ template<typename st_sample_t, MixMode mixMode>
int convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR);
// keep a single printConvertType shared across all RateConverter_Impl specializations.
@@ -116,7 +116,7 @@ public:
RateConverter_Impl(st_rate_t inputRate, st_rate_t outputRate);
virtual ~RateConverter_Impl() {}
- int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) override;
+ int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r, MixMode mixMode) override;
void setInputRate(st_rate_t inputRate) override { _inRate = inputRate; }
void setOutputRate(st_rate_t outputRate) override { _outRate = outputRate; }
@@ -128,7 +128,7 @@ public:
};
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t>
+template<typename st_sample_t, MixMode mixMode>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -159,15 +159,15 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStr
if (outStereo) {
// Output left channel
- clampedAdd(outBuffer[reverseStereo ], outL);
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
// Output right channel
- clampedAdd(outBuffer[reverseStereo ^ 1], outR);
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
outBuffer += 2;
} else {
// Output mono channel
- clampedAdd(outBuffer[0], (outL + outR) / 2);
+ processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
outBuffer += 1;
}
@@ -177,7 +177,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStr
}
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t>
+template<typename st_sample_t, MixMode mixMode>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -222,15 +222,15 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioS
if (outStereo) {
// output left channel
- clampedAdd(outBuffer[reverseStereo ], outL);
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
// output right channel
- clampedAdd(outBuffer[reverseStereo ^ 1], outR);
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
outBuffer += 2;
} else {
// output mono channel
- clampedAdd(outBuffer[0], (outL + outR) / 2);
+ processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
outBuffer += 1;
}
@@ -239,7 +239,7 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioS
}
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t>
+template<typename st_sample_t, MixMode mixMode>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
PRINT_OUTPUT_RATE;
@@ -290,15 +290,15 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(A
if (outStereo) {
// Output left channel
- clampedAdd(outBuffer[reverseStereo ], outL);
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
// Output right channel
- clampedAdd(outBuffer[reverseStereo ^ 1], outR);
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
outBuffer += 2;
} else {
// Output mono channel
- clampedAdd(outBuffer[0], (outL + outR) / 2);
+ processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
outBuffer += 1;
}
@@ -324,27 +324,33 @@ RateConverter_Impl<inStereo, outStereo, reverseStereo>::RateConverter_Impl(st_ra
_bufferPos(nullptr) {}
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t>
+template<typename st_sample_t, MixMode mixMode>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
assert(input.isStereo() == inStereo);
if (_inRate == _outRate) {
- return copyConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ return copyConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
} else {
if ((_inRate % _outRate) == 0 && (_inRate < 65536)) {
- return simpleConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ return simpleConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
} else {
- return interpolateConvert<st_sample_t>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ return interpolateConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
}
}
}
template<bool inStereo, bool outStereo, bool reverseStereo>
-int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t volL, st_volume_t volR, MixMode mixMode) {
if (outBytesPerSample == sizeof(int32)) {
- return convertForType<int32>(input, outBuffer, numSamples, volL, volR);
+ if (mixMode == MIX_ADD)
+ return convertForType<int32, MIX_ADD>(input, outBuffer, numSamples, volL, volR);
+ else
+ return convertForType<int32, MIX_CLAMPED_ADD>(input, outBuffer, numSamples, volL, volR);
} else {
- return convertForType<int16>(input, outBuffer, numSamples, volL, volR);
+ if (mixMode == MIX_ADD)
+ return convertForType<int16, MIX_ADD>(input, outBuffer, numSamples, volL, volR);
+ else
+ return convertForType<int16, MIX_CLAMPED_ADD>(input, outBuffer, numSamples, volL, volR);
}
}
diff --git a/audio/rate.h b/audio/rate.h
index 1a61d07c854..cf59a8f5f0c 100644
--- a/audio/rate.h
+++ b/audio/rate.h
@@ -39,31 +39,49 @@ typedef uint16 st_volume_t;
typedef uint32 st_size_t;
typedef uint32 st_rate_t;
+enum MixMode {
+ MIX_ADD,
+ MIX_CLAMPED_ADD
+};
+
// This assumes that 'a' and 'b' are 24-bit samples at most
-template <typename T>
-static inline void clampedAdd(T& a, int b) {
+template <MixMode Mode, typename T>
+static inline void processSample(T& a, int b) {
constexpr unsigned long long highestBit = 1ULL << (sizeof(T) * 8 - 1);
constexpr int maxVal = (int)(highestBit - 1);
constexpr int minVal = ~maxVal;
- int val;
#ifdef OUTPUT_UNSIGNED_AUDIO
constexpr int signMask = (int)highestBit;
- val = ((int)a ^ signMask) + b;
+#endif
+
+ if (Mode == MIX_ADD) {
+ a += b;
+ } else if (Mode == MIX_CLAMPED_ADD) {
+ int val;
+#ifdef OUTPUT_UNSIGNED_AUDIO
+ val = ((int)a ^ signMask) + b;
#else
- val = (int)a + b;
+ val = (int)a + b;
#endif
- if (val > maxVal)
- val = maxVal;
- else if (val < minVal)
- val = minVal;
+ if (val > maxVal)
+ val = maxVal;
+ else if (val < minVal)
+ val = minVal;
#ifdef OUTPUT_UNSIGNED_AUDIO
- a = (T)(val ^ signMask);
+ a = (T)(val ^ signMask);
#else
- a = (T)val;
+ a = (T)val;
#endif
+ }
+}
+
+// Fallback for engine code
+template <typename T>
+static inline void clampedAdd(T& a, int b) {
+ processSample<MIX_CLAMPED_ADD>(a, b);
}
/**
@@ -86,10 +104,11 @@ public:
* @param numSamples The desired number of samples to be written into the buffer.
* @param vol_l Volume for left channel.
* @param vol_r Volume for right channel.
+ * @param mixMode Sample mix mode for outBuffer.
*
* @return Number of sample pairs written into the buffer.
*/
- virtual int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r) = 0;
+ virtual int convert(AudioStream &input, byte *outBuffer, uint outBytesPerSample, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r, MixMode mixMode) = 0;
virtual void setInputRate(st_rate_t inputRate) = 0;
virtual void setOutputRate(st_rate_t outputRate) = 0;
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index ce160284650..995d1dbf777 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -234,7 +234,7 @@ Audio32::~Audio32() {
int Audio32::writeAudioInternal(Audio::AudioStream &sourceStream, Audio::RateConverter &converter, int16 *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume) {
const int samplePairsToRead = numSamples >> 1;
- const int samplePairsWritten = converter.convert(sourceStream, (byte *)targetBuffer, sizeof(int16), samplePairsToRead, leftVolume, rightVolume);
+ const int samplePairsWritten = converter.convert(sourceStream, (byte *)targetBuffer, sizeof(int16), samplePairsToRead, leftVolume, rightVolume, Audio::MIX_CLAMPED_ADD);
return samplePairsWritten << 1;
}
Commit: 424681dca2ac20e89bb19bfa2c86818311e248ed
https://github.com/scummvm/scummvm/commit/424681dca2ac20e89bb19bfa2c86818311e248ed
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Make sample clamping optional
Changed paths:
audio/mixer.cpp
audio/mixer.h
audio/mixer_intern.h
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 015812d90ce..0f6ab5298e9 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -227,8 +227,8 @@ private:
#pragma mark --- Mixer ---
#pragma mark -
-MixerImpl::MixerImpl(uint sampleRate, bool stereo, uint outBufSize, uint outBytesPerSample)
- : _mutex(), _sampleRate(sampleRate), _stereo(stereo), _outBufSize(outBufSize), _outBytesPerSample(outBytesPerSample)
+MixerImpl::MixerImpl(uint sampleRate, bool stereo, uint outBufSize, uint outBytesPerSample, bool clamp)
+ : _mutex(), _sampleRate(sampleRate), _stereo(stereo), _outBufSize(outBufSize), _outBytesPerSample(outBytesPerSample), _clamp(clamp)
, _mixerReady(false), _handleSeed(0), _soundTypeSettings() {
assert(sampleRate > 0);
@@ -264,6 +264,10 @@ uint MixerImpl::getOutputBytesPerSample() const {
return _outBytesPerSample;
}
+bool MixerImpl::getClamping() const {
+ return _clamp;
+}
+
void MixerImpl::insertChannel(SoundHandle *handle, Channel *chan) {
int index = -1;
for (int i = 0; i != NUM_CHANNELS; i++) {
@@ -802,7 +806,14 @@ int Channel::mix(byte *data, uint len) {
_samplesConsumed = _samplesDecoded;
_mixerTimeStamp = g_system->getMillis(true);
_pauseTime = 0;
- res = _converter->convert(*_stream, data, _mixer->getOutputBytesPerSample(), len, _volL, _volR, MIX_CLAMPED_ADD);
+ res = _converter->convert(
+ *_stream,
+ data,
+ _mixer->getOutputBytesPerSample(),
+ len,
+ _volL,
+ _volR,
+ _mixer->getClamping() ? MIX_CLAMPED_ADD : MIX_ADD);
_samplesDecoded += res;
}
diff --git a/audio/mixer.h b/audio/mixer.h
index 7ec1745683f..9c15a99f831 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -399,6 +399,13 @@ public:
* @return The output sample size is bytes.
*/
virtual uint getOutputBytesPerSample() const = 0;
+
+ /**
+ * Return whether the mixer is expected to clamp outgoing samples.
+ *
+ * @return true if output is clamped, false if not.
+ */
+ virtual bool getClamping() const = 0;
};
/** @} */
diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h
index 8201736692a..d6ff2de96c0 100644
--- a/audio/mixer_intern.h
+++ b/audio/mixer_intern.h
@@ -67,6 +67,7 @@ private:
const bool _stereo;
uint _outBufSize;
const uint _outBytesPerSample;
+ const bool _clamp;
bool _mixerReady;
uint32 _handleSeed;
@@ -83,7 +84,7 @@ private:
public:
- MixerImpl(uint sampleRate, bool stereo = true, uint outBufSize = 0, uint outBytesPerSample = 2);
+ MixerImpl(uint sampleRate, bool stereo = true, uint outBufSize = 0, uint outBytesPerSample = 2, bool clamp = true);
~MixerImpl();
bool isReady() const override { Common::StackLock lock(_mutex); return _mixerReady; }
@@ -141,6 +142,7 @@ public:
bool getOutputStereo() const override;
uint getOutputBufSize() const override;
uint getOutputBytesPerSample() const override;
+ bool getClamping() const override;
protected:
void insertChannel(SoundHandle *handle, Channel *chan);
Commit: 995c360cfc03ce037959ddaaab00c5b5b224f630
https://github.com/scummvm/scummvm/commit/995c360cfc03ce037959ddaaab00c5b5b224f630
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Don't clamp muted channels
Changed paths:
audio/mixer.cpp
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 0f6ab5298e9..cbb47186ae6 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -143,6 +143,11 @@ public:
*/
uint8 getFaderR() const;
+ /**
+ * Queries whether the channel is silent, i.e. will produce no audio output.
+ */
+ bool isSilent() const { return _volL == 0 && _volR == 0; }
+
/**
* Set the channel's sample rate.
*
@@ -346,15 +351,13 @@ int MixerImpl::mixCallback(byte *samples, uint len) {
// Since the mixer callback has been called, the mixer must be ready...
_mixerReady = true;
- // zero the sample buffer
- memset(samples, 0, len);
-
// we store samples of size defined by the backend
const uint bytesPerFrame = _outBytesPerSample * (_stereo ? 2 : 1);
assert(len % bytesPerFrame == 0);
- len /= bytesPerFrame;
+ const uint numFrames = len / bytesPerFrame;
- // mix all channels
+ // mix all channels, zeroing the buffer lazily on first non-silent channel
+ bool zeroed = false;
int res = 0, tmp;
for (int i = 0; i != NUM_CHANNELS; i++)
if (_channels[i]) {
@@ -362,14 +365,19 @@ int MixerImpl::mixCallback(byte *samples, uint len) {
delete _channels[i];
_channels[i] = nullptr;
} else if (!_channels[i]->isPaused()) {
- tmp = _channels[i]->mix(samples, len);
+ if (!_channels[i]->isSilent() && !zeroed) {
+ memset(samples, 0, len);
+ zeroed = true;
+ }
+ tmp = _channels[i]->mix(samples, numFrames);
if (tmp > res)
res = tmp;
}
}
- return res;
+ // optimisation: let the caller know that there's nothing to clamp
+ return (!_clamp && !zeroed) ? 0 : res;
}
void MixerImpl::stopAll() {
Commit: 85befa9c13c0cf953e63f79e67b605a00d5e8fa4
https://github.com/scummvm/scummvm/commit/85befa9c13c0cf953e63f79e67b605a00d5e8fa4
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-06-21T15:17:36+02:00
Commit Message:
AUDIO: Template-optimize convert methods
Also, introduce upscaleConvert for e.g. 11025, 22050 -> 44100
conversions.
Changed paths:
audio/rate.cpp
diff --git a/audio/rate.cpp b/audio/rate.cpp
index b115f63c1e9..7ebf1e88af9 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -80,12 +80,17 @@ private:
/** Current sample(s) in the input stream (left/right channel) */
int16 _inCurL, _inCurR;
- template<typename st_sample_t, MixMode mixMode>
- int copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
- template<typename st_sample_t, MixMode mixMode>
- int simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
- template<typename st_sample_t, MixMode mixMode>
- int interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t vol_l, st_volume_t vol_r);
+ template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+ int commonConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val, int outputSamples);
+
+ template<st_volume_t volL = static_cast<st_volume_t>(-1), st_volume_t volR = static_cast<st_volume_t>(-1), typename st_sample_t, MixMode mixMode>
+ int copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val);
+ template<st_volume_t volL = static_cast<st_volume_t>(-1), st_volume_t volR = static_cast<st_volume_t>(-1), typename st_sample_t, MixMode mixMode>
+ int downsampleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val);
+ template<st_volume_t volL = static_cast<st_volume_t>(-1), st_volume_t volR = static_cast<st_volume_t>(-1), typename st_sample_t, MixMode mixMode>
+ int upsampleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val);
+ template<st_volume_t volL = static_cast<st_volume_t>(-1), st_volume_t volR = static_cast<st_volume_t>(-1), typename st_sample_t, MixMode mixMode>
+ int interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val);
template<typename st_sample_t, MixMode mixMode>
int convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR);
@@ -128,14 +133,10 @@ public:
};
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t, MixMode mixMode>
-int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
- PRINT_OUTPUT_RATE;
-
- st_sample_t *outStart, *outEnd;
-
- outStart = outBuffer;
- outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
+template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::commonConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val, int outputSamples) {
+ const st_sample_t *outStart = outBuffer;
+ const st_sample_t *outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
while (outBuffer < outEnd) {
// Check if we have to refill the buffer
@@ -147,51 +148,112 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStr
return (outBuffer - outStart) / (outStereo ? 2 : 1);
}
- // Mix the data into the output buffer
- int16 inL, inR;
- inL = *_bufferPos++;
- inR = (inStereo ? *_bufferPos++ : inL);
- _bufferSize -= (inStereo ? 2 : 1);
-
- st_sample_t outL, outR;
- outL = (inL * (int)volL) / Audio::Mixer::kMaxMixerVolume;
- outR = (inR * (int)volR) / Audio::Mixer::kMaxMixerVolume;
-
- if (outStereo) {
- // Output left channel
- processSample<mixMode>(outBuffer[reverseStereo ], outL);
-
- // Output right channel
- processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
-
- outBuffer += 2;
+ // Process as many samples as we can from the current buffer
+ const int count = MIN(
+ _bufferSize / (inStereo ? 2 : 1),
+ (int)(outEnd - outBuffer) / (outStereo ? 2 : 1) / outputSamples);
+ _bufferSize -= count * (inStereo ? 2 : 1);
+
+ if (volL | volR) {
+ // Mix the data into the output buffer
+ for (int i = 0; i < count; ++i) {
+ int16 inL, inR;
+
+ if (inStereo) {
+ if (volL != 0)
+ inL = *_bufferPos++;
+ else
+ _bufferPos++;
+
+ if (volR != 0)
+ inR = *_bufferPos++;
+ else
+ _bufferPos++;
+ } else {
+ if (volL != 0) {
+ inL = *_bufferPos++;
+ if (volR != 0)
+ inR = inL;
+ } else {
+ inR = *_bufferPos++;
+ }
+ }
+
+ st_sample_t outL, outR;
+
+ if (volL != 0) {
+ if (volL != Audio::Mixer::kMaxMixerVolume)
+ outL = (inL * (int)volL_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outL = inL;
+ }
+
+ if (volR != 0) {
+ if (volR != Audio::Mixer::kMaxMixerVolume)
+ outR = (inR * (int)volR_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outR = inR;
+ }
+
+ // TODO: could be unrolled
+ for (int j = 0; j < outputSamples; ++j) {
+ if (outStereo) {
+ // Output left channel
+ if (volL != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
+
+ // Output right channel
+ if (volR != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
+ } else {
+ // Output mono channel
+ st_sample_t monoOut;
+ if (volL != 0 && volR != 0)
+ monoOut = (outL + outR) / 2;
+ else if (volL != 0)
+ monoOut = outL / 2;
+ else if (volR != 0)
+ monoOut = outR / 2;
+ processSample<mixMode>(outBuffer[0], monoOut);
+ }
+ outBuffer += (outStereo ? 2 : 1);
+ }
+ }
} else {
- // Output mono channel
- processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
-
- outBuffer += 1;
+ _bufferPos += count * (inStereo ? 2 : 1);
+ outBuffer += count * outputSamples * (outStereo ? 2 : 1);
}
}
-
return (outBuffer - outStart) / (outStereo ? 2 : 1);
}
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t, MixMode mixMode>
-int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
+template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::copyConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val) {
PRINT_OUTPUT_RATE;
- // How much to increment _outPos by
- frac_t outPos_inc = _inRate / _outRate;
+ return commonConvert<volL, volR, st_sample_t, mixMode>(input, outBuffer, numSamples, volL_val, volR_val, 1);
+}
+
+template<bool inStereo, bool outStereo, bool reverseStereo>
+template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::downsampleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val) {
+ PRINT_OUTPUT_RATE;
- st_sample_t *outStart, *outEnd;
+ // How much to increment _outPos by
+ const frac_t outPos_inc = _inRate / _outRate;
- outStart = outBuffer;
- outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
+ const st_sample_t *outStart = outBuffer;
+ const st_sample_t *outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
while (outBuffer < outEnd) {
// Read enough input samples so that _outPos >= 0
- do {
+ while (_outPos >= 0) {
+ const int skip = MIN((int)_outPos + 1, _bufferSize / (inStereo ? 2 : 1));
+ _bufferPos += skip * (inStereo ? 2 : 1);
+ _bufferSize -= skip * (inStereo ? 2 : 1);
+ _outPos -= skip;
+
// Check if we have to refill the buffer
if (_bufferSize == 0) {
_bufferPos = _buffer;
@@ -200,55 +262,106 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::simpleConvert(AudioS
if (_bufferSize <= 0)
return (outBuffer - outStart) / (outStereo ? 2 : 1);
}
+ }
- _bufferSize -= (inStereo ? 2 : 1);
- _outPos--;
-
- if (_outPos >= 0) {
- _bufferPos += (inStereo ? 2 : 1);
+ // Process as many samples as we can from the current buffer
+ const int count = MIN(
+ _bufferSize / (inStereo ? 2 : 1) / outPos_inc,
+ (int)(outEnd - outBuffer) / (outStereo ? 2 : 1));
+ _bufferSize -= count * outPos_inc * (inStereo ? 2 : 1);
+ _outPos = outPos_inc - 1;
+
+ // Frame stride remaining after reading one frame
+ const int stride = (outPos_inc - 1) * (inStereo ? 2 : 1);
+
+ if (volL | volR) {
+ for (int i = 0; i < count; ++i) {
+ int16 inL, inR;
+
+ if (inStereo) {
+ if (volL != 0)
+ inL = *_bufferPos++;
+ else
+ _bufferPos++;
+
+ if (volR != 0)
+ inR = *_bufferPos++;
+ else
+ _bufferPos++;
+ } else {
+ if (volL != 0) {
+ inL = *_bufferPos++;
+ if (volR != 0)
+ inR = inL;
+ } else {
+ inR = *_bufferPos++;
+ }
+ }
+
+ _bufferPos += stride;
+
+ st_sample_t outL, outR;
+ if (volL != 0) {
+ if (volL != Audio::Mixer::kMaxMixerVolume)
+ outL = (inL * (int)volL_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outL = inL;
+ }
+ if (volR != 0) {
+ if (volR != Audio::Mixer::kMaxMixerVolume)
+ outR = (inR * (int)volR_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outR = inR;
+ }
+
+ if (outStereo) {
+ // Output left channel
+ if (volL != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
+
+ // Output right channel
+ if (volR != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
+ } else {
+ // Output mono channel
+ st_sample_t monoOut;
+ if (volL != 0 && volR != 0)
+ monoOut = (outL + outR) / 2;
+ else if (volL != 0)
+ monoOut = outL / 2;
+ else if (volR != 0)
+ monoOut = outR / 2;
+ processSample<mixMode>(outBuffer[0], monoOut);
+ }
+
+ outBuffer += (outStereo ? 2 : 1);
}
- } while (_outPos >= 0);
-
- int16 inL, inR;
- inL = *_bufferPos++;
- inR = (inStereo ? *_bufferPos++ : inL);
-
- // Increment output position
- _outPos += outPos_inc;
-
- st_sample_t outL, outR;
- outL = (inL * (int)volL) / Audio::Mixer::kMaxMixerVolume;
- outR = (inR * (int)volR) / Audio::Mixer::kMaxMixerVolume;
-
- if (outStereo) {
- // output left channel
- processSample<mixMode>(outBuffer[reverseStereo ], outL);
-
- // output right channel
- processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
-
- outBuffer += 2;
} else {
- // output mono channel
- processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
-
- outBuffer += 1;
+ _bufferPos += count * outPos_inc * (inStereo ? 2 : 1);
+ outBuffer += count * (outStereo ? 2 : 1);
}
}
return (outBuffer - outStart) / (outStereo ? 2 : 1);
}
template<bool inStereo, bool outStereo, bool reverseStereo>
-template<typename st_sample_t, MixMode mixMode>
-int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
+template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::upsampleConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val) {
+ PRINT_OUTPUT_RATE;
+
+ return commonConvert<volL, volR, st_sample_t, mixMode>(input, outBuffer, numSamples, volL_val, volR_val, _outRate / _inRate);
+}
+
+template<bool inStereo, bool outStereo, bool reverseStereo>
+template<st_volume_t volL, st_volume_t volR, typename st_sample_t, MixMode mixMode>
+int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(AudioStream &input, st_sample_t *outBuffer, st_size_t numSamples, st_volume_t volL_val, st_volume_t volR_val) {
PRINT_OUTPUT_RATE;
// How much to increment _outPosFrac by
- frac_t outPos_inc = (_inRate << FRAC_BITS_LOW) / _outRate;
+ const frac_t outPos_inc = (_inRate << FRAC_BITS_LOW) / _outRate;
- st_sample_t *outStart, *outEnd;
- outStart = outBuffer;
- outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
+ const st_sample_t *outStart = outBuffer;
+ const st_sample_t *outEnd = outBuffer + numSamples * (outStereo ? 2 : 1);
while (outBuffer < outEnd) {
// Read enough input samples so that _outPosFrac < 0
@@ -263,12 +376,21 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(A
}
_bufferSize -= (inStereo ? 2 : 1);
- _inLastL = _inCurL;
- _inCurL = *_bufferPos++;
+
+ if (volL != 0 || (!inStereo && volR != 0)) {
+ _inLastL = _inCurL;
+ _inCurL = *_bufferPos++;
+ } else {
+ _bufferPos++;
+ }
if (inStereo) {
- _inLastR = _inCurR;
- _inCurR = *_bufferPos++;
+ if (volR != 0) {
+ _inLastR = _inCurR;
+ _inCurR = *_bufferPos++;
+ } else {
+ _bufferPos++;
+ }
}
_outPosFrac -= FRAC_ONE_LOW;
@@ -277,32 +399,58 @@ int RateConverter_Impl<inStereo, outStereo, reverseStereo>::interpolateConvert(A
// Loop as long as the _outPos trails behind, and as long as there is
// still space in the output buffer.
while (_outPosFrac < (frac_t)FRAC_ONE_LOW && outBuffer < outEnd) {
- // Interpolate
- int16 inL, inR;
- inL = (int16)(_inLastL + (((_inCurL - _inLastL) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
- inR = (inStereo ?
- (int16)(_inLastR + (((_inCurR - _inLastR) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
- inL);
+ if (volL | volR) {
+ // Interpolate
+ int16 inL, inR;
- st_sample_t outL, outR;
- outL = (inL * (int)volL) / Audio::Mixer::kMaxMixerVolume;
- outR = (inR * (int)volR) / Audio::Mixer::kMaxMixerVolume;
+ if (volL != 0 || (!inStereo && volR != 0)) {
+ inL = (int16)(_inLastL + (((_inCurL - _inLastL) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
+ }
- if (outStereo) {
- // Output left channel
- processSample<mixMode>(outBuffer[reverseStereo ], outL);
-
- // Output right channel
- processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
-
- outBuffer += 2;
- } else {
- // Output mono channel
- processSample<mixMode>(outBuffer[0], (outL + outR) / 2);
-
- outBuffer += 1;
+ if (volR != 0) {
+ inR = (inStereo ?
+ (int16)(_inLastR + (((_inCurR - _inLastR) * _outPosFrac + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
+ inL);
+ }
+
+ st_sample_t outL, outR;
+ if (volL != 0) {
+ if (volL != Audio::Mixer::kMaxMixerVolume)
+ outL = (inL * (int)volL_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outL = inL;
+ }
+
+ if (volR != 0) {
+ if (volR != Audio::Mixer::kMaxMixerVolume)
+ outR = (inR * (int)volR_val) / Audio::Mixer::kMaxMixerVolume;
+ else
+ outR = inR;
+ }
+
+ if (outStereo) {
+ // Output left channel
+ if (volL != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ], outL);
+
+ // Output right channel
+ if (volR != 0)
+ processSample<mixMode>(outBuffer[reverseStereo ^ 1], outR);
+ } else {
+ // Output mono channel
+ st_sample_t monoOut;
+ if (volL != 0 && volR != 0)
+ monoOut = (outL + outR) / 2;
+ else if (volL != 0)
+ monoOut = outL / 2;
+ else
+ monoOut = outR / 2;
+ processSample<mixMode>(outBuffer[0], monoOut);
+ }
}
+ outBuffer += (outStereo ? 2 : 1);
+
// Increment output position
_outPosFrac += outPos_inc;
}
@@ -328,14 +476,52 @@ template<typename st_sample_t, MixMode mixMode>
int RateConverter_Impl<inStereo, outStereo, reverseStereo>::convertForType(AudioStream &input, byte *outBuffer, st_size_t numSamples, st_volume_t volL, st_volume_t volR) {
assert(input.isStereo() == inStereo);
+ constexpr auto kMax = Audio::Mixer::kMaxMixerVolume;
+
if (_inRate == _outRate) {
- return copyConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ if (volL == 0 && volR == 0)
+ return copyConvert<0, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == 0 && volR == kMax)
+ return copyConvert<0, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == 0)
+ return copyConvert<kMax, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == kMax)
+ return copyConvert<kMax, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else
+ return copyConvert<static_cast<st_volume_t>(-1), static_cast<st_volume_t>(-1), st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ } else if ((_inRate % _outRate) == 0 && (_inRate < 65536)) {
+ if (volL == 0 && volR == 0)
+ return downsampleConvert<0, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == 0 && volR == kMax)
+ return downsampleConvert<0, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == 0)
+ return downsampleConvert<kMax, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == kMax)
+ return downsampleConvert<kMax, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else
+ return downsampleConvert<static_cast<st_volume_t>(-1), static_cast<st_volume_t>(-1), st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ } else if ((_outRate % _inRate) == 0) {
+ if (volL == 0 && volR == 0)
+ return upsampleConvert<0, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == 0 && volR == kMax)
+ return upsampleConvert<0, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == 0)
+ return upsampleConvert<kMax, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == kMax)
+ return upsampleConvert<kMax, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else
+ return upsampleConvert<static_cast<st_volume_t>(-1), static_cast<st_volume_t>(-1), st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
} else {
- if ((_inRate % _outRate) == 0 && (_inRate < 65536)) {
- return simpleConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
- } else {
- return interpolateConvert<st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
- }
+ if (volL == 0 && volR == 0)
+ return interpolateConvert<0, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == 0 && volR == kMax)
+ return interpolateConvert<0, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == 0)
+ return interpolateConvert<kMax, 0, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else if (volL == kMax && volR == kMax)
+ return interpolateConvert<kMax, kMax, st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
+ else
+ return interpolateConvert<static_cast<st_volume_t>(-1), static_cast<st_volume_t>(-1), st_sample_t, mixMode>(input, (st_sample_t *)outBuffer, numSamples, volL, volR);
}
}
More information about the Scummvm-git-logs
mailing list