From fa3bd6b0e1ae493f72d10668723dd5842ff0a2de Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Apr 2021 10:56:24 +0200 Subject: [PATCH] channelmix: support more than 19 channels The channelmatrix was limited to the 19 known channels, leaving only the first 19 channels usable. Use the full 64x64 matrix instead and make sure to fill all 64 channels with the identity matrix in the case we need to copy or distribute the matrix to unknown positions. See #57 --- spa/plugins/audioconvert/channelmix-ops.c | 223 +++++++++++----------- 1 file changed, 108 insertions(+), 115 deletions(-) diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index 64c904f44..c669c58b0 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -124,27 +124,6 @@ static const struct channelmix_info *find_channelmix_info(uint32_t src_chan, uin return NULL; } -#define M 0 -#define FL 1 -#define FR 2 -#define FC 3 -#define LFE 4 -#define SL 5 -#define SR 6 -#define FLC 7 -#define FRC 8 -#define RC 9 -#define RL 10 -#define RR 11 -#define TC 12 -#define TFL 13 -#define TFC 14 -#define TFR 15 -#define TRL 16 -#define TRC 17 -#define TRR 18 -#define NUM_CHAN 19 - #define SQRT3_2 1.224744871f /* sqrt(3/2) */ #define SQRT1_2 0.707106781f #define SQRT2 1.414213562f @@ -153,14 +132,15 @@ static const struct channelmix_info *find_channelmix_info(uint32_t src_chan, uin #define MATRIX_DOLBY 1 #define MATRIX_DPLII 2 -#define _MASK(ch) (1ULL << SPA_AUDIO_CHANNEL_ ## ch) -#define STEREO (_MASK(FL)|_MASK(FR)) -#define REAR (_MASK(RL)|_MASK(RR)) -#define SIDE (_MASK(SL)|_MASK(SR)) +#define _CH(ch) ((SPA_AUDIO_CHANNEL_ ## ch)-3) +#define _MASK(ch) (1ULL << _CH(ch)) +#define STEREO (_MASK(FL)|_MASK(FR)) +#define REAR (_MASK(RL)|_MASK(RR)) +#define SIDE (_MASK(SL)|_MASK(SR)) static int make_matrix(struct channelmix *mix) { - float matrix[NUM_CHAN][NUM_CHAN] = {{ 0.0f }}; + float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS] = {{ 0.0f }}; uint64_t src_mask = mix->src_mask; uint64_t dst_mask = mix->dst_mask; uint64_t unassigned; @@ -169,35 +149,48 @@ static int make_matrix(struct channelmix *mix) float slev = SQRT1_2; float llev = 0.5f; float maxsum = 0.0f; +#define _MATRIX(s,d) matrix[_CH(s)][_CH(d)] spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64, src_mask, dst_mask); - if ((src_mask & _MASK(MONO)) == _MASK(MONO)) - src_mask = _MASK(FC); - if ((dst_mask & _MASK(MONO)) == _MASK(MONO)) - dst_mask = _MASK(FC); + /* move the MONO mask to FC so that the lower bits can be shifed + * away. */ + if ((src_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0) + src_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC); + if ((dst_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0) + dst_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC); + + /* shift so that bit 0 is FL */ + src_mask >>= 3; + dst_mask >>= 3; if (src_mask == 0 || dst_mask == 0) { if (src_mask == _MASK(FC) && mix->src_chan == 1) { - /* one mono src goes everywhere */ - for (i = 0; i < NUM_CHAN; i++) + /* one FC/MONO src goes everywhere */ + spa_log_debug(mix->log, "distribute FC/MONO"); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) matrix[i][0]= 1.0f; } else if (dst_mask == _MASK(FC) && mix->dst_chan == 1) { - /* one mono dst get average of everything */ - for (i = 0; i < NUM_CHAN; i++) + /* one FC/MONO dst get average of everything */ + spa_log_debug(mix->log, "average FC/MONO"); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) matrix[0][i]= 1.0f / mix->src_chan; } else { /* just pair channels */ - for (i = 0; i < NUM_CHAN; i++) + spa_log_debug(mix->log, "paring channels"); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) matrix[i][i]= 1.0f; } src_mask = dst_mask = ~0LU; goto done; } else { - for (i = 0; i < NUM_CHAN; i++) { - if ((src_mask & dst_mask & (1ULL << (i + 2)))) + spa_log_debug(mix->log, "matching channels"); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + if ((src_mask & dst_mask & (1ULL << i))) { + spa_log_debug(mix->log, "matched %u", i); matrix[i][i]= 1.0f; + } } } @@ -209,11 +202,11 @@ static int make_matrix(struct channelmix *mix) if ((dst_mask & STEREO) == STEREO){ spa_log_debug(mix->log, "assign FC to STEREO"); if(src_mask & STEREO) { - matrix[FL][FC] += clev; - matrix[FR][FC] += clev; + _MATRIX(FL,FC) += clev; + _MATRIX(FR,FC) += clev; } else { - matrix[FL][FC] += SQRT1_2; - matrix[FR][FC] += SQRT1_2; + _MATRIX(FL,FC) += SQRT1_2; + _MATRIX(FR,FC) += SQRT1_2; } } else { spa_log_warn(mix->log, "can't assign FC"); @@ -223,10 +216,10 @@ static int make_matrix(struct channelmix *mix) if (unassigned & STEREO){ if (dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign STEREO to FC"); - matrix[FC][FL] += SQRT1_2; - matrix[FC][FR] += SQRT1_2; + _MATRIX(FC,FL) += SQRT1_2; + _MATRIX(FC,FR) += SQRT1_2; if (src_mask & _MASK(FC)) - matrix[FC][FC] = clev * SQRT2; + _MATRIX(FC,FC) = clev * SQRT2; } else { spa_log_warn(mix->log, "can't assign STEREO"); } @@ -235,30 +228,30 @@ static int make_matrix(struct channelmix *mix) if (unassigned & _MASK(RC)) { if (dst_mask & REAR){ spa_log_debug(mix->log, "assign RC to RL+RR"); - matrix[RL][RC] += SQRT1_2; - matrix[RR][RC] += SQRT1_2; + _MATRIX(RL,RC) += SQRT1_2; + _MATRIX(RR,RC) += SQRT1_2; } else if (dst_mask & SIDE) { spa_log_debug(mix->log, "assign RC to SL+SR"); - matrix[SL][RC] += SQRT1_2; - matrix[SR][RC] += SQRT1_2; + _MATRIX(SL,RC) += SQRT1_2; + _MATRIX(SR,RC) += SQRT1_2; } else if(dst_mask & STEREO) { spa_log_debug(mix->log, "assign RC to FL+FR"); if (matrix_encoding == MATRIX_DOLBY || matrix_encoding == MATRIX_DPLII) { if (unassigned & (_MASK(RL)|_MASK(RR))) { - matrix[FL][RC] -= slev * SQRT1_2; - matrix[FR][RC] += slev * SQRT1_2; + _MATRIX(FL,RC) -= slev * SQRT1_2; + _MATRIX(FR,RC) += slev * SQRT1_2; } else { - matrix[FL][RC] -= slev; - matrix[FR][RC] += slev; + _MATRIX(FL,RC) -= slev; + _MATRIX(FR,RC) += slev; } } else { - matrix[FL][RC] += slev * SQRT1_2; - matrix[FR][RC] += slev * SQRT1_2; + _MATRIX(FL,RC) += slev * SQRT1_2; + _MATRIX(FR,RC) += slev * SQRT1_2; } } else if (dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign RC to FC"); - matrix[FC][RC] += slev * SQRT1_2; + _MATRIX(FC,RC) += slev * SQRT1_2; } else { spa_log_warn(mix->log, "can't assign RC"); } @@ -267,37 +260,37 @@ static int make_matrix(struct channelmix *mix) if (unassigned & REAR) { if (dst_mask & _MASK(RC)) { spa_log_debug(mix->log, "assign RL+RR to RC"); - matrix[RC][RL] += SQRT1_2; - matrix[RC][RR] += SQRT1_2; + _MATRIX(RC,RL) += SQRT1_2; + _MATRIX(RC,RR) += SQRT1_2; } else if (dst_mask & SIDE) { spa_log_debug(mix->log, "assign RL+RR to SL+SR"); if (src_mask & SIDE) { - matrix[SL][RL] += SQRT1_2; - matrix[SR][RR] += SQRT1_2; + _MATRIX(SL,RL) += SQRT1_2; + _MATRIX(SR,RR) += SQRT1_2; } else { - matrix[SL][RL] += 1.0f; - matrix[SR][RR] += 1.0f; + _MATRIX(SL,RL) += 1.0f; + _MATRIX(SR,RR) += 1.0f; } } else if (dst_mask & STEREO) { spa_log_debug(mix->log, "assign RL+RR to FL+FR %f", slev); if (matrix_encoding == MATRIX_DOLBY) { - matrix[FL][RL] -= slev * SQRT1_2; - matrix[FL][RR] -= slev * SQRT1_2; - matrix[FR][RL] += slev * SQRT1_2; - matrix[FR][RR] += slev * SQRT1_2; + _MATRIX(FL,RL) -= slev * SQRT1_2; + _MATRIX(FL,RR) -= slev * SQRT1_2; + _MATRIX(FR,RL) += slev * SQRT1_2; + _MATRIX(FR,RR) += slev * SQRT1_2; } else if (matrix_encoding == MATRIX_DPLII) { - matrix[FL][RL] -= slev * SQRT3_2; - matrix[FL][RR] -= slev * SQRT1_2; - matrix[FR][RL] += slev * SQRT1_2; - matrix[FR][RR] += slev * SQRT3_2; + _MATRIX(FL,RL) -= slev * SQRT3_2; + _MATRIX(FL,RR) -= slev * SQRT1_2; + _MATRIX(FR,RL) += slev * SQRT1_2; + _MATRIX(FR,RR) += slev * SQRT3_2; } else { - matrix[FL][RL] += slev; - matrix[FR][RR] += slev; + _MATRIX(FL,RL) += slev; + _MATRIX(FR,RR) += slev; } } else if (dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign RL+RR to FC"); - matrix[FC][RL]+= slev * SQRT1_2; - matrix[FC][RR]+= slev * SQRT1_2; + _MATRIX(FC,RL)+= slev * SQRT1_2; + _MATRIX(FC,RR)+= slev * SQRT1_2; } else { spa_log_warn(mix->log, "can't assign RL"); } @@ -307,36 +300,36 @@ static int make_matrix(struct channelmix *mix) if (dst_mask & REAR) { spa_log_debug(mix->log, "assign SL+SR to RL+RR"); if (src_mask & _MASK(RL)) { - matrix[RL][SL] += SQRT1_2; - matrix[RR][SR] += SQRT1_2; + _MATRIX(RL,SL) += SQRT1_2; + _MATRIX(RR,SR) += SQRT1_2; } else { - matrix[RL][SL] += 1.0f; - matrix[RR][SR] += 1.0f; + _MATRIX(RL,SL) += 1.0f; + _MATRIX(RR,SR) += 1.0f; } } else if (dst_mask & _MASK(RC)) { spa_log_debug(mix->log, "assign SL+SR to RC"); - matrix[RC][SL]+= SQRT1_2; - matrix[RC][SR]+= SQRT1_2; + _MATRIX(RC,SL)+= SQRT1_2; + _MATRIX(RC,SR)+= SQRT1_2; } else if (dst_mask & STEREO) { spa_log_debug(mix->log, "assign SL+SR to FL+FR"); if (matrix_encoding == MATRIX_DOLBY) { - matrix[FL][SL] -= slev * SQRT1_2; - matrix[FL][SR] -= slev * SQRT1_2; - matrix[FR][SL] += slev * SQRT1_2; - matrix[FR][SR] += slev * SQRT1_2; + _MATRIX(FL,SL) -= slev * SQRT1_2; + _MATRIX(FL,SR) -= slev * SQRT1_2; + _MATRIX(FR,SL) += slev * SQRT1_2; + _MATRIX(FR,SR) += slev * SQRT1_2; } else if (matrix_encoding == MATRIX_DPLII) { - matrix[FL][SL] -= slev * SQRT3_2; - matrix[FL][SR] -= slev * SQRT1_2; - matrix[FR][SL] += slev * SQRT1_2; - matrix[FR][SR] += slev * SQRT3_2; + _MATRIX(FL,SL) -= slev * SQRT3_2; + _MATRIX(FL,SR) -= slev * SQRT1_2; + _MATRIX(FR,SL) += slev * SQRT1_2; + _MATRIX(FR,SR) += slev * SQRT3_2; } else { - matrix[FL][SL] += slev; - matrix[FR][SR] += slev; + _MATRIX(FL,SL) += slev; + _MATRIX(FR,SR) += slev; } } else if (dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign SL+SR to FC"); - matrix[FC][SL] += slev * SQRT1_2; - matrix[FC][SR] += slev * SQRT1_2; + _MATRIX(FC,SL) += slev * SQRT1_2; + _MATRIX(FC,SR) += slev * SQRT1_2; } else { spa_log_warn(mix->log, "can't assign SL"); } @@ -345,12 +338,12 @@ static int make_matrix(struct channelmix *mix) if (unassigned & _MASK(FLC)) { if (dst_mask & STEREO) { spa_log_debug(mix->log, "assign FLC+FRC to FL+FR"); - matrix[FL][FLC]+= 1.0f; - matrix[FR][FRC]+= 1.0f; + _MATRIX(FL,FLC)+= 1.0f; + _MATRIX(FR,FRC)+= 1.0f; } else if(dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign FLC+FRC to FC"); - matrix[FC][FLC]+= SQRT1_2; - matrix[FC][FRC]+= SQRT1_2; + _MATRIX(FC,FLC)+= SQRT1_2; + _MATRIX(FC,FRC)+= SQRT1_2; } else { spa_log_warn(mix->log, "can't assign FLC"); } @@ -359,11 +352,11 @@ static int make_matrix(struct channelmix *mix) SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_MIX_LFE)) { if (dst_mask & _MASK(FC)) { spa_log_debug(mix->log, "assign LFE to FC"); - matrix[FC][LFE] += llev; + _MATRIX(FC,LFE) += llev; } else if (dst_mask & STEREO) { spa_log_debug(mix->log, "assign LFE to FL+FR"); - matrix[FL][LFE] += llev * SQRT1_2; - matrix[FR][LFE] += llev * SQRT1_2; + _MATRIX(FL,LFE) += llev * SQRT1_2; + _MATRIX(FR,LFE) += llev * SQRT1_2; } else { spa_log_warn(mix->log, "can't assign LFE"); } @@ -379,8 +372,8 @@ static int make_matrix(struct channelmix *mix) if (unassigned & _MASK(FC)) { if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce FC from STEREO"); - matrix[FC][FL] += clev; - matrix[FC][FR] += clev; + _MATRIX(FC,FL) += clev; + _MATRIX(FC,FR) += clev; } else { spa_log_warn(mix->log, "can't produce FC"); } @@ -388,8 +381,8 @@ static int make_matrix(struct channelmix *mix) if (unassigned & _MASK(LFE) && mix->lfe_cutoff > 0.0f) { if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce LFE from STEREO"); - matrix[LFE][FL] += llev; - matrix[LFE][FR] += llev; + _MATRIX(LFE,FL) += llev; + _MATRIX(LFE,FR) += llev; } else { spa_log_warn(mix->log, "can't produce LFE"); } @@ -397,39 +390,39 @@ static int make_matrix(struct channelmix *mix) if (unassigned & SIDE) { if ((src_mask & REAR) == REAR) { spa_log_debug(mix->log, "produce SIDE from REAR"); - matrix[SL][RL] += 1.0f; - matrix[SR][RR] += 1.0f; + _MATRIX(SL,RL) += 1.0f; + _MATRIX(SR,RR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce SIDE from STEREO"); - matrix[SL][FL] += 1.0f; - matrix[SR][FR] += 1.0f; + _MATRIX(SL,FL) += 1.0f; + _MATRIX(SR,FR) += 1.0f; } } if (unassigned & REAR) { if ((src_mask & SIDE) == SIDE) { spa_log_debug(mix->log, "produce REAR from SIDE"); - matrix[RL][SL] += 1.0f; - matrix[RR][SR] += 1.0f; + _MATRIX(RL,SL) += 1.0f; + _MATRIX(RR,SR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce REAR from STEREO"); - matrix[RL][FL] += 1.0f; - matrix[RR][FR] += 1.0f; + _MATRIX(RL,FL) += 1.0f; + _MATRIX(RR,FR) += 1.0f; } } done: - for (jc = 0, ic = 0, i = 0; i < NUM_CHAN; i++) { + for (jc = 0, ic = 0, i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { float sum = 0.0f; - if ((dst_mask & (1UL << (i + 2))) == 0) + if ((dst_mask & (1UL << i)) == 0) continue; - for (jc = 0, j = 0; j < NUM_CHAN; j++) { - if ((src_mask & (1UL << (j + 2))) == 0) + for (jc = 0, j = 0; j < SPA_AUDIO_MAX_CHANNELS; j++) { + if ((src_mask & (1UL << j)) == 0) continue; mix->matrix_orig[ic][jc++] = matrix[i][j]; sum += fabs(matrix[i][j]); - if (i == LFE) + if (i == _CH(LFE)) lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->lfe_cutoff / mix->freq); } maxsum = SPA_MAX(maxsum, sum);