| /* | |
| * Copyright (c) 2013 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 "webrtc/modules/audio_processing/transient/wpd_tree.h" | |
| #include <sstream> | |
| #include <string> | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| #include "webrtc/base/scoped_ptr.h" | |
| #include "webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h" | |
| #include "webrtc/modules/audio_processing/transient/file_utils.h" | |
| #include "webrtc/system_wrappers/interface/file_wrapper.h" | |
| #include "webrtc/test/testsupport/fileutils.h" | |
| #include "webrtc/test/testsupport/gtest_disable.h" | |
| namespace webrtc { | |
| TEST(WPDTreeTest, Construction) { | |
| const size_t kTestBufferSize = 100; | |
| const int kLevels = 5; | |
| const int kExpectedNumberOfNodes = (1 << (kLevels + 1)) - 1; | |
| float test_buffer[kTestBufferSize]; | |
| memset(test_buffer, 0.f, kTestBufferSize * sizeof(*test_buffer)); | |
| float test_coefficients[] = {1.f, 2.f, 3.f, 4.f, 5.f}; | |
| const size_t kTestCoefficientsLength = sizeof(test_coefficients) / | |
| sizeof(test_coefficients[0]); | |
| WPDTree tree(kTestBufferSize, | |
| test_coefficients, | |
| test_coefficients, | |
| kTestCoefficientsLength, | |
| kLevels); | |
| ASSERT_EQ(kExpectedNumberOfNodes, tree.num_nodes()); | |
| // Checks for NodeAt(level, index). | |
| int nodes_at_level = 0; | |
| for (int level = 0; level <= kLevels; ++level) { | |
| nodes_at_level = 1 << level; | |
| for (int i = 0; i < nodes_at_level; ++i) { | |
| ASSERT_TRUE(NULL != tree.NodeAt(level, i)); | |
| } | |
| // Out of bounds. | |
| EXPECT_EQ(NULL, tree.NodeAt(level, -1)); | |
| EXPECT_EQ(NULL, tree.NodeAt(level, -12)); | |
| EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level)); | |
| EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level + 5)); | |
| } | |
| // Out of bounds. | |
| EXPECT_EQ(NULL, tree.NodeAt(-1, 0)); | |
| EXPECT_EQ(NULL, tree.NodeAt(-12, 0)); | |
| EXPECT_EQ(NULL, tree.NodeAt(kLevels + 1, 0)); | |
| EXPECT_EQ(NULL, tree.NodeAt(kLevels + 5, 0)); | |
| // Checks for Update(). | |
| EXPECT_EQ(0, tree.Update(test_buffer, kTestBufferSize)); | |
| EXPECT_EQ(-1, tree.Update(NULL, kTestBufferSize)); | |
| EXPECT_EQ(-1, tree.Update(test_buffer, kTestBufferSize - 1)); | |
| } | |
| // This test is for the correctness of the tree. | |
| // Checks the results from the Matlab equivalent, it is done comparing the | |
| // results that are stored in the output files from Matlab. | |
| // It also writes the results in its own set of files in the out directory. | |
| // Matlab and output files contain all the results in double precision (Little | |
| // endian) appended. | |
| TEST(WPDTreeTest, DISABLED_ON_IOS(CorrectnessBasedOnMatlabFiles)) { | |
| // 10 ms at 16000 Hz. | |
| const size_t kTestBufferSize = 160; | |
| const int kLevels = 3; | |
| const int kLeaves = 1 << kLevels; | |
| const size_t kLeavesSamples = kTestBufferSize >> kLevels; | |
| // Create tree with Discrete Meyer Wavelet Coefficients. | |
| WPDTree tree(kTestBufferSize, | |
| kDaubechies8HighPassCoefficients, | |
| kDaubechies8LowPassCoefficients, | |
| kDaubechies8CoefficientsLength, | |
| kLevels); | |
| // Allocate and open all matlab and out files. | |
| rtc::scoped_ptr<FileWrapper> matlab_files_data[kLeaves]; | |
| rtc::scoped_ptr<FileWrapper> out_files_data[kLeaves]; | |
| for (int i = 0; i < kLeaves; ++i) { | |
| // Matlab files. | |
| matlab_files_data[i].reset(FileWrapper::Create()); | |
| std::ostringstream matlab_stream; | |
| matlab_stream << "audio_processing/transient/wpd" << i; | |
| std::string matlab_string = test::ResourcePath(matlab_stream.str(), "dat"); | |
| matlab_files_data[i]->OpenFile(matlab_string.c_str(), | |
| true, // Read only. | |
| false, // No loop. | |
| false); // No text. | |
| bool file_opened = matlab_files_data[i]->Open(); | |
| ASSERT_TRUE(file_opened) << "File could not be opened.\n" << matlab_string; | |
| // Out files. | |
| out_files_data[i].reset(FileWrapper::Create()); | |
| std::ostringstream out_stream; | |
| out_stream << test::OutputPath() << "wpd_" << i << ".out"; | |
| std::string out_string = out_stream.str(); | |
| out_files_data[i]->OpenFile(out_string.c_str(), | |
| false, // Write mode. | |
| false, // No loop. | |
| false); // No text. | |
| file_opened = out_files_data[i]->Open(); | |
| ASSERT_TRUE(file_opened) << "File could not be opened.\n" << out_string; | |
| } | |
| // Prepare the test file. | |
| std::string test_file_name = test::ResourcePath( | |
| "audio_processing/transient/ajm-macbook-1-spke16m", "pcm"); | |
| rtc::scoped_ptr<FileWrapper> test_file(FileWrapper::Create()); | |
| test_file->OpenFile(test_file_name.c_str(), | |
| true, // Read only. | |
| false, // No loop. | |
| false); // No text. | |
| bool file_opened = test_file->Open(); | |
| ASSERT_TRUE(file_opened) << "File could not be opened.\n" << test_file_name; | |
| float test_buffer[kTestBufferSize]; | |
| // Only the first frames of the audio file are tested. The matlab files also | |
| // only contains information about the first frames. | |
| const size_t kMaxFramesToTest = 100; | |
| const float kTolerance = 0.03f; | |
| size_t frames_read = 0; | |
| // Read first buffer from the PCM test file. | |
| size_t file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(), | |
| kTestBufferSize, | |
| test_buffer); | |
| while (file_samples_read > 0 && frames_read < kMaxFramesToTest) { | |
| ++frames_read; | |
| if (file_samples_read < kTestBufferSize) { | |
| // Pad the rest of the buffer with zeros. | |
| for (size_t i = file_samples_read; i < kTestBufferSize; ++i) { | |
| test_buffer[i] = 0.0; | |
| } | |
| } | |
| tree.Update(test_buffer, kTestBufferSize); | |
| double matlab_buffer[kTestBufferSize]; | |
| // Compare results with data from the matlab test files. | |
| for (int i = 0; i < kLeaves; ++i) { | |
| // Compare data values | |
| size_t matlab_samples_read = | |
| ReadDoubleBufferFromFile(matlab_files_data[i].get(), | |
| kLeavesSamples, | |
| matlab_buffer); | |
| ASSERT_EQ(kLeavesSamples, matlab_samples_read) | |
| << "Matlab test files are malformed.\n" | |
| << "File: 3_" << i; | |
| // Get output data from the corresponding node | |
| const float* node_data = tree.NodeAt(kLevels, i)->data(); | |
| // Compare with matlab files. | |
| for (size_t j = 0; j < kLeavesSamples; ++j) { | |
| EXPECT_NEAR(matlab_buffer[j], node_data[j], kTolerance) | |
| << "\nLeaf: " << i << "\nSample: " << j | |
| << "\nFrame: " << frames_read - 1; | |
| } | |
| // Write results to out files. | |
| WriteFloatBufferToFile(out_files_data[i].get(), | |
| kLeavesSamples, | |
| node_data); | |
| } | |
| // Read next buffer from the PCM test file. | |
| file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(), | |
| kTestBufferSize, | |
| test_buffer); | |
| } | |
| // Close all matlab and out files. | |
| for (int i = 0; i < kLeaves; ++i) { | |
| matlab_files_data[i]->CloseFile(); | |
| out_files_data[i]->CloseFile(); | |
| } | |
| test_file->CloseFile(); | |
| } | |
| } // namespace webrtc |