63#include <pulp/format/detail/playhead_diff.hpp>
97 std::uint32_t count)
noexcept {
98 if (!src || !dst)
return;
99 for (std::uint32_t i = 0; i < count; ++i)
100 dst[i] =
static_cast<double>(src[i]);
105 std::uint32_t count)
noexcept {
106 if (!src || !dst)
return;
107 for (std::uint32_t i = 0; i < count; ++i)
108 dst[i] =
static_cast<float>(src[i]);
112inline void zero_f64(
double* dst, std::uint32_t count)
noexcept {
114 for (std::uint32_t i = 0; i < count; ++i) dst[i] = 0.0;
164 detail::PlayheadSnapshot& snapshot)
noexcept {
165 ctx.transport_validity = transport.validity;
167 ctx.is_playing = transport.is_playing;
169 ctx.is_recording = transport.is_recording;
171 ctx.is_looping = transport.is_looping;
173 ctx.tempo_bpm = transport.tempo_bpm;
175 ctx.position_beats = transport.position_beats;
177 ctx.position_samples = transport.position_samples;
179 ctx.time_sig_numerator = transport.time_sig_numerator;
180 ctx.time_sig_denominator = transport.time_sig_denominator;
183 ctx.loop_start_beats = transport.loop_start_beats;
184 ctx.loop_end_beats = transport.loop_end_beats;
187 ctx.host_time_ns = transport.host_time_ns;
189 ctx.frame_rate = transport.frame_rate;
191 ctx.bar = transport.host_bar;
194 std::isfinite(ctx.position_beats) &&
195 ctx.time_sig_numerator > 0 && ctx.time_sig_denominator > 0) {
196 detail::derive_bar_from_beats(ctx);
199 detail::compute_playhead_changes(
200 ctx, snapshot, detail::TransportDiffMode::FieldValidity);
220template <std::
size_t MaxChannels = kBoundaryMaxChannels>
229 delay_samples_ = latency_samples > 0 ? latency_samples : 0;
230 if (delay_samples_ > 0) {
231 for (
auto& line : lines_) line.prepare(delay_samples_);
237 for (
auto& line : lines_) line.reset();
258 if (delay_samples_ <= 0 || ch >= lines_.size())
return in;
259 return lines_[ch].process(in,
static_cast<float>(delay_samples_));
269 if (delay_samples_ <= 0 || ch >= lines_.size()) {
272 if (out != in) std::memcpy(out, in,
sizeof(
float) * count);
274 std::memset(out, 0,
sizeof(
float) * count);
278 auto& line = lines_[ch];
279 const float delay =
static_cast<float>(delay_samples_);
281 for (std::uint32_t i = 0; i < count; ++i)
282 out[i] = line.process(in[i], delay);
284 for (std::uint32_t i = 0; i < count; ++i)
285 out[i] = line.process(0.0f, delay);
290 std::array<signal::DelayLine, MaxChannels> lines_{};
291 int delay_samples_ = 0;
316template <std::
size_t MaxChannels>
319 float*
const* out_ptrs,
int out_channels,
320 const float*
const* in_ptrs,
int in_channels,
321 std::uint32_t count) {
322 const bool delayed = bypass.is_latency_compensated() &&
323 out_channels <= static_cast<int>(bypass.channel_capacity());
324 for (
int ch = 0; ch < out_channels; ++ch) {
325 float* dst = out_ptrs ? out_ptrs[ch] :
nullptr;
326 if (dst ==
nullptr)
continue;
328 (in_ptrs && ch < in_channels) ? in_ptrs[ch] :
nullptr;
332 bypass.process_channel(dst, src, count,
333 static_cast<std::size_t
>(ch));
334 }
else if (src !=
nullptr) {
335 std::memcpy(dst, src,
sizeof(
float) * count);
337 std::memset(dst, 0,
sizeof(
float) * count);
365 std::int32_t sample_offset,
401 for (std::size_t i = 0; i < all_params.size(); ++i) {
402 if (all_params[i].
id ==
id)
return i;
415 std::span<const state::ParamInfo> all_params,
416 std::vector<float>& snapshot) {
417 snapshot.resize(all_params.size());
418 for (std::size_t i = 0; i < all_params.size(); ++i) {
419 snapshot[i] = store.
get_value(all_params[i].
id);
439template <
typename AfterRead =
void (*)()>
443 AfterRead&& after_read = [] {}) {
444 if (
state.valid &&
state.generation == generation && snapshot.size() == all_params.size())
449 state.generation = generation;
462 return std::memcmp(¤t, &snapshotted,
sizeof(
float)) != 0;
524 buffer.reserve(event_capacity);
525 buffer.set_realtime_capacity_limit(
true);
553 template <
typename M
idiRange>
554 [[nodiscard]]
bool run(
Processor& processor,
const MidiRange& midi_in) {
555 if constexpr (
requires { midi_in.dropped_event_count(); }) {
556 if (midi_in.dropped_event_count() != 0) {
573 tracker.flush_pending_note_offs();
574 for (
const auto& ev : midi_in) {
A time-ordered list of per-note expression events for one block.
Definition mpe_buffer.hpp:51
Tracks MPE voice state across channels.
Definition mpe_voice_tracker.hpp:67
Definition parameter_event_queue.hpp:82
bool push(const ParameterEvent &e)
Definition parameter_event_queue.hpp:88
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
float get_value(ParamID id) const
Read a parameter's base value (lock-free).
Definition store.hpp:186
void set_value_rt(ParamID id, float value)
Real-time-safe parameter write for use from the audio thread.
bool state_snapshot_is_current(std::uint64_t generation) const noexcept
True when no writer is in flight and none has advanced the generation past generation.
Definition store.hpp:330
void bind_tracker_to_buffer(MpeVoiceTracker &tracker, MpeBuffer &out, int32_t ¤t_sample_offset, bool *expression_event_dropped=nullptr)
Convenience: install tracker callbacks that forward events to out with the given sample offset.
Definition mpe_buffer.hpp:163
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
Process context — passed every audio callback with transport state.
Definition process_context.hpp:89
Definition parameter_event_queue.hpp:34