Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

807 lines
27KB

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