mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibAudio: Prevent overflows during prediction
Saturating arithmetic leads to less screwed up audio in these cases.
This commit is contained in:
parent
0347d04289
commit
b432674923
Notes:
sideshowbarker
2024-07-17 03:18:29 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/b432674923 Pull-request: https://github.com/SerenityOS/serenity/pull/20686 Reviewed-by: https://github.com/Hendiadyoin1
2 changed files with 30 additions and 4 deletions
26
AK/Checked.h
26
AK/Checked.h
|
@ -234,6 +234,24 @@ public:
|
|||
m_overflow = false;
|
||||
}
|
||||
|
||||
constexpr void saturating_mul(T other)
|
||||
{
|
||||
// Figure out if the result is positive, negative or zero beforehand.
|
||||
auto either_is_zero = this->m_value == 0 || other == 0;
|
||||
auto result_is_positive = (this->m_value > 0) == (other > 0);
|
||||
|
||||
mul(other);
|
||||
if (m_overflow) {
|
||||
if (either_is_zero)
|
||||
m_value = 0;
|
||||
else if (result_is_positive)
|
||||
m_value = NumericLimits<T>::max();
|
||||
else
|
||||
m_value = NumericLimits<T>::min();
|
||||
}
|
||||
m_overflow = false;
|
||||
}
|
||||
|
||||
constexpr Checked& operator+=(Checked const& other)
|
||||
{
|
||||
m_overflow |= other.m_overflow;
|
||||
|
@ -354,6 +372,14 @@ public:
|
|||
return checked.value();
|
||||
}
|
||||
|
||||
template<typename U, typename V>
|
||||
static constexpr T saturating_mul(U a, V b)
|
||||
{
|
||||
Checked checked { a };
|
||||
checked.saturating_mul(b);
|
||||
return checked.value();
|
||||
}
|
||||
|
||||
template<typename U, typename V>
|
||||
[[nodiscard]] static constexpr bool multiplication_would_overflow(U u, V v)
|
||||
{
|
||||
|
|
|
@ -797,16 +797,16 @@ ErrorOr<void, LoaderError> FlacLoaderPlugin::decode_custom_lpc(Vector<i64>& deco
|
|||
// approximate the waveform with the predictor
|
||||
for (size_t i = subframe.order; i < m_current_frame->sample_count; ++i) {
|
||||
// (see below)
|
||||
i64 sample = 0;
|
||||
Checked<i64> sample = 0;
|
||||
for (size_t t = 0; t < subframe.order; ++t) {
|
||||
// It's really important that we compute in 64-bit land here.
|
||||
// Even though FLAC operates at a maximum bit depth of 32 bits, modern encoders use super-large coefficients for maximum compression.
|
||||
// These will easily overflow 32 bits and cause strange white noise that abruptly stops intermittently (at the end of a frame).
|
||||
// The simple fix of course is to do intermediate computations in 64 bits.
|
||||
// The simple fix of course is to do intermediate computations in 64 bits, but we additionally use saturating arithmetic.
|
||||
// These considerations are not in the original FLAC spec, but have been added to the IETF standard: https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-03#appendix-A.3
|
||||
sample += static_cast<i64>(coefficients[t]) * static_cast<i64>(decoded[i - t - 1]);
|
||||
sample.saturating_add(Checked<i64>::saturating_mul(static_cast<i64>(coefficients[t]), static_cast<i64>(decoded[i - t - 1])));
|
||||
}
|
||||
decoded[i] += sample >> lpc_shift;
|
||||
decoded[i] += sample.value() >> lpc_shift;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
Loading…
Reference in a new issue