OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
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
12namespace ossia::net::midi
13{
14const std::string& midi_node_name(midi_size_t i);
15
16class generic_node final
17 : public midi_node
18 , public midi_parameter
19{
20public:
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
118class note_on_N_node final
119 : public midi_node
120 , public midi_parameter
121{
122public:
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
147class note_off_N_node final
148 : public midi_node
149 , public midi_parameter
150{
151public:
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
176class control_N_node final
177 : public midi_node
178 , public midi_parameter
179{
180public:
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
205class program_N_node final
206 : public midi_node
207 , public midi_parameter
208{
209public:
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
234class program_node final
235 : public midi_node
236 , public midi_parameter
237{
238public:
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
268class note_on_node final
269 : public midi_node
270 , public midi_parameter
271{
272public:
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
302class note_off_node final
303 : public midi_node
304 , public midi_parameter
305{
306public:
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
338class control_node final
339 : public midi_node
340 , public midi_parameter
341{
342public:
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
373class pitch_bend_node final
374 : public midi_node
375 , public midi_parameter
376{
377public:
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
402class channel_node final : public midi_node
403{
404public:
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 node.hpp:48
Nano::Signal< void(const node_base &)> about_to_be_deleted
The node subclasses must call this in their destructor.
Definition node.hpp:204
The message struct.
Definition message.hpp:29