1 /*
2 * Carla Plugin Host
3 * Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16 */
17
18 #include "CarlaEngineOsc.hpp"
19
20 #ifdef HAVE_LIBLO
21
22 #include "CarlaEngineInternal.hpp"
23 #include "CarlaPlugin.hpp"
24 #include "CarlaMIDI.h"
25
26 #include <cctype>
27
28 CARLA_BACKEND_START_NAMESPACE
29
30 // -----------------------------------------------------------------------
31
handleMessage(const bool isTCP,const char * const path,const int argc,const lo_arg * const * const argv,const char * const types,const lo_message msg)32 int CarlaEngineOsc::handleMessage(const bool isTCP, const char* const path,
33 const int argc, const lo_arg* const* const argv, const char* const types,
34 const lo_message msg)
35 {
36 CARLA_SAFE_ASSERT_RETURN(fName.isNotEmpty(), 1);
37 CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', 1);
38 CARLA_SAFE_ASSERT_RETURN(path[0] == '/', 1);
39 #ifdef DEBUG
40 if (std::strncmp(path, "/bridge_pong", 12) != 0) {
41 carla_debug("CarlaEngineOsc::handleMessage(%s, \"%s\", %i, %p, \"%s\", %p)",
42 bool2str(isTCP), path, argc, argv, types, msg);
43 }
44 #endif
45
46 if (isTCP)
47 {
48 CARLA_SAFE_ASSERT_RETURN(fServerPathTCP.isNotEmpty(), 1);
49 CARLA_SAFE_ASSERT_RETURN(fServerTCP != nullptr, 1);
50 }
51 else
52 {
53 CARLA_SAFE_ASSERT_RETURN(fServerPathUDP.isNotEmpty(), 1);
54 CARLA_SAFE_ASSERT_RETURN(fServerUDP != nullptr, 1);
55 }
56
57 const lo_address source = lo_message_get_source(msg);
58
59 // Initial path check
60 if (std::strcmp(path, "/register") == 0)
61 return handleMsgRegister(isTCP, argc, argv, types, source);
62
63 if (std::strcmp(path, "/unregister") == 0)
64 return handleMsgUnregister(isTCP, argc, argv, types);
65
66 if (std::strncmp(path, "/ctrl/", 6) == 0)
67 {
68 CARLA_SAFE_ASSERT_RETURN(isTCP, 1);
69 return handleMsgControl(path + 6, argc, argv, types);
70 }
71
72 // Check if message is for this client
73 std::size_t bytesAfterName;
74 if (fControlDataTCP.owner != nullptr && std::strcmp(lo_address_get_hostname(source), fControlDataTCP.owner) == 0)
75 {
76 if (const char* const slash = std::strchr(path+1, '/'))
77 {
78 bytesAfterName = static_cast<std::size_t>(slash - path);
79 }
80 else
81 {
82 carla_stderr("CarlaEngineOsc::handleMessage() - message '%s' is invalid", path);
83 return 1;
84 }
85 }
86 else
87 {
88 bytesAfterName = fName.length();
89
90 if (std::strlen(path) <= bytesAfterName || std::strncmp(path+1, fName, bytesAfterName) != 0)
91 {
92 carla_stderr("CarlaEngineOsc::handleMessage() - message not for this client -> '%s' != '/%s/'",
93 path, fName.buffer());
94 return 1;
95 }
96
97 ++bytesAfterName;
98 }
99
100 // Get plugin id from path, "/carla/23/method" -> 23
101 uint pluginId = 0;
102 std::size_t offset;
103
104 if (! std::isdigit(path[bytesAfterName+1]))
105 {
106 carla_stderr("CarlaEngineOsc::handleMessage() - invalid message '%s'", path);
107 return 1;
108 }
109
110 if (std::isdigit(path[bytesAfterName+2]))
111 {
112 if (std::isdigit(path[bytesAfterName+4]))
113 {
114 carla_stderr2("CarlaEngineOsc::handleMessage() - invalid plugin id, over 999? (value: \"%s\")",
115 path+bytesAfterName);
116 return 1;
117 }
118 else if (std::isdigit(path[bytesAfterName+3]))
119 {
120 // 3 digits, /xyz/method
121 offset = 5;
122 pluginId += uint(path[bytesAfterName+1]-'0')*100;
123 pluginId += uint(path[bytesAfterName+2]-'0')*10;
124 pluginId += uint(path[bytesAfterName+3]-'0');
125 }
126 else
127 {
128 // 2 digits, /xy/method
129 offset = 4;
130 pluginId += uint(path[bytesAfterName+1]-'0')*10;
131 pluginId += uint(path[bytesAfterName+2]-'0');
132 }
133 }
134 else
135 {
136 // single digit, /x/method
137 offset = 3;
138 pluginId += uint(path[bytesAfterName+1]-'0');
139 }
140
141 if (pluginId > fEngine->getCurrentPluginCount())
142 {
143 carla_stderr("CarlaEngineOsc::handleMessage() - failed to get plugin, wrong id '%i'", pluginId);
144 return 0;
145 }
146
147 // Get plugin
148 const CarlaPluginPtr plugin = fEngine->getPluginUnchecked(pluginId);
149
150 if (plugin == nullptr || plugin->getId() != pluginId)
151 {
152 carla_stderr("CarlaEngineOsc::handleMessage() - invalid plugin id '%i', probably has been removed (path: '%s')", pluginId, path);
153 return 0;
154 }
155
156 // Get method from path, "/Carla/i/method" -> "method"
157 char method[48];
158 std::strncpy(method, path + (bytesAfterName + offset), 47);
159 method[47] = '\0';
160
161 if (method[0] == '\0')
162 {
163 carla_stderr("CarlaEngineOsc::handleMessage(%s, \"%s\", ...) - received message without method", bool2str(isTCP), path);
164 return 0;
165 }
166
167 // Internal methods
168 if (std::strcmp(method, "set_option") == 0)
169 return 0; //handleMsgSetOption(plugin, argc, argv, types); // TODO
170 if (std::strcmp(method, "set_active") == 0)
171 return handleMsgSetActive(plugin, argc, argv, types);
172 if (std::strcmp(method, "set_drywet") == 0)
173 return handleMsgSetDryWet(plugin, argc, argv, types);
174 if (std::strcmp(method, "set_volume") == 0)
175 return handleMsgSetVolume(plugin, argc, argv, types);
176 if (std::strcmp(method, "set_balance_left") == 0)
177 return handleMsgSetBalanceLeft(plugin, argc, argv, types);
178 if (std::strcmp(method, "set_balance_right") == 0)
179 return handleMsgSetBalanceRight(plugin, argc, argv, types);
180 if (std::strcmp(method, "set_panning") == 0)
181 return handleMsgSetPanning(plugin, argc, argv, types);
182 if (std::strcmp(method, "set_ctrl_channel") == 0)
183 return 0; //handleMsgSetControlChannel(plugin, argc, argv, types); // TODO
184 if (std::strcmp(method, "set_parameter_value") == 0)
185 return handleMsgSetParameterValue(plugin, argc, argv, types);
186 if (std::strcmp(method, "set_parameter_mapped_control_index") == 0)
187 return handleMsgSetParameterMappedControlIndex(plugin, argc, argv, types);
188 if (std::strcmp(method, "set_parameter_mapped_range") == 0)
189 return handleMsgSetParameterMappedRange(plugin, argc, argv, types);
190 if (std::strcmp(method, "set_parameter_midi_channel") == 0)
191 return handleMsgSetParameterMidiChannel(plugin, argc, argv, types);
192 if (std::strcmp(method, "set_program") == 0)
193 return handleMsgSetProgram(plugin, argc, argv, types);
194 if (std::strcmp(method, "set_midi_program") == 0)
195 return handleMsgSetMidiProgram(plugin, argc, argv, types);
196 if (std::strcmp(method, "set_custom_data") == 0)
197 return 0; //handleMsgSetCustomData(plugin, argc, argv, types); // TODO
198 if (std::strcmp(method, "set_chunk") == 0)
199 return 0; //handleMsgSetChunk(plugin, argc, argv, types); // TODO
200 if (std::strcmp(method, "note_on") == 0)
201 return handleMsgNoteOn(plugin, argc, argv, types);
202 if (std::strcmp(method, "note_off") == 0)
203 return handleMsgNoteOff(plugin, argc, argv, types);
204
205 // Send all other methods to plugins, TODO
206 plugin->handleOscMessage(method, argc, argv, types, msg);
207 return 0;
208 }
209
210 // -----------------------------------------------------------------------
211
handleMsgRegister(const bool isTCP,const int argc,const lo_arg * const * const argv,const char * const types,const lo_address source)212 int CarlaEngineOsc::handleMsgRegister(const bool isTCP,
213 const int argc, const lo_arg* const* const argv, const char* const types,
214 const lo_address source)
215 {
216 carla_debug("CarlaEngineOsc::handleMsgRegister()");
217 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "s");
218
219 const char* const url = &argv[0]->s;
220
221 CarlaOscData& oscData(isTCP ? fControlDataTCP : fControlDataUDP);
222
223 if (oscData.owner != nullptr)
224 {
225 carla_stderr("OSC backend already registered to %s", oscData.owner);
226
227 char* const path = lo_url_get_path(url);
228 const size_t pathlen = std::strlen(path);
229 CARLA_SAFE_ASSERT_RETURN(pathlen < 32, 0);
230
231 char targetPath[pathlen+12];
232 std::strcpy(targetPath, path);
233 std::strcat(targetPath, "/exit-error");
234
235 lo_send_from(source, isTCP ? fServerTCP : fServerUDP, LO_TT_IMMEDIATE,
236 targetPath, "s", "OSC already registered to another client");
237
238 free(path);
239 }
240 else
241 {
242 const char* const host = lo_address_get_hostname(source);
243 /* */ char* const port = lo_url_get_port(url); // NOTE: lo_address_get_port is buggy against TCP
244 const lo_address target = lo_address_new_with_proto(isTCP ? LO_TCP : LO_UDP, host, port);
245
246 oscData.owner = carla_strdup_safe(host);
247 oscData.path = carla_strdup_free(lo_url_get_path(url));
248 oscData.target = target;
249
250 char* const targeturl = lo_address_get_url(target);
251 carla_stdout("OSC %s backend registered to %s, path: %s, target: %s (host: %s, port: %s)",
252 isTCP ? "TCP" : "UDP", url, oscData.path, targeturl, host, port);
253 free(targeturl);
254 free(port);
255
256 if (isTCP)
257 {
258 const EngineOptions& opts(fEngine->getOptions());
259
260 fEngine->callback(false, true,
261 ENGINE_CALLBACK_ENGINE_STARTED,
262 fEngine->getCurrentPluginCount(),
263 opts.processMode,
264 opts.transportMode,
265 static_cast<int>(fEngine->getBufferSize()),
266 static_cast<float>(fEngine->getSampleRate()),
267 fEngine->getCurrentDriverName());
268
269 for (uint i=0, count=fEngine->getCurrentPluginCount(); i < count; ++i)
270 {
271 const CarlaPluginPtr plugin = fEngine->getPluginUnchecked(i);
272 CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);
273
274 fEngine->callback(false, true, ENGINE_CALLBACK_PLUGIN_ADDED, i, 0, 0, 0, 0.0f, plugin->getName());
275 }
276
277 fEngine->patchbayRefresh(false, true, fEngine->pData->graph.isUsingExternalOSC());
278 }
279 }
280
281 return 0;
282 }
283
handleMsgUnregister(const bool isTCP,const int argc,const lo_arg * const * const argv,const char * const types)284 int CarlaEngineOsc::handleMsgUnregister(const bool isTCP,
285 const int argc, const lo_arg* const* const argv, const char* const types)
286 {
287 carla_debug("CarlaEngineOsc::handleMsgUnregister()");
288 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "s");
289
290 CarlaOscData& oscData(isTCP ? fControlDataTCP : fControlDataUDP);
291
292 if (oscData.owner == nullptr)
293 {
294 carla_stderr("OSC backend is not registered yet, unregister failed");
295 return 0;
296 }
297
298 const char* const url = &argv[0]->s;
299
300 if (std::strcmp(oscData.owner, url) == 0)
301 {
302 carla_stdout("OSC client %s unregistered", url);
303 oscData.clear();
304 return 0;
305 }
306
307 carla_stderr("OSC backend unregister failed, current owner %s does not match requested %s", oscData.owner, url);
308 return 0;
309 }
310
handleMsgControl(const char * const method,const int argc,const lo_arg * const * const argv,const char * const types)311 int CarlaEngineOsc::handleMsgControl(const char* const method,
312 const int argc, const lo_arg* const* const argv, const char* const types)
313 {
314 carla_debug("CarlaEngineOsc::handleMsgControl()");
315 CARLA_SAFE_ASSERT_RETURN(method != nullptr && method[0] != '\0', 0);
316 CARLA_SAFE_ASSERT_RETURN(types != nullptr, 0);
317 CARLA_SAFE_ASSERT_RETURN(types[0] == 'i', 0);
318
319 if (fControlDataTCP.owner == nullptr)
320 {
321 carla_stderr("OSC backend is not registered yet, control failed");
322 return 0;
323 }
324
325 const int32_t messageId = argv[0]->i;
326 bool ok;
327
328 #define CARLA_SAFE_ASSERT_RETURN_OSC_ERR(cond) \
329 if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); sendResponse(messageId, #cond); return 0; }
330
331 /**/ if (std::strcmp(method, "clear_engine_xruns") == 0)
332 {
333 ok = true;
334 fEngine->clearXruns();
335 }
336 else if (std::strcmp(method, "cancel_engine_action") == 0)
337 {
338 ok = true;
339 fEngine->setActionCanceled(true);
340 }
341 else if (std::strcmp(method, "patchbay_connect") == 0)
342 {
343 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 6);
344 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
345 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 'i');
346 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[3] == 'i');
347 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[4] == 'i');
348 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[5] == 'i');
349
350 const bool external = argv[1]->i != 0;
351
352 const int32_t groupA = argv[2]->i;
353 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(groupA >= 0);
354
355 const int32_t portA = argv[3]->i;
356 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(portA >= 0);
357
358 const int32_t groupB = argv[4]->i;
359 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(groupB >= 0);
360
361 const int32_t portB = argv[5]->i;
362 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(portB >= 0);
363
364 ok = fEngine->patchbayConnect(external,
365 static_cast<uint32_t>(groupA),
366 static_cast<uint32_t>(portA),
367 static_cast<uint32_t>(groupB),
368 static_cast<uint32_t>(portB));
369 }
370 else if (std::strcmp(method, "patchbay_disconnect") == 0)
371 {
372 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 3);
373 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
374 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 'i');
375
376 const bool external = argv[1]->i != 0;
377
378 const int32_t connectionId = argv[2]->i;
379 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(connectionId >= 0);
380
381 ok = fEngine->patchbayDisconnect(external, static_cast<uint32_t>(connectionId));
382 }
383 else if (std::strcmp(method, "patchbay_set_group_pos") == 0)
384 {
385 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 7);
386 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
387 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 'i');
388 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[3] == 'i');
389 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[4] == 'i');
390 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[5] == 'i');
391 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[6] == 'i');
392
393 const bool external = argv[1]->i != 0;
394
395 const int32_t groupId = argv[2]->i;
396 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(groupId >= 0);
397
398 ok = fEngine->patchbaySetGroupPos(true, false,
399 external, static_cast<uint32_t>(groupId),
400 argv[3]->i, argv[4]->i, argv[5]->i, argv[6]->i);
401 }
402 else if (std::strcmp(method, "patchbay_refresh") == 0)
403 {
404 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
405 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
406
407 const bool external = argv[1]->i != 0;
408
409 ok = fEngine->patchbayRefresh(false, true, external);
410 }
411 else if (std::strcmp(method, "transport_play") == 0)
412 {
413 ok = true;
414 fEngine->transportPlay();
415 }
416 else if (std::strcmp(method, "transport_pause") == 0)
417 {
418 ok = true;
419 fEngine->transportPause();
420 }
421 else if (std::strcmp(method, "transport_bpm") == 0)
422 {
423 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
424 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'f');
425
426 const double bpm = argv[1]->f;
427 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(bpm >= 0.0);
428
429 ok = true;
430 fEngine->transportBPM(bpm);
431 }
432 else if (std::strcmp(method, "transport_relocate") == 0)
433 {
434 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
435
436 uint64_t frame;
437
438 /**/ if (types[1] == 'i')
439 {
440 const int32_t i = argv[1]->i;
441 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(i >= 0);
442 frame = static_cast<uint64_t>(i);
443 }
444 else if (types[1] == 'h')
445 {
446 const int64_t h = argv[1]->h;
447 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(h >= 0);
448 frame = static_cast<uint64_t>(h);
449 }
450 else
451 {
452 carla_stderr2("Wrong OSC type used for '%s'", method);
453 sendResponse(messageId, "Wrong OSC type");
454 return 0;
455 }
456
457 ok = true;
458 fEngine->transportRelocate(frame);
459 }
460 else if (std::strcmp(method, "add_plugin") == 0)
461 {
462 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 8);
463 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
464 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 'i');
465 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[3] == 's');
466 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[4] == 's');
467 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[5] == 's');
468 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[7] == 'i');
469
470 int32_t btype = argv[1]->i;
471 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(btype >= 0);
472
473 const int32_t ptype = argv[2]->i;
474 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(ptype >= 0);
475
476 // Force binary type to be native in some cases
477 switch (ptype)
478 {
479 case PLUGIN_INTERNAL:
480 case PLUGIN_LV2:
481 case PLUGIN_SF2:
482 case PLUGIN_SFZ:
483 case PLUGIN_JACK:
484 btype = BINARY_NATIVE;
485 break;
486 }
487
488 const char* filename = &argv[3]->s;
489
490 if (filename != nullptr && std::strcmp(filename, "(null)") == 0)
491 filename = nullptr;
492
493 const char* name = &argv[4]->s;
494
495 if (name != nullptr && std::strcmp(name, "(null)") == 0)
496 name = nullptr;
497
498 const char* const label = &argv[5]->s;
499 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(label != nullptr && label[0] != '\0');
500
501 int64_t uniqueId;
502
503 /**/ if (types[6] == 'i')
504 {
505 uniqueId = argv[6]->i;
506 }
507 else if (types[6] == 'h')
508 {
509 uniqueId = argv[6]->h;
510 }
511 else
512 {
513 carla_stderr2("Wrong OSC type used for '%s' uniqueId", method);
514 sendResponse(messageId, "Wrong OSC type");
515 return 0;
516 }
517
518 const int32_t options = argv[7]->i;
519 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(options >= 0);
520
521 ok = fEngine->addPlugin(static_cast<BinaryType>(btype),
522 static_cast<PluginType>(ptype),
523 filename, name, label, uniqueId, nullptr, static_cast<uint32_t>(options));
524 }
525 else if (std::strcmp(method, "remove_plugin") == 0)
526 {
527 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
528 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
529
530 const int32_t id = argv[1]->i;
531 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(id >= 0);
532
533 ok = fEngine->removePlugin(static_cast<uint32_t>(id));
534 }
535 else if (std::strcmp(method, "remove_all_plugins") == 0)
536 {
537 ok = fEngine->removeAllPlugins();
538 }
539 else if (std::strcmp(method, "rename_plugin") == 0)
540 {
541 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 3);
542 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
543 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 's');
544
545 const int32_t id = argv[1]->i;
546 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(id >= 0);
547
548 const char* const newName = &argv[2]->s;
549 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(newName != nullptr && newName[0] != '\0');
550
551 ok = fEngine->renamePlugin(static_cast<uint32_t>(id), newName);
552 }
553 else if (std::strcmp(method, "clone_plugin") == 0)
554 {
555 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
556 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
557
558 const int32_t id = argv[1]->i;
559 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(id >= 0);
560
561 ok = fEngine->clonePlugin(static_cast<uint32_t>(id));
562 }
563 else if (std::strcmp(method, "replace_plugin") == 0)
564 {
565 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 2);
566 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
567
568 const int32_t id = argv[1]->i;
569 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(id >= 0);
570
571 ok = fEngine->replacePlugin(static_cast<uint32_t>(id));
572 }
573 else if (std::strcmp(method, "switch_plugins") == 0)
574 {
575 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(argc == 3);
576 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[1] == 'i');
577 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(types[2] == 'i');
578
579 const int32_t idA = argv[1]->i;
580 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(idA >= 0);
581
582 const int32_t idB = argv[2]->i;
583 CARLA_SAFE_ASSERT_RETURN_OSC_ERR(idB >= 0);
584
585 ok = fEngine->switchPlugins(static_cast<uint32_t>(idA), static_cast<uint32_t>(idB));
586 }
587 else
588 {
589 carla_stderr2("Unhandled OSC control for '%s'", method);
590 sendResponse(messageId, "Unhandled OSC control method");
591 return 0;
592 }
593
594 #undef CARLA_SAFE_ASSERT_RETURN_OSC_ERR
595
596 sendResponse(messageId, ok ? "" : fEngine->getLastError());
597 return 0;
598 }
599
600 // -----------------------------------------------------------------------
601
handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS)602 int CarlaEngineOsc::handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS)
603 {
604 carla_debug("CarlaEngineOsc::handleMsgSetActive()");
605 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "i");
606
607 const bool active = (argv[0]->i != 0);
608
609 plugin->setActive(active, false, true);
610 return 0;
611 }
612
handleMsgSetDryWet(CARLA_ENGINE_OSC_HANDLE_ARGS)613 int CarlaEngineOsc::handleMsgSetDryWet(CARLA_ENGINE_OSC_HANDLE_ARGS)
614 {
615 carla_debug("CarlaEngineOsc::handleMsgSetDryWet()");
616 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "f");
617
618 const float value = argv[0]->f;
619
620 plugin->setDryWet(value, false, true);
621 return 0;
622 }
623
handleMsgSetVolume(CARLA_ENGINE_OSC_HANDLE_ARGS)624 int CarlaEngineOsc::handleMsgSetVolume(CARLA_ENGINE_OSC_HANDLE_ARGS)
625 {
626 carla_debug("CarlaEngineOsc::handleMsgSetVolume()");
627 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "f");
628
629 const float value = argv[0]->f;
630
631 plugin->setVolume(value, false, true);
632 return 0;
633 }
634
handleMsgSetBalanceLeft(CARLA_ENGINE_OSC_HANDLE_ARGS)635 int CarlaEngineOsc::handleMsgSetBalanceLeft(CARLA_ENGINE_OSC_HANDLE_ARGS)
636 {
637 carla_debug("CarlaEngineOsc::handleMsgSetBalanceLeft()");
638 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "f");
639
640 const float value = argv[0]->f;
641
642 plugin->setBalanceLeft(value, false, true);
643 return 0;
644 }
645
handleMsgSetBalanceRight(CARLA_ENGINE_OSC_HANDLE_ARGS)646 int CarlaEngineOsc::handleMsgSetBalanceRight(CARLA_ENGINE_OSC_HANDLE_ARGS)
647 {
648 carla_debug("CarlaEngineOsc::handleMsgSetBalanceRight()");
649 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "f");
650
651 const float value = argv[0]->f;
652
653 plugin->setBalanceRight(value, false, true);
654 return 0;
655 }
656
handleMsgSetPanning(CARLA_ENGINE_OSC_HANDLE_ARGS)657 int CarlaEngineOsc::handleMsgSetPanning(CARLA_ENGINE_OSC_HANDLE_ARGS)
658 {
659 carla_debug("CarlaEngineOsc::handleMsgSetPanning()");
660 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "f");
661
662 const float value = argv[0]->f;
663
664 plugin->setPanning(value, false, true);
665 return 0;
666 }
667
handleMsgSetParameterValue(CARLA_ENGINE_OSC_HANDLE_ARGS)668 int CarlaEngineOsc::handleMsgSetParameterValue(CARLA_ENGINE_OSC_HANDLE_ARGS)
669 {
670 carla_debug("CarlaEngineOsc::handleMsgSetParameterValue()");
671 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "if");
672
673 const int32_t index = argv[0]->i;
674 const float value = argv[1]->f;
675
676 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
677
678 plugin->setParameterValue(static_cast<uint32_t>(index), value, true, false, true);
679 return 0;
680 }
681
handleMsgSetParameterMappedControlIndex(CARLA_ENGINE_OSC_HANDLE_ARGS)682 int CarlaEngineOsc::handleMsgSetParameterMappedControlIndex(CARLA_ENGINE_OSC_HANDLE_ARGS)
683 {
684 carla_debug("CarlaEngineOsc::handleMsgSetParameterMappedIndex()");
685 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "ii");
686
687 const int32_t index = argv[0]->i;
688 const int32_t ctrl = argv[1]->i;
689
690 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
691 CARLA_SAFE_ASSERT_RETURN(ctrl >= CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED, 0);
692
693 plugin->setParameterMappedControlIndex(static_cast<uint32_t>(index), static_cast<int16_t>(ctrl), false, true, true);
694 return 0;
695 }
696
handleMsgSetParameterMappedRange(CARLA_ENGINE_OSC_HANDLE_ARGS)697 int CarlaEngineOsc::handleMsgSetParameterMappedRange(CARLA_ENGINE_OSC_HANDLE_ARGS)
698 {
699 carla_debug("CarlaEngineOsc::handleMsgSetParameterMappedRange()");
700 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "iff");
701
702 const int32_t index = argv[0]->i;
703 const float minimum = argv[1]->f;
704 const float maximum = argv[2]->f;
705
706 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
707
708 plugin->setParameterMappedRange(static_cast<uint32_t>(index), minimum, maximum, false, true);
709 return 0;
710 }
711
handleMsgSetParameterMidiChannel(CARLA_ENGINE_OSC_HANDLE_ARGS)712 int CarlaEngineOsc::handleMsgSetParameterMidiChannel(CARLA_ENGINE_OSC_HANDLE_ARGS)
713 {
714 carla_debug("CarlaEngineOsc::handleMsgSetParameterMidiChannel()");
715 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "ii");
716
717 const int32_t index = argv[0]->i;
718 const int32_t channel = argv[1]->i;
719
720 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
721 CARLA_SAFE_ASSERT_RETURN(channel >= 0 && channel < MAX_MIDI_CHANNELS, 0);
722
723 plugin->setParameterMidiChannel(static_cast<uint32_t>(index), static_cast<uint8_t>(channel), false, true);
724 return 0;
725 }
726
handleMsgSetProgram(CARLA_ENGINE_OSC_HANDLE_ARGS)727 int CarlaEngineOsc::handleMsgSetProgram(CARLA_ENGINE_OSC_HANDLE_ARGS)
728 {
729 carla_debug("CarlaEngineOsc::handleMsgSetProgram()");
730 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "i");
731
732 const int32_t index = argv[0]->i;
733
734 CARLA_SAFE_ASSERT_RETURN(index >= -1, 0);
735
736 plugin->setProgram(index, true, false, true);
737 return 0;
738 }
739
handleMsgSetMidiProgram(CARLA_ENGINE_OSC_HANDLE_ARGS)740 int CarlaEngineOsc::handleMsgSetMidiProgram(CARLA_ENGINE_OSC_HANDLE_ARGS)
741 {
742 carla_debug("CarlaEngineOsc::handleMsgSetMidiProgram()");
743 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(1, "i");
744
745 const int32_t index = argv[0]->i;
746
747 CARLA_SAFE_ASSERT_RETURN(index >= -1, 0);
748
749 plugin->setMidiProgram(index, true, false, true);
750 return 0;
751 }
752
handleMsgNoteOn(CARLA_ENGINE_OSC_HANDLE_ARGS)753 int CarlaEngineOsc::handleMsgNoteOn(CARLA_ENGINE_OSC_HANDLE_ARGS)
754 {
755 carla_debug("CarlaEngineOsc::handleMsgNoteOn()");
756 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(3, "iii");
757
758 const int32_t channel = argv[0]->i;
759 const int32_t note = argv[1]->i;
760 const int32_t velo = argv[2]->i;
761
762 CARLA_SAFE_ASSERT_RETURN(channel >= 0 && channel < MAX_MIDI_CHANNELS, 0);
763 CARLA_SAFE_ASSERT_RETURN(note >= 0 && note < MAX_MIDI_NOTE, 0);
764 CARLA_SAFE_ASSERT_RETURN(velo >= 0 && velo < MAX_MIDI_VALUE, 0);
765
766 plugin->sendMidiSingleNote(static_cast<uint8_t>(channel), static_cast<uint8_t>(note), static_cast<uint8_t>(velo), true, false, true);
767 return 0;
768 }
769
handleMsgNoteOff(CARLA_ENGINE_OSC_HANDLE_ARGS)770 int CarlaEngineOsc::handleMsgNoteOff(CARLA_ENGINE_OSC_HANDLE_ARGS)
771 {
772 carla_debug("CarlaEngineOsc::handleMsgNoteOff()");
773 CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "ii");
774
775 const int32_t channel = argv[0]->i;
776 const int32_t note = argv[1]->i;
777
778 CARLA_SAFE_ASSERT_RETURN(channel >= 0 && channel < MAX_MIDI_CHANNELS, 0);
779 CARLA_SAFE_ASSERT_RETURN(note >= 0 && note < MAX_MIDI_NOTE, 0);
780
781 plugin->sendMidiSingleNote(static_cast<uint8_t>(channel), static_cast<uint8_t>(note), 0, true, false, true);
782 return 0;
783 }
784
785 // -----------------------------------------------------------------------
786
787 CARLA_BACKEND_END_NAMESPACE
788
789 #endif // HAVE_LIBLO
790