/* $Id: downmix.c,v 1.15 2005/03/17 19:22:47 stebbins Exp $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ #include #include #include #include "common.h" #include "downmix.h" #define LVL_PLUS6DB 2.0 #define LVL_PLUS3DB 1.4142135623730951 #define LVL_3DB 0.7071067811865476 #define LVL_45DB 0.5946035575013605 #define LVL_6DB 0.5 #define LVL_SQRT_1_4 0.5 #define LVL_SQRT_3_4 0.866025404 #define HB_CH_FRONT_LEFT 0x00000001 #define HB_CH_FRONT_RIGHT 0x00000002 #define HB_CH_FRONT_CENTER 0x00000004 #define HB_CH_LOW_FREQUENCY 0x00000008 #define HB_CH_BACK_LEFT 0x00000010 #define HB_CH_BACK_RIGHT 0x00000020 #define HB_CH_BACK_CENTER 0x00000040 #define HB_CH_SIDE_LEFT 0x00000080 #define HB_CH_SIDE_RIGHT 0x00000100 #define HB_CH_SURROUND_MASK 0x000001f0 #define HB_CH_MASK 0x000007ff #define HB_CH_DOLBY 0x00000800 #define HB_CH_DPLII 0x00001000 #define DOWNMIX_MONO 0 #define DOWNMIX_STEREO 1 #define DOWNMIX_3F 2 #define DOWNMIX_2F1R 3 #define DOWNMIX_3F1R 4 #define DOWNMIX_2F2R 5 #define DOWNMIX_3F2R 6 #define DOWNMIX_3F4R 7 #define DOWNMIX_DOLBY 8 #define DOWNMIX_DPLII 9 #define DOWNMIX_NUM_MODES 10 #define DOWNMIX_CHANNEL_MASK 0x0f #define DOWNMIX_LFE_FLAG 0x10 #define DOWNMIX_FLAGS_MASK 0x10 hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] = { // MONO in { // MONO out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DOLBY out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // STEREO in { // MONO out { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DOLBY out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 3F in { // MONO out { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DOLBY out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 2F1R in { // MONO out { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 0, 1, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 1, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 }, { 0, 0, 0, 0, 0, 0, 0 , 1 }, { 0, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, 0, 0 , 0 } }, // DOLBY out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 3F1R in { // MONO out { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 1, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 1, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 1, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 }, { 0, 0, 0, 0, 0, 0, 0 , 1 }, { 0, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, 0, 0 , 0 }, { 0, 0, 0, 0, 0, 0, 0 , 0 } }, // DOLBY out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 2F2R in { // MONO out { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DOLBY out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 }, { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 3F2R in { // MONO out { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F1R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 2F2R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // 3F4R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DOLBY out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, // DPLII out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, }, // 3F4R in { // MONO out { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 } }, // STEREO out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 } }, // 3F out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 } }, // 2F1R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 } }, // 3F1R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 } }, // 2F2R out { { 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 } }, // 3F2R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 }, { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 } }, // 3F4R out { { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 } }, // DOLBY out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 } }, // DPLII out { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 } } }, }; static int channel_layout_map[DOWNMIX_NUM_MODES] = { // DOWNMIX_MONO (HB_CH_FRONT_CENTER), // DOWNMIX_STEREO (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT), // DOWNMIX_3F (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER), // DOWNMIX_2F1R (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_CENTER), // DOWNMIX_3F1R (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_CENTER), // DOWNMIX_2F2R (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), // DOWNMIX_3F2R (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), // DOWNMIX_3F4R (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_SIDE_LEFT| HB_CH_SIDE_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), // DOWNMIX_DOLBY (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT), // DOWNMIX_DPLII (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT) }; int hb_layout_to_mode(int layout) { int mode; switch (layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK) { case HB_INPUT_CH_LAYOUT_MONO: mode = DOWNMIX_MONO; break; case HB_INPUT_CH_LAYOUT_STEREO: mode = DOWNMIX_STEREO; break; case HB_INPUT_CH_LAYOUT_3F: mode = DOWNMIX_3F; break; case HB_INPUT_CH_LAYOUT_2F1R: mode = DOWNMIX_2F1R; break; case HB_INPUT_CH_LAYOUT_3F1R: mode = DOWNMIX_3F1R; break; case HB_INPUT_CH_LAYOUT_2F2R: mode = DOWNMIX_2F2R; break; case HB_INPUT_CH_LAYOUT_3F2R: mode = DOWNMIX_3F2R; break; case HB_INPUT_CH_LAYOUT_4F2R: mode = DOWNMIX_3F2R|DOWNMIX_LFE_FLAG; break; case HB_INPUT_CH_LAYOUT_3F4R: mode = DOWNMIX_3F4R; break; case HB_INPUT_CH_LAYOUT_DOLBY: mode = DOWNMIX_STEREO; break; default: mode = DOWNMIX_STEREO; break; } if (layout & HB_INPUT_CH_LAYOUT_DISCRETE_LFE_MASK) mode |= DOWNMIX_LFE_FLAG; return mode; } int hb_mixdown_to_mode(uint32_t mixdown) { switch (mixdown) { case HB_AMIXDOWN_MONO: return DOWNMIX_MONO; case HB_AMIXDOWN_STEREO: return DOWNMIX_STEREO; case HB_AMIXDOWN_DOLBY: return DOWNMIX_DOLBY; case HB_AMIXDOWN_DOLBYPLII: return DOWNMIX_DPLII; case HB_AMIXDOWN_6CH: return DOWNMIX_3F2R|DOWNMIX_LFE_FLAG; default: return DOWNMIX_STEREO; } } // ffmpeg gives us SMPTE channel layout // We could use this layout and remap channels in encfaac, // but VLC may have problems with remapping, so lets // allow remapping to the default QuickTime order which is: // // C L R LS RS Rls Rrs LFE // // This arrangement also makes it possible to use half as // many downmix matrices since the matrix with and without // LFE are the same. // // Use hb_layout_remap to accomplish this. For convenience // I've provided the necessary maps. // // SMPTE channel layout // // DUAL-MONO L R // DUAL-MONO-LFE L R LFE // MONO M // MONO-LFE M LFE // STEREO L R // STEREO-LFE L R LFE // 3F L R C // 3F-LFE L R C LFE // 2F1 L R S // 2F1-LFE L R LFE S // 3F1 L R C S // 3F1-LFE L R C LFE S // 2F2 L R LS RS // 2F2-LFE L R LFE LS RS // 3F2 L R C LS RS // 3F2-LFE L R C LFE LS RS // 3F4 L R C Rls Rrs LS RS // 3F4-LFE L R C LFE Rls Rrs LS RS // #define CH_C 0 #define CH_L 1 #define CH_R 2 #define CH_CS 3 #define CH_LS 3 #define CH_RS 4 #define CH_Rls 5 #define CH_Rrs 6 #define CH_LFE 7 hb_chan_map_t hb_qt_chan_map = { { {{ CH_C, }, { CH_C, CH_LFE, }}, // MONO {{ CH_L, CH_R, }, { CH_L, CH_R, CH_LFE, }}, // STEREO {{ CH_C, CH_L, CH_R, }, { CH_C, CH_L, CH_R, CH_LFE, }}, // 3F {{ CH_L, CH_R, CH_CS, }, { CH_L, CH_R, CH_CS, CH_LFE, }}, // 2F1R {{ CH_C, CH_L, CH_R, CH_CS, }, { CH_C, CH_L, CH_R, CH_CS, CH_LFE, }}, // 3F1R {{ CH_L, CH_R, CH_LS, CH_RS, }, { CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 2F2R {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, }, { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 3F2R {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, }, { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, CH_LFE }}, // 3F4R {{ CH_L, CH_R, }, { CH_L, CH_R, }}, // DOLBY {{ CH_L, CH_R, }, { CH_L, CH_R, }} // DPLII }, { // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE {{ 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO {{ 0, 1, 2, 0, 0, 0, 0, 0 }, { 0, 1, 2, 0, 0, 0, 0, 3 }}, // 3F {{ 0, 0, 1, 2, 0, 0, 0, 0 }, { 0, 0, 1, 2, 0, 0, 0, 3 }}, // 2F1R {{ 0, 1, 2, 3, 0, 0, 0, 0 }, { 0, 1, 2, 3, 0, 0, 0, 4 }}, // 3F1R {{ 0, 0, 1, 2, 3, 0, 0, 0 }, { 0, 0, 1, 2, 3, 0, 0, 4 }}, // 2F2R {{ 0, 1, 2, 3, 4, 0, 0, 0 }, { 0, 1, 2, 3, 4, 0, 0, 5 }}, // 3F2R {{ 0, 1, 2, 3, 4, 5, 6, 0 }, { 0, 1, 2, 3, 4, 5, 6, 7 }}, // 3F4R {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII } }; hb_chan_map_t hb_smpte_chan_map = { { {{ CH_C, }, { CH_C, CH_LFE, }}, // MONO {{ CH_L, CH_R, }, { CH_L, CH_R, CH_LFE, }}, // STEREO {{ CH_L, CH_R, CH_C, }, { CH_L, CH_R, CH_C, CH_LFE, }}, // 3F {{ CH_L, CH_R, CH_CS, }, { CH_L, CH_R, CH_LFE, CH_CS, }}, // 2F1R {{ CH_L, CH_R, CH_C, CH_CS, }, { CH_L, CH_R, CH_LFE, CH_CS, }}, // 3F1R {{ CH_L, CH_R, CH_LS, CH_RS, }, { CH_L, CH_R, CH_LFE, CH_LS, CH_RS, }}, // 2F2R {{ CH_L, CH_R, CH_C, CH_LS, CH_RS, }, { CH_L, CH_R, CH_C, CH_LFE, CH_LS, CH_RS, }}, // 3F2R {{ CH_L, CH_R, CH_C, CH_Rls, CH_Rrs, CH_LS, CH_RS }, { CH_L, CH_R, CH_C, CH_LFE, CH_Rls, CH_Rrs, CH_LS, CH_RS }}, // 3F4R {{ CH_L, CH_R, }, { CH_L, CH_R, }}, // DOLBY {{ CH_L, CH_R, }, { CH_L, CH_R, }} // DPLII }, { // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE {{ 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO {{ 2, 0, 1, 0, 0, 0, 0, 0 }, { 2, 0, 1, 0, 0, 0, 0, 3 }}, // 3F {{ 0, 0, 1, 2, 0, 0, 0, 0 }, { 0, 0, 1, 3, 0, 0, 0, 2 }}, // 2F1R {{ 2, 0, 1, 3, 0, 0, 0, 0 }, { 2, 0, 1, 4, 0, 0, 0, 3 }}, // 3F1R {{ 0, 0, 1, 2, 3, 0, 0, 0 }, { 0, 0, 1, 3, 4, 0, 0, 2 }}, // 2F2R {{ 2, 0, 1, 3, 4, 0, 0, 0 }, { 2, 0, 1, 4, 5, 0, 0, 3 }}, // 3F2R {{ 2, 0, 1, 5, 6, 3, 4, 0 }, { 2, 0, 1, 6, 7, 4, 5, 3 }}, // 3F4R {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII } }; hb_chan_map_t hb_ac3_chan_map = { { {{ CH_C, }, { CH_LFE, CH_C, }}, // MONO {{ CH_L, CH_R, }, { CH_LFE, CH_L, CH_R, }}, // STEREO {{ CH_L, CH_C, CH_R, }, { CH_LFE, CH_L, CH_C, CH_R, }}, // 3F {{ CH_L, CH_R, CH_CS, }, { CH_LFE, CH_L, CH_R, CH_CS, }}, // 2F1R {{ CH_L, CH_C, CH_R, CH_CS, }, { CH_LFE, CH_L, CH_C, CH_R, CH_CS, }}, // 3F1R {{ CH_L, CH_R, CH_LS, CH_RS, }, { CH_LFE, CH_L, CH_R, CH_LS, CH_RS, }}, // 2F2R {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, }, { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, }}, // 3F2R {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, }, { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs }}, // 3F4R {{ CH_L, CH_R, }, { CH_L, CH_R, }}, // DOLBY {{ CH_L, CH_R, }, { CH_L, CH_R, }} // DPLII }, { // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE {{ 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }}, // MONO {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 1, 2, 0, 0, 0, 0, 0 }}, // STEREO {{ 1, 0, 2, 0, 0, 0, 0, 0 }, { 2, 1, 3, 0, 0, 0, 0, 0 }}, // 3F {{ 0, 0, 1, 2, 0, 0, 0, 0 }, { 0, 1, 2, 3, 0, 0, 0, 0 }}, // 2F1R {{ 1, 0, 2, 3, 0, 0, 0, 0 }, { 2, 1, 3, 4, 0, 0, 0, 0 }}, // 3F1R {{ 0, 0, 1, 2, 3, 0, 0, 0 }, { 0, 1, 2, 3, 4, 0, 0, 0 }}, // 2F2R {{ 1, 0, 2, 3, 4, 0, 0, 0 }, { 2, 1, 3, 4, 5, 0, 0, 0 }}, // 3F2R {{ 1, 0, 2, 3, 4, 5, 6, 0 }, { 2, 1, 3, 4, 5, 6, 7, 0 }}, // 3F4R {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY {{ 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII } }; static const uint8_t nchans_tbl[] = {1, 2, 3, 3, 4, 4, 5, 7, 2, 2}; // Takes a set of samples and remaps the channel layout void hb_layout_remap( hb_chan_map_t * map_in, hb_chan_map_t * map_out, int layout, hb_sample_t * samples, int nsamples ) { int nchans; int ii, jj; int lfe; int * map; int * inv_map; int mode; hb_sample_t tmp[8]; mode = hb_layout_to_mode(layout); lfe = ((mode & DOWNMIX_LFE_FLAG) != 0); mode = mode & DOWNMIX_CHANNEL_MASK; nchans = nchans_tbl[mode] + lfe; inv_map = map_in->inv_chan_map[mode][lfe]; map = map_out->chan_map[mode][lfe]; for (ii = 0; ii < nsamples; ii++) { for (jj = 0; jj < nchans; jj++) { tmp[jj] = samples[jj]; } for (jj = 0; jj < nchans; jj++) { int ord = map[jj]; samples[jj] = tmp[inv_map[ord]]; } samples += nchans; } } static void matrix_mul( hb_sample_t * dst, hb_sample_t * src, int nchans_out, int nchans_in, int nsamples, hb_sample_t (*matrix)[8], hb_sample_t bias) { int nn, ii, jj; hb_sample_t val; for (nn = 0; nn < nsamples; nn++) { for (ii = 0; ii < nchans_out; ii++) { val = 0; for (jj = 0; jj < nchans_in; jj++) { val += src[jj] * matrix[jj][ii]; } dst[ii] = val + bias; } src += nchans_in; dst += nchans_out; } } static void set_level( hb_downmix_t * downmix ) { int ii, jj; int layout_in, layout_out; int mode_in; int mode_out; mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; for (ii = 0; ii < 8; ii++) { for (jj = 0; jj < 8; jj++) { downmix->matrix[ii][jj] *= downmix->level; } } if (mode_out >= DOWNMIX_DOLBY) return; layout_in = channel_layout_map[mode_in]; layout_out = channel_layout_map[mode_out]; if (layout_in & HB_CH_FRONT_CENTER) { if (!(layout_out & HB_CH_FRONT_CENTER)) { for (jj = 0; jj < 8; jj++) { downmix->matrix[downmix->center][jj] *= downmix->clev; } } } if (layout_in & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT)) { if (layout_out & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT)) { // Note, slev only gets set if input has surround, and output has none. return; } } for (jj = 0; jj < 8; jj++) { if ( downmix->left_surround >= 0 ) downmix->matrix[downmix->left_surround][jj] *= downmix->slev; if ( downmix->right_surround >= 0 ) downmix->matrix[downmix->right_surround][jj] *= downmix->slev; if ( downmix->rear_left_surround >= 0 ) downmix->matrix[downmix->rear_left_surround][jj] *= downmix->slev; if ( downmix->rear_right_surround >= 0 ) downmix->matrix[downmix->rear_right_surround][jj] *= downmix->slev; } } #define MIXMODE(x,y) (((x)<<4)|(y)) // The downmix operation can result in new sample values that are // outside the original range of sample values. If you wish to // guarantee that the levels to not exceed the original range, // call this function after initializing downmix and setting // your initial levels. // // Note that this can result in generally lower volume levels // in the resulting downmixed audio. void hb_downmix_adjust_level( hb_downmix_t * downmix ) { int mode_in, mode_out; hb_sample_t level = downmix->level; hb_sample_t clev = downmix->clev; hb_sample_t slev = downmix->slev; mode_in = downmix->mode_in & DOWNMIX_CHANNEL_MASK; mode_out = downmix->mode_out & DOWNMIX_CHANNEL_MASK; switch MIXMODE(mode_in, mode_out) { case MIXMODE(DOWNMIX_STEREO, DOWNMIX_MONO): case MIXMODE(DOWNMIX_2F2R, DOWNMIX_2F1R): case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F1R): case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F1R): case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F1R): case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F2R): level_3db: level /= LVL_PLUS3DB; break; case MIXMODE(DOWNMIX_3F, DOWNMIX_MONO): level /= LVL_PLUS3DB + clev * LVL_PLUS3DB; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F1R): case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F1R): case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F2R): if (1 + clev < LVL_PLUS3DB) goto level_3db; case MIXMODE(DOWNMIX_3F, DOWNMIX_STEREO): case MIXMODE(DOWNMIX_3F, DOWNMIX_2F1R): case MIXMODE(DOWNMIX_3F, DOWNMIX_2F2R): case MIXMODE(DOWNMIX_3F, DOWNMIX_DOLBY): case MIXMODE(DOWNMIX_3F, DOWNMIX_DPLII): case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F1R): case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F2R): case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F2R): level /= 1 + clev; break; case MIXMODE(DOWNMIX_2F1R, DOWNMIX_MONO): level /= LVL_PLUS3DB + LVL_3DB * clev; break; case MIXMODE(DOWNMIX_2F1R, DOWNMIX_DOLBY): level /= 1 + LVL_3DB; break; case MIXMODE(DOWNMIX_2F1R, DOWNMIX_STEREO): case MIXMODE(DOWNMIX_2F1R, DOWNMIX_3F): case MIXMODE(DOWNMIX_3F1R, DOWNMIX_3F): level /= 1 + LVL_3DB * slev; break; case MIXMODE(DOWNMIX_3F1R, DOWNMIX_MONO): level /= LVL_PLUS3DB + LVL_PLUS3DB * clev + LVL_3DB * slev; break; case MIXMODE(DOWNMIX_3F1R, DOWNMIX_STEREO): level /= 1 + clev + LVL_3DB * slev; break; case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DOLBY): case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DPLII): case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DOLBY): level /= 1 + LVL_PLUS3DB; break; case MIXMODE(DOWNMIX_2F2R, DOWNMIX_MONO): level /= LVL_PLUS3DB + LVL_PLUS3DB * slev; break; case MIXMODE(DOWNMIX_2F2R, DOWNMIX_STEREO): case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F): case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F): level /= 1 + slev; break; case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DPLII): level /= 1 + LVL_SQRT_1_4 + LVL_SQRT_3_4; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_MONO): case MIXMODE(DOWNMIX_3F4R, DOWNMIX_MONO): level /= LVL_PLUS3DB + LVL_PLUS3DB * clev * LVL_PLUS3DB * slev; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_STEREO): level /= 1 + clev + slev; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DOLBY): level /= 1 + 3 * LVL_3DB; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DPLII): level /= 1 + LVL_3DB + LVL_SQRT_1_4 + LVL_SQRT_3_4; break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_STEREO): level /= 1 + clev + LVL_PLUS3DB * slev; break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F): level /= 1 + LVL_PLUS3DB * slev; break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DOLBY): level /= 1 + 5 * LVL_3DB; break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DPLII): level /= 1 + LVL_3DB + 2 * LVL_SQRT_1_4 + 2 * LVL_SQRT_3_4; } downmix->level = level; downmix->matrix_initialized = 0; } void hb_downmix_set_bias( hb_downmix_t * downmix, hb_sample_t bias ) { downmix->bias = bias; } // Changes the downmix mode if it needs changing after initialization static void set_mode( hb_downmix_t * downmix ) { int ii, jj; int mode_in, mode_out; hb_sample_t (*matrix)[8]; mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; matrix = downmix_matrix[mode_in][mode_out]; for (ii = 0; ii < 8; ii++) { for (jj = 0; jj < 8; jj++) { downmix->matrix[ii][jj] = matrix[ii][jj]; } } } // Changes the downmix mode if it needs changing after initialization int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown ) { int lfe_in, lfe_out; int mode_in, mode_out; if ( downmix == NULL ) return -1; mode_in = hb_layout_to_mode(layout); mode_out = hb_mixdown_to_mode(mixdown); downmix->mode_in = mode_in; downmix->mode_out = mode_out; mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; if (mode_in >= DOWNMIX_NUM_MODES || mode_out >= DOWNMIX_NUM_MODES) return -1; lfe_in = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0); lfe_out = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0); downmix->nchans_in = nchans_tbl[mode_in] + lfe_in; downmix->nchans_out = nchans_tbl[mode_out] + lfe_out; downmix->matrix_initialized = 0; return 0; } // Changes the downmix levels if they need changing after initialization void hb_downmix_set_level( hb_downmix_t * downmix, hb_sample_t clev, hb_sample_t slev, hb_sample_t level ) { if ( downmix == NULL ) return; downmix->clev = clev; downmix->slev = slev; downmix->level = level; downmix->matrix_initialized = 0; } static void set_chan_map( hb_downmix_t * downmix ) { int nchans; int ii, jj; int lfe; int * map; int * inv_map; int mode; hb_sample_t matrix[8][8]; // Copy the matrix for ( ii = 0; ii < 8; ii++ ) { for ( jj = 0; jj < 8; jj++ ) { matrix[ii][jj] = downmix->matrix[ii][jj]; } } // Rearrange the rows to correspond to the input channel order lfe = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0); mode = downmix->mode_in & DOWNMIX_CHANNEL_MASK; nchans = nchans_tbl[mode] + lfe; map = downmix->map_in.chan_map[mode][lfe]; inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe]; downmix->center = -1; downmix->left_surround = -1; downmix->right_surround = -1; downmix->rear_left_surround = -1; downmix->rear_right_surround = -1; for ( ii = 0; ii < nchans; ii++ ) { int ord = map[ii]; int row = inv_map[ord]; switch (ord) { case CH_C: downmix->center = ii; break; case CH_LS: downmix->left_surround = ii; break; case CH_RS: downmix->right_surround = ii; break; case CH_Rls: downmix->rear_right_surround = ii; break; case CH_Rrs: downmix->rear_left_surround = ii; break; } for ( jj = 0; jj < 8; jj++ ) { downmix->matrix[ii][jj] = matrix[row][jj]; } } // Copy the matrix for ( ii = 0; ii < 8; ii++ ) { for ( jj = 0; jj < 8; jj++ ) { matrix[ii][jj] = downmix->matrix[ii][jj]; } } // Rearrange the columns to correspond to the output channel order lfe = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0); mode = downmix->mode_out & DOWNMIX_CHANNEL_MASK; nchans = nchans_tbl[mode] + lfe; map = downmix->map_out.chan_map[mode][lfe]; inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe]; for ( ii = 0; ii < nchans; ii++ ) { int ord = map[ii]; int col = inv_map[ord]; for ( jj = 0; jj < 8; jj++ ) { downmix->matrix[jj][ii] = matrix[jj][col]; } } } void hb_downmix_set_chan_map( hb_downmix_t * downmix, hb_chan_map_t * map_in, hb_chan_map_t * map_out ) { downmix->map_in = *map_in; downmix->map_out = *map_out; downmix->matrix_initialized = 0; } hb_downmix_t * hb_downmix_init(int layout, int mixdown) { hb_downmix_t * downmix = calloc(1, sizeof(hb_downmix_t)); if (downmix == NULL) return NULL; if ( hb_downmix_set_mode( downmix, layout, mixdown ) < 0 ) { free( downmix ); return NULL; } // Set some good default values hb_downmix_set_level( downmix, LVL_3DB, LVL_3DB, 1.0 ); downmix->bias = 0.0; downmix->matrix_initialized = 0; // The default input and output channel order is QT hb_downmix_set_chan_map( downmix, &hb_qt_chan_map, &hb_qt_chan_map ); return downmix; } void hb_downmix_close( hb_downmix_t **downmix ) { if (*downmix != NULL) free(*downmix); *downmix = NULL; } static void init_matrix( hb_downmix_t * downmix ) { if ( !downmix->matrix_initialized ) { set_mode( downmix ); set_chan_map( downmix ); set_level(downmix); downmix->matrix_initialized = 1; } } void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples) { init_matrix( downmix ); matrix_mul( dst, src, downmix->nchans_out, downmix->nchans_in, nsamples, downmix->matrix, downmix->bias ); } int hb_need_downmix( int layout, int mixdown ) { int mode_in, mode_out; mode_in = hb_layout_to_mode(layout); mode_out = hb_mixdown_to_mode(mixdown); return (mode_in != mode_out); }