1 /*
2  *  Copyright (c) 2014 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 // MSVC++ requires this to be set before any other includes to get M_PI.
12 #define _USE_MATH_DEFINES
13 
14 #include <cmath>
15 
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "webrtc/common_audio/channel_buffer.h"
18 #include "webrtc/modules/audio_processing/splitting_filter.h"
19 
20 namespace webrtc {
21 namespace {
22 
23 const size_t kSamplesPer16kHzChannel = 160;
24 const size_t kSamplesPer48kHzChannel = 480;
25 
26 }  // namespace
27 
28 // Generates a signal from presence or absence of sine waves of different
29 // frequencies.
30 // Splits into 3 bands and checks their presence or absence.
31 // Recombines the bands.
32 // Calculates the delay.
33 // Checks that the cross correlation of input and output is high enough at the
34 // calculated delay.
TEST(SplittingFilterTest,SplitsIntoThreeBandsAndReconstructs)35 TEST(SplittingFilterTest, SplitsIntoThreeBandsAndReconstructs) {
36   static const int kChannels = 1;
37   static const int kSampleRateHz = 48000;
38   static const size_t kNumBands = 3;
39   static const int kFrequenciesHz[kNumBands] = {1000, 12000, 18000};
40   static const float kAmplitude = 8192.f;
41   static const size_t kChunks = 8;
42   SplittingFilter splitting_filter(kChannels,
43                                    kNumBands,
44                                    kSamplesPer48kHzChannel);
45   IFChannelBuffer in_data(kSamplesPer48kHzChannel, kChannels, kNumBands);
46   IFChannelBuffer bands(kSamplesPer48kHzChannel, kChannels, kNumBands);
47   IFChannelBuffer out_data(kSamplesPer48kHzChannel, kChannels, kNumBands);
48   for (size_t i = 0; i < kChunks; ++i) {
49     // Input signal generation.
50     bool is_present[kNumBands];
51     memset(in_data.fbuf()->channels()[0],
52            0,
53            kSamplesPer48kHzChannel * sizeof(in_data.fbuf()->channels()[0][0]));
54     for (size_t j = 0; j < kNumBands; ++j) {
55       is_present[j] = i & (static_cast<size_t>(1) << j);
56       float amplitude = is_present[j] ? kAmplitude : 0.f;
57       for (size_t k = 0; k < kSamplesPer48kHzChannel; ++k) {
58         in_data.fbuf()->channels()[0][k] +=
59             amplitude * sin(2.f * M_PI * kFrequenciesHz[j] *
60                 (i * kSamplesPer48kHzChannel + k) / kSampleRateHz);
61       }
62     }
63     // Three band splitting filter.
64     splitting_filter.Analysis(&in_data, &bands);
65     // Energy calculation.
66     float energy[kNumBands];
67     for (size_t j = 0; j < kNumBands; ++j) {
68       energy[j] = 0.f;
69       for (size_t k = 0; k < kSamplesPer16kHzChannel; ++k) {
70         energy[j] += bands.fbuf_const()->channels(j)[0][k] *
71                      bands.fbuf_const()->channels(j)[0][k];
72       }
73       energy[j] /= kSamplesPer16kHzChannel;
74       if (is_present[j]) {
75         EXPECT_GT(energy[j], kAmplitude * kAmplitude / 4);
76       } else {
77         EXPECT_LT(energy[j], kAmplitude * kAmplitude / 4);
78       }
79     }
80     // Three band merge.
81     splitting_filter.Synthesis(&bands, &out_data);
82     // Delay and cross correlation estimation.
83     float xcorr = 0.f;
84     for (size_t delay = 0; delay < kSamplesPer48kHzChannel; ++delay) {
85       float tmpcorr = 0.f;
86       for (size_t j = delay; j < kSamplesPer48kHzChannel; ++j) {
87         tmpcorr += in_data.fbuf_const()->channels()[0][j - delay] *
88                    out_data.fbuf_const()->channels()[0][j];
89       }
90       tmpcorr /= kSamplesPer48kHzChannel;
91       if (tmpcorr > xcorr) {
92         xcorr = tmpcorr;
93       }
94     }
95     // High cross correlation check.
96     bool any_present = false;
97     for (size_t j = 0; j < kNumBands; ++j) {
98       any_present |= is_present[j];
99     }
100     if (any_present) {
101       EXPECT_GT(xcorr, kAmplitude * kAmplitude / 4);
102     }
103   }
104 }
105 
106 }  // namespace webrtc
107