MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RelationNetwork.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "NodeNetwork.hpp"
4#include "RelationSlot.hpp"
5
7
9
10/**
11 * @class RelationNetwork
12 * @brief Host for a dynamically growable set of slots and the operators that act on them
13 *
14 * The network owns the slots; everything computational lives in operators:
15 * advancing slot signals (AdvanceOperator), deriving one slot from others
16 * (DeriveOperator), turning slots into published outputs (CombineOperator),
17 * and any other slot logic (StepOperator and operators built on the same
18 * base). Construction adds no operators and no slots; a network with no
19 * publishing operator outputs nothing.
20 *
21 * Add slots with add_slot(), operators with add<Op>(...) in this order:
22 * control operators first, then AdvanceOperator, then DeriveOperator, then
23 * CombineOperator.
24 *
25 * @warning A RelationSlot's address is not stable: add_slot() may reallocate
26 * the whole slot vector. Read a slot fresh through get_slot(index)
27 * or get_node_output(index) rather than holding a pointer to it.
28 *
29 * add_slot() reserves each new slot's block storage, so a slot added while
30 * the network is already running does not allocate on its first block.
31 * process_batch() re-supplies every operator the current slot storage,
32 * applies mapped parameters, and runs the chain in order. Output 0 of the
33 * first publishing operator becomes the network's audio buffer.
34 *
35 * Structural edits (add_slot(), slot sources, callbacks, adding operators)
36 * must happen outside process_batch(). Parameter mapping uses Source and
37 * map() on RelationOperator (see RelationOperators.hpp).
38 */
39class MAYAFLUX_API RelationNetwork : public NodeNetwork {
40public:
42
43 /**
44 * @brief Add a slot to the network
45 * @param slot Fields not set take RelationSlot's own defaults. index is
46 * overwritten regardless of what is passed; a .node set
47 * directly still gets its hooks enabled, the same as
48 * RelationSlot::set_node().
49 * @return Stable index of the new slot. Never changes after insertion,
50 * though the slot's address may, on this or any later add_slot().
51 */
52 uint32_t add_slot(RelationSlot slot = {});
53
54 /**
55 * @brief Add several slots at once
56 * @param slots One slot per new entry, in order
57 * @return The new slots' indices, in the same order as slots
58 */
59 std::vector<uint32_t> add_slots(std::initializer_list<RelationSlot> slots);
60
61 [[nodiscard]] RelationSlot& get_slot(uint32_t index);
62 [[nodiscard]] const RelationSlot& get_slot(uint32_t index) const;
63
64 /**
65 * @brief Find a slot by name
66 * @return A reference to the slot, or nullopt if not found
67 */
68 [[nodiscard]] std::optional<std::reference_wrapper<RelationSlot>> find_slot(std::string_view name);
69 [[nodiscard]] std::optional<std::reference_wrapper<const RelationSlot>> find_slot(std::string_view name) const;
70
71 /**
72 * @brief Find the index of a slot by name
73 * @return Index, or nullopt if not found
74 */
75 [[nodiscard]] std::optional<uint32_t> find_slot_index(std::string_view name) const;
76
77 [[nodiscard]] size_t slot_count() const noexcept { return m_slots.size(); }
78
79 [[nodiscard]] std::vector<RelationSlot>& slots() noexcept { return m_slots; }
80 [[nodiscard]] const std::vector<RelationSlot>& slots() const noexcept { return m_slots; }
81
82 /**
83 * @brief Construct an operator in place and append it to the chain
84 * @tparam Op Concrete RelationOperator type
85 * @param args Forwarded to the Op constructor
86 * @return Shared pointer to the operator, retained by the network
87 *
88 * The operator receives the current slot storage before it is returned,
89 * so its public methods are callable immediately. An operator whose
90 * publishes_output() is true becomes a source of published outputs.
91 */
92 template <std::derived_from<RelationOperator> Op, typename... Args>
93 requires std::constructible_from<Op, Args...>
94 std::shared_ptr<Op> add(Args&&... args)
95 {
96 auto op = get_operator_chain()->emplace<Op>(std::forward<Args>(args)...);
97 op->set_slots(m_slots);
98 if (op->publishes_output()) {
99 m_publishers.push_back(op);
100 }
101 return op;
102 }
103
104 void process_batch(unsigned int num_samples) override;
105
106 [[nodiscard]] size_t get_node_count() const override { return m_slots.size(); }
107
108 /**
109 * @brief Block of the first published output, or nullopt when none is published
110 */
111 [[nodiscard]] std::optional<std::vector<double>> get_audio_buffer() const override;
112
113 /**
114 * @brief Level of one slot after the last processed block
115 * @note This is the slot's real underlying value, not what was published
116 * to its block: AdvanceOperator keeps level tracking the node even
117 * while the slot is inactive and its block is silenced. Read
118 * get_node_audio_buffer(index) for what was actually published.
119 */
120 [[nodiscard]] std::optional<double> get_node_output(size_t index) const override;
121
122 /**
123 * @brief Block of one slot from the last process_batch()
124 */
125 [[nodiscard]] std::optional<std::span<const double>> get_node_audio_buffer(size_t index) const override;
126
127 /**
128 * @brief Total published outputs across all publishing operators, in chain order
129 */
130 [[nodiscard]] size_t get_output_count() const;
131
132 /**
133 * @brief Block of one published output from the last process_batch()
134 * @param index Position in the concatenation of publishing operators' outputs
135 */
136 [[nodiscard]] std::optional<std::span<const double>> get_output_block(size_t index) const;
137
138 [[nodiscard]] std::unordered_map<std::string, std::string> get_metadata() const override;
139
140private:
141 std::vector<RelationSlot> m_slots;
142 std::vector<std::shared_ptr<RelationOperator>> m_publishers;
143};
144
145} // namespace MayaFlux::Nodes::Network
std::string name
Definition VKDevice.cpp:123
uint32_t index
Definition VKDevice.cpp:122
Abstract base class for structured collections of nodes with defined relationships.
std::vector< RelationSlot > & slots() noexcept
std::vector< std::shared_ptr< RelationOperator > > m_publishers
const std::vector< RelationSlot > & slots() const noexcept
size_t get_node_count() const override
Get the number of nodes in the network.
std::shared_ptr< Op > add(Args &&... args)
Construct an operator in place and append it to the chain.
Host for a dynamically growable set of slots and the operators that act on them.
One addressable participant of a RelationNetwork.