aboutsummaryrefslogtreecommitdiffstats
path: root/alc/effects/fshifter.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-01-19 13:30:00 -0800
committerChris Robinson <[email protected]>2023-01-19 13:30:00 -0800
commitd6e79c9023ad66986fcfe16caef15d8e8b14a20f (patch)
treefc5484966fdd317e238f673c032cfd7275e3c542 /alc/effects/fshifter.cpp
parent5069f042fa8478648214a7038d87ae976a041751 (diff)
Minor code refactor for the frequency shifter effect
Diffstat (limited to 'alc/effects/fshifter.cpp')
-rw-r--r--alc/effects/fshifter.cpp97
1 files changed, 50 insertions, 47 deletions
diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp
index 5d899aed..4bdb53a7 100644
--- a/alc/effects/fshifter.cpp
+++ b/alc/effects/fshifter.cpp
@@ -48,44 +48,47 @@ namespace {
using uint = unsigned int;
using complex_d = std::complex<double>;
-#define HIL_SIZE 1024
-#define OVERSAMP (1<<2)
+constexpr size_t HilSize{1024};
+constexpr size_t HilHalfSize{HilSize >> 1};
+constexpr size_t OversampleFactor{4};
-#define HIL_STEP (HIL_SIZE / OVERSAMP)
-#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1))
+static_assert(HilSize%OversampleFactor == 0, "Factor must be a clean divisor of the size");
+constexpr size_t HilStep{HilSize / OversampleFactor};
/* Define a Hann window, used to filter the HIL input and output. */
-std::array<double,HIL_SIZE> InitHannWindow()
-{
- std::array<double,HIL_SIZE> ret;
- /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
- for(size_t i{0};i < HIL_SIZE>>1;i++)
+struct Windower {
+ alignas(16) std::array<double,HilSize> mData;
+
+ Windower()
{
- constexpr double scale{al::numbers::pi / double{HIL_SIZE}};
- const double val{std::sin((static_cast<double>(i)+0.5) * scale)};
- ret[i] = ret[HIL_SIZE-1-i] = val * val;
+ /* Create lookup table of the Hann window for the desired size. */
+ for(size_t i{0};i < HilHalfSize;i++)
+ {
+ constexpr double scale{al::numbers::pi / double{HilSize}};
+ const double val{std::sin((static_cast<double>(i)+0.5) * scale)};
+ mData[i] = mData[HilSize-1-i] = val * val;
+ }
}
- return ret;
-}
-alignas(16) const std::array<double,HIL_SIZE> HannWindow = InitHannWindow();
+};
+const Windower gWindow{};
struct FshifterState final : public EffectState {
/* Effect parameters */
size_t mCount{};
size_t mPos{};
- uint mPhaseStep[2]{};
- uint mPhase[2]{};
- double mSign[2]{};
+ std::array<uint,2> mPhaseStep{};
+ std::array<uint,2> mPhase{};
+ std::array<double,2> mSign{};
/* Effects buffers */
- double mInFIFO[HIL_SIZE]{};
- complex_d mOutFIFO[HIL_STEP]{};
- complex_d mOutputAccum[HIL_SIZE]{};
- complex_d mAnalytic[HIL_SIZE]{};
- complex_d mOutdata[BufferLineSize]{};
+ std::array<double,HilSize> mInFIFO{};
+ std::array<complex_d,HilStep> mOutFIFO{};
+ std::array<complex_d,HilSize> mOutputAccum{};
+ std::array<complex_d,HilSize> mAnalytic{};
+ std::array<complex_d,BufferLineSize> mOutdata{};
- alignas(16) float mBufferOut[BufferLineSize]{};
+ alignas(16) FloatBufferLine mBufferOut{};
/* Effect gains for each output channel */
struct {
@@ -107,15 +110,15 @@ void FshifterState::deviceUpdate(const DeviceBase*, const Buffer&)
{
/* (Re-)initializing parameters and clear the buffers. */
mCount = 0;
- mPos = FIFO_LATENCY;
+ mPos = HilSize - HilStep;
- std::fill(std::begin(mPhaseStep), std::end(mPhaseStep), 0u);
- std::fill(std::begin(mPhase), std::end(mPhase), 0u);
- std::fill(std::begin(mSign), std::end(mSign), 1.0);
- std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0);
- std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{});
- std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{});
- std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{});
+ mPhaseStep.fill(0u);
+ mPhase.fill(0u);
+ mSign.fill(1.0);
+ mInFIFO.fill(0.0);
+ mOutFIFO.fill(complex_d{});
+ mOutputAccum.fill(complex_d{});
+ mAnalytic.fill(complex_d{});
for(auto &gain : mGains)
{
@@ -172,7 +175,7 @@ void FshifterState::process(const size_t samplesToDo, const al::span<const Float
{
for(size_t base{0u};base < samplesToDo;)
{
- size_t todo{minz(HIL_STEP-mCount, samplesToDo-base)};
+ size_t todo{minz(HilStep-mCount, samplesToDo-base)};
/* Fill FIFO buffer with samples data */
const size_t pos{mPos};
@@ -185,33 +188,33 @@ void FshifterState::process(const size_t samplesToDo, const al::span<const Float
mCount = count;
/* Check whether FIFO buffer is filled */
- if(mCount < HIL_STEP) break;
+ if(mCount < HilStep) break;
mCount = 0;
- mPos = (mPos+HIL_STEP) & (HIL_SIZE-1);
+ mPos = (mPos+HilStep) & (HilSize-1);
/* Real signal windowing and store in Analytic buffer */
- for(size_t src{mPos}, k{0u};src < HIL_SIZE;++src,++k)
- mAnalytic[k] = mInFIFO[src]*HannWindow[k];
- for(size_t src{0u}, k{HIL_SIZE-mPos};src < mPos;++src,++k)
- mAnalytic[k] = mInFIFO[src]*HannWindow[k];
+ for(size_t src{mPos}, k{0u};src < HilSize;++src,++k)
+ mAnalytic[k] = mInFIFO[src]*gWindow.mData[k];
+ for(size_t src{0u}, k{HilSize-mPos};src < mPos;++src,++k)
+ mAnalytic[k] = mInFIFO[src]*gWindow.mData[k];
/* Processing signal by Discrete Hilbert Transform (analytical signal). */
complex_hilbert(mAnalytic);
/* Windowing and add to output accumulator */
- for(size_t dst{mPos}, k{0u};dst < HIL_SIZE;++dst,++k)
- mOutputAccum[dst] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];
- for(size_t dst{0u}, k{HIL_SIZE-mPos};dst < mPos;++dst,++k)
- mOutputAccum[dst] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];
+ for(size_t dst{mPos}, k{0u};dst < HilSize;++dst,++k)
+ mOutputAccum[dst] += 2.0/OversampleFactor*gWindow.mData[k]*mAnalytic[k];
+ for(size_t dst{0u}, k{HilSize-mPos};dst < mPos;++dst,++k)
+ mOutputAccum[dst] += 2.0/OversampleFactor*gWindow.mData[k]*mAnalytic[k];
/* Copy out the accumulated result, then clear for the next iteration. */
- std::copy_n(mOutputAccum + mPos, HIL_STEP, mOutFIFO);
- std::fill_n(mOutputAccum + mPos, HIL_STEP, complex_d{});
+ std::copy_n(mOutputAccum.cbegin() + mPos, HilStep, mOutFIFO.begin());
+ std::fill_n(mOutputAccum.begin() + mPos, HilStep, complex_d{});
}
/* Process frequency shifter using the analytic signal obtained. */
- float *RESTRICT BufferOut{mBufferOut};
- for(int c{0};c < 2;++c)
+ float *RESTRICT BufferOut{al::assume_aligned<16>(mBufferOut.data())};
+ for(size_t c{0};c < 2;++c)
{
const uint phase_step{mPhaseStep[c]};
uint phase_idx{mPhase[c]};