/* $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_3 0.577350269
#define LVL_SQRT_2_3 0.816496581
#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_2_3, -LVL_SQRT_1_3, 0, 0, 0, 0, 0, 0 },
{ -LVL_SQRT_1_3, LVL_SQRT_2_3, 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_2_3, -LVL_SQRT_1_3, 0, 0, 0, 0, 0, 0 },
{ -LVL_SQRT_1_3, LVL_SQRT_2_3, 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_2_3*LVL_3DB, -LVL_SQRT_1_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
{ -LVL_SQRT_1_3*LVL_3DB, LVL_SQRT_2_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
{ LVL_SQRT_2_3*LVL_3DB, -LVL_SQRT_1_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
{ -LVL_SQRT_1_3*LVL_3DB, LVL_SQRT_2_3*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
//
// Map Indicies are mode, lfe, channel respectively
int hb_ac3_chan_map[10][2][8] =
{
// w/o LFE w/ LFE
// C L R LS RS Rls Rrs L R C LS RS Rls Rls LFE
{{ 0, }, { 1, 0, }}, // MONO
{{ 0, 1, }, { 1, 2, 0, }}, // STEREO
{{ 1, 0, 2, }, { 2, 1, 3, 0, }}, // 3F
{{ 0, 1, 2, }, { 1, 2, 3, 0, }}, // 2F1R
{{ 1, 0, 2, 3, }, { 2, 1, 3, 4, 0, }}, // 3F1R
{{ 0, 1, 2, 3, }, { 1, 2, 3, 4, 0, }}, // 2F2R
{{ 1, 0, 2, 3, 4, }, { 2, 1, 3, 4, 5, 0, }}, // 3F2R
{{ 1, 0, 2, 3, 4, 5, 6, }, { 2, 1, 3, 4, 5, 6, 7, 0 }}, // 3F4R
{{ 0, 1, }, { 0, 1, }}, // DOLBY
{{ 0, 1, }, { 0, 1, }} // DPLII
};
int hb_smpte_chan_map[10][2][8] =
{
// w/o LFE w/ LFE
// L R C LS RS Rls Rrs L R C LS RS Rls Rls LFE
{{ 0, }, { 0, 1, }}, // MONO
{{ 0, 1, }, { 0, 1, 2, }}, // STEREO
{{ 2, 0, 1, }, { 2, 0, 1, 3, }}, // 3F
{{ 0, 1, 2, }, { 0, 1, 3, 2, }}, // 2F1R
{{ 2, 0, 1, 3, }, { 2, 0, 1, 4, 3, }}, // 3F1R
{{ 0, 1, 2, 3, }, { 0, 1, 3, 4, 2, }}, // 2F2R
{{ 2, 0, 1, 3, 4, }, { 2, 0, 1, 4, 5, 3, }}, // 3F2R
{{ 2, 0, 1, 5, 6, 3, 4, }, { 2, 0, 1, 6, 7, 4, 5, 3 }}, // 3F4R
{{ 0, 1, }, { 0, 1, }}, // DOLBY
{{ 0, 1, }, { 0, 1, }} // 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( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples )
{
int nchans;
int ii, jj;
int lfe;
int * map;
int mode;
hb_sample_t tmp[6];
mode = hb_layout_to_mode(layout);
lfe = ((mode & DOWNMIX_LFE_FLAG) != 0);
mode = mode & DOWNMIX_CHANNEL_MASK;
nchans = nchans_tbl[mode] + lfe;
map = layouts[mode][lfe];
for (ii = 0; ii < nsamples; ii++)
{
for (jj = 0; jj < nchans; jj++)
{
tmp[jj] = samples[jj];
}
for (jj = 0; jj < nchans; jj++)
{
samples[jj] = tmp[map[jj]];
}
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_sample_t (*matrix)[8],
hb_sample_t clev,
hb_sample_t slev,
hb_sample_t level,
int mode_in,
int mode_out)
{
int ii, jj;
int spos;
int layout_in, layout_out;
for (ii = 0; ii < 8; ii++)
{
for (jj = 0; jj < 8; jj++)
{
matrix[ii][jj] *= level;
}
}
if (mode_out >= DOWNMIX_DOLBY)
return;
spos = 3;
layout_in = channel_layout_map[mode_in];
layout_out = channel_layout_map[mode_out];
if (!(layout_in & HB_CH_FRONT_CENTER))
{
spos--;
}
else
{
if (!(layout_out & HB_CH_FRONT_CENTER))
{
for (jj = 0; jj < 8; jj++)
{
matrix[0][jj] *= 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;
}
}
if (layout_in & (HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT))
{
for (jj = 0; jj < 8; jj++)
{
matrix[spos][jj] *= slev;
matrix[spos+1][jj] *= slev;
}
spos += 2;
}
else if (layout_in & (HB_CH_BACK_CENTER))
{
for (jj = 0; jj < 8; jj++)
{
matrix[spos][jj] *= slev;
}
}
if (layout_in & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT))
{
for (jj = 0; jj < 8; jj++)
{
matrix[spos][jj] *= slev;
matrix[spos+1][jj] *= 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 ii, jj;
int mode_in, mode_out;
hb_sample_t level = 1.0;
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_3 + LVL_SQRT_2_3;
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_3 + LVL_SQRT_2_3;
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_3 + 2 * LVL_SQRT_2_3;
}
for (ii = 0; ii < 8; ii++)
{
for (jj = 0; jj < 8; jj++)
{
downmix->matrix[ii][jj] *= level;
}
}
}
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
int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown )
{
int ii, jj;
int lfe_in, lfe_out;
int mode_in, mode_out;
hb_sample_t (*matrix)[8];
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;
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];
}
}
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;
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 )
{
int ii, jj;
int mode_in, mode_out;
hb_sample_t (*matrix)[8];
if ( downmix == NULL )
return;
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;
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];
}
}
downmix->clev = clev;
downmix->slev = slev;
downmix->level = level;
set_level(downmix->matrix, clev, slev, level, mode_in, mode_out);
}
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
downmix->clev = LVL_3DB;
downmix->slev = LVL_3DB;
downmix->level = 1.0;
downmix->bias = 0.0;
set_level(downmix->matrix, LVL_3DB, LVL_3DB, 1.0,
downmix->mode_in, downmix->mode_out);
return downmix;
}
void hb_downmix_close( hb_downmix_t **downmix )
{
if (*downmix != NULL)
free(*downmix);
*downmix = NULL;
}
void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples)
{
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);
}