1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18 #include "channels.h"
19 #include <math.h>
20
21 namespace android::audio_utils::channels {
22
23 // sparseChannelMatrixMultiply must be compiled with specific compiler flags
24 // for optimization. The body is in ChannelMix.cpp.
25 template <audio_channel_mask_t INPUT_CHANNEL_MASK,
26 audio_channel_mask_t OUTPUT_CHANNEL_MASK, bool ACCUMULATE>
27 bool sparseChannelMatrixMultiply(const float *src, float *dst, size_t frameCount);
28
clamp(float value)29 inline float clamp(float value) {
30 constexpr float LIMIT_AMPLITUDE = M_SQRT2; // 3dB = 1.41421356
31 return fmin(fmax(value, -LIMIT_AMPLITUDE), LIMIT_AMPLITUDE);
32 }
33
34 // This method can be evaluated constexpr.
35 template <audio_channel_mask_t OUTPUT_CHANNEL_MASK, size_t M>
fillChannelMatrix(audio_channel_mask_t INPUT_CHANNEL_MASK,float (& matrix)[M][audio_channel_count_from_out_mask (OUTPUT_CHANNEL_MASK)])36 constexpr bool fillChannelMatrix(audio_channel_mask_t INPUT_CHANNEL_MASK,
37 float (&matrix)[M][audio_channel_count_from_out_mask(OUTPUT_CHANNEL_MASK)]) {
38
39 // This is a bit long since there is no functional partial template specialization.
40 if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_STEREO) {
41 // Compute at what index each channel is: samples will be in the following order:
42 // FL FR FC LFE BL BR BC SL SR
43 //
44 // Prior to API 32, use of downmix resulted in channels being scaled in half amplitude.
45 // We now use a compliant downmix matrix for 5.1 with the following standards:
46 // ITU-R 775-2, ATSC A/52, ETSI TS 101 154, IEC 14496-3, which is unity gain for the
47 // front left and front right channel contribution.
48 //
49 // For 7.1 to 5.1 we set equal contributions for the side and back channels
50 // which follow Dolby downmix recommendations.
51 //
52 // We add contributions from the LFE into the L and R channels
53 // at a weight of 0.5 (rather than the power preserving 0.707)
54 // which is to ensure that headphones can still experience LFE
55 // with lesser risk of speaker overload.
56 //
57 // Note: geometrically left and right channels contribute only to the corresponding
58 // left and right outputs respectively. Geometrically center channels contribute
59 // to both left and right outputs, so they are scaled by 0.707 to preserve power.
60 //
61 // (transfer matrix)
62 // FL FR FC LFE BL BR BC SL SR
63 // 1.0 0.707 0.5 0.707 0.5 0.707
64 // 1.0 0.707 0.5 0.707 0.5 0.707
65 size_t index = 0;
66 constexpr float COEF_25 = 0.2508909536f;
67 constexpr float COEF_35 = 0.3543928915f;
68 constexpr float COEF_36 = 0.3552343859f;
69 constexpr float COEF_61 = 0.6057043428f;
70 constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
71
72 constexpr size_t FL = 0;
73 constexpr size_t FR = 1;
74 for (unsigned tmp = INPUT_CHANNEL_MASK; tmp != 0; ++index) {
75 if (index >= M) return false;
76 const unsigned lowestBit = tmp & -(signed)tmp;
77 switch (lowestBit) {
78 case AUDIO_CHANNEL_OUT_FRONT_LEFT:
79 case AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT:
80 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT:
81 matrix[index][FL] = 1.f;
82 matrix[index][FR] = 0.f;
83 break;
84 case AUDIO_CHANNEL_OUT_SIDE_LEFT:
85 case AUDIO_CHANNEL_OUT_BACK_LEFT:
86 case AUDIO_CHANNEL_OUT_TOP_BACK_LEFT:
87 case AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT: // FRONT_WIDE closer to SIDE.
88 matrix[index][FL] = MINUS_3_DB_IN_FLOAT;
89 matrix[index][FR] = 0.f;
90 break;
91 case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
92 case AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT:
93 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT:
94 matrix[index][FL] = 0.f;
95 matrix[index][FR] = 1.f;
96 break;
97 case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
98 case AUDIO_CHANNEL_OUT_BACK_RIGHT:
99 case AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT:
100 case AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT: // FRONT_WIDE closer to SIDE.
101 matrix[index][FL] = 0.f;
102 matrix[index][FR] = MINUS_3_DB_IN_FLOAT;
103 break;
104 case AUDIO_CHANNEL_OUT_FRONT_CENTER:
105 case AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER:
106 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER:
107 matrix[index][FL] = matrix[index][FR] = MINUS_3_DB_IN_FLOAT;
108 break;
109 case AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT:
110 matrix[index][FL] = COEF_61;
111 matrix[index][FR] = 0.f;
112 break;
113 case AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT:
114 matrix[index][FL] = 0.f;
115 matrix[index][FR] = COEF_61;
116 break;
117 case AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER:
118 matrix[index][FL] = COEF_61;
119 matrix[index][FR] = COEF_25;
120 break;
121 case AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER:
122 matrix[index][FL] = COEF_25;
123 matrix[index][FR] = COEF_61;
124 break;
125 case AUDIO_CHANNEL_OUT_TOP_CENTER:
126 matrix[index][FL] = matrix[index][FR] = COEF_36;
127 break;
128 case AUDIO_CHANNEL_OUT_TOP_BACK_CENTER:
129 matrix[index][FL] = matrix[index][FR] = COEF_35;
130 break;
131 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2:
132 matrix[index][FL] = 0.f;
133 matrix[index][FR] = MINUS_3_DB_IN_FLOAT;
134 break;
135 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
136 if (INPUT_CHANNEL_MASK & AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2) {
137 matrix[index][FL] = MINUS_3_DB_IN_FLOAT;
138 matrix[index][FR] = 0.f;
139 break;
140 }
141 FALLTHROUGH_INTENDED;
142 case AUDIO_CHANNEL_OUT_BACK_CENTER:
143 matrix[index][FL] = matrix[index][FR] = 0.5f;
144 break;
145 }
146 tmp ^= lowestBit;
147 }
148 return true;
149 } else if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_5POINT1) {
150 // FL FR FC LFE BL BR
151 size_t index = 0;
152 constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
153 constexpr float MINUS_4_5_DB_IN_FLOAT = 0.5946035575f;
154
155 constexpr size_t FL = 0;
156 constexpr size_t FR = 1;
157 constexpr size_t FC = 2;
158 constexpr size_t LFE = 3;
159 constexpr size_t BL = 4;
160 constexpr size_t BR = 5;
161 for (unsigned tmp = INPUT_CHANNEL_MASK; tmp != 0; ++index) {
162 if (index >= M) return false;
163 const unsigned lowestBit = tmp & -(signed)tmp;
164 matrix[index][FL] = matrix[index][FR] = matrix[index][FC] = 0.f;
165 matrix[index][LFE] = matrix[index][BL] = matrix[index][BR] = 0.f;
166 switch (lowestBit) {
167 case AUDIO_CHANNEL_OUT_FRONT_LEFT:
168 case AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT:
169 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT:
170 matrix[index][FL] = 1.f;
171 break;
172 case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
173 case AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT:
174 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT:
175 matrix[index][FR] = 1.f;
176 break;
177
178 case AUDIO_CHANNEL_OUT_FRONT_CENTER:
179 case AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER:
180 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER:
181 matrix[index][FC] = 1.f;
182 break;
183
184 // ADJUST
185 case AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT: // FRONT_WIDE closer to SIDE.
186 matrix[index][FL] = MINUS_3_DB_IN_FLOAT;
187 matrix[index][BL] = MINUS_4_5_DB_IN_FLOAT;
188 break;
189 case AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT: // FRONT_WIDE closer to SIDE.
190 matrix[index][FR] = MINUS_3_DB_IN_FLOAT;
191 matrix[index][BR] = MINUS_4_5_DB_IN_FLOAT;
192 break;
193
194 case AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER:
195 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
196 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
197 break;
198 case AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER:
199 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
200 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
201 break;
202
203 case AUDIO_CHANNEL_OUT_SIDE_LEFT:
204 case AUDIO_CHANNEL_OUT_BACK_LEFT:
205 case AUDIO_CHANNEL_OUT_TOP_BACK_LEFT:
206 matrix[index][BL] = 1.f;
207 break;
208 case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
209 case AUDIO_CHANNEL_OUT_BACK_RIGHT:
210 case AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT:
211 matrix[index][BR] = 1.f;
212 break;
213
214 case AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT:
215 matrix[index][BL] = 1.f;
216 break;
217 case AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT:
218 matrix[index][BR] = 1.f;
219 break;
220
221 case AUDIO_CHANNEL_OUT_TOP_BACK_CENTER:
222 case AUDIO_CHANNEL_OUT_BACK_CENTER:
223 matrix[index][BL] = matrix[index][BR] = MINUS_3_DB_IN_FLOAT;
224 break;
225
226 case AUDIO_CHANNEL_OUT_TOP_CENTER:
227 matrix[index][FC] = matrix[index][BL] = matrix[index][BR] = 0.5f;
228 break;
229
230 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
231 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2:
232 matrix[index][LFE] = 1.f;
233 break;
234 }
235 tmp ^= lowestBit;
236 }
237 return true;
238 } else if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_7POINT1) {
239 // FL FR FC LFE BL BR SL SR
240 size_t index = 0;
241 constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
242 constexpr float MINUS_4_5_DB_IN_FLOAT = 0.5946035575f;
243
244 constexpr size_t FL = 0;
245 constexpr size_t FR = 1;
246 constexpr size_t FC = 2;
247 constexpr size_t LFE = 3;
248 constexpr size_t BL = 4;
249 constexpr size_t BR = 5;
250 constexpr size_t SL = 6;
251 constexpr size_t SR = 7;
252 for (unsigned tmp = INPUT_CHANNEL_MASK; tmp != 0; ++index) {
253 if (index >= M) return false;
254 const unsigned lowestBit = tmp & -(signed)tmp;
255 matrix[index][FL] = matrix[index][FR] = matrix[index][FC] = 0.f;
256 matrix[index][LFE] = matrix[index][BL] = matrix[index][BR] = 0.f;
257 switch (lowestBit) {
258 case AUDIO_CHANNEL_OUT_FRONT_LEFT:
259 case AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT:
260 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT:
261 matrix[index][FL] = 1.f;
262 break;
263 case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
264 case AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT:
265 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT:
266 matrix[index][FR] = 1.f;
267 break;
268
269 case AUDIO_CHANNEL_OUT_FRONT_CENTER:
270 case AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER:
271 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER:
272 matrix[index][FC] = 1.f;
273 break;
274
275 case AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT: // FRONT_WIDE closer to SIDE.
276 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
277 matrix[index][SL] = MINUS_3_DB_IN_FLOAT;
278 break;
279 case AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT: // FRONT_WIDE closer to SIDE.
280 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
281 matrix[index][SR] = MINUS_3_DB_IN_FLOAT;
282 break;
283
284 case AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER:
285 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
286 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
287 break;
288 case AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER:
289 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
290 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
291 break;
292
293 case AUDIO_CHANNEL_OUT_BACK_LEFT:
294 case AUDIO_CHANNEL_OUT_TOP_BACK_LEFT:
295 matrix[index][BL] = 1.f;
296 break;
297 case AUDIO_CHANNEL_OUT_BACK_RIGHT:
298 case AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT:
299 matrix[index][BR] = 1.f;
300 break;
301
302 case AUDIO_CHANNEL_OUT_SIDE_LEFT:
303 case AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT:
304 matrix[index][SL] = 1.f;
305 break;
306 case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
307 case AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT:
308 matrix[index][SR] = 1.f;
309 break;
310
311 case AUDIO_CHANNEL_OUT_TOP_BACK_CENTER:
312 case AUDIO_CHANNEL_OUT_BACK_CENTER:
313 matrix[index][BL] = matrix[index][BR] = MINUS_3_DB_IN_FLOAT;
314 break;
315
316 case AUDIO_CHANNEL_OUT_TOP_CENTER:
317 matrix[index][FC] = matrix[index][BL] = matrix[index][BR] = 0.5f;
318 break;
319
320 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
321 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2:
322 matrix[index][LFE] = 1.f;
323 break;
324 }
325 tmp ^= lowestBit;
326 }
327 return true;
328 } else if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_7POINT1POINT4) {
329 // FL FR FC LFE BL BR SL SR TFL TFR TBL TBR
330 size_t index = 0;
331 constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
332 constexpr float MINUS_4_5_DB_IN_FLOAT = 0.5946035575f;
333
334 constexpr size_t FL = 0;
335 constexpr size_t FR = 1;
336 constexpr size_t FC = 2;
337 constexpr size_t LFE = 3;
338 constexpr size_t BL = 4;
339 constexpr size_t BR = 5;
340 constexpr size_t SL = 6;
341 constexpr size_t SR = 7;
342 constexpr size_t TFL = 8;
343 constexpr size_t TFR = 9;
344 constexpr size_t TBL = 10;
345 constexpr size_t TBR = 11;
346 for (unsigned tmp = INPUT_CHANNEL_MASK; tmp != 0; ++index) {
347 if (index >= M) return false;
348 const unsigned lowestBit = tmp & -(signed)tmp;
349 matrix[index][FL] = matrix[index][FR] = matrix[index][FC] = 0.f;
350 matrix[index][LFE] = matrix[index][BL] = matrix[index][BR] = 0.f;
351 switch (lowestBit) {
352 case AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT:
353 matrix[index][TFL] = 1.f;
354 break;
355 case AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT:
356 matrix[index][TFR] = 1.f;
357 break;
358 case AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER:
359 matrix[index][TFL] = matrix[index][TFR] = MINUS_3_DB_IN_FLOAT;
360 break;
361
362 case AUDIO_CHANNEL_OUT_FRONT_LEFT:
363 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT:
364 matrix[index][FL] = 1.f;
365 break;
366 case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
367 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT:
368 matrix[index][FR] = 1.f;
369 break;
370
371 case AUDIO_CHANNEL_OUT_FRONT_CENTER:
372 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER:
373 matrix[index][FC] = 1.f;
374 break;
375
376 case AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT: // FRONT_WIDE closer to SIDE.
377 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
378 matrix[index][SL] = MINUS_3_DB_IN_FLOAT;
379 break;
380 case AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT: // FRONT_WIDE closer to SIDE.
381 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
382 matrix[index][SR] = MINUS_3_DB_IN_FLOAT;
383 break;
384
385 case AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER:
386 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
387 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
388 break;
389 case AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER:
390 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
391 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
392 break;
393
394 case AUDIO_CHANNEL_OUT_BACK_LEFT:
395 matrix[index][BL] = 1.f;
396 break;
397 case AUDIO_CHANNEL_OUT_TOP_BACK_LEFT:
398 matrix[index][TBL] = 1.f;
399 break;
400 case AUDIO_CHANNEL_OUT_BACK_RIGHT:
401 matrix[index][BR] = 1.f;
402 break;
403 case AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT:
404 matrix[index][TBR] = 1.f;
405 break;
406
407 case AUDIO_CHANNEL_OUT_SIDE_LEFT:
408 case AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT:
409 matrix[index][SL] = 1.f;
410 break;
411 case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
412 case AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT:
413 matrix[index][SR] = 1.f;
414 break;
415
416 case AUDIO_CHANNEL_OUT_TOP_BACK_CENTER:
417 matrix[index][TBL] = matrix[index][TBR] = MINUS_3_DB_IN_FLOAT;
418 break;
419
420 case AUDIO_CHANNEL_OUT_BACK_CENTER:
421 matrix[index][BL] = matrix[index][BR] = MINUS_3_DB_IN_FLOAT;
422 break;
423
424 case AUDIO_CHANNEL_OUT_TOP_CENTER:
425 matrix[index][TFL] = matrix[index][TFR] = 0.5f;
426 matrix[index][TBL] = matrix[index][TBR] = 0.5f;
427 break;
428
429 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
430 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2:
431 matrix[index][LFE] = 1.f;
432 break;
433 }
434 tmp ^= lowestBit;
435 }
436 return true;
437 } else if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_9POINT1POINT6) {
438 // FL FR FC LFE BL BR SL SR TFL TFR TBL TBR TSL TSR FWL FWR
439 size_t index = 0;
440 constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
441 constexpr float MINUS_4_5_DB_IN_FLOAT = 0.5946035575f;
442
443 constexpr size_t FL = 0;
444 constexpr size_t FR = 1;
445 constexpr size_t FC = 2;
446 constexpr size_t LFE = 3;
447 constexpr size_t BL = 4;
448 constexpr size_t BR = 5;
449 constexpr size_t SL = 6;
450 constexpr size_t SR = 7;
451 constexpr size_t TFL = 8;
452 constexpr size_t TFR = 9;
453 constexpr size_t TBL = 10;
454 constexpr size_t TBR = 11;
455 constexpr size_t TSL = 12;
456 constexpr size_t TSR = 13;
457 constexpr size_t FWL = 14;
458 constexpr size_t FWR = 15;
459 for (unsigned tmp = INPUT_CHANNEL_MASK; tmp != 0; ++index) {
460 if (index >= M) return false;
461 const unsigned lowestBit = tmp & -(signed)tmp;
462 matrix[index][FL] = matrix[index][FR] = matrix[index][FC] = 0.f;
463 matrix[index][LFE] = matrix[index][BL] = matrix[index][BR] = 0.f;
464 switch (lowestBit) {
465 case AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT:
466 matrix[index][TFL] = 1.f;
467 break;
468 case AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT:
469 matrix[index][TFR] = 1.f;
470 break;
471 case AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER:
472 matrix[index][TFL] = matrix[index][TFR] = MINUS_3_DB_IN_FLOAT;
473 break;
474
475 case AUDIO_CHANNEL_OUT_FRONT_LEFT:
476 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT:
477 matrix[index][FL] = 1.f;
478 break;
479 case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
480 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT:
481 matrix[index][FR] = 1.f;
482 break;
483
484 case AUDIO_CHANNEL_OUT_FRONT_CENTER:
485 case AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER:
486 matrix[index][FC] = 1.f;
487 break;
488
489 case AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT:
490 matrix[index][FWL] = 1.f;
491 break;
492 case AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT:
493 matrix[index][FWR] = 1.f;
494 break;
495
496 case AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER:
497 matrix[index][FL] = MINUS_4_5_DB_IN_FLOAT;
498 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
499 break;
500 case AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER:
501 matrix[index][FR] = MINUS_4_5_DB_IN_FLOAT;
502 matrix[index][FC] = MINUS_3_DB_IN_FLOAT;
503 break;
504
505 case AUDIO_CHANNEL_OUT_BACK_LEFT:
506 matrix[index][BL] = 1.f;
507 break;
508 case AUDIO_CHANNEL_OUT_TOP_BACK_LEFT:
509 matrix[index][TBL] = 1.f;
510 break;
511 case AUDIO_CHANNEL_OUT_BACK_RIGHT:
512 matrix[index][BR] = 1.f;
513 break;
514 case AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT:
515 matrix[index][TBR] = 1.f;
516 break;
517
518 case AUDIO_CHANNEL_OUT_SIDE_LEFT:
519 matrix[index][SL] = 1.f;
520 break;
521 case AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT:
522 matrix[index][TSL] = 1.f;
523 break;
524 case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
525 matrix[index][SR] = 1.f;
526 break;
527 case AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT:
528 matrix[index][TSR] = 1.f;
529 break;
530
531 case AUDIO_CHANNEL_OUT_TOP_BACK_CENTER:
532 matrix[index][TBL] = matrix[index][TBR] = MINUS_3_DB_IN_FLOAT;
533 break;
534
535 case AUDIO_CHANNEL_OUT_BACK_CENTER:
536 matrix[index][BL] = matrix[index][BR] = MINUS_3_DB_IN_FLOAT;
537 break;
538
539 case AUDIO_CHANNEL_OUT_TOP_CENTER:
540 matrix[index][TFL] = matrix[index][TFR] = 0.5f;
541 matrix[index][TBL] = matrix[index][TBR] = 0.5f;
542 break;
543
544 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
545 case AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2:
546 matrix[index][LFE] = 1.f;
547 break;
548 }
549 tmp ^= lowestBit;
550 }
551 return true;
552 } else /* constexpr */ {
553 // We only accept NONE here as we don't do anything in that case.
554 static_assert(OUTPUT_CHANNEL_MASK==AUDIO_CHANNEL_NONE);
555 return true;
556 }
557 return false;
558 }
559
560 class IChannelMix {
561 public:
562 virtual ~IChannelMix() = default;
563
564 /**
565 * Set the input channel mask.
566 *
567 * \param inputChannelMask channel position mask for input data.
568 *
569 * \return false if the channel mask is not supported.
570 */
571 virtual bool setInputChannelMask(audio_channel_mask_t inputChannelMask) = 0;
572
573 /**
574 * Returns the input channel mask.
575 */
576 virtual audio_channel_mask_t getInputChannelMask() const = 0;
577
578 /**
579 * Remixes audio data in src to dst.
580 *
581 * \param src input audio buffer to remix
582 * \param dst remixed audio samples
583 * \param frameCount number of frames to remix
584 * \param accumulate is true if the remix is added to the destination or
585 * false if the remix replaces the destination.
586 *
587 * \return false if the channel mask set is not supported.
588 */
589 virtual bool process(
590 const float *src, float *dst, size_t frameCount, bool accumulate) const = 0;
591
592 /**
593 * Remixes audio data in src to dst.
594 *
595 * \param src input audio buffer to remix
596 * \param dst remixed audio samples
597 * \param frameCount number of frames to remix
598 * \param accumulate is true if the remix is added to the destination or
599 * false if the remix replaces the destination.
600 * \param inputChannelMask channel position mask for input data.
601 *
602 * \return false if the channel mask set is not supported.
603 */
604 virtual bool process(const float *src, float *dst, size_t frameCount, bool accumulate,
605 audio_channel_mask_t inputChannelMask) = 0;
606
607 /** Built in ChannelMix factory. */
608 static std::shared_ptr<IChannelMix> create(audio_channel_mask_t outputChannelMask);
609
610 /** Returns true if the Built-in factory supports the outputChannelMask */
611 static bool isOutputChannelMaskSupported(audio_channel_mask_t outputChannelMask);
612 };
613
614 /**
615 * ChannelMix
616 *
617 * Converts audio streams with different positional channel configurations.
618 *
619 */
620 template <audio_channel_mask_t OUTPUT_CHANNEL_MASK>
621 class ChannelMix : public IChannelMix {
622 public:
623 /**
624 * Creates a ChannelMix object
625 *
626 * Note: If construction is unsuccessful then getInputChannelMask will return
627 * AUDIO_CHANNEL_NONE.
628 *
629 * \param inputChannelMask channel position mask for input audio data.
630 */
ChannelMix(audio_channel_mask_t inputChannelMask)631 explicit ChannelMix(audio_channel_mask_t inputChannelMask) {
632 setInputChannelMask(inputChannelMask);
633 }
634
635 ChannelMix() = default;
636
setInputChannelMask(audio_channel_mask_t inputChannelMask)637 bool setInputChannelMask(audio_channel_mask_t inputChannelMask) override {
638 if (mInputChannelMask != inputChannelMask) {
639 if (inputChannelMask & ~((1 << MAX_INPUT_CHANNELS_SUPPORTED) - 1)) {
640 return false; // not channel position mask, or has unknown channels.
641 }
642 if (!fillChannelMatrix<OUTPUT_CHANNEL_MASK>(inputChannelMask, mMatrix)) {
643 return false; // missized matrix.
644 }
645 mInputChannelMask = inputChannelMask;
646 mInputChannelCount = audio_channel_count_from_out_mask(inputChannelMask);
647 }
648 return true;
649 }
650
getInputChannelMask()651 audio_channel_mask_t getInputChannelMask() const override {
652 return mInputChannelMask;
653 }
654
process(const float * src,float * dst,size_t frameCount,bool accumulate)655 bool process(const float *src, float *dst, size_t frameCount,
656 bool accumulate) const override {
657 return accumulate ? processSwitch<true>(src, dst, frameCount)
658 : processSwitch<false>(src, dst, frameCount);
659 }
660
process(const float * src,float * dst,size_t frameCount,bool accumulate,audio_channel_mask_t inputChannelMask)661 bool process(const float *src, float *dst, size_t frameCount,
662 bool accumulate, audio_channel_mask_t inputChannelMask) override {
663 return setInputChannelMask(inputChannelMask) && process(src, dst, frameCount, accumulate);
664 }
665
666 // The maximum channels supported (bits in the channel mask).
667 static constexpr size_t MAX_INPUT_CHANNELS_SUPPORTED = FCC_26;
668
669 private:
670 // Static/const parameters.
671 static inline constexpr audio_channel_mask_t mOutputChannelMask = OUTPUT_CHANNEL_MASK;
672 static inline constexpr size_t mOutputChannelCount =
673 audio_channel_count_from_out_mask(OUTPUT_CHANNEL_MASK);
674 static inline constexpr float MINUS_3_DB_IN_FLOAT = M_SQRT1_2; // -3dB = 0.70710678
675
676 // These values are modified only when the input channel mask changes.
677 // Keep alignment for matrix for more stable benchmarking.
678 //
679 // DO NOT change the order of these variables without running
680 // atest channelmix_benchmark
681 alignas(128) float mMatrix[MAX_INPUT_CHANNELS_SUPPORTED][mOutputChannelCount];
682 audio_channel_mask_t mInputChannelMask = AUDIO_CHANNEL_NONE;
683 size_t mInputChannelCount = 0;
684
685 /**
686 * Remixes audio data in src to dst.
687 *
688 * ACCUMULATE is true if the remix is added to the destination or
689 * false if the remix replaces the destination.
690 *
691 * \param src multichannel audio buffer to remix
692 * \param dst remixed audio samples
693 * \param frameCount number of multichannel frames to remix
694 *
695 * \return false if the CHANNEL_COUNT is not supported.
696 */
697 template <bool ACCUMULATE>
processSwitch(const float * src,float * dst,size_t frameCount)698 bool processSwitch(const float *src, float *dst, size_t frameCount) const {
699 constexpr bool ANDROID_SPECIFIC = true; // change for testing.
700 if constexpr (ANDROID_SPECIFIC) {
701 if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_STEREO
702 || OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_5POINT1) {
703 switch (mInputChannelMask) {
704 case AUDIO_CHANNEL_OUT_STEREO:
705 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_STEREO,
706 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
707 case AUDIO_CHANNEL_OUT_QUAD_BACK:
708 case AUDIO_CHANNEL_OUT_QUAD_SIDE:
709 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_QUAD_BACK,
710 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
711 case AUDIO_CHANNEL_OUT_5POINT1_BACK:
712 case AUDIO_CHANNEL_OUT_5POINT1_SIDE:
713 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1_BACK,
714 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
715 case AUDIO_CHANNEL_OUT_5POINT1POINT2:
716 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1POINT2,
717 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
718 case AUDIO_CHANNEL_OUT_5POINT1POINT4:
719 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1POINT4,
720 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
721 case AUDIO_CHANNEL_OUT_7POINT1:
722 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1,
723 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
724 case AUDIO_CHANNEL_OUT_7POINT1POINT2:
725 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1POINT2,
726 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
727 case AUDIO_CHANNEL_OUT_7POINT1POINT4:
728 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1POINT4,
729 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
730 case AUDIO_CHANNEL_OUT_9POINT1POINT6:
731 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_9POINT1POINT6,
732 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
733 case AUDIO_CHANNEL_OUT_22POINT2:
734 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_22POINT2,
735 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
736 default:
737 break; // handled below.
738 }
739 } else if constexpr (OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_7POINT1
740 || OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_7POINT1POINT4
741 || OUTPUT_CHANNEL_MASK == AUDIO_CHANNEL_OUT_9POINT1POINT6) {
742 switch (mInputChannelMask) {
743 case AUDIO_CHANNEL_OUT_STEREO:
744 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_STEREO,
745 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
746 case AUDIO_CHANNEL_OUT_QUAD_BACK:
747 // Note: case AUDIO_CHANNEL_OUT_QUAD_SIDE is not equivalent.
748 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_QUAD_BACK,
749 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
750 case AUDIO_CHANNEL_OUT_5POINT1_BACK:
751 // Note: case AUDIO_CHANNEL_OUT_5POINT1_SIDE is not equivalent.
752 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1_BACK,
753 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
754 case AUDIO_CHANNEL_OUT_5POINT1POINT2:
755 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1POINT2,
756 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
757 case AUDIO_CHANNEL_OUT_5POINT1POINT4:
758 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_5POINT1POINT4,
759 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
760 case AUDIO_CHANNEL_OUT_7POINT1:
761 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1,
762 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
763 case AUDIO_CHANNEL_OUT_7POINT1POINT2:
764 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1POINT2,
765 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
766 case AUDIO_CHANNEL_OUT_7POINT1POINT4:
767 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_7POINT1POINT4,
768 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
769 case AUDIO_CHANNEL_OUT_9POINT1POINT6:
770 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_9POINT1POINT6,
771 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
772 case AUDIO_CHANNEL_OUT_22POINT2:
773 return sparseChannelMatrixMultiply<AUDIO_CHANNEL_OUT_22POINT2,
774 OUTPUT_CHANNEL_MASK, ACCUMULATE>(src, dst, frameCount);
775 default:
776 break; // handled below.
777 }
778 }
779 }
780 return matrixProcess(src, dst, frameCount, ACCUMULATE);
781 }
782
783 /**
784 * Converts a source audio stream to destination audio stream with a matrix
785 * channel conversion.
786 *
787 * \param src multichannel audio buffer to remix
788 * \param dst remixed audio samples
789 * \param frameCount number of multichannel frames to remix
790 * \param accumulate is true if the remix is added to the destination or
791 * false if the remix replaces the destination.
792 *
793 * \return false if the CHANNEL_COUNT is not supported.
794 */
matrixProcess(const float * src,float * dst,size_t frameCount,bool accumulate)795 bool matrixProcess(const float *src, float *dst, size_t frameCount, bool accumulate) const {
796 // matrix multiply
797 if (mInputChannelMask == AUDIO_CHANNEL_NONE) return false;
798 while (frameCount) {
799 float ch[mOutputChannelCount]{};
800 for (size_t i = 0; i < mInputChannelCount; ++i) {
801 const float (&array)[mOutputChannelCount] = mMatrix[i];
802 for (size_t j = 0; j < mOutputChannelCount; ++j) {
803 ch[j] += array[j] * src[i];
804 }
805 }
806 if (accumulate) {
807 for (size_t j = 0; j < mOutputChannelCount; ++j) {
808 ch[j] += dst[j];
809 }
810 }
811 for (size_t j = 0; j < mOutputChannelCount; ++j) {
812 dst[j] = clamp(ch[j]);
813 }
814 src += mInputChannelCount;
815 dst += mOutputChannelCount;
816 --frameCount;
817 }
818 return true;
819 }
820 };
821
822 } // android::audio_utils::channels
823