🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2099 lines
80 KiB

  1. /**
  2. * Ambisonic reverb engine for the OpenAL cross platform audio library
  3. * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <cstdio>
  22. #include <cstdlib>
  23. #include <cmath>
  24. #include <array>
  25. #include <numeric>
  26. #include <algorithm>
  27. #include <functional>
  28. #include "alMain.h"
  29. #include "alcontext.h"
  30. #include "alu.h"
  31. #include "alAuxEffectSlot.h"
  32. #include "alListener.h"
  33. #include "alError.h"
  34. #include "bformatdec.h"
  35. #include "filters/biquad.h"
  36. #include "vector.h"
  37. #include "vecmat.h"
  38. /* This is a user config option for modifying the overall output of the reverb
  39. * effect.
  40. */
  41. ALfloat ReverbBoost = 1.0f;
  42. namespace {
  43. using namespace std::placeholders;
  44. /* The number of samples used for cross-faded delay lines. This can be used
  45. * to balance the compensation for abrupt line changes and attenuation due to
  46. * minimally lengthed recursive lines. Try to keep this below the device
  47. * update size.
  48. */
  49. constexpr int FADE_SAMPLES{128};
  50. /* The number of spatialized lines or channels to process. Four channels allows
  51. * for a 3D A-Format response. NOTE: This can't be changed without taking care
  52. * of the conversion matrices, and a few places where the length arrays are
  53. * assumed to have 4 elements.
  54. */
  55. constexpr int NUM_LINES{4};
  56. /* The B-Format to A-Format conversion matrix. The arrangement of rows is
  57. * deliberately chosen to align the resulting lines to their spatial opposites
  58. * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below
  59. * back left). It's not quite opposite, since the A-Format results in a
  60. * tetrahedron, but it's close enough. Should the model be extended to 8-lines
  61. * in the future, true opposites can be used.
  62. */
  63. alignas(16) constexpr ALfloat B2A[NUM_LINES][MAX_AMBI_CHANNELS]{
  64. { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f },
  65. { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f },
  66. { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f },
  67. { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }
  68. };
  69. /* Converts A-Format to B-Format. */
  70. alignas(16) constexpr ALfloat A2B[NUM_LINES][NUM_LINES]{
  71. { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f },
  72. { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f },
  73. { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f },
  74. { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f }
  75. };
  76. constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES};
  77. /* The all-pass and delay lines have a variable length dependent on the
  78. * effect's density parameter, which helps alter the perceived environment
  79. * size. The size-to-density conversion is a cubed scale:
  80. *
  81. * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE);
  82. *
  83. * The line lengths scale linearly with room size, so the inverse density
  84. * conversion is needed, taking the cube root of the re-scaled density to
  85. * calculate the line length multiplier:
  86. *
  87. * length_mult = max(5.0, cbrt(density*DENSITY_SCALE));
  88. *
  89. * The density scale below will result in a max line multiplier of 50, for an
  90. * effective size range of 5m to 50m.
  91. */
  92. constexpr ALfloat DENSITY_SCALE{125000.0f};
  93. /* All delay line lengths are specified in seconds.
  94. *
  95. * To approximate early reflections, we break them up into primary (those
  96. * arriving from the same direction as the source) and secondary (those
  97. * arriving from the opposite direction).
  98. *
  99. * The early taps decorrelate the 4-channel signal to approximate an average
  100. * room response for the primary reflections after the initial early delay.
  101. *
  102. * Given an average room dimension (d_a) and the speed of sound (c) we can
  103. * calculate the average reflection delay (r_a) regardless of listener and
  104. * source positions as:
  105. *
  106. * r_a = d_a / c
  107. * c = 343.3
  108. *
  109. * This can extended to finding the average difference (r_d) between the
  110. * maximum (r_1) and minimum (r_0) reflection delays:
  111. *
  112. * r_0 = 2 / 3 r_a
  113. * = r_a - r_d / 2
  114. * = r_d
  115. * r_1 = 4 / 3 r_a
  116. * = r_a + r_d / 2
  117. * = 2 r_d
  118. * r_d = 2 / 3 r_a
  119. * = r_1 - r_0
  120. *
  121. * As can be determined by integrating the 1D model with a source (s) and
  122. * listener (l) positioned across the dimension of length (d_a):
  123. *
  124. * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c
  125. *
  126. * The initial taps (T_(i=0)^N) are then specified by taking a power series
  127. * that ranges between r_0 and half of r_1 less r_0:
  128. *
  129. * R_i = 2^(i / (2 N - 1)) r_d
  130. * = r_0 + (2^(i / (2 N - 1)) - 1) r_d
  131. * = r_0 + T_i
  132. * T_i = R_i - r_0
  133. * = (2^(i / (2 N - 1)) - 1) r_d
  134. *
  135. * Assuming an average of 1m, we get the following taps:
  136. */
  137. constexpr std::array<ALfloat,NUM_LINES> EARLY_TAP_LENGTHS{{
  138. 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f
  139. }};
  140. /* The early all-pass filter lengths are based on the early tap lengths:
  141. *
  142. * A_i = R_i / a
  143. *
  144. * Where a is the approximate maximum all-pass cycle limit (20).
  145. */
  146. constexpr std::array<ALfloat,NUM_LINES> EARLY_ALLPASS_LENGTHS{{
  147. 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f
  148. }};
  149. /* The early delay lines are used to transform the primary reflections into
  150. * the secondary reflections. The A-format is arranged in such a way that
  151. * the channels/lines are spatially opposite:
  152. *
  153. * C_i is opposite C_(N-i-1)
  154. *
  155. * The delays of the two opposing reflections (R_i and O_i) from a source
  156. * anywhere along a particular dimension always sum to twice its full delay:
  157. *
  158. * 2 r_a = R_i + O_i
  159. *
  160. * With that in mind we can determine the delay between the two reflections
  161. * and thus specify our early line lengths (L_(i=0)^N) using:
  162. *
  163. * O_i = 2 r_a - R_(N-i-1)
  164. * L_i = O_i - R_(N-i-1)
  165. * = 2 (r_a - R_(N-i-1))
  166. * = 2 (r_a - T_(N-i-1) - r_0)
  167. * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1)))
  168. *
  169. * Using an average dimension of 1m, we get:
  170. */
  171. constexpr std::array<ALfloat,NUM_LINES> EARLY_LINE_LENGTHS{{
  172. 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f
  173. }};
  174. /* The late all-pass filter lengths are based on the late line lengths:
  175. *
  176. * A_i = (5 / 3) L_i / r_1
  177. */
  178. constexpr std::array<ALfloat,NUM_LINES> LATE_ALLPASS_LENGTHS{{
  179. 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f
  180. }};
  181. /* The late lines are used to approximate the decaying cycle of recursive
  182. * late reflections.
  183. *
  184. * Splitting the lines in half, we start with the shortest reflection paths
  185. * (L_(i=0)^(N/2)):
  186. *
  187. * L_i = 2^(i / (N - 1)) r_d
  188. *
  189. * Then for the opposite (longest) reflection paths (L_(i=N/2)^N):
  190. *
  191. * L_i = 2 r_a - L_(i-N/2)
  192. * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d
  193. *
  194. * For our 1m average room, we get:
  195. */
  196. constexpr std::array<ALfloat,NUM_LINES> LATE_LINE_LENGTHS{{
  197. 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f
  198. }};
  199. struct DelayLineI {
  200. /* The delay lines use interleaved samples, with the lengths being powers
  201. * of 2 to allow the use of bit-masking instead of a modulus for wrapping.
  202. */
  203. ALsizei Mask{0};
  204. ALfloat (*Line)[NUM_LINES]{nullptr};
  205. void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept
  206. {
  207. ASSUME(count > 0);
  208. for(ALsizei i{0};i < count;)
  209. {
  210. offset &= Mask;
  211. ALsizei td{mini(Mask+1 - offset, count - i)};
  212. do {
  213. Line[offset++][c] = in[i++];
  214. } while(--td);
  215. }
  216. }
  217. };
  218. struct VecAllpass {
  219. DelayLineI Delay;
  220. ALfloat Coeff{0.0f};
  221. ALsizei Offset[NUM_LINES][2]{};
  222. void processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset,
  223. const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo);
  224. void processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset,
  225. const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo);
  226. };
  227. struct T60Filter {
  228. /* Two filters are used to adjust the signal. One to control the low
  229. * frequencies, and one to control the high frequencies.
  230. */
  231. ALfloat MidGain[2]{0.0f, 0.0f};
  232. BiquadFilter HFFilter, LFFilter;
  233. void calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime,
  234. const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm);
  235. /* Applies the two T60 damping filter sections. */
  236. void process(ALfloat *samples, const ALsizei todo)
  237. {
  238. HFFilter.process(samples, samples, todo);
  239. LFFilter.process(samples, samples, todo);
  240. }
  241. };
  242. struct EarlyReflections {
  243. /* A Gerzon vector all-pass filter is used to simulate initial diffusion.
  244. * The spread from this filter also helps smooth out the reverb tail.
  245. */
  246. VecAllpass VecAp;
  247. /* An echo line is used to complete the second half of the early
  248. * reflections.
  249. */
  250. DelayLineI Delay;
  251. ALsizei Offset[NUM_LINES][2]{};
  252. ALfloat Coeff[NUM_LINES][2]{};
  253. /* The gain for each output channel based on 3D panning. */
  254. ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{};
  255. ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{};
  256. void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime,
  257. const ALfloat frequency);
  258. };
  259. struct LateReverb {
  260. /* A recursive delay line is used fill in the reverb tail. */
  261. DelayLineI Delay;
  262. ALsizei Offset[NUM_LINES][2]{};
  263. /* Attenuation to compensate for the modal density and decay rate of the
  264. * late lines.
  265. */
  266. ALfloat DensityGain[2]{0.0f, 0.0f};
  267. /* T60 decay filters are used to simulate absorption. */
  268. T60Filter T60[NUM_LINES];
  269. /* A Gerzon vector all-pass filter is used to simulate diffusion. */
  270. VecAllpass VecAp;
  271. /* The gain for each output channel based on 3D panning. */
  272. ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{};
  273. ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{};
  274. void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime,
  275. const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm,
  276. const ALfloat hf0norm, const ALfloat frequency);
  277. };
  278. struct ReverbState final : public EffectState {
  279. /* All delay lines are allocated as a single buffer to reduce memory
  280. * fragmentation and management code.
  281. */
  282. al::vector<ALfloat,16> mSampleBuffer;
  283. struct {
  284. /* Calculated parameters which indicate if cross-fading is needed after
  285. * an update.
  286. */
  287. ALfloat Density{AL_EAXREVERB_DEFAULT_DENSITY};
  288. ALfloat Diffusion{AL_EAXREVERB_DEFAULT_DIFFUSION};
  289. ALfloat DecayTime{AL_EAXREVERB_DEFAULT_DECAY_TIME};
  290. ALfloat HFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_HFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME};
  291. ALfloat LFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_LFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME};
  292. ALfloat HFReference{AL_EAXREVERB_DEFAULT_HFREFERENCE};
  293. ALfloat LFReference{AL_EAXREVERB_DEFAULT_LFREFERENCE};
  294. } mParams;
  295. /* Master effect filters */
  296. struct {
  297. BiquadFilter Lp;
  298. BiquadFilter Hp;
  299. } mFilter[NUM_LINES];
  300. /* Core delay line (early reflections and late reverb tap from this). */
  301. DelayLineI mDelay;
  302. /* Tap points for early reflection delay. */
  303. ALsizei mEarlyDelayTap[NUM_LINES][2]{};
  304. ALfloat mEarlyDelayCoeff[NUM_LINES][2]{};
  305. /* Tap points for late reverb feed and delay. */
  306. ALsizei mLateFeedTap{};
  307. ALsizei mLateDelayTap[NUM_LINES][2]{};
  308. /* Coefficients for the all-pass and line scattering matrices. */
  309. ALfloat mMixX{0.0f};
  310. ALfloat mMixY{0.0f};
  311. EarlyReflections mEarly;
  312. LateReverb mLate;
  313. /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */
  314. ALsizei mFadeCount{0};
  315. /* Maximum number of samples to process at once. */
  316. ALsizei mMaxUpdate[2]{BUFFERSIZE, BUFFERSIZE};
  317. /* The current write offset for all delay lines. */
  318. ALsizei mOffset{0};
  319. /* Temporary storage used when processing. */
  320. alignas(16) ALfloat mTempSamples[NUM_LINES][BUFFERSIZE]{};
  321. alignas(16) ALfloat mEarlyBuffer[NUM_LINES][BUFFERSIZE]{};
  322. alignas(16) ALfloat mLateBuffer[NUM_LINES][BUFFERSIZE]{};
  323. using MixOutT = void (ReverbState::*)(const ALsizei numOutput,
  324. ALfloat (*samplesOut)[BUFFERSIZE], const ALsizei todo);
  325. MixOutT mMixOut{&ReverbState::MixOutPlain};
  326. std::array<ALfloat,MAX_AMBI_ORDER+1> mOrderScales{};
  327. std::array<std::array<BandSplitter,NUM_LINES>,2> mAmbiSplitter;
  328. void MixOutPlain(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE],
  329. const ALsizei todo)
  330. {
  331. ASSUME(todo > 0);
  332. /* Convert back to B-Format, and mix the results to output. */
  333. for(ALsizei c{0};c < NUM_LINES;c++)
  334. {
  335. std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f);
  336. MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo);
  337. MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c],
  338. mEarly.PanGain[c], todo, 0, todo);
  339. }
  340. for(ALsizei c{0};c < NUM_LINES;c++)
  341. {
  342. std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f);
  343. MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo);
  344. MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c],
  345. mLate.PanGain[c], todo, 0, todo);
  346. }
  347. }
  348. void MixOutAmbiUp(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE],
  349. const ALsizei todo)
  350. {
  351. ASSUME(todo > 0);
  352. for(ALsizei c{0};c < NUM_LINES;c++)
  353. {
  354. std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f);
  355. MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo);
  356. /* Apply scaling to the B-Format's HF response to "upsample" it to
  357. * higher-order output.
  358. */
  359. const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
  360. mAmbiSplitter[0][c].applyHfScale(mTempSamples[0], hfscale, todo);
  361. MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c],
  362. mEarly.PanGain[c], todo, 0, todo);
  363. }
  364. for(ALsizei c{0};c < NUM_LINES;c++)
  365. {
  366. std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f);
  367. MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo);
  368. const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
  369. mAmbiSplitter[1][c].applyHfScale(mTempSamples[0], hfscale, todo);
  370. MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c],
  371. mLate.PanGain[c], todo, 0, todo);
  372. }
  373. }
  374. bool allocLines(const ALfloat frequency);
  375. void updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density,
  376. const ALfloat decayTime, const ALfloat frequency);
  377. void update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan,
  378. const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target);
  379. ALboolean deviceUpdate(const ALCdevice *device) override;
  380. void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override;
  381. void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override;
  382. DEF_NEWDEL(ReverbState)
  383. };
  384. /**************************************
  385. * Device Update *
  386. **************************************/
  387. inline ALfloat CalcDelayLengthMult(ALfloat density)
  388. { return maxf(5.0f, std::cbrt(density*DENSITY_SCALE)); }
  389. /* Given the allocated sample buffer, this function updates each delay line
  390. * offset.
  391. */
  392. inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay)
  393. {
  394. union {
  395. ALfloat *f;
  396. ALfloat (*f4)[NUM_LINES];
  397. } u;
  398. u.f = &sampleBuffer[reinterpret_cast<ptrdiff_t>(Delay->Line) * NUM_LINES];
  399. Delay->Line = u.f4;
  400. }
  401. /* Calculate the length of a delay line and store its mask and offset. */
  402. ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency,
  403. const ALuint extra, DelayLineI *Delay)
  404. {
  405. /* All line lengths are powers of 2, calculated from their lengths in
  406. * seconds, rounded up.
  407. */
  408. auto samples = static_cast<ALuint>(float2int(std::ceil(length*frequency)));
  409. samples = NextPowerOf2(samples + extra);
  410. /* All lines share a single sample buffer. */
  411. Delay->Mask = samples - 1;
  412. Delay->Line = reinterpret_cast<ALfloat(*)[NUM_LINES]>(offset);
  413. /* Return the sample count for accumulation. */
  414. return samples;
  415. }
  416. /* Calculates the delay line metrics and allocates the shared sample buffer
  417. * for all lines given the sample rate (frequency). If an allocation failure
  418. * occurs, it returns AL_FALSE.
  419. */
  420. bool ReverbState::allocLines(const ALfloat frequency)
  421. {
  422. /* All delay line lengths are calculated to accomodate the full range of
  423. * lengths given their respective paramters.
  424. */
  425. ALuint totalSamples{0u};
  426. /* Multiplier for the maximum density value, i.e. density=1, which is
  427. * actually the least density...
  428. */
  429. ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)};
  430. /* The main delay length includes the maximum early reflection delay, the
  431. * largest early tap width, the maximum late reverb delay, and the
  432. * largest late tap width. Finally, it must also be extended by the
  433. * update size (BUFFERSIZE) for block processing.
  434. */
  435. ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier +
  436. AL_EAXREVERB_MAX_LATE_REVERB_DELAY +
  437. (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())*0.25f*multiplier};
  438. totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay);
  439. /* The early vector all-pass line. */
  440. length = EARLY_ALLPASS_LENGTHS.back() * multiplier;
  441. totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.VecAp.Delay);
  442. /* The early reflection line. */
  443. length = EARLY_LINE_LENGTHS.back() * multiplier;
  444. totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.Delay);
  445. /* The late vector all-pass line. */
  446. length = LATE_ALLPASS_LENGTHS.back() * multiplier;
  447. totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.VecAp.Delay);
  448. /* The late delay lines are calculated from the largest maximum density
  449. * line length.
  450. */
  451. length = LATE_LINE_LENGTHS.back() * multiplier;
  452. totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.Delay);
  453. totalSamples *= NUM_LINES;
  454. if(totalSamples != mSampleBuffer.size())
  455. {
  456. mSampleBuffer.resize(totalSamples);
  457. mSampleBuffer.shrink_to_fit();
  458. }
  459. /* Clear the sample buffer. */
  460. std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f);
  461. /* Update all delays to reflect the new sample buffer. */
  462. RealizeLineOffset(mSampleBuffer.data(), &mDelay);
  463. RealizeLineOffset(mSampleBuffer.data(), &mEarly.VecAp.Delay);
  464. RealizeLineOffset(mSampleBuffer.data(), &mEarly.Delay);
  465. RealizeLineOffset(mSampleBuffer.data(), &mLate.VecAp.Delay);
  466. RealizeLineOffset(mSampleBuffer.data(), &mLate.Delay);
  467. return true;
  468. }
  469. ALboolean ReverbState::deviceUpdate(const ALCdevice *device)
  470. {
  471. const auto frequency = static_cast<ALfloat>(device->Frequency);
  472. /* Allocate the delay lines. */
  473. if(!allocLines(frequency))
  474. return AL_FALSE;
  475. const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)};
  476. /* The late feed taps are set a fixed position past the latest delay tap. */
  477. mLateFeedTap = float2int(
  478. (AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier) * frequency);
  479. /* Clear filters and gain coefficients since the delay lines were all just
  480. * cleared (if not reallocated).
  481. */
  482. for(auto &filter : mFilter)
  483. {
  484. filter.Lp.clear();
  485. filter.Hp.clear();
  486. }
  487. for(auto &coeff : mEarlyDelayCoeff)
  488. std::fill(std::begin(coeff), std::end(coeff), 0.0f);
  489. for(auto &coeff : mEarly.Coeff)
  490. std::fill(std::begin(coeff), std::end(coeff), 0.0f);
  491. mLate.DensityGain[0] = 0.0f;
  492. mLate.DensityGain[1] = 0.0f;
  493. for(auto &t60 : mLate.T60)
  494. {
  495. t60.MidGain[0] = 0.0f;
  496. t60.MidGain[1] = 0.0f;
  497. t60.HFFilter.clear();
  498. t60.LFFilter.clear();
  499. }
  500. for(auto &gains : mEarly.CurrentGain)
  501. std::fill(std::begin(gains), std::end(gains), 0.0f);
  502. for(auto &gains : mEarly.PanGain)
  503. std::fill(std::begin(gains), std::end(gains), 0.0f);
  504. for(auto &gains : mLate.CurrentGain)
  505. std::fill(std::begin(gains), std::end(gains), 0.0f);
  506. for(auto &gains : mLate.PanGain)
  507. std::fill(std::begin(gains), std::end(gains), 0.0f);
  508. /* Reset counters and offset base. */
  509. mFadeCount = 0;
  510. std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), BUFFERSIZE);
  511. mOffset = 0;
  512. if(device->mAmbiOrder > 1)
  513. {
  514. mMixOut = &ReverbState::MixOutAmbiUp;
  515. mOrderScales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder);
  516. }
  517. else
  518. {
  519. mMixOut = &ReverbState::MixOutPlain;
  520. mOrderScales.fill(1.0f);
  521. }
  522. mAmbiSplitter[0][0].init(400.0f / frequency);
  523. std::fill(mAmbiSplitter[0].begin()+1, mAmbiSplitter[0].end(), mAmbiSplitter[0][0]);
  524. std::fill(mAmbiSplitter[1].begin(), mAmbiSplitter[1].end(), mAmbiSplitter[0][0]);
  525. return AL_TRUE;
  526. }
  527. /**************************************
  528. * Effect Update *
  529. **************************************/
  530. /* Calculate a decay coefficient given the length of each cycle and the time
  531. * until the decay reaches -60 dB.
  532. */
  533. inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime)
  534. { return std::pow(REVERB_DECAY_GAIN, length/decayTime); }
  535. /* Calculate a decay length from a coefficient and the time until the decay
  536. * reaches -60 dB.
  537. */
  538. inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime)
  539. { return std::log10(coeff) * decayTime / std::log10(REVERB_DECAY_GAIN); }
  540. /* Calculate an attenuation to be applied to the input of any echo models to
  541. * compensate for modal density and decay time.
  542. */
  543. inline ALfloat CalcDensityGain(const ALfloat a)
  544. {
  545. /* The energy of a signal can be obtained by finding the area under the
  546. * squared signal. This takes the form of Sum(x_n^2), where x is the
  547. * amplitude for the sample n.
  548. *
  549. * Decaying feedback matches exponential decay of the form Sum(a^n),
  550. * where a is the attenuation coefficient, and n is the sample. The area
  551. * under this decay curve can be calculated as: 1 / (1 - a).
  552. *
  553. * Modifying the above equation to find the area under the squared curve
  554. * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
  555. * calculated by inverting the square root of this approximation,
  556. * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
  557. */
  558. return std::sqrt(1.0f - a*a);
  559. }
  560. /* Calculate the scattering matrix coefficients given a diffusion factor. */
  561. inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y)
  562. {
  563. /* The matrix is of order 4, so n is sqrt(4 - 1). */
  564. ALfloat n{std::sqrt(3.0f)};
  565. ALfloat t{diffusion * std::atan(n)};
  566. /* Calculate the first mixing matrix coefficient. */
  567. *x = std::cos(t);
  568. /* Calculate the second mixing matrix coefficient. */
  569. *y = std::sin(t) / n;
  570. }
  571. /* Calculate the limited HF ratio for use with the late reverb low-pass
  572. * filters.
  573. */
  574. ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF,
  575. const ALfloat decayTime, const ALfloat SpeedOfSound)
  576. {
  577. /* Find the attenuation due to air absorption in dB (converting delay
  578. * time to meters using the speed of sound). Then reversing the decay
  579. * equation, solve for HF ratio. The delay length is cancelled out of
  580. * the equation, so it can be calculated once for all lines.
  581. */
  582. ALfloat limitRatio{1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound)};
  583. /* Using the limit calculated above, apply the upper bound to the HF ratio.
  584. */
  585. return minf(limitRatio, hfRatio);
  586. }
  587. /* Calculates the 3-band T60 damping coefficients for a particular delay line
  588. * of specified length, using a combination of two shelf filter sections given
  589. * decay times for each band split at two reference frequencies.
  590. */
  591. void T60Filter::calcCoeffs(const ALfloat length, const ALfloat lfDecayTime,
  592. const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm,
  593. const ALfloat hf0norm)
  594. {
  595. const ALfloat lfGain{CalcDecayCoeff(length, lfDecayTime)};
  596. const ALfloat mfGain{CalcDecayCoeff(length, mfDecayTime)};
  597. const ALfloat hfGain{CalcDecayCoeff(length, hfDecayTime)};
  598. MidGain[1] = mfGain;
  599. LFFilter.setParams(BiquadType::LowShelf, lfGain/mfGain, lf0norm,
  600. calc_rcpQ_from_slope(lfGain/mfGain, 1.0f));
  601. HFFilter.setParams(BiquadType::HighShelf, hfGain/mfGain, hf0norm,
  602. calc_rcpQ_from_slope(hfGain/mfGain, 1.0f));
  603. }
  604. /* Update the early reflection line lengths and gain coefficients. */
  605. void EarlyReflections::updateLines(const ALfloat density, const ALfloat diffusion,
  606. const ALfloat decayTime, const ALfloat frequency)
  607. {
  608. const ALfloat multiplier{CalcDelayLengthMult(density)};
  609. /* Calculate the all-pass feed-back/forward coefficient. */
  610. VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f);
  611. for(ALsizei i{0};i < NUM_LINES;i++)
  612. {
  613. /* Calculate the length (in seconds) of each all-pass line. */
  614. ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier};
  615. /* Calculate the delay offset for each all-pass line. */
  616. VecAp.Offset[i][1] = float2int(length * frequency);
  617. /* Calculate the length (in seconds) of each delay line. */
  618. length = EARLY_LINE_LENGTHS[i] * multiplier;
  619. /* Calculate the delay offset for each delay line. */
  620. Offset[i][1] = float2int(length * frequency);
  621. /* Calculate the gain (coefficient) for each line. */
  622. Coeff[i][1] = CalcDecayCoeff(length, decayTime);
  623. }
  624. }
  625. /* Update the late reverb line lengths and T60 coefficients. */
  626. void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion,
  627. const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime,
  628. const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat frequency)
  629. {
  630. /* Scaling factor to convert the normalized reference frequencies from
  631. * representing 0...freq to 0...max_reference.
  632. */
  633. const ALfloat norm_weight_factor{frequency / AL_EAXREVERB_MAX_HFREFERENCE};
  634. const ALfloat late_allpass_avg{
  635. std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) /
  636. static_cast<float>(LATE_ALLPASS_LENGTHS.size())};
  637. /* To compensate for changes in modal density and decay time of the late
  638. * reverb signal, the input is attenuated based on the maximal energy of
  639. * the outgoing signal. This approximation is used to keep the apparent
  640. * energy of the signal equal for all ranges of density and decay time.
  641. *
  642. * The average length of the delay lines is used to calculate the
  643. * attenuation coefficient.
  644. */
  645. const ALfloat multiplier{CalcDelayLengthMult(density)};
  646. ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) /
  647. static_cast<float>(LATE_LINE_LENGTHS.size()) * multiplier};
  648. length += late_allpass_avg * multiplier;
  649. /* The density gain calculation uses an average decay time weighted by
  650. * approximate bandwidth. This attempts to compensate for losses of energy
  651. * that reduce decay time due to scattering into highly attenuated bands.
  652. */
  653. const ALfloat bandWeights[3]{
  654. lf0norm*norm_weight_factor,
  655. hf0norm*norm_weight_factor - lf0norm*norm_weight_factor,
  656. 1.0f - hf0norm*norm_weight_factor};
  657. DensityGain[1] = CalcDensityGain(
  658. CalcDecayCoeff(length,
  659. bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime
  660. )
  661. );
  662. /* Calculate the all-pass feed-back/forward coefficient. */
  663. VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f);
  664. for(ALsizei i{0};i < NUM_LINES;i++)
  665. {
  666. /* Calculate the length (in seconds) of each all-pass line. */
  667. length = LATE_ALLPASS_LENGTHS[i] * multiplier;
  668. /* Calculate the delay offset for each all-pass line. */
  669. VecAp.Offset[i][1] = float2int(length * frequency);
  670. /* Calculate the length (in seconds) of each delay line. */
  671. length = LATE_LINE_LENGTHS[i] * multiplier;
  672. /* Calculate the delay offset for each delay line. */
  673. Offset[i][1] = float2int(length*frequency + 0.5f);
  674. /* Approximate the absorption that the vector all-pass would exhibit
  675. * given the current diffusion so we don't have to process a full T60
  676. * filter for each of its four lines.
  677. */
  678. length += lerp(LATE_ALLPASS_LENGTHS[i], late_allpass_avg, diffusion) * multiplier;
  679. /* Calculate the T60 damping coefficients for each line. */
  680. T60[i].calcCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, lf0norm, hf0norm);
  681. }
  682. }
  683. /* Update the offsets for the main effect delay line. */
  684. void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay,
  685. const ALfloat density, const ALfloat decayTime, const ALfloat frequency)
  686. {
  687. const ALfloat multiplier{CalcDelayLengthMult(density)};
  688. /* Early reflection taps are decorrelated by means of an average room
  689. * reflection approximation described above the definition of the taps.
  690. * This approximation is linear and so the above density multiplier can
  691. * be applied to adjust the width of the taps. A single-band decay
  692. * coefficient is applied to simulate initial attenuation and absorption.
  693. *
  694. * Late reverb taps are based on the late line lengths to allow a zero-
  695. * delay path and offsets that would continue the propagation naturally
  696. * into the late lines.
  697. */
  698. for(ALsizei i{0};i < NUM_LINES;i++)
  699. {
  700. ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier};
  701. mEarlyDelayTap[i][1] = float2int(length * frequency);
  702. length = EARLY_TAP_LENGTHS[i]*multiplier;
  703. mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime);
  704. length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())*0.25f*multiplier;
  705. mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency);
  706. }
  707. }
  708. /* Creates a transform matrix given a reverb vector. The vector pans the reverb
  709. * reflections toward the given direction, using its magnitude (up to 1) as a
  710. * focal strength. This function results in a B-Format transformation matrix
  711. * that spatially focuses the signal in the desired direction.
  712. */
  713. alu::Matrix GetTransformFromVector(const ALfloat *vec)
  714. {
  715. /* Normalize the panning vector according to the N3D scale, which has an
  716. * extra sqrt(3) term on the directional components. Converting from OpenAL
  717. * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however
  718. * that the reverb panning vectors use left-handed coordinates, unlike the
  719. * rest of OpenAL which use right-handed. This is fixed by negating Z,
  720. * which cancels out with the B-Format Z negation.
  721. */
  722. ALfloat norm[3];
  723. ALfloat mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])};
  724. if(mag > 1.0f)
  725. {
  726. norm[0] = vec[0] / mag * -al::MathDefs<float>::Sqrt3();
  727. norm[1] = vec[1] / mag * al::MathDefs<float>::Sqrt3();
  728. norm[2] = vec[2] / mag * al::MathDefs<float>::Sqrt3();
  729. mag = 1.0f;
  730. }
  731. else
  732. {
  733. /* If the magnitude is less than or equal to 1, just apply the sqrt(3)
  734. * term. There's no need to renormalize the magnitude since it would
  735. * just be reapplied in the matrix.
  736. */
  737. norm[0] = vec[0] * -al::MathDefs<float>::Sqrt3();
  738. norm[1] = vec[1] * al::MathDefs<float>::Sqrt3();
  739. norm[2] = vec[2] * al::MathDefs<float>::Sqrt3();
  740. }
  741. return alu::Matrix{
  742. 1.0f, 0.0f, 0.0f, 0.0f,
  743. norm[0], 1.0f-mag, 0.0f, 0.0f,
  744. norm[1], 0.0f, 1.0f-mag, 0.0f,
  745. norm[2], 0.0f, 0.0f, 1.0f-mag
  746. };
  747. }
  748. /* Update the early and late 3D panning gains. */
  749. void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan,
  750. const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target)
  751. {
  752. /* Create matrices that transform a B-Format signal according to the
  753. * panning vectors.
  754. */
  755. const alu::Matrix earlymat{GetTransformFromVector(ReflectionsPan)};
  756. const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)};
  757. mOutBuffer = target.Main->Buffer;
  758. mOutChannels = target.Main->NumChannels;
  759. for(ALsizei i{0};i < NUM_LINES;i++)
  760. {
  761. const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i],
  762. earlymat[3][i]};
  763. ComputePanGains(target.Main, coeffs, earlyGain, mEarly.PanGain[i]);
  764. }
  765. for(ALsizei i{0};i < NUM_LINES;i++)
  766. {
  767. const ALfloat coeffs[MAX_AMBI_CHANNELS]{latemat[0][i], latemat[1][i], latemat[2][i],
  768. latemat[3][i]};
  769. ComputePanGains(target.Main, coeffs, lateGain, mLate.PanGain[i]);
  770. }
  771. }
  772. void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target)
  773. {
  774. const ALCdevice *Device{Context->Device};
  775. const ALlistener &Listener = Context->Listener;
  776. const auto frequency = static_cast<ALfloat>(Device->Frequency);
  777. /* Calculate the master filters */
  778. ALfloat hf0norm{minf(props->Reverb.HFReference / frequency, 0.49f)};
  779. /* Restrict the filter gains from going below -60dB to keep the filter from
  780. * killing most of the signal.
  781. */
  782. ALfloat gainhf{maxf(props->Reverb.GainHF, 0.001f)};
  783. mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm,
  784. calc_rcpQ_from_slope(gainhf, 1.0f));
  785. ALfloat lf0norm{minf(props->Reverb.LFReference / frequency, 0.49f)};
  786. ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)};
  787. mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm,
  788. calc_rcpQ_from_slope(gainlf, 1.0f));
  789. for(ALsizei i{1};i < NUM_LINES;i++)
  790. {
  791. mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp);
  792. mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp);
  793. }
  794. /* Update the main effect delay and associated taps. */
  795. updateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
  796. props->Reverb.Density, props->Reverb.DecayTime, frequency);
  797. /* Update the early lines. */
  798. mEarly.updateLines(props->Reverb.Density, props->Reverb.Diffusion, props->Reverb.DecayTime,
  799. frequency);
  800. /* Get the mixing matrix coefficients. */
  801. CalcMatrixCoeffs(props->Reverb.Diffusion, &mMixX, &mMixY);
  802. /* If the HF limit parameter is flagged, calculate an appropriate limit
  803. * based on the air absorption parameter.
  804. */
  805. ALfloat hfRatio{props->Reverb.DecayHFRatio};
  806. if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
  807. hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
  808. props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound
  809. );
  810. /* Calculate the LF/HF decay times. */
  811. const ALfloat lfDecayTime{clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio,
  812. AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)};
  813. const ALfloat hfDecayTime{clampf(props->Reverb.DecayTime * hfRatio,
  814. AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)};
  815. /* Update the late lines. */
  816. mLate.updateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime,
  817. props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, frequency);
  818. /* Update early and late 3D panning. */
  819. const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost};
  820. update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan,
  821. props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target);
  822. /* Calculate the max update size from the smallest relevant delay. */
  823. mMaxUpdate[1] = mini(BUFFERSIZE, mini(mEarly.Offset[0][1], mLate.Offset[0][1]));
  824. /* Determine if delay-line cross-fading is required. Density is essentially
  825. * a master control for the feedback delays, so changes the offsets of many
  826. * delay lines.
  827. */
  828. if(mParams.Density != props->Reverb.Density ||
  829. /* Diffusion and decay times influences the decay rate (gain) of the
  830. * late reverb T60 filter.
  831. */
  832. mParams.Diffusion != props->Reverb.Diffusion ||
  833. mParams.DecayTime != props->Reverb.DecayTime ||
  834. mParams.HFDecayTime != hfDecayTime ||
  835. mParams.LFDecayTime != lfDecayTime ||
  836. /* HF/LF References control the weighting used to calculate the density
  837. * gain.
  838. */
  839. mParams.HFReference != props->Reverb.HFReference ||
  840. mParams.LFReference != props->Reverb.LFReference)
  841. mFadeCount = 0;
  842. mParams.Density = props->Reverb.Density;
  843. mParams.Diffusion = props->Reverb.Diffusion;
  844. mParams.DecayTime = props->Reverb.DecayTime;
  845. mParams.HFDecayTime = hfDecayTime;
  846. mParams.LFDecayTime = lfDecayTime;
  847. mParams.HFReference = props->Reverb.HFReference;
  848. mParams.LFReference = props->Reverb.LFReference;
  849. }
  850. /**************************************
  851. * Effect Processing *
  852. **************************************/
  853. /* Applies a scattering matrix to the 4-line (vector) input. This is used
  854. * for both the below vector all-pass model and to perform modal feed-back
  855. * delay network (FDN) mixing.
  856. *
  857. * The matrix is derived from a skew-symmetric matrix to form a 4D rotation
  858. * matrix with a single unitary rotational parameter:
  859. *
  860. * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
  861. * [ -a, d, c, -b ]
  862. * [ -b, -c, d, a ]
  863. * [ -c, b, -a, d ]
  864. *
  865. * The rotation is constructed from the effect's diffusion parameter,
  866. * yielding:
  867. *
  868. * 1 = x^2 + 3 y^2
  869. *
  870. * Where a, b, and c are the coefficient y with differing signs, and d is the
  871. * coefficient x. The final matrix is thus:
  872. *
  873. * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
  874. * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
  875. * [ y, -y, x, y ] x = cos(t)
  876. * [ -y, -y, -y, x ] y = sin(t) / n
  877. *
  878. * Any square orthogonal matrix with an order that is a power of two will
  879. * work (where ^T is transpose, ^-1 is inverse):
  880. *
  881. * M^T = M^-1
  882. *
  883. * Using that knowledge, finding an appropriate matrix can be accomplished
  884. * naively by searching all combinations of:
  885. *
  886. * M = D + S - S^T
  887. *
  888. * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y)
  889. * whose combination of signs are being iterated.
  890. */
  891. inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in,
  892. const ALfloat xCoeff, const ALfloat yCoeff)
  893. {
  894. out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]);
  895. out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]);
  896. out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]);
  897. out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] );
  898. }
  899. /* Utilizes the above, but reverses the input channels. */
  900. inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset,
  901. const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei base,
  902. const ALfloat (*RESTRICT in)[BUFFERSIZE], const ALsizei count)
  903. {
  904. const DelayLineI delay{*Delay};
  905. ASSUME(base >= 0);
  906. ASSUME(count > 0);
  907. for(ALsizei i{0};i < count;)
  908. {
  909. offset &= delay.Mask;
  910. ALsizei td{mini(delay.Mask+1 - offset, count-i)};
  911. do {
  912. ALfloat f[NUM_LINES];
  913. for(ALsizei j{0};j < NUM_LINES;j++)
  914. f[NUM_LINES-1-j] = in[j][base+i];
  915. ++i;
  916. VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff);
  917. } while(--td);
  918. }
  919. }
  920. /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass
  921. * filter to the 4-line input.
  922. *
  923. * It works by vectorizing a regular all-pass filter and replacing the delay
  924. * element with a scattering matrix (like the one above) and a diagonal
  925. * matrix of delay elements.
  926. *
  927. * Two static specializations are used for transitional (cross-faded) delay
  928. * line processing and non-transitional processing.
  929. */
  930. void VecAllpass::processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset,
  931. const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo)
  932. {
  933. const DelayLineI delay{Delay};
  934. const ALfloat feedCoeff{Coeff};
  935. ASSUME(todo > 0);
  936. ALsizei vap_offset[NUM_LINES];
  937. for(ALsizei j{0};j < NUM_LINES;j++)
  938. vap_offset[j] = offset - Offset[j][0];
  939. for(ALsizei i{0};i < todo;)
  940. {
  941. for(ALsizei j{0};j < NUM_LINES;j++)
  942. vap_offset[j] &= delay.Mask;
  943. offset &= delay.Mask;
  944. ALsizei maxoff{offset};
  945. for(ALsizei j{0};j < NUM_LINES;j++)
  946. maxoff = maxi(maxoff, vap_offset[j]);
  947. ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)};
  948. do {
  949. ALfloat f[NUM_LINES];
  950. for(ALsizei j{0};j < NUM_LINES;j++)
  951. {
  952. const ALfloat input{samples[j][i]};
  953. const ALfloat out{delay.Line[vap_offset[j]++][j] - feedCoeff*input};
  954. f[j] = input + feedCoeff*out;
  955. samples[j][i] = out;
  956. }
  957. ++i;
  958. VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff);
  959. } while(--td);
  960. }
  961. }
  962. void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset,
  963. const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo)
  964. {
  965. const DelayLineI delay{Delay};
  966. const ALfloat feedCoeff{Coeff};
  967. ASSUME(todo > 0);
  968. fade *= 1.0f/FADE_SAMPLES;
  969. ALsizei vap_offset[NUM_LINES][2];
  970. for(ALsizei j{0};j < NUM_LINES;j++)
  971. {
  972. vap_offset[j][0] = offset - Offset[j][0];
  973. vap_offset[j][1] = offset - Offset[j][1];
  974. }
  975. for(ALsizei i{0};i < todo;)
  976. {
  977. for(ALsizei j{0};j < NUM_LINES;j++)
  978. {
  979. vap_offset[j][0] &= delay.Mask;
  980. vap_offset[j][1] &= delay.Mask;
  981. }
  982. offset &= delay.Mask;
  983. ALsizei maxoff{offset};
  984. for(ALsizei j{0};j < NUM_LINES;j++)
  985. maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1]));
  986. ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)};
  987. do {
  988. fade += FadeStep;
  989. ALfloat f[NUM_LINES];
  990. for(ALsizei j{0};j < NUM_LINES;j++)
  991. f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) +
  992. delay.Line[vap_offset[j][1]++][j]*fade;
  993. for(ALsizei j{0};j < NUM_LINES;j++)
  994. {
  995. const ALfloat input{samples[j][i]};
  996. const ALfloat out{f[j] - feedCoeff*input};
  997. f[j] = input + feedCoeff*out;
  998. samples[j][i] = out;
  999. }
  1000. ++i;
  1001. VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff);
  1002. } while(--td);
  1003. }
  1004. }
  1005. /* This generates early reflections.
  1006. *
  1007. * This is done by obtaining the primary reflections (those arriving from the
  1008. * same direction as the source) from the main delay line. These are
  1009. * attenuated and all-pass filtered (based on the diffusion parameter).
  1010. *
  1011. * The early lines are then fed in reverse (according to the approximately
  1012. * opposite spatial location of the A-Format lines) to create the secondary
  1013. * reflections (those arriving from the opposite direction as the source).
  1014. *
  1015. * The early response is then completed by combining the primary reflections
  1016. * with the delayed and attenuated output from the early lines.
  1017. *
  1018. * Finally, the early response is reversed, scattered (based on diffusion),
  1019. * and fed into the late reverb section of the main delay line.
  1020. *
  1021. * Two static specializations are used for transitional (cross-faded) delay
  1022. * line processing and non-transitional processing.
  1023. */
  1024. void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo,
  1025. const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE])
  1026. {
  1027. ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples};
  1028. const DelayLineI early_delay{State->mEarly.Delay};
  1029. const DelayLineI main_delay{State->mDelay};
  1030. const ALfloat mixX{State->mMixX};
  1031. const ALfloat mixY{State->mMixY};
  1032. ASSUME(todo > 0);
  1033. /* First, load decorrelated samples from the main delay line as the primary
  1034. * reflections.
  1035. */
  1036. for(ALsizei j{0};j < NUM_LINES;j++)
  1037. {
  1038. ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]};
  1039. const ALfloat coeff{State->mEarlyDelayCoeff[j][0]};
  1040. for(ALsizei i{0};i < todo;)
  1041. {
  1042. early_delay_tap &= main_delay.Mask;
  1043. ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo - i)};
  1044. do {
  1045. temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff;
  1046. } while(--td);
  1047. }
  1048. }
  1049. /* Apply a vector all-pass, to help color the initial reflections based on
  1050. * the diffusion strength.
  1051. */
  1052. State->mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo);
  1053. /* Apply a delay and bounce to generate secondary reflections, combine with
  1054. * the primary reflections and write out the result for mixing.
  1055. */
  1056. for(ALsizei j{0};j < NUM_LINES;j++)
  1057. {
  1058. ALint feedb_tap{offset - State->mEarly.Offset[j][0]};
  1059. const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]};
  1060. ASSUME(base >= 0);
  1061. for(ALsizei i{0};i < todo;)
  1062. {
  1063. feedb_tap &= early_delay.Mask;
  1064. ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)};
  1065. do {
  1066. out[j][base+i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff;
  1067. ++i;
  1068. } while(--td);
  1069. }
  1070. }
  1071. for(ALsizei j{0};j < NUM_LINES;j++)
  1072. early_delay.write(offset, NUM_LINES-1-j, temps[j], todo);
  1073. /* Also write the result back to the main delay line for the late reverb
  1074. * stage to pick up at the appropriate time, appplying a scatter and
  1075. * bounce to improve the initial diffusion in the late reverb.
  1076. */
  1077. const ALsizei late_feed_tap{offset - State->mLateFeedTap};
  1078. VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, base, out, todo);
  1079. }
  1080. void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo,
  1081. const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE])
  1082. {
  1083. ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples};
  1084. const DelayLineI early_delay{State->mEarly.Delay};
  1085. const DelayLineI main_delay{State->mDelay};
  1086. const ALfloat mixX{State->mMixX};
  1087. const ALfloat mixY{State->mMixY};
  1088. ASSUME(todo > 0);
  1089. for(ALsizei j{0};j < NUM_LINES;j++)
  1090. {
  1091. ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]};
  1092. ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]};
  1093. const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]};
  1094. const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES};
  1095. const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES};
  1096. ALfloat fadeCount{fade};
  1097. for(ALsizei i{0};i < todo;)
  1098. {
  1099. early_delay_tap0 &= main_delay.Mask;
  1100. early_delay_tap1 &= main_delay.Mask;
  1101. ALsizei td{mini(main_delay.Mask+1 - maxi(early_delay_tap0, early_delay_tap1), todo-i)};
  1102. do {
  1103. fadeCount += 1.0f;
  1104. const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount};
  1105. const ALfloat fade1{newCoeffStep*fadeCount};
  1106. temps[j][i++] =
  1107. main_delay.Line[early_delay_tap0++][j]*fade0 +
  1108. main_delay.Line[early_delay_tap1++][j]*fade1;
  1109. } while(--td);
  1110. }
  1111. }
  1112. State->mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo);
  1113. for(ALsizei j{0};j < NUM_LINES;j++)
  1114. {
  1115. ALint feedb_tap0{offset - State->mEarly.Offset[j][0]};
  1116. ALint feedb_tap1{offset - State->mEarly.Offset[j][1]};
  1117. const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]};
  1118. const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES};
  1119. const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES};
  1120. ALfloat fadeCount{fade};
  1121. ASSUME(base >= 0);
  1122. for(ALsizei i{0};i < todo;)
  1123. {
  1124. feedb_tap0 &= early_delay.Mask;
  1125. feedb_tap1 &= early_delay.Mask;
  1126. ALsizei td{mini(early_delay.Mask+1 - maxi(feedb_tap0, feedb_tap1), todo - i)};
  1127. do {
  1128. fadeCount += 1.0f;
  1129. const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount};
  1130. const ALfloat fade1{feedb_newCoeffStep*fadeCount};
  1131. out[j][base+i] = temps[j][i] +
  1132. early_delay.Line[feedb_tap0++][j]*fade0 +
  1133. early_delay.Line[feedb_tap1++][j]*fade1;
  1134. ++i;
  1135. } while(--td);
  1136. }
  1137. }
  1138. for(ALsizei j{0};j < NUM_LINES;j++)
  1139. early_delay.write(offset, NUM_LINES-1-j, temps[j], todo);
  1140. const ALsizei late_feed_tap{offset - State->mLateFeedTap};
  1141. VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, base, out, todo);
  1142. }
  1143. /* This generates the reverb tail using a modified feed-back delay network
  1144. * (FDN).
  1145. *
  1146. * Results from the early reflections are mixed with the output from the late
  1147. * delay lines.
  1148. *
  1149. * The late response is then completed by T60 and all-pass filtering the mix.
  1150. *
  1151. * Finally, the lines are reversed (so they feed their opposite directions)
  1152. * and scattered with the FDN matrix before re-feeding the delay lines.
  1153. *
  1154. * Two variations are made, one for for transitional (cross-faded) delay line
  1155. * processing and one for non-transitional processing.
  1156. */
  1157. void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo,
  1158. const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE])
  1159. {
  1160. ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples};
  1161. const DelayLineI late_delay{State->mLate.Delay};
  1162. const DelayLineI main_delay{State->mDelay};
  1163. const ALfloat mixX{State->mMixX};
  1164. const ALfloat mixY{State->mMixY};
  1165. ASSUME(todo > 0);
  1166. /* First, load decorrelated samples from the main and feedback delay lines.
  1167. * Filter the signal to apply its frequency-dependent decay.
  1168. */
  1169. for(ALsizei j{0};j < NUM_LINES;j++)
  1170. {
  1171. ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]};
  1172. ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]};
  1173. const ALfloat midGain{State->mLate.T60[j].MidGain[0]};
  1174. const ALfloat densityGain{State->mLate.DensityGain[0] * midGain};
  1175. for(ALsizei i{0};i < todo;)
  1176. {
  1177. late_delay_tap &= main_delay.Mask;
  1178. late_feedb_tap &= late_delay.Mask;
  1179. ALsizei td{mini(
  1180. mini(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap),
  1181. todo - i)};
  1182. do {
  1183. temps[j][i++] =
  1184. main_delay.Line[late_delay_tap++][j]*densityGain +
  1185. late_delay.Line[late_feedb_tap++][j]*midGain;
  1186. } while(--td);
  1187. }
  1188. State->mLate.T60[j].process(temps[j], todo);
  1189. }
  1190. /* Apply a vector all-pass to improve micro-surface diffusion, and write
  1191. * out the results for mixing.
  1192. */
  1193. State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo);
  1194. for(ALsizei j{0};j < NUM_LINES;j++)
  1195. std::copy_n(temps[j], todo, out[j]+base);
  1196. /* Finally, scatter and bounce the results to refeed the feedback buffer. */
  1197. VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, base, out, todo);
  1198. }
  1199. void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo,
  1200. const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE])
  1201. {
  1202. ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples};
  1203. const DelayLineI late_delay{State->mLate.Delay};
  1204. const DelayLineI main_delay{State->mDelay};
  1205. const ALfloat mixX{State->mMixX};
  1206. const ALfloat mixY{State->mMixY};
  1207. ASSUME(todo > 0);
  1208. for(ALsizei j{0};j < NUM_LINES;j++)
  1209. {
  1210. const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]};
  1211. const ALfloat midGain{State->mLate.T60[j].MidGain[1]};
  1212. const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES};
  1213. const ALfloat midStep{midGain / FADE_SAMPLES};
  1214. const ALfloat oldDensityGain{State->mLate.DensityGain[0] * oldMidGain};
  1215. const ALfloat densityGain{State->mLate.DensityGain[1] * midGain};
  1216. const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES};
  1217. const ALfloat densityStep{densityGain / FADE_SAMPLES};
  1218. ALsizei late_delay_tap0{offset - State->mLateDelayTap[j][0]};
  1219. ALsizei late_delay_tap1{offset - State->mLateDelayTap[j][1]};
  1220. ALsizei late_feedb_tap0{offset - State->mLate.Offset[j][0]};
  1221. ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]};
  1222. ALfloat fadeCount{fade};
  1223. for(ALsizei i{0};i < todo;)
  1224. {
  1225. late_delay_tap0 &= main_delay.Mask;
  1226. late_delay_tap1 &= main_delay.Mask;
  1227. late_feedb_tap0 &= late_delay.Mask;
  1228. late_feedb_tap1 &= late_delay.Mask;
  1229. ALsizei td{mini(
  1230. mini(main_delay.Mask+1 - maxi(late_delay_tap0, late_delay_tap1),
  1231. late_delay.Mask+1 - maxi(late_feedb_tap0, late_feedb_tap1)),
  1232. todo - i)};
  1233. do {
  1234. fadeCount += 1.0f;
  1235. const ALfloat fade0{oldDensityGain + oldDensityStep*fadeCount};
  1236. const ALfloat fade1{densityStep*fadeCount};
  1237. const ALfloat gfade0{oldMidGain + oldMidStep*fadeCount};
  1238. const ALfloat gfade1{midStep*fadeCount};
  1239. temps[j][i++] =
  1240. main_delay.Line[late_delay_tap0++][j]*fade0 +
  1241. main_delay.Line[late_delay_tap1++][j]*fade1 +
  1242. late_delay.Line[late_feedb_tap0++][j]*gfade0 +
  1243. late_delay.Line[late_feedb_tap1++][j]*gfade1;
  1244. } while(--td);
  1245. }
  1246. State->mLate.T60[j].process(temps[j], todo);
  1247. }
  1248. State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo);
  1249. for(ALsizei j{0};j < NUM_LINES;j++)
  1250. std::copy_n(temps[j], todo, out[j]+base);
  1251. VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, base, out, todo);
  1252. }
  1253. void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput)
  1254. {
  1255. ALsizei fadeCount{mFadeCount};
  1256. ASSUME(samplesToDo > 0);
  1257. /* Convert B-Format to A-Format for processing. */
  1258. ALfloat (&afmt)[NUM_LINES][BUFFERSIZE] = mTempSamples;
  1259. for(ALsizei c{0};c < NUM_LINES;c++)
  1260. {
  1261. std::fill_n(std::begin(afmt[c]), samplesToDo, 0.0f);
  1262. MixRowSamples(afmt[c], B2A[c], samplesIn, numInput, 0, samplesToDo);
  1263. /* Band-pass the incoming samples. */
  1264. mFilter[c].Lp.process(afmt[c], afmt[c], samplesToDo);
  1265. mFilter[c].Hp.process(afmt[c], afmt[c], samplesToDo);
  1266. }
  1267. /* Process reverb for these samples. */
  1268. for(ALsizei base{0};base < samplesToDo;)
  1269. {
  1270. ALsizei todo{samplesToDo - base};
  1271. /* If cross-fading, don't do more samples than there are to fade. */
  1272. if(FADE_SAMPLES-fadeCount > 0)
  1273. {
  1274. todo = mini(todo, FADE_SAMPLES-fadeCount);
  1275. todo = mini(todo, mMaxUpdate[0]);
  1276. }
  1277. todo = mini(todo, mMaxUpdate[1]);
  1278. ASSUME(todo > 0 && todo <= BUFFERSIZE);
  1279. const ALsizei offset{mOffset + base};
  1280. ASSUME(offset >= 0);
  1281. /* Feed the initial delay line. */
  1282. for(ALsizei c{0};c < NUM_LINES;c++)
  1283. mDelay.write(offset, c, afmt[c]+base, todo);
  1284. /* Process the samples for reverb. */
  1285. if(UNLIKELY(fadeCount < FADE_SAMPLES))
  1286. {
  1287. auto fade = static_cast<ALfloat>(fadeCount);
  1288. /* Generate early reflections and late reverb. */
  1289. EarlyReflection_Faded(this, offset, todo, fade, base, mEarlyBuffer);
  1290. LateReverb_Faded(this, offset, todo, fade, base, mLateBuffer);
  1291. /* Step fading forward. */
  1292. fadeCount += todo;
  1293. if(fadeCount >= FADE_SAMPLES)
  1294. {
  1295. /* Update the cross-fading delay line taps. */
  1296. fadeCount = FADE_SAMPLES;
  1297. for(ALsizei c{0};c < NUM_LINES;c++)
  1298. {
  1299. mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1];
  1300. mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1];
  1301. mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1];
  1302. mEarly.Offset[c][0] = mEarly.Offset[c][1];
  1303. mEarly.Coeff[c][0] = mEarly.Coeff[c][1];
  1304. mLateDelayTap[c][0] = mLateDelayTap[c][1];
  1305. mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1];
  1306. mLate.Offset[c][0] = mLate.Offset[c][1];
  1307. mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1];
  1308. }
  1309. mLate.DensityGain[0] = mLate.DensityGain[1];
  1310. mMaxUpdate[0] = mMaxUpdate[1];
  1311. }
  1312. }
  1313. else
  1314. {
  1315. /* Generate early reflections and late reverb. */
  1316. EarlyReflection_Unfaded(this, offset, todo, base, mEarlyBuffer);
  1317. LateReverb_Unfaded(this, offset, todo, base, mLateBuffer);
  1318. }
  1319. base += todo;
  1320. }
  1321. mOffset = (mOffset+samplesToDo) & 0x3fffffff;
  1322. mFadeCount = fadeCount;
  1323. /* Finally, mix early reflections and late reverb. */
  1324. (this->*mMixOut)(numOutput, samplesOut, samplesToDo);
  1325. }
  1326. void EAXReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
  1327. {
  1328. switch(param)
  1329. {
  1330. case AL_EAXREVERB_DECAY_HFLIMIT:
  1331. if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
  1332. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range");
  1333. props->Reverb.DecayHFLimit = val;
  1334. break;
  1335. default:
  1336. alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x",
  1337. param);
  1338. }
  1339. }
  1340. void EAXReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
  1341. { EAXReverb_setParami(props, context, param, vals[0]); }
  1342. void EAXReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val)
  1343. {
  1344. switch(param)
  1345. {
  1346. case AL_EAXREVERB_DENSITY:
  1347. if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
  1348. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range");
  1349. props->Reverb.Density = val;
  1350. break;
  1351. case AL_EAXREVERB_DIFFUSION:
  1352. if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
  1353. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range");
  1354. props->Reverb.Diffusion = val;
  1355. break;
  1356. case AL_EAXREVERB_GAIN:
  1357. if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
  1358. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range");
  1359. props->Reverb.Gain = val;
  1360. break;
  1361. case AL_EAXREVERB_GAINHF:
  1362. if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
  1363. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range");
  1364. props->Reverb.GainHF = val;
  1365. break;
  1366. case AL_EAXREVERB_GAINLF:
  1367. if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
  1368. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range");
  1369. props->Reverb.GainLF = val;
  1370. break;
  1371. case AL_EAXREVERB_DECAY_TIME:
  1372. if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
  1373. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range");
  1374. props->Reverb.DecayTime = val;
  1375. break;
  1376. case AL_EAXREVERB_DECAY_HFRATIO:
  1377. if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
  1378. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range");
  1379. props->Reverb.DecayHFRatio = val;
  1380. break;
  1381. case AL_EAXREVERB_DECAY_LFRATIO:
  1382. if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
  1383. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range");
  1384. props->Reverb.DecayLFRatio = val;
  1385. break;
  1386. case AL_EAXREVERB_REFLECTIONS_GAIN:
  1387. if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
  1388. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range");
  1389. props->Reverb.ReflectionsGain = val;
  1390. break;
  1391. case AL_EAXREVERB_REFLECTIONS_DELAY:
  1392. if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
  1393. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range");
  1394. props->Reverb.ReflectionsDelay = val;
  1395. break;
  1396. case AL_EAXREVERB_LATE_REVERB_GAIN:
  1397. if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
  1398. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range");
  1399. props->Reverb.LateReverbGain = val;
  1400. break;
  1401. case AL_EAXREVERB_LATE_REVERB_DELAY:
  1402. if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
  1403. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range");
  1404. props->Reverb.LateReverbDelay = val;
  1405. break;
  1406. case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
  1407. if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
  1408. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range");
  1409. props->Reverb.AirAbsorptionGainHF = val;
  1410. break;
  1411. case AL_EAXREVERB_ECHO_TIME:
  1412. if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
  1413. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range");
  1414. props->Reverb.EchoTime = val;
  1415. break;
  1416. case AL_EAXREVERB_ECHO_DEPTH:
  1417. if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
  1418. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range");
  1419. props->Reverb.EchoDepth = val;
  1420. break;
  1421. case AL_EAXREVERB_MODULATION_TIME:
  1422. if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
  1423. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range");
  1424. props->Reverb.ModulationTime = val;
  1425. break;
  1426. case AL_EAXREVERB_MODULATION_DEPTH:
  1427. if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
  1428. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range");
  1429. props->Reverb.ModulationDepth = val;
  1430. break;
  1431. case AL_EAXREVERB_HFREFERENCE:
  1432. if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
  1433. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range");
  1434. props->Reverb.HFReference = val;
  1435. break;
  1436. case AL_EAXREVERB_LFREFERENCE:
  1437. if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
  1438. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range");
  1439. props->Reverb.LFReference = val;
  1440. break;
  1441. case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
  1442. if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
  1443. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range");
  1444. props->Reverb.RoomRolloffFactor = val;
  1445. break;
  1446. default:
  1447. alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x",
  1448. param);
  1449. }
  1450. }
  1451. void EAXReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals)
  1452. {
  1453. switch(param)
  1454. {
  1455. case AL_EAXREVERB_REFLECTIONS_PAN:
  1456. if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2])))
  1457. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range");
  1458. props->Reverb.ReflectionsPan[0] = vals[0];
  1459. props->Reverb.ReflectionsPan[1] = vals[1];
  1460. props->Reverb.ReflectionsPan[2] = vals[2];
  1461. break;
  1462. case AL_EAXREVERB_LATE_REVERB_PAN:
  1463. if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2])))
  1464. SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range");
  1465. props->Reverb.LateReverbPan[0] = vals[0];
  1466. props->Reverb.LateReverbPan[1] = vals[1];
  1467. props->Reverb.LateReverbPan[2] = vals[2];
  1468. break;
  1469. default:
  1470. EAXReverb_setParamf(props, context, param, vals[0]);
  1471. break;
  1472. }
  1473. }
  1474. void EAXReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
  1475. {
  1476. switch(param)
  1477. {
  1478. case AL_EAXREVERB_DECAY_HFLIMIT:
  1479. *val = props->Reverb.DecayHFLimit;
  1480. break;
  1481. default:
  1482. alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x",
  1483. param);
  1484. }
  1485. }
  1486. void EAXReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
  1487. { EAXReverb_getParami(props, context, param, vals); }
  1488. void EAXReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val)
  1489. {
  1490. switch(param)
  1491. {
  1492. case AL_EAXREVERB_DENSITY:
  1493. *val = props->Reverb.Density;
  1494. break;
  1495. case AL_EAXREVERB_DIFFUSION:
  1496. *val = props->Reverb.Diffusion;
  1497. break;
  1498. case AL_EAXREVERB_GAIN:
  1499. *val = props->Reverb.Gain;
  1500. break;
  1501. case AL_EAXREVERB_GAINHF:
  1502. *val = props->Reverb.GainHF;
  1503. break;
  1504. case AL_EAXREVERB_GAINLF:
  1505. *val = props->Reverb.GainLF;
  1506. break;
  1507. case AL_EAXREVERB_DECAY_TIME:
  1508. *val = props->Reverb.DecayTime;
  1509. break;
  1510. case AL_EAXREVERB_DECAY_HFRATIO:
  1511. *val = props->Reverb.DecayHFRatio;
  1512. break;
  1513. case AL_EAXREVERB_DECAY_LFRATIO:
  1514. *val = props->Reverb.DecayLFRatio;
  1515. break;
  1516. case AL_EAXREVERB_REFLECTIONS_GAIN:
  1517. *val = props->Reverb.ReflectionsGain;
  1518. break;
  1519. case AL_EAXREVERB_REFLECTIONS_DELAY:
  1520. *val = props->Reverb.ReflectionsDelay;
  1521. break;
  1522. case AL_EAXREVERB_LATE_REVERB_GAIN:
  1523. *val = props->Reverb.LateReverbGain;
  1524. break;
  1525. case AL_EAXREVERB_LATE_REVERB_DELAY:
  1526. *val = props->Reverb.LateReverbDelay;
  1527. break;
  1528. case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
  1529. *val = props->Reverb.AirAbsorptionGainHF;
  1530. break;
  1531. case AL_EAXREVERB_ECHO_TIME:
  1532. *val = props->Reverb.EchoTime;
  1533. break;
  1534. case AL_EAXREVERB_ECHO_DEPTH:
  1535. *val = props->Reverb.EchoDepth;
  1536. break;
  1537. case AL_EAXREVERB_MODULATION_TIME:
  1538. *val = props->Reverb.ModulationTime;
  1539. break;
  1540. case AL_EAXREVERB_MODULATION_DEPTH:
  1541. *val = props->Reverb.ModulationDepth;
  1542. break;
  1543. case AL_EAXREVERB_HFREFERENCE:
  1544. *val = props->Reverb.HFReference;
  1545. break;
  1546. case AL_EAXREVERB_LFREFERENCE:
  1547. *val = props->Reverb.LFReference;
  1548. break;
  1549. case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
  1550. *val = props->Reverb.RoomRolloffFactor;
  1551. break;
  1552. default:
  1553. alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x",
  1554. param);
  1555. }
  1556. }
  1557. void EAXReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals)
  1558. {
  1559. switch(param)
  1560. {
  1561. case AL_EAXREVERB_REFLECTIONS_PAN:
  1562. vals[0] = props->Reverb.ReflectionsPan[0];
  1563. vals[1] = props->Reverb.ReflectionsPan[1];
  1564. vals[2] = props->Reverb.ReflectionsPan[2];
  1565. break;
  1566. case AL_EAXREVERB_LATE_REVERB_PAN:
  1567. vals[0] = props->Reverb.LateReverbPan[0];
  1568. vals[1] = props->Reverb.LateReverbPan[1];
  1569. vals[2] = props->Reverb.LateReverbPan[2];
  1570. break;
  1571. default:
  1572. EAXReverb_getParamf(props, context, param, vals);
  1573. break;
  1574. }
  1575. }
  1576. DEFINE_ALEFFECT_VTABLE(EAXReverb);
  1577. struct ReverbStateFactory final : public EffectStateFactory {
  1578. EffectState *create() override { return new ReverbState{}; }
  1579. EffectProps getDefaultProps() const noexcept override;
  1580. const EffectVtable *getEffectVtable() const noexcept override { return &EAXReverb_vtable; }
  1581. };
  1582. EffectProps ReverbStateFactory::getDefaultProps() const noexcept
  1583. {
  1584. EffectProps props{};
  1585. props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
  1586. props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
  1587. props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
  1588. props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
  1589. props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
  1590. props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
  1591. props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
  1592. props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
  1593. props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
  1594. props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
  1595. props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
  1596. props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
  1597. props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
  1598. props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
  1599. props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
  1600. props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
  1601. props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
  1602. props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
  1603. props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
  1604. props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
  1605. props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
  1606. props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
  1607. props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
  1608. props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
  1609. props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
  1610. props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
  1611. props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
  1612. return props;
  1613. }
  1614. void StdReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
  1615. {
  1616. switch(param)
  1617. {
  1618. case AL_REVERB_DECAY_HFLIMIT:
  1619. if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
  1620. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range");
  1621. props->Reverb.DecayHFLimit = val;
  1622. break;
  1623. default:
  1624. alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param);
  1625. }
  1626. }
  1627. void StdReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
  1628. { StdReverb_setParami(props, context, param, vals[0]); }
  1629. void StdReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val)
  1630. {
  1631. switch(param)
  1632. {
  1633. case AL_REVERB_DENSITY:
  1634. if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
  1635. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range");
  1636. props->Reverb.Density = val;
  1637. break;
  1638. case AL_REVERB_DIFFUSION:
  1639. if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
  1640. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range");
  1641. props->Reverb.Diffusion = val;
  1642. break;
  1643. case AL_REVERB_GAIN:
  1644. if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
  1645. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range");
  1646. props->Reverb.Gain = val;
  1647. break;
  1648. case AL_REVERB_GAINHF:
  1649. if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
  1650. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range");
  1651. props->Reverb.GainHF = val;
  1652. break;
  1653. case AL_REVERB_DECAY_TIME:
  1654. if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
  1655. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range");
  1656. props->Reverb.DecayTime = val;
  1657. break;
  1658. case AL_REVERB_DECAY_HFRATIO:
  1659. if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
  1660. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range");
  1661. props->Reverb.DecayHFRatio = val;
  1662. break;
  1663. case AL_REVERB_REFLECTIONS_GAIN:
  1664. if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
  1665. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range");
  1666. props->Reverb.ReflectionsGain = val;
  1667. break;
  1668. case AL_REVERB_REFLECTIONS_DELAY:
  1669. if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
  1670. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range");
  1671. props->Reverb.ReflectionsDelay = val;
  1672. break;
  1673. case AL_REVERB_LATE_REVERB_GAIN:
  1674. if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
  1675. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range");
  1676. props->Reverb.LateReverbGain = val;
  1677. break;
  1678. case AL_REVERB_LATE_REVERB_DELAY:
  1679. if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
  1680. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range");
  1681. props->Reverb.LateReverbDelay = val;
  1682. break;
  1683. case AL_REVERB_AIR_ABSORPTION_GAINHF:
  1684. if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
  1685. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range");
  1686. props->Reverb.AirAbsorptionGainHF = val;
  1687. break;
  1688. case AL_REVERB_ROOM_ROLLOFF_FACTOR:
  1689. if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
  1690. SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range");
  1691. props->Reverb.RoomRolloffFactor = val;
  1692. break;
  1693. default:
  1694. alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param);
  1695. }
  1696. }
  1697. void StdReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals)
  1698. { StdReverb_setParamf(props, context, param, vals[0]); }
  1699. void StdReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
  1700. {
  1701. switch(param)
  1702. {
  1703. case AL_REVERB_DECAY_HFLIMIT:
  1704. *val = props->Reverb.DecayHFLimit;
  1705. break;
  1706. default:
  1707. alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param);
  1708. }
  1709. }
  1710. void StdReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
  1711. { StdReverb_getParami(props, context, param, vals); }
  1712. void StdReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val)
  1713. {
  1714. switch(param)
  1715. {
  1716. case AL_REVERB_DENSITY:
  1717. *val = props->Reverb.Density;
  1718. break;
  1719. case AL_REVERB_DIFFUSION:
  1720. *val = props->Reverb.Diffusion;
  1721. break;
  1722. case AL_REVERB_GAIN:
  1723. *val = props->Reverb.Gain;
  1724. break;
  1725. case AL_REVERB_GAINHF:
  1726. *val = props->Reverb.GainHF;
  1727. break;
  1728. case AL_REVERB_DECAY_TIME:
  1729. *val = props->Reverb.DecayTime;
  1730. break;
  1731. case AL_REVERB_DECAY_HFRATIO:
  1732. *val = props->Reverb.DecayHFRatio;
  1733. break;
  1734. case AL_REVERB_REFLECTIONS_GAIN:
  1735. *val = props->Reverb.ReflectionsGain;
  1736. break;
  1737. case AL_REVERB_REFLECTIONS_DELAY:
  1738. *val = props->Reverb.ReflectionsDelay;
  1739. break;
  1740. case AL_REVERB_LATE_REVERB_GAIN:
  1741. *val = props->Reverb.LateReverbGain;
  1742. break;
  1743. case AL_REVERB_LATE_REVERB_DELAY:
  1744. *val = props->Reverb.LateReverbDelay;
  1745. break;
  1746. case AL_REVERB_AIR_ABSORPTION_GAINHF:
  1747. *val = props->Reverb.AirAbsorptionGainHF;
  1748. break;
  1749. case AL_REVERB_ROOM_ROLLOFF_FACTOR:
  1750. *val = props->Reverb.RoomRolloffFactor;
  1751. break;
  1752. default:
  1753. alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param);
  1754. }
  1755. }
  1756. void StdReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals)
  1757. { StdReverb_getParamf(props, context, param, vals); }
  1758. DEFINE_ALEFFECT_VTABLE(StdReverb);
  1759. struct StdReverbStateFactory final : public EffectStateFactory {
  1760. EffectState *create() override { return new ReverbState{}; }
  1761. EffectProps getDefaultProps() const noexcept override;
  1762. const EffectVtable *getEffectVtable() const noexcept override { return &StdReverb_vtable; }
  1763. };
  1764. EffectProps StdReverbStateFactory::getDefaultProps() const noexcept
  1765. {
  1766. EffectProps props{};
  1767. props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
  1768. props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
  1769. props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
  1770. props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
  1771. props.Reverb.GainLF = 1.0f;
  1772. props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
  1773. props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
  1774. props.Reverb.DecayLFRatio = 1.0f;
  1775. props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
  1776. props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
  1777. props.Reverb.ReflectionsPan[0] = 0.0f;
  1778. props.Reverb.ReflectionsPan[1] = 0.0f;
  1779. props.Reverb.ReflectionsPan[2] = 0.0f;
  1780. props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
  1781. props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
  1782. props.Reverb.LateReverbPan[0] = 0.0f;
  1783. props.Reverb.LateReverbPan[1] = 0.0f;
  1784. props.Reverb.LateReverbPan[2] = 0.0f;
  1785. props.Reverb.EchoTime = 0.25f;
  1786. props.Reverb.EchoDepth = 0.0f;
  1787. props.Reverb.ModulationTime = 0.25f;
  1788. props.Reverb.ModulationDepth = 0.0f;
  1789. props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
  1790. props.Reverb.HFReference = 5000.0f;
  1791. props.Reverb.LFReference = 250.0f;
  1792. props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
  1793. props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
  1794. return props;
  1795. }
  1796. } // namespace
  1797. EffectStateFactory *ReverbStateFactory_getFactory()
  1798. {
  1799. static ReverbStateFactory ReverbFactory{};
  1800. return &ReverbFactory;
  1801. }
  1802. EffectStateFactory *StdReverbStateFactory_getFactory()
  1803. {
  1804. static StdReverbStateFactory ReverbFactory{};
  1805. return &ReverbFactory;
  1806. }