DSPark 1.8.0
Header-only C++20 DSP for real-time and offline audio
Loading...
Searching...
No Matches
OfflineConvolutionWindow.h
1// DSPark - Professional Audio DSP Framework
2// Copyright (c) 2026 Cristian Moresi - MIT License
3
4#pragma once
5
11#include "../OfflineProcessing.h"
12#if DSPARK_HAS_OFFLINE
13#include "../FFT.h"
14#include "../SimdOps.h"
15#include <algorithm>
16#include <cmath>
17#include <cstdint>
18#include <memory>
19#include <optional>
20
21namespace dspark::detail
22{
24{
25 public:
26 // For input x[0,3B), return y[i] = sum_j h[B+i-j]*x[j], i in [0,B).
27 // Only lags [-2B+1,2B-1] occur. A 4B circular embedding represents every
28 // one of them without collision. Other output positions are discarded.
29 template <class Impulse>
30 OfflineConvolutionWindow(OfflineSession &job, int block, Impulse impulse) : block_(block)
31 {
32 if (block < 128 || block > 65536 || (block & (block - 1)))
34 const auto size = 4 * static_cast<std::uint64_t>(block);
35 time_ = job.allocateScratch<double>(size + 2);
36 spectrum_ = job.allocateScratch<double>(size + 2);
37 kernel_ = job.allocateScratch<double>(size + 2);
38 // The Core real FFT requests <4N doubles. Include cumulative Stockham
39 // plan-vector growth and implementation-specific allocation bookkeeping.
40 job.charge(offlineBytes(4 * size, sizeof(double)) + 2048);
41 fft_.emplace(static_cast<std::size_t>(size));
42 for (int i = 0; i < 4 * block; ++i)
43 {
44 const int lag = i < 2 * block ? i : i - 4 * block;
45 const double value = i == 2 * block ? 0 : impulse(lag);
46 if (!std::isfinite(value))
48 time_[i] = value;
49 }
50 fft_->forward(time_.get(), kernel_.get());
51 for (std::uint64_t i = 0; i < size + 2; ++i)
52 if (!std::isfinite(kernel_[i]))
54 }
57
58 // Fill all 3B finite, normalized input values before each process call.
59 [[nodiscard]] double *input() noexcept
60 {
61 return time_.get();
62 }
63 [[nodiscard]] const double *process() noexcept
64 {
65 const int size = 4 * block_;
66 std::fill_n(time_.get() + 3 * block_, block_ + 2, 0.);
67 fft_->forward(time_.get(), spectrum_.get());
68 std::fill_n(time_.get(), size + 2, 0.);
69 simd::complexMulAccum(time_.get(), spectrum_.get(), kernel_.get(), size / 2 + 1);
70 fft_->inverse(time_.get(), time_.get());
71 return time_.get() + block_;
72 }
73
74 private:
75 int block_;
76 OfflineScratchArray<double> time_, spectrum_, kernel_;
77 std::optional<FFTReal<double>> fft_;
78};
79} // namespace dspark::detail
80#endif // DSPARK_HAS_OFFLINE
OfflineConvolutionWindow(const OfflineConvolutionWindow &)=delete
OfflineConvolutionWindow(OfflineSession &job, int block, Impulse impulse)
OfflineConvolutionWindow & operator=(const OfflineConvolutionWindow &)=delete
void charge(std::size_t bytes)
OfflineScratchArray< U > allocateScratch(std::uint64_t count)
void offlineFail(OfflineStatus status)
std::unique_ptr< T[], OfflineScratchDeleter< T > > OfflineScratchArray
std::size_t offlineBytes(std::uint64_t count, std::size_t size)
void complexMulAccum(float *DSPARK_RESTRICT accum, const float *DSPARK_RESTRICT a, const float *DSPARK_RESTRICT b, int bins) noexcept
Complex multiply-accumulate over interleaved [re, im, ...] spectra.
Definition SimdOps.h:1039