Loading...
Searching...
No Matches
ControlTree.hpp
Go to the documentation of this file.
1#pragma once
2
18#include <ossia/network/base/device.hpp>
19#include <ossia/network/base/node.hpp>
20#include <ossia/network/base/parameter.hpp>
21#include <ossia/network/common/complex_type.hpp>
22#include <ossia/network/domain/domain.hpp>
23#include <ossia/network/generic/generic_node.hpp>
24
25#include <functional>
26#include <memory>
27#include <string>
28#include <vector>
29
30namespace Gfx
31{
32
35{
36 std::string name;
37 std::string description;
38
39 ossia::val_type type{};
40 ossia::domain domain;
41 ossia::value initial;
42 ossia::access_mode access{ossia::access_mode::BI};
43
46 std::function<void(const ossia::value&)> onSet;
47};
48
56inline std::vector<ossia::net::parameter_base*> addControlGroup(
57 ossia::net::device_base& dev, ossia::net::node_base& parent,
58 const std::string& group, const std::vector<TreeControl>& controls)
59{
60 std::vector<ossia::net::parameter_base*> out;
61 out.reserve(controls.size());
62
63 // Reload puts the saved tree back before the hardware is opened, so the group
64 // and its children can already be there. add_child refuses a duplicate name
65 // and returns null.
66 ossia::net::node_base* groupPtr = parent.find_child(group);
67 if(!groupPtr)
68 groupPtr = parent.add_child(
69 std::make_unique<ossia::net::generic_node>(group, dev, parent));
70 if(!groupPtr)
71 {
72 out.resize(controls.size(), nullptr);
73 return out;
74 }
75
76 for(const auto& c : controls)
77 {
78 // Same again per control: adopt the node the document restored rather than
79 // failing to add a second one with the same name.
80 if(auto* existing = groupPtr->find_child(c.name))
81 {
82 // Whether the parameter PRE-EXISTED (the document restored it, so its
83 // value is the user's) or is created right here (no restored value —
84 // its default-constructed 0.0 is fabricated, not the user's).
85 auto* param = existing->get_parameter();
86 const bool parameterWasRestored = (param != nullptr);
87 if(!param)
88 param = existing->create_parameter(c.type);
89 if(!param)
90 {
91 out.push_back(nullptr);
92 continue;
93 }
94
95 if(c.domain)
96 param->set_domain(c.domain);
97 param->set_access(c.access);
98 if(!c.description.empty())
99 ossia::net::set_description(*existing, c.description);
100
101 // A restored value is the user's, not the hardware's, so it is pushed
102 // back through the callback rather than overwritten with c.initial the
103 // way a freshly created node is. But a parameter CREATED here holds only
104 // its default-constructed value (0.0 for FLOAT) — no document ever held
105 // it — so pushing it would slam a gain/exposure to zero. The fresh-node
106 // path refuses to write c.initial for the same reason; the adopt path
107 // must likewise write nothing when it just made the parameter.
108 const auto restored = param->value();
109 param->callbacks_clear();
110 if(c.onSet)
111 {
112 // Driven before the callback is installed, not after: the write has to
113 // reach the hardware, and doing it through an installed callback would
114 // re-enter the parameter that is being set up.
115 if(parameterWasRestored && restored.valid())
116 c.onSet(restored);
117 auto cb = c.onSet;
118 param->add_callback(std::move(cb));
119 }
120 out.push_back(param);
121 continue;
122 }
123
124 auto node = std::make_unique<ossia::net::generic_node>(c.name, dev, *groupPtr);
125 auto* param = node->create_parameter(c.type);
126 if(!param)
127 {
128 out.push_back(nullptr);
129 continue;
130 }
131
132 if(c.domain)
133 param->set_domain(c.domain);
134 param->set_access(c.access);
135
136 if(!c.description.empty())
137 ossia::net::set_description(*node, c.description);
138
139 // The initial value is set before the callback is installed: it describes
140 // what the hardware already holds, and writing it back would be a
141 // round-trip through the driver for no reason -- and, for a control whose
142 // write performs an action, an unwanted action.
143 if(c.initial.valid())
144 param->push_value(c.initial);
145
146 if(c.onSet)
147 {
148 auto cb = c.onSet;
149 param->add_callback(std::move(cb));
150 }
151
152 // add_child takes ownership; the node keeps the parameter alive.
153 auto* added = groupPtr->add_child(std::move(node));
154 out.push_back(added ? param : nullptr);
155 }
156
157 return out;
158}
159
160} // namespace Gfx
Binds the rendering pipeline to ossia processes.
Definition AssetTable.cpp:7
std::vector< ossia::net::parameter_base * > addControlGroup(ossia::net::device_base &dev, ossia::net::node_base &parent, const std::string &group, const std::vector< TreeControl > &controls)
Creates <parent>/<group>/<name> for each control.
Definition ControlTree.hpp:56
One settable thing, described independently of where it came from.
Definition ControlTree.hpp:35
std::string name
tree-safe; becomes the address component
Definition ControlTree.hpp:36
std::string description
shown in the explorer
Definition ControlTree.hpp:37
std::function< void(const ossia::value &)> onSet
Definition ControlTree.hpp:46