diff --git a/Core/Util/AudioFormat.cpp b/Core/Util/AudioFormat.cpp index 5806c2c51c..2424b405d5 100644 --- a/Core/Util/AudioFormat.cpp +++ b/Core/Util/AudioFormat.cpp @@ -37,7 +37,10 @@ void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int out += 16; size -= 16; } - } else { + } +#if 0 + // This path wraps instead of clamps in _mm_slli_epi16. Needs fixing. + else { // We have to shift inside the loop to avoid the signed 16-bit multiply issue. int leftShift = 0; int leftVol16 = leftVol; @@ -63,9 +66,17 @@ void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int } } #endif - for (size_t i = 0; i < size; i += 2) { - out[i] = ApplySampleVolume(in[i], leftVol); - out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); +#endif + if (leftVol <= 0x7fff && -leftVol <= 0x8000 && rightVol <= 0x7fff && -rightVol <= 0x8000) { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume(in[i], leftVol); + out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + } + } else { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume20Bit(in[i], leftVol); + out[i + 1] = ApplySampleVolume20Bit(in[i + 1], rightVol); + } } } diff --git a/Core/Util/AudioFormat.h b/Core/Util/AudioFormat.h index 841b8e634a..7fc20eaf83 100644 --- a/Core/Util/AudioFormat.h +++ b/Core/Util/AudioFormat.h @@ -59,6 +59,12 @@ static inline s16 ApplySampleVolume(s16 sample, int vol) { #endif } +// We sacrifice a little volume precision to fit in 32 bits, for speed. +// Probably not worth it to make a special path for 64-bit CPUs. +static inline s16 ApplySampleVolume20Bit(s16 sample, int vol20) { + return clamp_s16((sample * (vol20 >> 4)) >> 12); +} + void SetupAudioFormats(); void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int rightVol); void ConvertS16ToF32(float *ou, const s16 *in, size_t size); diff --git a/Core/Util/AudioFormatNEON.cpp b/Core/Util/AudioFormatNEON.cpp index 4eafe47ba7..4653764b49 100644 --- a/Core/Util/AudioFormatNEON.cpp +++ b/Core/Util/AudioFormatNEON.cpp @@ -58,9 +58,16 @@ void AdjustVolumeBlockNEON(s16 *out, s16 *in, size_t size, int leftVol, int righ } } - for (size_t i = 0; i < size; i += 2) { - out[i] = ApplySampleVolume(in[i], leftVol); - out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + if (leftVol <= 0x7fff && -leftVol <= 0x8000 && rightVol <= 0x7fff && -rightVol <= 0x8000) { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume(in[i], leftVol); + out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + } + } else { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume20Bit(in[i], leftVol); + out[i + 1] = ApplySampleVolume20Bit(in[i + 1], rightVol); + } } }