channelmix: apply channel volumes correctly

This commit is contained in:
Wim Taymans 2019-08-14 14:56:16 +02:00
parent 449d98910b
commit 87ae7a8011
5 changed files with 270 additions and 253 deletions

View file

@ -31,24 +31,20 @@ channelmix_copy_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT ds
uint32_t i, n; uint32_t i, n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
const float *m = mix->matrix;
const float v = mix->volume;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->identity) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
spa_memcpy(d[i], s[i], n_samples * sizeof(float)); spa_memcpy(d[i], s[i], n_samples * sizeof(float));
} }
else { else {
for (i = 0; i < n_dst; i++) { for (i = 0; i < n_dst; i++) {
const float vol = m[i * n_src + i];
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[i][n] = s[i][n] * vol; d[i][n] = s[i][n] * mix->matrix[i][i];
} }
} }
} }
@ -61,13 +57,12 @@ channelmix_f32_n_m_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT
uint32_t i, j, n; uint32_t i, j, n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix;
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
for (i = 0; i < n_dst; i++) { for (i = 0; i < n_dst; i++) {
float sum = 0.0f; float sum = 0.0f;
for (j = 0; j < n_src; j++) for (j = 0; j < n_src; j++)
sum += s[j][n] * m[i * n_src + j]; sum += s[j][n] * mix->matrix[i][j];
d[i][n] = sum; d[i][n] = sum;
} }
} }
@ -83,19 +78,26 @@ channelmix_f32_1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT
uint32_t n; uint32_t n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][0];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
memset(d[1], 0, n_samples * sizeof(float)); memset(d[1], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[0][n] = d[1][n] = s[0][n]; d[0][n] = d[1][n] = s[0][n];
} }
else { else if (mix->equal) {
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[0][n] = d[1][n] = s[0][n] * v; d[0][n] = d[1][n] = s[0][n] * v0;
}
else {
for (n = 0; n < n_samples; n++) {
d[0][n] = s[0][n] * v0;
d[1][n] = s[0][n] * v1;
}
} }
} }
@ -106,15 +108,19 @@ channelmix_f32_2_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT
uint32_t n; uint32_t n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[0][1];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
} }
else { else if (mix->equal) {
const float f = v * 0.5f;
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[0][n] = (s[0][n] + s[1][n]) * f; d[0][n] = (s[0][n] + s[1][n]) * v0;
}
else {
for (n = 0; n < n_samples; n++)
d[0][n] = s[0][n] * v0 + s[1][n] * v1;
} }
} }
@ -125,15 +131,22 @@ channelmix_f32_4_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT
uint32_t n; uint32_t n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[0][1];
const float v2 = mix->matrix[0][2];
const float v3 = mix->matrix[0][3];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
} }
else { else if (mix->equal) {
const float f = v * 0.25f;
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[0][n] = (s[0][n] + s[1][n] + s[2][n] + s[3][n]) * f; d[0][n] = (s[0][n] + s[1][n] + s[2][n] + s[3][n]) * v0;
}
else {
for (n = 0; n < n_samples; n++)
d[0][n] = s[0][n] * v0 + s[1][n] * v1 +
s[2][n] * v2 + s[3][n] * v3;
} }
} }
@ -144,15 +157,20 @@ channelmix_f32_3p1_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t n; uint32_t n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[0][1];
const float v2 = mix->matrix[0][2];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
} }
else { else if (mix->equal) {
const float f = v * 0.5f;
for (n = 0; n < n_samples; n++) for (n = 0; n < n_samples; n++)
d[0][n] = (s[0][n] + s[1][n] + s[2][n]) * f; d[0][n] = (s[0][n] + s[1][n] + s[2][n] + s[3][n]) * v0;
}
else {
for (n = 0; n < n_samples; n++)
d[0][n] = s[0][n] * v0 + s[1][n] * v1 + s[2][n] * v2;
} }
} }
@ -166,22 +184,33 @@ channelmix_f32_2_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT
uint32_t i, n; uint32_t i, n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][1];
const float v2 = mix->matrix[2][0];
const float v3 = mix->matrix[3][1];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = d[2][n] = s[0][n]; d[0][n] = d[2][n] = s[0][n];
d[1][n] = d[3][n] = s[1][n]; d[1][n] = d[3][n] = s[1][n];
} }
} }
else if (v0 == v2 && v1 == v3) {
for (n = 0; n < n_samples; n++) {
d[0][n] = d[2][n] = s[0][n] * v0;
d[1][n] = d[3][n] = s[1][n] * v1;
}
}
else { else {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = d[2][n] = s[0][n] * v; d[0][n] = s[0][n] * v0;
d[1][n] = d[3][n] = s[1][n] * v; d[1][n] = s[1][n] * v1;
d[2][n] = s[0][n] * v2;
d[3][n] = s[1][n] * v3;
} }
} }
} }
@ -194,13 +223,14 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t i, n; uint32_t i, n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][1];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = s[0][n]; d[0][n] = s[0][n];
d[1][n] = s[1][n]; d[1][n] = s[1][n];
@ -209,11 +239,10 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
} }
} }
else { else {
const float f = 0.5f * v;
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = s[0][n] * v; d[0][n] = s[0][n] * v0;
d[1][n] = s[1][n] * v; d[1][n] = s[1][n] * v1;
d[2][n] = (s[0][n] + s[1][n]) * f; d[2][n] = (d[0][n] + d[1][n]) * 0.5f;
d[3][n] = 0.0f; d[3][n] = 0.0f;
} }
} }
@ -227,13 +256,16 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t i, n; uint32_t i, n;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][1];
const float v4 = mix->matrix[4][0];
const float v5 = mix->matrix[5][1];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = d[4][n] = s[0][n]; d[0][n] = d[4][n] = s[0][n];
d[1][n] = d[5][n] = s[1][n]; d[1][n] = d[5][n] = s[1][n];
@ -242,12 +274,13 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
} }
} }
else { else {
const float f = 0.5f * v;
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = d[4][n] = s[0][n] * v; d[0][n] = s[0][n] * v0;
d[1][n] = d[5][n] = s[1][n] * v; d[1][n] = s[1][n] * v1;
d[2][n] = (s[0][n] + s[1][n]) * f; d[2][n] = (d[0][n] + d[1][n]) * 0.5f;
d[3][n] = 0.0f; d[3][n] = 0.0f;
d[4][n] = s[0][n] * v4;
d[5][n] = s[1][n] * v5;
} }
} }
} }
@ -260,28 +293,22 @@ channelmix_f32_5p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t n; uint32_t n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix; const float v0 = mix->matrix[0][0];
const float clev = m[2]; const float v1 = mix->matrix[1][1];
const float llev = m[3]; const float clev = mix->matrix[2][0];
const float slev = m[4]; const float llev = mix->matrix[3][0];
float v = mix->volume; const float slev0 = mix->matrix[4][0];
const float slev1 = mix->matrix[4][1];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
memset(d[1], 0, n_samples * sizeof(float)); memset(d[1], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) {
for (n = 0; n < n_samples; n++) {
const float ctr = clev * s[2][n] + llev * s[3][n];
d[0][n] = s[0][n] + ctr + (slev * s[4][n]);
d[1][n] = s[1][n] + ctr + (slev * s[5][n]);
}
}
else { else {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
const float ctr = clev * s[2][n] + llev * s[3][n]; const float ctr = clev * s[2][n] + llev * s[3][n];
d[0][n] = (s[0][n] + ctr + (slev * s[4][n])) * v; d[0][n] = s[0][n] * v0 + ctr + (slev0 * s[4][n]);
d[1][n] = (s[1][n] + ctr + (slev * s[5][n])) * v; d[1][n] = s[1][n] * v1 + ctr + (slev1 * s[5][n]);
} }
} }
} }
@ -294,19 +321,23 @@ channelmix_f32_5p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
uint32_t i, n; uint32_t i, n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][1];
const float v2 = mix->matrix[2][2];
const float v3 = mix->matrix[3][3];
const float v4 = mix->matrix[0][4];
const float v5 = mix->matrix[1][5];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else { else {
const float f1 = 0.5f * v;
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = (s[0][n] + s[4][n]) * f1; d[0][n] = s[0][n] * v0 + s[4][n] * v4;
d[1][n] = (s[1][n] + s[5][n]) * f1; d[1][n] = s[1][n] * v1 + s[5][n] * v5;
d[2][n] = s[2][n] * v; d[2][n] = s[2][n] * v2;
d[3][n] = s[3][n] * v; d[3][n] = s[3][n] * v3;
} }
} }
} }
@ -319,31 +350,24 @@ channelmix_f32_5p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t i, n; uint32_t i, n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix; const float clev = mix->matrix[2][0];
const float clev = m[2]; const float llev = mix->matrix[3][0];
const float llev = m[3]; const float v0 = mix->matrix[0][0];
float v = mix->volume; const float v1 = mix->matrix[1][1];
const float v4 = mix->matrix[2][4];
const float v5 = mix->matrix[3][5];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) {
for (n = 0; n < n_samples; n++) {
const float ctr = s[2][n] * clev + s[3][n] * llev;
d[0][n] = s[0][n] + ctr;
d[1][n] = s[1][n] + ctr;
d[2][n] = s[4][n];
d[3][n] = s[5][n];
}
}
else { else {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
const float ctr = s[2][n] * clev + s[3][n] * llev; const float ctr = s[2][n] * clev + s[3][n] * llev;
d[0][n] = (s[0][n] + ctr) * v; d[0][n] = s[0][n] * v0 + ctr;
d[1][n] = (s[1][n] + ctr) * v; d[1][n] = s[1][n] * v1 + ctr;
d[2][n] = s[4][n] * v; d[2][n] = s[4][n] * v4;
d[3][n] = s[5][n] * v; d[3][n] = s[5][n] * v5;
} }
} }
} }
@ -358,28 +382,24 @@ channelmix_f32_7p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t n; uint32_t n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix; const float v0 = mix->matrix[0][0];
const float clev = m[2]; const float v1 = mix->matrix[1][1];
const float llev = m[3]; const float clev = (mix->matrix[0][2] + mix->matrix[1][2]) * 0.5f;
const float slev = m[4]; const float llev = (mix->matrix[0][3] + mix->matrix[1][3]) * 0.5f;
float v = mix->volume; const float slev0 = mix->matrix[0][4];
const float slev1 = mix->matrix[1][5];
const float rlev0 = mix->matrix[0][6];
const float rlev1 = mix->matrix[1][7];
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(d[0], 0, n_samples * sizeof(float)); memset(d[0], 0, n_samples * sizeof(float));
memset(d[1], 0, n_samples * sizeof(float)); memset(d[1], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) {
for (n = 0; n < n_samples; n++) {
const float ctr = clev * s[2][n] + llev * s[3][n];
d[0][n] = s[0][n] + ctr + (slev * (s[4][n] + s[6][n]));
d[1][n] = s[1][n] + ctr + (slev * (s[5][n] + s[7][n]));
}
}
else { else {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
const float ctr = clev * s[2][n] + llev * s[3][n]; const float ctr = clev * s[2][n] + llev * s[3][n];
d[0][n] = (s[0][n] + ctr + (slev * (s[4][n] + s[6][n]))) * v; d[0][n] = s[0][n] * v0 + ctr + s[4][n] * slev0 + s[6][n] * rlev0;
d[1][n] = (s[1][n] + ctr + (slev * (s[5][n] + s[6][n]))) * v; d[1][n] = s[1][n] * v1 + ctr + s[5][n] * slev1 + s[6][n] * rlev1;
} }
} }
} }
@ -392,19 +412,23 @@ channelmix_f32_7p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
uint32_t i, n; uint32_t i, n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
float v = mix->volume; const float v0 = mix->matrix[0][0];
const float v1 = mix->matrix[1][1];
const float v2 = mix->matrix[2][2];
const float v3 = mix->matrix[3][3];
const float v4 = (mix->matrix[0][4] + mix->matrix[0][6]) * 0.5f;
const float v5 = (mix->matrix[1][5] + mix->matrix[1][6]) * 0.5f;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else { else {
const float f1 = 0.5 * v;
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
d[0][n] = s[0][n] + (s[4][n] + s[6][n]) * f1; d[0][n] = s[0][n] * v0 + (s[4][n] + s[6][n]) * v4;
d[1][n] = s[1][n] + (s[5][n] + s[7][n]) * f1; d[1][n] = s[1][n] * v1 + (s[5][n] + s[7][n]) * v5;
d[2][n] = s[2][n] * v; d[2][n] = s[2][n] * v2;
d[3][n] = s[3][n] * v; d[3][n] = s[3][n] * v3;
} }
} }
} }
@ -417,36 +441,28 @@ channelmix_f32_7p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t i, n; uint32_t i, n;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix; const float v0 = mix->matrix[0][0];
const float clev = m[2]; const float v1 = mix->matrix[1][1];
const float llev = m[3]; const float clev = (mix->matrix[0][2] + mix->matrix[1][2]) * 0.5f;
const float slev = m[4]; const float llev = (mix->matrix[0][3] + mix->matrix[1][3]) * 0.5f;
float v = mix->volume; const float slev0 = mix->matrix[0][4];
const float slev1 = mix->matrix[1][5];
const float rlev0 = mix->matrix[0][6];
const float rlev1 = mix->matrix[1][7];
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) {
for (n = 0; n < n_samples; n++) {
const float ctr = s[2][n] * clev + s[3][n] * llev;
const float sl = s[4][n] * slev;
const float sr = s[5][n] * slev;
d[0][n] = s[0][n] + ctr + sl;
d[1][n] = s[1][n] + ctr + sr;
d[2][n] = s[6][n] + sl;
d[3][n] = s[7][n] + sr;
}
}
else { else {
for (n = 0; n < n_samples; n++) { for (n = 0; n < n_samples; n++) {
const float ctr = s[2][n] * clev + s[3][n] * llev; const float ctr = s[2][n] * clev + s[3][n] * llev;
const float sl = s[4][n] * slev; const float sl = s[4][n] * slev0;
const float sr = s[5][n] * slev; const float sr = s[5][n] * slev1;
d[0][n] = (s[0][n] + ctr + sl) * v; d[0][n] = s[0][n] * v0 + ctr + sl;
d[1][n] = (s[1][n] + ctr + sr) * v; d[1][n] = s[1][n] * v1 + ctr + sr;
d[2][n] = (s[6][n] + sl) * v; d[2][n] = s[6][n] * rlev0 + sl;
d[3][n] = (s[7][n] + sr) * v; d[3][n] = s[7][n] * rlev1 + sr;
} }
} }
} }

View file

@ -32,14 +32,12 @@ void channelmix_copy_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
uint32_t i, n, unrolled; uint32_t i, n, unrolled;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float *m = mix->matrix;
float v = mix->volume;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
spa_memcpy(d[i], s[i], n_samples * sizeof(float)); spa_memcpy(d[i], s[i], n_samples * sizeof(float));
} }
@ -48,7 +46,7 @@ void channelmix_copy_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
float *di = d[i]; float *di = d[i];
const float *si = s[i]; const float *si = s[i];
__m128 t[4]; __m128 t[4];
const __m128 vol = _mm_set1_ps(m[i * n_src + i]); const __m128 vol = _mm_set1_ps(mix->matrix[i][i]);
if (SPA_IS_ALIGNED(di, 16) && if (SPA_IS_ALIGNED(di, 16) &&
SPA_IS_ALIGNED(si, 16)) SPA_IS_ALIGNED(si, 16))
@ -79,8 +77,8 @@ channelmix_f32_2_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
uint32_t i, n, unrolled; uint32_t i, n, unrolled;
float **d = (float **)dst; float **d = (float **)dst;
const float **s = (const float **)src; const float **s = (const float **)src;
float v = mix->volume; const __m128 v0 = _mm_set1_ps(mix->matrix[0][0]);
const __m128 vol = _mm_set1_ps(v); const __m128 v1 = _mm_set1_ps(mix->matrix[1][1]);
__m128 in; __m128 in;
const float *sFL = s[0], *sFR = s[1]; const float *sFL = s[0], *sFR = s[1];
float *dFL = d[0], *dFR = d[1], *dRL = d[2], *dRR = d[3]; float *dFL = d[0], *dFR = d[1], *dRL = d[2], *dRR = d[3];
@ -95,11 +93,11 @@ channelmix_f32_2_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
else else
unrolled = 0; unrolled = 0;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
in = _mm_load_ps(&sFL[n]); in = _mm_load_ps(&sFL[n]);
_mm_store_ps(&dFL[n], in); _mm_store_ps(&dFL[n], in);
@ -119,18 +117,18 @@ channelmix_f32_2_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRI
} }
else { else {
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
in = _mm_mul_ps(_mm_load_ps(&sFL[n]), vol); in = _mm_mul_ps(_mm_load_ps(&sFL[n]), v0);
_mm_store_ps(&dFL[n], in); _mm_store_ps(&dFL[n], in);
_mm_store_ps(&dRL[n], in); _mm_store_ps(&dRL[n], in);
in = _mm_mul_ps(_mm_load_ps(&sFR[n]), vol); in = _mm_mul_ps(_mm_load_ps(&sFR[n]), v1);
_mm_store_ps(&dFR[n], in); _mm_store_ps(&dFR[n], in);
_mm_store_ps(&dRR[n], in); _mm_store_ps(&dRR[n], in);
} }
for(; n < n_samples; n++) { for(; n < n_samples; n++) {
in = _mm_mul_ss(_mm_load_ss(&sFL[n]), vol); in = _mm_mul_ss(_mm_load_ss(&sFL[n]), v0);
_mm_store_ss(&dFL[n], in); _mm_store_ss(&dFL[n], in);
_mm_store_ss(&dRL[n], in); _mm_store_ss(&dRL[n], in);
in = _mm_mul_ss(_mm_load_ss(&sFR[n]), vol); in = _mm_mul_ss(_mm_load_ss(&sFR[n]), v1);
_mm_store_ss(&dFR[n], in); _mm_store_ss(&dFR[n], in);
_mm_store_ss(&dRR[n], in); _mm_store_ss(&dRR[n], in);
} }
@ -145,12 +143,12 @@ channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
uint32_t n, unrolled; uint32_t n, unrolled;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
float v = mix->volume; const __m128 v0 = _mm_set1_ps(mix->matrix[0][0]);
const float *m = mix->matrix; const __m128 v1 = _mm_set1_ps(mix->matrix[1][1]);
const __m128 clev = _mm_set1_ps(m[2]); const __m128 clev = _mm_set1_ps(mix->matrix[2][0]);
const __m128 llev = _mm_set1_ps(m[3]); const __m128 llev = _mm_set1_ps(mix->matrix[3][0]);
const __m128 slev = _mm_set1_ps(m[4]); const __m128 slev0 = _mm_set1_ps(mix->matrix[4][0]);
const __m128 vol = _mm_set1_ps(v); const __m128 slev1 = _mm_set1_ps(mix->matrix[4][1]);
__m128 in, ctr; __m128 in, ctr;
const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5]; const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5];
float *dFL = d[0], *dFR = d[1]; float *dFL = d[0], *dFR = d[1];
@ -167,19 +165,19 @@ channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
else else
unrolled = 0; unrolled = 0;
if (v <= VOLUME_MIN) { if (mix->zero) {
memset(dFL, 0, n_samples * sizeof(float)); memset(dFL, 0, n_samples * sizeof(float));
memset(dFR, 0, n_samples * sizeof(float)); memset(dFR, 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev); ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev);
ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev)); ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev));
in = _mm_mul_ps(_mm_load_ps(&sSL[n]), slev); in = _mm_mul_ps(_mm_load_ps(&sSL[n]), slev0);
in = _mm_add_ps(in, ctr); in = _mm_add_ps(in, ctr);
in = _mm_add_ps(in, _mm_load_ps(&sFL[n])); in = _mm_add_ps(in, _mm_load_ps(&sFL[n]));
_mm_store_ps(&dFL[n], in); _mm_store_ps(&dFL[n], in);
in = _mm_mul_ps(_mm_load_ps(&sSR[n]), slev); in = _mm_mul_ps(_mm_load_ps(&sSR[n]), slev1);
in = _mm_add_ps(in, ctr); in = _mm_add_ps(in, ctr);
in = _mm_add_ps(in, _mm_load_ps(&sFR[n])); in = _mm_add_ps(in, _mm_load_ps(&sFR[n]));
_mm_store_ps(&dFR[n], in); _mm_store_ps(&dFR[n], in);
@ -187,11 +185,11 @@ channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
for(; n < n_samples; n++) { for(; n < n_samples; n++) {
ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev); ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev);
ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev)); ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev));
in = _mm_mul_ss(_mm_load_ss(&sSL[n]), slev); in = _mm_mul_ss(_mm_load_ss(&sSL[n]), slev0);
in = _mm_add_ss(in, ctr); in = _mm_add_ss(in, ctr);
in = _mm_add_ss(in, _mm_load_ss(&sFL[n])); in = _mm_add_ss(in, _mm_load_ss(&sFL[n]));
_mm_store_ss(&dFL[n], in); _mm_store_ss(&dFL[n], in);
in = _mm_mul_ss(_mm_load_ss(&sSR[n]), slev); in = _mm_mul_ss(_mm_load_ss(&sSR[n]), slev1);
in = _mm_add_ss(in, ctr); in = _mm_add_ss(in, ctr);
in = _mm_add_ss(in, _mm_load_ss(&sFR[n])); in = _mm_add_ss(in, _mm_load_ss(&sFR[n]));
_mm_store_ss(&dFR[n], in); _mm_store_ss(&dFR[n], in);
@ -201,29 +199,29 @@ channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev); ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev);
ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev)); ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev));
in = _mm_mul_ps(_mm_load_ps(&sSL[n]), slev); in = _mm_mul_ps(_mm_load_ps(&sSL[n]), slev0);
in = _mm_add_ps(in, ctr); in = _mm_add_ps(in, ctr);
in = _mm_add_ps(in, _mm_load_ps(&sFL[n])); in = _mm_add_ps(in, _mm_load_ps(&sFL[n]));
in = _mm_mul_ps(in, vol); in = _mm_mul_ps(in, v0);
_mm_store_ps(&dFL[n], in); _mm_store_ps(&dFL[n], in);
in = _mm_mul_ps(_mm_load_ps(&sSR[n]), slev); in = _mm_mul_ps(_mm_load_ps(&sSR[n]), slev1);
in = _mm_add_ps(in, ctr); in = _mm_add_ps(in, ctr);
in = _mm_add_ps(in, _mm_load_ps(&sFR[n])); in = _mm_add_ps(in, _mm_load_ps(&sFR[n]));
in = _mm_mul_ps(in, vol); in = _mm_mul_ps(in, v1);
_mm_store_ps(&dFR[n], in); _mm_store_ps(&dFR[n], in);
} }
for(; n < n_samples; n++) { for(; n < n_samples; n++) {
ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev); ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev);
ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev)); ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev));
in = _mm_mul_ss(_mm_load_ss(&sSL[n]), slev); in = _mm_mul_ss(_mm_load_ss(&sSL[n]), slev0);
in = _mm_add_ss(in, ctr); in = _mm_add_ss(in, ctr);
in = _mm_add_ss(in, _mm_load_ss(&sFL[n])); in = _mm_add_ss(in, _mm_load_ss(&sFL[n]));
in = _mm_mul_ss(in, vol); in = _mm_mul_ss(in, v0);
_mm_store_ss(&dFL[n], in); _mm_store_ss(&dFL[n], in);
in = _mm_mul_ss(_mm_load_ss(&sSR[n]), slev); in = _mm_mul_ss(_mm_load_ss(&sSR[n]), slev1);
in = _mm_add_ss(in, ctr); in = _mm_add_ss(in, ctr);
in = _mm_add_ss(in, _mm_load_ss(&sFR[n])); in = _mm_add_ss(in, _mm_load_ss(&sFR[n]));
in = _mm_mul_ss(in, vol); in = _mm_mul_ss(in, v1);
_mm_store_ss(&dFR[n], in); _mm_store_ss(&dFR[n], in);
} }
} }
@ -237,9 +235,12 @@ channelmix_f32_5p1_3p1_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RE
uint32_t i, n, unrolled; uint32_t i, n, unrolled;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
float v = mix->volume; const __m128 v0 = _mm_set1_ps(mix->matrix[0][0]);
const __m128 slev = _mm_set1_ps(v * 0.5f); const __m128 v1 = _mm_set1_ps(mix->matrix[1][1]);
const __m128 vol = _mm_set1_ps(v); const __m128 slev0 = _mm_set1_ps(mix->matrix[0][4]);
const __m128 slev1 = _mm_set1_ps(mix->matrix[1][5]);
const __m128 v2 = _mm_set1_ps(mix->matrix[2][2]);
const __m128 v3 = _mm_set1_ps(mix->matrix[3][3]);
__m128 avg[2]; __m128 avg[2];
const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5]; const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5];
float *dFL = d[0], *dFR = d[1], *dFC = d[2], *dLFE = d[3]; float *dFL = d[0], *dFR = d[1], *dFC = d[2], *dLFE = d[3];
@ -258,56 +259,48 @@ channelmix_f32_5p1_3p1_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RE
else else
unrolled = 0; unrolled = 0;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) {
for(n = 0; n < unrolled; n += 8) {
avg[0] = _mm_add_ps(_mm_load_ps(&sFL[n]), _mm_load_ps(&sSL[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFL[n+4]), _mm_load_ps(&sSL[n+4]));
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], slev));
avg[0] = _mm_add_ps(_mm_load_ps(&sFR[n]), _mm_load_ps(&sSR[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFR[n+4]), _mm_load_ps(&sSR[n+4]));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], slev));
_mm_store_ps(&dFC[n], _mm_load_ps(&sFC[n]));
_mm_store_ps(&dFC[n+4], _mm_load_ps(&sFC[n+4]));
_mm_store_ps(&dLFE[n], _mm_load_ps(&sLFE[n]));
_mm_store_ps(&dLFE[n+4], _mm_load_ps(&sLFE[n+4]));
}
for(; n < n_samples; n++) {
avg[0] = _mm_add_ss(_mm_load_ss(&sFL[n]), _mm_load_ss(&sSL[n]));
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], slev));
avg[0] = _mm_add_ss(_mm_load_ss(&sFR[n]), _mm_load_ss(&sSR[n]));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], slev));
_mm_store_ss(&dFC[n], _mm_load_ss(&sFC[n]));
_mm_store_ss(&dLFE[n], _mm_load_ss(&sLFE[n]));
}
}
else { else {
for(n = 0; n < unrolled; n += 8) { for(n = 0; n < unrolled; n += 8) {
avg[0] = _mm_add_ps(_mm_load_ps(&sFL[n]), _mm_load_ps(&sSL[n])); avg[0] = _mm_add_ps(
avg[1] = _mm_add_ps(_mm_load_ps(&sFL[n+4]), _mm_load_ps(&sSL[n+4])); _mm_mul_ps(_mm_load_ps(&sFL[n]), v0),
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], slev)); _mm_mul_ps(_mm_load_ps(&sSL[n]), slev0));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], slev)); avg[1] = _mm_add_ps(
avg[0] = _mm_add_ps(_mm_load_ps(&sFR[n]), _mm_load_ps(&sSR[n])); _mm_mul_ps(_mm_load_ps(&sFL[n+4]), v0),
avg[1] = _mm_add_ps(_mm_load_ps(&sFR[n+4]), _mm_load_ps(&sSR[n+4])); _mm_mul_ps(_mm_load_ps(&sSL[n+4]), slev0));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], slev)); _mm_store_ps(&dFL[n], avg[0]);
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], slev)); _mm_store_ps(&dFL[n+4], avg[1]);
_mm_store_ps(&dFC[n], _mm_mul_ps(_mm_load_ps(&sFC[n]), vol));
_mm_store_ps(&dFC[n+4], _mm_mul_ps(_mm_load_ps(&sFC[n+4]), vol)); avg[0] = _mm_add_ps(
_mm_store_ps(&dLFE[n], _mm_mul_ps(_mm_load_ps(&sLFE[n]), vol)); _mm_mul_ps(_mm_load_ps(&sFR[n]), v1),
_mm_store_ps(&dLFE[n+4], _mm_mul_ps(_mm_load_ps(&sLFE[n+4]), vol)); _mm_mul_ps(_mm_load_ps(&sSR[n]), slev1));
avg[1] = _mm_add_ps(
_mm_mul_ps(_mm_load_ps(&sFR[n+4]), v1),
_mm_mul_ps(_mm_load_ps(&sSR[n+4]), slev1));
_mm_store_ps(&dFR[n], avg[0]);
_mm_store_ps(&dFR[n+4], avg[1]);
_mm_store_ps(&dFC[n], _mm_mul_ps(_mm_load_ps(&sFC[n]), v2));
_mm_store_ps(&dFC[n+4], _mm_mul_ps(_mm_load_ps(&sFC[n+4]), v2));
_mm_store_ps(&dLFE[n], _mm_mul_ps(_mm_load_ps(&sLFE[n]), v3));
_mm_store_ps(&dLFE[n+4], _mm_mul_ps(_mm_load_ps(&sLFE[n+4]), v3));
} }
for(; n < n_samples; n++) { for(; n < n_samples; n++) {
avg[0] = _mm_add_ss(_mm_load_ss(&sFL[n]), _mm_load_ss(&sSL[n])); avg[0] = _mm_add_ss(
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], slev)); _mm_mul_ss(_mm_load_ss(&sFL[n]), v0),
avg[0] = _mm_add_ss(_mm_load_ss(&sFR[n]), _mm_load_ss(&sSR[n])); _mm_mul_ss(_mm_load_ss(&sSL[n]), slev0));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], slev)); _mm_store_ss(&dFL[n], avg[0]);
_mm_store_ss(&dFC[n], _mm_mul_ss(_mm_load_ss(&sFC[n]), vol));
_mm_store_ss(&dLFE[n], _mm_mul_ss(_mm_load_ss(&sLFE[n]), vol)); avg[0] = _mm_add_ss(
_mm_mul_ss(_mm_load_ss(&sFR[n]), v1),
_mm_mul_ss(_mm_load_ss(&sSR[n]), slev1));
_mm_store_ss(&dFR[n], avg[0]);
_mm_store_ss(&dFC[n], _mm_mul_ss(_mm_load_ss(&sFC[n]), v2));
_mm_store_ss(&dLFE[n], _mm_mul_ss(_mm_load_ss(&sLFE[n]), v3));
} }
} }
} }
@ -320,11 +313,10 @@ channelmix_f32_5p1_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
uint32_t i, n, unrolled; uint32_t i, n, unrolled;
float **d = (float **) dst; float **d = (float **) dst;
const float **s = (const float **) src; const float **s = (const float **) src;
const float *m = mix->matrix; const __m128 clev = _mm_set1_ps(mix->matrix[2][2]);
float v = mix->volume; const __m128 llev = _mm_set1_ps(mix->matrix[3][3]);
const __m128 clev = _mm_set1_ps(m[2]); const __m128 v0 = _mm_set1_ps(mix->matrix[0][0]);
const __m128 llev = _mm_set1_ps(m[3]); const __m128 v1 = _mm_set1_ps(mix->matrix[1][1]);
const __m128 vol = _mm_set1_ps(v);
__m128 ctr; __m128 ctr;
const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5]; const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5];
float *dFL = d[0], *dFR = d[1], *dRL = d[2], *dRR = d[3]; float *dFL = d[0], *dFR = d[1], *dRL = d[2], *dRR = d[3];
@ -343,11 +335,11 @@ channelmix_f32_5p1_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
else else
unrolled = 0; unrolled = 0;
if (v <= VOLUME_MIN) { if (mix->zero) {
for (i = 0; i < n_dst; i++) for (i = 0; i < n_dst; i++)
memset(d[i], 0, n_samples * sizeof(float)); memset(d[i], 0, n_samples * sizeof(float));
} }
else if (v == VOLUME_NORM) { else if (mix->norm) {
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev); ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev);
ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev)); ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev));
@ -369,18 +361,18 @@ channelmix_f32_5p1_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_REST
for(n = 0; n < unrolled; n += 4) { for(n = 0; n < unrolled; n += 4) {
ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev); ctr = _mm_mul_ps(_mm_load_ps(&sFC[n]), clev);
ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev)); ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev));
_mm_store_ps(&dFL[n], _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFL[n]), ctr), vol)); _mm_store_ps(&dFL[n], _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFL[n]), ctr), v0));
_mm_store_ps(&dFR[n], _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFR[n]), ctr), vol)); _mm_store_ps(&dFR[n], _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFR[n]), ctr), v1));
_mm_store_ps(&dRL[n], _mm_mul_ps(_mm_load_ps(&sSL[n]), vol)); _mm_store_ps(&dRL[n], _mm_mul_ps(_mm_load_ps(&sSL[n]), v0));
_mm_store_ps(&dRR[n], _mm_mul_ps(_mm_load_ps(&sSR[n]), vol)); _mm_store_ps(&dRR[n], _mm_mul_ps(_mm_load_ps(&sSR[n]), v1));
} }
for(; n < n_samples; n++) { for(; n < n_samples; n++) {
ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev); ctr = _mm_mul_ss(_mm_load_ss(&sFC[n]), clev);
ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev)); ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev));
_mm_store_ss(&dFL[n], _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFL[n]), ctr), vol)); _mm_store_ss(&dFL[n], _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFL[n]), ctr), v0));
_mm_store_ss(&dFR[n], _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFR[n]), ctr), vol)); _mm_store_ss(&dFR[n], _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFR[n]), ctr), v1));
_mm_store_ss(&dRL[n], _mm_mul_ss(_mm_load_ss(&sSL[n]), vol)); _mm_store_ss(&dRL[n], _mm_mul_ss(_mm_load_ss(&sSL[n]), v0));
_mm_store_ss(&dRR[n], _mm_mul_ss(_mm_load_ss(&sSR[n]), vol)); _mm_store_ss(&dRR[n], _mm_mul_ss(_mm_load_ss(&sSR[n]), v1));
} }
} }
} }

View file

@ -162,7 +162,7 @@ static int make_matrix(struct channelmix *mix)
uint64_t src_mask = mix->src_mask; uint64_t src_mask = mix->src_mask;
uint64_t dst_mask = mix->dst_mask; uint64_t dst_mask = mix->dst_mask;
uint64_t unassigned; uint64_t unassigned;
uint32_t i, j, matrix_encoding = MATRIX_NORMAL, c; uint32_t i, j, ic, jc, matrix_encoding = MATRIX_NORMAL;
float clev = SQRT1_2; float clev = SQRT1_2;
float slev = SQRT1_2; float slev = SQRT1_2;
float llev = 0.5f; float llev = 0.5f;
@ -325,17 +325,17 @@ static int make_matrix(struct channelmix *mix)
} }
} }
c = 0; for (ic = 0, i = 0; i < NUM_CHAN; i++) {
for (i = 0; i < NUM_CHAN; i++) {
float sum = 0.0f; float sum = 0.0f;
if ((dst_mask & (1UL << (i + 2))) == 0) if ((dst_mask & (1UL << (i + 2))) == 0)
continue; continue;
for (j = 0; j < NUM_CHAN; j++) { for (jc = 0, j = 0; j < NUM_CHAN; j++) {
if ((src_mask & (1UL << (j + 2))) == 0) if ((src_mask & (1UL << (j + 2))) == 0)
continue; continue;
mix->matrix_orig[c++] = matrix[i][j]; mix->matrix_orig[ic][jc++] = matrix[i][j];
sum += fabs(matrix[i][j]); sum += fabs(matrix[i][j]);
} }
ic++;
max = SPA_MAX(max, sum); max = SPA_MAX(max, sum);
} }
return 0; return 0;
@ -345,46 +345,56 @@ static void impl_channelmix_set_volume(struct channelmix *mix, float volume, boo
uint32_t n_channel_volumes, float *channel_volumes) uint32_t n_channel_volumes, float *channel_volumes)
{ {
float volumes[SPA_AUDIO_MAX_CHANNELS]; float volumes[SPA_AUDIO_MAX_CHANNELS];
float vol = mute ? 0.0f : volume, sum; float vol = mute ? 0.0f : volume, sum, t;
uint32_t i, j; uint32_t i, j;
uint32_t src_chan = mix->src_chan; uint32_t src_chan = mix->src_chan;
uint32_t dst_chan = mix->dst_chan; uint32_t dst_chan = mix->dst_chan;
/** apply global volume to channels */ /** apply global volume to channels */
sum = 0.0; sum = 0.0;
mix->norm = true;
for (i = 0; i < n_channel_volumes; i++) { for (i = 0; i < n_channel_volumes; i++) {
volumes[i] = channel_volumes[i] * vol; volumes[i] = channel_volumes[i] * vol;
if (volumes[i] != 1.0f)
mix->norm = false;
sum += volumes[i]; sum += volumes[i];
} }
mix->volume = sum / n_channel_volumes;
if (n_channel_volumes == src_chan) { if (n_channel_volumes == src_chan) {
for (i = 0; i < dst_chan; i++) { for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) { for (j = 0; j < src_chan; j++) {
float v = mix->matrix_orig[i * src_chan + j]; mix->matrix[i][j] = mix->matrix_orig[i][j] * volumes[j];
mix->matrix[i * src_chan + j] = v * volumes[j];
} }
} }
} else if (n_channel_volumes == dst_chan) { } else if (n_channel_volumes == dst_chan) {
for (i = 0; i < dst_chan; i++) { for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) { for (j = 0; j < src_chan; j++) {
float v = mix->matrix_orig[i * src_chan + j]; mix->matrix[i][j] = mix->matrix_orig[i][j] * volumes[i];
mix->matrix[i * src_chan + j] = v * volumes[i];
} }
} }
} }
mix->is_identity = dst_chan == src_chan; mix->zero = true;
mix->equal = true;
mix->identity = dst_chan == src_chan;
t = 0.0;
for (i = 0; i < dst_chan; i++) { for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) { for (j = 0; j < src_chan; j++) {
float v = mix->matrix[i * src_chan + j]; float v = mix->matrix[i][j];
spa_log_debug(mix->log, "%d %d: %f", i, j, v); spa_log_debug(mix->log, "%d %d: %f", i, j, v);
if (i == 0 && j == 0)
t = v;
else if (t != v)
mix->equal = false;
if (v != 0.0)
mix->zero = false;
if ((i == j && v != 1.0f) || if ((i == j && v != 1.0f) ||
(i != j && v != 0.0f)) (i != j && v != 0.0f))
mix->is_identity = false; mix->identity = false;
} }
} }
spa_log_debug(mix->log, "vol:%f, identity:%d", mix->volume, mix->is_identity); spa_log_debug(mix->log, "zero:%d norm:%d identity:%d", mix->zero, mix->norm, mix->identity);
} }
static void impl_channelmix_free(struct channelmix *mix) static void impl_channelmix_free(struct channelmix *mix)

View file

@ -49,11 +49,12 @@ struct channelmix {
struct spa_log *log; struct spa_log *log;
unsigned int is_identity:1; unsigned int zero:1; /* all zero components */
float volume; unsigned int identity:1; /* identity matrix */
float matrix_orig[SPA_AUDIO_MAX_CHANNELS * SPA_AUDIO_MAX_CHANNELS]; unsigned int norm:1; /* all normal values */
unsigned int equal:1; /* all values are equal */
float matrix[SPA_AUDIO_MAX_CHANNELS * SPA_AUDIO_MAX_CHANNELS]; float matrix_orig[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS];
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS];
void (*process) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst], void (*process) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples); uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples);

View file

@ -245,11 +245,11 @@ static int setup_convert(struct impl *this,
emit_params_changed(this); emit_params_changed(this);
spa_log_info(this->log, NAME " %p: got channelmix features %08x:%08x %d", spa_log_info(this->log, NAME " %p: got channelmix features %08x:%08x identity:%d",
this, this->cpu_flags, this->mix.cpu_flags, this, this->cpu_flags, this->mix.cpu_flags,
this->mix.is_identity); this->mix.identity);
this->is_passthrough = this->mix.is_identity; this->is_passthrough = this->mix.identity;
return 0; return 0;
} }
@ -916,9 +916,7 @@ static int impl_node_process(void *object)
void *dst_datas[n_dst_datas]; void *dst_datas[n_dst_datas];
bool is_passthrough; bool is_passthrough;
is_passthrough = this->is_passthrough && is_passthrough = this->is_passthrough && this->mix.identity;
this->mix.volume == 1.0f &&
this->mix.is_identity;
n_samples = sb->datas[0].chunk->size / inport->stride; n_samples = sb->datas[0].chunk->size / inport->stride;