Loading...
Searching...
No Matches
DeviceInterface.hpp
1#pragma once
2#include <Device/Node/DeviceNode.hpp>
3#include <Device/Protocol/DeviceSettings.hpp>
4
5#include <score/tools/std/HashMap.hpp>
6
7#include <ossia/detail/callback_container.hpp>
8#include <ossia/network/base/value_callback.hpp>
9
10#include <ossia-qt/device_metatype.hpp>
11
12#include <nano_signal_slot.hpp>
13#include <score_lib_device_export.h>
14
15#include <verdigris>
16class QMenu;
17namespace score
18{
19struct DocumentContext;
20}
21namespace ossia
22{
23class value;
24}
25
26namespace ossia::net
27{
28class node_base;
29class parameter_base;
30class device_base;
31struct network_context;
32using network_context_ptr = std::shared_ptr<network_context>;
33}
34namespace State
35{
36struct Message;
37}
38namespace Device
39{
40struct FullAddressSettings;
41
51enum class NodeKind : uint16_t
52{
53 None = 0,
54 Value = 1 << 0,
55 AudioIn = 1 << 1,
56 AudioOut = 1 << 2,
57 MidiIn = 1 << 3,
58 MidiOut = 1 << 4,
59 TextureIn = 1 << 5,
60 TextureOut = 1 << 6,
61 GeometryIn = 1 << 7,
62 GeometryOut = 1 << 8,
63};
64
65constexpr NodeKind operator|(NodeKind a, NodeKind b) noexcept
66{
67 return NodeKind(uint16_t(a) | uint16_t(b));
68}
69constexpr NodeKind& operator|=(NodeKind& a, NodeKind b) noexcept
70{
71 return a = a | b;
72}
74constexpr bool carries(NodeKind set, NodeKind wanted) noexcept
75{
76 return (uint16_t(set) & uint16_t(wanted)) == uint16_t(wanted);
77}
78
79struct SCORE_LIB_DEVICE_EXPORT DeviceCapas
80{
81 bool canAddNode{true};
82 bool canRemoveNode{true};
83 bool canRenameNode{true};
84 bool canSetProperties{true};
85 bool canDisconnect{true};
86 bool canRefreshValue{true};
87 bool canRefreshTree{false};
88 bool asyncConnect{false};
89 bool canListen{true};
90 bool canSerialize{true};
91 bool canLearn{false};
92 bool hasCallbacks{true};
94 NodeKind nodeKinds{NodeKind::Value};
95};
96
97enum DeviceLogging : int8_t
98{
99 LogNothing,
100 LogUnfolded,
101 LogEverything
102};
103
104class SCORE_LIB_DEVICE_EXPORT DeviceInterface
105 : public QObject
106 , public Nano::Observer
107{
108 W_OBJECT(DeviceInterface)
109
110public:
112 virtual ~DeviceInterface();
113
114 const Device::DeviceSettings& settings() const noexcept;
115 const QString& name() const noexcept;
116
117 virtual void addNode(const Device::Node& n);
118
119 DeviceCapas capabilities() const noexcept;
120 virtual DeviceResources usedResources() const noexcept;
121
122 virtual void disconnect();
123 virtual bool reconnect() = 0;
124 virtual void recreate(const Device::Node&); // Argument is the node of the
125 // device, used for recreation
126 virtual bool connected() const;
127 W_INVOKABLE(connected)
128
129 void updateSettings(const Device::DeviceSettings&);
130
131 // Asks, and returns all the new addresses if the device can refresh itself
132 // Minuit-like.
133 // The addresses are not applied to the device, they have to be via a
134 // command!
135 virtual Device::Node refresh();
136 std::optional<ossia::value> refresh(const State::Address&);
137 void request(const Device::Node&);
150 void setListening(const State::Address&, bool, bool reportCurrentValue = true);
151 void addToListening(const std::vector<State::Address>&);
153 std::vector<State::Address> listening() const;
155 std::vector<State::Address> listeningRequests() const;
157 void restoreListening();
158
159 virtual void addAddress(const Device::FullAddressSettings&);
160 virtual void updateAddress(
161 const State::Address& currentAddr, const Device::FullAddressSettings& newAddr);
162 virtual void removeNode(const State::Address&);
163
164 void sendMessage(const State::Address& addr, const ossia::value& v);
165
166 // Make a node from an inside path, if it has been added for instance.
167 Device::Node getNode(const State::Address&) const;
168 Device::Node getNodeWithoutChildren(const State::Address&) const;
169
170 bool isLogging() const;
171 void setLogging(DeviceLogging);
172
173 virtual ossia::net::device_base* getDevice() const = 0;
174
175 virtual bool isLearning() const;
176 virtual void setLearning(bool);
177
178 virtual QMimeData* mimeData() const;
179 virtual void setupContextMenu(QMenu&) const;
180
181 void nodeCreated(const ossia::net::node_base&);
182 void nodeRemoving(const ossia::net::node_base&);
183 void nodeRenamed(const ossia::net::node_base&, std::string);
184 void addressCreated(const ossia::net::parameter_base&);
185 void addressUpdated(const ossia::net::node_base&, ossia::string_view key);
186 void addressRemoved(const ossia::net::parameter_base& addr);
187
188 Nano::Signal<void(const State::Address&, const ossia::value&)> valueUpdated;
189
190public:
191 // These signals are emitted if a device changes from the inside
192 void pathAdded(const State::Address& arg_1)
193 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathAdded, arg_1)
194 void pathUpdated(
195 const State::Address& arg_1, // current address
196 const Device::AddressSettings& arg_2)
197 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathUpdated, arg_1, arg_2) // new data
198 void pathRemoved(const State::Address& arg_1)
199 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathRemoved, arg_1)
200
201 // In case the whole namespace changed?
202 void namespaceUpdated() E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, namespaceUpdated)
203
204 // In case the device changed
205 void deviceChanged(ossia::net::device_base* old_dev, ossia::net::device_base* new_dev)
206 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, deviceChanged, old_dev, new_dev)
207
208
211 void deviceClearing(ossia::net::device_base* dev)
212 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, deviceClearing, dev)
213
214 /* If logging is enabled, these two signals may be sent
215 * when something happens */
216 void logInbound(const QString& arg_1) const
217 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, logInbound, arg_1)
218 void logOutbound(const QString& arg_1) const
219 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, logOutbound, arg_1)
220
221 void connectionChanged(bool arg_1) const
222 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, connectionChanged, arg_1)
223
224protected:
225 Device::DeviceSettings m_settings;
226 DeviceCapas m_capas;
227
228 using callback_pair = std::pair<
229 ossia::net::parameter_base*,
230 ossia::callback_container<ossia::value_callback>::iterator>;
231 score::hash_map<State::Address, callback_pair> m_callbacks;
232
233 void removeListening_impl(ossia::net::node_base& node, State::Address addr);
234 void removeListening_impl(
235 ossia::net::node_base& node, State::Address addr, std::vector<State::Address>&);
236 void renameListening_impl(const State::Address& parent, const QString& newName);
237 void setLogging_impl(DeviceLogging) const;
238 void enableCallbacks();
239 void disableCallbacks();
240
241 // Refresh without handling callbacks
242 Device::Node simple_refresh();
243
244private:
245 bool listen_impl(const State::Address& addr, bool b, bool report = true);
246
247 // What the explorer asked to listen to; outlives the callbacks, which die
248 // with the ossia nodes on reconnect / refresh.
249 ossia::hash_set<State::Address> m_listeningRequests;
250 DeviceLogging m_logging = DeviceLogging::LogNothing;
251 bool m_callbacksEnabled = false;
252};
253
254class SCORE_LIB_DEVICE_EXPORT OwningDeviceInterface : public DeviceInterface
255{
256public:
257 ~OwningDeviceInterface() override;
258 void replaceDevice(ossia::net::device_base*);
259 void releaseDevice();
260
261protected:
262 void disconnect() override;
263
264 using DeviceInterface::DeviceInterface;
265
266 ossia::net::device_base* getDevice() const final override { return m_dev.get(); }
267
268 std::shared_ptr<ossia::net::device_base> m_dev;
269 bool m_owned{true};
270};
271
272SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
273getNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
274
275SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
276createNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
277
279inline bool hasEditableValue(ossia::parameter_type t) noexcept
280{
281 switch(t)
282 {
283 case ossia::parameter_type::MESSAGE:
284 case ossia::parameter_type::AUDIO:
285 return true;
286 case ossia::parameter_type::MIDI:
287 case ossia::parameter_type::TEXTURE:
288 case ossia::parameter_type::GEOMETRY:
289 return false;
290 }
291 return false;
292}
293
294SCORE_LIB_DEVICE_EXPORT Device::Node ToDeviceExplorer(const ossia::net::node_base& node);
295
296SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
297findNodeFromPath(const Device::Node& path, ossia::net::device_base& dev);
298
299SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
300findNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
301
302SCORE_LIB_DEVICE_EXPORT
303void releaseDevice(
304 ossia::net::network_context& ctx, std::unique_ptr<ossia::net::device_base> dev);
305SCORE_LIB_DEVICE_EXPORT
306void releaseDevice(
307 ossia::net::network_context& ctx, std::shared_ptr<ossia::net::device_base> dev);
308}
Definition DeviceInterface.hpp:107
Definition DeviceInterface.hpp:255
Manipulation of Devices from Qt.
Definition AddressSettings.cpp:14
bool hasEditableValue(ossia::parameter_type t) noexcept
Whether a parameter of that kind carries a value the explorer can show and edit.
Definition DeviceInterface.hpp:279
constexpr bool carries(NodeKind set, NodeKind wanted) noexcept
Whether every kind in wanted is in set.
Definition DeviceInterface.hpp:74
NodeKind
The kinds of nodes a device can carry.
Definition DeviceInterface.hpp:52
Utilities for OSSIA data structures.
Definition DeviceInterface.hpp:35
Base toolkit upon which the software is built.
Definition Application.cpp:83
STL namespace.
Definition AddressSettings.hpp:49
Definition DeviceInterface.hpp:80
Definition DeviceSettings.hpp:20
Definition AddressSettings.hpp:62
The Address struct.
Definition Address.hpp:81
The Message struct.
Definition Message.hpp:15