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&);
146 void setListening(const State::Address&, bool);
147 void addToListening(const std::vector<State::Address>&);
149 std::vector<State::Address> listening() const;
151 std::vector<State::Address> listeningRequests() const;
153 void restoreListening();
154
155 virtual void addAddress(const Device::FullAddressSettings&);
156 virtual void updateAddress(
157 const State::Address& currentAddr, const Device::FullAddressSettings& newAddr);
158 virtual void removeNode(const State::Address&);
159
160 void sendMessage(const State::Address& addr, const ossia::value& v);
161
162 // Make a node from an inside path, if it has been added for instance.
163 Device::Node getNode(const State::Address&) const;
164 Device::Node getNodeWithoutChildren(const State::Address&) const;
165
166 bool isLogging() const;
167 void setLogging(DeviceLogging);
168
169 virtual ossia::net::device_base* getDevice() const = 0;
170
171 virtual bool isLearning() const;
172 virtual void setLearning(bool);
173
174 virtual QMimeData* mimeData() const;
175 virtual void setupContextMenu(QMenu&) const;
176
177 void nodeCreated(const ossia::net::node_base&);
178 void nodeRemoving(const ossia::net::node_base&);
179 void nodeRenamed(const ossia::net::node_base&, std::string);
180 void addressCreated(const ossia::net::parameter_base&);
181 void addressUpdated(const ossia::net::node_base&, ossia::string_view key);
182 void addressRemoved(const ossia::net::parameter_base& addr);
183
184 Nano::Signal<void(const State::Address&, const ossia::value&)> valueUpdated;
185
186public:
187 // These signals are emitted if a device changes from the inside
188 void pathAdded(const State::Address& arg_1)
189 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathAdded, arg_1)
190 void pathUpdated(
191 const State::Address& arg_1, // current address
192 const Device::AddressSettings& arg_2)
193 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathUpdated, arg_1, arg_2) // new data
194 void pathRemoved(const State::Address& arg_1)
195 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, pathRemoved, arg_1)
196
197 // In case the whole namespace changed?
198 void namespaceUpdated() E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, namespaceUpdated)
199
200 // In case the device changed
201 void deviceChanged(ossia::net::device_base* old_dev, ossia::net::device_base* new_dev)
202 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, deviceChanged, old_dev, new_dev)
203
204 /* If logging is enabled, these two signals may be sent
205 * when something happens */
206 void logInbound(const QString& arg_1) const
207 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, logInbound, arg_1)
208 void logOutbound(const QString& arg_1) const
209 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, logOutbound, arg_1)
210
211 void connectionChanged(bool arg_1) const
212 E_SIGNAL(SCORE_LIB_DEVICE_EXPORT, connectionChanged, arg_1)
213
214protected:
215 Device::DeviceSettings m_settings;
216 DeviceCapas m_capas;
217
218 using callback_pair = std::pair<
219 ossia::net::parameter_base*,
220 ossia::callback_container<ossia::value_callback>::iterator>;
221 score::hash_map<State::Address, callback_pair> m_callbacks;
222
223 void removeListening_impl(ossia::net::node_base& node, State::Address addr);
224 void removeListening_impl(
225 ossia::net::node_base& node, State::Address addr, std::vector<State::Address>&);
226 void renameListening_impl(const State::Address& parent, const QString& newName);
227 void setLogging_impl(DeviceLogging) const;
228 void enableCallbacks();
229 void disableCallbacks();
230
231 // Refresh without handling callbacks
232 Device::Node simple_refresh();
233
234private:
235 bool listen_impl(const State::Address& addr, bool b);
236
237 // What the explorer asked to listen to; outlives the callbacks, which die
238 // with the ossia nodes on reconnect / refresh.
239 ossia::hash_set<State::Address> m_listeningRequests;
240 DeviceLogging m_logging = DeviceLogging::LogNothing;
241 bool m_callbacksEnabled = false;
242};
243
244class SCORE_LIB_DEVICE_EXPORT OwningDeviceInterface : public DeviceInterface
245{
246public:
247 ~OwningDeviceInterface() override;
248 void replaceDevice(ossia::net::device_base*);
249 void releaseDevice();
250
251protected:
252 void disconnect() override;
253
254 using DeviceInterface::DeviceInterface;
255
256 ossia::net::device_base* getDevice() const final override { return m_dev.get(); }
257
258 std::shared_ptr<ossia::net::device_base> m_dev;
259 bool m_owned{true};
260};
261
262SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
263getNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
264
265SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
266createNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
267
269inline bool hasEditableValue(ossia::parameter_type t) noexcept
270{
271 switch(t)
272 {
273 case ossia::parameter_type::MESSAGE:
274 case ossia::parameter_type::AUDIO:
275 return true;
276 case ossia::parameter_type::MIDI:
277 case ossia::parameter_type::TEXTURE:
278 case ossia::parameter_type::GEOMETRY:
279 return false;
280 }
281 return false;
282}
283
284SCORE_LIB_DEVICE_EXPORT Device::Node ToDeviceExplorer(const ossia::net::node_base& node);
285
286SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
287findNodeFromPath(const Device::Node& path, ossia::net::device_base& dev);
288
289SCORE_LIB_DEVICE_EXPORT ossia::net::node_base*
290findNodeFromPath(const QStringList& path, ossia::net::device_base& dev);
291
292SCORE_LIB_DEVICE_EXPORT
293void releaseDevice(
294 ossia::net::network_context& ctx, std::unique_ptr<ossia::net::device_base> dev);
295SCORE_LIB_DEVICE_EXPORT
296void releaseDevice(
297 ossia::net::network_context& ctx, std::shared_ptr<ossia::net::device_base> dev);
298}
Definition DeviceInterface.hpp:107
Definition DeviceInterface.hpp:245
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:269
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:117
Definition AddressSettings.hpp:49
Definition DeviceInterface.hpp:80
Definition DeviceSettings.hpp:20
Definition AddressSettings.hpp:62
The Address struct.
Definition Address.hpp:58
The Message struct.
Definition Message.hpp:15