11void linear(std::span<double> data,
double a,
double b)
noexcept
13 std::ranges::transform(data, data.begin(),
14 [
a,
b](
double x) { return a * x + b; });
17void power(std::span<double> data,
double exponent)
noexcept
19 std::ranges::transform(data, data.begin(),
20 [exponent](
double x) { return std::pow(x, exponent); });
23void exponential(std::span<double> data,
double a,
double b,
double base)
noexcept
25 if (base == std::numbers::e) {
26 std::ranges::transform(data, data.begin(),
27 [
a,
b](
double x) { return a * std::exp(b * x); });
29 std::ranges::transform(data, data.begin(),
30 [
a,
b, base](
double x) { return a * std::pow(base, b * x); });
34void logarithmic(std::span<double> data,
double a,
double b,
double c,
double base)
noexcept
36 const double log_factor = (base == std::numbers::e) ? 1.0 : (1.0 / std::log(base));
37 std::ranges::transform(data, data.begin(),
38 [
a,
b, c, log_factor](
double x) {
39 const double arg = b * x + c;
40 return (arg > 0.0) ? a * std::log(arg) * log_factor : 0.0;
44void clamp(std::span<double> data,
double lo,
double hi)
noexcept
46 std::ranges::transform(data, data.begin(),
47 [lo, hi](
double x) { return std::clamp(x, lo, hi); });
50void quantize(std::span<double> data, uint8_t bits)
noexcept
52 const double levels = std::pow(2.0, bits) - 1.0;
53 const double inv_levels = 1.0 / levels;
54 std::ranges::transform(data, data.begin(),
55 [levels, inv_levels](
double x) {
56 const double clamped = std::clamp(x, -1.0, 1.0);
57 return static_cast<double>(std::lrint(clamped * levels)) * inv_levels;
61void normalize(std::span<double> data,
double target_min,
double target_max)
noexcept
68 for (
double v : data) {
78 const double inv_src = 1.0 / (hi - lo);
79 const double dst_range = target_max - target_min;
80 std::ranges::transform(data, data.begin(),
81 [lo, inv_src, dst_range, target_min](
double x) {
82 return (x - lo) * inv_src * dst_range + target_min;
90void reverse(std::span<double> data)
noexcept
92 std::ranges::reverse(data);
95void fade(std::span<double> data,
double fade_in_ratio,
double fade_out_ratio)
noexcept
100 const size_t n = data.size();
101 const auto in_end =
static_cast<size_t>(fade_in_ratio *
static_cast<double>(n));
102 const size_t out_start = n -
static_cast<size_t>(fade_out_ratio *
static_cast<double>(n));
104 const double pi = std::numbers::pi;
107 const auto in_len =
static_cast<double>(in_end - 1);
108 for (
size_t i = 0; i < in_end; ++i) {
109 const double t = (in_len > 0.0)
110 ?
static_cast<double>(i) / in_len
112 data[i] *= std::sin(t * pi * 0.5);
117 const auto out_len =
static_cast<double>(n - 1 - out_start);
118 for (
size_t i = out_start; i < n; ++i) {
119 const double t = (out_len > 0.0)
120 ?
static_cast<double>(i - out_start) / out_len
122 data[i] *= std::cos(t * pi * 0.5);
127std::vector<double>
slice(std::span<const double> data,
131 if (data.empty() || end_ratio <= start_ratio)
134 const size_t s =
static_cast<size_t>(std::clamp(start_ratio, 0.0, 1.0) *
static_cast<double>(data.size()));
135 const size_t e =
static_cast<size_t>(std::clamp(end_ratio, 0.0, 1.0) *
static_cast<double>(data.size()));
140 return { data.begin() + s, data.begin() + e };
143std::vector<double>
delay(std::span<const double> data,
144 uint32_t delay_samples,
147 std::vector<double> out(data.size() + delay_samples, fill_value);
148 std::ranges::copy(data, out.begin() + delay_samples);
158 const size_t dst_n = dst.size();
159 const size_t src_n = src.size();
161 if (dst_n == 0 || src_n == 0)
164 if (dst_n == 1 || src_n == 1) {
165 std::ranges::fill(dst, src[0]);
169 const double step =
static_cast<double>(src_n - 1) /
static_cast<double>(dst_n - 1);
171 Parallel::for_each(Parallel::par_unseq,
172 std::views::iota(
size_t { 0 }, dst_n).begin(),
173 std::views::iota(
size_t { 0 }, dst_n).end(),
174 [&src, &dst, step, src_n](
size_t i) {
175 const double pos =
static_cast<double>(i) * step;
176 const auto idx =
static_cast<size_t>(pos);
177 const size_t idx1 = std::min(idx + 1, src_n - 1);
178 const double frac = pos -
static_cast<double>(idx);
179 dst[i] = src[idx] + frac * (src[idx1] - src[idx]);
185 const size_t dst_n = dst.size();
186 const size_t src_n = src.size();
188 if (dst_n == 0 || src_n == 0)
191 if (dst_n == 1 || src_n == 1) {
192 std::ranges::fill(dst, src[0]);
196 const double step =
static_cast<double>(src_n - 1) /
static_cast<double>(dst_n - 1);
197 const size_t last = src_n - 1;
199 Parallel::for_each(Parallel::par_unseq,
200 std::views::iota(
size_t { 0 }, dst_n).begin(),
201 std::views::iota(
size_t { 0 }, dst_n).end(),
202 [&src, &dst, step, last](
size_t i) {
203 const double pos =
static_cast<double>(i) * step;
204 const auto idx =
static_cast<size_t>(pos);
205 const double f = pos -
static_cast<double>(idx);
207 const size_t i0 = idx > 0 ? idx - 1 : 0;
208 const size_t i1 = idx;
209 const size_t i2 = std::min(idx + 1, last);
210 const size_t i3 = std::min(idx + 2, last);
212 const double y0 = src[i0], y1 = src[i1], y2 = src[i2], y3 = src[i3];
213 const double a = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
214 const double b = y0 - 2.5 * y1 + 2.0 * y2 - 0.5 * y3;
215 const double c = -0.5 * y0 + 0.5 * y2;
216 dst[i] = ((
a * f +
b) * f + c) * f + y1;
220std::vector<double>
time_stretch(std::span<const double> data,
double stretch_factor)
222 if (data.empty() || stretch_factor <= 0.0)
225 if (stretch_factor == 1.0)
226 return { data.begin(), data.end() };
228 const auto out_size =
static_cast<size_t>(
229 static_cast<double>(data.size()) * stretch_factor);
234 std::vector<double> out(out_size);
void exponential(std::span< double > data, double a, double b, double base) noexcept
Exponential map y = a * base^(b*x) applied in-place Scalar transcendental — not SIMD hot-path.
void fade(std::span< double > data, double fade_in_ratio, double fade_out_ratio) noexcept
Apply equal-power (cosine) fade-in then fade-out envelope in-place The cosine taper maintains constan...
void linear(std::span< double > data, double a, double b) noexcept
Linear map y = a*x + b applied in-place.
void clamp(std::span< double > data, double lo, double hi) noexcept
Clamp values to [lo, hi] in-place.
void interpolate_cubic(std::span< const double > src, std::span< double > dst) noexcept
Catmull-Rom cubic interpolation from src into dst (caller sizes dst) Branchless boundary clamping; Ho...
std::vector< double > slice(std::span< const double > data, double start_ratio, double end_ratio)
Extract a contiguous slice by ratio, returning a new vector.
std::vector< double > delay(std::span< const double > data, uint32_t delay_samples, double fill_value)
Prepend delay_samples zero-valued (or fill_value) samples, returning a new vector.
void reverse(std::span< double > data) noexcept
Reverse temporal order in-place.
std::vector< double > time_stretch(std::span< const double > data, double stretch_factor)
Time-stretch via linear interpolation resampling Fast but alias-naive: no anti-aliasing pre-filter is...
void normalize(std::span< double > data, double target_min, double target_max) noexcept
Normalize to [target_min, target_max] in-place Single-pass min/max reduction followed by a single tra...
void logarithmic(std::span< double > data, double a, double b, double c, double base) noexcept
Logarithmic map y = a * log_base(b*x + c) applied in-place Values where (b*x + c) <= 0 are mapped to ...
void quantize(std::span< double > data, uint8_t bits) noexcept
Quantize to n-bit resolution in-place Input is assumed to be in [-1, 1]; values outside are clamped f...
void interpolate_linear(std::span< const double > src, std::span< double > dst) noexcept
Linear interpolation from src into dst (caller sizes dst) Branchless inner loop with precomputed step...
std::vector< double > power(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Power (sum of squares) per window.