1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/common_audio/sparse_fir_filter.h" 12 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "webrtc/base/arraysize.h" 15 #include "webrtc/base/scoped_ptr.h" 16 #include "webrtc/common_audio/fir_filter.h" 17 18 namespace webrtc { 19 namespace { 20 21 static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f}; 22 static const float kInput[] = 23 {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f}; 24 25 template <size_t N> 26 void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) { 27 EXPECT_EQ(0, memcmp(expected_output, output, sizeof(output))); 28 } 29 30 } // namespace 31 32 TEST(SparseFIRFilterTest, FilterAsIdentity) { 33 const float kCoeff = 1.f; 34 const size_t kNumCoeff = 1; 35 const size_t kSparsity = 3; 36 const size_t kOffset = 0; 37 float output[arraysize(kInput)]; 38 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset); 39 filter.Filter(kInput, arraysize(kInput), output); 40 VerifyOutput(kInput, output); 41 } 42 43 TEST(SparseFIRFilterTest, SameOutputForScalarCoefficientAndDifferentSparsity) { 44 const float kCoeff = 2.f; 45 const size_t kNumCoeff = 1; 46 const size_t kLowSparsity = 1; 47 const size_t kHighSparsity = 7; 48 const size_t kOffset = 0; 49 float low_sparsity_output[arraysize(kInput)]; 50 float high_sparsity_output[arraysize(kInput)]; 51 SparseFIRFilter low_sparsity_filter(&kCoeff, 52 kNumCoeff, 53 kLowSparsity, 54 kOffset); 55 SparseFIRFilter high_sparsity_filter(&kCoeff, 56 kNumCoeff, 57 kHighSparsity, 58 kOffset); 59 low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output); 60 high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output); 61 VerifyOutput(low_sparsity_output, high_sparsity_output); 62 } 63 64 TEST(SparseFIRFilterTest, FilterUsedAsScalarMultiplication) { 65 const float kCoeff = 5.f; 66 const size_t kNumCoeff = 1; 67 const size_t kSparsity = 5; 68 const size_t kOffset = 0; 69 float output[arraysize(kInput)]; 70 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset); 71 filter.Filter(kInput, arraysize(kInput), output); 72 EXPECT_FLOAT_EQ(5.f, output[0]); 73 EXPECT_FLOAT_EQ(20.f, output[3]); 74 EXPECT_FLOAT_EQ(25.f, output[4]); 75 EXPECT_FLOAT_EQ(50.f, output[arraysize(kInput) - 1]); 76 } 77 78 TEST(SparseFIRFilterTest, FilterUsedAsInputShifting) { 79 const float kCoeff = 1.f; 80 const size_t kNumCoeff = 1; 81 const size_t kSparsity = 1; 82 const size_t kOffset = 4; 83 float output[arraysize(kInput)]; 84 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset); 85 filter.Filter(kInput, arraysize(kInput), output); 86 EXPECT_FLOAT_EQ(0.f, output[0]); 87 EXPECT_FLOAT_EQ(0.f, output[3]); 88 EXPECT_FLOAT_EQ(1.f, output[4]); 89 EXPECT_FLOAT_EQ(2.f, output[5]); 90 EXPECT_FLOAT_EQ(6.f, output[arraysize(kInput) - 1]); 91 } 92 93 TEST(SparseFIRFilterTest, FilterUsedAsArbitraryWeighting) { 94 const size_t kSparsity = 2; 95 const size_t kOffset = 1; 96 float output[arraysize(kInput)]; 97 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); 98 filter.Filter(kInput, arraysize(kInput), output); 99 EXPECT_FLOAT_EQ(0.f, output[0]); 100 EXPECT_FLOAT_EQ(0.9f, output[3]); 101 EXPECT_FLOAT_EQ(1.4f, output[4]); 102 EXPECT_FLOAT_EQ(2.4f, output[5]); 103 EXPECT_FLOAT_EQ(8.61f, output[arraysize(kInput) - 1]); 104 } 105 106 TEST(SparseFIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) { 107 const size_t kSparsity = 1; 108 const size_t kOffset = 0; 109 float output[arraysize(kInput)]; 110 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); 111 filter.Filter(kInput, 2, output); 112 EXPECT_FLOAT_EQ(0.2f, output[0]); 113 EXPECT_FLOAT_EQ(0.7f, output[1]); 114 } 115 116 TEST(SparseFIRFilterTest, MultipleFilterCalls) { 117 const size_t kSparsity = 1; 118 const size_t kOffset = 0; 119 float output[arraysize(kInput)]; 120 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); 121 filter.Filter(kInput, 2, output); 122 EXPECT_FLOAT_EQ(0.2f, output[0]); 123 EXPECT_FLOAT_EQ(0.7f, output[1]); 124 filter.Filter(kInput, 2, output); 125 EXPECT_FLOAT_EQ(1.3f, output[0]); 126 EXPECT_FLOAT_EQ(2.4f, output[1]); 127 filter.Filter(kInput, 2, output); 128 EXPECT_FLOAT_EQ(2.81f, output[0]); 129 EXPECT_FLOAT_EQ(2.62f, output[1]); 130 filter.Filter(kInput, 2, output); 131 EXPECT_FLOAT_EQ(2.81f, output[0]); 132 EXPECT_FLOAT_EQ(2.62f, output[1]); 133 filter.Filter(&kInput[3], 3, output); 134 EXPECT_FLOAT_EQ(3.41f, output[0]); 135 EXPECT_FLOAT_EQ(4.12f, output[1]); 136 EXPECT_FLOAT_EQ(6.21f, output[2]); 137 filter.Filter(&kInput[3], 3, output); 138 EXPECT_FLOAT_EQ(8.12f, output[0]); 139 EXPECT_FLOAT_EQ(9.14f, output[1]); 140 EXPECT_FLOAT_EQ(9.45f, output[2]); 141 } 142 143 TEST(SparseFIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) { 144 const size_t kSparsity = 3; 145 const size_t kOffset = 1; 146 float output_block_based[arraysize(kInput)]; 147 SparseFIRFilter filter_block(kCoeffs, 148 arraysize(kCoeffs), 149 kSparsity, 150 kOffset); 151 filter_block.Filter(kInput, arraysize(kInput), output_block_based); 152 float output_sample_based[arraysize(kInput)]; 153 SparseFIRFilter filter_sample(kCoeffs, 154 arraysize(kCoeffs), 155 kSparsity, 156 kOffset); 157 for (size_t i = 0; i < arraysize(kInput); ++i) 158 filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]); 159 VerifyOutput(output_block_based, output_sample_based); 160 } 161 162 TEST(SparseFIRFilterTest, SimpleHighPassFilter) { 163 const size_t kSparsity = 2; 164 const size_t kOffset = 2; 165 const float kHPCoeffs[] = {1.f, -1.f}; 166 const float kConstantInput[] = 167 {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; 168 float output[arraysize(kConstantInput)]; 169 SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset); 170 filter.Filter(kConstantInput, arraysize(kConstantInput), output); 171 EXPECT_FLOAT_EQ(0.f, output[0]); 172 EXPECT_FLOAT_EQ(0.f, output[1]); 173 EXPECT_FLOAT_EQ(1.f, output[2]); 174 EXPECT_FLOAT_EQ(1.f, output[3]); 175 for (size_t i = kSparsity + kOffset; i < arraysize(kConstantInput); ++i) 176 EXPECT_FLOAT_EQ(0.f, output[i]); 177 } 178 179 TEST(SparseFIRFilterTest, SimpleLowPassFilter) { 180 const size_t kSparsity = 2; 181 const size_t kOffset = 2; 182 const float kLPCoeffs[] = {1.f, 1.f}; 183 const float kHighFrequencyInput[] = 184 {1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f}; 185 float output[arraysize(kHighFrequencyInput)]; 186 SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset); 187 filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output); 188 EXPECT_FLOAT_EQ(0.f, output[0]); 189 EXPECT_FLOAT_EQ(0.f, output[1]); 190 EXPECT_FLOAT_EQ(1.f, output[2]); 191 EXPECT_FLOAT_EQ(1.f, output[3]); 192 for (size_t i = kSparsity + kOffset; i < arraysize(kHighFrequencyInput); ++i) 193 EXPECT_FLOAT_EQ(0.f, output[i]); 194 } 195 196 TEST(SparseFIRFilterTest, SameOutputWhenSwappedCoefficientsAndInput) { 197 const size_t kSparsity = 1; 198 const size_t kOffset = 0; 199 float output[arraysize(kCoeffs)]; 200 float output_swapped[arraysize(kCoeffs)]; 201 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); 202 // Use arraysize(kCoeffs) for in_length to get same-length outputs. 203 filter.Filter(kInput, arraysize(kCoeffs), output); 204 SparseFIRFilter filter_swapped(kInput, 205 arraysize(kCoeffs), 206 kSparsity, 207 kOffset); 208 filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped); 209 VerifyOutput(output, output_swapped); 210 } 211 212 TEST(SparseFIRFilterTest, SameOutputAsFIRFilterWhenSparsityOneAndOffsetZero) { 213 const size_t kSparsity = 1; 214 const size_t kOffset = 0; 215 float output[arraysize(kInput)]; 216 float sparse_output[arraysize(kInput)]; 217 rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(kCoeffs, 218 arraysize(kCoeffs), 219 arraysize(kInput))); 220 SparseFIRFilter sparse_filter(kCoeffs, 221 arraysize(kCoeffs), 222 kSparsity, 223 kOffset); 224 filter->Filter(kInput, arraysize(kInput), output); 225 sparse_filter.Filter(kInput, arraysize(kInput), sparse_output); 226 for (size_t i = 0; i < arraysize(kInput); ++i) { 227 EXPECT_FLOAT_EQ(output[i], sparse_output[i]); 228 } 229 } 230 231 } // namespace webrtc 232