aboutsummaryrefslogtreecommitdiffstats
path: root/alc/effects/pshifter.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-10-25 16:29:01 -0700
committerChris Robinson <[email protected]>2023-10-25 16:29:01 -0700
commit62e0d9125f98b8dd174c9fabce81ab633b66b2df (patch)
tree233504d3dce8a76fb8e8d33a872af9f3a34a4cd4 /alc/effects/pshifter.cpp
parenta90d8a6f92536111b970e12b4c83da8a82e48f2f (diff)
Use PFFFT for the pitch shifter
Diffstat (limited to 'alc/effects/pshifter.cpp')
-rw-r--r--alc/effects/pshifter.cpp49
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);