24#include <unordered_map>
34#define PULP_FORMAT_HAS_EDITOR_BACKGROUND 1
48using dataplane::ValueChannelSet;
72 std::function<bool(uint32_t, uint32_t)>;
78 std::unordered_map<const void*, EditorResizeHandlerEntry>;
80inline std::unordered_map<const void*, EditorResizeHandlerSet>&
82 static std::unordered_map<const void*, EditorResizeHandlerSet> table;
90 static std::unordered_map<const void*, bool> table;
98inline std::unordered_map<const void*, std::shared_ptr<PanicState>>&
panic_states() {
99 static std::unordered_map<const void*, std::shared_ptr<PanicState>> table;
146 std::atomic<const void*>
queue{
nullptr};
155 auto v =
static_cast<std::uint64_t
>(
reinterpret_cast<std::uintptr_t
>(queue));
157 v *= 0xff51afd7ed558ccdULL;
167 if (slot.queue.load(std::memory_order_acquire) == queue)
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);
289 return std::atomic_load_explicit(&published_plugin_state_,
290 std::memory_order_acquire);
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;
412 if (!layout.
inputs.empty() &&
413 layout.
inputs.size() != desc.input_buses.size())
416 layout.
outputs.size() != desc.output_buses.size())
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;
423 (declared[i].default_channels == 0 || declared[i].optional))
429 if (!layout.
inputs.empty() && !side_ok(layout.
inputs, desc.input_buses))
431 if (!layout.
outputs.empty() && !side_ok(layout.
outputs, desc.output_buses))
464 latency_changed_.store(
true, std::memory_order_release);
467 tail_changed_.store(
true, std::memory_order_release);
479 return latency_changed_.load(std::memory_order_relaxed) &&
480 latency_changed_.exchange(
false, std::memory_order_acq_rel);
483 return tail_changed_.load(std::memory_order_relaxed) &&
484 tail_changed_.exchange(
false, std::memory_order_acq_rel);
493 return latency_changed_.load(std::memory_order_acquire);
496 return tail_changed_.load(std::memory_order_acquire);
506 note_names_changed_.store(
true, std::memory_order_release);
509 return note_names_changed_.exchange(
false, std::memory_order_acq_rel);
512 return note_names_changed_.load(std::memory_order_acquire);
536 state_dirty_.store(
true, std::memory_order_release);
539 return state_dirty_.exchange(
false, std::memory_order_acq_rel);
542 return state_dirty_.load(std::memory_order_acquire);
600 virtual std::pair<uint32_t, uint32_t>
editor_size()
const {
return {400, 300}; }
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);
668 static
void no_view(
view::View*) noexcept {}
707 std::vector<detail::EditorResizeHandlerEntry> candidates;
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) {
716 candidates.push_back(entry);
726 for (
const auto& candidate : candidates) {
728 if (candidate.is_active) {
732 active = candidate.is_active();
734 if (!active)
continue;
735 if (handler)
return false;
736 handler = candidate.handler;
738 return handler ? handler(width, height) :
false;
759 virtual std::unique_ptr<class AraDocumentController>
813 auto* output =
audio.main_output();
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;
984 if (param_events_ !=
nullptr &&
987 slot->read.store(
true, std::memory_order_relaxed);
989 return param_events_;
997 return modulation_events_;
1016 std::uint32_t sample_offset)
noexcept {
1017 if (output_param_events_ ==
nullptr)
return false;
1019 id,
static_cast<int32_t
>(sample_offset), value, 0});
1024 return output_param_events_;
1039 modulation_events_ =
events;
1054 std::function<
bool(uint32_t, uint32_t)> handler) {
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;
1069 table[
this][editor_owner] = {
1070 std::move(handler), std::move(is_active)};
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);
1191 return std::nullopt;
1294 slot = std::make_shared<PanicState>();
1299 std::shared_ptr<const std::vector<uint8_t>> published_plugin_state_;
1300 static constexpr std::size_t kF64FallbackMaxBuses = 16;
1304 bool f64_fallback_capacity_ok(std::size_t input_channels,
1305 std::size_t output_channels,
1306 std::size_t frames)
const;
1308 bool f64_fallback_process_buffers_capacity_ok(
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_{};
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};
1374 if (!opted_out || queue ==
nullptr)
1380 const void* expected =
nullptr;
1383 if (slot.queue.compare_exchange_strong(expected, queue, std::memory_order_acq_rel)) {
1384 slot.read.store(
false, std::memory_order_relaxed);
1394 return slot_ !=
nullptr && slot_->read.load(std::memory_order_relaxed);
1402 void disarm() noexcept {
1403 if (slot_ ==
nullptr)
1405 slot_->queue.store(
nullptr, std::memory_order_release);
1406 slot_->read.store(
false, std::memory_order_relaxed);
1412 bool reported_ =
false;
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
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
Sample-accurate MPE expression event stream.
Definition analyzer_provider.hpp:12
Definition audio_bridge.hpp:9
Definition child_process_manager.hpp:18
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
Naming individual notes so a host can label them in its editors.
Definition prepare_resources.hpp:102
PrepareResourceLimits resource_limits
Definition prepare_resources.hpp:107
Process context — passed every audio callback with transport state.
Definition process_context.hpp:89
Definition processor.hpp:73
EditorResizeHandler handler
Definition processor.hpp:74
std::function< bool()> is_active
Definition processor.hpp:75
Definition parameter_event_queue.hpp:34
Sample-accurate MIDI 2.0 UMP packet stream.