X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fdownmix.c;h=2a441e9f01964ca40b35a2b1bb03c136c14bcb88;hb=4f0019f03c2e85e8634150ff0c9a31bee6d35ce5;hp=0ab9b90f349839fbba42a3a5a05b06b0ee9545c4;hpb=a9ba7b2e29125df32483cc79ab0315bcec728d9f;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/downmix.c b/libhb/downmix.c index 0ab9b90f..2a441e9f 100644 --- a/libhb/downmix.c +++ b/libhb/downmix.c @@ -16,8 +16,8 @@ #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 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 @@ -605,8 +605,8 @@ hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] = // 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 }, + { -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 }, @@ -699,8 +699,8 @@ hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] = { { 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 }, + { -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 } }, @@ -792,10 +792,10 @@ hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] = { { 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 }, + { -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 } } }, }; @@ -888,6 +888,7 @@ int hb_mixdown_to_mode(uint32_t mixdown) } } + // 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 @@ -924,55 +925,241 @@ int hb_mixdown_to_mode(uint32_t mixdown) // 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] = +#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 = +{ { -// 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 + {{ 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 +} }; -int hb_smpte_chan_map[10][2][8] = +hb_chan_map_t hb_ac3_chan_map = { -// 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 +{ + {{ 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( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples ) +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[6]; + 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; - map = layouts[mode][lfe]; + inv_map = map_in->inv_chan_map[mode][lfe]; + map = map_out->chan_map[mode][lfe]; for (ii = 0; ii < nsamples; ii++) { @@ -982,7 +1169,8 @@ void hb_layout_remap( int (*layouts)[2][8], hb_sample_t * samples, int layout, i } for (jj = 0; jj < nchans; jj++) { - samples[jj] = tmp[map[jj]]; + int ord = map[jj]; + samples[jj] = tmp[inv_map[ord]]; } samples += nchans; } @@ -1016,43 +1204,36 @@ static void matrix_mul( } } -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) +static void set_level( hb_downmix_t * downmix ) { int ii, jj; - int spos; 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++) { - matrix[ii][jj] *= level; + downmix->matrix[ii][jj] *= downmix->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_in & HB_CH_FRONT_CENTER) { if (!(layout_out & HB_CH_FRONT_CENTER)) { for (jj = 0; jj < 8; jj++) { - matrix[0][jj] *= clev; + downmix->matrix[downmix->center][jj] *= downmix->clev; } } } @@ -1064,29 +1245,16 @@ static void set_level( 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++) { - 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; - } + 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; } } @@ -1101,9 +1269,8 @@ static void set_level( // 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 level = downmix->level; hb_sample_t clev = downmix->clev; hb_sample_t slev = downmix->slev; @@ -1182,7 +1349,7 @@ void hb_downmix_adjust_level( hb_downmix_t * downmix ) break; case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DPLII): - level /= 1 + LVL_SQRT_1_3 + LVL_SQRT_2_3; + level /= 1 + LVL_SQRT_1_4 + LVL_SQRT_3_4; break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_MONO): @@ -1199,7 +1366,7 @@ void hb_downmix_adjust_level( hb_downmix_t * downmix ) break; case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DPLII): - level /= 1 + LVL_3DB + LVL_SQRT_1_3 + LVL_SQRT_2_3; + level /= 1 + LVL_3DB + LVL_SQRT_1_4 + LVL_SQRT_3_4; break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_STEREO): @@ -1215,30 +1382,44 @@ void hb_downmix_adjust_level( hb_downmix_t * downmix ) break; case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DPLII): - level /= 1 + LVL_3DB + 2 * LVL_SQRT_1_3 + 2 * LVL_SQRT_2_3; + 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] *= level; + downmix->matrix[ii][jj] = matrix[ii][jj]; } } } -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; @@ -1254,53 +1435,121 @@ int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown ) 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; + + 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 ) { - 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; + downmix->clev = clev; + downmix->slev = slev; + downmix->level = level; + downmix->matrix_initialized = 0; +} - if (mode_in >= DOWNMIX_NUM_MODES || mode_out >= DOWNMIX_NUM_MODES) - return; +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]; - matrix = downmix_matrix[mode_in][mode_out]; + // Copy the matrix + for ( ii = 0; ii < 8; ii++ ) + { + for ( jj = 0; jj < 8; jj++ ) + { + matrix[ii][jj] = downmix->matrix[ii][jj]; + } + } - for (ii = 0; ii < 8; ii++) + // 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++ ) { - for (jj = 0; jj < 8; jj++) + int ord = map[ii]; + int row = inv_map[ord]; + switch (ord) { - downmix->matrix[ii][jj] = matrix[ii][jj]; + 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]; } } - downmix->clev = clev; - downmix->slev = slev; - downmix->level = level; - set_level(downmix->matrix, clev, slev, level, mode_in, mode_out); + + // 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) @@ -1315,12 +1564,11 @@ hb_downmix_t * hb_downmix_init(int layout, int mixdown) return NULL; } // Set some good default values - downmix->clev = LVL_3DB; - downmix->slev = LVL_3DB; - downmix->level = 1.0; + hb_downmix_set_level( downmix, LVL_3DB, LVL_3DB, 1.0 ); downmix->bias = 0.0; - set_level(downmix->matrix, LVL_3DB, LVL_3DB, 1.0, - downmix->mode_in, downmix->mode_out); + 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; } @@ -1331,10 +1579,22 @@ void hb_downmix_close( hb_downmix_t **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) { - matrix_mul(dst, src, downmix->nchans_out, downmix->nchans_in, - nsamples, downmix->matrix, downmix->bias); + 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 )