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