Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::audio::buffer_ops Namespace Reference

Classes

struct  MinMax
 Pair returned by find_min_max. More...
struct  PeakRms
 Block level reading returned by measure_peak_rms: the peak absolute sample value and the root-mean-square level. More...

Functions

template<typename Fn>
void map_samples (const float *in, float *out, std::size_t n, Fn &&fn)
 Write out[i] = fn(in[i]) for every sample, in index order.
template<std::size_t... Counts, typename Fn>
void with_channel_count (std::size_t channels, Fn &&fn)
 Call fn once with the channel count, as a compile-time constant when it is one of Counts... and as a runtime std::size_t otherwise.
void apply_gain (std::span< float > samples, float gain)
 Apply a constant gain to a single channel of samples in place.
void apply_gain (BufferView< float > buffer, float gain)
 Apply a constant gain to every channel of a multi-channel buffer.
void apply_gain_ramp (std::span< float > samples, float start_gain, float end_gain)
 Apply a linear gain ramp from start_gain to end_gain across the span.
void apply_gain_ramp (BufferView< float > buffer, float start_gain, float end_gain)
 Apply the same gain ramp to every channel of a multi-channel buffer.
void clip (std::span< float > samples, float lo, float hi)
 Hard-clip every sample to [lo, hi] in place.
void clip (BufferView< float > buffer, float lo, float hi)
 Hard-clip every channel of a multi-channel buffer to [lo, hi].
MinMax find_min_max (std::span< const float > samples)
 Find the min and max sample values in a span.
MinMax find_min_max (const BufferView< float > &buffer, std::size_t channel)
 Find the min and max for one channel of a multi-channel buffer.
MinMax find_min_max (const BufferView< const float > &buffer, std::size_t channel)
float find_magnitude (std::span< const float > samples)
 Find the peak absolute value (magnitude) in a span.
float find_magnitude (const BufferView< float > &buffer, std::size_t channel)
 Find the peak absolute value across one channel of a multi-channel buffer.
float find_magnitude (const BufferView< const float > &buffer, std::size_t channel)
PeakRms measure_peak_rms (std::span< const float > samples) noexcept
 Measure the peak absolute value and RMS of a block in one pass.
PeakRms measure_peak_rms (const BufferView< float > &buffer, std::size_t channel) noexcept
 Measure one channel of a multi-channel buffer.
PeakRms measure_peak_rms (const BufferView< const float > &buffer, std::size_t channel) noexcept

Variables

constexpr std::size_t kPeakRmsLanes = 16
 Number of independent partial sums measure_peak_rms keeps.

Function Documentation

◆ apply_gain() [1/2]

void pulp::audio::buffer_ops::apply_gain ( BufferView< float > buffer,
float gain )

Apply a constant gain to every channel of a multi-channel buffer.

◆ apply_gain() [2/2]

void pulp::audio::buffer_ops::apply_gain ( std::span< float > samples,
float gain )

Apply a constant gain to a single channel of samples in place.

◆ apply_gain_ramp() [1/2]

void pulp::audio::buffer_ops::apply_gain_ramp ( BufferView< float > buffer,
float start_gain,
float end_gain )

Apply the same gain ramp to every channel of a multi-channel buffer.

◆ apply_gain_ramp() [2/2]

void pulp::audio::buffer_ops::apply_gain_ramp ( std::span< float > samples,
float start_gain,
float end_gain )

Apply a linear gain ramp from start_gain to end_gain across the span.

The ramp is sample-accurate: samples[0] is multiplied by start_gain, samples[N-1] by end_gain, with (end - start) / (N - 1) step between adjacent samples (or start for a 1-sample span). A 0-length span is a no-op.

◆ clip() [1/2]

void pulp::audio::buffer_ops::clip ( BufferView< float > buffer,
float lo,
float hi )

Hard-clip every channel of a multi-channel buffer to [lo, hi].

◆ clip() [2/2]

void pulp::audio::buffer_ops::clip ( std::span< float > samples,
float lo,
float hi )

Hard-clip every sample to [lo, hi] in place.

NaN inputs become lo (matches the audio convention of treating non-finite samples as silence rather than letting them propagate).

◆ find_magnitude() [1/3]

float pulp::audio::buffer_ops::find_magnitude ( const BufferView< const float > & buffer,
std::size_t channel )

◆ find_magnitude() [2/3]

float pulp::audio::buffer_ops::find_magnitude ( const BufferView< float > & buffer,
std::size_t channel )

Find the peak absolute value across one channel of a multi-channel buffer.

◆ find_magnitude() [3/3]

float pulp::audio::buffer_ops::find_magnitude ( std::span< const float > samples)

Find the peak absolute value (magnitude) in a span.

Empty span yields 0.0f.

Built from the SIMD min/max reductions, so a NaN anywhere in the span can make the result NaN (it does on the Apple backend). That differs from measure_peak_rms().peak, which ignores NaN samples; use that one for a meter that must keep reading through a stray NaN.

◆ find_min_max() [1/3]

MinMax pulp::audio::buffer_ops::find_min_max ( const BufferView< const float > & buffer,
std::size_t channel )

◆ find_min_max() [2/3]

MinMax pulp::audio::buffer_ops::find_min_max ( const BufferView< float > & buffer,
std::size_t channel )

Find the min and max for one channel of a multi-channel buffer.

◆ find_min_max() [3/3]

MinMax pulp::audio::buffer_ops::find_min_max ( std::span< const float > samples)

Find the min and max sample values in a span.

Empty span yields {0, 0}.

◆ map_samples()

template<typename Fn>
void pulp::audio::buffer_ops::map_samples ( const float * in,
float * out,
std::size_t n,
Fn && fn )
inline

Write out[i] = fn(in[i]) for every sample, in index order.

This is the per-sample loop a processor writes for a stateless or in-order stateful sample function (gain, mix, a waveshaper), written so it vectorizes whether or not the host processes in place. A plain out[i] = f(in[i]) loop compiles to a runtime overlap check, and out == in — the usual in-place call — fails that check and runs the scalar fallback. Here the in-place case is its own single-pointer loop, which the compiler can vectorize without a check.

in and out must be the same pointer or not overlap. fn is called exactly once per sample, in increasing index order, so a function that carries state from one sample to the next still sees samples in order.

◆ measure_peak_rms() [1/3]

PeakRms pulp::audio::buffer_ops::measure_peak_rms ( const BufferView< const float > & buffer,
std::size_t channel )
noexcept

◆ measure_peak_rms() [2/3]

PeakRms pulp::audio::buffer_ops::measure_peak_rms ( const BufferView< float > & buffer,
std::size_t channel )
noexcept

Measure one channel of a multi-channel buffer.

◆ measure_peak_rms() [3/3]

PeakRms pulp::audio::buffer_ops::measure_peak_rms ( std::span< const float > samples)
noexcept

Measure the peak absolute value and RMS of a block in one pass.

This is the per-block meter reading a processor publishes for its UI. It is allocation-free, safe on the audio thread, and vectorizes: independent partial sums break the serial add chain a naive sum += x * x loop forms. RMS is sqrt(sum_of_squares / size).

Non-finite input: a NaN sample, quiet or signaling, is ignored by peak (the same result as folding with std::max(peak, std::abs(x))) but propagates to rms, so a NaN in the block still shows up in the reading. An infinite sample makes both values infinite.

◆ with_channel_count()

template<std::size_t... Counts, typename Fn>
void pulp::audio::buffer_ops::with_channel_count ( std::size_t channels,
Fn && fn )
inline

Call fn once with the channel count, as a compile-time constant when it is one of Counts... and as a runtime std::size_t otherwise.

A sample-outer loop over a runtime channel count (for i … for ch < channels) cannot be unrolled across channels, so per-channel state is re-addressed every sample and independent channel work is not overlapped. Dispatching once per block lets the common layouts compile with a constant count while any other count still runs:

buffer_ops::with_channel_count<1, 2>(channels, [&](auto count) {
for (std::size_t i = 0; i < n; ++i)
for (std::size_t ch = 0; ch < count; ++ch)
out[ch][i] = step(ch, in[ch][i]);
});
void with_channel_count(std::size_t channels, Fn &&fn)
Call fn once with the channel count, as a compile-time constant when it is one of Counts....
Definition buffer_ops.hpp:76

count is a std::integral_constant<std::size_t, N> for a listed count, which converts to std::size_t, so the same generic lambda body serves both.

Variable Documentation

◆ kPeakRmsLanes

std::size_t pulp::audio::buffer_ops::kPeakRmsLanes = 16
inlineconstexpr

Number of independent partial sums measure_peak_rms keeps.

Sample i is accumulated into partial i % kPeakRmsLanes; the partials are then combined pairwise (lane k with lane k + 8, then k with k + 4, k + 2, and finally 0 with 1). The order is fixed rather than tied to the host's SIMD width, so builds that make the same FMA-contraction choice for sum + x * x agree bit for bit; rms can differ in the last bit between builds that do and do not contract it (the per-compiler policy is in tools/cmake/PulpFloatingPointContraction.cmake). peak is always identical.