Chromium Code Reviews| Index: webrtc/modules/audio_processing/repetition_detector_unittest.cc |
| diff --git a/webrtc/modules/audio_processing/repetition_detector_unittest.cc b/webrtc/modules/audio_processing/repetition_detector_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fc75e287f5260c5569c5f9946adcb2e9a5de9986 |
| --- /dev/null |
| +++ b/webrtc/modules/audio_processing/repetition_detector_unittest.cc |
| @@ -0,0 +1,345 @@ |
| +/* |
| + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| + |
| +#include <map> |
| + |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "webrtc/modules/audio_processing/repetition_detector.h" |
| + |
| +namespace webrtc { |
| + |
| +class RepetitionDetectorTest : public RepetitionDetector, |
|
hlundin-webrtc
2015/08/31 13:46:46
This class is both a test fixture for the class un
minyue-webrtc
2015/09/01 10:21:48
Ok. I can do that.
|
| + public ::testing::Test { |
| + public: |
| + struct ExpectedCount { |
| + int id_; |
| + int count_; |
| + }; |
| + |
| + protected: |
| + void ResetRepetitionPattern(const Pattern* patterns, size_t num_patterns) { |
|
minyue-webrtc
2015/08/28 14:27:00
the diff is not smart enough to align the two vers
|
| + ClearRepetitionPatterns(); |
| + RegisterRepetitionPatterns(patterns, num_patterns); |
| + } |
| + |
| + void Verify(const ExpectedCount* expected_counts, size_t num_patterns, |
| + const int16_t* tester, size_t samples_per_channel, |
| + int sample_rate_hz, size_t channels = 1) { |
| + Verify(expected_counts, num_patterns, tester, sizeof(int16_t), |
| + samples_per_channel, sample_rate_hz, channels); |
| + } |
| + void VerifyStereo(const ExpectedCount* expected_counts, size_t num_patterns, |
| + const int16_t* tester, size_t samples_per_channel, |
| + int sample_rate_hz) { |
| + VerifyStereo(expected_counts, num_patterns, tester, sizeof(int16_t), |
| + samples_per_channel, sample_rate_hz); |
| + } |
| + |
| + void ReportRepetition(int id) override { |
| + auto it = counters_.find(id); |
| + if (it == counters_.end()) { |
| + counters_[id] = 0; |
| + } |
| + counters_[id]++; |
| + } |
| + |
| + int GetCount(int id) { |
| + auto it = counters_.find(id); |
| + if (it == counters_.end()) { |
| + return 0; |
| + } |
| + return counters_[id]; |
| + } |
| + |
| + void ResetCounters() { |
| + for (auto& item : counters_) { |
| + item.second = 0; |
| + } |
| + } |
| + |
| + private: |
| + // Verify if the counts on the repetition patterns match expectation after |
| + // injecting a signal. No reset on the counters |
| + void Verify(const ExpectedCount* expected_counts, int num_patterns, |
| + const void* tester, size_t bytes_per_sample, |
| + size_t samples_per_channel, int sample_rate_hz, |
| + size_t channels) { |
| + Detect(tester, bytes_per_sample * channels, samples_per_channel, |
| + sample_rate_hz); |
| + int id; |
| + for (int idx = 0; idx < num_patterns; idx++) { |
| + id = expected_counts[idx].id_; |
| + EXPECT_EQ(expected_counts[idx].count_, GetCount(id)) << |
| + "Repetition #" << id << " counted wrong."; |
| + } |
| + } |
| + |
| + void VerifyStereo(const ExpectedCount* expected_counts, int num_patterns, |
| + const void* tester, size_t bytes_per_sample, |
| + size_t samples_per_channel, int sample_rate_hz) { |
| + const size_t kNumChannels = 2; |
| + |
| + // Get memory to store interleaved stereo. |
| + std::unique_ptr<char[]> tester_stereo( |
| + new char[samples_per_channel * bytes_per_sample * kNumChannels]); |
| + size_t tester_stereo_index = 0; |
| + const char* tester_pointer = reinterpret_cast<const char*>(tester); |
| + |
| + for (size_t idx = 0; idx < samples_per_channel; ++idx) { |
| + for (size_t channel = 0; channel < kNumChannels; ++channel) { |
| + memcpy(&tester_stereo[tester_stereo_index], tester_pointer, |
| + bytes_per_sample); |
| + tester_stereo_index += bytes_per_sample; |
| + } |
| + tester_pointer += bytes_per_sample; |
| + } |
| + |
| + Verify(expected_counts, num_patterns, tester_stereo.get(), bytes_per_sample, |
| + samples_per_channel, sample_rate_hz, kNumChannels); |
| + } |
| + |
| + std::map<int, size_t> counters_; |
| +}; |
| + |
| +TEST_F(RepetitionDetectorTest, Basic) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3} |
| + }; |
| + const int16_t kTestSignal[] = {1, 2, 3, 1, 2, 3}; |
| + const ExpectedCount kExpectedCounts_1[] = { |
| + {0, 1} |
| + }; |
| + const ExpectedCount kExpectedCounts_2[] = { |
| + {0, 1} |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts_1, sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + Verify(kExpectedCounts_2, sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts_1, |
| + sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), kTestSignal, |
| + sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + VerifyStereo(kExpectedCounts_2, |
| + sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), kTestSignal, |
| + sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, StereoOutOfSync) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3} |
| + }; |
| + const int16_t kTestSignal[] = { |
| + 1, 1, |
| + 2, 2, |
| + 3, 3, |
| + 1, 1, |
| + 2, 2, |
| + 3, 1}; |
| + const ExpectedCount kExpectedCounts[] = { |
| + {0, 0} |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t) / 2, |
| + kSampleRateHz, 2); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, IncompletePattern) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3}, |
| + }; |
| + const int16_t kTestSignal[] = {1, 2, 1, 2, 3, 1, 2, 3}; |
| + const ExpectedCount kExpectedCounts[] = { |
| + {0, 1}, |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), |
| + kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, PatternLongerThanFrame) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 6, 6}, |
| + }; |
| + const int16_t kTestSignal_1[] = {1, 2, 3, 4, 5}; |
| + const int16_t kTestSignal_2[] = {6, 1, 2, 3, 4, 5, 6}; |
| + const ExpectedCount kExpectedCounts_1[] = { |
| + {0, 0}, |
| + }; |
| + const ExpectedCount kExpectedCounts_2[] = { |
| + {0, 1}, |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts_1, sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), |
| + kTestSignal_1, sizeof(kTestSignal_1) / sizeof(int16_t), |
| + kSampleRateHz); |
| + Verify(kExpectedCounts_2, sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), |
| + kTestSignal_2, sizeof(kTestSignal_2) / sizeof(int16_t), |
| + kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts_1, |
| + sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), kTestSignal_1, |
| + sizeof(kTestSignal_1) / sizeof(int16_t), kSampleRateHz); |
| + VerifyStereo(kExpectedCounts_2, |
| + sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), kTestSignal_2, |
| + sizeof(kTestSignal_2) / sizeof(int16_t), kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, TwoPatterns) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3}, |
| + {1, 4, 4}, |
| + }; |
| + const int16_t kTestSignal[] = {1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4}; |
| + const ExpectedCount kExpectedCounts[] = { |
| + // 1,2,3 belongs to both patterns. |
| + {0, 1}, |
| + {1, 1} |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), |
| + kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts, |
| + sizeof(kExpectedCounts) / sizeof(ExpectedCount), kTestSignal, |
| + sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, NestedPatterns) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3}, |
| + {1, 6, 6}, // When a triplet repeated 3 times, this is triggered. |
| + }; |
| + const int16_t kTestSignal[] = {1, 2, 3, 1, 2, 3}; |
| + const ExpectedCount kExpectedCounts_1[] = { |
| + {0, 1}, |
| + {1, 0} |
| + }; |
| + const ExpectedCount kExpectedCounts_2[] = { |
| + {0, 1}, |
| + {1, 1} |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts_1, sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + Verify(kExpectedCounts_2, sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts_1, |
| + sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), kTestSignal, |
| + sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + VerifyStereo(kExpectedCounts_2, |
| + sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), kTestSignal, |
| + sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, NotFullLengthPattern) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 4, 3}, |
| + }; |
| + const int16_t kTestSignal[] = {1, 2, 3, -1, 1, 2, 3, -2}; |
| + const ExpectedCount kExpectedCounts[] = { |
| + {0, 1}, |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts, sizeof(kExpectedCounts) / sizeof(ExpectedCount), |
| + kTestSignal, sizeof(kTestSignal) / sizeof(int16_t), |
| + kSampleRateHz); |
| +} |
| + |
| +TEST_F(RepetitionDetectorTest, ZerosCountOrNot) { |
| + // To make the test signal most obvious, we choose a special sample rate. |
| + const int kSampleRateHz = 1000; |
| + |
| + const Pattern kRepetitionPatterns[] = { |
| + // id, look_back_ms, min_length_ms |
| + {0, 3, 3}, |
| + }; |
| + const int16_t kTestSignal_1[] = {0, 0, 0, 0, 0, 0}; |
| + const int16_t kTestSignal_2[] = {0, 1, 2, 0, 1, 2}; |
| + const ExpectedCount kExpectedCounts_1[] = { |
| + // Full zeros won't count. |
| + {0, 0}, |
| + }; |
| + const ExpectedCount kExpectedCounts_2[] = { |
| + // Partial zero will count. |
| + {0, 1}, |
| + }; |
| + |
| + ResetRepetitionPattern(kRepetitionPatterns, |
| + sizeof(kRepetitionPatterns) / sizeof(Pattern)); |
| + Verify(kExpectedCounts_1, sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), |
| + kTestSignal_1, sizeof(kTestSignal_1) / sizeof(int16_t), |
| + kSampleRateHz); |
| + Verify(kExpectedCounts_2, sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), |
| + kTestSignal_2, sizeof(kTestSignal_2) / sizeof(int16_t), |
| + kSampleRateHz); |
| + ResetCounters(); |
| + VerifyStereo(kExpectedCounts_1, |
| + sizeof(kExpectedCounts_1) / sizeof(ExpectedCount), kTestSignal_1, |
| + sizeof(kTestSignal_1) / sizeof(int16_t), kSampleRateHz); |
| + VerifyStereo(kExpectedCounts_2, |
| + sizeof(kExpectedCounts_2) / sizeof(ExpectedCount), kTestSignal_2, |
| + sizeof(kTestSignal_2) / sizeof(int16_t), kSampleRateHz); |
| +} |
| + |
| +} // namespace webrtc |