|
|
@@ -24,13 +24,13 @@
|
|
|
#include <stdlib.h>
|
|
|
#include <math.h>
|
|
|
|
|
|
-#include "AL/al.h"
|
|
|
-#include "AL/alc.h"
|
|
|
#include "alMain.h"
|
|
|
+#include "alu.h"
|
|
|
#include "alAuxEffectSlot.h"
|
|
|
#include "alEffect.h"
|
|
|
+#include "alFilter.h"
|
|
|
#include "alError.h"
|
|
|
-#include "alu.h"
|
|
|
+
|
|
|
|
|
|
typedef struct DelayLine
|
|
|
{
|
|
|
@@ -40,18 +40,19 @@ typedef struct DelayLine
|
|
|
ALfloat *Line;
|
|
|
} DelayLine;
|
|
|
|
|
|
-typedef struct ALverbState {
|
|
|
- // Must be first in all effects!
|
|
|
- ALeffectState state;
|
|
|
+typedef struct ALreverbState {
|
|
|
+ DERIVE_FROM_TYPE(ALeffectState);
|
|
|
+
|
|
|
+ ALboolean IsEax;
|
|
|
|
|
|
// All delay lines are allocated as a single buffer to reduce memory
|
|
|
// fragmentation and management code.
|
|
|
ALfloat *SampleBuffer;
|
|
|
ALuint TotalSamples;
|
|
|
|
|
|
- // Master effect low-pass filter (2 chained 1-pole filters).
|
|
|
- FILTER LpFilter;
|
|
|
- ALfloat LpHistory[2];
|
|
|
+ // Master effect filters
|
|
|
+ ALfilterState LpFilter;
|
|
|
+ ALfilterState HpFilter; // EAX only
|
|
|
|
|
|
struct {
|
|
|
// Modulator delay line.
|
|
|
@@ -85,7 +86,7 @@ typedef struct ALverbState {
|
|
|
|
|
|
// The gain for each output channel based on 3D panning (only for the
|
|
|
// EAX path).
|
|
|
- ALfloat PanGain[MAXCHANNELS];
|
|
|
+ ALfloat PanGain[MaxChannels];
|
|
|
} Early;
|
|
|
|
|
|
// Decorrelator delay line.
|
|
|
@@ -124,7 +125,7 @@ typedef struct ALverbState {
|
|
|
|
|
|
// The gain for each output channel based on 3D panning (only for the
|
|
|
// EAX path).
|
|
|
- ALfloat PanGain[MAXCHANNELS];
|
|
|
+ ALfloat PanGain[MaxChannels];
|
|
|
} Late;
|
|
|
|
|
|
struct {
|
|
|
@@ -157,7 +158,11 @@ typedef struct ALverbState {
|
|
|
// The gain for each output channel (non-EAX path only; aliased from
|
|
|
// Late.PanGain)
|
|
|
ALfloat *Gain;
|
|
|
-} ALverbState;
|
|
|
+
|
|
|
+ /* Temporary storage used when processing, before deinterlacing. */
|
|
|
+ ALfloat ReverbSamples[BUFFERSIZE][4];
|
|
|
+ ALfloat EarlySamples[BUFFERSIZE][4];
|
|
|
+} ALreverbState;
|
|
|
|
|
|
/* This is a user config option for modifying the overall output of the reverb
|
|
|
* effect.
|
|
|
@@ -219,24 +224,24 @@ static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
|
|
|
|
|
|
|
|
|
// Basic delay line input/output routines.
|
|
|
-static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
|
|
|
+static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
|
|
|
{
|
|
|
return Delay->Line[offset&Delay->Mask];
|
|
|
}
|
|
|
|
|
|
-static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
|
|
|
+static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
|
|
|
{
|
|
|
Delay->Line[offset&Delay->Mask] = in;
|
|
|
}
|
|
|
|
|
|
// Attenuated delay line output routine.
|
|
|
-static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
|
|
|
+static inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
|
|
|
{
|
|
|
return coeff * Delay->Line[offset&Delay->Mask];
|
|
|
}
|
|
|
|
|
|
// Basic attenuated all-pass input/output routine.
|
|
|
-static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
|
|
|
+static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
|
|
|
{
|
|
|
ALfloat out, feed;
|
|
|
|
|
|
@@ -252,7 +257,7 @@ static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint
|
|
|
|
|
|
// Given an input sample, this function produces modulation for the late
|
|
|
// reverb.
|
|
|
-static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
|
|
|
+static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in)
|
|
|
{
|
|
|
ALfloat sinus, frac;
|
|
|
ALuint offset;
|
|
|
@@ -261,7 +266,7 @@ static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
|
|
|
// Calculate the sinus rythm (dependent on modulation time and the
|
|
|
// sampling rate). The center of the sinus is moved to reduce the delay
|
|
|
// of the effect when the time or depth are low.
|
|
|
- sinus = 1.0f - aluCos(F_PI*2.0f * State->Mod.Index / State->Mod.Range);
|
|
|
+ sinus = 1.0f - cosf(F_2PI * State->Mod.Index / State->Mod.Range);
|
|
|
|
|
|
// The depth determines the range over which to read the input samples
|
|
|
// from, so it must be filtered to reduce the distortion caused by even
|
|
|
@@ -289,7 +294,7 @@ static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
|
|
|
}
|
|
|
|
|
|
// Delay line output routine for early reflections.
|
|
|
-static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
|
|
|
+static inline ALfloat EarlyDelayLineOut(ALreverbState *State, ALuint index)
|
|
|
{
|
|
|
return AttenuatedDelayLineOut(&State->Early.Delay[index],
|
|
|
State->Offset - State->Early.Offset[index],
|
|
|
@@ -298,7 +303,7 @@ static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
|
|
|
|
|
|
// Given an input sample, this function produces four-channel output for the
|
|
|
// early reflections.
|
|
|
-static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
|
|
|
+static inline ALvoid EarlyReflection(ALreverbState *State, ALfloat in, ALfloat *restrict out)
|
|
|
{
|
|
|
ALfloat d[4], v, f[4];
|
|
|
|
|
|
@@ -343,7 +348,7 @@ static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *
|
|
|
}
|
|
|
|
|
|
// All-pass input/output routine for late reverb.
|
|
|
-static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
|
|
|
+static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint index, ALfloat in)
|
|
|
{
|
|
|
return AllpassInOut(&State->Late.ApDelay[index],
|
|
|
State->Offset - State->Late.ApOffset[index],
|
|
|
@@ -352,7 +357,7 @@ static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALflo
|
|
|
}
|
|
|
|
|
|
// Delay line output routine for late reverb.
|
|
|
-static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
|
|
|
+static inline ALfloat LateDelayLineOut(ALreverbState *State, ALuint index)
|
|
|
{
|
|
|
return AttenuatedDelayLineOut(&State->Late.Delay[index],
|
|
|
State->Offset - State->Late.Offset[index],
|
|
|
@@ -360,7 +365,7 @@ static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
|
|
|
}
|
|
|
|
|
|
// Low-pass filter input/output routine for late reverb.
|
|
|
-static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
|
|
|
+static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in)
|
|
|
{
|
|
|
in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
|
|
|
State->Late.LpSample[index] = in;
|
|
|
@@ -369,7 +374,7 @@ static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALflo
|
|
|
|
|
|
// Given four decorrelated input samples, this function produces four-channel
|
|
|
// output for the late reverb.
|
|
|
-static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
|
|
|
+static inline ALvoid LateReverb(ALreverbState *State, const ALfloat *restrict in, ALfloat *restrict out)
|
|
|
{
|
|
|
ALfloat d[4], f[4];
|
|
|
|
|
|
@@ -440,7 +445,7 @@ static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
|
|
|
|
|
|
// Given an input sample, this function mixes echo into the four-channel late
|
|
|
// reverb.
|
|
|
-static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
|
|
|
+static inline ALvoid EAXEcho(ALreverbState *State, ALfloat in, ALfloat *restrict late)
|
|
|
{
|
|
|
ALfloat out, feed;
|
|
|
|
|
|
@@ -474,19 +479,19 @@ static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
|
|
|
|
|
|
// Perform the non-EAX reverb pass on a given input sample, resulting in
|
|
|
// four-channel output.
|
|
|
-static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
|
|
|
+static inline ALvoid VerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict out)
|
|
|
{
|
|
|
- ALfloat feed, taps[4];
|
|
|
+ ALfloat feed, late[4], taps[4];
|
|
|
|
|
|
- // Low-pass filter the incoming sample.
|
|
|
- in = lpFilter2P(&State->LpFilter, 0, in);
|
|
|
+ // Filter the incoming sample.
|
|
|
+ in = ALfilterState_processSingle(&State->LpFilter, in);
|
|
|
|
|
|
// Feed the initial delay line.
|
|
|
DelayLineIn(&State->Delay, State->Offset, in);
|
|
|
|
|
|
// Calculate the early reflection from the first delay tap.
|
|
|
in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
|
|
|
- EarlyReflection(State, in, early);
|
|
|
+ EarlyReflection(State, in, out);
|
|
|
|
|
|
// Feed the decorrelator from the energy-attenuated output of the second
|
|
|
// delay tap.
|
|
|
@@ -501,18 +506,25 @@ static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early,
|
|
|
taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
|
|
|
LateReverb(State, taps, late);
|
|
|
|
|
|
+ // Mix early reflections and late reverb.
|
|
|
+ out[0] += late[0];
|
|
|
+ out[1] += late[1];
|
|
|
+ out[2] += late[2];
|
|
|
+ out[3] += late[3];
|
|
|
+
|
|
|
// Step all delays forward one sample.
|
|
|
State->Offset++;
|
|
|
}
|
|
|
|
|
|
// Perform the EAX reverb pass on a given input sample, resulting in four-
|
|
|
// channel output.
|
|
|
-static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
|
|
|
+static inline ALvoid EAXVerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict early, ALfloat *restrict late)
|
|
|
{
|
|
|
ALfloat feed, taps[4];
|
|
|
|
|
|
// Low-pass filter the incoming sample.
|
|
|
- in = lpFilter2P(&State->LpFilter, 0, in);
|
|
|
+ in = ALfilterState_processSingle(&State->LpFilter, in);
|
|
|
+ in = ALfilterState_processSingle(&State->HpFilter, in);
|
|
|
|
|
|
// Perform any modulation on the input.
|
|
|
in = EAXModulation(State, in);
|
|
|
@@ -544,85 +556,66 @@ static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *earl
|
|
|
State->Offset++;
|
|
|
}
|
|
|
|
|
|
-// This processes the reverb state, given the input samples and an output
|
|
|
-// buffer.
|
|
|
-static ALvoid VerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
|
|
|
+static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
|
|
|
{
|
|
|
- ALverbState *State = (ALverbState*)effect;
|
|
|
- ALuint index;
|
|
|
- ALfloat early[4], late[4], out[4];
|
|
|
- const ALfloat *panGain = State->Gain;
|
|
|
+ ALfloat (*restrict out)[4] = State->ReverbSamples;
|
|
|
+ ALuint index, c;
|
|
|
|
|
|
+ /* Process reverb for these samples. */
|
|
|
for(index = 0;index < SamplesToDo;index++)
|
|
|
+ VerbPass(State, SamplesIn[index], out[index]);
|
|
|
+
|
|
|
+ for(c = 0;c < MaxChannels;c++)
|
|
|
{
|
|
|
- // Process reverb for this sample.
|
|
|
- VerbPass(State, SamplesIn[index], early, late);
|
|
|
-
|
|
|
- // Mix early reflections and late reverb.
|
|
|
- out[0] = (early[0] + late[0]);
|
|
|
- out[1] = (early[1] + late[1]);
|
|
|
- out[2] = (early[2] + late[2]);
|
|
|
- out[3] = (early[3] + late[3]);
|
|
|
-
|
|
|
- // Output the results.
|
|
|
- SamplesOut[index][FRONT_LEFT] += panGain[FRONT_LEFT] * out[0];
|
|
|
- SamplesOut[index][FRONT_RIGHT] += panGain[FRONT_RIGHT] * out[1];
|
|
|
- SamplesOut[index][FRONT_CENTER] += panGain[FRONT_CENTER] * out[3];
|
|
|
- SamplesOut[index][SIDE_LEFT] += panGain[SIDE_LEFT] * out[0];
|
|
|
- SamplesOut[index][SIDE_RIGHT] += panGain[SIDE_RIGHT] * out[1];
|
|
|
- SamplesOut[index][BACK_LEFT] += panGain[BACK_LEFT] * out[0];
|
|
|
- SamplesOut[index][BACK_RIGHT] += panGain[BACK_RIGHT] * out[1];
|
|
|
- SamplesOut[index][BACK_CENTER] += panGain[BACK_CENTER] * out[2];
|
|
|
+ ALfloat gain = State->Gain[c];
|
|
|
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ for(index = 0;index < SamplesToDo;index++)
|
|
|
+ SamplesOut[c][index] += gain * out[index][c&3];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// This processes the EAX reverb state, given the input samples and an output
|
|
|
-// buffer.
|
|
|
-static ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
|
|
|
+static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
|
|
|
{
|
|
|
- ALverbState *State = (ALverbState*)effect;
|
|
|
- ALuint index;
|
|
|
- ALfloat early[4], late[4];
|
|
|
+ ALfloat (*restrict early)[4] = State->EarlySamples;
|
|
|
+ ALfloat (*restrict late)[4] = State->ReverbSamples;
|
|
|
+ ALuint index, c;
|
|
|
|
|
|
+ /* Process reverb for these samples. */
|
|
|
for(index = 0;index < SamplesToDo;index++)
|
|
|
+ EAXVerbPass(State, SamplesIn[index], early[index], late[index]);
|
|
|
+
|
|
|
+ for(c = 0;c < MaxChannels;c++)
|
|
|
{
|
|
|
- // Process reverb for this sample.
|
|
|
- EAXVerbPass(State, SamplesIn[index], early, late);
|
|
|
-
|
|
|
- // Unfortunately, while the number and configuration of gains for
|
|
|
- // panning adjust according to MAXCHANNELS, the output from the
|
|
|
- // reverb engine is not so scalable.
|
|
|
- SamplesOut[index][FRONT_LEFT] +=
|
|
|
- (State->Early.PanGain[FRONT_LEFT]*early[0] +
|
|
|
- State->Late.PanGain[FRONT_LEFT]*late[0]);
|
|
|
- SamplesOut[index][FRONT_RIGHT] +=
|
|
|
- (State->Early.PanGain[FRONT_RIGHT]*early[1] +
|
|
|
- State->Late.PanGain[FRONT_RIGHT]*late[1]);
|
|
|
- SamplesOut[index][FRONT_CENTER] +=
|
|
|
- (State->Early.PanGain[FRONT_CENTER]*early[3] +
|
|
|
- State->Late.PanGain[FRONT_CENTER]*late[3]);
|
|
|
- SamplesOut[index][SIDE_LEFT] +=
|
|
|
- (State->Early.PanGain[SIDE_LEFT]*early[0] +
|
|
|
- State->Late.PanGain[SIDE_LEFT]*late[0]);
|
|
|
- SamplesOut[index][SIDE_RIGHT] +=
|
|
|
- (State->Early.PanGain[SIDE_RIGHT]*early[1] +
|
|
|
- State->Late.PanGain[SIDE_RIGHT]*late[1]);
|
|
|
- SamplesOut[index][BACK_LEFT] +=
|
|
|
- (State->Early.PanGain[BACK_LEFT]*early[0] +
|
|
|
- State->Late.PanGain[BACK_LEFT]*late[0]);
|
|
|
- SamplesOut[index][BACK_RIGHT] +=
|
|
|
- (State->Early.PanGain[BACK_RIGHT]*early[1] +
|
|
|
- State->Late.PanGain[BACK_RIGHT]*late[1]);
|
|
|
- SamplesOut[index][BACK_CENTER] +=
|
|
|
- (State->Early.PanGain[BACK_CENTER]*early[2] +
|
|
|
- State->Late.PanGain[BACK_CENTER]*late[2]);
|
|
|
+ ALfloat earlyGain, lateGain;
|
|
|
+
|
|
|
+ earlyGain = State->Early.PanGain[c];
|
|
|
+ if(earlyGain > GAIN_SILENCE_THRESHOLD)
|
|
|
+ {
|
|
|
+ for(index = 0;index < SamplesToDo;index++)
|
|
|
+ SamplesOut[c][index] += earlyGain*early[index][c&3];
|
|
|
+ }
|
|
|
+ lateGain = State->Late.PanGain[c];
|
|
|
+ if(lateGain > GAIN_SILENCE_THRESHOLD)
|
|
|
+ {
|
|
|
+ for(index = 0;index < SamplesToDo;index++)
|
|
|
+ SamplesOut[c][index] += lateGain*late[index][c&3];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
|
|
|
+{
|
|
|
+ if(State->IsEax)
|
|
|
+ ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut);
|
|
|
+ else
|
|
|
+ ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut);
|
|
|
+}
|
|
|
|
|
|
// Given the allocated sample buffer, this function updates each delay line
|
|
|
// offset.
|
|
|
-static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay)
|
|
|
+static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
|
|
|
{
|
|
|
Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
|
|
|
}
|
|
|
@@ -646,7 +639,7 @@ static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequenc
|
|
|
* for all lines given the sample rate (frequency). If an allocation failure
|
|
|
* occurs, it returns AL_FALSE.
|
|
|
*/
|
|
|
-static ALboolean AllocLines(ALuint frequency, ALverbState *State)
|
|
|
+static ALboolean AllocLines(ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
ALuint totalSamples, index;
|
|
|
ALfloat length;
|
|
|
@@ -734,12 +727,8 @@ static ALboolean AllocLines(ALuint frequency, ALverbState *State)
|
|
|
return AL_TRUE;
|
|
|
}
|
|
|
|
|
|
-// This updates the device-dependant EAX reverb state. This is called on
|
|
|
-// initialization and any time the device parameters (eg. playback frequency,
|
|
|
-// format) have been changed.
|
|
|
-static ALboolean ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
|
|
|
+static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device)
|
|
|
{
|
|
|
- ALverbState *State = (ALverbState*)effect;
|
|
|
ALuint frequency = Device->Frequency, index;
|
|
|
|
|
|
// Allocate the delay lines.
|
|
|
@@ -750,8 +739,8 @@ static ALboolean ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
|
|
|
// is calculated given the current sample rate. This ensures that the
|
|
|
// resulting filter response over time is consistent across all sample
|
|
|
// rates.
|
|
|
- State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF,
|
|
|
- MODULATION_FILTER_CONST / frequency);
|
|
|
+ State->Mod.Coeff = powf(MODULATION_FILTER_COEFF,
|
|
|
+ MODULATION_FILTER_CONST / frequency);
|
|
|
|
|
|
// The early reflection and late all-pass filter line lengths are static,
|
|
|
// so their offsets only need to be calculated once.
|
|
|
@@ -772,28 +761,21 @@ static ALboolean ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
|
|
|
|
|
|
// Calculate a decay coefficient given the length of each cycle and the time
|
|
|
// until the decay reaches -60 dB.
|
|
|
-static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
|
|
|
+static inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
|
|
|
{
|
|
|
- return aluPow(0.001f/*-60 dB*/, length/decayTime);
|
|
|
+ return powf(0.001f/*-60 dB*/, length/decayTime);
|
|
|
}
|
|
|
|
|
|
// Calculate a decay length from a coefficient and the time until the decay
|
|
|
// reaches -60 dB.
|
|
|
-static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
|
|
|
-{
|
|
|
- return aluLog10(coeff) * decayTime / aluLog10(0.001f)/*-60 dB*/;
|
|
|
-}
|
|
|
-
|
|
|
-// Calculate the high frequency parameter for the I3DL2 coefficient
|
|
|
-// calculation.
|
|
|
-static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
|
|
|
+static inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
|
|
|
{
|
|
|
- return aluCos(F_PI*2.0f * hfRef / frequency);
|
|
|
+ return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/;
|
|
|
}
|
|
|
|
|
|
// Calculate an attenuation to be applied to the input of any echo models to
|
|
|
// compensate for modal density and decay time.
|
|
|
-static __inline ALfloat CalcDensityGain(ALfloat a)
|
|
|
+static inline ALfloat CalcDensityGain(ALfloat a)
|
|
|
{
|
|
|
/* The energy of a signal can be obtained by finding the area under the
|
|
|
* squared signal. This takes the form of Sum(x_n^2), where x is the
|
|
|
@@ -808,22 +790,22 @@ static __inline ALfloat CalcDensityGain(ALfloat a)
|
|
|
* calculated by inverting the square root of this approximation,
|
|
|
* yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
|
|
|
*/
|
|
|
- return aluSqrt(1.0f - (a * a));
|
|
|
+ return sqrtf(1.0f - (a * a));
|
|
|
}
|
|
|
|
|
|
// Calculate the mixing matrix coefficients given a diffusion factor.
|
|
|
-static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
|
|
|
+static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
|
|
|
{
|
|
|
ALfloat n, t;
|
|
|
|
|
|
// The matrix is of order 4, so n is sqrt (4 - 1).
|
|
|
- n = aluSqrt(3.0f);
|
|
|
- t = diffusion * aluAtan(n);
|
|
|
+ n = sqrtf(3.0f);
|
|
|
+ t = diffusion * atanf(n);
|
|
|
|
|
|
// Calculate the first mixing matrix coefficient.
|
|
|
- *x = aluCos(t);
|
|
|
+ *x = cosf(t);
|
|
|
// Calculate the second mixing matrix coefficient.
|
|
|
- *y = aluSin(t) / n;
|
|
|
+ *y = sinf(t) / n;
|
|
|
}
|
|
|
|
|
|
// Calculate the limited HF ratio for use with the late reverb low-pass
|
|
|
@@ -847,7 +829,7 @@ static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF,
|
|
|
|
|
|
// Calculate the coefficient for a HF (and eventually LF) decay damping
|
|
|
// filter.
|
|
|
-static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
|
|
|
+static inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
|
|
|
{
|
|
|
ALfloat coeff, g;
|
|
|
|
|
|
@@ -862,7 +844,14 @@ static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloa
|
|
|
|
|
|
// Damping is done with a 1-pole filter, so g needs to be squared.
|
|
|
g *= g;
|
|
|
- coeff = lpCoeffCalc(g, cw);
|
|
|
+ if(g < 0.9999f) /* 1-epsilon */
|
|
|
+ {
|
|
|
+ /* Be careful with gains < 0.001, as that causes the coefficient
|
|
|
+ * head towards 1, which will flatten the signal. */
|
|
|
+ g = maxf(g, 0.001f);
|
|
|
+ coeff = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) /
|
|
|
+ (1 - g);
|
|
|
+ }
|
|
|
|
|
|
// Very low decay times will produce minimal output, so apply an
|
|
|
// upper bound to the coefficient.
|
|
|
@@ -874,7 +863,7 @@ static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloa
|
|
|
// Update the EAX modulation index, range, and depth. Keep in mind that this
|
|
|
// kind of vibrato is additive and not multiplicative as one may expect. The
|
|
|
// downswing will sound stronger than the upswing.
|
|
|
-static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
|
|
|
+static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
ALuint range;
|
|
|
|
|
|
@@ -904,7 +893,7 @@ static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequenc
|
|
|
}
|
|
|
|
|
|
// Update the offsets for the initial effect delay line.
|
|
|
-static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
|
|
|
+static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
// Calculate the initial delay taps.
|
|
|
State->DelayTap[0] = fastf2u(earlyDelay * frequency);
|
|
|
@@ -912,7 +901,7 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint freq
|
|
|
}
|
|
|
|
|
|
// Update the early reflections gain and line coefficients.
|
|
|
-static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
|
|
|
+static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State)
|
|
|
{
|
|
|
ALuint index;
|
|
|
|
|
|
@@ -929,7 +918,7 @@ static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat la
|
|
|
}
|
|
|
|
|
|
// Update the offsets for the decorrelator line.
|
|
|
-static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
|
|
|
+static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
ALuint index;
|
|
|
ALfloat length;
|
|
|
@@ -943,14 +932,14 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState
|
|
|
*/
|
|
|
for(index = 0;index < 3;index++)
|
|
|
{
|
|
|
- length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
|
|
|
+ length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) *
|
|
|
LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
|
|
|
State->DecoTap[index] = fastf2u(length * frequency);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Update the late reverb gains, line lengths, and line coefficients.
|
|
|
-static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
|
|
|
+static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
ALfloat length;
|
|
|
ALuint index;
|
|
|
@@ -977,7 +966,7 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
|
|
|
decayTime));
|
|
|
|
|
|
// Calculate the all-pass feed-back and feed-forward coefficient.
|
|
|
- State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
|
|
|
+ State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f);
|
|
|
|
|
|
for(index = 0;index < 4;index++)
|
|
|
{
|
|
|
@@ -1008,7 +997,7 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
|
|
|
|
|
|
// Update the echo gain, line offset, line coefficients, and mixing
|
|
|
// coefficients.
|
|
|
-static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
|
|
|
+static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
|
|
|
{
|
|
|
// Update the offset and coefficient for the echo delay line.
|
|
|
State->Echo.Offset = fastf2u(echoTime * frequency);
|
|
|
@@ -1021,7 +1010,7 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT
|
|
|
State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
|
|
|
|
|
|
// Calculate the echo all-pass feed coefficient.
|
|
|
- State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
|
|
|
+ State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f);
|
|
|
|
|
|
// Calculate the echo all-pass attenuation coefficient.
|
|
|
State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
|
|
|
@@ -1040,30 +1029,26 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT
|
|
|
}
|
|
|
|
|
|
// Update the early and late 3D panning gains.
|
|
|
-static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State)
|
|
|
+static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State)
|
|
|
{
|
|
|
ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
|
|
|
ReflectionsPan[2] };
|
|
|
ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
|
|
|
LateReverbPan[2] };
|
|
|
- const ALfloat *speakerGain;
|
|
|
ALfloat ambientGain;
|
|
|
ALfloat dirGain;
|
|
|
ALfloat length;
|
|
|
- ALuint index;
|
|
|
- ALint pos;
|
|
|
|
|
|
Gain *= ReverbBoost;
|
|
|
|
|
|
- // Attenuate non-directional reverb according to the number of channels
|
|
|
- ambientGain = aluSqrt(2.0f/Device->NumChan);
|
|
|
+ /* Attenuate reverb according to its coverage (dirGain=0 will give
|
|
|
+ * Gain*ambientGain, and dirGain=1 will give Gain). */
|
|
|
+ ambientGain = minf(sqrtf(2.0f/Device->NumChan), 1.0f);
|
|
|
|
|
|
- // Calculate the 3D-panning gains for the early reflections and late
|
|
|
- // reverb.
|
|
|
length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
|
|
|
if(length > 1.0f)
|
|
|
{
|
|
|
- length = 1.0f / aluSqrt(length);
|
|
|
+ length = 1.0f / sqrtf(length);
|
|
|
earlyPan[0] *= length;
|
|
|
earlyPan[1] *= length;
|
|
|
earlyPan[2] *= length;
|
|
|
@@ -1071,248 +1056,727 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
|
|
|
length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
|
|
|
if(length > 1.0f)
|
|
|
{
|
|
|
- length = 1.0f / aluSqrt(length);
|
|
|
+ length = 1.0f / sqrtf(length);
|
|
|
latePan[0] *= length;
|
|
|
latePan[1] *= length;
|
|
|
latePan[2] *= length;
|
|
|
}
|
|
|
|
|
|
- /* This code applies directional reverb just like the mixer applies
|
|
|
- * directional sources. It diffuses the sound toward all speakers as the
|
|
|
- * magnitude of the panning vector drops, which is only a rough
|
|
|
- * approximation of the expansion of sound across the speakers from the
|
|
|
- * panning direction.
|
|
|
- */
|
|
|
- pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
|
|
|
- speakerGain = Device->PanningLUT[pos];
|
|
|
- dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
|
|
|
+ dirGain = sqrtf(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]);
|
|
|
+ ComputeAngleGains(Device, atan2f(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI,
|
|
|
+ lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain);
|
|
|
|
|
|
- for(index = 0;index < MAXCHANNELS;index++)
|
|
|
- State->Early.PanGain[index] = 0.0f;
|
|
|
- for(index = 0;index < Device->NumChan;index++)
|
|
|
- {
|
|
|
- enum Channel chan = Device->Speaker2Chan[index];
|
|
|
- State->Early.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- pos = aluCart2LUTpos(latePan[2], latePan[0]);
|
|
|
- speakerGain = Device->PanningLUT[pos];
|
|
|
- dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
|
|
|
-
|
|
|
- for(index = 0;index < MAXCHANNELS;index++)
|
|
|
- State->Late.PanGain[index] = 0.0f;
|
|
|
- for(index = 0;index < Device->NumChan;index++)
|
|
|
- {
|
|
|
- enum Channel chan = Device->Speaker2Chan[index];
|
|
|
- State->Late.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
|
|
|
- }
|
|
|
+ dirGain = sqrtf(latePan[0]*latePan[0] + latePan[2]*latePan[2]);
|
|
|
+ ComputeAngleGains(Device, atan2f(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI,
|
|
|
+ lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain);
|
|
|
}
|
|
|
|
|
|
-// This updates the EAX reverb state. This is called any time the EAX reverb
|
|
|
-// effect is loaded into a slot.
|
|
|
-static ALvoid ReverbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot)
|
|
|
+static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot)
|
|
|
{
|
|
|
- ALverbState *State = (ALverbState*)effect;
|
|
|
- ALuint frequency = Context->Device->Frequency;
|
|
|
- ALboolean isEAX = AL_FALSE;
|
|
|
- ALfloat cw, x, y, hfRatio;
|
|
|
+ ALuint frequency = Device->Frequency;
|
|
|
+ ALfloat lfscale, hfscale, hfRatio;
|
|
|
+ ALfloat cw, x, y;
|
|
|
+
|
|
|
+ if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
|
|
|
+ State->IsEax = AL_TRUE;
|
|
|
+ else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
|
|
|
+ State->IsEax = AL_FALSE;
|
|
|
|
|
|
- if(Slot->effect.type == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
|
|
|
+ // Calculate the master low-pass filter (from the master effect HF gain).
|
|
|
+ if(State->IsEax)
|
|
|
{
|
|
|
- State->state.Process = EAXVerbProcess;
|
|
|
- isEAX = AL_TRUE;
|
|
|
+ hfscale = Slot->EffectProps.Reverb.HFReference / frequency;
|
|
|
+ ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
|
|
|
+ Slot->EffectProps.Reverb.GainHF,
|
|
|
+ hfscale, 0.0f);
|
|
|
+ lfscale = Slot->EffectProps.Reverb.LFReference / frequency;
|
|
|
+ ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf,
|
|
|
+ Slot->EffectProps.Reverb.GainLF,
|
|
|
+ lfscale, 0.0f);
|
|
|
}
|
|
|
- else if(Slot->effect.type == AL_EFFECT_REVERB || EmulateEAXReverb)
|
|
|
+ else
|
|
|
{
|
|
|
- State->state.Process = VerbProcess;
|
|
|
- isEAX = AL_FALSE;
|
|
|
+ hfscale = (ALfloat)LOWPASSFREQREF / frequency;
|
|
|
+ ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
|
|
|
+ Slot->EffectProps.Reverb.GainHF,
|
|
|
+ hfscale, 0.0f);
|
|
|
}
|
|
|
|
|
|
- // Calculate the master low-pass filter (from the master effect HF gain).
|
|
|
- if(isEAX) cw = CalcI3DL2HFreq(Slot->effect.Reverb.HFReference, frequency);
|
|
|
- else cw = CalcI3DL2HFreq(LOWPASSFREQREF, frequency);
|
|
|
- // This is done with 2 chained 1-pole filters, so no need to square g.
|
|
|
- State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Reverb.GainHF, cw);
|
|
|
-
|
|
|
- if(isEAX)
|
|
|
+ if(State->IsEax)
|
|
|
{
|
|
|
// Update the modulator line.
|
|
|
- UpdateModulator(Slot->effect.Reverb.ModulationTime,
|
|
|
- Slot->effect.Reverb.ModulationDepth,
|
|
|
+ UpdateModulator(Slot->EffectProps.Reverb.ModulationTime,
|
|
|
+ Slot->EffectProps.Reverb.ModulationDepth,
|
|
|
frequency, State);
|
|
|
}
|
|
|
|
|
|
// Update the initial effect delay.
|
|
|
- UpdateDelayLine(Slot->effect.Reverb.ReflectionsDelay,
|
|
|
- Slot->effect.Reverb.LateReverbDelay,
|
|
|
+ UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay,
|
|
|
+ Slot->EffectProps.Reverb.LateReverbDelay,
|
|
|
frequency, State);
|
|
|
|
|
|
// Update the early lines.
|
|
|
- UpdateEarlyLines(Slot->effect.Reverb.Gain,
|
|
|
- Slot->effect.Reverb.ReflectionsGain,
|
|
|
- Slot->effect.Reverb.LateReverbDelay, State);
|
|
|
+ UpdateEarlyLines(Slot->EffectProps.Reverb.Gain,
|
|
|
+ Slot->EffectProps.Reverb.ReflectionsGain,
|
|
|
+ Slot->EffectProps.Reverb.LateReverbDelay, State);
|
|
|
|
|
|
// Update the decorrelator.
|
|
|
- UpdateDecorrelator(Slot->effect.Reverb.Density, frequency, State);
|
|
|
+ UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State);
|
|
|
|
|
|
// Get the mixing matrix coefficients (x and y).
|
|
|
- CalcMatrixCoeffs(Slot->effect.Reverb.Diffusion, &x, &y);
|
|
|
+ CalcMatrixCoeffs(Slot->EffectProps.Reverb.Diffusion, &x, &y);
|
|
|
// Then divide x into y to simplify the matrix calculation.
|
|
|
State->Late.MixCoeff = y / x;
|
|
|
|
|
|
// If the HF limit parameter is flagged, calculate an appropriate limit
|
|
|
// based on the air absorption parameter.
|
|
|
- hfRatio = Slot->effect.Reverb.DecayHFRatio;
|
|
|
- if(Slot->effect.Reverb.DecayHFLimit &&
|
|
|
- Slot->effect.Reverb.AirAbsorptionGainHF < 1.0f)
|
|
|
+ hfRatio = Slot->EffectProps.Reverb.DecayHFRatio;
|
|
|
+ if(Slot->EffectProps.Reverb.DecayHFLimit &&
|
|
|
+ Slot->EffectProps.Reverb.AirAbsorptionGainHF < 1.0f)
|
|
|
hfRatio = CalcLimitedHfRatio(hfRatio,
|
|
|
- Slot->effect.Reverb.AirAbsorptionGainHF,
|
|
|
- Slot->effect.Reverb.DecayTime);
|
|
|
+ Slot->EffectProps.Reverb.AirAbsorptionGainHF,
|
|
|
+ Slot->EffectProps.Reverb.DecayTime);
|
|
|
|
|
|
+ cw = cosf(F_2PI * hfscale);
|
|
|
// Update the late lines.
|
|
|
- UpdateLateLines(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain,
|
|
|
- x, Slot->effect.Reverb.Density, Slot->effect.Reverb.DecayTime,
|
|
|
- Slot->effect.Reverb.Diffusion, hfRatio, cw, frequency, State);
|
|
|
+ UpdateLateLines(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
|
|
|
+ x, Slot->EffectProps.Reverb.Density, Slot->EffectProps.Reverb.DecayTime,
|
|
|
+ Slot->EffectProps.Reverb.Diffusion, hfRatio, cw, frequency, State);
|
|
|
|
|
|
- if(isEAX)
|
|
|
+ if(State->IsEax)
|
|
|
{
|
|
|
// Update the echo line.
|
|
|
- UpdateEchoLine(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain,
|
|
|
- Slot->effect.Reverb.EchoTime, Slot->effect.Reverb.DecayTime,
|
|
|
- Slot->effect.Reverb.Diffusion, Slot->effect.Reverb.EchoDepth,
|
|
|
+ UpdateEchoLine(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
|
|
|
+ Slot->EffectProps.Reverb.EchoTime, Slot->EffectProps.Reverb.DecayTime,
|
|
|
+ Slot->EffectProps.Reverb.Diffusion, Slot->EffectProps.Reverb.EchoDepth,
|
|
|
hfRatio, cw, frequency, State);
|
|
|
|
|
|
// Update early and late 3D panning.
|
|
|
- Update3DPanning(Context->Device, Slot->effect.Reverb.ReflectionsPan,
|
|
|
- Slot->effect.Reverb.LateReverbPan, Slot->Gain, State);
|
|
|
+ Update3DPanning(Device, Slot->EffectProps.Reverb.ReflectionsPan,
|
|
|
+ Slot->EffectProps.Reverb.LateReverbPan, Slot->Gain, State);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- ALCdevice *Device = Context->Device;
|
|
|
- ALfloat gain = Slot->Gain;
|
|
|
- ALuint index;
|
|
|
-
|
|
|
/* Update channel gains */
|
|
|
- gain *= aluSqrt(2.0f/Device->NumChan) * ReverbBoost;
|
|
|
- for(index = 0;index < MAXCHANNELS;index++)
|
|
|
- State->Gain[index] = 0.0f;
|
|
|
- for(index = 0;index < Device->NumChan;index++)
|
|
|
- {
|
|
|
- enum Channel chan = Device->Speaker2Chan[index];
|
|
|
- State->Gain[chan] = gain;
|
|
|
- }
|
|
|
+ ALfloat gain = sqrtf(2.0f/Device->NumChan) * ReverbBoost * Slot->Gain;
|
|
|
+ SetGains(Device, gain, State->Gain);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// This destroys the reverb state. It should be called only when the effect
|
|
|
-// slot has a different (or no) effect loaded over the reverb effect.
|
|
|
-static ALvoid ReverbDestroy(ALeffectState *effect)
|
|
|
+
|
|
|
+static ALvoid ALreverbState_Destruct(ALreverbState *State)
|
|
|
{
|
|
|
- ALverbState *State = (ALverbState*)effect;
|
|
|
- if(State)
|
|
|
- {
|
|
|
- free(State->SampleBuffer);
|
|
|
- State->SampleBuffer = NULL;
|
|
|
- free(State);
|
|
|
- }
|
|
|
+ free(State->SampleBuffer);
|
|
|
+ State->SampleBuffer = NULL;
|
|
|
}
|
|
|
|
|
|
-// This creates the reverb state. It should be called only when the reverb
|
|
|
-// effect is loaded into a slot that doesn't already have a reverb effect.
|
|
|
-ALeffectState *ReverbCreate(void)
|
|
|
+static void ALreverbState_Delete(ALreverbState *state)
|
|
|
{
|
|
|
- ALverbState *State = NULL;
|
|
|
- ALuint index;
|
|
|
+ free(state);
|
|
|
+}
|
|
|
|
|
|
- State = malloc(sizeof(ALverbState));
|
|
|
- if(!State)
|
|
|
- return NULL;
|
|
|
+DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
|
|
|
|
|
|
- State->state.Destroy = ReverbDestroy;
|
|
|
- State->state.DeviceUpdate = ReverbDeviceUpdate;
|
|
|
- State->state.Update = ReverbUpdate;
|
|
|
- State->state.Process = VerbProcess;
|
|
|
|
|
|
- State->TotalSamples = 0;
|
|
|
- State->SampleBuffer = NULL;
|
|
|
+typedef struct ALreverbStateFactory {
|
|
|
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
|
|
|
+} ALreverbStateFactory;
|
|
|
+
|
|
|
+static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
|
|
|
+{
|
|
|
+ ALreverbState *state;
|
|
|
+ ALuint index;
|
|
|
|
|
|
- State->LpFilter.coeff = 0.0f;
|
|
|
- State->LpFilter.history[0] = 0.0f;
|
|
|
- State->LpFilter.history[1] = 0.0f;
|
|
|
+ state = malloc(sizeof(ALreverbState));
|
|
|
+ if(!state) return NULL;
|
|
|
+ SET_VTABLE2(ALreverbState, ALeffectState, state);
|
|
|
|
|
|
- State->Mod.Delay.Mask = 0;
|
|
|
- State->Mod.Delay.Line = NULL;
|
|
|
- State->Mod.Index = 0;
|
|
|
- State->Mod.Range = 1;
|
|
|
- State->Mod.Depth = 0.0f;
|
|
|
- State->Mod.Coeff = 0.0f;
|
|
|
- State->Mod.Filter = 0.0f;
|
|
|
+ state->TotalSamples = 0;
|
|
|
+ state->SampleBuffer = NULL;
|
|
|
|
|
|
- State->Delay.Mask = 0;
|
|
|
- State->Delay.Line = NULL;
|
|
|
- State->DelayTap[0] = 0;
|
|
|
- State->DelayTap[1] = 0;
|
|
|
+ ALfilterState_clear(&state->LpFilter);
|
|
|
+ ALfilterState_clear(&state->HpFilter);
|
|
|
|
|
|
- State->Early.Gain = 0.0f;
|
|
|
+ state->Mod.Delay.Mask = 0;
|
|
|
+ state->Mod.Delay.Line = NULL;
|
|
|
+ state->Mod.Index = 0;
|
|
|
+ state->Mod.Range = 1;
|
|
|
+ state->Mod.Depth = 0.0f;
|
|
|
+ state->Mod.Coeff = 0.0f;
|
|
|
+ state->Mod.Filter = 0.0f;
|
|
|
+
|
|
|
+ state->Delay.Mask = 0;
|
|
|
+ state->Delay.Line = NULL;
|
|
|
+ state->DelayTap[0] = 0;
|
|
|
+ state->DelayTap[1] = 0;
|
|
|
+
|
|
|
+ state->Early.Gain = 0.0f;
|
|
|
for(index = 0;index < 4;index++)
|
|
|
{
|
|
|
- State->Early.Coeff[index] = 0.0f;
|
|
|
- State->Early.Delay[index].Mask = 0;
|
|
|
- State->Early.Delay[index].Line = NULL;
|
|
|
- State->Early.Offset[index] = 0;
|
|
|
+ state->Early.Coeff[index] = 0.0f;
|
|
|
+ state->Early.Delay[index].Mask = 0;
|
|
|
+ state->Early.Delay[index].Line = NULL;
|
|
|
+ state->Early.Offset[index] = 0;
|
|
|
}
|
|
|
|
|
|
- State->Decorrelator.Mask = 0;
|
|
|
- State->Decorrelator.Line = NULL;
|
|
|
- State->DecoTap[0] = 0;
|
|
|
- State->DecoTap[1] = 0;
|
|
|
- State->DecoTap[2] = 0;
|
|
|
+ state->Decorrelator.Mask = 0;
|
|
|
+ state->Decorrelator.Line = NULL;
|
|
|
+ state->DecoTap[0] = 0;
|
|
|
+ state->DecoTap[1] = 0;
|
|
|
+ state->DecoTap[2] = 0;
|
|
|
|
|
|
- State->Late.Gain = 0.0f;
|
|
|
- State->Late.DensityGain = 0.0f;
|
|
|
- State->Late.ApFeedCoeff = 0.0f;
|
|
|
- State->Late.MixCoeff = 0.0f;
|
|
|
+ state->Late.Gain = 0.0f;
|
|
|
+ state->Late.DensityGain = 0.0f;
|
|
|
+ state->Late.ApFeedCoeff = 0.0f;
|
|
|
+ state->Late.MixCoeff = 0.0f;
|
|
|
for(index = 0;index < 4;index++)
|
|
|
{
|
|
|
- State->Late.ApCoeff[index] = 0.0f;
|
|
|
- State->Late.ApDelay[index].Mask = 0;
|
|
|
- State->Late.ApDelay[index].Line = NULL;
|
|
|
- State->Late.ApOffset[index] = 0;
|
|
|
-
|
|
|
- State->Late.Coeff[index] = 0.0f;
|
|
|
- State->Late.Delay[index].Mask = 0;
|
|
|
- State->Late.Delay[index].Line = NULL;
|
|
|
- State->Late.Offset[index] = 0;
|
|
|
-
|
|
|
- State->Late.LpCoeff[index] = 0.0f;
|
|
|
- State->Late.LpSample[index] = 0.0f;
|
|
|
+ state->Late.ApCoeff[index] = 0.0f;
|
|
|
+ state->Late.ApDelay[index].Mask = 0;
|
|
|
+ state->Late.ApDelay[index].Line = NULL;
|
|
|
+ state->Late.ApOffset[index] = 0;
|
|
|
+
|
|
|
+ state->Late.Coeff[index] = 0.0f;
|
|
|
+ state->Late.Delay[index].Mask = 0;
|
|
|
+ state->Late.Delay[index].Line = NULL;
|
|
|
+ state->Late.Offset[index] = 0;
|
|
|
+
|
|
|
+ state->Late.LpCoeff[index] = 0.0f;
|
|
|
+ state->Late.LpSample[index] = 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ for(index = 0;index < MaxChannels;index++)
|
|
|
+ {
|
|
|
+ state->Early.PanGain[index] = 0.0f;
|
|
|
+ state->Late.PanGain[index] = 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ state->Echo.DensityGain = 0.0f;
|
|
|
+ state->Echo.Delay.Mask = 0;
|
|
|
+ state->Echo.Delay.Line = NULL;
|
|
|
+ state->Echo.ApDelay.Mask = 0;
|
|
|
+ state->Echo.ApDelay.Line = NULL;
|
|
|
+ state->Echo.Coeff = 0.0f;
|
|
|
+ state->Echo.ApFeedCoeff = 0.0f;
|
|
|
+ state->Echo.ApCoeff = 0.0f;
|
|
|
+ state->Echo.Offset = 0;
|
|
|
+ state->Echo.ApOffset = 0;
|
|
|
+ state->Echo.LpCoeff = 0.0f;
|
|
|
+ state->Echo.LpSample = 0.0f;
|
|
|
+ state->Echo.MixCoeff[0] = 0.0f;
|
|
|
+ state->Echo.MixCoeff[1] = 0.0f;
|
|
|
+
|
|
|
+ state->Offset = 0;
|
|
|
+
|
|
|
+ state->Gain = state->Late.PanGain;
|
|
|
+
|
|
|
+ return STATIC_CAST(ALeffectState, state);
|
|
|
+}
|
|
|
+
|
|
|
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory);
|
|
|
+
|
|
|
+ALeffectStateFactory *ALreverbStateFactory_getFactory(void)
|
|
|
+{
|
|
|
+ static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } };
|
|
|
+
|
|
|
+ return STATIC_CAST(ALeffectStateFactory, &ReverbFactory);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
|
|
+{
|
|
|
+ ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_EAXREVERB_DECAY_HFLIMIT:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayHFLimit = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
+}
|
|
|
+void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
|
|
+{
|
|
|
+ ALeaxreverb_setParami(effect, context, param, vals[0]);
|
|
|
+}
|
|
|
+void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
|
|
+{
|
|
|
+ ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_EAXREVERB_DENSITY:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Density = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DIFFUSION:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Diffusion = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAIN:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Gain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAINHF:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.GainHF = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAINLF:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.GainLF = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_TIME:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayTime = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_HFRATIO:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayHFRatio = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_LFRATIO:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayLFRatio = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ReflectionsGain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ReflectionsDelay = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.LateReverbGain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.LateReverbDelay = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.AirAbsorptionGainHF = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ECHO_TIME:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.EchoTime = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ECHO_DEPTH:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.EchoDepth = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_MODULATION_TIME:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ModulationTime = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_MODULATION_DEPTH:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ModulationDepth = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_HFREFERENCE:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.HFReference = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LFREFERENCE:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.LFReference = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
|
|
|
+ if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.RoomRolloffFactor = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
}
|
|
|
+}
|
|
|
+void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
|
|
+{
|
|
|
+ ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_PAN:
|
|
|
+ if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ LockContext(context);
|
|
|
+ props->Reverb.ReflectionsPan[0] = vals[0];
|
|
|
+ props->Reverb.ReflectionsPan[1] = vals[1];
|
|
|
+ props->Reverb.ReflectionsPan[2] = vals[2];
|
|
|
+ UnlockContext(context);
|
|
|
+ break;
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_PAN:
|
|
|
+ if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ LockContext(context);
|
|
|
+ props->Reverb.LateReverbPan[0] = vals[0];
|
|
|
+ props->Reverb.LateReverbPan[1] = vals[1];
|
|
|
+ props->Reverb.LateReverbPan[2] = vals[2];
|
|
|
+ UnlockContext(context);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ ALeaxreverb_setParamf(effect, context, param, vals[0]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- for(index = 0;index < MAXCHANNELS;index++)
|
|
|
+void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
|
|
+{
|
|
|
+ const ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
{
|
|
|
- State->Early.PanGain[index] = 0.0f;
|
|
|
- State->Late.PanGain[index] = 0.0f;
|
|
|
+ case AL_EAXREVERB_DECAY_HFLIMIT:
|
|
|
+ *val = props->Reverb.DecayHFLimit;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
}
|
|
|
+}
|
|
|
+void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
|
|
+{
|
|
|
+ ALeaxreverb_getParami(effect, context, param, vals);
|
|
|
+}
|
|
|
+void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
|
|
+{
|
|
|
+ const ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_EAXREVERB_DENSITY:
|
|
|
+ *val = props->Reverb.Density;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DIFFUSION:
|
|
|
+ *val = props->Reverb.Diffusion;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAIN:
|
|
|
+ *val = props->Reverb.Gain;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAINHF:
|
|
|
+ *val = props->Reverb.GainHF;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_GAINLF:
|
|
|
+ *val = props->Reverb.GainLF;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_TIME:
|
|
|
+ *val = props->Reverb.DecayTime;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_HFRATIO:
|
|
|
+ *val = props->Reverb.DecayHFRatio;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_DECAY_LFRATIO:
|
|
|
+ *val = props->Reverb.DecayLFRatio;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
|
|
|
+ *val = props->Reverb.ReflectionsGain;
|
|
|
+ break;
|
|
|
|
|
|
- State->Echo.DensityGain = 0.0f;
|
|
|
- State->Echo.Delay.Mask = 0;
|
|
|
- State->Echo.Delay.Line = NULL;
|
|
|
- State->Echo.ApDelay.Mask = 0;
|
|
|
- State->Echo.ApDelay.Line = NULL;
|
|
|
- State->Echo.Coeff = 0.0f;
|
|
|
- State->Echo.ApFeedCoeff = 0.0f;
|
|
|
- State->Echo.ApCoeff = 0.0f;
|
|
|
- State->Echo.Offset = 0;
|
|
|
- State->Echo.ApOffset = 0;
|
|
|
- State->Echo.LpCoeff = 0.0f;
|
|
|
- State->Echo.LpSample = 0.0f;
|
|
|
- State->Echo.MixCoeff[0] = 0.0f;
|
|
|
- State->Echo.MixCoeff[1] = 0.0f;
|
|
|
-
|
|
|
- State->Offset = 0;
|
|
|
-
|
|
|
- State->Gain = State->Late.PanGain;
|
|
|
-
|
|
|
- return &State->state;
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
|
|
|
+ *val = props->Reverb.ReflectionsDelay;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
|
|
|
+ *val = props->Reverb.LateReverbGain;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
|
|
|
+ *val = props->Reverb.LateReverbDelay;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
|
|
|
+ *val = props->Reverb.AirAbsorptionGainHF;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ECHO_TIME:
|
|
|
+ *val = props->Reverb.EchoTime;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ECHO_DEPTH:
|
|
|
+ *val = props->Reverb.EchoDepth;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_MODULATION_TIME:
|
|
|
+ *val = props->Reverb.ModulationTime;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_MODULATION_DEPTH:
|
|
|
+ *val = props->Reverb.ModulationDepth;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_HFREFERENCE:
|
|
|
+ *val = props->Reverb.HFReference;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_LFREFERENCE:
|
|
|
+ *val = props->Reverb.LFReference;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
|
|
|
+ *val = props->Reverb.RoomRolloffFactor;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
}
|
|
|
+void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
|
|
+{
|
|
|
+ const ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_EAXREVERB_REFLECTIONS_PAN:
|
|
|
+ LockContext(context);
|
|
|
+ vals[0] = props->Reverb.ReflectionsPan[0];
|
|
|
+ vals[1] = props->Reverb.ReflectionsPan[1];
|
|
|
+ vals[2] = props->Reverb.ReflectionsPan[2];
|
|
|
+ UnlockContext(context);
|
|
|
+ break;
|
|
|
+ case AL_EAXREVERB_LATE_REVERB_PAN:
|
|
|
+ LockContext(context);
|
|
|
+ vals[0] = props->Reverb.LateReverbPan[0];
|
|
|
+ vals[1] = props->Reverb.LateReverbPan[1];
|
|
|
+ vals[2] = props->Reverb.LateReverbPan[2];
|
|
|
+ UnlockContext(context);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ ALeaxreverb_getParamf(effect, context, param, vals);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+DEFINE_ALEFFECT_VTABLE(ALeaxreverb);
|
|
|
+
|
|
|
+void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
|
|
+{
|
|
|
+ ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_REVERB_DECAY_HFLIMIT:
|
|
|
+ if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayHFLimit = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
+}
|
|
|
+void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
|
|
+{
|
|
|
+ ALreverb_setParami(effect, context, param, vals[0]);
|
|
|
+}
|
|
|
+void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
|
|
+{
|
|
|
+ ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_REVERB_DENSITY:
|
|
|
+ if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Density = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DIFFUSION:
|
|
|
+ if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Diffusion = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_GAIN:
|
|
|
+ if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.Gain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_GAINHF:
|
|
|
+ if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.GainHF = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DECAY_TIME:
|
|
|
+ if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayTime = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DECAY_HFRATIO:
|
|
|
+ if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.DecayHFRatio = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_REFLECTIONS_GAIN:
|
|
|
+ if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ReflectionsGain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_REFLECTIONS_DELAY:
|
|
|
+ if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.ReflectionsDelay = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_LATE_REVERB_GAIN:
|
|
|
+ if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.LateReverbGain = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_LATE_REVERB_DELAY:
|
|
|
+ if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.LateReverbDelay = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
|
|
|
+ if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.AirAbsorptionGainHF = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
|
|
|
+ if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
|
|
+ props->Reverb.RoomRolloffFactor = val;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
+}
|
|
|
+void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
|
|
+{
|
|
|
+ ALreverb_setParamf(effect, context, param, vals[0]);
|
|
|
+}
|
|
|
+
|
|
|
+void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
|
|
+{
|
|
|
+ const ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_REVERB_DECAY_HFLIMIT:
|
|
|
+ *val = props->Reverb.DecayHFLimit;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
+}
|
|
|
+void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
|
|
+{
|
|
|
+ ALreverb_getParami(effect, context, param, vals);
|
|
|
+}
|
|
|
+void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
|
|
+{
|
|
|
+ const ALeffectProps *props = &effect->Props;
|
|
|
+ switch(param)
|
|
|
+ {
|
|
|
+ case AL_REVERB_DENSITY:
|
|
|
+ *val = props->Reverb.Density;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DIFFUSION:
|
|
|
+ *val = props->Reverb.Diffusion;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_GAIN:
|
|
|
+ *val = props->Reverb.Gain;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_GAINHF:
|
|
|
+ *val = props->Reverb.GainHF;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DECAY_TIME:
|
|
|
+ *val = props->Reverb.DecayTime;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_DECAY_HFRATIO:
|
|
|
+ *val = props->Reverb.DecayHFRatio;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_REFLECTIONS_GAIN:
|
|
|
+ *val = props->Reverb.ReflectionsGain;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_REFLECTIONS_DELAY:
|
|
|
+ *val = props->Reverb.ReflectionsDelay;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_LATE_REVERB_GAIN:
|
|
|
+ *val = props->Reverb.LateReverbGain;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_LATE_REVERB_DELAY:
|
|
|
+ *val = props->Reverb.LateReverbDelay;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
|
|
|
+ *val = props->Reverb.AirAbsorptionGainHF;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
|
|
|
+ *val = props->Reverb.RoomRolloffFactor;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
|
|
+ }
|
|
|
+}
|
|
|
+void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
|
|
+{
|
|
|
+ ALreverb_getParamf(effect, context, param, vals);
|
|
|
+}
|
|
|
+
|
|
|
+DEFINE_ALEFFECT_VTABLE(ALreverb);
|