diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/effects/reverb.c | 62 |
1 files changed, 42 insertions, 20 deletions
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9fba183a..392c2258 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1124,17 +1124,19 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co } } -/* Creates a transform matrix given a reverb vector. This works by creating a - * Z-focus transform, then a rotate transform around X, then Y, to place the - * focal point in the direction of the vector, using the vector length as a - * focus strength. - * - * This isn't technically correct since the vector is supposed to define the - * aperture and not rotate the perceived soundfield, but in practice it's - * probably good enough. +/* Creates a transform matrix given a reverb vector. This works by first + * creating an inverse rotation around Y then X, applying a Z-focus transform, + * then non-inverse rotations back around X then Y, to place the focal point in + * the direction of the vector, using the vector length as a focus strength. + * + * This convoluted construction ultimately results in a B-Format transformation + * matrix that retains its original orientation, but spatially focuses the + * signal in the desired direction. There is probably a more efficient way to + * do this, but let's see how good the optimizer is. */ static aluMatrixf GetTransformFromVector(const ALfloat *vec) { + const ALfloat sqrt_3 = 1.732050808f; aluMatrixf zfocus, xrot, yrot; aluMatrixf tmp1, tmp2; ALfloat length; @@ -1145,12 +1147,12 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) /* Define a Z-focus (X in Ambisonics) transform, given the panning vector * length. */ - sa = sinf(minf(length, 1.0f) * (F_PI/4.0f)); + sa = sinf(minf(length, 1.0f) * (F_PI/2.0f)); aluMatrixfSet(&zfocus, - 1.0f/(1.0f+sa), 0.0f, 0.0f, (sa/(1.0f+sa))/1.732050808f, - 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, - 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, - (sa/(1.0f+sa))*1.732050808f, 0.0f, 0.0f, 1.0f/(1.0f+sa) + 1.0f/(1.0f+sa), 0.0f, 0.0f, sa/(1.0f+sa)/sqrt_3, + 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, + 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, + sa/(1.0f+sa)*sqrt_3, 0.0f, 0.0f, 1.0f/(1.0f+sa) ); /* Define rotation around X (Y in Ambisonics) */ @@ -1176,19 +1178,39 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) 0.0f, -sinf(a), 0.0f, cosf(a) ); + /* First, define a matrix that applies the inverse of the Y- then X- + * rotation matrices, so that the desired direction lands on Z. + */ +#define MATRIX_INVMULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ + _res.m[row][col] = _m1.m[0][row]*_m2.m[col][0] + \ + _m1.m[1][row]*_m2.m[col][1] + \ + _m1.m[2][row]*_m2.m[col][2] + \ + _m1.m[3][row]*_m2.m[col][3]; \ + } \ +} while(0) + MATRIX_INVMULT(tmp1, xrot, yrot); +#undef MATRIX_INVMULT + #define MATRIX_MULT(_res, _m1, _m2) do { \ int row, col; \ for(col = 0;col < 4;col++) \ { \ for(row = 0;row < 4;row++) \ - _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ - _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ + _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + \ + _m1.m[row][1]*_m2.m[1][col] + \ + _m1.m[row][2]*_m2.m[2][col] + \ + _m1.m[row][3]*_m2.m[3][col]; \ } \ } while(0) - /* Define a matrix that first focuses on Z, then rotates around X then Y to - * focus the output in the direction of the vector. + /* Now apply matrices to focus on Z, then rotate back around X then Y, to + * result in a focus in the direction of the vector. */ - MATRIX_MULT(tmp1, xrot, zfocus); + MATRIX_MULT(tmp2, zfocus, tmp1); + MATRIX_MULT(tmp1, xrot, tmp2); MATRIX_MULT(tmp2, yrot, tmp1); #undef MATRIX_MULT @@ -1214,8 +1236,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ } \ } while(0) - /* Create a matrix that first converts A-Format to B-Format, then rotates - * the B-Format soundfield according to the panning vector. + /* Create a matrix that first converts A-Format to B-Format, then + * transforms the B-Format signal according to the panning vector. */ rot = GetTransformFromVector(ReflectionsPan); MATRIX_MULT(transform, rot, A2B); |