2019-07-28 21:29:59 -07:00
|
|
|
#ifndef ALU_H
|
|
|
|
#define ALU_H
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-12-01 01:12:05 -08:00
|
|
|
#include <array>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <cmath>
|
|
|
|
#include <cstddef>
|
2020-05-03 18:47:49 -07:00
|
|
|
#include <type_traits>
|
2018-12-01 01:12:05 -08:00
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "alspan.h"
|
2020-12-12 10:38:24 -08:00
|
|
|
#include "core/ambidefs.h"
|
2020-11-27 22:27:45 -08:00
|
|
|
#include "core/bufferline.h"
|
|
|
|
#include "core/devformat.h"
|
2019-05-29 17:32:16 -07:00
|
|
|
|
2020-11-02 04:24:36 -08:00
|
|
|
struct ALCcontext;
|
2020-11-27 22:27:45 -08:00
|
|
|
struct ALCdevice;
|
2019-07-28 11:28:36 -07:00
|
|
|
struct ALeffectslot;
|
2020-11-27 22:27:45 -08:00
|
|
|
struct MixParams;
|
2019-01-12 01:25:33 -08:00
|
|
|
|
2019-10-02 16:53:23 -07:00
|
|
|
|
2020-02-25 04:52:39 -08:00
|
|
|
#define MAX_SENDS 6
|
2014-06-02 19:19:22 -07:00
|
|
|
|
2014-03-22 02:39:57 -07:00
|
|
|
|
2019-08-20 04:16:44 -07:00
|
|
|
using MixerFunc = void(*)(const al::span<const float> InSamples,
|
|
|
|
const al::span<FloatBufferLine> OutBuffer, float *CurrentGains, const float *TargetGains,
|
2019-08-20 12:00:24 -07:00
|
|
|
const size_t Counter, const size_t OutPos);
|
2011-06-25 00:08:05 -07:00
|
|
|
|
2019-10-02 16:53:23 -07:00
|
|
|
extern MixerFunc MixSamples;
|
|
|
|
|
2010-11-26 17:47:43 -08:00
|
|
|
|
2020-10-21 16:39:21 -07:00
|
|
|
constexpr float GainMixMax{1000.0f}; /* +60dB */
|
2016-08-27 06:28:04 -07:00
|
|
|
|
2020-10-21 16:39:21 -07:00
|
|
|
constexpr float SpeedOfSoundMetersPerSec{343.3f};
|
|
|
|
constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
|
2012-09-14 02:52:37 -07:00
|
|
|
|
2020-10-21 16:39:21 -07:00
|
|
|
/** Target gain for the reverb decay feedback reaching the decay time. */
|
|
|
|
constexpr float ReverbDecayGain{0.001f}; /* -60 dB */
|
2017-05-21 00:01:39 -07:00
|
|
|
|
2020-10-21 17:16:27 -07:00
|
|
|
|
2016-04-14 15:25:12 -07:00
|
|
|
enum HrtfRequestMode {
|
|
|
|
Hrtf_Default = 0,
|
|
|
|
Hrtf_Enable = 1,
|
|
|
|
Hrtf_Disable = 2,
|
|
|
|
};
|
|
|
|
|
2017-08-07 01:38:26 -07:00
|
|
|
void aluInit(void);
|
|
|
|
|
2015-09-27 20:55:39 -07:00
|
|
|
void aluInitMixer(void);
|
2014-12-15 12:23:28 -08:00
|
|
|
|
2016-04-14 15:25:12 -07:00
|
|
|
/* aluInitRenderer
|
|
|
|
*
|
|
|
|
* Set up the appropriate panning method and mixing method given the device
|
|
|
|
* properties.
|
|
|
|
*/
|
2020-04-08 10:15:43 -07:00
|
|
|
void aluInitRenderer(ALCdevice *device, int hrtf_id, HrtfRequestMode hrtf_appreq,
|
|
|
|
HrtfRequestMode hrtf_userreq);
|
2010-08-03 23:10:00 -07:00
|
|
|
|
2020-11-02 04:24:36 -08:00
|
|
|
void aluInitEffectPanning(ALeffectslot *slot, ALCcontext *context);
|
2016-01-28 00:02:46 -08:00
|
|
|
|
2018-05-17 03:52:40 -07:00
|
|
|
/**
|
|
|
|
* Calculates ambisonic encoder coefficients using the X, Y, and Z direction
|
|
|
|
* components, which must represent a normalized (unit length) vector, and the
|
|
|
|
* spread is the angular width of the sound (0...tau).
|
|
|
|
*
|
|
|
|
* NOTE: The components use ambisonic coordinates. As a result:
|
|
|
|
*
|
|
|
|
* Ambisonic Y = OpenAL -X
|
|
|
|
* Ambisonic Z = OpenAL Y
|
|
|
|
* Ambisonic X = OpenAL -Z
|
|
|
|
*
|
|
|
|
* The components are ordered such that OpenAL's X, Y, and Z are the first,
|
|
|
|
* second, and third parameters respectively -- simply negate X and Z.
|
|
|
|
*/
|
2020-12-04 13:53:56 -08:00
|
|
|
std::array<float,MaxAmbiChannels> CalcAmbiCoeffs(const float y, const float z, const float x,
|
2020-04-21 23:58:53 -07:00
|
|
|
const float spread);
|
2018-05-17 03:52:40 -07:00
|
|
|
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 07:33:13 -07:00
|
|
|
/**
|
2016-01-25 06:11:51 -08:00
|
|
|
* CalcDirectionCoeffs
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 07:33:13 -07:00
|
|
|
*
|
2018-05-17 03:52:40 -07:00
|
|
|
* Calculates ambisonic coefficients based on an OpenAL direction vector. The
|
|
|
|
* vector must be normalized (unit length), and the spread is the angular width
|
|
|
|
* of the sound (0...tau).
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 07:33:13 -07:00
|
|
|
*/
|
2020-12-04 13:53:56 -08:00
|
|
|
inline std::array<float,MaxAmbiChannels> CalcDirectionCoeffs(const float (&dir)[3],
|
2020-04-21 23:58:53 -07:00
|
|
|
const float spread)
|
2018-05-17 03:52:40 -07:00
|
|
|
{
|
|
|
|
/* Convert from OpenAL coords to Ambisonics. */
|
2020-04-21 23:58:53 -07:00
|
|
|
return CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread);
|
2018-05-17 03:52:40 -07:00
|
|
|
}
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 07:33:13 -07:00
|
|
|
|
2016-01-25 06:11:51 -08:00
|
|
|
/**
|
|
|
|
* CalcAngleCoeffs
|
|
|
|
*
|
2016-04-15 18:14:19 -07:00
|
|
|
* Calculates ambisonic coefficients based on azimuth and elevation. The
|
|
|
|
* azimuth and elevation parameters are in radians, going right and up
|
|
|
|
* respectively.
|
2016-01-25 06:11:51 -08:00
|
|
|
*/
|
2020-12-04 13:53:56 -08:00
|
|
|
inline std::array<float,MaxAmbiChannels> CalcAngleCoeffs(const float azimuth,
|
2020-04-21 23:58:53 -07:00
|
|
|
const float elevation, const float spread)
|
2017-02-23 16:44:59 -08:00
|
|
|
{
|
2019-10-05 20:00:22 -07:00
|
|
|
const float x{-std::sin(azimuth) * std::cos(elevation)};
|
|
|
|
const float y{ std::sin(elevation)};
|
|
|
|
const float z{ std::cos(azimuth) * std::cos(elevation)};
|
2018-05-17 03:52:40 -07:00
|
|
|
|
2020-04-21 23:58:53 -07:00
|
|
|
return CalcAmbiCoeffs(x, y, z, spread);
|
2017-02-23 16:44:59 -08:00
|
|
|
}
|
2017-02-23 00:23:16 -08:00
|
|
|
|
2016-01-25 06:11:51 -08:00
|
|
|
|
|
|
|
/**
|
2018-09-19 22:18:46 -07:00
|
|
|
* ComputePanGains
|
2016-01-25 06:11:51 -08:00
|
|
|
*
|
|
|
|
* Computes panning gains using the given channel decoder coefficients and the
|
2018-09-19 22:18:46 -07:00
|
|
|
* pre-calculated direction or angle coefficients. For B-Format sources, the
|
|
|
|
* coeffs are a 'slice' of a transform matrix for the input channel, used to
|
|
|
|
* scale and orient the sound samples.
|
2014-11-04 03:33:35 -08:00
|
|
|
*/
|
2019-10-05 20:00:22 -07:00
|
|
|
void ComputePanGains(const MixParams *mix, const float*RESTRICT coeffs, const float ingain,
|
|
|
|
const al::span<float,MAX_OUTPUT_CHANNELS> gains);
|
2014-10-31 17:18:45 -07:00
|
|
|
|
2018-12-23 08:51:28 -08:00
|
|
|
|
2020-05-03 18:47:49 -07:00
|
|
|
/** Helper to set an identity/pass-through panning for ambisonic mixing (3D input). */
|
|
|
|
template<typename T, typename I, typename F>
|
|
|
|
auto SetAmbiPanIdentity(T iter, I count, F func) -> std::enable_if_t<std::is_integral<I>::value>
|
2019-02-21 02:13:30 -08:00
|
|
|
{
|
2020-05-03 18:47:49 -07:00
|
|
|
if(count < 1) return;
|
|
|
|
|
2020-12-04 13:53:56 -08:00
|
|
|
std::array<float,MaxAmbiChannels> coeffs{{1.0f}};
|
2020-05-03 18:47:49 -07:00
|
|
|
func(*iter, coeffs);
|
|
|
|
++iter;
|
|
|
|
for(I i{1};i < count;++i,++iter)
|
|
|
|
{
|
|
|
|
coeffs[i-1] = 0.0f;
|
|
|
|
coeffs[i ] = 1.0f;
|
|
|
|
func(*iter, coeffs);
|
|
|
|
}
|
2019-02-21 02:13:30 -08:00
|
|
|
}
|
|
|
|
|
2012-04-28 07:28:36 -07:00
|
|
|
|
2020-04-03 08:49:15 -07:00
|
|
|
extern const float ConeScale;
|
|
|
|
extern const float ZScale;
|
2011-09-23 22:33:37 -07:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
#endif
|