DSPark 1.8.0
Header-only C++20 DSP for real-time and offline audio
Loading...
Searching...
No Matches
ContinuousStereoColor.h
1// DSPark - Professional Audio DSP Framework
2// Copyright (c) 2026 Cristian Moresi - MIT License
3
4#pragma once
5
21#include "../FIRFilter.h"
22#include "ContinuousClip.h"
23#include "DcBlock.h"
24#include "StereoColorCoefficients.h"
25#include <algorithm>
26#include <array>
27#include <cassert>
28#include <cmath>
29
30namespace dspark::detail
31{
32template <ClipperCurve C> class ContinuousStereoColor final
33{
35 static constexpr int count = stereo_color_coefficients::moments, block = 256;
36 static constexpr int powers = stereo_color_coefficients::powers;
37 std::array<FIRFilter<double>, powers> input_;
38 std::array<FIRFilter<double>, count> output_;
39 continuous_clip::Interval<C, powers - 1, false, false, count> integral_{.08};
40 std::array<std::array<double, block>, powers> scratch_{};
41 DcBlockState dc_{};
42 double pole_;
43
44 public:
45 [[nodiscard]] static constexpr int latency() noexcept
46 {
48 }
49 // Dynamic payload; the owning wrapper accounts for sizeof(*this).
50 [[nodiscard]] static constexpr std::size_t allocationBound() noexcept
51 {
52 // Five vector requests per FIR. Include their implementation-specific
53 // alignment bookkeeping (MSVC adds 39 bytes to large vector requests),
54 // as well as the scalar payload; offline budgets count both.
55 return (powers * 257 + count * 258) * (sizeof(std::atomic<double>) + 4 * sizeof(double)) +
56 (powers + count) * (sizeof(int) + 5 * 64);
57 }
58 explicit ContinuousStereoColor(int sourceFactor) : pole_(std::pow(.9995, sourceFactor))
59 {
60 assert(sourceFactor == 1 || sourceFactor == 2 || sourceFactor == 4 || sourceFactor == 8);
61 const int sourceIndex = sourceFactor == 8 ? 3 : sourceFactor == 4 ? 2 : sourceFactor == 2 ? 1 : 0;
62 for (int k = 0; k < powers; ++k)
63 {
64 input_[k].prepare(257, 1);
65 input_[k].setCoefficients(stereo_color_coefficients::reconstruction[k]);
66 }
67 for (int k = 0; k < count; ++k)
68 {
69 output_[k].prepare(258, 1);
70 output_[k].setCoefficients(stereo_color_coefficients::projection[sourceIndex][k]);
71 }
72 }
73 void reset() noexcept
74 {
75 dc_ = {};
76 for (auto &filter : input_) filter.reset();
77 for (auto &filter : output_) filter.reset();
78 }
79 void process(AudioBufferView<double> data) noexcept
80 {
81 for (int offset = 0; offset < data.getNumSamples(); offset += block)
82 {
83 const int size = std::min(block, data.getNumSamples() - offset);
84 auto *samples = data.getChannel(0) + offset;
85 for (int k = 0; k < powers; ++k)
86 {
87 auto *channel = scratch_[k].data();
88 std::copy_n(samples, size, channel);
89 input_[k].processBlock({&channel, 1, size});
90 }
91 for (int i = 0; i < size; ++i)
92 {
93 std::array<double, powers> power{};
94 for (int k = 0; k < powers; ++k) power[k] = scratch_[k][i];
95 const auto moments = integral_.polynomial(power);
96 for (int k = 0; k < count; ++k) scratch_[k][i] = moments[k];
97 }
98 for (int k = 0; k < count; ++k)
99 {
100 auto *channel = scratch_[k].data();
101 output_[k].processBlock({&channel, 1, size});
102 }
103 for (int i = 0; i < size; ++i)
104 {
105 double result = 0;
106 for (int k = 0; k < count; ++k) result += scratch_[k][i];
107 samples[i] = dcBlockStep(pole_, dc_, result);
108 }
109 }
110 }
111};
112} // namespace dspark::detail
Non-owning view over audio channel data.
Definition AudioBuffer.h:50
static constexpr int latency() noexcept
static constexpr std::size_t allocationBound() noexcept
void process(AudioBufferView< double > data) noexcept
Moments polynomial(const Poly &power) const noexcept
Integrates an already reconstructed power polynomial on [0,1]. Returns integral(t^j * shape(p(t)),...
constexpr std::array< std::array< std::array< double, 258 >, moments >, 4 > projection
constexpr std::array< std::array< double, 257 >, powers > reconstruction
double dcBlockStep(double pole, DcBlockState &state, double input) noexcept
Applies (1 - z^-1) / (1 - pole * z^-1), with a pole in [0, 1).
Definition DcBlock.h:24
Previous input and output of the one-pole DC blocker.
Definition DcBlock.h:18