1 /*
2 * Copyright (c) 2013 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/modules/audio_processing/transient/wpd_tree.h"
12
13 #include <sstream>
14 #include <string>
15
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h"
19 #include "webrtc/modules/audio_processing/transient/file_utils.h"
20 #include "webrtc/system_wrappers/include/file_wrapper.h"
21 #include "webrtc/test/testsupport/fileutils.h"
22
23 namespace webrtc {
24
TEST(WPDTreeTest,Construction)25 TEST(WPDTreeTest, Construction) {
26 const size_t kTestBufferSize = 100;
27 const int kLevels = 5;
28 const int kExpectedNumberOfNodes = (1 << (kLevels + 1)) - 1;
29
30 float test_buffer[kTestBufferSize];
31 memset(test_buffer, 0.f, kTestBufferSize * sizeof(*test_buffer));
32 float test_coefficients[] = {1.f, 2.f, 3.f, 4.f, 5.f};
33 const size_t kTestCoefficientsLength = sizeof(test_coefficients) /
34 sizeof(test_coefficients[0]);
35 WPDTree tree(kTestBufferSize,
36 test_coefficients,
37 test_coefficients,
38 kTestCoefficientsLength,
39 kLevels);
40 ASSERT_EQ(kExpectedNumberOfNodes, tree.num_nodes());
41 // Checks for NodeAt(level, index).
42 int nodes_at_level = 0;
43 for (int level = 0; level <= kLevels; ++level) {
44 nodes_at_level = 1 << level;
45 for (int i = 0; i < nodes_at_level; ++i) {
46 ASSERT_TRUE(NULL != tree.NodeAt(level, i));
47 }
48 // Out of bounds.
49 EXPECT_EQ(NULL, tree.NodeAt(level, -1));
50 EXPECT_EQ(NULL, tree.NodeAt(level, -12));
51 EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level));
52 EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level + 5));
53 }
54 // Out of bounds.
55 EXPECT_EQ(NULL, tree.NodeAt(-1, 0));
56 EXPECT_EQ(NULL, tree.NodeAt(-12, 0));
57 EXPECT_EQ(NULL, tree.NodeAt(kLevels + 1, 0));
58 EXPECT_EQ(NULL, tree.NodeAt(kLevels + 5, 0));
59 // Checks for Update().
60 EXPECT_EQ(0, tree.Update(test_buffer, kTestBufferSize));
61 EXPECT_EQ(-1, tree.Update(NULL, kTestBufferSize));
62 EXPECT_EQ(-1, tree.Update(test_buffer, kTestBufferSize - 1));
63 }
64
65 // This test is for the correctness of the tree.
66 // Checks the results from the Matlab equivalent, it is done comparing the
67 // results that are stored in the output files from Matlab.
68 // It also writes the results in its own set of files in the out directory.
69 // Matlab and output files contain all the results in double precision (Little
70 // endian) appended.
71 #if defined(WEBRTC_IOS)
TEST(WPDTreeTest,DISABLED_CorrectnessBasedOnMatlabFiles)72 TEST(WPDTreeTest, DISABLED_CorrectnessBasedOnMatlabFiles) {
73 #else
74 TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) {
75 #endif
76 // 10 ms at 16000 Hz.
77 const size_t kTestBufferSize = 160;
78 const int kLevels = 3;
79 const int kLeaves = 1 << kLevels;
80 const size_t kLeavesSamples = kTestBufferSize >> kLevels;
81 // Create tree with Discrete Meyer Wavelet Coefficients.
82 WPDTree tree(kTestBufferSize,
83 kDaubechies8HighPassCoefficients,
84 kDaubechies8LowPassCoefficients,
85 kDaubechies8CoefficientsLength,
86 kLevels);
87 // Allocate and open all matlab and out files.
88 rtc::scoped_ptr<FileWrapper> matlab_files_data[kLeaves];
89 rtc::scoped_ptr<FileWrapper> out_files_data[kLeaves];
90
91 for (int i = 0; i < kLeaves; ++i) {
92 // Matlab files.
93 matlab_files_data[i].reset(FileWrapper::Create());
94
95 std::ostringstream matlab_stream;
96 matlab_stream << "audio_processing/transient/wpd" << i;
97 std::string matlab_string = test::ResourcePath(matlab_stream.str(), "dat");
98 matlab_files_data[i]->OpenFile(matlab_string.c_str(),
99 true, // Read only.
100 false, // No loop.
101 false); // No text.
102
103 bool file_opened = matlab_files_data[i]->Open();
104 ASSERT_TRUE(file_opened) << "File could not be opened.\n" << matlab_string;
105
106 // Out files.
107 out_files_data[i].reset(FileWrapper::Create());
108
109 std::ostringstream out_stream;
110 out_stream << test::OutputPath() << "wpd_" << i << ".out";
111 std::string out_string = out_stream.str();
112
113 out_files_data[i]->OpenFile(out_string.c_str(),
114 false, // Write mode.
115 false, // No loop.
116 false); // No text.
117
118 file_opened = out_files_data[i]->Open();
119 ASSERT_TRUE(file_opened) << "File could not be opened.\n" << out_string;
120 }
121
122 // Prepare the test file.
123 std::string test_file_name = test::ResourcePath(
124 "audio_processing/transient/ajm-macbook-1-spke16m", "pcm");
125
126 rtc::scoped_ptr<FileWrapper> test_file(FileWrapper::Create());
127
128 test_file->OpenFile(test_file_name.c_str(),
129 true, // Read only.
130 false, // No loop.
131 false); // No text.
132
133 bool file_opened = test_file->Open();
134 ASSERT_TRUE(file_opened) << "File could not be opened.\n" << test_file_name;
135
136 float test_buffer[kTestBufferSize];
137
138 // Only the first frames of the audio file are tested. The matlab files also
139 // only contains information about the first frames.
140 const size_t kMaxFramesToTest = 100;
141 const float kTolerance = 0.03f;
142
143 size_t frames_read = 0;
144
145 // Read first buffer from the PCM test file.
146 size_t file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(),
147 kTestBufferSize,
148 test_buffer);
149 while (file_samples_read > 0 && frames_read < kMaxFramesToTest) {
150 ++frames_read;
151
152 if (file_samples_read < kTestBufferSize) {
153 // Pad the rest of the buffer with zeros.
154 for (size_t i = file_samples_read; i < kTestBufferSize; ++i) {
155 test_buffer[i] = 0.0;
156 }
157 }
158 tree.Update(test_buffer, kTestBufferSize);
159 double matlab_buffer[kTestBufferSize];
160
161 // Compare results with data from the matlab test files.
162 for (int i = 0; i < kLeaves; ++i) {
163 // Compare data values
164 size_t matlab_samples_read =
165 ReadDoubleBufferFromFile(matlab_files_data[i].get(),
166 kLeavesSamples,
167 matlab_buffer);
168
169 ASSERT_EQ(kLeavesSamples, matlab_samples_read)
170 << "Matlab test files are malformed.\n"
171 << "File: 3_" << i;
172 // Get output data from the corresponding node
173 const float* node_data = tree.NodeAt(kLevels, i)->data();
174 // Compare with matlab files.
175 for (size_t j = 0; j < kLeavesSamples; ++j) {
176 EXPECT_NEAR(matlab_buffer[j], node_data[j], kTolerance)
177 << "\nLeaf: " << i << "\nSample: " << j
178 << "\nFrame: " << frames_read - 1;
179 }
180
181 // Write results to out files.
182 WriteFloatBufferToFile(out_files_data[i].get(),
183 kLeavesSamples,
184 node_data);
185 }
186
187 // Read next buffer from the PCM test file.
188 file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(),
189 kTestBufferSize,
190 test_buffer);
191 }
192
193 // Close all matlab and out files.
194 for (int i = 0; i < kLeaves; ++i) {
195 matlab_files_data[i]->CloseFile();
196 out_files_data[i]->CloseFile();
197 }
198
199 test_file->CloseFile();
200 }
201
202 } // namespace webrtc
203