diff options
author | kleines Filmröllchen <malu.bertsch@gmail.com> | 2021-08-27 23:47:09 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-09-12 23:38:57 +0200 |
commit | 152ec28da0d1a51ade18fe6799a34ac9b7aa07b0 (patch) | |
tree | 540e62552da0d9bb767e566f8951f081009e136a /Userland/Libraries/LibAudio/Buffer.h | |
parent | 2909c3a931439d0cbed3e4599d9eed47a6fdb446 (diff) | |
download | serenity-152ec28da0d1a51ade18fe6799a34ac9b7aa07b0.zip |
Audio: Change how volume works
Across the entire audio system, audio now works in 0-1 terms instead of
0-100 as before. Therefore, volume is now a double instead of an int.
The master volume of the AudioServer changes smoothly through a
FadingProperty, preventing clicks. Finally, volume computations are done
with logarithmic scaling, which is more natural for the human ear.
Note that this could be 4-5 different commits, but as they change each
other's code all the time, it makes no sense to split them up.
Diffstat (limited to 'Userland/Libraries/LibAudio/Buffer.h')
-rw-r--r-- | Userland/Libraries/LibAudio/Buffer.h | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/Userland/Libraries/LibAudio/Buffer.h b/Userland/Libraries/LibAudio/Buffer.h index ebf40af0bd..1a518784e7 100644 --- a/Userland/Libraries/LibAudio/Buffer.h +++ b/Userland/Libraries/LibAudio/Buffer.h @@ -8,6 +8,7 @@ #pragma once #include <AK/ByteBuffer.h> +#include <AK/Math.h> #include <AK/MemoryStream.h> #include <AK/String.h> #include <AK/Types.h> @@ -16,25 +17,32 @@ #include <string.h> namespace Audio { +using namespace AK::Exponentials; + +// Constants for logarithmic volume. See Frame::operator* +// Corresponds to 60dB +constexpr double DYNAMIC_RANGE = 1000; +constexpr double VOLUME_A = 1 / DYNAMIC_RANGE; +double const VOLUME_B = log(DYNAMIC_RANGE); // A single sample in an audio buffer. // Values are floating point, and should range from -1.0 to +1.0 struct Frame { - Frame() + constexpr Frame() : left(0) , right(0) { } // For mono - Frame(double left) + constexpr Frame(double left) : left(left) , right(left) { } // For stereo - Frame(double left, double right) + constexpr Frame(double left, double right) : left(left) , right(right) { @@ -53,26 +61,54 @@ struct Frame { right = -1; } - void scale(int percent) + // Logarithmic scaling, as audio should ALWAYS do. + // Reference: https://www.dr-lex.be/info-stuff/volumecontrols.html + // We use the curve `factor = a * exp(b * change)`, + // where change is the input fraction we want to change by, + // a = 1/1000, b = ln(1000) = 6.908 and factor is the multiplier used. + // The value 1000 represents the dynamic range in sound pressure, which corresponds to 60 dB(A). + // This is a good dynamic range because it can represent all loudness values from + // 30 dB(A) (barely hearable with background noise) + // to 90 dB(A) (almost too loud to hear and about the reasonable limit of actual sound equipment). + ALWAYS_INLINE Frame& log_multiply(double const change) + { + double factor = VOLUME_A * exp(VOLUME_B * change); + left *= factor; + right *= factor; + return *this; + } + + ALWAYS_INLINE Frame log_multiplied(double const volume_change) + { + Frame new_frame { left, right }; + new_frame.log_multiply(volume_change); + return new_frame; + } + + constexpr Frame& operator*=(double const mult) { - double pct = (double)percent / 100.0; - left *= pct; - right *= pct; + left *= mult; + right *= mult; + return *this; } - // FIXME: This is temporary until we have log scaling - Frame scaled(double fraction) const + constexpr Frame operator*(double const mult) { - return Frame { left * fraction, right * fraction }; + return { left * mult, right * mult }; } - Frame& operator+=(const Frame& other) + constexpr Frame& operator+=(Frame const& other) { left += other.left; right += other.right; return *this; } + constexpr Frame operator+(Frame const& other) + { + return { left + other.left, right + other.right }; + } + double left; double right; }; |