blob: 905238229ff3a376bb2858416d3782ecfacf61ba [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
13#include <cmath>
14#include <cstring>
15
16#include "testing/gtest/include/gtest/gtest.h"
17
18using std::complex;
19
20namespace {
21
22class NoopCallback : public webrtc::LappedTransform::Callback {
23 public:
24 NoopCallback() : block_num_(0) {}
25
26 virtual void ProcessAudioBlock(const complex<float>* const* in_block,
27 int in_channels, int frames, int out_channels,
28 complex<float>* const* out_block) {
29 CHECK_EQ(in_channels, out_channels);
30 for (int i = 0; i < out_channels; ++i) {
31 memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames);
32 }
33 ++block_num_;
34 }
35
36 int block_num() {
37 return block_num_;
38 }
39
40 private:
41 int block_num_;
42};
43
44class FftCheckerCallback : public webrtc::LappedTransform::Callback {
45 public:
46 FftCheckerCallback() : block_num_(0) {}
47
48 virtual void ProcessAudioBlock(const complex<float>* const* in_block,
49 int in_channels, int frames, int out_channels,
50 complex<float>* const* out_block) {
51 CHECK_EQ(in_channels, out_channels);
52
53 float full_length = (frames - 1) * 2;
54 ++block_num_;
55
56 if (block_num_ == 1) {
57 for (int i = 0; i < frames; ++i) {
58 ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
59 ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
60 }
61 } else {
62 ASSERT_NEAR(in_block[0][0].real(), full_length, 1e-5f);
63 ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
64 for (int i = 1; i < frames; ++i) {
65 ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
66 ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
67 }
68 }
69 }
70
71 int block_num() {
72 return block_num_;
73 }
74
75 private:
76 int block_num_;
77};
78
79void SetFloatArray(float value, int rows, int cols, float* const* array) {
80 for (int i = 0; i < rows; ++i) {
81 for (int j = 0; j < cols; ++j) {
82 array[i][j] = value;
83 }
84 }
85}
86
87} // namespace
88
89namespace webrtc {
90
91TEST(LappedTransformTest, Windowless) {
92 const int kChannels = 3;
93 const int kChunkLength = 512;
94 const int kBlockLength = 64;
95 const int kShiftAmount = 32;
96 NoopCallback noop;
97 LappedTransform trans(kChannels, kChannels, kChunkLength, nullptr,
98 kBlockLength, kShiftAmount, &noop);
99 float in_buffer[kChannels][kChunkLength];
100 float* in_chunk[kChannels];
101 float out_buffer[kChannels][kChunkLength];
102 float* out_chunk[kChannels];
103
104 in_chunk[0] = in_buffer[0];
105 in_chunk[1] = in_buffer[1];
106 in_chunk[2] = in_buffer[2];
107 out_chunk[0] = out_buffer[0];
108 out_chunk[1] = out_buffer[1];
109 out_chunk[2] = out_buffer[2];
110 SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk);
111 SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk);
112
113 trans.ProcessChunk(in_chunk, out_chunk);
114
115 for (int i = 0; i < kChannels; ++i) {
116 for (int j = 0; j < kChunkLength; ++j) {
117 ASSERT_NEAR(out_chunk[i][j], (j < kBlockLength) ? 0.0f : 2.0f, 1e-5f);
118 }
119 }
120
121 ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num());
122}
123
124TEST(LappedTransformTest, IdentityProcessor) {
125 const int kChunkLength = 512;
126 const int kBlockLength = 64;
127 const int kShiftAmount = 32;
128 NoopCallback noop;
129 float window[kBlockLength];
130 float* window_ptr = window;
131
132 // Identity window for |overlap = block_size / 2|.
133 SetFloatArray(sqrtf(0.5f), 1, kBlockLength, &window_ptr);
134
135 LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kShiftAmount,
136 &noop);
137 float in_buffer[kChunkLength];
138 float* in_chunk = in_buffer;
139 float out_buffer[kChunkLength];
140 float* out_chunk = out_buffer;
141
142 SetFloatArray(2.0f, 1, kChunkLength, &in_chunk);
143 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
144
145 trans.ProcessChunk(&in_chunk, &out_chunk);
146
147 for (int i = 0; i < kChunkLength; ++i) {
148 ASSERT_NEAR(out_chunk[i], (i < kBlockLength) ? 0.0f : 2.0f, 1e-5f);
149 }
150
151 ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
152}
153
154TEST(LappedTransformTest, Callbacks) {
155 const int kChunkLength = 512;
156 const int kBlockLength = 64;
157 FftCheckerCallback call;
158 LappedTransform trans(1, 1, kChunkLength, nullptr, kBlockLength,
159 kBlockLength, &call);
160 float in_buffer[kChunkLength];
161 float* in_chunk = in_buffer;
162 float out_buffer[kChunkLength];
163 float* out_chunk = out_buffer;
164
165 SetFloatArray(1.0f, 1, kChunkLength, &in_chunk);
166 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
167
168 trans.ProcessChunk(&in_chunk, &out_chunk);
169
170 ASSERT_EQ(kChunkLength / kBlockLength, call.block_num());
171}
172
173} // namespace webrtc
174