OSSIA
Open Scenario System for Interactive Application
midi_impl.hpp
1 #pragma once
3 #include <ossia/network/base/osc_address.hpp>
4 #include <ossia/network/domain/domain.hpp>
5 #include <ossia/network/value/value.hpp>
6 #include <ossia/protocols/midi/detail/channel.hpp>
7 #include <ossia/protocols/midi/midi_device.hpp>
8 #include <ossia/protocols/midi/midi_node.hpp>
9 #include <ossia/protocols/midi/midi_parameter.hpp>
10 #include <ossia/protocols/midi/midi_protocol.hpp>
11 
12 namespace ossia::net::midi
13 {
14 const std::string& midi_node_name(midi_size_t i);
15 
16 class generic_node final
17  : public midi_node
18  , public midi_parameter
19 {
20 public:
21  generic_node(address_info addr, midi_device& dev, ossia::net::node_base& p)
22  : midi_node{dev, p}
23  , midi_parameter{addr, *this}
24  {
25  using namespace std::literals;
26  switch(addr.type)
27  {
28  case address_info::Type::NoteOn:
29  m_name = "on"s;
30  break;
31  case address_info::Type::NoteOn_N:
32  m_name = midi_node_name(addr.note);
33  break;
34  case address_info::Type::NoteOff:
35  m_name = "off"s;
36  break;
37  case address_info::Type::NoteOff_N:
38  m_name = midi_node_name(addr.note);
39  break;
40  case address_info::Type::CC:
41  m_name = "control"s;
42  break;
43  case address_info::Type::CC_N:
44  m_name = midi_node_name(addr.note);
45  break;
46  case address_info::Type::PC:
47  m_name = "program"s;
48  break;
49  case address_info::Type::PC_N:
50  m_name = midi_node_name(addr.note);
51  break;
52  case address_info::Type::PB:
53  m_name = "pitchbend"s;
54  break;
55  case address_info::Type::Any:
56  m_name = "TODO"s;
57  break;
58  default:
59  break;
60  }
61 
62  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
63  m_parameter.reset(this);
64  }
65 
66  std::unique_ptr<node_base> make_child(const std::string& name) override
67  {
68  int num = -1;
69 
70  try
71  {
72  num = std::stoi(name);
73  }
74  catch(...)
75  {
76  }
77 
78  if(num == -1)
79  {
80  return nullptr;
81  }
82 
83  address_info ai{m_info.channel, {}, midi_size_t(num)};
84  switch(m_info.type)
85  {
86  case address_info::Type::NoteOn:
87  ai.type = address_info::Type::NoteOn_N;
88  break;
89  case address_info::Type::NoteOff:
90  ai.type = address_info::Type::NoteOff_N;
91  break;
92  case address_info::Type::CC:
93  ai.type = address_info::Type::CC_N;
94  break;
95  case address_info::Type::PC:
96  ai.type = address_info::Type::PC_N;
97  break;
98  default:
99  return nullptr;
100  }
101 
102  return std::make_unique<generic_node>(ai, m_device, *this);
103  }
104 
105  ~generic_node()
106  {
107  m_children.clear();
108 
109  about_to_be_deleted(*this);
110 
111  m_device.on_parameter_removing(*this);
112  m_device.get_protocol().observe(*this, false);
113 
114  m_parameter.release();
115  }
116 };
117 
118 class note_on_N_node final
119  : public midi_node
120  , public midi_parameter
121 {
122 public:
123  note_on_N_node(
124  midi_size_t channel, midi_size_t note, midi_device& aDevice,
125  ossia::net::node_base& aParent)
126  : midi_node{aDevice, aParent}
127  , midi_parameter{address_info{channel, address_info::Type::NoteOn_N, note}, *this}
128  {
129  m_name = midi_node_name(note);
130  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
131  m_parameter.reset(this);
132  }
133 
134  ~note_on_N_node()
135  {
136  m_children.clear();
137 
138  about_to_be_deleted(*this);
139 
140  m_device.on_parameter_removing(*this);
141  m_device.get_protocol().observe(*this, false);
142 
143  m_parameter.release();
144  }
145 };
146 
147 class note_off_N_node final
148  : public midi_node
149  , public midi_parameter
150 {
151 public:
152  note_off_N_node(
153  midi_size_t channel, midi_size_t note, midi_device& aDevice,
154  ossia::net::node_base& aParent)
155  : midi_node{aDevice, aParent}
156  , midi_parameter{address_info{channel, address_info::Type::NoteOff_N, note}, *this}
157  {
158  m_name = midi_node_name(note);
159  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
160  m_parameter.reset(this);
161  }
162 
163  ~note_off_N_node()
164  {
165  m_children.clear();
166 
167  about_to_be_deleted(*this);
168 
169  m_device.on_parameter_removing(*this);
170  m_device.get_protocol().observe(*this, false);
171 
172  m_parameter.release();
173  }
174 };
175 
176 class control_N_node final
177  : public midi_node
178  , public midi_parameter
179 {
180 public:
181  control_N_node(
182  midi_size_t channel, midi_size_t param, midi_device& aDevice,
183  ossia::net::node_base& aParent)
184  : midi_node{aDevice, aParent}
185  , midi_parameter{address_info{channel, address_info::Type::CC_N, param}, *this}
186  {
187  m_name = midi_node_name(param);
188  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
189  m_parameter.reset(this);
190  }
191 
192  ~control_N_node()
193  {
194  m_children.clear();
195 
196  about_to_be_deleted(*this);
197 
198  m_device.on_parameter_removing(*this);
199  m_device.get_protocol().observe(*this, false);
200 
201  m_parameter.release();
202  }
203 };
204 
205 class program_N_node final
206  : public midi_node
207  , public midi_parameter
208 {
209 public:
210  program_N_node(
211  midi_size_t channel, midi_size_t param, midi_device& aDevice,
212  ossia::net::node_base& aParent)
213  : midi_node{aDevice, aParent}
214  , midi_parameter{address_info{channel, address_info::Type::PC_N, param}, *this}
215  {
216  m_name = midi_node_name(param);
217  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
218  m_parameter.reset(this);
219  }
220 
221  ~program_N_node()
222  {
223  m_children.clear();
224 
225  about_to_be_deleted(*this);
226 
227  m_device.on_parameter_removing(*this);
228  m_device.get_protocol().observe(*this, false);
229 
230  m_parameter.release();
231  }
232 };
233 
234 class program_node final
235  : public midi_node
236  , public midi_parameter
237 {
238 public:
239  program_node(midi_size_t channel, midi_device& aDevice, ossia::net::node_base& aParent)
240  : midi_node(aDevice, aParent)
241  , midi_parameter{address_info{channel, address_info::Type::PC, 0}, *this}
242  {
243  using namespace std::literals;
244  m_name = "program"s;
245  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
246  m_parameter.reset(this);
247  m_children.reserve(128);
248  for(int i = 0; i < 128; i++)
249  {
250  auto ptr = std::make_unique<program_N_node>(channel, i, m_device, *this);
251  m_children.push_back(std::move(ptr));
252  }
253  }
254 
255  ~program_node()
256  {
257  m_children.clear();
258 
259  about_to_be_deleted(*this);
260 
261  m_device.on_parameter_removing(*this);
262  m_device.get_protocol().observe(*this, false);
263 
264  m_parameter.release();
265  }
266 };
267 
268 class note_on_node final
269  : public midi_node
270  , public midi_parameter
271 {
272 public:
273  note_on_node(midi_size_t channel, midi_device& aDevice, ossia::net::node_base& aParent)
274  : midi_node(aDevice, aParent)
275  , midi_parameter{address_info{channel, address_info::Type::NoteOn, 0}, *this}
276  {
277  using namespace std::literals;
278  m_name = "on"s;
279  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
280  m_parameter.reset(this);
281  m_children.reserve(128);
282  for(int i = 0; i < 128; i++)
283  {
284  auto ptr = std::make_unique<note_on_N_node>(channel, i, m_device, *this);
285  m_children.push_back(std::move(ptr));
286  }
287  }
288 
289  ~note_on_node()
290  {
291  m_children.clear();
292 
293  about_to_be_deleted(*this);
294 
295  m_device.on_parameter_removing(*this);
296  m_device.get_protocol().observe(*this, false);
297 
298  m_parameter.release();
299  }
300 };
301 
302 class note_off_node final
303  : public midi_node
304  , public midi_parameter
305 {
306 public:
307  note_off_node(
308  midi_size_t channel, midi_device& aDevice, ossia::net::node_base& aParent)
309  : midi_node(aDevice, aParent)
310  , midi_parameter{address_info{channel, address_info::Type::NoteOff, 0}, *this}
311  {
312  using namespace std::literals;
313  m_name = "off"s;
314  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
315  m_parameter.reset(this);
316 
317  m_children.reserve(128);
318  for(int i = 0; i < 128; i++)
319  {
320  auto ptr = std::make_unique<note_off_N_node>(channel, i, m_device, *this);
321  m_children.push_back(std::move(ptr));
322  }
323  }
324 
325  ~note_off_node()
326  {
327  m_children.clear();
328 
329  about_to_be_deleted(*this);
330 
331  m_device.on_parameter_removing(*this);
332  m_device.get_protocol().observe(*this, false);
333 
334  m_parameter.release();
335  }
336 };
337 
338 class control_node final
339  : public midi_node
340  , public midi_parameter
341 {
342 public:
343  control_node(midi_size_t channel, midi_device& aDevice, ossia::net::node_base& aParent)
344  : midi_node(aDevice, aParent)
345  , midi_parameter{address_info{channel, address_info::Type::CC, 0}, *this}
346  {
347  using namespace std::literals;
348  m_name = "control"s;
349  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
350  m_parameter.reset(this);
351 
352  m_children.reserve(128);
353  for(int i = 0; i < 128; i++)
354  {
355  auto ptr = std::make_unique<control_N_node>(channel, i, m_device, *this);
356  m_children.push_back(std::move(ptr));
357  }
358  }
359 
360  ~control_node()
361  {
362  m_children.clear();
363 
364  about_to_be_deleted(*this);
365 
366  m_device.on_parameter_removing(*this);
367  m_device.get_protocol().observe(*this, false);
368 
369  m_parameter.release();
370  }
371 };
372 
373 class pitch_bend_node final
374  : public midi_node
375  , public midi_parameter
376 {
377 public:
378  pitch_bend_node(
379  midi_size_t channel, midi_device& aDevice, ossia::net::node_base& aParent)
380  : midi_node(aDevice, aParent)
381  , midi_parameter{address_info{channel, address_info::Type::PB, 0}, *this}
382  {
383  using namespace std::literals;
384  m_name = "pitchbend"s;
385  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
386  m_parameter.reset(this);
387  }
388 
389  ~pitch_bend_node()
390  {
391  m_children.clear();
392 
393  about_to_be_deleted(*this);
394 
395  m_device.on_parameter_removing(*this);
396  m_device.get_protocol().observe(*this, false);
397 
398  m_parameter.release();
399  }
400 };
401 
402 class channel_node final : public midi_node
403 {
404 public:
405  const midi_size_t channel;
406 
407  channel_node(
408  bool init, midi_size_t channel, midi_device& aDevice,
409  ossia::net::node_base& aParent)
410  : midi_node(aDevice, aParent)
411  , channel{channel}
412  {
413  m_name = midi_node_name(channel);
414  m_oscAddressCache = ossia::net::osc_parameter_string((ossia::net::node_base&)*this);
415  m_children.reserve(5);
416 
417  if(init)
418  {
419  m_children.push_back(std::make_unique<note_on_node>(channel, m_device, *this));
420 
421  m_children.push_back(std::make_unique<note_off_node>(channel, m_device, *this));
422 
423  m_children.push_back(std::make_unique<control_node>(channel, m_device, *this));
424 
425  m_children.push_back(std::make_unique<program_node>(channel, m_device, *this));
426 
427  m_children.push_back(std::make_unique<pitch_bend_node>(channel, m_device, *this));
428  }
429  }
430 
431  ~channel_node()
432  {
433  m_children.clear();
434 
435  about_to_be_deleted(*this);
436  }
437 
438  std::array<ossia::message, 2> note_on(midi_size_t note, midi_size_t vel)
439  {
440  const auto& c = children();
441  return {
443  *c[0]->get_parameter(),
444  value{std::vector<ossia::value>{int32_t{note}, int32_t{vel}}}},
445  ossia::message{*c[0]->children()[note]->get_parameter(), int32_t{vel}}}};
446  }
447 
448  std::array<ossia::message, 2> note_off(midi_size_t note, midi_size_t vel)
449  {
450  const auto& c = children();
451  return {
453  *c[1]->get_parameter(),
454  value{std::vector<ossia::value>{int32_t{note}, int32_t{vel}}}},
455  ossia::message{*c[1]->children()[note]->get_parameter(), int32_t{vel}}}};
456  }
457 
458  std::unique_ptr<node_base> make_child(const std::string& name) override
459  {
460  address_info ai{channel, {}, 0};
461  if(name == "on")
462  {
463  ai.type = address_info::Type::NoteOn;
464  }
465  else if(name == "off")
466  {
467  ai.type = address_info::Type::NoteOff;
468  }
469  else if(name == "control")
470  {
471  ai.type = address_info::Type::CC;
472  }
473  else if(name == "program")
474  {
475  ai.type = address_info::Type::PC;
476  }
477  else if(name == "pitchbend")
478  {
479  ai.type = address_info::Type::PB;
480  }
481  else
482  {
483  return nullptr;
484  }
485 
486  return std::make_unique<generic_node>(ai, m_device, *this);
487  }
488 };
489 
490 }
The node_base class.
Definition: network/base/node.hpp:48
Nano::Signal< void(const node_base &)> about_to_be_deleted
The node subclasses must call this in their destructor.
Definition: network/base/node.hpp:201
The message struct.
Definition: message.hpp:29