rlm@0: /** rlm@0: * OpenAL cross platform audio library rlm@0: * Copyright (C) 2009 by Chris Robinson. rlm@0: * This library is free software; you can redistribute it and/or rlm@0: * modify it under the terms of the GNU Library General Public rlm@0: * License as published by the Free Software Foundation; either rlm@0: * version 2 of the License, or (at your option) any later version. rlm@0: * rlm@0: * This library is distributed in the hope that it will be useful, rlm@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of rlm@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU rlm@0: * Library General Public License for more details. rlm@0: * rlm@0: * You should have received a copy of the GNU Library General Public rlm@0: * License along with this library; if not, write to the rlm@0: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, rlm@0: * Boston, MA 02111-1307, USA. rlm@0: * Or go to http://www.gnu.org/copyleft/lgpl.html rlm@0: */ rlm@0: rlm@0: #include "config.h" rlm@0: rlm@0: #include rlm@0: #include rlm@0: rlm@0: #include "alMain.h" rlm@0: #include "alFilter.h" rlm@0: #include "alAuxEffectSlot.h" rlm@0: #include "alError.h" rlm@0: #include "alu.h" rlm@0: rlm@0: rlm@0: typedef struct ALmodulatorState { rlm@0: // Must be first in all effects! rlm@0: ALeffectState state; rlm@0: rlm@0: enum { rlm@0: SINUSOID, rlm@0: SAWTOOTH, rlm@0: SQUARE rlm@0: } Waveform; rlm@0: rlm@0: ALuint index; rlm@0: ALuint step; rlm@0: rlm@0: ALfloat Gain[MAXCHANNELS]; rlm@0: rlm@0: FILTER iirFilter; rlm@0: ALfloat history[1]; rlm@0: } ALmodulatorState; rlm@0: rlm@0: #define WAVEFORM_FRACBITS 16 rlm@0: #define WAVEFORM_FRACMASK ((1<history[offset]; rlm@0: ALfloat a = iir->coeff; rlm@0: ALfloat output = input; rlm@0: rlm@0: output = output + (history[0]-output)*a; rlm@0: history[0] = output; rlm@0: rlm@0: return input - output; rlm@0: } rlm@0: rlm@0: rlm@0: #define DECL_TEMPLATE(func) \ rlm@0: static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ rlm@0: const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS]) \ rlm@0: { \ rlm@0: const ALuint step = state->step; \ rlm@0: ALuint index = state->index; \ rlm@0: ALfloat samp; \ rlm@0: ALuint i; \ rlm@0: \ rlm@0: for(i = 0;i < SamplesToDo;i++) \ rlm@0: { \ rlm@0: samp = SamplesIn[i]; \ rlm@0: \ rlm@0: index += step; \ rlm@0: index &= WAVEFORM_FRACMASK; \ rlm@0: samp *= func(index); \ rlm@0: \ rlm@0: samp = hpFilter1P(&state->iirFilter, 0, samp); \ rlm@0: \ rlm@0: SamplesOut[i][FRONT_LEFT] += state->Gain[FRONT_LEFT] * samp; \ rlm@0: SamplesOut[i][FRONT_RIGHT] += state->Gain[FRONT_RIGHT] * samp; \ rlm@0: SamplesOut[i][FRONT_CENTER] += state->Gain[FRONT_CENTER] * samp; \ rlm@0: SamplesOut[i][SIDE_LEFT] += state->Gain[SIDE_LEFT] * samp; \ rlm@0: SamplesOut[i][SIDE_RIGHT] += state->Gain[SIDE_RIGHT] * samp; \ rlm@0: SamplesOut[i][BACK_LEFT] += state->Gain[BACK_LEFT] * samp; \ rlm@0: SamplesOut[i][BACK_RIGHT] += state->Gain[BACK_RIGHT] * samp; \ rlm@0: SamplesOut[i][BACK_CENTER] += state->Gain[BACK_CENTER] * samp; \ rlm@0: } \ rlm@0: state->index = index; \ rlm@0: } rlm@0: rlm@0: DECL_TEMPLATE(Sin) rlm@0: DECL_TEMPLATE(Saw) rlm@0: DECL_TEMPLATE(Square) rlm@0: rlm@0: #undef DECL_TEMPLATE rlm@0: rlm@0: rlm@0: static ALvoid ModulatorDestroy(ALeffectState *effect) rlm@0: { rlm@0: ALmodulatorState *state = (ALmodulatorState*)effect; rlm@0: free(state); rlm@0: } rlm@0: rlm@0: static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device) rlm@0: { rlm@0: return AL_TRUE; rlm@0: (void)effect; rlm@0: (void)Device; rlm@0: } rlm@0: rlm@0: static ALvoid ModulatorUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot) rlm@0: { rlm@0: ALmodulatorState *state = (ALmodulatorState*)effect; rlm@0: ALCdevice *Device = Context->Device; rlm@0: ALfloat gain, cw, a = 0.0f; rlm@0: ALuint index; rlm@0: rlm@0: if(Slot->effect.Params.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) rlm@0: state->Waveform = SINUSOID; rlm@0: else if(Slot->effect.Params.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) rlm@0: state->Waveform = SAWTOOTH; rlm@0: else if(Slot->effect.Params.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) rlm@0: state->Waveform = SQUARE; rlm@0: rlm@0: state->step = Slot->effect.Params.Modulator.Frequency*(1<Frequency; rlm@0: if(!state->step) rlm@0: state->step = 1; rlm@0: rlm@0: cw = cos(2.0*M_PI * Slot->effect.Params.Modulator.HighPassCutoff / rlm@0: Device->Frequency); rlm@0: a = (2.0f-cw) - aluSqrt(aluPow(2.0f-cw, 2.0f) - 1.0f); rlm@0: state->iirFilter.coeff = a; rlm@0: rlm@0: gain = Slot->Gain; rlm@0: for(index = 0;index < MAXCHANNELS;index++) rlm@0: state->Gain[index] = 0.0f; rlm@0: for(index = 0;index < Device->NumChan;index++) rlm@0: { rlm@0: enum Channel chan = Device->Speaker2Chan[index]; rlm@0: state->Gain[chan] = gain; rlm@0: } rlm@0: } rlm@0: rlm@0: static ALvoid ModulatorProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS]) rlm@0: { rlm@0: ALmodulatorState *state = (ALmodulatorState*)effect; rlm@0: (void)Slot; rlm@0: rlm@0: switch(state->Waveform) rlm@0: { rlm@0: case SINUSOID: rlm@0: ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut); rlm@0: break; rlm@0: rlm@0: case SAWTOOTH: rlm@0: ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut); rlm@0: break; rlm@0: rlm@0: case SQUARE: rlm@0: ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut); rlm@0: break; rlm@0: } rlm@0: } rlm@0: rlm@0: ALeffectState *ModulatorCreate(void) rlm@0: { rlm@0: ALmodulatorState *state; rlm@0: rlm@0: state = malloc(sizeof(*state)); rlm@0: if(!state) rlm@0: return NULL; rlm@0: rlm@0: state->state.Destroy = ModulatorDestroy; rlm@0: state->state.DeviceUpdate = ModulatorDeviceUpdate; rlm@0: state->state.Update = ModulatorUpdate; rlm@0: state->state.Process = ModulatorProcess; rlm@0: rlm@0: state->index = 0.0f; rlm@0: state->step = 1.0f; rlm@0: rlm@0: state->iirFilter.coeff = 0.0f; rlm@0: state->iirFilter.history[0] = 0.0f; rlm@0: rlm@0: return &state->state; rlm@0: }