diff options
author | Chris Robinson <[email protected]> | 2023-10-25 16:29:01 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-10-25 16:29:01 -0700 |
commit | 62e0d9125f98b8dd174c9fabce81ab633b66b2df (patch) | |
tree | 233504d3dce8a76fb8e8d33a872af9f3a34a4cd4 /alc/effects/pshifter.cpp | |
parent | a90d8a6f92536111b970e12b4c83da8a82e48f2f (diff) |
Use PFFFT for the pitch shifter
Diffstat (limited to 'alc/effects/pshifter.cpp')
-rw-r--r-- | alc/effects/pshifter.cpp | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index 95269009..0c27be30 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -28,7 +28,6 @@ #include <iterator> #include "alc/effects/base.h" -#include "alcomplex.h" #include "almalloc.h" #include "alnumbers.h" #include "alnumeric.h" @@ -40,6 +39,7 @@ #include "core/mixer.h" #include "core/mixer/defs.h" #include "intrusive_ptr.h" +#include "pffft.h" struct ContextBase; @@ -74,6 +74,12 @@ struct Windower { const Windower gWindow{}; +struct PFFFTSetupDeleter { + void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); } +}; +using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>; + + struct FrequencyBin { float Magnitude; float FreqBin; @@ -93,7 +99,9 @@ struct PshifterState final : public EffectState { std::array<float,StftHalfSize+1> mSumPhase; std::array<float,StftSize> mOutputAccum; - std::array<complex_f,StftSize> mFftBuffer; + PFFFTSetupPtr mFft; + alignas(16) std::array<float,StftSize> mFftBuffer; + alignas(16) std::array<float,StftSize> mFftWorkBuffer; std::array<FrequencyBin,StftHalfSize+1> mAnalysisBuffer; std::array<FrequencyBin,StftHalfSize+1> mSynthesisBuffer; @@ -126,12 +134,15 @@ void PshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*) mLastPhase.fill(0.0f); mSumPhase.fill(0.0f); mOutputAccum.fill(0.0f); - mFftBuffer.fill(complex_f{}); + mFftBuffer.fill(0.0f); mAnalysisBuffer.fill(FrequencyBin{}); mSynthesisBuffer.fill(FrequencyBin{}); std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); + + if(!mFft) + mFft = PFFFTSetupPtr{pffft_new_setup(StftSize, PFFFT_REAL)}; } void PshifterState::update(const ContextBase*, const EffectSlot *slot, @@ -186,15 +197,19 @@ void PshifterState::process(const size_t samplesToDo, mFftBuffer[k] = mFIFO[src] * gWindow.mData[k]; for(size_t src{0u}, k{StftSize-mPos};src < mPos;++src,++k) mFftBuffer[k] = mFIFO[src] * gWindow.mData[k]; - forward_fft(al::span{mFftBuffer}); + pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(), + mFftWorkBuffer.data(), PFFFT_FORWARD); /* Analyze the obtained data. Since the real FFT is symmetric, only * StftHalfSize+1 samples are needed. */ - for(size_t k{0u};k < StftHalfSize+1;k++) + for(size_t k{0u};k < StftHalfSize+1;++k) { - const float magnitude{std::abs(mFftBuffer[k])}; - const float phase{std::arg(mFftBuffer[k])}; + const auto cplx = (k == 0) ? complex_f{mFftBuffer[0]} : + (k == StftHalfSize) ? complex_f{mFftBuffer[1]} : + complex_f{mFftBuffer[k*2], mFftBuffer[k*2 + 1]}; + const float magnitude{std::abs(cplx)}; + const float phase{std::arg(cplx)}; /* Compute the phase difference from the last update and subtract * the expected phase difference for this bin. @@ -266,21 +281,29 @@ void PshifterState::process(const size_t samplesToDo, tmp -= static_cast<float>(qpd + (qpd%2)); mSumPhase[k] = tmp * al::numbers::pi_v<float>; - mFftBuffer[k] = std::polar(mSynthesisBuffer[k].Magnitude, mSumPhase[k]); + const complex_f cplx{std::polar(mSynthesisBuffer[k].Magnitude, mSumPhase[k])}; + if(k == 0) + mFftBuffer[0] = cplx.real(); + else if(k == StftHalfSize) + mFftBuffer[1] = cplx.real(); + else + { + mFftBuffer[k*2 + 0] = cplx.real(); + mFftBuffer[k*2 + 1] = cplx.imag(); + } } - for(size_t k{StftHalfSize+1};k < StftSize;++k) - mFftBuffer[k] = std::conj(mFftBuffer[StftSize-k]); /* Apply an inverse FFT to get the time-domain signal, and accumulate * for the output with windowing. */ - inverse_fft(al::span{mFftBuffer}); + pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(), + mFftWorkBuffer.data(), PFFFT_BACKWARD); static constexpr float scale{3.0f / OversampleFactor / StftSize}; for(size_t dst{mPos}, k{0u};dst < StftSize;++dst,++k) - mOutputAccum[dst] += gWindow.mData[k]*mFftBuffer[k].real() * scale; + mOutputAccum[dst] += gWindow.mData[k]*mFftBuffer[k] * scale; for(size_t dst{0u}, k{StftSize-mPos};dst < mPos;++dst,++k) - mOutputAccum[dst] += gWindow.mData[k]*mFftBuffer[k].real() * scale; + mOutputAccum[dst] += gWindow.mData[k]*mFftBuffer[k] * scale; /* Copy out the accumulated result, then clear for the next iteration. */ std::copy_n(mOutputAccum.begin() + mPos, StftStep, mFIFO.begin() + mPos); |