OpenAL-soft for windows

This commit is contained in:
RexTimmy 2016-10-22 09:22:33 +10:00
parent e2f2c4932b
commit 3a0a720115
207 changed files with 53310 additions and 13291 deletions

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);

File diff suppressed because it is too large Load diff