Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
sample_interpolation.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <algorithm>
8#include <array>
9#include <cmath>
10#include <cstdint>
11#include <cstdlib>
12#include <limits>
13#include <span>
14#include <string_view>
15#include <type_traits>
16
17namespace pulp::audio {
18
19inline constexpr std::uint32_t kMaximumSampleInterpolationTaps = 128;
20
21enum class SampleInterpolationPolicy : std::uint8_t {
22 Hold = 0,
24 Linear = 2,
28};
29
39
40inline constexpr std::array<SampleInterpolationPolicyInfo, 6>
42 {SampleInterpolationPolicy::Hold, "hold", "Hold"},
43 {SampleInterpolationPolicy::Nearest, "nearest", "Nearest"},
44 {SampleInterpolationPolicy::Linear, "linear", "Linear"},
46 "cubic-hermite", "Cubic Hermite"},
48 "cubic-lagrange", "Cubic Lagrange"},
50 "ratio-tracking-sinc", "Ratio-tracking sinc"},
51 }};
52
54 SampleInterpolationPolicy policy) noexcept {
55 for (const auto& candidate : kSampleInterpolationPolicies)
56 if (candidate.policy == policy) return &candidate;
57 return nullptr;
58}
59
61 std::string_view id) noexcept {
62 for (const auto& candidate : kSampleInterpolationPolicies)
63 if (candidate.id == id) return &candidate;
64 return nullptr;
65}
66
67constexpr std::string_view sample_interpolation_policy_id(
68 SampleInterpolationPolicy policy) noexcept {
69 const auto* info = sample_interpolation_policy_info(policy);
70 return info == nullptr ? std::string_view{} : info->id;
71}
72
73constexpr std::string_view sample_interpolation_policy_name(
74 SampleInterpolationPolicy policy) noexcept {
75 const auto* info = sample_interpolation_policy_info(policy);
76 return info == nullptr ? std::string_view{"Unknown"} : info->name;
77}
78
80 std::int32_t first_offset = 0;
81 std::uint32_t tap_count = 0;
82};
83
97
100 float fraction,
101 const SampleSincKernelSelection& sinc = {}) noexcept {
102 switch (policy) {
104 return {0, 1};
106 return {fraction < 0.5f ? 0 : 1, 1};
108 return {0, 2};
111 return {-1, 4};
113 return sinc.valid()
115 sinc.wider.first_offset(), sinc.wider.tap_count()}
117 }
118 return {};
119}
120
123 float fraction,
124 std::span<const float> taps,
125 const SampleSincKernelSelection& sinc = {}) noexcept {
126 const auto footprint = sample_interpolation_footprint(policy, fraction, sinc);
127 if (footprint.tap_count == 0 || taps.size() != footprint.tap_count)
128 return 0.0f;
129
130 switch (policy) {
133 return taps[0];
135 return signal::Interpolator::linear(fraction, taps[0], taps[1]);
138 fraction, taps[0], taps[1], taps[2], taps[3]);
141 fraction, taps[0], taps[1], taps[2], taps[3]);
143 return sinc.apply(taps, fraction);
144 }
145 return 0.0f;
146}
147
151
152 bool valid() const noexcept {
155 !sinc.valid())) {
156 return false;
157 }
158 const auto span = footprint(0.0f);
159 return span.tap_count > 0 &&
160 span.tap_count <= kMaximumSampleInterpolationTaps;
161 }
162
163 SampleInterpolationFootprint footprint(float fraction) const noexcept {
164 return sample_interpolation_footprint(policy, fraction, sinc);
165 }
166
167 std::uint32_t guard_frames() const noexcept {
168 std::uint32_t guard = 0;
169 for (const auto fraction : {0.0f, 0.5f}) {
170 const auto span = footprint(fraction);
171 const auto last_offset = span.tap_count == 0
172 ? span.first_offset
173 : span.first_offset +
174 static_cast<std::int32_t>(span.tap_count - 1);
175 guard = std::max(guard, static_cast<std::uint32_t>(std::max(
176 std::abs(span.first_offset), std::abs(last_offset))));
177 }
178 return guard;
179 }
180
181 float evaluate(float fraction, std::span<const float> taps) const noexcept {
182 return evaluate_sample_interpolation(policy, fraction, taps, sinc);
183 }
184};
185
186static_assert(std::is_trivially_copyable_v<PreparedSampleInterpolation>);
187
189 const PreparedSampleInterpolation& left,
190 const PreparedSampleInterpolation& right) noexcept {
191 const auto same_kernel = [](const SampleSincKernelView& a,
192 const SampleSincKernelView& b) noexcept {
193 return a.storage_identity() == b.storage_identity() &&
194 a.half_width() == b.half_width() &&
195 a.phases() == b.phases() && a.cutoff() == b.cutoff();
196 };
197 return left.policy == right.policy &&
198 same_kernel(left.sinc.wider, right.sinc.wider) &&
199 same_kernel(left.sinc.narrower, right.sinc.narrower) &&
200 left.sinc.narrower_gain == right.sinc.narrower_gain;
201}
202
209
211 double normalized_position,
212 const PreparedSampleInterpolation& interpolation) noexcept {
214 const auto minimum_safe_position = std::nextafter(
215 static_cast<double>(std::numeric_limits<std::int64_t>::min()), 0.0);
216 const auto maximum_safe_position = std::nextafter(
217 static_cast<double>(std::numeric_limits<std::int64_t>::max()), 0.0);
218 if (!interpolation.valid() || !std::isfinite(normalized_position) ||
219 normalized_position <= minimum_safe_position ||
220 normalized_position >= maximum_safe_position) {
221 return result;
222 }
223 result.base_frame = static_cast<std::int64_t>(
224 std::floor(normalized_position));
225 result.fraction = static_cast<float>(
226 normalized_position - static_cast<double>(result.base_frame));
227 result.footprint = interpolation.footprint(result.fraction);
228 result.valid = result.footprint.tap_count > 0 &&
229 result.footprint.tap_count <=
231 return result;
232}
233
234constexpr bool valid_loop_interpolation(LoopInterpolationMode mode) noexcept {
235 switch (mode) {
239 return true;
240 }
241 return false;
242}
243
256
257} // namespace pulp::audio
Definition sample_sinc_kernel.hpp:30
High-quality sample interpolation for delay lines and resampling.
Definition analyzer_provider.hpp:12
bool same_sample_interpolation(const PreparedSampleInterpolation &left, const PreparedSampleInterpolation &right) noexcept
Definition sample_interpolation.hpp:188
constexpr std::array< SampleInterpolationPolicyInfo, 6 > kSampleInterpolationPolicies
Definition sample_interpolation.hpp:41
constexpr std::string_view sample_interpolation_policy_id(SampleInterpolationPolicy policy) noexcept
Definition sample_interpolation.hpp:67
@ Linear
Definition loop_types.hpp:16
@ Hold
Definition instrument_envelope.hpp:11
LoopInterpolationMode
Definition loop_types.hpp:20
@ Linear
Definition loop_types.hpp:22
@ None
Definition loop_types.hpp:21
@ Cubic
Definition loop_types.hpp:23
constexpr bool valid_loop_interpolation(LoopInterpolationMode mode) noexcept
Definition sample_interpolation.hpp:234
constexpr bool valid_sample_interpolation(SampleInterpolationPolicy policy) noexcept
Definition sample_interpolation.hpp:84
SampleInterpolationPolicy
Definition sample_interpolation.hpp:21
@ Linear
Definition sample_interpolation.hpp:24
@ Nearest
Definition sample_interpolation.hpp:23
@ RatioTrackingSinc
Definition sample_interpolation.hpp:27
@ Hold
Definition sample_interpolation.hpp:22
@ CubicLagrange
Definition sample_interpolation.hpp:26
@ CubicHermite
Definition sample_interpolation.hpp:25
ResolvedSampleInterpolationPosition resolve_sample_interpolation_position(double normalized_position, const PreparedSampleInterpolation &interpolation) noexcept
Definition sample_interpolation.hpp:210
constexpr std::uint32_t kMaximumSampleInterpolationTaps
Definition sample_interpolation.hpp:19
float evaluate_sample_interpolation(SampleInterpolationPolicy policy, float fraction, std::span< const float > taps, const SampleSincKernelSelection &sinc={}) noexcept
Definition sample_interpolation.hpp:121
constexpr SampleInterpolationPolicy sample_interpolation_policy(LoopInterpolationMode mode) noexcept
Definition sample_interpolation.hpp:244
constexpr SampleInterpolationFootprint sample_interpolation_footprint(SampleInterpolationPolicy policy, float fraction, const SampleSincKernelSelection &sinc={}) noexcept
Definition sample_interpolation.hpp:98
constexpr const SampleInterpolationPolicyInfo * sample_interpolation_policy_info(SampleInterpolationPolicy policy) noexcept
Definition sample_interpolation.hpp:53
constexpr std::string_view sample_interpolation_policy_name(SampleInterpolationPolicy policy) noexcept
Definition sample_interpolation.hpp:73
float sinc(float x)
Sinc function: sin(pi*x) / (pi*x), with sinc(0) = 1.
Definition special_functions.hpp:17
Definition sample_interpolation.hpp:148
SampleSincKernelSelection sinc
Definition sample_interpolation.hpp:150
SampleInterpolationFootprint footprint(float fraction) const noexcept
Definition sample_interpolation.hpp:163
std::uint32_t guard_frames() const noexcept
Definition sample_interpolation.hpp:167
float evaluate(float fraction, std::span< const float > taps) const noexcept
Definition sample_interpolation.hpp:181
bool valid() const noexcept
Definition sample_interpolation.hpp:152
SampleInterpolationPolicy policy
Definition sample_interpolation.hpp:149
Definition sample_interpolation.hpp:203
bool valid
Definition sample_interpolation.hpp:207
float fraction
Definition sample_interpolation.hpp:205
SampleInterpolationFootprint footprint
Definition sample_interpolation.hpp:206
std::int64_t base_frame
Definition sample_interpolation.hpp:204
Definition sample_interpolation.hpp:79
std::uint32_t tap_count
Definition sample_interpolation.hpp:81
std::int32_t first_offset
Definition sample_interpolation.hpp:80
Stable serialization/UI metadata for one interpolation policy.
Definition sample_interpolation.hpp:34
std::string_view name
Definition sample_interpolation.hpp:37
SampleInterpolationPolicy policy
Definition sample_interpolation.hpp:35
std::string_view id
Definition sample_interpolation.hpp:36
Definition sample_sinc_kernel.hpp:202
static SampleType linear(SampleType frac, SampleType y0, SampleType y1)
Linear interpolation between two samples.
Definition interpolator.hpp:33
static SampleType lagrange(SampleType frac, SampleType ym1, SampleType y0, SampleType y1, SampleType y2)
4-point Lagrange interpolation.
Definition interpolator.hpp:60
static SampleType hermite(SampleType frac, SampleType ym1, SampleType y0, SampleType y1, SampleType y2)
Cubic Hermite (Catmull-Rom) interpolation.
Definition interpolator.hpp:41