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"
33 #define STFT_SIZE 1024
34 #define STFT_HALF_SIZE (STFT_SIZE>>1)
35 #define OVERSAMP (1<<2)
37 #define STFT_STEP (STFT_SIZE / OVERSAMP)
38 #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1))
40 typedef struct ALcomplex
{
45 typedef struct ALphasor
{
50 typedef struct ALFrequencyDomain
{
55 typedef struct ALpshifterState
{
56 DERIVE_FROM_TYPE(ALeffectState
);
58 /* Effect parameters */
65 ALfloat InFIFO
[STFT_SIZE
];
66 ALfloat OutFIFO
[STFT_STEP
];
67 ALdouble LastPhase
[STFT_HALF_SIZE
+1];
68 ALdouble SumPhase
[STFT_HALF_SIZE
+1];
69 ALdouble OutputAccum
[STFT_SIZE
];
71 ALcomplex FFTbuffer
[STFT_SIZE
];
73 ALfrequencyDomain Analysis_buffer
[STFT_HALF_SIZE
+1];
74 ALfrequencyDomain Syntesis_buffer
[STFT_HALF_SIZE
+1];
76 alignas(16) ALfloat BufferOut
[BUFFERSIZE
];
78 /* Effect gains for each output channel */
79 ALfloat CurrentGains
[MAX_OUTPUT_CHANNELS
];
80 ALfloat TargetGains
[MAX_OUTPUT_CHANNELS
];
83 static ALvoid
ALpshifterState_Destruct(ALpshifterState
*state
);
84 static ALboolean
ALpshifterState_deviceUpdate(ALpshifterState
*state
, ALCdevice
*device
);
85 static ALvoid
ALpshifterState_update(ALpshifterState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
);
86 static ALvoid
ALpshifterState_process(ALpshifterState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
);
87 DECLARE_DEFAULT_ALLOCATORS(ALpshifterState
)
89 DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState
);
92 /* Define a Hann window, used to filter the STFT input and output. */
93 alignas(16) static ALdouble HannWindow
[STFT_SIZE
];
95 static void InitHannWindow(void)
99 /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */
100 for(i
= 0;i
< STFT_SIZE
>>1;i
++)
102 ALdouble val
= sin(M_PI
* (ALdouble
)i
/ (ALdouble
)(STFT_SIZE
-1));
103 HannWindow
[i
] = HannWindow
[STFT_SIZE
-1-i
] = val
* val
;
106 static alonce_flag HannInitOnce
= AL_ONCE_FLAG_INIT
;
109 /* Fast double-to-int conversion. Assumes the FPU is already in round-to-zero
111 static inline ALint
fastd2i(ALdouble d
)
113 /* NOTE: SSE2 is required for the efficient double-to-int opcodes on x86.
114 * Otherwise, we need to rely on x87's fistp opcode with it already in
115 * round-to-zero mode. x86-64 guarantees SSE2 support.
117 #if (defined(__i386__) && !defined(__SSE2_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP < 2))
120 #elif defined(_MSC_VER) && defined(_M_IX86)
134 /* Converts ALcomplex to ALphasor */
135 static inline ALphasor
rect2polar(ALcomplex number
)
139 polar
.Amplitude
= sqrt(number
.Real
*number
.Real
+ number
.Imag
*number
.Imag
);
140 polar
.Phase
= atan2(number
.Imag
, number
.Real
);
145 /* Converts ALphasor to ALcomplex */
146 static inline ALcomplex
polar2rect(ALphasor number
)
150 cartesian
.Real
= number
.Amplitude
* cos(number
.Phase
);
151 cartesian
.Imag
= number
.Amplitude
* sin(number
.Phase
);
156 /* Addition of two complex numbers (ALcomplex format) */
157 static inline ALcomplex
complex_add(ALcomplex a
, ALcomplex b
)
161 result
.Real
= a
.Real
+ b
.Real
;
162 result
.Imag
= a
.Imag
+ b
.Imag
;
167 /* Subtraction of two complex numbers (ALcomplex format) */
168 static inline ALcomplex
complex_sub(ALcomplex a
, ALcomplex b
)
172 result
.Real
= a
.Real
- b
.Real
;
173 result
.Imag
= a
.Imag
- b
.Imag
;
178 /* Multiplication of two complex numbers (ALcomplex format) */
179 static inline ALcomplex
complex_mult(ALcomplex a
, ALcomplex b
)
183 result
.Real
= a
.Real
*b
.Real
- a
.Imag
*b
.Imag
;
184 result
.Imag
= a
.Imag
*b
.Real
+ a
.Real
*b
.Imag
;
189 /* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is
190 * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the
191 * Discrete Fourier Transform (DFT) of the time domain data stored in
192 * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers
193 * (ALcomplex), FFTSize MUST BE power of two.
195 static inline ALvoid
FFT(ALcomplex
*FFTBuffer
, ALsizei FFTSize
, ALdouble Sign
)
197 ALsizei i
, j
, k
, mask
, step
, step2
;
198 ALcomplex temp
, u
, w
;
201 /* Bit-reversal permutation applied to a sequence of FFTSize items */
202 for(i
= 1;i
< FFTSize
-1;i
++)
204 for(mask
= 0x1, j
= 0;mask
< FFTSize
;mask
<<= 1)
215 FFTBuffer
[i
] = FFTBuffer
[j
];
220 /* Iterative form of Danielson–Lanczos lemma */
221 for(i
= 1, step
= 2;i
< FFTSize
;i
<<=1, step
<<=1)
227 w
.Imag
= sin(arg
) * Sign
;
232 for(j
= 0;j
< step2
;j
++)
234 for(k
= j
;k
< FFTSize
;k
+=step
)
236 temp
= complex_mult(FFTBuffer
[k
+step2
], u
);
237 FFTBuffer
[k
+step2
] = complex_sub(FFTBuffer
[k
], temp
);
238 FFTBuffer
[k
] = complex_add(FFTBuffer
[k
], temp
);
241 u
= complex_mult(u
, w
);
247 static void ALpshifterState_Construct(ALpshifterState
*state
)
249 ALeffectState_Construct(STATIC_CAST(ALeffectState
, state
));
250 SET_VTABLE2(ALpshifterState
, ALeffectState
, state
);
252 alcall_once(&HannInitOnce
, InitHannWindow
);
255 static ALvoid
ALpshifterState_Destruct(ALpshifterState
*state
)
257 ALeffectState_Destruct(STATIC_CAST(ALeffectState
,state
));
260 static ALboolean
ALpshifterState_deviceUpdate(ALpshifterState
*state
, ALCdevice
*device
)
262 /* (Re-)initializing parameters and clear the buffers. */
263 state
->count
= FIFO_LATENCY
;
264 state
->PitchShiftI
= FRACTIONONE
;
265 state
->PitchShift
= 1.0f
;
266 state
->FreqPerBin
= device
->Frequency
/ (ALfloat
)STFT_SIZE
;
268 memset(state
->InFIFO
, 0, sizeof(state
->InFIFO
));
269 memset(state
->OutFIFO
, 0, sizeof(state
->OutFIFO
));
270 memset(state
->FFTbuffer
, 0, sizeof(state
->FFTbuffer
));
271 memset(state
->LastPhase
, 0, sizeof(state
->LastPhase
));
272 memset(state
->SumPhase
, 0, sizeof(state
->SumPhase
));
273 memset(state
->OutputAccum
, 0, sizeof(state
->OutputAccum
));
274 memset(state
->Analysis_buffer
, 0, sizeof(state
->Analysis_buffer
));
275 memset(state
->Syntesis_buffer
, 0, sizeof(state
->Syntesis_buffer
));
277 memset(state
->CurrentGains
, 0, sizeof(state
->CurrentGains
));
278 memset(state
->TargetGains
, 0, sizeof(state
->TargetGains
));
283 static ALvoid
ALpshifterState_update(ALpshifterState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
)
285 const ALCdevice
*device
= context
->Device
;
286 ALfloat coeffs
[MAX_AMBI_COEFFS
];
290 (ALfloat
)(props
->Pshifter
.CoarseTune
*100 + props
->Pshifter
.FineTune
) / 1200.0f
292 state
->PitchShiftI
= (ALsizei
)(pitch
*FRACTIONONE
+ 0.5f
);
293 state
->PitchShift
= state
->PitchShiftI
* (1.0f
/FRACTIONONE
);
295 CalcAngleCoeffs(0.0f
, 0.0f
, 0.0f
, coeffs
);
296 ComputeDryPanGains(&device
->Dry
, coeffs
, slot
->Params
.Gain
, state
->TargetGains
);
299 static ALvoid
ALpshifterState_process(ALpshifterState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
)
301 /* Pitch shifter engine based on the work of Stephan Bernsee.
302 * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
305 static const ALdouble expected
= M_PI
*2.0 / OVERSAMP
;
306 const ALdouble freq_per_bin
= state
->FreqPerBin
;
307 ALfloat
*restrict bufferOut
= state
->BufferOut
;
308 ALsizei count
= state
->count
;
311 for(i
= 0;i
< SamplesToDo
;)
314 /* Fill FIFO buffer with samples data */
315 state
->InFIFO
[count
] = SamplesIn
[0][i
];
316 bufferOut
[i
] = state
->OutFIFO
[count
- FIFO_LATENCY
];
319 } while(++i
< SamplesToDo
&& count
< STFT_SIZE
);
321 /* Check whether FIFO buffer is filled */
322 if(count
< STFT_SIZE
) break;
323 count
= FIFO_LATENCY
;
325 /* Real signal windowing and store in FFTbuffer */
326 for(k
= 0;k
< STFT_SIZE
;k
++)
328 state
->FFTbuffer
[k
].Real
= state
->InFIFO
[k
] * HannWindow
[k
];
329 state
->FFTbuffer
[k
].Imag
= 0.0;
333 /* Apply FFT to FFTbuffer data */
334 FFT(state
->FFTbuffer
, STFT_SIZE
, -1.0);
336 /* Analyze the obtained data. Since the real FFT is symmetric, only
337 * STFT_HALF_SIZE+1 samples are needed.
339 for(k
= 0;k
< STFT_HALF_SIZE
+1;k
++)
345 /* Compute amplitude and phase */
346 component
= rect2polar(state
->FFTbuffer
[k
]);
348 /* Compute phase difference and subtract expected phase difference */
349 tmp
= (component
.Phase
- state
->LastPhase
[k
]) - k
*expected
;
351 /* Map delta phase into +/- Pi interval */
352 qpd
= fastd2i(tmp
/ M_PI
);
353 tmp
-= M_PI
* (qpd
+ (qpd
%2));
355 /* Get deviation from bin frequency from the +/- Pi interval */
358 /* Compute the k-th partials' true frequency, twice the amplitude
359 * for maintain the gain (because half of bins are used) and store
360 * amplitude and true frequency in analysis buffer.
362 state
->Analysis_buffer
[k
].Amplitude
= 2.0 * component
.Amplitude
;
363 state
->Analysis_buffer
[k
].Frequency
= (k
+ tmp
) * freq_per_bin
;
365 /* Store actual phase[k] for the calculations in the next frame*/
366 state
->LastPhase
[k
] = component
.Phase
;
371 for(k
= 0;k
< STFT_HALF_SIZE
+1;k
++)
373 state
->Syntesis_buffer
[k
].Amplitude
= 0.0;
374 state
->Syntesis_buffer
[k
].Frequency
= 0.0;
377 for(k
= 0;k
< STFT_HALF_SIZE
+1;k
++)
379 j
= (k
*state
->PitchShiftI
) >> FRACTIONBITS
;
380 if(j
>= STFT_HALF_SIZE
+1) break;
382 state
->Syntesis_buffer
[j
].Amplitude
+= state
->Analysis_buffer
[k
].Amplitude
;
383 state
->Syntesis_buffer
[j
].Frequency
= state
->Analysis_buffer
[k
].Frequency
*
388 /* Synthesis the processing data */
389 for(k
= 0;k
< STFT_HALF_SIZE
+1;k
++)
394 /* Compute bin deviation from scaled freq */
395 tmp
= state
->Syntesis_buffer
[k
].Frequency
/freq_per_bin
- k
;
397 /* Calculate actual delta phase and accumulate it to get bin phase */
398 state
->SumPhase
[k
] += (k
+ tmp
) * expected
;
400 component
.Amplitude
= state
->Syntesis_buffer
[k
].Amplitude
;
401 component
.Phase
= state
->SumPhase
[k
];
403 /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/
404 state
->FFTbuffer
[k
] = polar2rect(component
);
406 /* zero negative frequencies for recontruct a real signal */
407 for(k
= STFT_HALF_SIZE
+1;k
< STFT_SIZE
;k
++)
409 state
->FFTbuffer
[k
].Real
= 0.0;
410 state
->FFTbuffer
[k
].Imag
= 0.0;
413 /* Apply iFFT to buffer data */
414 FFT(state
->FFTbuffer
, STFT_SIZE
, 1.0);
416 /* Windowing and add to output */
417 for(k
= 0;k
< STFT_SIZE
;k
++)
418 state
->OutputAccum
[k
] += HannWindow
[k
] * state
->FFTbuffer
[k
].Real
/
419 (0.5 * STFT_HALF_SIZE
* OVERSAMP
);
421 /* Shift accumulator, input & output FIFO */
422 for(k
= 0;k
< STFT_STEP
;k
++) state
->OutFIFO
[k
] = (ALfloat
)state
->OutputAccum
[k
];
423 for(j
= 0;k
< STFT_SIZE
;k
++,j
++) state
->OutputAccum
[j
] = state
->OutputAccum
[k
];
424 for(;j
< STFT_SIZE
;j
++) state
->OutputAccum
[j
] = 0.0;
425 for(k
= 0;k
< FIFO_LATENCY
;k
++)
426 state
->InFIFO
[k
] = state
->InFIFO
[k
+STFT_STEP
];
428 state
->count
= count
;
430 /* Now, mix the processed sound data to the output. */
431 MixSamples(bufferOut
, NumChannels
, SamplesOut
, state
->CurrentGains
, state
->TargetGains
,
432 maxi(SamplesToDo
, 512), 0, SamplesToDo
);
435 typedef struct PshifterStateFactory
{
436 DERIVE_FROM_TYPE(EffectStateFactory
);
437 } PshifterStateFactory
;
439 static ALeffectState
*PshifterStateFactory_create(PshifterStateFactory
*UNUSED(factory
))
441 ALpshifterState
*state
;
443 NEW_OBJ0(state
, ALpshifterState
)();
444 if(!state
) return NULL
;
446 return STATIC_CAST(ALeffectState
, state
);
449 DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory
);
451 EffectStateFactory
*PshifterStateFactory_getFactory(void)
453 static PshifterStateFactory PshifterFactory
= { { GET_VTABLE2(PshifterStateFactory
, EffectStateFactory
) } };
455 return STATIC_CAST(EffectStateFactory
, &PshifterFactory
);
459 void ALpshifter_setParamf(ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum param
, ALfloat
UNUSED(val
))
461 alSetError( context
, AL_INVALID_ENUM
, "Invalid pitch shifter float property 0x%04x", param
);
464 void ALpshifter_setParamfv(ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum param
, const ALfloat
*UNUSED(vals
))
466 alSetError( context
, AL_INVALID_ENUM
, "Invalid pitch shifter float-vector property 0x%04x", param
);
469 void ALpshifter_setParami(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint val
)
471 ALeffectProps
*props
= &effect
->Props
;
474 case AL_PITCH_SHIFTER_COARSE_TUNE
:
475 if(!(val
>= AL_PITCH_SHIFTER_MIN_COARSE_TUNE
&& val
<= AL_PITCH_SHIFTER_MAX_COARSE_TUNE
))
476 SETERR_RETURN(context
, AL_INVALID_VALUE
,,"Pitch shifter coarse tune out of range");
477 props
->Pshifter
.CoarseTune
= val
;
480 case AL_PITCH_SHIFTER_FINE_TUNE
:
481 if(!(val
>= AL_PITCH_SHIFTER_MIN_FINE_TUNE
&& val
<= AL_PITCH_SHIFTER_MAX_FINE_TUNE
))
482 SETERR_RETURN(context
, AL_INVALID_VALUE
,,"Pitch shifter fine tune out of range");
483 props
->Pshifter
.FineTune
= val
;
487 alSetError(context
, AL_INVALID_ENUM
, "Invalid pitch shifter integer property 0x%04x", param
);
490 void ALpshifter_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
492 ALpshifter_setParami(effect
, context
, param
, vals
[0]);
495 void ALpshifter_getParami(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*val
)
497 const ALeffectProps
*props
= &effect
->Props
;
500 case AL_PITCH_SHIFTER_COARSE_TUNE
:
501 *val
= (ALint
)props
->Pshifter
.CoarseTune
;
503 case AL_PITCH_SHIFTER_FINE_TUNE
:
504 *val
= (ALint
)props
->Pshifter
.FineTune
;
508 alSetError(context
, AL_INVALID_ENUM
, "Invalid pitch shifter integer property 0x%04x", param
);
511 void ALpshifter_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
513 ALpshifter_getParami(effect
, context
, param
, vals
);
516 void ALpshifter_getParamf(const ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum param
, ALfloat
*UNUSED(val
))
518 alSetError(context
, AL_INVALID_ENUM
, "Invalid pitch shifter float property 0x%04x", param
);
521 void ALpshifter_getParamfv(const ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum param
, ALfloat
*UNUSED(vals
))
523 alSetError(context
, AL_INVALID_ENUM
, "Invalid pitch shifter float vector-property 0x%04x", param
);
526 DEFINE_ALEFFECT_VTABLE(ALpshifter
);