Index: webrtc/common_audio/lapped_transform_unittest.cc |
diff --git a/webrtc/common_audio/lapped_transform_unittest.cc b/webrtc/common_audio/lapped_transform_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a78488e326d9b0759955bb8a9b3941ecd0057235 |
--- /dev/null |
+++ b/webrtc/common_audio/lapped_transform_unittest.cc |
@@ -0,0 +1,208 @@ |
+/* |
+ * Copyright (c) 2014 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/common_audio/lapped_transform.h" |
+ |
+#include <algorithm> |
+#include <cmath> |
+#include <cstring> |
+ |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using std::complex; |
+ |
+namespace { |
+ |
+class NoopCallback : public webrtc::LappedTransform::Callback { |
+ public: |
+ NoopCallback() : block_num_(0) {} |
+ |
+ virtual void ProcessAudioBlock(const complex<float>* const* in_block, |
+ size_t in_channels, |
+ size_t frames, |
+ size_t out_channels, |
+ complex<float>* const* out_block) { |
+ RTC_CHECK_EQ(in_channels, out_channels); |
+ for (size_t i = 0; i < out_channels; ++i) { |
+ memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames); |
+ } |
+ ++block_num_; |
+ } |
+ |
+ size_t block_num() { |
+ return block_num_; |
+ } |
+ |
+ private: |
+ size_t block_num_; |
+}; |
+ |
+class FftCheckerCallback : public webrtc::LappedTransform::Callback { |
+ public: |
+ FftCheckerCallback() : block_num_(0) {} |
+ |
+ virtual void ProcessAudioBlock(const complex<float>* const* in_block, |
+ size_t in_channels, |
+ size_t frames, |
+ size_t out_channels, |
+ complex<float>* const* out_block) { |
+ RTC_CHECK_EQ(in_channels, out_channels); |
+ |
+ size_t full_length = (frames - 1) * 2; |
+ ++block_num_; |
+ |
+ if (block_num_ > 0) { |
+ ASSERT_NEAR(in_block[0][0].real(), static_cast<float>(full_length), |
+ 1e-5f); |
+ ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f); |
+ for (size_t i = 1; i < frames; ++i) { |
+ ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f); |
+ ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f); |
+ } |
+ } |
+ } |
+ |
+ size_t block_num() { |
+ return block_num_; |
+ } |
+ |
+ private: |
+ size_t block_num_; |
+}; |
+ |
+void SetFloatArray(float value, int rows, int cols, float* const* array) { |
+ for (int i = 0; i < rows; ++i) { |
+ for (int j = 0; j < cols; ++j) { |
+ array[i][j] = value; |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
+namespace webrtc { |
+ |
+TEST(LappedTransformTest, Windowless) { |
+ const size_t kChannels = 3; |
+ const size_t kChunkLength = 512; |
+ const size_t kBlockLength = 64; |
+ const size_t kShiftAmount = 64; |
+ NoopCallback noop; |
+ |
+ // Rectangular window. |
+ float window[kBlockLength]; |
+ std::fill(window, &window[kBlockLength], 1.0f); |
+ |
+ LappedTransform trans(kChannels, kChannels, kChunkLength, window, |
+ kBlockLength, kShiftAmount, &noop); |
+ float in_buffer[kChannels][kChunkLength]; |
+ float* in_chunk[kChannels]; |
+ float out_buffer[kChannels][kChunkLength]; |
+ float* out_chunk[kChannels]; |
+ |
+ in_chunk[0] = in_buffer[0]; |
+ in_chunk[1] = in_buffer[1]; |
+ in_chunk[2] = in_buffer[2]; |
+ out_chunk[0] = out_buffer[0]; |
+ out_chunk[1] = out_buffer[1]; |
+ out_chunk[2] = out_buffer[2]; |
+ SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk); |
+ SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk); |
+ |
+ trans.ProcessChunk(in_chunk, out_chunk); |
+ |
+ for (size_t i = 0; i < kChannels; ++i) { |
+ for (size_t j = 0; j < kChunkLength; ++j) { |
+ ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f); |
+ } |
+ } |
+ |
+ ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num()); |
+} |
+ |
+TEST(LappedTransformTest, IdentityProcessor) { |
+ const size_t kChunkLength = 512; |
+ const size_t kBlockLength = 64; |
+ const size_t kShiftAmount = 32; |
+ NoopCallback noop; |
+ |
+ // Identity window for |overlap = block_size / 2|. |
+ float window[kBlockLength]; |
+ std::fill(window, &window[kBlockLength], std::sqrt(0.5f)); |
+ |
+ LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kShiftAmount, |
+ &noop); |
+ float in_buffer[kChunkLength]; |
+ float* in_chunk = in_buffer; |
+ float out_buffer[kChunkLength]; |
+ float* out_chunk = out_buffer; |
+ |
+ SetFloatArray(2.0f, 1, kChunkLength, &in_chunk); |
+ SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk); |
+ |
+ trans.ProcessChunk(&in_chunk, &out_chunk); |
+ |
+ for (size_t i = 0; i < kChunkLength; ++i) { |
+ ASSERT_NEAR(out_chunk[i], |
+ (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f, |
+ 1e-5f); |
+ } |
+ |
+ ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num()); |
+} |
+ |
+TEST(LappedTransformTest, Callbacks) { |
+ const size_t kChunkLength = 512; |
+ const size_t kBlockLength = 64; |
+ FftCheckerCallback call; |
+ |
+ // Rectangular window. |
+ float window[kBlockLength]; |
+ std::fill(window, &window[kBlockLength], 1.0f); |
+ |
+ LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, |
+ kBlockLength, &call); |
+ float in_buffer[kChunkLength]; |
+ float* in_chunk = in_buffer; |
+ float out_buffer[kChunkLength]; |
+ float* out_chunk = out_buffer; |
+ |
+ SetFloatArray(1.0f, 1, kChunkLength, &in_chunk); |
+ SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk); |
+ |
+ trans.ProcessChunk(&in_chunk, &out_chunk); |
+ |
+ ASSERT_EQ(kChunkLength / kBlockLength, call.block_num()); |
+} |
+ |
+TEST(LappedTransformTest, chunk_length) { |
+ const size_t kBlockLength = 64; |
+ FftCheckerCallback call; |
+ const float window[kBlockLength] = {}; |
+ |
+ // Make sure that chunk_length returns the same value passed to the |
+ // LappedTransform constructor. |
+ { |
+ const size_t kExpectedChunkLength = 512; |
+ const LappedTransform trans(1, 1, kExpectedChunkLength, window, |
+ kBlockLength, kBlockLength, &call); |
+ |
+ EXPECT_EQ(kExpectedChunkLength, trans.chunk_length()); |
+ } |
+ { |
+ const size_t kExpectedChunkLength = 160; |
+ const LappedTransform trans(1, 1, kExpectedChunkLength, window, |
+ kBlockLength, kBlockLength, &call); |
+ |
+ EXPECT_EQ(kExpectedChunkLength, trans.chunk_length()); |
+ } |
+} |
+ |
+} // namespace webrtc |