• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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