173 lines
6.9 KiB
C++
173 lines
6.9 KiB
C++
|
|
/*
|
||
|
|
* Copyright (C) 2022 The Android Open Source Project
|
||
|
|
*
|
||
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
* you may not use this file except in compliance with the License.
|
||
|
|
* You may obtain a copy of the License at
|
||
|
|
*
|
||
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
* See the License for the specific language governing permissions and
|
||
|
|
* limitations under the License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
// #define LOG_NDEBUG 0
|
||
|
|
#define LOG_TAG "audio_utils_mel_aggregator_tests"
|
||
|
|
|
||
|
|
#include <audio_utils/MelAggregator.h>
|
||
|
|
|
||
|
|
#include <gtest/gtest.h>
|
||
|
|
#include <gmock/gmock.h>
|
||
|
|
|
||
|
|
namespace android::audio_utils {
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
constexpr int32_t kTestPortId = 1;
|
||
|
|
constexpr float kFloatError = 0.1f;
|
||
|
|
constexpr float kMelFloatError = 0.0001f;
|
||
|
|
|
||
|
|
/** Value used for CSD calculation. 3 MELs with this value will cause a change of 1% in CSD. */
|
||
|
|
constexpr float kCustomMelDbA = 107.f;
|
||
|
|
|
||
|
|
using ::testing::ElementsAre;
|
||
|
|
using ::testing::Pointwise;
|
||
|
|
using ::testing::FloatNear;
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, ResetAggregator) {
|
||
|
|
MelAggregator aggregator{100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(1, {10.f, 10.f}, 0));
|
||
|
|
aggregator.reset(1.f, {CsdRecord(1, 1, 1.f, 1.f)});
|
||
|
|
|
||
|
|
EXPECT_EQ(aggregator.getCachedMelRecordsSize(), size_t{0});
|
||
|
|
EXPECT_EQ(aggregator.getCsd(), 1.f);
|
||
|
|
EXPECT_EQ(aggregator.getCsdRecordsSize(), size_t{1});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, AggregateValuesFromDifferentStreams) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {10.f, 10.f},
|
||
|
|
/* timestamp */0));
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {10.f, 10.f},
|
||
|
|
/* timestamp */0));
|
||
|
|
|
||
|
|
ASSERT_EQ(aggregator.getCachedMelRecordsSize(), size_t{1});
|
||
|
|
aggregator.foreachCachedMel([](const MelRecord &record) {
|
||
|
|
EXPECT_EQ(record.portId, kTestPortId);
|
||
|
|
EXPECT_THAT(record.mels, Pointwise(FloatNear(kFloatError), {13.f, 13.f}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, AggregateWithOlderValues) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {1.f, 1.f},
|
||
|
|
/* timestamp */1));
|
||
|
|
// second mel array contains values that are older than the first entry
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {2.f, 2.f, 2.f},
|
||
|
|
/* timestamp */0));
|
||
|
|
|
||
|
|
ASSERT_EQ(aggregator.getCachedMelRecordsSize(), size_t{1});
|
||
|
|
aggregator.foreachCachedMel([](const MelRecord &record) {
|
||
|
|
EXPECT_EQ(record.portId, kTestPortId);
|
||
|
|
EXPECT_THAT(record.mels, Pointwise(FloatNear(kFloatError), {2.f, 4.5f, 4.5f}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, AggregateWithNewerValues) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {1.f, 1.f},
|
||
|
|
/* timestamp */1));
|
||
|
|
// second mel array contains values that are older than the first entry
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {2.f, 2.f},
|
||
|
|
/* timestamp */2));
|
||
|
|
|
||
|
|
ASSERT_EQ(aggregator.getCachedMelRecordsSize(), size_t{1});
|
||
|
|
aggregator.foreachCachedMel([](const MelRecord &record) {
|
||
|
|
EXPECT_EQ(record.portId, kTestPortId);
|
||
|
|
EXPECT_THAT(record.mels, Pointwise(FloatNear(kFloatError), {1.f, 4.5f, 2.f}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, AggregateWithNonOverlappingValues) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {1.f, 1.f},
|
||
|
|
/* timestamp */0));
|
||
|
|
// second mel array contains values that are older than the first entry
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {1.f, 1.f},
|
||
|
|
/* timestamp */2));
|
||
|
|
|
||
|
|
ASSERT_EQ(aggregator.getCachedMelRecordsSize(), size_t{2});
|
||
|
|
aggregator.foreachCachedMel([](const MelRecord &record) {
|
||
|
|
EXPECT_EQ(record.portId, kTestPortId);
|
||
|
|
EXPECT_THAT(record.mels, Pointwise(FloatNear(kFloatError), {1.f, 1.f}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, CheckMelIntervalSplit) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 100};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {3.f, 3.f}, /* timestamp */1));
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId, {3.f, 3.f, 3.f, 3.f},
|
||
|
|
/* timestamp */0));
|
||
|
|
|
||
|
|
ASSERT_EQ(aggregator.getCachedMelRecordsSize(), size_t{1});
|
||
|
|
|
||
|
|
aggregator.foreachCachedMel([](const MelRecord &record) {
|
||
|
|
EXPECT_EQ(record.portId, kTestPortId);
|
||
|
|
EXPECT_THAT(record.mels, Pointwise(FloatNear(kFloatError), {3.f, 6.f, 6.f, 3.f}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, CsdRollingWindowDiscardsOldElements) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 3};
|
||
|
|
|
||
|
|
aggregator.aggregateAndAddNewMelRecord(MelRecord(kTestPortId,
|
||
|
|
std::vector<float>(3, kCustomMelDbA),
|
||
|
|
/* timestamp */0));
|
||
|
|
float csdValue = aggregator.getCsd();
|
||
|
|
auto records = aggregator.aggregateAndAddNewMelRecord(
|
||
|
|
MelRecord(kTestPortId, std::vector<float>(3, kCustomMelDbA), /* timestamp */3));
|
||
|
|
|
||
|
|
EXPECT_EQ(records.size(), size_t{2}); // new record and record to remove
|
||
|
|
EXPECT_TRUE(records[0].value * records[1].value < 0.f);
|
||
|
|
EXPECT_EQ(csdValue, aggregator.getCsd());
|
||
|
|
EXPECT_EQ(aggregator.getCsdRecordsSize(), size_t{1});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, CsdReaches100PercWith107dB) {
|
||
|
|
MelAggregator aggregator{/* csdWindowSeconds */ 300};
|
||
|
|
|
||
|
|
// 287s of 107dB should produce at least 100% CSD
|
||
|
|
auto records = aggregator.aggregateAndAddNewMelRecord(
|
||
|
|
MelRecord(kTestPortId, std::vector<float>(288, kCustomMelDbA), /* timestamp */0));
|
||
|
|
|
||
|
|
// each record should have a CSD value between 1% and 2%
|
||
|
|
EXPECT_GE(records.size(), size_t{50});
|
||
|
|
EXPECT_GE(aggregator.getCsd(), 1.f);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(MelAggregatorTest, CsdReaches100PercWith80dB) {
|
||
|
|
constexpr int64_t seconds40h = 40*3600;
|
||
|
|
MelAggregator aggregator{seconds40h};
|
||
|
|
|
||
|
|
// 40h of 80dB should produce (near) exactly 100% CSD
|
||
|
|
auto records = aggregator.aggregateAndAddNewMelRecord(
|
||
|
|
MelRecord(kTestPortId,
|
||
|
|
std::vector<float>(seconds40h, 80.0f),
|
||
|
|
/* timestamp */0));
|
||
|
|
|
||
|
|
// each record should have a CSD value between 1% and 2%
|
||
|
|
EXPECT_GE(records.size(), size_t{50});
|
||
|
|
EXPECT_NEAR(aggregator.getCsd(), 1.f, kMelFloatError);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
} // namespace android
|