blob: de59328971652a299a44290552375735a723ff05 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/media/audio/lib/processing/filter.h"
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
namespace media_audio {
namespace {
TEST(LinearFilterTest, Construction) {
{
auto source_rate = 48000;
auto dest_rate = 48000;
int32_t expected_num_frac_bits = Fixed::Format::FractionalBits; // default
LinearFilter filter(source_rate, dest_rate);
auto expected_side_length = 1 << expected_num_frac_bits;
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.num_frac_bits(), expected_num_frac_bits);
EXPECT_EQ(filter.side_length(), expected_side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 1.0);
}
{
auto source_rate = 32000;
auto dest_rate = 96000;
int32_t expected_num_frac_bits = Fixed::Format::FractionalBits; // default
LinearFilter filter(source_rate, dest_rate);
auto expected_side_length = 1 << expected_num_frac_bits;
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.num_frac_bits(), expected_num_frac_bits);
EXPECT_EQ(filter.side_length(), expected_side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 3.0);
}
{
auto source_rate = 96000;
auto dest_rate = 48000;
int32_t num_frac_bits = 6;
LinearFilter filter(source_rate, dest_rate, num_frac_bits);
auto expected_side_length = 1 << num_frac_bits;
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.num_frac_bits(), num_frac_bits);
EXPECT_EQ(filter.side_length(), expected_side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 0.5);
}
}
TEST(SincFilterTest, Construction) {
{
auto source_rate = 48000;
auto dest_rate = 48000;
int32_t expected_num_frac_bits = Fixed::Format::FractionalBits; // default
auto num_taps = SincFilter::kSideTaps; // default
auto side_length = (num_taps + 1) << expected_num_frac_bits; // default
SincFilter filter(source_rate, dest_rate);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.num_frac_bits(), expected_num_frac_bits);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 1.0);
}
{
auto source_rate = 32000;
auto dest_rate = 96000;
int32_t expected_num_frac_bits = Fixed::Format::FractionalBits; // default
auto num_taps = SincFilter::kSideTaps; // default
auto side_length = (num_taps + 1) << expected_num_frac_bits; // default
SincFilter filter(source_rate, dest_rate);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_EQ(filter.num_frac_bits(), expected_num_frac_bits);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 3.0);
}
{
auto source_rate = 96000;
auto dest_rate = 48000;
auto num_taps = 9;
int32_t num_frac_bits = Fixed::Format::FractionalBits;
auto side_length = (num_taps + 1) << num_frac_bits;
SincFilter filter(source_rate, dest_rate, side_length);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_EQ(filter.num_frac_bits(), num_frac_bits);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 0.5);
}
{
auto source_rate = 16000;
auto dest_rate = 96000;
int32_t num_frac_bits = 4;
auto num_taps = 10;
auto side_length = (num_taps + 1) << num_frac_bits;
SincFilter filter(source_rate, dest_rate, side_length, num_frac_bits);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_EQ(filter.num_frac_bits(), num_frac_bits);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 6.0);
}
}
TEST(LinearFilterTest, FilterCoefficients) {
auto source_rate = 48000;
auto dest_rate = 48000;
int32_t num_frac_bits = 6;
LinearFilter filter(source_rate, dest_rate, num_frac_bits);
float frac_size = static_cast<float>(1 << num_frac_bits);
int64_t expected_side_length = static_cast<int64_t>(frac_size);
EXPECT_EQ(filter.side_length(), expected_side_length);
for (auto idx = 0; idx < expected_side_length; ++idx) {
EXPECT_FLOAT_EQ(filter[idx], (frac_size - static_cast<float>(idx)) / frac_size);
}
}
TEST(SincFilterTest, FilterCoefficients_Unity) {
auto source_rate = 48000;
auto dest_rate = 48000;
auto num_taps = 10;
int32_t num_frac_bits = 4;
auto side_length = ((num_taps + 1) << num_frac_bits);
SincFilter filter(source_rate, dest_rate, side_length, num_frac_bits);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_EQ(filter.num_frac_bits(), num_frac_bits);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 1.0);
EXPECT_FLOAT_EQ(filter[0], 1.0f);
auto frac_size = 1 << num_frac_bits;
auto frac_half = frac_size >> 1;
auto idx = frac_size;
for (auto tap = 1; tap <= num_taps; ++tap, idx += frac_size) {
EXPECT_FLOAT_EQ(filter[idx], 0.0f) << "idx: " << idx;
if (tap & 1) {
EXPECT_GT(filter[idx - frac_half], 0.0f);
EXPECT_LT(filter[idx + frac_half], 0.0f);
} else {
EXPECT_LT(filter[idx - frac_half], 0.0f);
EXPECT_GT(filter[idx + frac_half], 0.0f);
}
}
}
TEST(SincFilterTest, FilterCoefficients_DownSample) {
auto source_rate = 48000;
auto dest_rate = 24000;
auto num_taps = 9;
int32_t num_frac_bits = 4;
auto side_length = ((num_taps + 1) << num_frac_bits);
SincFilter filter(source_rate, dest_rate, side_length, num_frac_bits);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 0.5);
}
TEST(SincFilterTest, FilterCoefficients_UpSample) {
auto source_rate = 24000;
auto dest_rate = 48000;
auto num_taps = 8;
int32_t num_frac_bits = 3;
auto side_length = ((num_taps + 1) << num_frac_bits);
SincFilter filter(source_rate, dest_rate, side_length, num_frac_bits);
EXPECT_EQ(filter.source_rate(), source_rate);
EXPECT_EQ(filter.dest_rate(), dest_rate);
EXPECT_EQ(filter.side_length(), side_length);
EXPECT_DOUBLE_EQ(filter.rate_conversion_ratio(), 2.0);
}
TEST(LinearFilterTest, ComputeSample) {
auto source_rate = 48000;
auto dest_rate = 48000;
int32_t num_frac_bits = 4;
LinearFilter filter(source_rate, dest_rate, num_frac_bits);
auto frac_size = 1 << num_frac_bits;
auto frac_half = frac_size >> 1;
auto frac_quarter = frac_half >> 1;
float data[] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
EXPECT_FLOAT_EQ(filter.ComputeSample(0, &data[1]), data[1]);
EXPECT_FLOAT_EQ(filter.ComputeSample(frac_half, &data[2]), (data[2] + data[3]) / 2.0f);
EXPECT_FLOAT_EQ(filter.ComputeSample(frac_half + frac_quarter, &data[3]),
(data[3] + 3.0f * data[4]) / 4.0f);
}
void ValidateSincComputeSample(int32_t source_rate, int32_t dest_rate, int64_t side_length,
int32_t num_frac_bits) {
SincFilter filter(source_rate, dest_rate, side_length, num_frac_bits);
// If values outside indices [1,33] are used in `ComputeSample`, data compares will fail.
float data[] = {
999999.0f, //
0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, //
0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, //
1.7f, //
1.8f, 1.9f, 2.f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, //
2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, //
-999999.0f,
};
auto frac_size = 1 << num_frac_bits;
auto frac_half = frac_size >> 1;
auto frac_quarter = frac_half >> 1;
auto frac_three_quarters = frac_size - frac_quarter;
// These values should be precisely equal
SCOPED_TRACE("Compute(17.0) == [17]");
EXPECT_FLOAT_EQ(filter.ComputeSample(0, &data[17]), data[17]);
// These values are only calculated to a specific quality tolerance (related to `side_length` and
// `num_frac_bits`), so the only SAFE things to do here are rough comparisons.
SCOPED_TRACE("[17] < Compute(17.25)");
EXPECT_LT(data[17], filter.ComputeSample(frac_half, &data[17]));
SCOPED_TRACE("Compare 16.5 < 16.75");
EXPECT_LT(filter.ComputeSample(frac_half, &data[16]),
filter.ComputeSample(frac_three_quarters, &data[16]));
SCOPED_TRACE("Compare 17.25 < 17.5");
EXPECT_LT(filter.ComputeSample(frac_quarter, &data[17]),
filter.ComputeSample(frac_half, &data[17]));
}
TEST(SincFilterTest, ComputeSample) {
// Unity rate ratio
auto source_rate = 48000;
auto dest_rate = 48000;
auto num_taps = 2;
int32_t num_frac_bits = 2;
auto side_length = (num_taps + 1) << num_frac_bits;
ValidateSincComputeSample(source_rate, dest_rate, side_length, num_frac_bits);
// Up-sampling rate ratio
source_rate = 24000;
dest_rate = 48000;
num_taps = 3;
num_frac_bits = 2;
side_length = (num_taps + 1) << num_frac_bits;
ValidateSincComputeSample(source_rate, dest_rate, side_length, num_frac_bits);
// Down-sampling rate ratio
source_rate = 48000;
dest_rate = 24000;
num_taps = 3;
num_frac_bits = 3;
side_length = ((num_taps + 1) << num_frac_bits) * 2;
ValidateSincComputeSample(source_rate, dest_rate, side_length, num_frac_bits);
source_rate = 148500; // rates don't change results calculated in ValidateSincComputeSample
dest_rate = 36000;
num_taps = 3;
num_frac_bits = 3;
// Width is chosen to be non-integral and to reference a final data element that is right at the
// edge of the data populated in ValidateSincComputeSample (downsampling of about 4.125:1).
side_length = 132;
ValidateSincComputeSample(source_rate, dest_rate, side_length, num_frac_bits);
}
} // namespace
} // namespace media_audio