Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
processor.hpp
Go to the documentation of this file.
1#pragma once
2
12#include <pulp/format/panic.hpp>
13#include <pulp/state/store.hpp>
17#include <array>
18#include <atomic>
19#include <cstddef>
20#include <cstdint>
21#include <functional>
22#include <mutex>
23#include <optional>
24#include <unordered_map>
25#include <memory>
26#include <span>
27#include <string>
28#include <string_view>
29#include <vector>
30
34#define PULP_FORMAT_HAS_EDITOR_BACKGROUND 1
35
36// Forward-declared, never included: `pulp-wclap-dsp` compiles core/format
37// without the data-plane include path (the wasm DSP build has no editor), so
38// pulling in value_channel_set.hpp here breaks that target. A pointer return
39// needs only the declaration. pulp::view::ValueChannelSet names the same class
40// as pulp::dataplane::ValueChannelSet.
41namespace pulp::dataplane {
42class ValueChannelSet;
43}
44
45namespace pulp::view {
47class View;
48using dataplane::ValueChannelSet;
49}
50
51namespace pulp::format {
52
53namespace detail {
54
67inline std::mutex& editor_resize_mutex() {
68 static std::mutex m;
69 return m;
70}
72 std::function<bool(uint32_t, uint32_t)>;
78 std::unordered_map<const void*, EditorResizeHandlerEntry>;
79
80inline std::unordered_map<const void*, EditorResizeHandlerSet>&
82 static std::unordered_map<const void*, EditorResizeHandlerSet> table;
83 return table;
84}
85
89inline std::unordered_map<const void*, bool>& standalone_processors() {
90 static std::unordered_map<const void*, bool> table;
91 return table;
92}
93
98inline std::unordered_map<const void*, std::shared_ptr<PanicState>>& panic_states() {
99 static std::unordered_map<const void*, std::shared_ptr<PanicState>> table;
100 return table;
101}
102
103} // namespace detail
104
105class EditorFactory;
106
139namespace detail {
146 std::atomic<const void*> queue{nullptr};
147 std::atomic<bool> read{false};
148};
149inline constexpr std::size_t kParamEventsOptOutSlots = 256;
150inline constexpr std::size_t kParamEventsOptOutProbe = 8;
152inline std::atomic<std::size_t> param_events_opt_out_count{0};
153
154inline std::size_t param_events_opt_out_home(const void* queue) noexcept {
155 auto v = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(queue));
156 v ^= v >> 33;
157 v *= 0xff51afd7ed558ccdULL;
158 v ^= v >> 33;
159 return static_cast<std::size_t>(v) & (kParamEventsOptOutSlots - 1);
160}
161
163inline ParamEventsOptOutSlot* param_events_opt_out_find(const void* queue) noexcept {
164 const auto home = param_events_opt_out_home(queue);
165 for (std::size_t i = 0; i < kParamEventsOptOutProbe; ++i) {
166 auto& slot = param_events_opt_out_slots[(home + i) & (kParamEventsOptOutSlots - 1)];
167 if (slot.queue.load(std::memory_order_acquire) == queue)
168 return &slot;
169 }
170 return nullptr;
171}
172} // namespace detail
173
175public:
177 // Adapters clear the handler on editor close. If abnormal teardown
178 // skips that close, make address reuse safe before this new instance
179 // can observe a stale handler left under the same `this` key. Keep the
180 // virtual destructor exactly defaulted: its spelling/order is part of
181 // the frozen Processor node ABI.
182 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
183 detail::editor_resize_handlers().erase(this);
184 detail::standalone_processors().erase(this);
185 detail::panic_states().erase(this);
186 }
187 virtual ~Processor();
188
195 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
196 return detail::standalone_processors().count(this) != 0
199 }
200
203 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
204 if (kind == EditorHostKind::standalone)
205 detail::standalone_processors()[this] = true;
206 else
207 detail::standalone_processors().erase(this);
208 }
209
211 virtual PluginDescriptor descriptor() const = 0;
212
215 virtual void define_parameters(state::StateStore& store) = 0;
216
219 virtual void prepare(const PrepareContext& context) = 0;
220
228 virtual void release() {}
229
253 virtual void suspend() {}
254
257 virtual void resume() {}
258
267 virtual std::vector<uint8_t> serialize_plugin_state() const { return {}; }
268
275 void publish_plugin_state_snapshot(std::vector<uint8_t> bytes) {
276 auto snapshot = std::make_shared<const std::vector<uint8_t>>(std::move(bytes));
277 std::atomic_store_explicit(&published_plugin_state_, std::move(snapshot),
278 std::memory_order_release);
279 }
280
281 void publish_plugin_state_snapshot(std::span<const uint8_t> bytes) {
282 publish_plugin_state_snapshot(std::vector<uint8_t>(bytes.begin(), bytes.end()));
283 }
284
288 std::shared_ptr<const std::vector<uint8_t>> published_plugin_state_snapshot() const {
289 return std::atomic_load_explicit(&published_plugin_state_,
290 std::memory_order_acquire);
291 }
292
303 virtual bool deserialize_plugin_state(std::span<const uint8_t>) { return true; }
304
316
333 virtual void on_memory_pressure(MemoryPressure /*level*/) {}
334
338 virtual int latency_samples() const { return 0; }
339
369
382 struct BusesLayout {
383 std::vector<int> inputs;
384 std::vector<int> outputs;
385 };
386
402 virtual bool is_bus_layout_supported(const BusesLayout& layout) const {
403 const auto desc = descriptor();
404 if (!desc.supported_bus_layouts.empty()) {
405 return std::any_of(desc.supported_bus_layouts.begin(),
406 desc.supported_bus_layouts.end(),
407 [&](const auto& declared) {
408 return declared.inputs == layout.inputs &&
409 declared.outputs == layout.outputs;
410 });
411 }
412 if (!layout.inputs.empty() &&
413 layout.inputs.size() != desc.input_buses.size())
414 return false;
415 if (!layout.outputs.empty() &&
416 layout.outputs.size() != desc.output_buses.size())
417 return false;
418 auto side_ok = [](const auto& proposed, const auto& declared) {
419 for (std::size_t i = 0; i < proposed.size(); ++i) {
420 const int channels = proposed[i];
421 if (channels == 1 || channels == 2) continue;
422 if (channels == 0 &&
423 (declared[i].default_channels == 0 || declared[i].optional))
424 continue;
425 return false;
426 }
427 return true;
428 };
429 if (!layout.inputs.empty() && !side_ok(layout.inputs, desc.input_buses))
430 return false;
431 if (!layout.outputs.empty() && !side_ok(layout.outputs, desc.output_buses))
432 return false;
433 return true;
434 }
435
463 void flag_latency_changed() noexcept {
464 latency_changed_.store(true, std::memory_order_release);
465 }
466 void flag_tail_changed() noexcept {
467 tail_changed_.store(true, std::memory_order_release);
468 }
469
476 // Polled by the adapters every block; a plain load keeps the common
477 // nothing-changed case free of read-modify-write traffic.
479 return latency_changed_.load(std::memory_order_relaxed) &&
480 latency_changed_.exchange(false, std::memory_order_acq_rel);
481 }
483 return tail_changed_.load(std::memory_order_relaxed) &&
484 tail_changed_.exchange(false, std::memory_order_acq_rel);
485 }
486
492 bool latency_change_pending() const noexcept {
493 return latency_changed_.load(std::memory_order_acquire);
494 }
495 bool tail_change_pending() const noexcept {
496 return tail_changed_.load(std::memory_order_acquire);
497 }
498
505 void flag_note_names_changed() noexcept {
506 note_names_changed_.store(true, std::memory_order_release);
507 }
509 return note_names_changed_.exchange(false, std::memory_order_acq_rel);
510 }
511 bool note_names_change_pending() const noexcept {
512 return note_names_changed_.load(std::memory_order_acquire);
513 }
514
535 void flag_state_dirty() noexcept {
536 state_dirty_.store(true, std::memory_order_release);
537 }
538 bool consume_state_dirty_flag() noexcept {
539 return state_dirty_.exchange(false, std::memory_order_acq_rel);
540 }
541 bool state_dirty_pending() const noexcept {
542 return state_dirty_.load(std::memory_order_acquire);
543 }
544
563 virtual void process(
564 audio::BufferView<float>& audio_output,
565 const audio::BufferView<const float>& audio_input,
566 midi::MidiBuffer& midi_in,
567 midi::MidiBuffer& midi_out,
568 const ProcessContext& context) = 0;
569
573
575 virtual bool has_editor() const { return true; }
576
594 std::vector<std::string_view> scripts;
595 std::vector<std::string_view> materialized_documents;
596 bool empty() const noexcept { return scripts.empty() && materialized_documents.empty(); }
597 };
598
600 virtual std::pair<uint32_t, uint32_t> editor_size() const { return {400, 300}; }
601
616 virtual ViewSize view_size() const {
617#ifdef PULP_PLUGIN_DESIGN_W
619 PULP_PLUGIN_DESIGN_W, PULP_PLUGIN_DESIGN_H,
620 PULP_PLUGIN_DESIGN_MIN_W, PULP_PLUGIN_DESIGN_MIN_H,
621 PULP_PLUGIN_DESIGN_MAX_W, PULP_PLUGIN_DESIGN_MAX_H);
622#else
623 auto [w, h] = editor_size();
624 return ViewSize{w, h, 0, 0, 0, 0};
625#endif
626 }
627
637 virtual std::unique_ptr<view::View> create_view();
638
649 using ViewDeleter = void (*)(view::View*);
650
651 SettingsSection() noexcept : view(nullptr, &no_view) {}
652 SettingsSection(std::string title, std::unique_ptr<view::View> view);
653 ~SettingsSection() = default;
654 SettingsSection(SettingsSection&&) noexcept = default;
655 SettingsSection& operator=(SettingsSection&&) noexcept = default;
657 SettingsSection& operator=(const SettingsSection&) = delete;
658
660 std::unique_ptr<view::View> take_view();
661
662 std::string title;
665 std::unique_ptr<view::View, ViewDeleter> view;
666
667 private:
668 static void no_view(view::View*) noexcept {}
669 };
670
673 virtual void on_view_opened(view::View& /*view*/) {}
674
678 virtual void on_view_closed(view::View& /*view*/) {}
679
682 virtual void on_view_resized(view::View& /*view*/, uint32_t /*w*/, uint32_t /*h*/) {}
683
706 bool request_editor_resize(uint32_t width, uint32_t height) {
707 std::vector<detail::EditorResizeHandlerEntry> candidates;
708 {
709 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
710 auto& table = detail::editor_resize_handlers();
711 auto it = table.find(this);
712 if (it == table.end()) return false;
713 candidates.reserve(it->second.size());
714 for (const auto& [owner, entry] : it->second) {
715 (void)owner;
716 candidates.push_back(entry);
717 }
718 }
719
720 // Hosts may retain an editor object after detaching it from its
721 // window. Such a stale-but-live registration must not make a reopened
722 // editor look ambiguous. Evaluate attachment predicates outside the
723 // side-table mutex: they are host callbacks and may re-enter teardown.
724 // Two genuinely active views remain ambiguous and are refused.
726 for (const auto& candidate : candidates) {
727 bool active = true;
728 if (candidate.is_active) {
729 // Format adapters own this predicate and must keep it
730 // non-throwing: Processor is also compiled by exception-free
731 // targets such as WebCLAP.
732 active = candidate.is_active();
733 }
734 if (!active) continue;
735 if (handler) return false;
736 handler = candidate.handler;
737 }
738 return handler ? handler(width, height) : false;
739 }
740
743 virtual void on_host_transport_changed(bool /*is_playing*/,
744 double /*position_seconds*/) {}
745
750 virtual void on_host_tempo_changed(double /*new_tempo_bpm*/) {}
751
759 virtual std::unique_ptr<class AraDocumentController>
761
766 virtual view::ScriptedUiSession* active_scripted_ui() { return nullptr; }
767 virtual const view::ScriptedUiSession* active_scripted_ui() const { return nullptr; }
768
775 virtual std::vector<SettingsSection> settings_sections() { return {}; }
776
784 const PrepareContext&) const {
785 return {};
786 }
787
798
808 virtual void process(
810 midi::MidiBuffer& midi_in,
811 midi::MidiBuffer& midi_out,
812 const ProcessContext& context) {
813 auto* output = audio.main_output();
814 if (!output) return;
815
817 auto* input = audio.main_input();
818 auto* previous_sidechain = sidechain_;
819 sidechain_ = audio.sidechain_input();
820 process(*output, input ? *input : empty_input, midi_in, midi_out, context);
821 sidechain_ = previous_sidechain;
822 }
823
831 virtual std::vector<std::byte> serialize_dsp_state() const { return {}; }
832 virtual bool restore_dsp_state(const std::vector<std::byte>& /*blob*/) { return false; }
833
842 virtual bool supports_editor_reload() const { return false; }
843
850 virtual std::uint64_t editor_reload_generation() const { return 0; }
851
858 const BusesLayout& layout);
859
868 virtual void process_f64(
869 audio::BufferView<double>& audio_output,
870 const audio::BufferView<const double>& audio_input,
871 midi::MidiBuffer& midi_in,
872 midi::MidiBuffer& midi_out,
873 const ProcessContext& context);
874
881 virtual void process_f64(
883 midi::MidiBuffer& midi_in,
884 midi::MidiBuffer& midi_out,
885 const ProcessContext& context);
886
925 virtual void on_non_realtime_tick() {}
926
943 virtual bool non_realtime_tick_pending() const { return false; }
944
955 state::StateStore& state() { return *state_store_; }
956 const state::StateStore& state() const { return *state_store_; }
957
960 const audio::BufferView<const float>* sidechain_input() const { return sidechain_; }
961
965 const midi::MpeBuffer* mpe_input() const { return mpe_input_; }
966
970 const midi::UmpBuffer* ump_input() const { return ump_input_; }
971
984 if (param_events_ != nullptr &&
985 detail::param_events_opt_out_count.load(std::memory_order_relaxed) != 0) {
986 if (auto* slot = detail::param_events_opt_out_find(param_events_))
987 slot->read.store(true, std::memory_order_relaxed);
988 }
989 return param_events_;
990 }
991
997 return modulation_events_;
998 }
999
1016 std::uint32_t sample_offset) noexcept {
1017 if (output_param_events_ == nullptr) return false;
1018 return output_param_events_->push(state::ParameterEvent{
1019 id, static_cast<int32_t>(sample_offset), value, 0});
1020 }
1021
1024 return output_param_events_;
1025 }
1026
1028 void set_state_store(state::StateStore* store) { state_store_ = store; }
1030 void set_sidechain(const audio::BufferView<const float>* sc) { sidechain_ = sc; }
1032 void set_mpe_input(const midi::MpeBuffer* mpe) { mpe_input_ = mpe; }
1034 void set_ump_input(const midi::UmpBuffer* ump) { ump_input_ = ump; }
1039 modulation_events_ = events;
1040 }
1041
1046
1054 std::function<bool(uint32_t, uint32_t)> handler) {
1055 set_editor_resize_handler(this, std::move(handler));
1056 }
1057
1062 const void* editor_owner,
1063 std::function<bool(uint32_t, uint32_t)> handler,
1064 std::function<bool()> is_active = {}) {
1065 if (!editor_owner) return;
1066 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
1067 auto& table = detail::editor_resize_handlers();
1068 if (handler) {
1069 table[this][editor_owner] = {
1070 std::move(handler), std::move(is_active)};
1071 } else {
1072 auto it = table.find(this);
1073 if (it == table.end()) return;
1074 it->second.erase(editor_owner);
1075 if (it->second.empty()) table.erase(it);
1076 }
1077 }
1078
1093 virtual std::vector<NoteName> note_names() const { return {}; }
1094
1111 virtual view::ValueChannelSet* value_channels() { return nullptr; }
1112
1124 const std::function<void(view::ValueChannelSet*)>& visitor) {
1125 if (visitor) visitor(value_channels());
1126 }
1127
1138 const std::function<void(view::ScriptedUiSession*)>& visitor) {
1139 if (visitor) visitor(active_scripted_ui());
1140 }
1141
1145 const std::function<void(const view::ScriptedUiSession*)>& visitor) const {
1146 if (visitor) visitor(active_scripted_ui());
1147 }
1148
1154 virtual bool supports_in_place_scripted_ui_reload() const { return false; }
1155
1163 virtual bool reload_active_scripted_ui_in_place(std::string* /*error*/) {
1164 return false;
1165 }
1166
1171 return false;
1172 }
1173
1190 virtual std::optional<std::uint32_t> editor_background() const {
1191 return std::nullopt;
1192 }
1193
1196 virtual EditorPrewarm editor_prewarm() const { return {}; }
1197
1217 return true;
1218 }
1219
1230 return true;
1231 }
1232
1261
1270 virtual void on_panic(PanicMode /*mode*/) {}
1271
1280 panic_state()->request(mode);
1281 }
1282
1285 return panic_state()->capabilities();
1286 }
1287
1290 std::shared_ptr<PanicState> panic_state() const {
1291 std::lock_guard<std::mutex> lock(detail::editor_resize_mutex());
1292 auto& slot = detail::panic_states()[this];
1293 if (!slot)
1294 slot = std::make_shared<PanicState>();
1295 return slot;
1296 }
1297
1298 private:
1299 std::shared_ptr<const std::vector<uint8_t>> published_plugin_state_;
1300 static constexpr std::size_t kF64FallbackMaxBuses = 16;
1301
1302 static bool requires_rich_f64_fallback(const ProcessBuffers64& audio);
1303
1304 bool f64_fallback_capacity_ok(std::size_t input_channels,
1305 std::size_t output_channels,
1306 std::size_t frames) const;
1307
1308 bool f64_fallback_process_buffers_capacity_ok(
1309 const ProcessBuffers64& audio) const;
1310
1311 static void copy_f64_to_f32(audio::BufferView<float> dst,
1313
1314 static void copy_f32_to_f64(audio::BufferView<double> dst,
1316
1317 static void clear_active_outputs(ProcessBuffers64& audio);
1318
1319 void process_f64_via_f32_process_buffers(ProcessBuffers64& audio,
1320 midi::MidiBuffer& midi_in,
1321 midi::MidiBuffer& midi_out,
1322 const ProcessContext& context);
1323
1324 state::StateStore* state_store_ = nullptr;
1325 const audio::BufferView<const float>* sidechain_ = nullptr;
1326 const midi::MpeBuffer* mpe_input_ = nullptr;
1327 const midi::UmpBuffer* ump_input_ = nullptr;
1328 const state::ParameterEventQueue* param_events_ = nullptr;
1329 const state::ModulationEventQueue* modulation_events_ = nullptr;
1330 state::ParameterEventQueue* output_param_events_ = nullptr;
1331 audio::Buffer<float> f64_fallback_input_scratch_;
1332 audio::Buffer<float> f64_fallback_output_scratch_;
1333 std::array<audio::Buffer<float>, kF64FallbackMaxBuses> f64_fallback_input_bus_scratch_{};
1334 std::array<audio::Buffer<float>, kF64FallbackMaxBuses> f64_fallback_output_bus_scratch_{};
1335 std::array<ProcessBusBufferView<const float>, kF64FallbackMaxBuses> f64_fallback_input_views_{};
1336 std::array<ProcessBusBufferView<float>, kF64FallbackMaxBuses> f64_fallback_output_views_{};
1337 // RT-safe pending flags published from process() and consumed by adapters
1338 // on the host / main thread.
1339 std::atomic<bool> latency_changed_{false};
1340 std::atomic<bool> tail_changed_{false};
1341 std::atomic<bool> note_names_changed_{false};
1342 std::atomic<bool> state_dirty_{false};
1343};
1344
1363 public:
1368 disarm();
1369 }
1370
1372 void arm(bool opted_out, const state::ParameterEventQueue* queue) noexcept {
1373 disarm();
1374 if (!opted_out || queue == nullptr)
1375 return;
1376 const auto home = detail::param_events_opt_out_home(queue);
1377 for (std::size_t i = 0; i < detail::kParamEventsOptOutProbe; ++i) {
1378 auto& slot = detail::param_events_opt_out_slots[(home + i) &
1380 const void* expected = nullptr;
1381 // Only a slot this monitor claims is reset: a probed slot may
1382 // belong to another adapter whose record must survive.
1383 if (slot.queue.compare_exchange_strong(expected, queue, std::memory_order_acq_rel)) {
1384 slot.read.store(false, std::memory_order_relaxed);
1385 slot_ = &slot;
1386 detail::param_events_opt_out_count.fetch_add(1, std::memory_order_relaxed);
1387 return;
1388 }
1389 }
1390 }
1391
1393 bool read_while_opted_out() const noexcept {
1394 return slot_ != nullptr && slot_->read.load(std::memory_order_relaxed);
1395 }
1396
1399 bool report(const Processor& processor);
1400
1401 private:
1402 void disarm() noexcept {
1403 if (slot_ == nullptr)
1404 return;
1405 slot_->queue.store(nullptr, std::memory_order_release);
1406 slot_->read.store(false, std::memory_order_relaxed);
1407 detail::param_events_opt_out_count.fetch_sub(1, std::memory_order_relaxed);
1408 slot_ = nullptr;
1409 }
1410
1411 detail::ParamEventsOptOutSlot* slot_ = nullptr;
1412 bool reported_ = false;
1413};
1414
1416using ProcessorFactory = std::unique_ptr<Processor>(*)();
1417
1418} // namespace pulp::format
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
Owning multi-channel audio buffer with contiguous storage.
Definition buffer.hpp:119
A processor's declared channels.
Definition value_channel_set.hpp:61
Builds a processor's editors.
Definition editor_host.hpp:576
void arm(bool opted_out, const state::ParameterEventQueue *queue) noexcept
Registers queue when the processor opted out; does nothing otherwise.
Definition processor.hpp:1372
~ParamEventsOptOutMonitor()
Definition processor.hpp:1367
bool read_while_opted_out() const noexcept
True once the processor read param_events() while opted out.
Definition processor.hpp:1393
bool report(const Processor &processor)
Logs, once, that processor read param_events() while opted out.
ParamEventsOptOutMonitor & operator=(const ParamEventsOptOutMonitor &)=delete
ParamEventsOptOutMonitor(const ParamEventsOptOutMonitor &)=delete
Definition processor.hpp:174
const midi::MpeBuffer * mpe_input() const
Access the per-note MPE expression buffer for this block.
Definition processor.hpp:965
virtual view::ValueChannelSet * value_channels()
Named value channels this processor publishes for its UI — gain reduction, an envelope follower,...
Definition processor.hpp:1111
virtual std::pair< uint32_t, uint32_t > editor_size() const
Preferred editor window size in logical pixels.
Definition processor.hpp:600
const audio::BufferView< const float > * sidechain_input() const
Access sidechain input buffer (set by format adapters before process).
Definition processor.hpp:960
virtual void process(ProcessBuffers &audio, midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ProcessContext &context)
Additive multi-bus process entry point.
Definition processor.hpp:808
virtual PrepareResourceLimit check_prepare_resource_limits(const PrepareContext &context) const
Check the processor's estimate against the host-supplied prepare limits.
Definition processor.hpp:793
void flag_note_names_changed() noexcept
Note-name change notification, same shape as the latency / tail pair above.
Definition processor.hpp:505
virtual std::uint64_t editor_reload_generation() const
Monotonic counter that increments each time this processor's editor content should be rebuilt (after ...
Definition processor.hpp:850
virtual void on_memory_pressure(MemoryPressure)
Called on the main/UI thread when the host observes memory pressure.
Definition processor.hpp:333
bool consume_latency_changed_flag() noexcept
Adapter-side polling helper.
Definition processor.hpp:478
virtual bool has_editor() const
Editor support.
Definition processor.hpp:575
virtual PluginDescriptor descriptor() const =0
Return the plugin's metadata. Called once during initialization.
virtual void process(audio::BufferView< float > &audio_output, const audio::BufferView< const float > &audio_input, midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ProcessContext &context)=0
Process one buffer of audio.
void prepare_f64_fallback_scratch(const PrepareContext &context, const BusesLayout &layout)
virtual bool supports_editor_reload() const
Editor live-reload support (live-swap 1.9).
Definition processor.hpp:842
virtual ViewSize view_size() const
Return the full view size hints (preferred/min/max).
Definition processor.hpp:616
virtual void define_parameters(state::StateStore &store)=0
Register parameters with the state store.
void set_editor_host_kind(EditorHostKind kind)
Definition processor.hpp:202
state::StateStore & state()
Access the parameter state store.
Definition processor.hpp:955
virtual void on_view_opened(view::View &)
Called after a view has been constructed and attached.
Definition processor.hpp:673
virtual EditorFactory * editor_factory()
The UI-agnostic editor factory for this processor, or null.
virtual void release()
Release resources.
Definition processor.hpp:228
const state::StateStore & state() const
Definition processor.hpp:956
virtual void on_host_tempo_changed(double)
Called when the host's transport tempo changes.
Definition processor.hpp:750
void publish_plugin_state_snapshot(std::vector< uint8_t > bytes)
Publish an immutable custom-state snapshot from a non-audio thread.
Definition processor.hpp:275
bool latency_change_pending() const noexcept
Non-mutating peek used by adapters that need to decide whether to ping the host for a main-thread cal...
Definition processor.hpp:492
const state::ParameterEventQueue * param_events() const
Access sample-accurate parameter automation for this block.
Definition processor.hpp:983
virtual void process_f64(audio::BufferView< double > &audio_output, const audio::BufferView< const double > &audio_input, midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ProcessContext &context)
Native double-precision process entry point.
const state::ModulationEventQueue * modulation_events() const
Timestamped host modulation events for the current block.
Definition processor.hpp:996
EditorHostKind editor_host_kind() const
Whether this processor runs inside a plug-in host or the Pulp standalone app.
Definition processor.hpp:194
virtual void on_non_realtime_tick()
Non-realtime maintenance tick.
Definition processor.hpp:925
virtual bool reload_active_scripted_ui_in_place(std::string *)
Reload a processor-owned scripted editor in place when the editor generation changes.
Definition processor.hpp:1163
virtual std::vector< uint8_t > serialize_plugin_state() const
Serialize plugin-owned state that is not part of StateStore.
Definition processor.hpp:267
virtual void on_panic(PanicMode)
Panic hook: stop this plug-in's own voices.
Definition processor.hpp:1270
virtual bool is_bus_layout_supported(const BusesLayout &layout) const
Validate a proposed bus layout.
Definition processor.hpp:402
virtual view::ScriptedUiSession * active_scripted_ui()
Return the active scripted UI session when a custom create_view() path owns one.
Definition processor.hpp:766
void request_panic(PanicMode mode=PanicMode::immediate)
Ask the plug-in to silence itself and, where the host has MIDI output, end the notes it has sent.
Definition processor.hpp:1279
void set_state_store(state::StateStore *store)
Definition processor.hpp:1028
virtual int latency_samples() const
Latency in samples introduced by this processor (default 0).
Definition processor.hpp:338
void set_param_events(const state::ParameterEventQueue *events)
Definition processor.hpp:1036
virtual void on_view_closed(view::View &)
Called immediately before a view is destroyed.
Definition processor.hpp:678
void set_mpe_input(const midi::MpeBuffer *mpe)
Definition processor.hpp:1032
bool note_names_change_pending() const noexcept
Definition processor.hpp:511
void set_editor_resize_handler(const void *editor_owner, std::function< bool(uint32_t, uint32_t)> handler, std::function< bool()> is_active={})
Definition processor.hpp:1061
bool tail_change_pending() const noexcept
Definition processor.hpp:495
virtual bool restore_dsp_state(const std::vector< std::byte > &)
Definition processor.hpp:832
void set_output_param_events(state::ParameterEventQueue *events)
Definition processor.hpp:1045
virtual void resume()
Resume processing after a prior suspend().
Definition processor.hpp:257
virtual EditorPrewarm editor_prewarm() const
See EditorPrewarm above.
Definition processor.hpp:1196
virtual std::vector< SettingsSection > settings_sections()
Settings tabs this plugin contributes, composed by the host alongside its own host-owned tabs (e....
Definition processor.hpp:775
Processor()
Definition processor.hpp:176
virtual bool wants_sample_accurate_parameters() const
Whether this processor reads sample-accurate parameter automation: param_events(),...
Definition processor.hpp:1216
std::shared_ptr< const std::vector< uint8_t > > published_plugin_state_snapshot() const
Returns null until the plugin opts into published snapshots.
Definition processor.hpp:288
virtual void suspend()
Pause processing for a heavy main-thread operation (preset load, convolution kernel reallocation,...
Definition processor.hpp:253
bool consume_state_dirty_flag() noexcept
Definition processor.hpp:538
virtual PrepareResourceUsage estimate_prepare_resources(const PrepareContext &) const
Estimate storage the next prepare() will allocate or reserve.
Definition processor.hpp:783
void prepare_f64_fallback_scratch(const PrepareContext &context)
Prepare scratch used by the default process_f64() fallback.
void set_sidechain(const audio::BufferView< const float > *sc)
Definition processor.hpp:1030
virtual const view::ScriptedUiSession * active_scripted_ui() const
Definition processor.hpp:767
const state::ParameterEventQueue * output_param_events() const
Access the output parameter-event queue, if the adapter wired one.
Definition processor.hpp:1023
const midi::UmpBuffer * ump_input() const
Access the MIDI 2.0 UMP buffer for this block.
Definition processor.hpp:970
virtual std::unique_ptr< class AraDocumentController > create_ara_document_controller()
Optional ARA 2.x document-controller factory.
virtual void visit_value_channels(const std::function< void(view::ValueChannelSet *)> &visitor)
Synchronously visit the current value-channel set while the processor keeps it alive.
Definition processor.hpp:1123
void set_editor_resize_handler(std::function< bool(uint32_t, uint32_t)> handler)
Definition processor.hpp:1053
bool consume_note_names_changed_flag() noexcept
Definition processor.hpp:508
virtual void on_view_resized(view::View &, uint32_t, uint32_t)
Called when the host resizes the editor window.
Definition processor.hpp:682
bool push_output_param_event(state::ParamID id, float value, std::uint32_t sample_offset) noexcept
Emit a sample-accurate parameter change to the host from process().
Definition processor.hpp:1015
bool consume_tail_changed_flag() noexcept
Definition processor.hpp:482
void flag_state_dirty() noexcept
Non-parameter state-change notification, same shape as the latency / tail / note-name flags above.
Definition processor.hpp:535
void set_modulation_events(const state::ModulationEventQueue *events)
Definition processor.hpp:1038
virtual bool supports_in_place_scripted_ui_reload() const
Opt in when a processor-owned scripted editor must reload its existing session rather than rebuilding...
Definition processor.hpp:1154
virtual std::optional< std::uint32_t > editor_background() const
The editor's own background colour, as 0xRRGGBB.
Definition processor.hpp:1190
virtual bool process_block(ProcessBlock &)
Process the additive block contract directly.
Definition processor.hpp:1170
void publish_plugin_state_snapshot(std::span< const uint8_t > bytes)
Definition processor.hpp:281
virtual std::unique_ptr< view::View > create_view()
Create a custom view for this processor.
virtual bool non_realtime_tick_pending() const
RT-safe query: "I have non-realtime work waiting".
Definition processor.hpp:943
virtual void visit_active_scripted_ui(const std::function< void(view::ScriptedUiSession *)> &visitor)
Synchronously visit the active scripted-UI session while the processor keeps it alive.
Definition processor.hpp:1137
PanicCapabilities panic_capabilities() const
What a panic request can do in the current host. Cheap; any thread.
Definition processor.hpp:1284
virtual bool wants_au_scheduled_parameter_slices() const
AU v2 only, and only for a processor that wants sample-accurate parameters.
Definition processor.hpp:1229
virtual std::vector< std::byte > serialize_dsp_state() const
Opt-in DSP-state carry across a hot-reload (reload lane, item 1.6).
Definition processor.hpp:831
virtual std::vector< NoteName > note_names() const
Names for individual notes, shown by hosts in the piano roll and drum editors.
Definition processor.hpp:1093
virtual bool deserialize_plugin_state(std::span< const uint8_t >)
Restore plugin-owned state previously returned by serialize_plugin_state().
Definition processor.hpp:303
std::shared_ptr< PanicState > panic_state() const
The request/state object adapters service.
Definition processor.hpp:1290
void set_ump_input(const midi::UmpBuffer *ump)
Definition processor.hpp:1034
virtual void on_host_transport_changed(bool, double)
Called when the host's transport state transitions between playing and stopped, or jumps to a new pos...
Definition processor.hpp:743
MemoryPressure
Memory-pressure levels a host can surface to a plugin.
Definition processor.hpp:308
@ Critical
Serious — drop every cache the plugin can rebuild on demand (image atlases, analysis buffers,...
Definition processor.hpp:314
@ Advisory
Hint only — trim obviously disposable caches, keep working set.
Definition processor.hpp:310
bool state_dirty_pending() const noexcept
Definition processor.hpp:541
void flag_latency_changed() noexcept
Cross-adapter latency / tail change notifications.
Definition processor.hpp:463
void flag_tail_changed() noexcept
Definition processor.hpp:466
virtual void visit_active_scripted_ui(const std::function< void(const view::ScriptedUiSession *)> &visitor) const
Const counterpart to visit_active_scripted_ui().
Definition processor.hpp:1144
bool request_editor_resize(uint32_t width, uint32_t height)
Editor-INITIATED host-window resize (the plugin↔host direction that on_view_resized does not cover).
Definition processor.hpp:706
virtual void process_f64(ProcessBuffers64 &audio, midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ProcessContext &context)
Additive double-precision richer-surface process entry point.
virtual void prepare(const PrepareContext &context)=0
Prepare for processing.
Collection of timestamped MIDI events within a single audio buffer period.
Definition buffer.hpp:31
A time-ordered list of per-note expression events for one block.
Definition mpe_buffer.hpp:51
A time-ordered list of UMP events for one audio block.
Definition ump_buffer.hpp:41
Definition parameter_event_queue.hpp:50
Definition parameter_event_queue.hpp:82
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
Definition scripted_ui.hpp:125
Definition view.hpp:73
Processor-level MIDI panic: a request any thread can raise, serviced on the audio thread at the start...
Sample-accurate MPE expression event stream.
Definition analyzer_provider.hpp:12
Definition audio_bridge.hpp:9
Definition child_process_manager.hpp:18
The plugin processor interface.
Definition device_quotas.hpp:67
constexpr std::size_t kParamEventsOptOutSlots
Definition processor.hpp:149
std::atomic< std::size_t > param_events_opt_out_count
Definition processor.hpp:152
constexpr std::size_t kParamEventsOptOutProbe
Definition processor.hpp:150
std::unordered_map< const void *, std::shared_ptr< PanicState > > & panic_states()
Panic request/state per processor, in a side table for the same layout reason as the handlers above.
Definition processor.hpp:98
ParamEventsOptOutSlot param_events_opt_out_slots[kParamEventsOptOutSlots]
Definition processor.hpp:151
std::unordered_map< const void *, EditorResizeHandlerSet > & editor_resize_handlers()
Definition processor.hpp:81
std::function< bool(uint32_t, uint32_t)> EditorResizeHandler
Definition processor.hpp:71
std::unordered_map< const void *, EditorResizeHandlerEntry > EditorResizeHandlerSet
Definition processor.hpp:77
std::size_t param_events_opt_out_home(const void *queue) noexcept
Definition processor.hpp:154
ParamEventsOptOutSlot * param_events_opt_out_find(const void *queue) noexcept
The slot registered for queue, or null.
Definition processor.hpp:163
std::mutex & editor_resize_mutex()
Backing store for the editor→host resize handler (see Processor::request_editor_resize).
Definition processor.hpp:67
std::unordered_map< const void *, bool > & standalone_processors()
Processors a Pulp standalone app owns, keyed by this so Processor's layout is unchanged.
Definition processor.hpp:89
Definition mpe_expression.hpp:41
What the product grants a device: the quota table indexed by capability tier and live thermal state.
Definition aax_editor.hpp:31
PanicMode
How hard a panic stops the plug-in.
Definition panic.hpp:33
@ immediate
Hard stop: voices are reset and release tails cut (MIDI CC 120 semantic).
Definition panic.hpp:36
@ home
Definition editor_host.hpp:353
std::unique_ptr< Processor >(*)() ProcessorFactory
Factory function type — plugins provide this to create processor instances.
Definition processor.hpp:1416
constexpr ViewSize view_size_from_design(uint32_t preferred_width, uint32_t preferred_height, uint32_t min_width=0, uint32_t min_height=0, uint32_t max_width=0, uint32_t max_height=0)
Build a ViewSize from a design-import preferred size with sensible derived bounds.
Definition plugin_descriptor.hpp:76
PrepareResourceLimit
Prepare context — passed once before processing starts.
Definition prepare_resources.hpp:16
PrepareResourceLimit first_exceeded_prepare_resource_limit(const PrepareResourceUsage &usage, const PrepareResourceLimits &limits) noexcept
Definition prepare_resources.hpp:71
ProcessBuffersT< double > ProcessBuffers64
Definition process_block.hpp:423
ProcessBuffersT< float > ProcessBuffers
Definition process_block.hpp:422
EditorHostKind
Where a processor's editor lives, as far as the keyboard is concerned.
Definition editor_host_kind.hpp:15
@ standalone
Definition editor_host_kind.hpp:15
@ plugin
Definition editor_host_kind.hpp:15
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
STL namespace.
Naming individual notes so a host can label them in its editors.
What a panic request can do in the current host.
Definition panic.hpp:43
Plugin metadata — declared once, immutable.
Definition plugin_descriptor.hpp:245
Definition prepare_resources.hpp:102
PrepareResourceLimits resource_limits
Definition prepare_resources.hpp:107
Processor-reported prepared resource usage estimate.
Definition prepare_resources.hpp:53
Additive block-scoped process contract.
Definition process_block.hpp:517
Process context — passed every audio callback with transport state.
Definition process_context.hpp:89
── Opt-in DSP-state carry across a hot-reload (reload lane, item 1.6) ── On a hot-reload the new proc...
Definition processor.hpp:382
std::vector< int > inputs
Definition processor.hpp:383
std::vector< int > outputs
Definition processor.hpp:384
What a scripted editor evaluates every time it opens and that does not depend on the instance: the te...
Definition processor.hpp:593
std::vector< std::string_view > scripts
Definition processor.hpp:594
std::vector< std::string_view > materialized_documents
Definition processor.hpp:595
bool empty() const noexcept
Definition processor.hpp:596
std::unique_ptr< view::View, ViewDeleter > view
Tab content (built by the plugin).
Definition processor.hpp:665
void(*)(view::View *) ViewDeleter
Definition processor.hpp:649
std::unique_ptr< view::View > take_view()
Hand the view over as an ordinary owning pointer (empty if none).
SettingsSection(SettingsSection &&) noexcept=default
SettingsSection() noexcept
Definition processor.hpp:651
std::string title
Tab label, e.g.
Definition processor.hpp:662
SettingsSection(std::string title, std::unique_ptr< view::View > view)
Editor size hints (in logical pixels).
Definition plugin_descriptor.hpp:27
EditorResizeHandler handler
Definition processor.hpp:74
std::function< bool()> is_active
Definition processor.hpp:75
The parameter-event queues adapters hand to opted-out processors, keyed by address,...
Definition processor.hpp:145
std::atomic< const void * > queue
Definition processor.hpp:146
std::atomic< bool > read
Definition processor.hpp:147
Definition parameter_event_queue.hpp:34
Sample-accurate MIDI 2.0 UMP packet stream.