blob: 4c4f8ac10c39b53a463e75454a17794d4296c673 [file] [log] [blame]
henrika2250b052019-07-04 11:27:52 +02001/*
2 * Copyright (c) 2019 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 "audio/utility/channel_mixing_matrix.h"
12
13#include <stddef.h>
14
15#include "audio/utility/channel_mixer.h"
16#include "rtc_base/arraysize.h"
17#include "rtc_base/logging.h"
18#include "rtc_base/strings/string_builder.h"
19#include "test/gtest.h"
20
21namespace webrtc {
22
23// Test all possible layout conversions can be constructed and mixed.
24// Also ensure that the channel matrix fulfill certain conditions when remapping
25// is supported.
26TEST(ChannelMixingMatrixTest, ConstructAllPossibleLayouts) {
27 for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
28 input_layout <= CHANNEL_LAYOUT_MAX;
29 input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
30 for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
31 output_layout <= CHANNEL_LAYOUT_MAX;
32 output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
33 // DISCRETE, BITSTREAM can't be tested here based on the current approach.
34 // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
35 // Stereo down mix should never be the output layout.
36 if (input_layout == CHANNEL_LAYOUT_BITSTREAM ||
37 input_layout == CHANNEL_LAYOUT_DISCRETE ||
38 input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
39 output_layout == CHANNEL_LAYOUT_BITSTREAM ||
40 output_layout == CHANNEL_LAYOUT_DISCRETE ||
41 output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
42 output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) {
43 continue;
44 }
45
46 rtc::StringBuilder ss;
47 ss << "Input Layout: " << input_layout
48 << ", Output Layout: " << output_layout;
49 SCOPED_TRACE(ss.str());
50 ChannelMixingMatrix matrix_builder(
51 input_layout, ChannelLayoutToChannelCount(input_layout),
52 output_layout, ChannelLayoutToChannelCount(output_layout));
53 const int input_channels = ChannelLayoutToChannelCount(input_layout);
54 const int output_channels = ChannelLayoutToChannelCount(output_layout);
55 std::vector<std::vector<float>> matrix;
56 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
57
58 if (remapping) {
59 // Also ensure that (when remapping can take place), a maximum of one
60 // input channel is included per output. This knowledge will simplify
61 // the channel mixing algorithm since it allows us to find the only
62 // scale factor which equals 1.0 and copy that input to its
63 // corresponding output. If no such factor can be found, the
64 // corresponding output can be set to zero.
65 for (int i = 0; i < output_channels; i++) {
66 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
67 int num_input_channels_accounted_for_per_output = 0;
68 for (int j = 0; j < input_channels; j++) {
69 float scale = matrix[i][j];
70 if (scale > 0) {
71 EXPECT_EQ(scale, 1.0f);
72 num_input_channels_accounted_for_per_output++;
73 }
74 }
75 // Each output channel shall contain contribution from one or less
76 // input channels.
77 EXPECT_LE(num_input_channels_accounted_for_per_output, 1);
78 }
79 }
80 }
81 }
82}
83
84// Verify channels are mixed and scaled correctly.
85TEST(ChannelMixingMatrixTest, StereoToMono) {
86 ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
87 ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
88 ChannelMixingMatrix matrix_builder(
89 input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
90 ChannelLayoutToChannelCount(output_layout));
91 std::vector<std::vector<float>> matrix;
92 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
93
94 // Input: stereo
95 // LEFT RIGHT
96 // Output: mono CENTER 0.5 0.5
97 //
98 EXPECT_FALSE(remapping);
99 EXPECT_EQ(1u, matrix.size());
100 EXPECT_EQ(2u, matrix[0].size());
101 EXPECT_EQ(0.5f, matrix[0][0]);
102 EXPECT_EQ(0.5f, matrix[0][1]);
103}
104
105TEST(ChannelMixingMatrixTest, MonoToStereo) {
106 ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
107 ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
108 ChannelMixingMatrix matrix_builder(
109 input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
110 ChannelLayoutToChannelCount(output_layout));
111 std::vector<std::vector<float>> matrix;
112 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
113
114 // Input: mono
115 // CENTER
116 // Output: stereo LEFT 1
117 // RIGHT 1
118 //
119 EXPECT_TRUE(remapping);
120 EXPECT_EQ(2u, matrix.size());
121 EXPECT_EQ(1u, matrix[0].size());
122 EXPECT_EQ(1.0f, matrix[0][0]);
123 EXPECT_EQ(1u, matrix[1].size());
124 EXPECT_EQ(1.0f, matrix[1][0]);
125}
126
127TEST(ChannelMixingMatrixTest, MonoToTwoOne) {
128 ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
129 ChannelLayout output_layout = CHANNEL_LAYOUT_2_1;
130 ChannelMixingMatrix matrix_builder(
131 input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
132 ChannelLayoutToChannelCount(output_layout));
133 std::vector<std::vector<float>> matrix;
134 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
135
136 // Input: mono
137 // CENTER
138 // Output: 2.1 FRONT_LEFT 1
139 // FRONT_RIGHT 1
140 // BACK_CENTER 0
141 //
142 EXPECT_FALSE(remapping);
143 EXPECT_EQ(3u, matrix.size());
144 EXPECT_EQ(1u, matrix[0].size());
145 EXPECT_EQ(1.0f, matrix[0][0]);
146 EXPECT_EQ(1.0f, matrix[1][0]);
147 EXPECT_EQ(0.0f, matrix[2][0]);
148}
149
150TEST(ChannelMixingMatrixTest, FiveOneToMono) {
151 ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
152 ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
153 ChannelMixingMatrix matrix_builder(
154 input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
155 ChannelLayoutToChannelCount(output_layout));
156 std::vector<std::vector<float>> matrix;
157 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
158
159 // Note: 1/sqrt(2) is shown as 0.707.
160 //
161 // Input: 5.1
162 // LEFT RIGHT CENTER LFE SIDE_LEFT SIDE_RIGHT
163 // Output: mono CENTER 0.707 0.707 1 0.707 0.707 0.707
164 //
165 EXPECT_FALSE(remapping);
166 EXPECT_EQ(1u, matrix.size());
167 EXPECT_EQ(6u, matrix[0].size());
168 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][0]);
169 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][1]);
170 // The center channel will be mixed at scale 1.
171 EXPECT_EQ(1.0f, matrix[0][2]);
172 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][3]);
173 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][4]);
174 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][5]);
175}
176
177TEST(ChannelMixingMatrixTest, FiveOneBackToStereo) {
178 // Front L, Front R, Front C, LFE, Back L, Back R
179 ChannelLayout input_layout = CHANNEL_LAYOUT_5_1_BACK;
180 ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
181 const int input_channels = ChannelLayoutToChannelCount(input_layout);
182 const int output_channels = ChannelLayoutToChannelCount(output_layout);
183 ChannelMixingMatrix matrix_builder(input_layout, input_channels,
184 output_layout, output_channels);
185 std::vector<std::vector<float>> matrix;
186 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
187
188 // Note: 1/sqrt(2) is shown as 0.707.
189 // Note: The Channels enumerator is given by {LEFT = 0, RIGHT, CENTER, LFE,
190 // BACK_LEFT, BACK_RIGHT,...}, hence we can use the enumerator values as
191 // indexes in the matrix when verifying the scaling factors.
192 //
193 // Input: 5.1
194 // LEFT RIGHT CENTER LFE BACK_LEFT BACK_RIGHT
195 // Output: stereo LEFT 1 0 0.707 0.707 0.707 0
196 // RIGHT 0 1 0.707 0.707 0 0.707
197 //
198 EXPECT_FALSE(remapping);
199 EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
200 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[LEFT].size());
201 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[RIGHT].size());
202 EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
203 EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
204 EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
205 EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
206 EXPECT_EQ(0.0f, matrix[LEFT][BACK_RIGHT]);
207 EXPECT_EQ(0.0f, matrix[RIGHT][BACK_LEFT]);
208 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][CENTER]);
209 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][LFE]);
210 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][BACK_LEFT]);
211 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][CENTER]);
212 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][LFE]);
213 EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][BACK_RIGHT]);
214}
215
216TEST(ChannelMixingMatrixTest, FiveOneToSevenOne) {
217 // Front L, Front R, Front C, LFE, Side L, Side R
218 ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
219 // Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R
220 ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
221 const int input_channels = ChannelLayoutToChannelCount(input_layout);
222 const int output_channels = ChannelLayoutToChannelCount(output_layout);
223 ChannelMixingMatrix matrix_builder(input_layout, input_channels,
224 output_layout, output_channels);
225 std::vector<std::vector<float>> matrix;
226 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
227
228 // Input: 5.1
229 // LEFT RIGHT CENTER LFE SIDE_LEFT SIDE_RIGHT
230 // Output: 7.1 LEFT 1 0 0 0 0 0
231 // RIGHT 0 1 0 0 0 0
232 // CENTER 0 0 1 0 0 0
233 // LFE 0 0 0 1 0 0
234 // SIDE_LEFT 0 0 0 0 1 0
235 // SIDE_RIGHT 0 0 0 0 0 1
236 // BACK_LEFT 0 0 0 0 0 0
237 // BACK_RIGHT 0 0 0 0 0 0
238 //
239 EXPECT_TRUE(remapping);
240 EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
241 for (int i = 0; i < output_channels; i++) {
242 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
243 for (int j = 0; j < input_channels; j++) {
244 if (i == j) {
245 EXPECT_EQ(1.0f, matrix[i][j]);
246 } else {
247 EXPECT_EQ(0.0f, matrix[i][j]);
248 }
249 }
250 }
251}
252
253TEST(ChannelMixingMatrixTest, StereoToFiveOne) {
254 ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
255 ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
256 const int input_channels = ChannelLayoutToChannelCount(input_layout);
257 const int output_channels = ChannelLayoutToChannelCount(output_layout);
258 ChannelMixingMatrix matrix_builder(input_layout, input_channels,
259 output_layout, output_channels);
260 std::vector<std::vector<float>> matrix;
261 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
262
263 // Input: Stereo
264 // LEFT RIGHT
265 // Output: 5.1 LEFT 1 0
266 // RIGHT 0 1
267 // CENTER 0 0
268 // LFE 0 0
269 // SIDE_LEFT 0 0
270 // SIDE_RIGHT 0 0
271 //
272 EXPECT_TRUE(remapping);
273 EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
274 for (int n = 0; n < output_channels; n++) {
275 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
276 if (n == LEFT) {
277 EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
278 EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
279 } else if (n == RIGHT) {
280 EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
281 EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
282 } else {
283 EXPECT_EQ(0.0f, matrix[n][LEFT]);
284 EXPECT_EQ(0.0f, matrix[n][RIGHT]);
285 }
286 }
287}
288
289TEST(ChannelMixingMatrixTest, DiscreteToDiscrete) {
290 const struct {
291 int input_channels;
292 int output_channels;
293 } test_case[] = {
294 {2, 2},
295 {2, 5},
296 {5, 2},
297 };
298
299 for (size_t n = 0; n < arraysize(test_case); n++) {
300 int input_channels = test_case[n].input_channels;
301 int output_channels = test_case[n].output_channels;
302 ChannelMixingMatrix matrix_builder(CHANNEL_LAYOUT_DISCRETE, input_channels,
303 CHANNEL_LAYOUT_DISCRETE,
304 output_channels);
305 std::vector<std::vector<float>> matrix;
306 bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
307 EXPECT_TRUE(remapping);
308 EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
309 for (int i = 0; i < output_channels; i++) {
310 EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
311 for (int j = 0; j < input_channels; j++) {
312 if (i == j) {
313 EXPECT_EQ(1.0f, matrix[i][j]);
314 } else {
315 EXPECT_EQ(0.0f, matrix[i][j]);
316 }
317 }
318 }
319 }
320}
321
322} // namespace webrtc