diff options
author | Sven Göthel <[email protected]> | 2024-01-05 13:52:12 +0100 |
---|---|---|
committer | Sven Göthel <[email protected]> | 2024-01-05 13:52:12 +0100 |
commit | ec98cdacc85ff0202852472c7756586437912f22 (patch) | |
tree | 42414746a27ab35cb8cdbc95af521d74821e57f4 /core/uhjfilter.cpp | |
parent | fd5269bec9a5fe4815974b1786a037e6a247bfd2 (diff) | |
parent | b82cd2e60edb8fbe5fdd3567105ae76a016a554c (diff) |
Diffstat (limited to 'core/uhjfilter.cpp')
-rw-r--r-- | core/uhjfilter.cpp | 37 |
1 files changed, 15 insertions, 22 deletions
diff --git a/core/uhjfilter.cpp b/core/uhjfilter.cpp index 28999e09..681b0abc 100644 --- a/core/uhjfilter.cpp +++ b/core/uhjfilter.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include <iterator> +#include <vector> #include "alcomplex.h" #include "alnumeric.h" @@ -20,11 +21,6 @@ UhjQualityType UhjEncodeQuality{UhjQualityType::Default}; namespace { -struct PFFFTSetupDeleter { - void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); } -}; -using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>; - /* Convolution is implemented using a segmented overlap-add method. The filter * response is broken up into multiple segments of 128 samples, and each * segment has an FFT applied with a 256-sample buffer (the latter half left @@ -57,13 +53,11 @@ struct SegmentedFilter { static_assert(N >= sFftLength); static_assert((N % sSampleLength) == 0); - PFFFTSetupPtr mFft; + PFFFTSetup mFft; alignas(16) std::array<float,sFftLength*sNumSegments> mFilterData; - SegmentedFilter() + SegmentedFilter() : mFft{sFftLength, PFFFT_REAL} { - mFft = PFFFTSetupPtr{pffft_new_setup(sFftLength, PFFFT_REAL)}; - using complex_d = std::complex<double>; constexpr size_t fft_size{N}; constexpr size_t half_size{fft_size / 2}; @@ -71,8 +65,7 @@ struct SegmentedFilter { /* To set up the filter, we need to generate the desired response. * Start with a pure delay that passes all frequencies through. */ - auto fftBuffer = std::make_unique<complex_d[]>(fft_size); - std::fill_n(fftBuffer.get(), fft_size, complex_d{}); + auto fftBuffer = std::vector<complex_d>(fft_size, complex_d{}); fftBuffer[half_size] = 1.0; /* Convert to the frequency domain, shift the phase of each bin by +90 @@ -82,27 +75,27 @@ struct SegmentedFilter { * To maintain that and their phase (0 or pi), they're heavily * attenuated instead of shifted like the others. */ - forward_fft(al::span{fftBuffer.get(), fft_size}); + forward_fft(al::span{fftBuffer}); fftBuffer[0] *= std::numeric_limits<double>::epsilon(); for(size_t i{1};i < half_size;++i) fftBuffer[i] = complex_d{-fftBuffer[i].imag(), fftBuffer[i].real()}; fftBuffer[half_size] *= std::numeric_limits<double>::epsilon(); for(size_t i{half_size+1};i < fft_size;++i) fftBuffer[i] = std::conj(fftBuffer[fft_size - i]); - inverse_fft(al::span{fftBuffer.get(), fft_size}); + inverse_fft(al::span{fftBuffer}); /* The segments of the filter are converted back to the frequency * domain, each on their own (0 stuffed). */ - auto fftBuffer2 = std::make_unique<complex_d[]>(sFftLength); + auto fftBuffer2 = std::vector<complex_d>(sFftLength); auto fftTmp = al::vector<float,16>(sFftLength); float *filter{mFilterData.data()}; for(size_t s{0};s < sNumSegments;++s) { for(size_t i{0};i < sSampleLength;++i) fftBuffer2[i] = fftBuffer[sSampleLength*s + i].real() / double{fft_size}; - std::fill_n(fftBuffer2.get()+sSampleLength, sSampleLength, complex_d{}); - forward_fft(al::span{fftBuffer2.get(), sFftLength}); + std::fill_n(fftBuffer2.data()+sSampleLength, sSampleLength, complex_d{}); + forward_fft(al::span{fftBuffer2}); /* Convert to zdomain data for PFFFT, scaled by the FFT length so * the iFFT result will be normalized. @@ -113,7 +106,7 @@ struct SegmentedFilter { fftTmp[i*2 + 1] = static_cast<float>((i == 0) ? fftBuffer2[sSampleLength].real() : fftBuffer2[i].imag()) / float{sFftLength}; } - pffft_zreorder(mFft.get(), fftTmp.data(), filter, PFFFT_BACKWARD); + mFft.zreorder(fftTmp.data(), filter, PFFFT_BACKWARD); filter += sFftLength; } } @@ -246,7 +239,7 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut, std::copy_n(mWXInOut.begin(), sSegmentSize, input); std::fill_n(input+sSegmentSize, sSegmentSize, 0.0f); - pffft_transform(Filter.mFft.get(), input, input, mWorkData.data(), PFFFT_FORWARD); + Filter.mFft.transform(input, input, mWorkData.data(), PFFFT_FORWARD); /* Convolve each input segment with its IR filter counterpart (aligned * in time, from newest to oldest). @@ -255,14 +248,14 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut, const float *filter{Filter.mFilterData.data()}; for(size_t s{curseg};s < sNumSegments;++s) { - pffft_zconvolve_accumulate(Filter.mFft.get(), input, filter, mFftBuffer.data()); + Filter.mFft.zconvolve_accumulate(input, filter, mFftBuffer.data()); input += sFftLength; filter += sFftLength; } input = mWXHistory.data(); for(size_t s{0};s < curseg;++s) { - pffft_zconvolve_accumulate(Filter.mFft.get(), input, filter, mFftBuffer.data()); + Filter.mFft.zconvolve_accumulate(input, filter, mFftBuffer.data()); input += sFftLength; filter += sFftLength; } @@ -270,8 +263,8 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut, /* Convert back to samples, writing to the output and storing the extra * for next time. */ - pffft_transform(Filter.mFft.get(), mFftBuffer.data(), mFftBuffer.data(), - mWorkData.data(), PFFFT_BACKWARD); + Filter.mFft.transform(mFftBuffer.data(), mFftBuffer.data(), mWorkData.data(), + PFFFT_BACKWARD); for(size_t i{0};i < sSegmentSize;++i) mWXInOut[i] = mFftBuffer[i] + mWXInOut[sSegmentSize+i]; |