diff options
Diffstat (limited to 'Alc/effects/pshifter.cpp')
-rw-r--r-- | Alc/effects/pshifter.cpp | 161 |
1 files changed, 80 insertions, 81 deletions
diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index d3a399ff..410eb982 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -20,8 +20,8 @@ #include "config.h" -#include <math.h> -#include <stdlib.h> +#include <cmath> +#include <cstdlib> #include "alMain.h" #include "alAuxEffectSlot.h" @@ -32,6 +32,8 @@ #include "alcomplex.h" +namespace { + #define STFT_SIZE 1024 #define STFT_HALF_SIZE (STFT_SIZE>>1) #define OVERSAMP (1<<2) @@ -39,71 +41,7 @@ #define STFT_STEP (STFT_SIZE / OVERSAMP) #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) - -typedef struct ALphasor { - ALdouble Amplitude; - ALdouble Phase; -} ALphasor; - -typedef struct ALFrequencyDomain { - ALdouble Amplitude; - ALdouble Frequency; -} ALfrequencyDomain; - - -struct ALpshifterState final : public ALeffectState { - /* Effect parameters */ - ALsizei count; - ALsizei PitchShiftI; - ALfloat PitchShift; - ALfloat FreqPerBin; - - /*Effects buffers*/ - ALfloat InFIFO[STFT_SIZE]; - ALfloat OutFIFO[STFT_STEP]; - ALdouble LastPhase[STFT_HALF_SIZE+1]; - ALdouble SumPhase[STFT_HALF_SIZE+1]; - ALdouble OutputAccum[STFT_SIZE]; - - ALcomplex FFTbuffer[STFT_SIZE]; - - ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; - ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; -}; - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state); -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); - - -/* Define a Hann window, used to filter the STFT input and output. */ -alignas(16) static ALdouble HannWindow[STFT_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */ - for(i = 0;i < STFT_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); - HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val; - } -} -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - - -static inline ALint double2int(ALdouble d) +inline ALint double2int(ALdouble d) { #if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) @@ -133,46 +71,105 @@ static inline ALint double2int(ALdouble d) #endif } +/* Define a Hann window, used to filter the STFT input and output. */ +/* Making this constexpr seems to require C++14. */ +std::array<ALdouble,STFT_SIZE> InitHannWindow(void) +{ + std::array<ALdouble,STFT_SIZE> ret; + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(ALsizei i{0};i < STFT_SIZE>>1;i++) + { + ALdouble val = std::sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); + ret[i] = ret[STFT_SIZE-1-i] = val * val; + } + return ret; +} +alignas(16) const std::array<ALdouble,STFT_SIZE> HannWindow = InitHannWindow(); + + +struct ALphasor { + ALdouble Amplitude; + ALdouble Phase; +}; + +struct ALfrequencyDomain { + ALdouble Amplitude; + ALdouble Frequency; +}; + /* Converts ALcomplex to ALphasor */ -static inline ALphasor rect2polar(ALcomplex number) +inline ALphasor rect2polar(ALcomplex number) { ALphasor polar; - polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag); - polar.Phase = atan2(number.Imag, number.Real); + polar.Amplitude = std::sqrt(number.Real*number.Real + number.Imag*number.Imag); + polar.Phase = std::atan2(number.Imag, number.Real); return polar; } /* Converts ALphasor to ALcomplex */ -static inline ALcomplex polar2rect(ALphasor number) +inline ALcomplex polar2rect(ALphasor number) { ALcomplex cartesian; - cartesian.Real = number.Amplitude * cos(number.Phase); - cartesian.Imag = number.Amplitude * sin(number.Phase); + cartesian.Real = number.Amplitude * std::cos(number.Phase); + cartesian.Imag = number.Amplitude * std::sin(number.Phase); return cartesian; } -static void ALpshifterState_Construct(ALpshifterState *state) + +struct ALpshifterState final : public ALeffectState { + /* Effect parameters */ + ALsizei count; + ALsizei PitchShiftI; + ALfloat PitchShift; + ALfloat FreqPerBin; + + /*Effects buffers*/ + ALfloat InFIFO[STFT_SIZE]; + ALfloat OutFIFO[STFT_STEP]; + ALdouble LastPhase[STFT_HALF_SIZE+1]; + ALdouble SumPhase[STFT_HALF_SIZE+1]; + ALdouble OutputAccum[STFT_SIZE]; + + ALcomplex FFTbuffer[STFT_SIZE]; + + ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +}; + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state); +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + +void ALpshifterState_Construct(ALpshifterState *state) { new (state) ALpshifterState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); } -static ALvoid ALpshifterState_Destruct(ALpshifterState *state) +ALvoid ALpshifterState_Destruct(ALpshifterState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALpshifterState(); } -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) +ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; @@ -195,13 +192,13 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice return AL_TRUE; } -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; float pitch; - pitch = powf(2.0f, + pitch = std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); state->PitchShiftI = fastf2i(pitch*FRACTIONONE); @@ -211,7 +208,7 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -347,6 +344,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD maxi(SamplesToDo, 512), 0, SamplesToDo); } +} // namespace + struct PshifterStateFactory final : public EffectStateFactory { PshifterStateFactory() noexcept; }; |