blob: 4b521fad580d2602ecd867e64e151d5957343cb9 [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
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +000056 if (block_num_ > 0) {
andrew@webrtc.org325cff02014-10-01 17:42:18 +000057 ASSERT_NEAR(in_block[0][0].real(), full_length, 1e-5f);
58 ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
59 for (int i = 1; i < frames; ++i) {
60 ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
61 ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
62 }
63 }
64 }
65
66 int block_num() {
67 return block_num_;
68 }
69
70 private:
71 int block_num_;
72};
73
74void SetFloatArray(float value, int rows, int cols, float* const* array) {
75 for (int i = 0; i < rows; ++i) {
76 for (int j = 0; j < cols; ++j) {
77 array[i][j] = value;
78 }
79 }
80}
81
82} // namespace
83
84namespace webrtc {
85
86TEST(LappedTransformTest, Windowless) {
87 const int kChannels = 3;
88 const int kChunkLength = 512;
89 const int kBlockLength = 64;
90 const int kShiftAmount = 32;
91 NoopCallback noop;
92 LappedTransform trans(kChannels, kChannels, kChunkLength, nullptr,
93 kBlockLength, kShiftAmount, &noop);
94 float in_buffer[kChannels][kChunkLength];
95 float* in_chunk[kChannels];
96 float out_buffer[kChannels][kChunkLength];
97 float* out_chunk[kChannels];
98
99 in_chunk[0] = in_buffer[0];
100 in_chunk[1] = in_buffer[1];
101 in_chunk[2] = in_buffer[2];
102 out_chunk[0] = out_buffer[0];
103 out_chunk[1] = out_buffer[1];
104 out_chunk[2] = out_buffer[2];
105 SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk);
106 SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk);
107
108 trans.ProcessChunk(in_chunk, out_chunk);
109
110 for (int i = 0; i < kChannels; ++i) {
111 for (int j = 0; j < kChunkLength; ++j) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000112 ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000113 }
114 }
115
116 ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num());
117}
118
119TEST(LappedTransformTest, IdentityProcessor) {
120 const int kChunkLength = 512;
121 const int kBlockLength = 64;
122 const int kShiftAmount = 32;
123 NoopCallback noop;
124 float window[kBlockLength];
125 float* window_ptr = window;
126
127 // Identity window for |overlap = block_size / 2|.
128 SetFloatArray(sqrtf(0.5f), 1, kBlockLength, &window_ptr);
129
130 LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kShiftAmount,
131 &noop);
132 float in_buffer[kChunkLength];
133 float* in_chunk = in_buffer;
134 float out_buffer[kChunkLength];
135 float* out_chunk = out_buffer;
136
137 SetFloatArray(2.0f, 1, kChunkLength, &in_chunk);
138 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
139
140 trans.ProcessChunk(&in_chunk, &out_chunk);
141
142 for (int i = 0; i < kChunkLength; ++i) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000143 ASSERT_NEAR(out_chunk[i],
144 (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
145 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000146 }
147
148 ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
149}
150
151TEST(LappedTransformTest, Callbacks) {
152 const int kChunkLength = 512;
153 const int kBlockLength = 64;
154 FftCheckerCallback call;
155 LappedTransform trans(1, 1, kChunkLength, nullptr, kBlockLength,
156 kBlockLength, &call);
157 float in_buffer[kChunkLength];
158 float* in_chunk = in_buffer;
159 float out_buffer[kChunkLength];
160 float* out_chunk = out_buffer;
161
162 SetFloatArray(1.0f, 1, kChunkLength, &in_chunk);
163 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
164
165 trans.ProcessChunk(&in_chunk, &out_chunk);
166
167 ASSERT_EQ(kChunkLength / kBlockLength, call.block_num());
168}
169
170} // namespace webrtc
171