19template <
typename SampleType>
26template <
typename SampleType =
float, std::
size_t MaxPo
ints = 32>
28 static_assert(MaxPoints >= 2,
"a transfer curve needs room for two endpoints");
32 std::array<Point, MaxPoints>
points{};
47template <
typename SampleType =
float, std::
size_t MaxPo
ints = 32>
52 SampleType output_min,
53 SampleType output_max)
noexcept {
54 static_assert(std::is_floating_point_v<SampleType>,
55 "transfer curves require a floating-point sample type");
57 if (points.size() < 2 || points.size() > MaxPoints ||
58 !std::isfinite(input_min) || !std::isfinite(input_max) ||
59 !std::isfinite(output_min) || !std::isfinite(output_max) ||
60 !(input_min < input_max) || output_min > output_max ||
61 !std::isfinite(input_max - input_min) ||
62 !std::isfinite(output_max - output_min) ||
63 points.front().input != input_min || points.back().input != input_max)
73 for (std::size_t
i = 0;
i < points.size(); ++
i) {
74 const auto point = points[
i];
75 if (!std::isfinite(point.input) || !std::isfinite(point.output) ||
76 point.input < input_min || point.input > input_max ||
77 point.output < output_min || point.output > output_max)
84 const auto input_delta = point.input - points[
i - 1].input;
85 if (!(input_delta > SampleType{}) || !std::isfinite(input_delta) ||
86 !std::isfinite(point.output - points[
i - 1].output))
89 const auto inverse_input_delta = SampleType{1} / input_delta;
90 if (!std::isfinite(inverse_input_delta))
return std::nullopt;
100template <
typename SampleType, std::
size_t MaxPo
ints>
103 SampleType input)
noexcept {
104 if (!std::isfinite(input) || curve.point_count < 2 || curve.point_count > MaxPoints)
106 if (input <= curve.input_min)
return curve.points.front().output;
107 if (input >= curve.input_max)
return curve.points[curve.point_count - 1].output;
110 std::size_t high = curve.point_count - 1;
111 while (high - low > 1) {
112 const auto middle = low + (high - low) / 2;
113 if (input < curve.points[middle].input)
119 const auto&
left = curve.points[low];
120 const auto&
right = curve.points[low + 1];
121 const auto progress = (input -
left.input) * curve.inverse_input_deltas[low];
124 if (!std::isfinite(output))
return SampleType{};
125 return std::clamp(output, std::min(
left.output,
right.output),
136template <
typename SampleType =
float, std::
size_t MaxPo
ints = 32>
144 TransferCurveT() noexcept : published_(identity_curve()), active_(identity_curve()) {}
147 SampleType input_min,
148 SampleType input_max,
149 SampleType output_min,
150 SampleType output_max)
noexcept {
152 points, input_min, input_max, output_min, output_max);
158 SampleType
process(SampleType input)
noexcept {
163 void process(
const SampleType* input, SampleType* output,
int num_samples)
noexcept {
164 if (input ==
nullptr || output ==
nullptr || num_samples <= 0)
return;
166 for (
int i = 0;
i < num_samples; ++
i)
170 void process(SampleType* samples,
int num_samples)
noexcept {
171 process(samples, samples, num_samples);
176 void reset() noexcept { sync_curve(); }
184 curve.
points[0] =
Point{SampleType{-1}, SampleType{-1}};
185 curve.points[1] =
Point{SampleType{1}, SampleType{1}};
186 curve.inverse_input_deltas[0] = SampleType{0.5};
187 curve.point_count = 2;
188 curve.input_min = SampleType{-1};
189 curve.input_max = SampleType{1};
190 curve.output_min = SampleType{-1};
191 curve.output_max = SampleType{1};
195 void sync_curve() noexcept { active_ = published_.read(); }
197 pulp::runtime::TripleBuffer<PreparedCurve> published_;
Audio-thread processor for a fixed-capacity arbitrary transfer curve.
Definition transfer_curve.hpp:137
TransferCurvePointT< SampleType > Point
Definition transfer_curve.hpp:139
static constexpr std::size_t max_points
Definition transfer_curve.hpp:142
void process(SampleType *samples, int num_samples) noexcept
Definition transfer_curve.hpp:170
void process(const SampleType *input, SampleType *output, int num_samples) noexcept
Definition transfer_curve.hpp:163
SampleType process(SampleType input) noexcept
Definition transfer_curve.hpp:158
TransferCurveT() noexcept
Definition transfer_curve.hpp:144
PreparedTransferCurveT< SampleType, MaxPoints > PreparedCurve
Definition transfer_curve.hpp:140
static constexpr int tail_samples() noexcept
Definition transfer_curve.hpp:179
static constexpr int latency_samples() noexcept
Definition transfer_curve.hpp:178
bool publish_curve(std::span< const Point > points, SampleType input_min, SampleType input_max, SampleType output_min, SampleType output_max) noexcept
Definition transfer_curve.hpp:146
void reset() noexcept
A transfer curve has no history.
Definition transfer_curve.hpp:176
A shared, allocation-free curve vocabulary for modulation segments.
Definition additive_bank.hpp:218
TransferCurvePointT< double > TransferCurvePoint64
Definition transfer_curve.hpp:202
TransferCurveT< double, 32 > TransferCurve64
Definition transfer_curve.hpp:206
TransferCurvePointT< float > TransferCurvePoint
Definition transfer_curve.hpp:201
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
SampleType interpolate_modulation_curve(SampleType start, SampleType end, ProgressType progress, ModulationCurve curve={}) noexcept
Definition modulation_curve.hpp:97
ModulationCurve sanitize_modulation_curve(ModulationCurve curve) noexcept
Definition modulation_curve.hpp:42
PreparedTransferCurveT< float, 32 > PreparedTransferCurve
Definition transfer_curve.hpp:203
SampleType evaluate_transfer_curve(const PreparedTransferCurveT< SampleType, MaxPoints > &curve, SampleType input) noexcept
Evaluate a prepared curve.
Definition transfer_curve.hpp:101
TransferCurveT< float, 32 > TransferCurve
Definition transfer_curve.hpp:205
@ i
Definition formant_filter_bank.hpp:20
PreparedTransferCurveT< double, 32 > PreparedTransferCurve64
Definition transfer_curve.hpp:204
std::optional< PreparedTransferCurveT< SampleType, MaxPoints > > prepare_transfer_curve(std::span< const TransferCurvePointT< SampleType > > points, SampleType input_min, SampleType input_max, SampleType output_min, SampleType output_max) noexcept
Validate and prepare a piecewise transfer curve.
Definition transfer_curve.hpp:48
@ prepared
Definition finite_stretch_builder.hpp:19
@ progress
Definition finite_stretch_builder.hpp:30
Curve strength is dimensionless and legal in [0, 1].
Definition modulation_curve.hpp:37
Definition transfer_curve.hpp:27
std::array< Point, MaxPoints > points
Definition transfer_curve.hpp:32
SampleType input_max
Definition transfer_curve.hpp:36
SampleType output_min
Definition transfer_curve.hpp:37
SampleType input_min
Definition transfer_curve.hpp:35
std::size_t point_count
Definition transfer_curve.hpp:34
std::array< SampleType, MaxPoints - 1 > inverse_input_deltas
Definition transfer_curve.hpp:33
TransferCurvePointT< SampleType > Point
Definition transfer_curve.hpp:30
SampleType output_max
Definition transfer_curve.hpp:38
Definition transfer_curve.hpp:20
ModulationCurve curve_to_next
Definition transfer_curve.hpp:23
float output
Definition transfer_curve.hpp:22
float input
Definition transfer_curve.hpp:21
Lock-free latest-value publication between two threads.