2 * OpenAL cross platform audio library
3 * Copyright (C) 2018 by Raul Herraiz.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
27 #include "alAuxEffectSlot.h"
30 #include "filters/defs.h"
32 #include "alcomplex.h"
35 #define OVERSAMP (1<<2)
37 #define HIL_STEP (HIL_SIZE / OVERSAMP)
38 #define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1))
41 typedef struct ALfshifterState
{
42 DERIVE_FROM_TYPE(ALeffectState
);
44 /* Effect parameters */
51 ALfloat InFIFO
[HIL_SIZE
];
52 ALcomplex OutFIFO
[HIL_SIZE
];
53 ALcomplex OutputAccum
[HIL_SIZE
];
54 ALcomplex Analytic
[HIL_SIZE
];
55 ALcomplex Outdata
[BUFFERSIZE
];
57 alignas(16) ALfloat BufferOut
[BUFFERSIZE
];
59 /* Effect gains for each output channel */
60 ALfloat CurrentGains
[MAX_OUTPUT_CHANNELS
];
61 ALfloat TargetGains
[MAX_OUTPUT_CHANNELS
];
64 static ALvoid
ALfshifterState_Destruct(ALfshifterState
*state
);
65 static ALboolean
ALfshifterState_deviceUpdate(ALfshifterState
*state
, ALCdevice
*device
);
66 static ALvoid
ALfshifterState_update(ALfshifterState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
);
67 static ALvoid
ALfshifterState_process(ALfshifterState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
);
68 DECLARE_DEFAULT_ALLOCATORS(ALfshifterState
)
70 DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState
);
72 /* Define a Hann window, used to filter the HIL input and output. */
73 alignas(16) static ALdouble HannWindow
[HIL_SIZE
];
75 static void InitHannWindow(void)
79 /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
80 for(i
= 0;i
< HIL_SIZE
>>1;i
++)
82 ALdouble val
= sin(M_PI
* (ALdouble
)i
/ (ALdouble
)(HIL_SIZE
-1));
83 HannWindow
[i
] = HannWindow
[HIL_SIZE
-1-i
] = val
* val
;
87 static alonce_flag HannInitOnce
= AL_ONCE_FLAG_INIT
;
89 static void ALfshifterState_Construct(ALfshifterState
*state
)
91 ALeffectState_Construct(STATIC_CAST(ALeffectState
, state
));
92 SET_VTABLE2(ALfshifterState
, ALeffectState
, state
);
94 alcall_once(&HannInitOnce
, InitHannWindow
);
97 static ALvoid
ALfshifterState_Destruct(ALfshifterState
*state
)
99 ALeffectState_Destruct(STATIC_CAST(ALeffectState
,state
));
102 static ALboolean
ALfshifterState_deviceUpdate(ALfshifterState
*state
, ALCdevice
*UNUSED(device
))
104 /* (Re-)initializing parameters and clear the buffers. */
105 state
->count
= FIFO_LATENCY
;
106 state
->PhaseStep
= 0;
108 state
->ld_sign
= 1.0;
110 memset(state
->InFIFO
, 0, sizeof(state
->InFIFO
));
111 memset(state
->OutFIFO
, 0, sizeof(state
->OutFIFO
));
112 memset(state
->OutputAccum
, 0, sizeof(state
->OutputAccum
));
113 memset(state
->Analytic
, 0, sizeof(state
->Analytic
));
115 memset(state
->CurrentGains
, 0, sizeof(state
->CurrentGains
));
116 memset(state
->TargetGains
, 0, sizeof(state
->TargetGains
));
121 static ALvoid
ALfshifterState_update(ALfshifterState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
)
123 const ALCdevice
*device
= context
->Device
;
124 ALfloat coeffs
[MAX_AMBI_COEFFS
];
127 step
= props
->Fshifter
.Frequency
/ (ALfloat
)device
->Frequency
;
128 state
->PhaseStep
= fastf2i(minf(step
, 0.5f
) * FRACTIONONE
);
130 switch(props
->Fshifter
.LeftDirection
)
132 case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN
:
133 state
->ld_sign
= -1.0;
136 case AL_FREQUENCY_SHIFTER_DIRECTION_UP
:
137 state
->ld_sign
= 1.0;
140 case AL_FREQUENCY_SHIFTER_DIRECTION_OFF
:
142 state
->PhaseStep
= 0;
146 CalcAngleCoeffs(0.0f
, 0.0f
, 0.0f
, coeffs
);
147 ComputePanGains(&device
->Dry
, coeffs
, slot
->Params
.Gain
, state
->TargetGains
);
150 static ALvoid
ALfshifterState_process(ALfshifterState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
)
152 static const ALcomplex complex_zero
= { 0.0, 0.0 };
153 ALfloat
*restrict BufferOut
= state
->BufferOut
;
156 for(base
= 0;base
< SamplesToDo
;)
158 ALsizei todo
= mini(HIL_SIZE
-state
->count
, SamplesToDo
-base
);
162 /* Fill FIFO buffer with samples data */
164 for(j
= 0;j
< todo
;j
++,k
++)
166 state
->InFIFO
[k
] = SamplesIn
[0][base
+j
];
167 state
->Outdata
[base
+j
] = state
->OutFIFO
[k
-FIFO_LATENCY
];
169 state
->count
+= todo
;
172 /* Check whether FIFO buffer is filled */
173 if(state
->count
< HIL_SIZE
) continue;
175 state
->count
= FIFO_LATENCY
;
177 /* Real signal windowing and store in Analytic buffer */
178 for(k
= 0;k
< HIL_SIZE
;k
++)
180 state
->Analytic
[k
].Real
= state
->InFIFO
[k
] * HannWindow
[k
];
181 state
->Analytic
[k
].Imag
= 0.0;
184 /* Processing signal by Discrete Hilbert Transform (analytical signal). */
185 complex_hilbert(state
->Analytic
, HIL_SIZE
);
187 /* Windowing and add to output accumulator */
188 for(k
= 0;k
< HIL_SIZE
;k
++)
190 state
->OutputAccum
[k
].Real
+= 2.0/OVERSAMP
*HannWindow
[k
]*state
->Analytic
[k
].Real
;
191 state
->OutputAccum
[k
].Imag
+= 2.0/OVERSAMP
*HannWindow
[k
]*state
->Analytic
[k
].Imag
;
194 /* Shift accumulator, input & output FIFO */
195 for(k
= 0;k
< HIL_STEP
;k
++) state
->OutFIFO
[k
] = state
->OutputAccum
[k
];
196 for(j
= 0;k
< HIL_SIZE
;k
++,j
++) state
->OutputAccum
[j
] = state
->OutputAccum
[k
];
197 for(;j
< HIL_SIZE
;j
++) state
->OutputAccum
[j
] = complex_zero
;
198 for(k
= 0;k
< FIFO_LATENCY
;k
++)
199 state
->InFIFO
[k
] = state
->InFIFO
[k
+HIL_STEP
];
202 /* Process frequency shifter using the analytic signal obtained. */
203 for(k
= 0;k
< SamplesToDo
;k
++)
205 ALdouble phase
= state
->Phase
* ((1.0/FRACTIONONE
) * 2.0*M_PI
);
206 BufferOut
[k
] = (ALfloat
)(state
->Outdata
[k
].Real
*cos(phase
) +
207 state
->Outdata
[k
].Imag
*sin(phase
)*state
->ld_sign
);
209 state
->Phase
+= state
->PhaseStep
;
210 state
->Phase
&= FRACTIONMASK
;
213 /* Now, mix the processed sound data to the output. */
214 MixSamples(BufferOut
, NumChannels
, SamplesOut
, state
->CurrentGains
, state
->TargetGains
,
215 maxi(SamplesToDo
, 512), 0, SamplesToDo
);
218 typedef struct FshifterStateFactory
{
219 DERIVE_FROM_TYPE(EffectStateFactory
);
220 } FshifterStateFactory
;
222 static ALeffectState
*FshifterStateFactory_create(FshifterStateFactory
*UNUSED(factory
))
224 ALfshifterState
*state
;
226 NEW_OBJ0(state
, ALfshifterState
)();
227 if(!state
) return NULL
;
229 return STATIC_CAST(ALeffectState
, state
);
232 DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory
);
234 EffectStateFactory
*FshifterStateFactory_getFactory(void)
236 static FshifterStateFactory FshifterFactory
= { { GET_VTABLE2(FshifterStateFactory
, EffectStateFactory
) } };
238 return STATIC_CAST(EffectStateFactory
, &FshifterFactory
);
241 void ALfshifter_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
243 ALeffectProps
*props
= &effect
->Props
;
246 case AL_FREQUENCY_SHIFTER_FREQUENCY
:
247 if(!(val
>= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY
&& val
<= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY
))
248 SETERR_RETURN(context
, AL_INVALID_VALUE
,,"Frequency shifter frequency out of range");
249 props
->Fshifter
.Frequency
= val
;
253 alSetError(context
, AL_INVALID_ENUM
, "Invalid frequency shifter float property 0x%04x", param
);
257 void ALfshifter_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
259 ALfshifter_setParamf(effect
, context
, param
, vals
[0]);
262 void ALfshifter_setParami(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint val
)
264 ALeffectProps
*props
= &effect
->Props
;
267 case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION
:
268 if(!(val
>= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION
&& val
<= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION
))
269 SETERR_RETURN(context
, AL_INVALID_VALUE
,,"Frequency shifter left direction out of range");
270 props
->Fshifter
.LeftDirection
= val
;
273 case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION
:
274 if(!(val
>= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION
&& val
<= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION
))
275 SETERR_RETURN(context
, AL_INVALID_VALUE
,,"Frequency shifter right direction out of range");
276 props
->Fshifter
.RightDirection
= val
;
280 alSetError(context
, AL_INVALID_ENUM
, "Invalid frequency shifter integer property 0x%04x", param
);
283 void ALfshifter_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
285 ALfshifter_setParami(effect
, context
, param
, vals
[0]);
288 void ALfshifter_getParami(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*val
)
290 const ALeffectProps
*props
= &effect
->Props
;
293 case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION
:
294 *val
= props
->Fshifter
.LeftDirection
;
296 case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION
:
297 *val
= props
->Fshifter
.RightDirection
;
300 alSetError(context
, AL_INVALID_ENUM
, "Invalid frequency shifter integer property 0x%04x", param
);
303 void ALfshifter_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
305 ALfshifter_getParami(effect
, context
, param
, vals
);
308 void ALfshifter_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
311 const ALeffectProps
*props
= &effect
->Props
;
314 case AL_FREQUENCY_SHIFTER_FREQUENCY
:
315 *val
= props
->Fshifter
.Frequency
;
319 alSetError(context
, AL_INVALID_ENUM
, "Invalid frequency shifter float property 0x%04x", param
);
324 void ALfshifter_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
326 ALfshifter_getParamf(effect
, context
, param
, vals
);
329 DEFINE_ALEFFECT_VTABLE(ALfshifter
);