diff options
author | Alex Loiko <aleloi@webrtc.org> | 2018-02-16 10:42:48 +0100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2018-02-16 10:46:48 +0000 |
commit | 6df09f6f6a7daf5b6708081f1fb66e711186a306 (patch) | |
tree | a349b4d2b0ba15dac8c231490dde86f645a68931 /common_audio | |
parent | e4be6dad656a36165534b520e4888eb1717dced3 (diff) | |
download | webrtc-6df09f6f6a7daf5b6708081f1fb66e711186a306.tar.gz |
Add decibel conversion functions to //common_audio:common_audio
The functions replace some existing code and will be used in the
the new AutomaticGainController.
Bug: webrtc:7949
Change-Id: I9a32132d4a4699a507b8548a2eac10972a2f3fd6
Reviewed-on: https://webrtc-review.googlesource.com/53141
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Alex Loiko <aleloi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22045}
Diffstat (limited to 'common_audio')
-rw-r--r-- | common_audio/audio_util_unittest.cc | 127 | ||||
-rw-r--r-- | common_audio/include/audio_util.h | 28 |
2 files changed, 110 insertions, 45 deletions
diff --git a/common_audio/audio_util_unittest.cc b/common_audio/audio_util_unittest.cc index 7af3c36960..230669ed1e 100644 --- a/common_audio/audio_util_unittest.cc +++ b/common_audio/audio_util_unittest.cc @@ -9,6 +9,8 @@ */ #include "common_audio/include/audio_util.h" + +#include "rtc_base/arraysize.h" #include "test/gmock.h" #include "test/gtest.h" #include "typedefs.h" // NOLINT(build/include) @@ -26,84 +28,121 @@ void ExpectArraysEq(const int16_t* ref, const int16_t* test, size_t length) { void ExpectArraysEq(const float* ref, const float* test, size_t length) { for (size_t i = 0; i < length; ++i) { - EXPECT_FLOAT_EQ(ref[i], test[i]); + EXPECT_NEAR(ref[i], test[i], 0.01f); } } TEST(AudioUtilTest, FloatToS16) { - const size_t kSize = 9; - const float kInput[kSize] = {0.f, - 0.4f / 32767.f, - 0.6f / 32767.f, - -0.4f / 32768.f, - -0.6f / 32768.f, - 1.f, - -1.f, - 1.1f, - -1.1f}; - const int16_t kReference[kSize] = {0, 0, 1, 0, -1, - 32767, -32768, 32767, -32768}; + static constexpr float kInput[] = {0.f, + 0.4f / 32767.f, + 0.6f / 32767.f, + -0.4f / 32768.f, + -0.6f / 32768.f, + 1.f, + -1.f, + 1.1f, + -1.1f}; + static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, + 32767, -32768, 32767, -32768}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); int16_t output[kSize]; FloatToS16(kInput, kSize, output); ExpectArraysEq(kReference, output, kSize); } TEST(AudioUtilTest, S16ToFloat) { - const size_t kSize = 7; - const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768}; - const float kReference[kSize] = { + static constexpr int16_t kInput[] = {0, 1, -1, 16384, -16384, 32767, -32768}; + static constexpr float kReference[] = { 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); float output[kSize]; S16ToFloat(kInput, kSize, output); ExpectArraysEq(kReference, output, kSize); } TEST(AudioUtilTest, FloatS16ToS16) { - const size_t kSize = 7; - const float kInput[kSize] = {0.f, 0.4f, 0.5f, -0.4f, - -0.5f, 32768.f, -32769.f}; - const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768}; + static constexpr float kInput[] = {0.f, 0.4f, 0.5f, -0.4f, + -0.5f, 32768.f, -32769.f}; + static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, 32767, -32768}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); int16_t output[kSize]; FloatS16ToS16(kInput, kSize, output); ExpectArraysEq(kReference, output, kSize); } TEST(AudioUtilTest, FloatToFloatS16) { - const size_t kSize = 9; - const float kInput[kSize] = {0.f, - 0.4f / 32767.f, - 0.6f / 32767.f, - -0.4f / 32768.f, - -0.6f / 32768.f, - 1.f, - -1.f, - 1.1f, - -1.1f}; - const float kReference[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f, - 32767.f, -32768.f, 36043.7f, -36044.8f}; + static constexpr float kInput[] = {0.f, + 0.4f / 32767.f, + 0.6f / 32767.f, + -0.4f / 32768.f, + -0.6f / 32768.f, + 1.f, + -1.f, + 1.1f, + -1.1f}; + static constexpr float kReference[] = { + 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); float output[kSize]; FloatToFloatS16(kInput, kSize, output); ExpectArraysEq(kReference, output, kSize); } TEST(AudioUtilTest, FloatS16ToFloat) { - const size_t kSize = 9; - const float kInput[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f, - 32767.f, -32768.f, 36043.7f, -36044.8f}; - const float kReference[kSize] = {0.f, - 0.4f / 32767.f, - 0.6f / 32767.f, - -0.4f / 32768.f, - -0.6f / 32768.f, - 1.f, - -1.f, - 1.1f, - -1.1f}; + static constexpr float kInput[] = { + 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f}; + static constexpr float kReference[] = {0.f, + 0.4f / 32767.f, + 0.6f / 32767.f, + -0.4f / 32768.f, + -0.6f / 32768.f, + 1.f, + -1.f, + 1.1f, + -1.1f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); float output[kSize]; FloatS16ToFloat(kInput, kSize, output); ExpectArraysEq(kReference, output, kSize); } +TEST(AudioUtilTest, DbfsToFloatS16) { + static constexpr float kInput[] = {-90.f, -70.f, -30.f, -20.f, -10.f, + -5.f, -1.f, 0.f, 1.f}; + static constexpr float kReference[] = { + 1.036215186f, 10.36215115f, 1036.215088f, 3276.800049f, 10362.15137f, + 18426.80078f, 29204.51172f, 32768.f, 36766.30078f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + float output[kSize]; + for (size_t i = 0; i < kSize; ++i) { + output[i] = DbfsToFloatS16(kInput[i]); + } + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, FloatS16ToDbfs) { + static constexpr float kInput[] = {1.036215143f, 10.36215143f, 1036.215143f, + 3276.8f, 10362.151436f, 18426.800543f, + 29204.51074f, 32768.0f, 36766.30071f}; + + static constexpr float kReference[] = { + -90.f, -70.f, -30.f, -20.f, -10.f, -5.f, -1.f, 0.f, 0.9999923706f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + + float output[kSize]; + for (size_t i = 0; i < kSize; ++i) { + output[i] = FloatS16ToDbfs(kInput[i]); + } + ExpectArraysEq(kReference, output, kSize); +} + TEST(AudioUtilTest, InterleavingStereo) { const int16_t kInterleaved[] = {2, 3, 4, 9, 8, 27, 16, 81}; const size_t kSamplesPerChannel = 4; diff --git a/common_audio/include/audio_util.h b/common_audio/include/audio_util.h index b9e1b26b0d..e4ea9a1a33 100644 --- a/common_audio/include/audio_util.h +++ b/common_audio/include/audio_util.h @@ -12,8 +12,9 @@ #define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ #include <algorithm> -#include <limits> +#include <cmath> #include <cstring> +#include <limits> #include "rtc_base/checks.h" #include "typedefs.h" // NOLINT(build/include) @@ -26,6 +27,10 @@ typedef std::numeric_limits<int16_t> limits_int16; // S16: int16_t [-32768, 32767] // Float: float [-1.0, 1.0] // FloatS16: float [-32768.0, 32767.0] +// Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0] +// The ratio conversion functions use this naming convention: +// Ratio: float (0, +inf) +// Db: float (-inf, +inf) static inline int16_t FloatToS16(float v) { if (v > 0) return v >= 1 ? limits_int16::max() @@ -65,6 +70,27 @@ void FloatS16ToS16(const float* src, size_t size, int16_t* dest); void FloatToFloatS16(const float* src, size_t size, float* dest); void FloatS16ToFloat(const float* src, size_t size, float* dest); +inline float DbToRatio(float v) { + return std::pow(10.0f, v / 20.0f); +} + +inline float DbfsToFloatS16(float v) { + static constexpr float kMaximumAbsFloatS16 = -limits_int16::min(); + return DbToRatio(v) * kMaximumAbsFloatS16; +} + +inline float FloatS16ToDbfs(float v) { + RTC_DCHECK_GE(v, 0); + + // kMinDbfs is equal to -20.0 * log10(-limits_int16::min()) + static constexpr float kMinDbfs = -90.30899869919436f; + if (v <= 1.0f) { + return kMinDbfs; + } + // Equal to 20 * log10(v / (-limits_int16::min())) + return 20.0f * std::log10(v) + kMinDbfs; +} + // Copy audio from |src| channels to |dest| channels unless |src| and |dest| // point to the same address. |src| and |dest| must have the same number of // channels, and there must be sufficient space allocated in |dest|. |