/* $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);
}