mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 00:54:54 +00:00
OpenAL-soft for windows
This commit is contained in:
parent
e2f2c4932b
commit
3a0a720115
207 changed files with 53310 additions and 13291 deletions
412
Engine/lib/openal-soft/Alc/effects/chorus.c
Normal file
412
Engine/lib/openal-soft/Alc/effects/chorus.c
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2013 by Mike Gorchak
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
enum ChorusWaveForm {
|
||||
CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
|
||||
CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
|
||||
};
|
||||
|
||||
typedef struct ALchorusState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
ALfloat *SampleBuffer[2];
|
||||
ALuint BufferLength;
|
||||
ALuint offset;
|
||||
ALuint lfo_range;
|
||||
ALfloat lfo_scale;
|
||||
ALint lfo_disp;
|
||||
|
||||
/* Gains for left and right sides */
|
||||
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
/* effect parameters */
|
||||
enum ChorusWaveForm waveform;
|
||||
ALint delay;
|
||||
ALfloat depth;
|
||||
ALfloat feedback;
|
||||
} ALchorusState;
|
||||
|
||||
static ALvoid ALchorusState_Destruct(ALchorusState *state);
|
||||
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
|
||||
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
|
||||
|
||||
|
||||
static void ALchorusState_Construct(ALchorusState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALchorusState, ALeffectState, state);
|
||||
|
||||
state->BufferLength = 0;
|
||||
state->SampleBuffer[0] = NULL;
|
||||
state->SampleBuffer[1] = NULL;
|
||||
state->offset = 0;
|
||||
state->lfo_range = 1;
|
||||
state->waveform = CWF_Triangle;
|
||||
}
|
||||
|
||||
static ALvoid ALchorusState_Destruct(ALchorusState *state)
|
||||
{
|
||||
al_free(state->SampleBuffer[0]);
|
||||
state->SampleBuffer[0] = NULL;
|
||||
state->SampleBuffer[1] = NULL;
|
||||
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
|
||||
{
|
||||
ALuint maxlen;
|
||||
ALuint it;
|
||||
|
||||
maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1;
|
||||
maxlen = NextPowerOf2(maxlen);
|
||||
|
||||
if(maxlen != state->BufferLength)
|
||||
{
|
||||
void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
|
||||
if(!temp) return AL_FALSE;
|
||||
|
||||
al_free(state->SampleBuffer[0]);
|
||||
state->SampleBuffer[0] = temp;
|
||||
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
|
||||
|
||||
state->BufferLength = maxlen;
|
||||
}
|
||||
|
||||
for(it = 0;it < state->BufferLength;it++)
|
||||
{
|
||||
state->SampleBuffer[0][it] = 0.0f;
|
||||
state->SampleBuffer[1][it] = 0.0f;
|
||||
}
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat frequency = (ALfloat)Device->Frequency;
|
||||
ALfloat coeffs[MAX_AMBI_COEFFS];
|
||||
ALfloat rate;
|
||||
ALint phase;
|
||||
|
||||
switch(props->Chorus.Waveform)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM_TRIANGLE:
|
||||
state->waveform = CWF_Triangle;
|
||||
break;
|
||||
case AL_CHORUS_WAVEFORM_SINUSOID:
|
||||
state->waveform = CWF_Sinusoid;
|
||||
break;
|
||||
}
|
||||
state->depth = props->Chorus.Depth;
|
||||
state->feedback = props->Chorus.Feedback;
|
||||
state->delay = fastf2i(props->Chorus.Delay * frequency);
|
||||
|
||||
/* Gains for left and right sides */
|
||||
CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
|
||||
CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
|
||||
|
||||
phase = props->Chorus.Phase;
|
||||
rate = props->Chorus.Rate;
|
||||
if(!(rate > 0.0f))
|
||||
{
|
||||
state->lfo_scale = 0.0f;
|
||||
state->lfo_range = 1;
|
||||
state->lfo_disp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate LFO coefficient */
|
||||
state->lfo_range = fastf2u(frequency/rate + 0.5f);
|
||||
switch(state->waveform)
|
||||
{
|
||||
case CWF_Triangle:
|
||||
state->lfo_scale = 4.0f / state->lfo_range;
|
||||
break;
|
||||
case CWF_Sinusoid:
|
||||
state->lfo_scale = F_TAU / state->lfo_range;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate lfo phase displacement */
|
||||
state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
|
||||
{
|
||||
ALfloat lfo_value;
|
||||
|
||||
lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_left = fastf2i(lfo_value) + state->delay;
|
||||
|
||||
offset += state->lfo_disp;
|
||||
lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_right = fastf2i(lfo_value) + state->delay;
|
||||
}
|
||||
|
||||
static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
|
||||
{
|
||||
ALfloat lfo_value;
|
||||
|
||||
lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_left = fastf2i(lfo_value) + state->delay;
|
||||
|
||||
offset += state->lfo_disp;
|
||||
lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_right = fastf2i(lfo_value) + state->delay;
|
||||
}
|
||||
|
||||
#define DECL_TEMPLATE(Func) \
|
||||
static void Process##Func(ALchorusState *state, const ALuint SamplesToDo, \
|
||||
const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
|
||||
{ \
|
||||
const ALuint bufmask = state->BufferLength-1; \
|
||||
ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
|
||||
ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
|
||||
ALuint offset = state->offset; \
|
||||
const ALfloat feedback = state->feedback; \
|
||||
ALuint it; \
|
||||
\
|
||||
for(it = 0;it < SamplesToDo;it++) \
|
||||
{ \
|
||||
ALint delay_left, delay_right; \
|
||||
Func(&delay_left, &delay_right, offset, state); \
|
||||
\
|
||||
out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
|
||||
leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
|
||||
\
|
||||
out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
|
||||
rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
|
||||
\
|
||||
offset++; \
|
||||
} \
|
||||
state->offset = offset; \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(Triangle)
|
||||
DECL_TEMPLATE(Sinusoid)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
ALuint it, kt;
|
||||
ALuint base;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALfloat temps[128][2];
|
||||
ALuint td = minu(128, SamplesToDo-base);
|
||||
|
||||
switch(state->waveform)
|
||||
{
|
||||
case CWF_Triangle:
|
||||
ProcessTriangle(state, td, SamplesIn[0]+base, temps);
|
||||
break;
|
||||
case CWF_Sinusoid:
|
||||
ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
|
||||
break;
|
||||
}
|
||||
|
||||
for(kt = 0;kt < NumChannels;kt++)
|
||||
{
|
||||
ALfloat gain = state->Gain[0][kt];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][it+base] += temps[it][0] * gain;
|
||||
}
|
||||
|
||||
gain = state->Gain[1][kt];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][it+base] += temps[it][1] * gain;
|
||||
}
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALchorusStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALchorusStateFactory;
|
||||
|
||||
static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALchorusState *state;
|
||||
|
||||
NEW_OBJ0(state, ALchorusState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory);
|
||||
|
||||
|
||||
ALeffectStateFactory *ALchorusStateFactory_getFactory(void)
|
||||
{
|
||||
static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &ChorusFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM:
|
||||
if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Waveform = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_PHASE:
|
||||
if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Phase = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALchorus_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_RATE:
|
||||
if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Rate = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DEPTH:
|
||||
if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Depth = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_FEEDBACK:
|
||||
if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DELAY:
|
||||
if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Chorus.Delay = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALchorus_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM:
|
||||
*val = props->Chorus.Waveform;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_PHASE:
|
||||
*val = props->Chorus.Phase;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALchorus_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_RATE:
|
||||
*val = props->Chorus.Rate;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DEPTH:
|
||||
*val = props->Chorus.Depth;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_FEEDBACK:
|
||||
*val = props->Chorus.Feedback;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DELAY:
|
||||
*val = props->Chorus.Delay;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALchorus_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALchorus);
|
||||
254
Engine/lib/openal-soft/Alc/effects/compressor.c
Normal file
254
Engine/lib/openal-soft/Alc/effects/compressor.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2013 by Anis A. Hireche
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "alError.h"
|
||||
#include "alMain.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
typedef struct ALcompressorState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
/* Effect gains for each channel */
|
||||
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
/* Effect parameters */
|
||||
ALboolean Enabled;
|
||||
ALfloat AttackRate;
|
||||
ALfloat ReleaseRate;
|
||||
ALfloat GainCtrl;
|
||||
} ALcompressorState;
|
||||
|
||||
static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
|
||||
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
|
||||
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
|
||||
static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
|
||||
|
||||
|
||||
static void ALcompressorState_Construct(ALcompressorState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALcompressorState, ALeffectState, state);
|
||||
|
||||
state->Enabled = AL_TRUE;
|
||||
state->AttackRate = 0.0f;
|
||||
state->ReleaseRate = 0.0f;
|
||||
state->GainCtrl = 1.0f;
|
||||
}
|
||||
|
||||
static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
|
||||
{
|
||||
const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
|
||||
const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
|
||||
|
||||
state->AttackRate = 1.0f / attackTime;
|
||||
state->ReleaseRate = 1.0f / releaseTime;
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
|
||||
{
|
||||
ALuint i;
|
||||
|
||||
state->Enabled = props->Compressor.OnOff;
|
||||
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
|
||||
for(i = 0;i < 4;i++)
|
||||
ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
|
||||
slot->Params.Gain, state->Gain[i]);
|
||||
}
|
||||
|
||||
static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
ALuint i, j, k;
|
||||
ALuint base;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALfloat temps[64][4];
|
||||
ALuint td = minu(64, SamplesToDo-base);
|
||||
|
||||
/* Load samples into the temp buffer first. */
|
||||
for(j = 0;j < 4;j++)
|
||||
{
|
||||
for(i = 0;i < td;i++)
|
||||
temps[i][j] = SamplesIn[j][i+base];
|
||||
}
|
||||
|
||||
if(state->Enabled)
|
||||
{
|
||||
ALfloat gain = state->GainCtrl;
|
||||
ALfloat output, amplitude;
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
{
|
||||
/* Roughly calculate the maximum amplitude from the 4-channel
|
||||
* signal, and attack or release the gain control to reach it.
|
||||
*/
|
||||
amplitude = fabsf(temps[i][0]);
|
||||
amplitude = maxf(amplitude + fabsf(temps[i][1]),
|
||||
maxf(amplitude + fabsf(temps[i][2]),
|
||||
amplitude + fabsf(temps[i][3])));
|
||||
if(amplitude > gain)
|
||||
gain = minf(gain+state->AttackRate, amplitude);
|
||||
else if(amplitude < gain)
|
||||
gain = maxf(gain-state->ReleaseRate, amplitude);
|
||||
|
||||
/* Apply the inverse of the gain control to normalize/compress
|
||||
* the volume. */
|
||||
output = 1.0f / clampf(gain, 0.5f, 2.0f);
|
||||
for(j = 0;j < 4;j++)
|
||||
temps[i][j] *= output;
|
||||
}
|
||||
|
||||
state->GainCtrl = gain;
|
||||
}
|
||||
else
|
||||
{
|
||||
ALfloat gain = state->GainCtrl;
|
||||
ALfloat output, amplitude;
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
{
|
||||
/* Same as above, except the amplitude is forced to 1. This
|
||||
* helps ensure smooth gain changes when the compressor is
|
||||
* turned on and off.
|
||||
*/
|
||||
amplitude = 1.0f;
|
||||
if(amplitude > gain)
|
||||
gain = minf(gain+state->AttackRate, amplitude);
|
||||
else if(amplitude < gain)
|
||||
gain = maxf(gain-state->ReleaseRate, amplitude);
|
||||
|
||||
output = 1.0f / clampf(gain, 0.5f, 2.0f);
|
||||
for(j = 0;j < 4;j++)
|
||||
temps[i][j] *= output;
|
||||
}
|
||||
|
||||
state->GainCtrl = gain;
|
||||
}
|
||||
|
||||
/* Now mix to the output. */
|
||||
for(j = 0;j < 4;j++)
|
||||
{
|
||||
for(k = 0;k < NumChannels;k++)
|
||||
{
|
||||
ALfloat gain = state->Gain[j][k];
|
||||
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
|
||||
continue;
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
SamplesOut[k][base+i] += gain * temps[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALcompressorStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALcompressorStateFactory;
|
||||
|
||||
static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALcompressorState *state;
|
||||
|
||||
NEW_OBJ0(state, ALcompressorState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
|
||||
{
|
||||
static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_COMPRESSOR_ONOFF:
|
||||
if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Compressor.OnOff = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALcompressor_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALcompressor_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_COMPRESSOR_ONOFF:
|
||||
*val = props->Compressor.OnOff;
|
||||
break;
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALcompressor_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALcompressor_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALcompressor);
|
||||
201
Engine/lib/openal-soft/Alc/effects/dedicated.c
Normal file
201
Engine/lib/openal-soft/Alc/effects/dedicated.c
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2011 by Chris Robinson.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
typedef struct ALdedicatedState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
ALfloat gains[MAX_OUTPUT_CHANNELS];
|
||||
} ALdedicatedState;
|
||||
|
||||
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state);
|
||||
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device);
|
||||
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
|
||||
|
||||
|
||||
static void ALdedicatedState_Construct(ALdedicatedState *state)
|
||||
{
|
||||
ALsizei s;
|
||||
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
|
||||
|
||||
for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
|
||||
state->gains[s] = 0.0f;
|
||||
}
|
||||
|
||||
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
|
||||
{
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat Gain;
|
||||
ALuint i;
|
||||
|
||||
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
||||
state->gains[i] = 0.0f;
|
||||
|
||||
Gain = Slot->Params.Gain * props->Dedicated.Gain;
|
||||
if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
|
||||
{
|
||||
int idx;
|
||||
if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1)
|
||||
{
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
|
||||
state->gains[idx] = Gain;
|
||||
}
|
||||
}
|
||||
else if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
|
||||
{
|
||||
int idx;
|
||||
/* Dialog goes to the front-center speaker if it exists, otherwise it
|
||||
* plays from the front-center location. */
|
||||
if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1)
|
||||
{
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
|
||||
state->gains[idx] = Gain;
|
||||
}
|
||||
else
|
||||
{
|
||||
ALfloat coeffs[MAX_AMBI_COEFFS];
|
||||
CalcXYZCoeffs(0.0f, 0.0f, -1.0f, 0.0f, coeffs);
|
||||
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels;
|
||||
ComputePanningGains(device->Dry, coeffs, Gain, state->gains);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
const ALfloat *gains = state->gains;
|
||||
ALuint i, c;
|
||||
|
||||
for(c = 0;c < NumChannels;c++)
|
||||
{
|
||||
if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD))
|
||||
continue;
|
||||
|
||||
for(i = 0;i < SamplesToDo;i++)
|
||||
SamplesOut[c][i] += SamplesIn[0][i] * gains[c];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALdedicatedStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALdedicatedStateFactory;
|
||||
|
||||
ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALdedicatedState *state;
|
||||
|
||||
NEW_OBJ0(state, ALdedicatedState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory);
|
||||
|
||||
|
||||
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void)
|
||||
{
|
||||
static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALdedicated_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN:
|
||||
if(!(val >= 0.0f && isfinite(val)))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Dedicated.Gain = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALdedicated_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALdedicated_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN:
|
||||
*val = props->Dedicated.Gain;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALdedicated_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALdedicated);
|
||||
298
Engine/lib/openal-soft/Alc/effects/distortion.c
Normal file
298
Engine/lib/openal-soft/Alc/effects/distortion.c
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2013 by Mike Gorchak
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
typedef struct ALdistortionState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
/* Effect gains for each channel */
|
||||
ALfloat Gain[MAX_OUTPUT_CHANNELS];
|
||||
|
||||
/* Effect parameters */
|
||||
ALfilterState lowpass;
|
||||
ALfilterState bandpass;
|
||||
ALfloat attenuation;
|
||||
ALfloat edge_coeff;
|
||||
} ALdistortionState;
|
||||
|
||||
static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
|
||||
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
|
||||
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
|
||||
|
||||
|
||||
static void ALdistortionState_Construct(ALdistortionState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALdistortionState, ALeffectState, state);
|
||||
|
||||
ALfilterState_clear(&state->lowpass);
|
||||
ALfilterState_clear(&state->bandpass);
|
||||
}
|
||||
|
||||
static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
|
||||
{
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat frequency = (ALfloat)Device->Frequency;
|
||||
ALfloat bandwidth;
|
||||
ALfloat cutoff;
|
||||
ALfloat edge;
|
||||
|
||||
/* Store distorted signal attenuation settings */
|
||||
state->attenuation = props->Distortion.Gain;
|
||||
|
||||
/* Store waveshaper edge settings */
|
||||
edge = sinf(props->Distortion.Edge * (F_PI_2));
|
||||
edge = minf(edge, 0.99f);
|
||||
state->edge_coeff = 2.0f * edge / (1.0f-edge);
|
||||
|
||||
/* Lowpass filter */
|
||||
cutoff = props->Distortion.LowpassCutoff;
|
||||
/* Bandwidth value is constant in octaves */
|
||||
bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
|
||||
ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
|
||||
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
|
||||
);
|
||||
|
||||
/* Bandpass filter */
|
||||
cutoff = props->Distortion.EQCenter;
|
||||
/* Convert bandwidth in Hz to octaves */
|
||||
bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
|
||||
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
|
||||
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
|
||||
);
|
||||
|
||||
ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain);
|
||||
}
|
||||
|
||||
static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
const ALfloat fc = state->edge_coeff;
|
||||
ALuint base;
|
||||
ALuint it;
|
||||
ALuint ot;
|
||||
ALuint kt;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
float buffer[2][64 * 4];
|
||||
ALuint td = minu(64, SamplesToDo-base);
|
||||
|
||||
/* Perform 4x oversampling to avoid aliasing. */
|
||||
/* Oversampling greatly improves distortion */
|
||||
/* quality and allows to implement lowpass and */
|
||||
/* bandpass filters using high frequencies, at */
|
||||
/* which classic IIR filters became unstable. */
|
||||
|
||||
/* Fill oversample buffer using zero stuffing */
|
||||
for(it = 0;it < td;it++)
|
||||
{
|
||||
buffer[0][it*4 + 0] = SamplesIn[0][it+base];
|
||||
buffer[0][it*4 + 1] = 0.0f;
|
||||
buffer[0][it*4 + 2] = 0.0f;
|
||||
buffer[0][it*4 + 3] = 0.0f;
|
||||
}
|
||||
|
||||
/* First step, do lowpass filtering of original signal, */
|
||||
/* additionally perform buffer interpolation and lowpass */
|
||||
/* cutoff for oversampling (which is fortunately first */
|
||||
/* step of distortion). So combine three operations into */
|
||||
/* the one. */
|
||||
ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4);
|
||||
|
||||
/* Second step, do distortion using waveshaper function */
|
||||
/* to emulate signal processing during tube overdriving. */
|
||||
/* Three steps of waveshaping are intended to modify */
|
||||
/* waveform without boost/clipping/attenuation process. */
|
||||
for(it = 0;it < td;it++)
|
||||
{
|
||||
for(ot = 0;ot < 4;ot++)
|
||||
{
|
||||
/* Restore signal power by multiplying sample by amount of oversampling */
|
||||
ALfloat smp = buffer[1][it*4 + ot] * 4.0f;
|
||||
|
||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
|
||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
|
||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
|
||||
|
||||
buffer[1][it*4 + ot] = smp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Third step, do bandpass filtering of distorted signal */
|
||||
ALfilterState_process(&state->bandpass, buffer[0], buffer[1], td*4);
|
||||
|
||||
for(kt = 0;kt < NumChannels;kt++)
|
||||
{
|
||||
/* Fourth step, final, do attenuation and perform decimation,
|
||||
* store only one sample out of 4.
|
||||
*/
|
||||
ALfloat gain = state->Gain[kt] * state->attenuation;
|
||||
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
|
||||
continue;
|
||||
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][base+it] += gain * buffer[0][it*4];
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALdistortionStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALdistortionStateFactory;
|
||||
|
||||
static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALdistortionState *state;
|
||||
|
||||
NEW_OBJ0(state, ALdistortionState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
|
||||
|
||||
|
||||
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
|
||||
{
|
||||
static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALdistortion_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_DISTORTION_EDGE:
|
||||
if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Distortion.Edge = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_GAIN:
|
||||
if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Distortion.Gain = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_LOWPASS_CUTOFF:
|
||||
if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Distortion.LowpassCutoff = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQCENTER:
|
||||
if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Distortion.EQCenter = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQBANDWIDTH:
|
||||
if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Distortion.EQBandwidth = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALdistortion_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALdistortion_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_DISTORTION_EDGE:
|
||||
*val = props->Distortion.Edge;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_GAIN:
|
||||
*val = props->Distortion.Gain;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_LOWPASS_CUTOFF:
|
||||
*val = props->Distortion.LowpassCutoff;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQCENTER:
|
||||
*val = props->Distortion.EQCenter;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQBANDWIDTH:
|
||||
*val = props->Distortion.EQBandwidth;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALdistortion_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALdistortion);
|
||||
326
Engine/lib/openal-soft/Alc/effects/echo.c
Normal file
326
Engine/lib/openal-soft/Alc/effects/echo.c
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2009 by Chris Robinson.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
typedef struct ALechoState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
ALfloat *SampleBuffer;
|
||||
ALuint BufferLength;
|
||||
|
||||
// The echo is two tap. The delay is the number of samples from before the
|
||||
// current offset
|
||||
struct {
|
||||
ALuint delay;
|
||||
} Tap[2];
|
||||
ALuint Offset;
|
||||
/* The panning gains for the two taps */
|
||||
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
ALfloat FeedGain;
|
||||
|
||||
ALfilterState Filter;
|
||||
} ALechoState;
|
||||
|
||||
static ALvoid ALechoState_Destruct(ALechoState *state);
|
||||
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
|
||||
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALechoState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
|
||||
|
||||
|
||||
static void ALechoState_Construct(ALechoState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALechoState, ALeffectState, state);
|
||||
|
||||
state->BufferLength = 0;
|
||||
state->SampleBuffer = NULL;
|
||||
|
||||
state->Tap[0].delay = 0;
|
||||
state->Tap[1].delay = 0;
|
||||
state->Offset = 0;
|
||||
|
||||
ALfilterState_clear(&state->Filter);
|
||||
}
|
||||
|
||||
static ALvoid ALechoState_Destruct(ALechoState *state)
|
||||
{
|
||||
al_free(state->SampleBuffer);
|
||||
state->SampleBuffer = NULL;
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
|
||||
{
|
||||
ALuint maxlen, i;
|
||||
|
||||
// Use the next power of 2 for the buffer length, so the tap offsets can be
|
||||
// wrapped using a mask instead of a modulo
|
||||
maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
|
||||
maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
|
||||
maxlen = NextPowerOf2(maxlen);
|
||||
|
||||
if(maxlen != state->BufferLength)
|
||||
{
|
||||
void *temp = al_calloc(16, maxlen * sizeof(ALfloat));
|
||||
if(!temp) return AL_FALSE;
|
||||
|
||||
al_free(state->SampleBuffer);
|
||||
state->SampleBuffer = temp;
|
||||
state->BufferLength = maxlen;
|
||||
}
|
||||
for(i = 0;i < state->BufferLength;i++)
|
||||
state->SampleBuffer[i] = 0.0f;
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALuint frequency = Device->Frequency;
|
||||
ALfloat coeffs[MAX_AMBI_COEFFS];
|
||||
ALfloat gain, lrpan, spread;
|
||||
|
||||
state->Tap[0].delay = fastf2u(props->Echo.Delay * frequency) + 1;
|
||||
state->Tap[1].delay = fastf2u(props->Echo.LRDelay * frequency);
|
||||
state->Tap[1].delay += state->Tap[0].delay;
|
||||
|
||||
spread = props->Echo.Spread;
|
||||
if(spread < 0.0f) lrpan = -1.0f;
|
||||
else lrpan = 1.0f;
|
||||
/* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage
|
||||
* spread (where 0 = point, tau = omni).
|
||||
*/
|
||||
spread = asinf(1.0f - fabsf(spread))*4.0f;
|
||||
|
||||
state->FeedGain = props->Echo.Feedback;
|
||||
|
||||
gain = minf(1.0f - props->Echo.Damping, 0.01f);
|
||||
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
|
||||
gain, LOWPASSFREQREF/frequency,
|
||||
calc_rcpQ_from_slope(gain, 0.75f));
|
||||
|
||||
gain = Slot->Params.Gain;
|
||||
|
||||
/* First tap panning */
|
||||
CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]);
|
||||
|
||||
/* Second tap panning */
|
||||
CalcXYZCoeffs( lrpan, 0.0f, 0.0f, spread, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]);
|
||||
}
|
||||
|
||||
static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
const ALuint mask = state->BufferLength-1;
|
||||
const ALuint tap1 = state->Tap[0].delay;
|
||||
const ALuint tap2 = state->Tap[1].delay;
|
||||
ALuint offset = state->Offset;
|
||||
ALfloat x[2], y[2], in, out;
|
||||
ALuint base;
|
||||
ALuint i, k;
|
||||
|
||||
x[0] = state->Filter.x[0];
|
||||
x[1] = state->Filter.x[1];
|
||||
y[0] = state->Filter.y[0];
|
||||
y[1] = state->Filter.y[1];
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALfloat temps[128][2];
|
||||
ALuint td = minu(128, SamplesToDo-base);
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
{
|
||||
/* First tap */
|
||||
temps[i][0] = state->SampleBuffer[(offset-tap1) & mask];
|
||||
/* Second tap */
|
||||
temps[i][1] = state->SampleBuffer[(offset-tap2) & mask];
|
||||
|
||||
// Apply damping and feedback gain to the second tap, and mix in the
|
||||
// new sample
|
||||
in = temps[i][1] + SamplesIn[0][i+base];
|
||||
out = in*state->Filter.b0 +
|
||||
x[0]*state->Filter.b1 + x[1]*state->Filter.b2 -
|
||||
y[0]*state->Filter.a1 - y[1]*state->Filter.a2;
|
||||
x[1] = x[0]; x[0] = in;
|
||||
y[1] = y[0]; y[0] = out;
|
||||
|
||||
state->SampleBuffer[offset&mask] = out * state->FeedGain;
|
||||
offset++;
|
||||
}
|
||||
|
||||
for(k = 0;k < NumChannels;k++)
|
||||
{
|
||||
ALfloat gain = state->Gain[0][k];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(i = 0;i < td;i++)
|
||||
SamplesOut[k][i+base] += temps[i][0] * gain;
|
||||
}
|
||||
|
||||
gain = state->Gain[1][k];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(i = 0;i < td;i++)
|
||||
SamplesOut[k][i+base] += temps[i][1] * gain;
|
||||
}
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
state->Filter.x[0] = x[0];
|
||||
state->Filter.x[1] = x[1];
|
||||
state->Filter.y[0] = y[0];
|
||||
state->Filter.y[1] = y[1];
|
||||
|
||||
state->Offset = offset;
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALechoStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALechoStateFactory;
|
||||
|
||||
ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALechoState *state;
|
||||
|
||||
NEW_OBJ0(state, ALechoState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALechoStateFactory_getFactory(void)
|
||||
{
|
||||
static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &EchoFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALecho_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_ECHO_DELAY:
|
||||
if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Echo.Delay = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_LRDELAY:
|
||||
if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Echo.LRDelay = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_DAMPING:
|
||||
if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Echo.Damping = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_FEEDBACK:
|
||||
if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Echo.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_SPREAD:
|
||||
if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Echo.Spread = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALecho_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALecho_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_ECHO_DELAY:
|
||||
*val = props->Echo.Delay;
|
||||
break;
|
||||
|
||||
case AL_ECHO_LRDELAY:
|
||||
*val = props->Echo.LRDelay;
|
||||
break;
|
||||
|
||||
case AL_ECHO_DAMPING:
|
||||
*val = props->Echo.Damping;
|
||||
break;
|
||||
|
||||
case AL_ECHO_FEEDBACK:
|
||||
*val = props->Echo.Feedback;
|
||||
break;
|
||||
|
||||
case AL_ECHO_SPREAD:
|
||||
*val = props->Echo.Spread;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALecho_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALecho);
|
||||
404
Engine/lib/openal-soft/Alc/effects/equalizer.c
Normal file
404
Engine/lib/openal-soft/Alc/effects/equalizer.c
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2013 by Mike Gorchak
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
/* The document "Effects Extension Guide.pdf" says that low and high *
|
||||
* frequencies are cutoff frequencies. This is not fully correct, they *
|
||||
* are corner frequencies for low and high shelf filters. If they were *
|
||||
* just cutoff frequencies, there would be no need in cutoff frequency *
|
||||
* gains, which are present. Documentation for "Creative Proteus X2" *
|
||||
* software describes 4-band equalizer functionality in a much better *
|
||||
* way. This equalizer seems to be a predecessor of OpenAL 4-band *
|
||||
* equalizer. With low and high shelf filters we are able to cutoff *
|
||||
* frequencies below and/or above corner frequencies using attenuation *
|
||||
* gains (below 1.0) and amplify all low and/or high frequencies using *
|
||||
* gains above 1.0. *
|
||||
* *
|
||||
* Low-shelf Low Mid Band High Mid Band High-shelf *
|
||||
* corner center center corner *
|
||||
* frequency frequency frequency frequency *
|
||||
* 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz *
|
||||
* *
|
||||
* | | | | *
|
||||
* | | | | *
|
||||
* B -----+ /--+--\ /--+--\ +----- *
|
||||
* O |\ | | | | | | /| *
|
||||
* O | \ - | - - | - / | *
|
||||
* S + | \ | | | | | | / | *
|
||||
* T | | | | | | | | | | *
|
||||
* ---------+---------------+------------------+---------------+-------- *
|
||||
* C | | | | | | | | | | *
|
||||
* U - | / | | | | | | \ | *
|
||||
* T | / - | - - | - \ | *
|
||||
* O |/ | | | | | | \| *
|
||||
* F -----+ \--+--/ \--+--/ +----- *
|
||||
* F | | | | *
|
||||
* | | | | *
|
||||
* *
|
||||
* Gains vary from 0.126 up to 7.943, which means from -18dB attenuation *
|
||||
* up to +18dB amplification. Band width varies from 0.01 up to 1.0 in *
|
||||
* octaves for two mid bands. *
|
||||
* *
|
||||
* Implementation is based on the "Cookbook formulae for audio EQ biquad *
|
||||
* filter coefficients" by Robert Bristow-Johnson *
|
||||
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
|
||||
|
||||
|
||||
/* The maximum number of sample frames per update. */
|
||||
#define MAX_UPDATE_SAMPLES 256
|
||||
|
||||
typedef struct ALequalizerState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
/* Effect gains for each channel */
|
||||
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
/* Effect parameters */
|
||||
ALfilterState filter[4][MAX_EFFECT_CHANNELS];
|
||||
|
||||
ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES];
|
||||
} ALequalizerState;
|
||||
|
||||
static ALvoid ALequalizerState_Destruct(ALequalizerState *state);
|
||||
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device);
|
||||
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
|
||||
static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
|
||||
|
||||
|
||||
static void ALequalizerState_Construct(ALequalizerState *state)
|
||||
{
|
||||
int it, ft;
|
||||
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALequalizerState, ALeffectState, state);
|
||||
|
||||
/* Initialize sample history only on filter creation to avoid */
|
||||
/* sound clicks if filter settings were changed in runtime. */
|
||||
for(it = 0; it < 4; it++)
|
||||
{
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
ALfilterState_clear(&state->filter[it][ft]);
|
||||
}
|
||||
}
|
||||
|
||||
static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
|
||||
{
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat frequency = (ALfloat)device->Frequency;
|
||||
ALfloat gain, freq_mult;
|
||||
ALuint i;
|
||||
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
|
||||
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
|
||||
ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
|
||||
slot->Params.Gain, state->Gain[i]);
|
||||
|
||||
/* Calculate coefficients for the each type of filter. Note that the shelf
|
||||
* filters' gain is for the reference frequency, which is the centerpoint
|
||||
* of the transition band.
|
||||
*/
|
||||
gain = sqrtf(props->Equalizer.LowGain);
|
||||
freq_mult = props->Equalizer.LowCutoff/frequency;
|
||||
ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf,
|
||||
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
|
||||
);
|
||||
/* Copy the filter coefficients for the other input channels. */
|
||||
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
|
||||
{
|
||||
state->filter[0][i].a1 = state->filter[0][0].a1;
|
||||
state->filter[0][i].a2 = state->filter[0][0].a2;
|
||||
state->filter[0][i].b0 = state->filter[0][0].b0;
|
||||
state->filter[0][i].b1 = state->filter[0][0].b1;
|
||||
state->filter[0][i].b2 = state->filter[0][0].b2;
|
||||
}
|
||||
|
||||
gain = props->Equalizer.Mid1Gain;
|
||||
freq_mult = props->Equalizer.Mid1Center/frequency;
|
||||
ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking,
|
||||
gain, freq_mult, calc_rcpQ_from_bandwidth(
|
||||
freq_mult, props->Equalizer.Mid1Width
|
||||
)
|
||||
);
|
||||
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
|
||||
{
|
||||
state->filter[1][i].a1 = state->filter[1][0].a1;
|
||||
state->filter[1][i].a2 = state->filter[1][0].a2;
|
||||
state->filter[1][i].b0 = state->filter[1][0].b0;
|
||||
state->filter[1][i].b1 = state->filter[1][0].b1;
|
||||
state->filter[1][i].b2 = state->filter[1][0].b2;
|
||||
}
|
||||
|
||||
gain = props->Equalizer.Mid2Gain;
|
||||
freq_mult = props->Equalizer.Mid2Center/frequency;
|
||||
ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking,
|
||||
gain, freq_mult, calc_rcpQ_from_bandwidth(
|
||||
freq_mult, props->Equalizer.Mid2Width
|
||||
)
|
||||
);
|
||||
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
|
||||
{
|
||||
state->filter[2][i].a1 = state->filter[2][0].a1;
|
||||
state->filter[2][i].a2 = state->filter[2][0].a2;
|
||||
state->filter[2][i].b0 = state->filter[2][0].b0;
|
||||
state->filter[2][i].b1 = state->filter[2][0].b1;
|
||||
state->filter[2][i].b2 = state->filter[2][0].b2;
|
||||
}
|
||||
|
||||
gain = sqrtf(props->Equalizer.HighGain);
|
||||
freq_mult = props->Equalizer.HighCutoff/frequency;
|
||||
ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf,
|
||||
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
|
||||
);
|
||||
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
|
||||
{
|
||||
state->filter[3][i].a1 = state->filter[3][0].a1;
|
||||
state->filter[3][i].a2 = state->filter[3][0].a2;
|
||||
state->filter[3][i].b0 = state->filter[3][0].b0;
|
||||
state->filter[3][i].b1 = state->filter[3][0].b1;
|
||||
state->filter[3][i].b2 = state->filter[3][0].b2;
|
||||
}
|
||||
}
|
||||
|
||||
static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer;
|
||||
ALuint it, kt, ft;
|
||||
ALuint base;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALuint td = minu(MAX_UPDATE_SAMPLES, SamplesToDo-base);
|
||||
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td);
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
ALfilterState_process(&state->filter[1][ft], Samples[1][ft], Samples[0][ft], td);
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
ALfilterState_process(&state->filter[2][ft], Samples[2][ft], Samples[1][ft], td);
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
ALfilterState_process(&state->filter[3][ft], Samples[3][ft], Samples[2][ft], td);
|
||||
|
||||
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
|
||||
{
|
||||
for(kt = 0;kt < NumChannels;kt++)
|
||||
{
|
||||
ALfloat gain = state->Gain[ft][kt];
|
||||
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
|
||||
continue;
|
||||
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][base+it] += gain * Samples[3][ft][it];
|
||||
}
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALequalizerStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALequalizerStateFactory;
|
||||
|
||||
ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALequalizerState *state;
|
||||
|
||||
NEW_OBJ0(state, ALequalizerState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void)
|
||||
{
|
||||
static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALequalizer_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_EQUALIZER_LOW_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.LowGain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_LOW_CUTOFF:
|
||||
if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.LowCutoff = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid1Gain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_CENTER:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid1Center = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_WIDTH:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid1Width = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid2Gain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_CENTER:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid2Center = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_WIDTH:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.Mid2Width = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.HighGain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_CUTOFF:
|
||||
if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Equalizer.HighCutoff = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALequalizer_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
|
||||
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
|
||||
void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALequalizer_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_EQUALIZER_LOW_GAIN:
|
||||
*val = props->Equalizer.LowGain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_LOW_CUTOFF:
|
||||
*val = props->Equalizer.LowCutoff;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_GAIN:
|
||||
*val = props->Equalizer.Mid1Gain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_CENTER:
|
||||
*val = props->Equalizer.Mid1Center;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_WIDTH:
|
||||
*val = props->Equalizer.Mid1Width;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_GAIN:
|
||||
*val = props->Equalizer.Mid2Gain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_CENTER:
|
||||
*val = props->Equalizer.Mid2Center;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_WIDTH:
|
||||
*val = props->Equalizer.Mid2Width;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_GAIN:
|
||||
*val = props->Equalizer.HighGain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_CUTOFF:
|
||||
*val = props->Equalizer.HighCutoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALequalizer_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALequalizer);
|
||||
411
Engine/lib/openal-soft/Alc/effects/flanger.c
Normal file
411
Engine/lib/openal-soft/Alc/effects/flanger.c
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2013 by Mike Gorchak
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
enum FlangerWaveForm {
|
||||
FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
|
||||
FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
|
||||
};
|
||||
|
||||
typedef struct ALflangerState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
ALfloat *SampleBuffer[2];
|
||||
ALuint BufferLength;
|
||||
ALuint offset;
|
||||
ALuint lfo_range;
|
||||
ALfloat lfo_scale;
|
||||
ALint lfo_disp;
|
||||
|
||||
/* Gains for left and right sides */
|
||||
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
/* effect parameters */
|
||||
enum FlangerWaveForm waveform;
|
||||
ALint delay;
|
||||
ALfloat depth;
|
||||
ALfloat feedback;
|
||||
} ALflangerState;
|
||||
|
||||
static ALvoid ALflangerState_Destruct(ALflangerState *state);
|
||||
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device);
|
||||
static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
|
||||
|
||||
|
||||
static void ALflangerState_Construct(ALflangerState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALflangerState, ALeffectState, state);
|
||||
|
||||
state->BufferLength = 0;
|
||||
state->SampleBuffer[0] = NULL;
|
||||
state->SampleBuffer[1] = NULL;
|
||||
state->offset = 0;
|
||||
state->lfo_range = 1;
|
||||
state->waveform = FWF_Triangle;
|
||||
}
|
||||
|
||||
static ALvoid ALflangerState_Destruct(ALflangerState *state)
|
||||
{
|
||||
al_free(state->SampleBuffer[0]);
|
||||
state->SampleBuffer[0] = NULL;
|
||||
state->SampleBuffer[1] = NULL;
|
||||
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
|
||||
{
|
||||
ALuint maxlen;
|
||||
ALuint it;
|
||||
|
||||
maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1;
|
||||
maxlen = NextPowerOf2(maxlen);
|
||||
|
||||
if(maxlen != state->BufferLength)
|
||||
{
|
||||
void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
|
||||
if(!temp) return AL_FALSE;
|
||||
|
||||
al_free(state->SampleBuffer[0]);
|
||||
state->SampleBuffer[0] = temp;
|
||||
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
|
||||
|
||||
state->BufferLength = maxlen;
|
||||
}
|
||||
|
||||
for(it = 0;it < state->BufferLength;it++)
|
||||
{
|
||||
state->SampleBuffer[0][it] = 0.0f;
|
||||
state->SampleBuffer[1][it] = 0.0f;
|
||||
}
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat frequency = (ALfloat)Device->Frequency;
|
||||
ALfloat coeffs[MAX_AMBI_COEFFS];
|
||||
ALfloat rate;
|
||||
ALint phase;
|
||||
|
||||
switch(props->Flanger.Waveform)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM_TRIANGLE:
|
||||
state->waveform = FWF_Triangle;
|
||||
break;
|
||||
case AL_FLANGER_WAVEFORM_SINUSOID:
|
||||
state->waveform = FWF_Sinusoid;
|
||||
break;
|
||||
}
|
||||
state->depth = props->Flanger.Depth;
|
||||
state->feedback = props->Flanger.Feedback;
|
||||
state->delay = fastf2i(props->Flanger.Delay * frequency);
|
||||
|
||||
/* Gains for left and right sides */
|
||||
CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
|
||||
CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
|
||||
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
|
||||
|
||||
phase = props->Flanger.Phase;
|
||||
rate = props->Flanger.Rate;
|
||||
if(!(rate > 0.0f))
|
||||
{
|
||||
state->lfo_scale = 0.0f;
|
||||
state->lfo_range = 1;
|
||||
state->lfo_disp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate LFO coefficient */
|
||||
state->lfo_range = fastf2u(frequency/rate + 0.5f);
|
||||
switch(state->waveform)
|
||||
{
|
||||
case FWF_Triangle:
|
||||
state->lfo_scale = 4.0f / state->lfo_range;
|
||||
break;
|
||||
case FWF_Sinusoid:
|
||||
state->lfo_scale = F_TAU / state->lfo_range;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate lfo phase displacement */
|
||||
state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
|
||||
{
|
||||
ALfloat lfo_value;
|
||||
|
||||
lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_left = fastf2i(lfo_value) + state->delay;
|
||||
|
||||
offset += state->lfo_disp;
|
||||
lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_right = fastf2i(lfo_value) + state->delay;
|
||||
}
|
||||
|
||||
static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
|
||||
{
|
||||
ALfloat lfo_value;
|
||||
|
||||
lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_left = fastf2i(lfo_value) + state->delay;
|
||||
|
||||
offset += state->lfo_disp;
|
||||
lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
|
||||
lfo_value *= state->depth * state->delay;
|
||||
*delay_right = fastf2i(lfo_value) + state->delay;
|
||||
}
|
||||
|
||||
#define DECL_TEMPLATE(Func) \
|
||||
static void Process##Func(ALflangerState *state, const ALuint SamplesToDo, \
|
||||
const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
|
||||
{ \
|
||||
const ALuint bufmask = state->BufferLength-1; \
|
||||
ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
|
||||
ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
|
||||
ALuint offset = state->offset; \
|
||||
const ALfloat feedback = state->feedback; \
|
||||
ALuint it; \
|
||||
\
|
||||
for(it = 0;it < SamplesToDo;it++) \
|
||||
{ \
|
||||
ALint delay_left, delay_right; \
|
||||
Func(&delay_left, &delay_right, offset, state); \
|
||||
\
|
||||
out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
|
||||
leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
|
||||
\
|
||||
out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
|
||||
rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
|
||||
\
|
||||
offset++; \
|
||||
} \
|
||||
state->offset = offset; \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(Triangle)
|
||||
DECL_TEMPLATE(Sinusoid)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
ALuint it, kt;
|
||||
ALuint base;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALfloat temps[128][2];
|
||||
ALuint td = minu(128, SamplesToDo-base);
|
||||
|
||||
switch(state->waveform)
|
||||
{
|
||||
case FWF_Triangle:
|
||||
ProcessTriangle(state, td, SamplesIn[0]+base, temps);
|
||||
break;
|
||||
case FWF_Sinusoid:
|
||||
ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
|
||||
break;
|
||||
}
|
||||
|
||||
for(kt = 0;kt < NumChannels;kt++)
|
||||
{
|
||||
ALfloat gain = state->Gain[0][kt];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][it+base] += temps[it][0] * gain;
|
||||
}
|
||||
|
||||
gain = state->Gain[1][kt];
|
||||
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
|
||||
{
|
||||
for(it = 0;it < td;it++)
|
||||
SamplesOut[kt][it+base] += temps[it][1] * gain;
|
||||
}
|
||||
}
|
||||
|
||||
base += td;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALflangerStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALflangerStateFactory;
|
||||
|
||||
ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALflangerState *state;
|
||||
|
||||
NEW_OBJ0(state, ALflangerState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
|
||||
{
|
||||
static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM:
|
||||
if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Waveform = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_PHASE:
|
||||
if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Phase = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALflanger_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_RATE:
|
||||
if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Rate = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DEPTH:
|
||||
if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Depth = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_FEEDBACK:
|
||||
if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DELAY:
|
||||
if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Flanger.Delay = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALflanger_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM:
|
||||
*val = props->Flanger.Waveform;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_PHASE:
|
||||
*val = props->Flanger.Phase;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALflanger_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_RATE:
|
||||
*val = props->Flanger.Rate;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DEPTH:
|
||||
*val = props->Flanger.Depth;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_FEEDBACK:
|
||||
*val = props->Flanger.Feedback;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DELAY:
|
||||
*val = props->Flanger.Delay;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALflanger_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALflanger);
|
||||
311
Engine/lib/openal-soft/Alc/effects/modulator.c
Normal file
311
Engine/lib/openal-soft/Alc/effects/modulator.c
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2009 by Chris Robinson.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "alu.h"
|
||||
|
||||
|
||||
typedef struct ALmodulatorState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
|
||||
void (*Process)(ALfloat*, const ALfloat*, ALuint, const ALuint, ALuint);
|
||||
|
||||
ALuint index;
|
||||
ALuint step;
|
||||
|
||||
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
|
||||
|
||||
ALfilterState Filter[MAX_EFFECT_CHANNELS];
|
||||
} ALmodulatorState;
|
||||
|
||||
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state);
|
||||
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device);
|
||||
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
|
||||
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
|
||||
DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
|
||||
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
|
||||
|
||||
|
||||
#define WAVEFORM_FRACBITS 24
|
||||
#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
|
||||
#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
|
||||
|
||||
static inline ALfloat Sin(ALuint index)
|
||||
{
|
||||
return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
|
||||
}
|
||||
|
||||
static inline ALfloat Saw(ALuint index)
|
||||
{
|
||||
return (ALfloat)index / WAVEFORM_FRACONE;
|
||||
}
|
||||
|
||||
static inline ALfloat Square(ALuint index)
|
||||
{
|
||||
return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
|
||||
}
|
||||
|
||||
#define DECL_TEMPLATE(func) \
|
||||
static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\
|
||||
ALuint index, const ALuint step, ALuint todo) \
|
||||
{ \
|
||||
ALuint i; \
|
||||
for(i = 0;i < todo;i++) \
|
||||
{ \
|
||||
index += step; \
|
||||
index &= WAVEFORM_FRACMASK; \
|
||||
dst[i] = src[i] * func(index); \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(Sin)
|
||||
DECL_TEMPLATE(Saw)
|
||||
DECL_TEMPLATE(Square)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
|
||||
static void ALmodulatorState_Construct(ALmodulatorState *state)
|
||||
{
|
||||
ALuint i;
|
||||
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALmodulatorState, ALeffectState, state);
|
||||
|
||||
state->index = 0;
|
||||
state->step = 1;
|
||||
|
||||
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
|
||||
ALfilterState_clear(&state->Filter[i]);
|
||||
}
|
||||
|
||||
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
|
||||
{
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
|
||||
{
|
||||
ALfloat cw, a;
|
||||
ALuint i;
|
||||
|
||||
if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
|
||||
state->Process = ModulateSin;
|
||||
else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
|
||||
state->Process = ModulateSaw;
|
||||
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
|
||||
state->Process = ModulateSquare;
|
||||
|
||||
state->step = fastf2u(props->Modulator.Frequency*WAVEFORM_FRACONE /
|
||||
Device->Frequency);
|
||||
if(state->step == 0) state->step = 1;
|
||||
|
||||
/* Custom filter coeffs, which match the old version instead of a low-shelf. */
|
||||
cw = cosf(F_TAU * props->Modulator.HighPassCutoff / Device->Frequency);
|
||||
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
|
||||
|
||||
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
|
||||
{
|
||||
state->Filter[i].a1 = -a;
|
||||
state->Filter[i].a2 = 0.0f;
|
||||
state->Filter[i].b0 = a;
|
||||
state->Filter[i].b1 = -a;
|
||||
state->Filter[i].b2 = 0.0f;
|
||||
}
|
||||
|
||||
STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer;
|
||||
STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels;
|
||||
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
|
||||
ComputeFirstOrderGains(Device->FOAOut, IdentityMatrixf.m[i],
|
||||
Slot->Params.Gain, state->Gain[i]);
|
||||
}
|
||||
|
||||
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
|
||||
{
|
||||
const ALuint step = state->step;
|
||||
ALuint index = state->index;
|
||||
ALuint base;
|
||||
|
||||
for(base = 0;base < SamplesToDo;)
|
||||
{
|
||||
ALfloat temps[2][128];
|
||||
ALuint td = minu(128, SamplesToDo-base);
|
||||
ALuint i, j, k;
|
||||
|
||||
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
|
||||
{
|
||||
ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td);
|
||||
state->Process(temps[1], temps[0], index, step, td);
|
||||
|
||||
for(k = 0;k < NumChannels;k++)
|
||||
{
|
||||
ALfloat gain = state->Gain[j][k];
|
||||
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
|
||||
continue;
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
SamplesOut[k][base+i] += gain * temps[1][i];
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0;i < td;i++)
|
||||
{
|
||||
index += step;
|
||||
index &= WAVEFORM_FRACMASK;
|
||||
}
|
||||
base += td;
|
||||
}
|
||||
state->index = index;
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALmodulatorStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALmodulatorStateFactory;
|
||||
|
||||
static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALmodulatorState *state;
|
||||
|
||||
NEW_OBJ0(state, ALmodulatorState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void)
|
||||
{
|
||||
static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } };
|
||||
|
||||
return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Modulator.Frequency = val;
|
||||
break;
|
||||
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Modulator.HighPassCutoff = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
|
||||
{
|
||||
ALmodulator_setParamf(effect, context, param, vals[0]);
|
||||
}
|
||||
void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
|
||||
{
|
||||
ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
ALmodulator_setParamf(effect, context, param, (ALfloat)val);
|
||||
break;
|
||||
|
||||
case AL_RING_MODULATOR_WAVEFORM:
|
||||
if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
|
||||
props->Modulator.Waveform = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
|
||||
{
|
||||
ALmodulator_setParami(effect, context, param, vals[0]);
|
||||
}
|
||||
|
||||
void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
*val = (ALint)props->Modulator.Frequency;
|
||||
break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
*val = (ALint)props->Modulator.HighPassCutoff;
|
||||
break;
|
||||
case AL_RING_MODULATOR_WAVEFORM:
|
||||
*val = props->Modulator.Waveform;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
|
||||
{
|
||||
ALmodulator_getParami(effect, context, param, vals);
|
||||
}
|
||||
void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
|
||||
{
|
||||
const ALeffectProps *props = &effect->Props;
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
*val = props->Modulator.Frequency;
|
||||
break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
*val = props->Modulator.HighPassCutoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
|
||||
{
|
||||
ALmodulator_getParamf(effect, context, param, vals);
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALmodulator);
|
||||
179
Engine/lib/openal-soft/Alc/effects/null.c
Normal file
179
Engine/lib/openal-soft/Alc/effects/null.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "alMain.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
|
||||
|
||||
typedef struct ALnullState {
|
||||
DERIVE_FROM_TYPE(ALeffectState);
|
||||
} ALnullState;
|
||||
|
||||
/* Forward-declare "virtual" functions to define the vtable with. */
|
||||
static ALvoid ALnullState_Destruct(ALnullState *state);
|
||||
static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device);
|
||||
static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
|
||||
static ALvoid ALnullState_process(ALnullState *state, ALuint samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALuint NumChannels);
|
||||
static void *ALnullState_New(size_t size);
|
||||
static void ALnullState_Delete(void *ptr);
|
||||
|
||||
/* Define the ALeffectState vtable for this type. */
|
||||
DEFINE_ALEFFECTSTATE_VTABLE(ALnullState);
|
||||
|
||||
|
||||
/* This constructs the effect state. It's called when the object is first
|
||||
* created. Make sure to call the parent Construct function first, and set the
|
||||
* vtable!
|
||||
*/
|
||||
static void ALnullState_Construct(ALnullState *state)
|
||||
{
|
||||
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
|
||||
SET_VTABLE2(ALnullState, ALeffectState, state);
|
||||
}
|
||||
|
||||
/* This destructs (not free!) the effect state. It's called only when the
|
||||
* effect slot is no longer used. Make sure to call the parent Destruct
|
||||
* function before returning!
|
||||
*/
|
||||
static ALvoid ALnullState_Destruct(ALnullState *state)
|
||||
{
|
||||
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
|
||||
}
|
||||
|
||||
/* This updates the device-dependant effect state. This is called on
|
||||
* initialization and any time the device parameters (eg. playback frequency,
|
||||
* format) have been changed.
|
||||
*/
|
||||
static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device))
|
||||
{
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
/* This updates the effect state. This is called any time the effect is
|
||||
* (re)loaded into a slot.
|
||||
*/
|
||||
static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
|
||||
{
|
||||
}
|
||||
|
||||
/* This processes the effect state, for the given number of samples from the
|
||||
* input to the output buffer. The result should be added to the output buffer,
|
||||
* not replace it.
|
||||
*/
|
||||
static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels))
|
||||
{
|
||||
}
|
||||
|
||||
/* This allocates memory to store the object, before it gets constructed.
|
||||
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
|
||||
*/
|
||||
static void *ALnullState_New(size_t size)
|
||||
{
|
||||
return al_malloc(16, size);
|
||||
}
|
||||
|
||||
/* This frees the memory used by the object, after it has been destructed.
|
||||
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
|
||||
*/
|
||||
static void ALnullState_Delete(void *ptr)
|
||||
{
|
||||
al_free(ptr);
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALnullStateFactory {
|
||||
DERIVE_FROM_TYPE(ALeffectStateFactory);
|
||||
} ALnullStateFactory;
|
||||
|
||||
/* Creates ALeffectState objects of the appropriate type. */
|
||||
ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
|
||||
{
|
||||
ALnullState *state;
|
||||
|
||||
NEW_OBJ0(state, ALnullState)();
|
||||
if(!state) return NULL;
|
||||
|
||||
return STATIC_CAST(ALeffectState, state);
|
||||
}
|
||||
|
||||
/* Define the ALeffectStateFactory vtable for this type. */
|
||||
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory);
|
||||
|
||||
ALeffectStateFactory *ALnullStateFactory_getFactory(void)
|
||||
{
|
||||
static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } };
|
||||
return STATIC_CAST(ALeffectStateFactory, &NullFactory);
|
||||
}
|
||||
|
||||
|
||||
void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_setParamiv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_setParamf(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_setParamfv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
|
||||
void ALnull_getParami(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_getParamiv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_getParamf(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
void ALnull_getParamfv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals))
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(ALnull);
|
||||
1994
Engine/lib/openal-soft/Alc/effects/reverb.c
Normal file
1994
Engine/lib/openal-soft/Alc/effects/reverb.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue