81 return std::endian::native == std::endian::little;
91 static_assert(std::is_integral_v<T>);
93 auto* in_bytes =
reinterpret_cast<const uint8_t*
>(&value);
94 auto* out_bytes =
reinterpret_cast<uint8_t*
>(&out);
95 for (std::size_t i = 0; i <
sizeof(T); ++i) {
96 out_bytes[i] = in_bytes[
sizeof(T) - 1 - i];
104 std::memcpy(&value, src,
sizeof(T));
118 std::memcpy(dst, &value,
sizeof(T));
125 val =
static_cast<int32_t
>(src[0])
126 | (
static_cast<int32_t
>(src[1]) << 8)
127 | (
static_cast<int32_t
>(src[2]) << 16);
129 val =
static_cast<int32_t
>(src[2])
130 | (
static_cast<int32_t
>(src[1]) << 8)
131 | (
static_cast<int32_t
>(src[0]) << 16);
134 if (val & 0x800000) val |=
static_cast<int32_t
>(0xFF000000u);
141 constexpr int32_t kMax = (1 << 23) - 1;
142 constexpr int32_t kMin = -(1 << 23);
143 if (value > kMax) value = kMax;
144 else if (value < kMin) value = kMin;
147 dst[0] =
static_cast<uint8_t
>(value & 0xFF);
148 dst[1] =
static_cast<uint8_t
>((value >> 8) & 0xFF);
149 dst[2] =
static_cast<uint8_t
>((value >> 16) & 0xFF);
151 dst[0] =
static_cast<uint8_t
>((value >> 16) & 0xFF);
152 dst[1] =
static_cast<uint8_t
>((value >> 8) & 0xFF);
153 dst[2] =
static_cast<uint8_t
>(value & 0xFF);
158 return std::isfinite(v) ? v : 0.0f;
188 return ::pulp::audio::bytes_per_sample(format_);
193 std::size_t
bytes_for(std::size_t frames, std::size_t channels)
const noexcept {
203 float*
const* dst_channels,
205 std::size_t channels)
const noexcept {
212 float*
const* dst_channels,
214 std::size_t channels,
215 float gain)
const noexcept {
216 if (!src || !dst_channels || frames == 0 || channels == 0)
return;
217 const auto* bytes =
static_cast<const uint8_t*
>(src);
219 for (std::size_t f = 0; f < frames; ++f) {
220 for (std::size_t c = 0; c < channels; ++c) {
221 const std::size_t byte_index = byte_offset(f, c, frames, channels, bps);
222 dst_channels[c][f] = decode_sample(bytes + byte_index) * gain;
233 std::size_t channels)
const noexcept {
234 if (!src_channels || !dst || frames == 0 || channels == 0)
return;
235 auto* bytes =
static_cast<uint8_t*
>(dst);
237 for (std::size_t f = 0; f < frames; ++f) {
238 for (std::size_t c = 0; c < channels; ++c) {
239 const std::size_t byte_index = byte_offset(f, c, frames, channels, bps);
240 encode_sample(bytes + byte_index, src_channels[c][f]);
246 std::size_t byte_offset(std::size_t frame,
249 std::size_t channels,
250 std::size_t bps)
const noexcept {
252 return (frame * channels + channel) * bps;
255 return (channel * frames + frame) * bps;
258 float decode_sample(
const uint8_t* src)
const noexcept {
261 const int8_t v =
static_cast<int8_t
>(*src);
274 return static_cast<float>(
280 std::memcpy(&f, &bits,
sizeof(
float));
286 std::memcpy(&d, &bits,
sizeof(
double));
287 return static_cast<float>(
d);
293 void encode_sample(uint8_t* dst,
float value)
const noexcept {
297 value = std::clamp(value, -1.0f, 1.0f);
298 const int8_t
v =
static_cast<int8_t
>(
299 std::lrintf(value * 127.0f));
300 std::memcpy(dst, &v, 1);
304 value = std::clamp(value, -1.0f, 1.0f);
305 const int16_t
v =
static_cast<int16_t
>(
306 std::lrintf(value * 32767.0f));
311 value = std::clamp(value, -1.0f, 1.0f);
312 const int32_t
v =
static_cast<int32_t
>(
313 std::lrintf(value * 8388607.0f));
318 value = std::clamp(value, -1.0f, 1.0f);
321 v = std::numeric_limits<int32_t>::max();
322 }
else if (value <= -1.0f) {
323 v = std::numeric_limits<int32_t>::min();
325 v =
static_cast<int32_t
>(
326 std::lrint(
static_cast<double>(value) * 2147483647.0));
333 std::memcpy(&bits, &value,
sizeof(int32_t));
338 const double d =
static_cast<double>(
value);
340 std::memcpy(&bits, &d,
sizeof(int64_t));
void from_float(const float *const *src_channels, void *dst, std::size_t frames, std::size_t channels) const noexcept
Convert planar float channels → PCM bytes.
Definition sample_converter.hpp:230
void to_float(const void *src, float *const *dst_channels, std::size_t frames, std::size_t channels) const noexcept
Convert PCM bytes → planar float channels.
Definition sample_converter.hpp:202
SampleConverter(SampleFormat format, Endianness endian=Endianness::Native, Layout layout=Layout::Interleaved) noexcept
Definition sample_converter.hpp:177
Layout layout() const noexcept
Definition sample_converter.hpp:184
std::size_t bytes_for(std::size_t frames, std::size_t channels) const noexcept
Total byte size for frames * channels PCM samples in the configured layout.
Definition sample_converter.hpp:193
SampleFormat format() const noexcept
Definition sample_converter.hpp:182
std::size_t bytes_per_sample() const noexcept
Bytes occupied per sample (independent of layout / channel count).
Definition sample_converter.hpp:187
Endianness endian() const noexcept
Definition sample_converter.hpp:183
void to_float_scaled(const void *src, float *const *dst_channels, std::size_t frames, std::size_t channels, float gain) const noexcept
Same as to_float with a per-sample gain multiplier applied during conversion (saves a second pass ove...
Definition sample_converter.hpp:211
float finite_or_zero(float v) noexcept
Definition sample_converter.hpp:157
constexpr float kInt24Scale
Definition sample_converter.hpp:168
void store_int24(uint8_t *dst, int32_t value, Endianness dst_endian) noexcept
Definition sample_converter.hpp:138
constexpr float kInt16Scale
Definition sample_converter.hpp:167
void store_int(uint8_t *dst, T value, Endianness dst_endian) noexcept
Definition sample_converter.hpp:113
constexpr bool host_is_little_endian() noexcept
Definition sample_converter.hpp:80
T byteswap_int(T value) noexcept
Definition sample_converter.hpp:90
constexpr float kInt8Scale
Definition sample_converter.hpp:166
int32_t load_int24(const uint8_t *src, Endianness src_endian) noexcept
Definition sample_converter.hpp:121
constexpr double kInt32Scale
Definition sample_converter.hpp:169
Endianness resolve_endianness(Endianness e) noexcept
Definition sample_converter.hpp:84
T load_int(const uint8_t *src, Endianness src_endian) noexcept
Definition sample_converter.hpp:102
Definition analyzer_provider.hpp:12
SampleFormat
Packed-PCM sample format the bytes are encoded in.
Definition sample_converter.hpp:36
@ Float32
IEEE-754 single.
Definition sample_converter.hpp:41
@ Int16
16-bit signed
Definition sample_converter.hpp:38
@ Int24
24-bit signed packed (3 bytes)
Definition sample_converter.hpp:39
@ Int8
8-bit signed (-128..127)
Definition sample_converter.hpp:37
@ Int32
32-bit signed
Definition sample_converter.hpp:40
@ Float64
IEEE-754 double.
Definition sample_converter.hpp:42
Endianness
Byte order.
Definition sample_converter.hpp:48
@ Little
Definition sample_converter.hpp:49
@ Native
Definition sample_converter.hpp:51
@ Big
Definition sample_converter.hpp:50
constexpr bool is_float(SampleFormat format) noexcept
True if format is a floating-point format.
Definition sample_converter.hpp:74
Layout
Memory layout of the byte stream relative to channels.
Definition sample_converter.hpp:55
@ Interleaved
[ch0_s0, ch1_s0, ch0_s1, ch1_s1, ...]
Definition sample_converter.hpp:56
@ Planar
[ch0_s0, ch0_s1, ..., ch1_s0, ch1_s1, ...]
Definition sample_converter.hpp:57
constexpr std::size_t bytes_per_sample(SampleFormat format) noexcept
Bytes per sample for format. Returns 0 for unknown values.
Definition sample_converter.hpp:61
@ Float32
Definition audio_file.hpp:51
@ Int16
Definition audio_file.hpp:51
@ Int24
Definition audio_file.hpp:51
@ d
Definition pitch.hpp:22
@ f
Definition pitch.hpp:25
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
@ v
Definition input_events.hpp:41