blob: 3becfe1381b91a1dbd9c5969c1c60ba5b6592eb6 [file] [log] [blame]
andrew@webrtc.org325cff02014-10-01 17:42:18 +00001/*
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#include "webrtc/common_audio/lapped_transform.h"
12
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +000013#include <algorithm>
andrew@webrtc.org325cff02014-10-01 17:42:18 +000014#include <cmath>
15#include <cstring>
16
17#include "testing/gtest/include/gtest/gtest.h"
18
19using std::complex;
20
21namespace {
22
23class NoopCallback : public webrtc::LappedTransform::Callback {
24 public:
25 NoopCallback() : block_num_(0) {}
26
27 virtual void ProcessAudioBlock(const complex<float>* const* in_block,
28 int in_channels, int frames, int out_channels,
29 complex<float>* const* out_block) {
30 CHECK_EQ(in_channels, out_channels);
31 for (int i = 0; i < out_channels; ++i) {
32 memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames);
33 }
34 ++block_num_;
35 }
36
37 int block_num() {
38 return block_num_;
39 }
40
41 private:
42 int block_num_;
43};
44
45class FftCheckerCallback : public webrtc::LappedTransform::Callback {
46 public:
47 FftCheckerCallback() : block_num_(0) {}
48
49 virtual void ProcessAudioBlock(const complex<float>* const* in_block,
50 int in_channels, int frames, int out_channels,
51 complex<float>* const* out_block) {
52 CHECK_EQ(in_channels, out_channels);
53
Peter Kastingb7e50542015-06-11 12:55:50 -070054 int full_length = (frames - 1) * 2;
andrew@webrtc.org325cff02014-10-01 17:42:18 +000055 ++block_num_;
56
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +000057 if (block_num_ > 0) {
Peter Kastingb7e50542015-06-11 12:55:50 -070058 ASSERT_NEAR(in_block[0][0].real(), static_cast<float>(full_length),
59 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +000060 ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
61 for (int i = 1; i < frames; ++i) {
62 ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
63 ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
64 }
65 }
66 }
67
68 int block_num() {
69 return block_num_;
70 }
71
72 private:
73 int block_num_;
74};
75
76void SetFloatArray(float value, int rows, int cols, float* const* array) {
77 for (int i = 0; i < rows; ++i) {
78 for (int j = 0; j < cols; ++j) {
79 array[i][j] = value;
80 }
81 }
82}
83
84} // namespace
85
86namespace webrtc {
87
88TEST(LappedTransformTest, Windowless) {
89 const int kChannels = 3;
90 const int kChunkLength = 512;
91 const int kBlockLength = 64;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +000092 const int kShiftAmount = 64;
andrew@webrtc.org325cff02014-10-01 17:42:18 +000093 NoopCallback noop;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +000094
95 // Rectangular window.
96 float window[kBlockLength];
97 std::fill(window, &window[kBlockLength], 1.0f);
98
99 LappedTransform trans(kChannels, kChannels, kChunkLength, window,
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000100 kBlockLength, kShiftAmount, &noop);
101 float in_buffer[kChannels][kChunkLength];
102 float* in_chunk[kChannels];
103 float out_buffer[kChannels][kChunkLength];
104 float* out_chunk[kChannels];
105
106 in_chunk[0] = in_buffer[0];
107 in_chunk[1] = in_buffer[1];
108 in_chunk[2] = in_buffer[2];
109 out_chunk[0] = out_buffer[0];
110 out_chunk[1] = out_buffer[1];
111 out_chunk[2] = out_buffer[2];
112 SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk);
113 SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk);
114
115 trans.ProcessChunk(in_chunk, out_chunk);
116
117 for (int i = 0; i < kChannels; ++i) {
118 for (int j = 0; j < kChunkLength; ++j) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000119 ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000120 }
121 }
122
123 ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num());
124}
125
126TEST(LappedTransformTest, IdentityProcessor) {
127 const int kChunkLength = 512;
128 const int kBlockLength = 64;
129 const int kShiftAmount = 32;
130 NoopCallback noop;
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000131
132 // Identity window for |overlap = block_size / 2|.
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000133 float window[kBlockLength];
134 std::fill(window, &window[kBlockLength], std::sqrt(0.5f));
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000135
136 LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kShiftAmount,
137 &noop);
138 float in_buffer[kChunkLength];
139 float* in_chunk = in_buffer;
140 float out_buffer[kChunkLength];
141 float* out_chunk = out_buffer;
142
143 SetFloatArray(2.0f, 1, kChunkLength, &in_chunk);
144 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
145
146 trans.ProcessChunk(&in_chunk, &out_chunk);
147
148 for (int i = 0; i < kChunkLength; ++i) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000149 ASSERT_NEAR(out_chunk[i],
150 (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
151 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000152 }
153
154 ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
155}
156
157TEST(LappedTransformTest, Callbacks) {
158 const int kChunkLength = 512;
159 const int kBlockLength = 64;
160 FftCheckerCallback call;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000161
162 // Rectangular window.
163 float window[kBlockLength];
164 std::fill(window, &window[kBlockLength], 1.0f);
165
166 LappedTransform trans(1, 1, kChunkLength, window, kBlockLength,
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000167 kBlockLength, &call);
168 float in_buffer[kChunkLength];
169 float* in_chunk = in_buffer;
170 float out_buffer[kChunkLength];
171 float* out_chunk = out_buffer;
172
173 SetFloatArray(1.0f, 1, kChunkLength, &in_chunk);
174 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
175
176 trans.ProcessChunk(&in_chunk, &out_chunk);
177
178 ASSERT_EQ(kChunkLength / kBlockLength, call.block_num());
179}
180
Michael Graczykcc846492015-05-28 18:01:33 -0700181TEST(LappedTransformTest, chunk_length) {
Michael Graczyk9b720f72015-05-27 17:09:47 -0700182 const int kBlockLength = 64;
183 FftCheckerCallback call;
184 const float window[kBlockLength] = {};
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000185
Michael Graczykcc846492015-05-28 18:01:33 -0700186 // Make sure that chunk_length returns the same value passed to the
Michael Graczyk9b720f72015-05-27 17:09:47 -0700187 // LappedTransform constructor.
188 {
189 const int kExpectedChunkLength = 512;
190 const LappedTransform trans(1, 1, kExpectedChunkLength, window,
191 kBlockLength, kBlockLength, &call);
192
Michael Graczykcc846492015-05-28 18:01:33 -0700193 EXPECT_EQ(kExpectedChunkLength, trans.chunk_length());
Michael Graczyk9b720f72015-05-27 17:09:47 -0700194 }
195 {
196 const int kExpectedChunkLength = 160;
197 const LappedTransform trans(1, 1, kExpectedChunkLength, window,
198 kBlockLength, kBlockLength, &call);
199
Michael Graczykcc846492015-05-28 18:01:33 -0700200 EXPECT_EQ(kExpectedChunkLength, trans.chunk_length());
Michael Graczyk9b720f72015-05-27 17:09:47 -0700201 }
202}
203
204} // namespace webrtc