mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
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
This commit is contained in:
parent
4bfa4a3964
commit
fa3bd6b0e1
1 changed files with 108 additions and 115 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue