Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
spectral_frame.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <bit>
5#include <cmath>
6#include <complex>
7#include <cstdint>
8#include <optional>
9#include <span>
10#include <utility>
11#include <vector>
12
13namespace pulp::graph {
14
38
39template <typename T> struct SpectralResult {
40 std::optional<T> value;
42 explicit operator bool() const noexcept {
43 return value.has_value();
44 }
45};
46
50 static constexpr std::size_t encoded_size = 32;
51 std::uint16_t version = 1;
52 std::uint16_t profile = 1;
53 std::uint32_t fft_size = 0;
54 std::uint32_t hop = 0;
55 std::uint16_t channels = 0;
56 std::uint16_t bins = 0;
57 std::uint64_t sample_rate_bits = 0;
58 std::uint8_t window = 1; // symmetric float Hann v1
59 std::uint8_t phase = 1; // local-window-origin v1
60 std::uint8_t normalization = 1; // squared-window WOLA v1
61 std::uint8_t precision = 1; // binary32 complex bins v1
62
63 friend bool operator==(const SpectralFrameContract&, const SpectralFrameContract&) = default;
64
67 [[nodiscard]] std::array<std::uint8_t, encoded_size> encode() const noexcept {
68 std::array<std::uint8_t, encoded_size> out{};
69 auto put = [&](std::size_t offset, std::uint64_t value, unsigned bytes) {
70 for (unsigned i = 0; i < bytes; ++i)
71 out[offset + i] = static_cast<std::uint8_t>(value >> (8 * i));
72 };
73 put(0, version, 2);
74 put(2, profile, 2);
75 put(4, fft_size, 4);
76 put(8, hop, 4);
77 put(12, channels, 2);
78 put(14, bins, 2);
79 put(16, sample_rate_bits, 8);
80 out[24] = window;
81 out[25] = phase;
82 out[26] = normalization;
83 out[27] = precision;
84 return out;
85 }
86
87 [[nodiscard]] static SpectralResult<SpectralFrameContract>
88 decode(std::span<const std::uint8_t> bytes) noexcept {
89 if (bytes.size() != encoded_size)
90 return {std::nullopt, SpectralError::InvalidContract};
91 auto get = [&](std::size_t offset, unsigned count) {
92 std::uint64_t value = 0;
93 for (unsigned i = 0; i < count; ++i)
94 value |= std::uint64_t(bytes[offset + i]) << (8 * i);
95 return value;
96 };
97 SpectralFrameContract contract;
98 contract.version = static_cast<std::uint16_t>(get(0, 2));
99 contract.profile = static_cast<std::uint16_t>(get(2, 2));
100 contract.fft_size = static_cast<std::uint32_t>(get(4, 4));
101 contract.hop = static_cast<std::uint32_t>(get(8, 4));
102 contract.channels = static_cast<std::uint16_t>(get(12, 2));
103 contract.bins = static_cast<std::uint16_t>(get(14, 2));
104 contract.sample_rate_bits = get(16, 8);
105 contract.window = bytes[24];
106 contract.phase = bytes[25];
107 contract.normalization = bytes[26];
108 contract.precision = bytes[27];
109 if (contract.version != 1 || contract.profile != 1 || contract.window != 1 ||
110 contract.phase != 1 || contract.normalization != 1 || contract.precision != 1 ||
111 bytes[28] != 0 || bytes[29] != 0 || bytes[30] != 0 || bytes[31] != 0 ||
112 contract.fft_size < 256 || contract.fft_size > 16384 ||
113 (contract.fft_size & (contract.fft_size - 1)) != 0 || contract.hop == 0 ||
114 contract.hop > contract.fft_size / 2 || contract.channels == 0 ||
115 contract.channels > 16 || contract.bins != contract.fft_size / 2 + 1 ||
116 (contract.sample_rate_bits >> 63) ||
117 (contract.sample_rate_bits & 0x7fffffffffffffffULL) == 0 ||
118 (contract.sample_rate_bits & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL)
119 return {std::nullopt, SpectralError::InvalidContract};
120 return {contract};
121 }
122};
123
126class SpectralIdentity {
127 public:
129 double sample_rate) {
130 if (fft_size < 256 || fft_size > 16384 || (fft_size & (fft_size - 1)) != 0 || hop < 1 ||
131 hop > fft_size / 2 || channels < 1 || channels > 16 || !std::isfinite(sample_rate) ||
132 sample_rate <= 0)
133 return {std::nullopt, SpectralError::InvalidIdentity};
134 return {SpectralIdentity(fft_size, hop, channels, sample_rate)};
135 }
136 int fft_size() const noexcept {
137 return fft_size_;
138 }
139 int hop() const noexcept {
140 return hop_;
141 }
142 int channels() const noexcept {
143 return channels_;
144 }
145 int bins() const noexcept {
146 return fft_size_ / 2 + 1;
147 }
148 double sample_rate() const noexcept {
149 return std::bit_cast<double>(rate_bits_);
150 }
151 std::uint64_t sample_rate_bits() const noexcept {
152 return rate_bits_;
153 }
155 SpectralFrameContract contract;
156 contract.fft_size = static_cast<std::uint32_t>(fft_size_);
157 contract.hop = static_cast<std::uint32_t>(hop_);
158 contract.channels = static_cast<std::uint16_t>(channels_);
159 contract.bins = static_cast<std::uint16_t>(bins());
160 contract.sample_rate_bits = rate_bits_;
161 return contract;
162 }
163 friend bool operator==(const SpectralIdentity&, const SpectralIdentity&) = default;
164
165 private:
166 SpectralIdentity(int n, int h, int c, double rate)
167 : fft_size_(n), hop_(h), channels_(c), rate_bits_(std::bit_cast<std::uint64_t>(rate)) {}
168 int fft_size_, hop_, channels_;
169 std::uint64_t rate_bits_;
170};
171
174class QualifiedSpectralStage {
175 public:
176 enum class Kind : std::uint8_t { IdentityV1, RealMaskV1 };
181 std::span<const float> gains) {
182 if (gains.size() != static_cast<size_t>(identity.channels()) * identity.bins())
183 return {std::nullopt, SpectralError::InvalidMask};
184 for (const float gain : gains)
185 if (!std::isfinite(gain) || gain < 0 || gain > 1)
186 return {std::nullopt, SpectralError::InvalidMask};
187 std::vector<float> owned(gains.begin(), gains.end());
188 for (auto& gain : owned)
189 if (gain == 0)
190 gain = 0.0f;
191 return {QualifiedSpectralStage(identity, Kind::RealMaskV1, std::move(owned))};
192 }
193 const SpectralIdentity& identity() const noexcept {
194 return identity_;
195 }
196 Kind kind() const noexcept {
197 return kind_;
198 }
199 std::span<const float> gains() const noexcept {
200 return gains_;
201 }
202 std::size_t retained_config_bytes() const noexcept {
203 return gains_.capacity() * sizeof(float);
204 }
205
206 private:
208 : identity_(identity), kind_(kind), gains_(std::move(gains)) {}
209 SpectralIdentity identity_;
210 Kind kind_;
211 std::vector<float> gains_;
212};
213
215 std::uint64_t epoch = 0;
216 std::uint64_t sequence = 0;
217 std::int64_t origin = 0;
218 std::int64_t completion = 0;
219 friend bool operator==(const SpectralFrameStamp&, const SpectralFrameStamp&) = default;
220};
221
224 std::span<const std::complex<float>> bins;
225};
226
229 std::span<SpectralFrameStamp> stamps;
230 std::span<std::complex<float>> bins;
231 std::uint32_t count = 0;
232 std::uint32_t bins_per_frame = 0;
237 std::array<std::uint8_t, SpectralFrameContract::encoded_size> encoded_contract{};
238 bool fatal = false;
239 std::int64_t fatal_origin = 0;
240};
241
242} // namespace pulp::graph
Closed catalog value.
Definition spectral_frame.hpp:174
Kind kind() const noexcept
Definition spectral_frame.hpp:196
std::span< const float > gains() const noexcept
Definition spectral_frame.hpp:199
static SpectralResult< QualifiedSpectralStage > identity_v1(SpectralIdentity identity)
Definition spectral_frame.hpp:177
static SpectralResult< QualifiedSpectralStage > real_mask_v1(SpectralIdentity identity, std::span< const float > gains)
Definition spectral_frame.hpp:180
const SpectralIdentity & identity() const noexcept
Definition spectral_frame.hpp:193
std::size_t retained_config_bytes() const noexcept
Definition spectral_frame.hpp:202
Kind
Definition spectral_frame.hpp:176
@ IdentityV1
Definition spectral_frame.hpp:176
@ RealMaskV1
Definition spectral_frame.hpp:176
Profile-one indexed channels: symmetric float Hann, local-window phase, forward scale one,...
Definition spectral_frame.hpp:126
int bins() const noexcept
Definition spectral_frame.hpp:145
int channels() const noexcept
Definition spectral_frame.hpp:142
friend bool operator==(const SpectralIdentity &, const SpectralIdentity &)=default
double sample_rate() const noexcept
Definition spectral_frame.hpp:148
int fft_size() const noexcept
Definition spectral_frame.hpp:136
static SpectralResult< SpectralIdentity > make(int fft_size, int hop, int channels, double sample_rate)
Definition spectral_frame.hpp:128
std::uint64_t sample_rate_bits() const noexcept
Definition spectral_frame.hpp:151
SpectralFrameContract frame_contract() const noexcept
Definition spectral_frame.hpp:154
int hop() const noexcept
Definition spectral_frame.hpp:139
Definition graph_runtime_buffer_assignment.hpp:8
SpectralError
Definition spectral_frame.hpp:15
@ UnsupportedTransactionalReplacement
Definition spectral_frame.hpp:26
@ TransitionPending
Definition spectral_frame.hpp:23
@ PendingMailboxData
Definition spectral_frame.hpp:25
@ OutputUnderrun
Definition spectral_frame.hpp:35
@ InvalidConnection
Definition spectral_frame.hpp:20
@ InvalidFrame
Definition spectral_frame.hpp:31
@ InvalidIdentity
Definition spectral_frame.hpp:17
@ None
Definition spectral_frame.hpp:16
@ SpectralPinnedExecutionUnsupported
Definition spectral_frame.hpp:27
@ SynthesisOverflow
Definition spectral_frame.hpp:34
@ MissingFrame
Definition spectral_frame.hpp:32
@ ChronologyExhausted
Definition spectral_frame.hpp:29
@ StageContractViolation
Definition spectral_frame.hpp:33
@ InvalidMask
Definition spectral_frame.hpp:18
@ Busy
Definition spectral_frame.hpp:24
@ IdentityMismatch
Definition spectral_frame.hpp:19
@ EpochExhausted
Definition spectral_frame.hpp:28
@ RequiresStoppedController
Definition spectral_frame.hpp:22
@ UnsupportedOperation
Definition spectral_frame.hpp:21
@ InvalidContract
Definition spectral_frame.hpp:36
@ CapacityExceeded
Definition spectral_frame.hpp:30
@ None
Definition graph_runtime_plan.hpp:187
STL namespace.
Snapshot-owned payload and descriptors; callback borrows never own storage.
Definition spectral_frame.hpp:228
std::span< std::complex< float > > bins
Definition spectral_frame.hpp:230
std::uint32_t bins_per_frame
Definition spectral_frame.hpp:232
std::uint32_t count
Definition spectral_frame.hpp:231
bool fatal
Definition spectral_frame.hpp:238
SpectralFrameContract contract
Definition spectral_frame.hpp:233
std::int64_t fatal_origin
Definition spectral_frame.hpp:239
std::array< std::uint8_t, SpectralFrameContract::encoded_size > encoded_contract
Canonical wire identity copied at publication.
Definition spectral_frame.hpp:237
std::span< SpectralFrameStamp > stamps
Definition spectral_frame.hpp:229
Versioned, canonical identity carried by every routed spectral batch.
Definition spectral_frame.hpp:49
std::uint8_t window
Definition spectral_frame.hpp:58
std::uint8_t precision
Definition spectral_frame.hpp:61
std::uint16_t version
Definition spectral_frame.hpp:51
std::uint8_t phase
Definition spectral_frame.hpp:59
std::uint16_t bins
Definition spectral_frame.hpp:56
std::uint16_t profile
Definition spectral_frame.hpp:52
friend bool operator==(const SpectralFrameContract &, const SpectralFrameContract &)=default
std::uint32_t hop
Definition spectral_frame.hpp:54
std::uint32_t fft_size
Definition spectral_frame.hpp:53
std::uint16_t channels
Definition spectral_frame.hpp:55
std::array< std::uint8_t, encoded_size > encode() const noexcept
Canonical little-endian value encoding.
Definition spectral_frame.hpp:67
static SpectralResult< SpectralFrameContract > decode(std::span< const std::uint8_t > bytes) noexcept
Definition spectral_frame.hpp:88
std::uint8_t normalization
Definition spectral_frame.hpp:60
std::uint64_t sample_rate_bits
Definition spectral_frame.hpp:57
static constexpr std::size_t encoded_size
Definition spectral_frame.hpp:50
Definition spectral_frame.hpp:222
std::span< const std::complex< float > > bins
Definition spectral_frame.hpp:224
SpectralFrameStamp stamp
Definition spectral_frame.hpp:223
Definition spectral_frame.hpp:214
std::uint64_t sequence
Definition spectral_frame.hpp:216
friend bool operator==(const SpectralFrameStamp &, const SpectralFrameStamp &)=default
std::int64_t origin
Definition spectral_frame.hpp:217
std::int64_t completion
Definition spectral_frame.hpp:218
std::uint64_t epoch
Definition spectral_frame.hpp:215
Definition spectral_frame.hpp:39
SpectralError error
Definition spectral_frame.hpp:41
std::optional< T > value
Definition spectral_frame.hpp:40