blob: 1bfb3b4b6551256286428151ae7eaab097d464d8 [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
54 float full_length = (frames - 1) * 2;
55 ++block_num_;
56
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +000057 if (block_num_ > 0) {
andrew@webrtc.org325cff02014-10-01 17:42:18 +000058 ASSERT_NEAR(in_block[0][0].real(), full_length, 1e-5f);
59 ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
60 for (int i = 1; i < frames; ++i) {
61 ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
62 ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
63 }
64 }
65 }
66
67 int block_num() {
68 return block_num_;
69 }
70
71 private:
72 int block_num_;
73};
74
75void SetFloatArray(float value, int rows, int cols, float* const* array) {
76 for (int i = 0; i < rows; ++i) {
77 for (int j = 0; j < cols; ++j) {
78 array[i][j] = value;
79 }
80 }
81}
82
83} // namespace
84
85namespace webrtc {
86
87TEST(LappedTransformTest, Windowless) {
88 const int kChannels = 3;
89 const int kChunkLength = 512;
90 const int kBlockLength = 64;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +000091 const int kShiftAmount = 64;
andrew@webrtc.org325cff02014-10-01 17:42:18 +000092 NoopCallback noop;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +000093
94 // Rectangular window.
95 float window[kBlockLength];
96 std::fill(window, &window[kBlockLength], 1.0f);
97
98 LappedTransform trans(kChannels, kChannels, kChunkLength, window,
andrew@webrtc.org325cff02014-10-01 17:42:18 +000099 kBlockLength, kShiftAmount, &noop);
100 float in_buffer[kChannels][kChunkLength];
101 float* in_chunk[kChannels];
102 float out_buffer[kChannels][kChunkLength];
103 float* out_chunk[kChannels];
104
105 in_chunk[0] = in_buffer[0];
106 in_chunk[1] = in_buffer[1];
107 in_chunk[2] = in_buffer[2];
108 out_chunk[0] = out_buffer[0];
109 out_chunk[1] = out_buffer[1];
110 out_chunk[2] = out_buffer[2];
111 SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk);
112 SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk);
113
114 trans.ProcessChunk(in_chunk, out_chunk);
115
116 for (int i = 0; i < kChannels; ++i) {
117 for (int j = 0; j < kChunkLength; ++j) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000118 ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000119 }
120 }
121
122 ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num());
123}
124
125TEST(LappedTransformTest, IdentityProcessor) {
126 const int kChunkLength = 512;
127 const int kBlockLength = 64;
128 const int kShiftAmount = 32;
129 NoopCallback noop;
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000130
131 // Identity window for |overlap = block_size / 2|.
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000132 float window[kBlockLength];
133 std::fill(window, &window[kBlockLength], std::sqrt(0.5f));
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000134
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) {
aluebs@webrtc.orgc0da63c2015-01-13 22:28:35 +0000148 ASSERT_NEAR(out_chunk[i],
149 (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
150 1e-5f);
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000151 }
152
153 ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
154}
155
156TEST(LappedTransformTest, Callbacks) {
157 const int kChunkLength = 512;
158 const int kBlockLength = 64;
159 FftCheckerCallback call;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000160
161 // Rectangular window.
162 float window[kBlockLength];
163 std::fill(window, &window[kBlockLength], 1.0f);
164
165 LappedTransform trans(1, 1, kChunkLength, window, kBlockLength,
andrew@webrtc.org325cff02014-10-01 17:42:18 +0000166 kBlockLength, &call);
167 float in_buffer[kChunkLength];
168 float* in_chunk = in_buffer;
169 float out_buffer[kChunkLength];
170 float* out_chunk = out_buffer;
171
172 SetFloatArray(1.0f, 1, kChunkLength, &in_chunk);
173 SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
174
175 trans.ProcessChunk(&in_chunk, &out_chunk);
176
177 ASSERT_EQ(kChunkLength / kBlockLength, call.block_num());
178}
179
180} // namespace webrtc
181