diff options
Diffstat (limited to 'Alc/panning.cpp')
-rw-r--r-- | Alc/panning.cpp | 259 |
1 files changed, 128 insertions, 131 deletions
diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 4d1cd2c0..507ea5f7 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -65,121 +65,7 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -} // namespace - -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_COEFFS]) -{ - /* Zeroth-order */ - coeffs[0] = 1.0f; /* ACN 0 = 1 */ - /* First-order */ - coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ - /* Second-order */ - coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ - coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ - coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ - coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ - /* Third-order */ - coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ - coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ - coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ - - if(spread > 0.0f) - { - /* Implement the spread by using a spherical source that subtends the - * angle spread. See: - * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 - * - * When adjusted for N3D normalization instead of SN3D, these - * calculations are: - * - * ZH0 = -sqrt(pi) * (-1+ca); - * ZH1 = 0.5*sqrt(pi) * sa*sa; - * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); - * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); - * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); - * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); - * - * The gain of the source is compensated for size, so that the - * loundness doesn't depend on the spread. Thus: - * - * ZH0 = 1.0f; - * ZH1 = 0.5f * (ca+1.0f); - * ZH2 = 0.5f * (ca+1.0f)*ca; - * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); - * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; - * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); - */ - ALfloat ca = cosf(spread * 0.5f); - /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = sqrtf(1.0f + spread/F_TAU); - - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; - - /* Zeroth-order */ - coeffs[0] *= ZH0_norm; - /* First-order */ - coeffs[1] *= ZH1_norm; - coeffs[2] *= ZH1_norm; - coeffs[3] *= ZH1_norm; - /* Second-order */ - coeffs[4] *= ZH2_norm; - coeffs[5] *= ZH2_norm; - coeffs[6] *= ZH2_norm; - coeffs[7] *= ZH2_norm; - coeffs[8] *= ZH2_norm; - /* Third-order */ - coeffs[9] *= ZH3_norm; - coeffs[10] *= ZH3_norm; - coeffs[11] *= ZH3_norm; - coeffs[12] *= ZH3_norm; - coeffs[13] *= ZH3_norm; - coeffs[14] *= ZH3_norm; - coeffs[15] *= ZH3_norm; - } -} - - -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - ASSUME(numchans > 0); - auto iter = std::transform(chancoeffs, chancoeffs+numchans, std::begin(gains), - [numcoeffs,coeffs,ingain](const ChannelConfig &chancoeffs) -> ALfloat - { - ASSUME(numcoeffs > 0); - float gain{std::inner_product(std::begin(chancoeffs), std::begin(chancoeffs)+numcoeffs, - coeffs, float{0.0f})}; - return clampf(gain, 0.0f, 1.0f) * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} - -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - ASSUME(numchans > 0); - auto iter = std::transform(chanmap, chanmap+numchans, std::begin(gains), - [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat - { - ASSUME(chanmap.Index >= 0); - return chanmap.Scale * coeffs[chanmap.Index] * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} - - -static inline const char *GetLabelFromChannel(enum Channel channel) +inline const char *GetLabelFromChannel(enum Channel channel) { switch(channel) { @@ -230,9 +116,8 @@ struct ChannelMap { ChannelConfig Config; }; -static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], - ChannelConfig *ambicoeffs, const ChannelMap *chanmap, - ALsizei count, ALsizei *outcount) +void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs, + const ChannelMap *chanmap, ALsizei count, ALsizei *outcount) { auto copy_coeffs = [&devchans,ambicoeffs](ALsizei maxchans, const ChannelMap &channel) -> ALsizei { @@ -250,11 +135,9 @@ static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], *outcount = mini(maxcount, MAX_OUTPUT_CHANNELS); } -static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - ALsizei i; - - for(i = 0;i < conf->NumSpeakers;i++) + for(ALsizei i{0};i < conf->NumSpeakers;i++) { enum Channel ch; int chidx = -1; @@ -343,7 +226,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp } -static const ChannelMap MonoCfg[1] = { +constexpr ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.52305643e-2f } }, @@ -378,8 +261,7 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, }; -static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const ALsizei *RESTRICT chans_per_order) +void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { const char *devname = device->DeviceName.c_str(); ALsizei i; @@ -399,7 +281,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde } } -static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { const char *devname = device->DeviceName.c_str(); ALfloat maxdist = 0.0f; @@ -457,7 +339,7 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL } } -static void InitPanning(ALCdevice *device) +void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; ALsizei coeffcount = 0; @@ -604,7 +486,7 @@ static void InitPanning(ALCdevice *device) device->RealOut.NumChannels = 0; } -static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = N3D2N3DScale; @@ -689,7 +571,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A InitDistanceComp(device, conf, speakermap); } -static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; @@ -770,7 +652,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz InitDistanceComp(device, conf, speakermap); } -static void InitHrtfPanning(ALCdevice *device) +void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ static constexpr struct AngularPoint AmbiPoints[] = { @@ -892,7 +774,7 @@ static void InitHrtfPanning(ALCdevice *device) ChansPerOrder); } -static void InitUhjPanning(ALCdevice *device) +void InitUhjPanning(ALCdevice *device) { static constexpr ALsizei count{3}; @@ -910,6 +792,121 @@ static void InitUhjPanning(ALCdevice *device) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); } +} // namespace + + +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat (&coeffs)[MAX_AMBI_COEFFS]) +{ + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); + * + * The gain of the source is compensated for size, so that the + * loundness doesn't depend on the spread. Thus: + * + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); + */ + ALfloat ca = cosf(spread * 0.5f); + /* Increase the source volume by up to +3dB for a full spread. */ + ALfloat scale = sqrtf(1.0f + spread/F_TAU); + + ALfloat ZH0_norm = scale; + ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } +} + + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + ASSUME(numchans > 0); + auto iter = std::transform(chancoeffs, chancoeffs+numchans, std::begin(gains), + [numcoeffs,coeffs,ingain](const ChannelConfig &chancoeffs) -> ALfloat + { + ASSUME(numcoeffs > 0); + float gain{std::inner_product(std::begin(chancoeffs), std::begin(chancoeffs)+numcoeffs, + coeffs, float{0.0f})}; + return clampf(gain, 0.0f, 1.0f) * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} + +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + ASSUME(numchans > 0); + auto iter = std::transform(chanmap, chanmap+numchans, std::begin(gains), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + { + ASSUME(chanmap.Index >= 0); + return chanmap.Scale * coeffs[chanmap.Index] * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} + + void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) { /* Hold the HRTF the device last used, in case it's used again. */ |