OSSIA
Open Scenario System for Interactive Application
ossia-max/src/object_base.hpp
1 #pragma once
2 #include "ext.h"
3 #include "ext_critical.h"
4 #include "ext_obex.h"
5 #include "matcher.hpp"
6 
7 #include <ossia/detail/config.hpp>
8 
10 #include <ossia/detail/optional.hpp>
11 #include <ossia/detail/safe_vec.hpp>
12 #include <ossia/network/base/node.hpp>
13 #include <ossia/network/base/osc_address.hpp>
14 #include <ossia/network/base/value_callback.hpp>
15 #include <ossia/network/common/path.hpp>
16 #include <ossia/network/dataspace/dataspace.hpp>
17 #include <ossia/network/generic/generic_device.hpp>
18 
19 #include <iostream>
20 #include <map>
21 
22 #define OSSIA_MAX_MAX_ATTR_SIZE 256
23 
24 namespace ossia
25 {
26 namespace max_binding
27 {
28 
29 #pragma mark -
30 #pragma mark t_object_base structure declaration
31 
32 enum class object_class
33 {
34  root = 0,
35  param,
36  remote,
37  model,
38  view,
39  device,
40  client,
41  attribute,
42  explorer,
43  search,
44  monitor,
45  fuzzysearch,
46  cue
47 };
48 
49 struct object_base;
50 class ossia_max;
51 
52 struct search_result
53 {
54  object_base* object{};
55  t_object* patcher{};
56  t_object* parent{};
57  t_symbol* classname{};
58  int level{}; // relative hierarchy level
59 
60  friend bool operator<(search_result a, search_result b) { return a.level < b.level; }
61 };
62 
63 struct object_base
64 {
65 public:
66  t_object m_object; // the Max object instance.
67  // !!! this member is handled by Max API : that's why there is no place in
68  // our code where it is initialized.
69 
70  void** m_inlets{};
71  void* m_data_out{};
72  void* m_set_out{};
73  void* m_dumpout{};
74 
75  // flags
76  bool m_dead{false}; // whether this object is being deleted or not;
77  bool m_is_deleted{};
78  bool m_lock{false}; // attribute lock
79  bool m_local_mute{false};
80  bool m_registering{}; // true while registering to prevent recursive registration
81  bool m_registered{}; // true if register_node() have been called at least once
82  ossia::net::address_scope m_addr_scope{};
83  object_class m_otype{};
84 
85  void* m_clock{};
86  void* m_highlight_clock{}; // clock to reset color after some amount of time
87  // to highlight the object in the patcher
88 
89  float m_rate{10.f};
90 
91  std::shared_ptr<ossia::net::generic_device> m_device{};
92  using matcher_vector = std::vector<std::shared_ptr<matcher>>;
93  matcher_vector m_matchers{};
94  std::vector<matcher*> m_node_selection{};
95  std::optional<ossia::traversal::path> m_selection_path{};
96  static void class_setup(t_class* c);
97 
98  void fill_selection();
99  void update_path();
100  void get_hierarchy();
101 
102  void set_description();
103  void set_tags();
104  void set_priority();
105  void set_hidden();
106  void set_recall_safe();
107 
108  // return the global path of the object with pattern
109  object_base* find_parent_object();
110 
111  // return the first parent ossia object, nullptr otherwise
112  object_base*
113  find_parent_object_recursively(t_object* patcher, bool look_for_model_view);
114 
115  static void get_description(object_base* x, std::vector<matcher*> nodes);
116  static void get_tags(object_base* x, std::vector<matcher*> nodes);
117  static void get_priority(object_base* x, std::vector<matcher*> nodes);
118  static void get_hidden(object_base* x, std::vector<matcher*> nodes);
119  static void get_zombie(object_base* x, std::vector<matcher*> nodes);
120  static void get_mess_cb(object_base* x, t_symbol* s);
121  static void select_mess_cb(object_base* x, t_symbol* s, int argc, t_atom* argv);
122  static void get_recall_safe(object_base* x, std::vector<matcher*> nodes);
123 
124  // default attributes
125  t_symbol* m_name{};
126  t_symbol* m_tags[OSSIA_MAX_MAX_ATTR_SIZE] = {{}};
127  t_symbol* m_description{};
128  float m_priority{};
129  long m_invisible{};
130  long m_defer_set{1};
131  long m_recall_safe{};
132  long m_trim_addr{1};
133  long m_saveget{};
134  long m_saveset{};
135  long m_savebi{1};
136 
137  t_object* m_patcher{};
138 
139  long m_tags_size{};
140  long m_description_size{};
141  t_jrgba m_color{};
142 
143  std::vector<search_result> m_found_parameters{};
144  std::vector<search_result> m_found_models{};
145 
146  // constructor
147  object_base();
148 
149  // dtor
150  ~object_base();
151 
152  bool m_loadbanged{}; // true if object received a loadbang
153 
154  std::mutex m_bind_mutex;
155  // TODO check where this is filled
156  std::vector<t_object*> m_patcher_hierarchy; // canvas hierarchy in ascending order, the
157  // last is the root patcher
158 
159  static void update_attribute(
160  object_base* x, ossia::string_view attribute, const ossia::net::node_base* node);
161  static t_max_err
162  notify(object_base* x, t_symbol* s, t_symbol* msg, void* sender, void* data);
163  void on_parameter_removing(const ossia::net::parameter_base& n);
164  void on_node_removing(const ossia::net::node_base& n);
165 
166  static void defer_set_output(object_base* x, t_symbol* s, int argc, t_atom* argv);
167  static void set(object_base* x, t_symbol* s, int argc, t_atom* argv);
168  static void get_address(object_base* x, std::vector<matcher*> nodes);
169  static void lock_and_touch(object_base* x, t_symbol* s);
170  static void loadbang(object_base* x);
171  void save_children_state();
172  void highlight();
173  void clear_and_init_registration();
174 
175  static void reset_color(object_base* x);
176 
177  void push_parameter_value(ossia::net::parameter_base* param, const ossia::value& val);
178  void set_matchers_index();
179 
180  std::vector<std::string> m_paths{};
181 
182 protected:
183  std::vector<std::shared_ptr<matcher>> find_or_create_matchers();
184  void remove_matchers(const ossia::net::node_base& m);
185  void remove_matcher(const std::shared_ptr<matcher>& m);
186 
187  [[nodiscard]] matcher_vector::iterator remove_matcher(matcher_vector::iterator m);
188 
189  std::map<std::string, ossia::value> m_value_map{};
190 
191 private:
192  std::vector<std::shared_ptr<matcher>> find_parent_nodes();
193  void load_configuration(ossia_max& omax);
194  void create_patcher_hierarchy(ossia_max& omax);
195  unsigned long poly_index();
196  void make_global_paths(const std::string& name);
197 };
198 
199 #pragma mark -
200 #pragma mark Utilities
201 
202 // Typed function switcher to convert ossia::value to t_atom
203 struct value2atom
204 {
205  std::vector<t_atom>& data;
206  void operator()(impulse) const
207  {
208  t_atom a;
209  atom_setsym(&a, gensym("bang"));
210  data.push_back(a);
211  }
212 
213  void operator()(int32_t i) const
214  {
215  t_atom a;
216  atom_setlong(&a, i);
217  data.push_back(a);
218  }
219 
220  void operator()(int64_t i) const
221  {
222  t_atom a;
223  atom_setlong(&a, i);
224  data.push_back(a);
225  }
226 
227  void operator()(float f) const
228  {
229  t_atom a;
230  atom_setfloat(&a, f);
231  data.push_back(a);
232  }
233 
234  void operator()(bool b) const
235  {
236  t_atom a;
237  float f = b ? 1. : 0.;
238  atom_setfloat(&a, f);
239  data.push_back(a);
240  }
241 
242  void operator()(const std::string& str) const
243  {
244  t_symbol* s = gensym(str.c_str());
245  t_atom a;
246  atom_setsym(&a, s);
247  data.push_back(a);
248  }
249 
250  template <std::size_t N>
251  void operator()(std::array<float, N> vec) const
252  {
253  data.reserve(data.size() + N);
254  for(std::size_t i = 0; i < N; i++)
255  {
256  t_atom a;
257  atom_setfloat(&a, vec[i]);
258  data.push_back(a);
259  }
260  }
261 
262  void operator()(const std::vector<ossia::value>& t) const
263  {
264  data.reserve(data.size() + t.size());
265  for(const auto& v : t)
266  v.apply(*this);
267  }
268 
269  void operator()(const ossia::value_map_type& t) const { }
270 
271  void operator()() const { }
272 };
273 
274 // Template typed function switcher to convert t_atom or standard type into
275 // ossia::value
276 template <typename T>
277 struct value_visitor
278 {
279  T* x;
280 
281  void set_out(t_atom& a) const
282  {
283  if(x->m_set_out)
284  {
285  if(x->m_defer_set)
286  {
287  defer_low(
288  (t_object*)x, (method)object_base::defer_set_output, gensym("set"), 1, &a);
289  }
290  else
291  {
292  outlet_anything(x->m_set_out, gensym("set"), 1, &a);
293  }
294  }
295  }
296 
297  void set_out(int N, t_atom* a) const
298  {
299  if(x->m_set_out)
300  {
301  if(x->m_defer_set)
302  {
303  defer_low(
304  (t_object*)x, (method)object_base::defer_set_output, gensym("set"), N, a);
305  }
306  else
307  {
308  outlet_anything(x->m_set_out, gensym("set"), N, a);
309  }
310  }
311  }
312 
313  void operator()(impulse) const
314  {
315  outlet_bang(x->m_data_out);
316 
317  if(x->m_set_out)
318  outlet_bang(x->m_set_out);
319  }
320 
321  void operator()(int32_t i) const
322  {
323  t_atom a;
324  atom_setlong(&a, i);
325  outlet_int(x->m_data_out, i);
326 
327  set_out(a);
328  }
329 
330  void operator()(float f) const
331  {
332  t_atom a;
333 
334  atom_setfloat(&a, f);
335  if(x && x->m_data_out)
336  {
337  outlet_float(x->m_data_out, f);
338  }
339  set_out(a);
340  }
341 
342  void operator()(bool b) const { (*this)(b ? 1 : 0); }
343 
344  void operator()(const std::string& str) const
345  {
346  t_symbol* s = gensym(str.c_str());
347  t_atom a;
348 
349  atom_setsym(&a, s);
350  outlet_anything(x->m_data_out, s, 0, nullptr);
351 
352  set_out(a);
353  }
354 
355  template <std::size_t N>
356  void operator()(std::array<float, N> vec) const
357  {
358  t_atom a[N];
359 
360  for(int i = 0; i < N; i++)
361  atom_setfloat(a + i, vec[i]);
362  outlet_list(x->m_data_out, gensym("list"), N, a);
363 
364  set_out(N, a);
365  }
366 
367  void operator()(const std::vector<ossia::value>& t) const
368  {
369  std::vector<t_atom> va;
370  value2atom vm{va};
371 
372  if(t.empty())
373  return;
374 
375  for(const auto& v : t)
376  v.apply(vm);
377 
378  t_atom* list_ptr = !va.empty() ? va.data() : nullptr;
379  if(x->m_data_out)
380  outlet_list(x->m_data_out, gensym("list"), va.size(), list_ptr);
381 
382  set_out(va.size(), list_ptr);
383  }
384 
385  void operator()(const ossia::value_map_type& t) const { }
386 
387  void operator()() const
388  {
389  object_error((t_object*)x, "%s received an invalid data", x->m_name->s_name);
390  }
391 };
392 
393 } // max namespace
394 } // ossia namespace
The node_base class.
Definition: network/base/node.hpp:48
The parameter_base class.
Definition: ossia/network/base/parameter.hpp:48
The value class.
Definition: value.hpp:173
Definition: git_info.h:7