Collection of tools useful for audio production
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.

924 lines
30KB

  1. /*
  2. * Carla UI bridge code
  3. * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * 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 COPYING file
  16. */
  17. #ifdef BRIDGE_LV2
  18. #include "carla_bridge_client.h"
  19. #include "carla_lv2.h"
  20. #include "carla_midi.h"
  21. #include "rtmempool/rtmempool.h"
  22. #include <vector>
  23. #include <QtCore/QDir>
  24. #ifdef BRIDGE_LV2_X11
  25. # include <QtGui/QDialog>
  26. #endif
  27. CARLA_BRIDGE_START_NAMESPACE
  28. // -------------------------------------------------------------------------
  29. // fake values
  30. uint32_t bufferSize = 512;
  31. double sampleRate = 44100.0;
  32. // feature ids
  33. const uint32_t lv2_feature_id_event = 0;
  34. const uint32_t lv2_feature_id_logs = 1;
  35. const uint32_t lv2_feature_id_programs = 2;
  36. const uint32_t lv2_feature_id_state_make_path = 3;
  37. const uint32_t lv2_feature_id_state_map_path = 4;
  38. const uint32_t lv2_feature_id_strict_bounds = 5;
  39. const uint32_t lv2_feature_id_uri_map = 6;
  40. const uint32_t lv2_feature_id_urid_map = 7;
  41. const uint32_t lv2_feature_id_urid_unmap = 8;
  42. const uint32_t lv2_feature_id_ui_parent = 9;
  43. const uint32_t lv2_feature_id_ui_port_map = 10;
  44. const uint32_t lv2_feature_id_ui_resize = 11;
  45. const uint32_t lv2_feature_count = 12;
  46. // pre-set uri[d] map ids
  47. const uint32_t CARLA_URI_MAP_ID_NULL = 0;
  48. const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 1;
  49. const uint32_t CARLA_URI_MAP_ID_ATOM_PATH = 2;
  50. const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 3;
  51. const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 4;
  52. const uint32_t CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM = 5;
  53. const uint32_t CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT = 6;
  54. const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 7;
  55. const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 8;
  56. const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 9;
  57. const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 10;
  58. const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 11;
  59. const uint32_t CARLA_URI_MAP_ID_COUNT = 12;
  60. // -------------------------------------------------------------------------
  61. class CarlaLv2Client : public CarlaClient
  62. {
  63. public:
  64. CarlaLv2Client(CarlaToolkit* const toolkit)
  65. : CarlaClient(toolkit)
  66. {
  67. handle = nullptr;
  68. widget = nullptr;
  69. descriptor = nullptr;
  70. rdf_descriptor = nullptr;
  71. rdf_ui_descriptor = nullptr;
  72. programs = nullptr;
  73. #ifdef BRIDGE_LV2_X11
  74. m_resizable = false;
  75. x11_widget = new QDialog;
  76. #else
  77. m_resizable = true;
  78. #endif
  79. for (uint32_t i=0; i < CARLA_URI_MAP_ID_COUNT; i++)
  80. customURIDs.push_back(nullptr);
  81. for (uint32_t i=0; i < lv2_feature_count+1; i++)
  82. features[i] = nullptr;
  83. // -----------------------------------------------------------------
  84. // initialize features
  85. LV2_Event_Feature* Event_Feature = new LV2_Event_Feature;
  86. Event_Feature->callback_data = this;
  87. Event_Feature->lv2_event_ref = carla_lv2_event_ref;
  88. Event_Feature->lv2_event_unref = carla_lv2_event_unref;
  89. LV2_Log_Log* Log_Feature = new LV2_Log_Log;
  90. Log_Feature->handle = this;
  91. Log_Feature->printf = carla_lv2_log_printf;
  92. Log_Feature->vprintf = carla_lv2_log_vprintf;
  93. LV2_Programs_Host* Programs_Feature = new LV2_Programs_Host;
  94. Programs_Feature->handle = this;
  95. Programs_Feature->program_changed = carla_lv2_program_changed;
  96. LV2_State_Make_Path* State_MakePath_Feature = new LV2_State_Make_Path;
  97. State_MakePath_Feature->handle = this;
  98. State_MakePath_Feature->path = carla_lv2_state_make_path;
  99. LV2_State_Map_Path* State_MapPath_Feature = new LV2_State_Map_Path;
  100. State_MapPath_Feature->handle = this;
  101. State_MapPath_Feature->abstract_path = carla_lv2_state_map_abstract_path;
  102. State_MapPath_Feature->absolute_path = carla_lv2_state_map_absolute_path;
  103. LV2_URI_Map_Feature* URI_Map_Feature = new LV2_URI_Map_Feature;
  104. URI_Map_Feature->callback_data = this;
  105. URI_Map_Feature->uri_to_id = carla_lv2_uri_to_id;
  106. LV2_URID_Map* URID_Map_Feature = new LV2_URID_Map;
  107. URID_Map_Feature->handle = this;
  108. URID_Map_Feature->map = carla_lv2_urid_map;
  109. LV2_URID_Unmap* URID_Unmap_Feature = new LV2_URID_Unmap;
  110. URID_Unmap_Feature->handle = this;
  111. URID_Unmap_Feature->unmap = carla_lv2_urid_unmap;
  112. LV2UI_Port_Map* UI_PortMap_Feature = new LV2UI_Port_Map;
  113. UI_PortMap_Feature->handle = this;
  114. UI_PortMap_Feature->port_index = carla_lv2_ui_port_map;
  115. LV2UI_Resize* UI_Resize_Feature = new LV2UI_Resize;
  116. UI_Resize_Feature->handle = this;
  117. UI_Resize_Feature->ui_resize = carla_lv2_ui_resize;
  118. features[lv2_feature_id_event] = new LV2_Feature;
  119. features[lv2_feature_id_event]->URI = LV2_EVENT_URI;
  120. features[lv2_feature_id_event]->data = Event_Feature;
  121. features[lv2_feature_id_logs] = new LV2_Feature;
  122. features[lv2_feature_id_logs]->URI = LV2_LOG__log;
  123. features[lv2_feature_id_logs]->data = Log_Feature;
  124. features[lv2_feature_id_programs] = new LV2_Feature;
  125. features[lv2_feature_id_programs]->URI = LV2_PROGRAMS__Host;
  126. features[lv2_feature_id_programs]->data = Programs_Feature;
  127. features[lv2_feature_id_state_make_path] = new LV2_Feature;
  128. features[lv2_feature_id_state_make_path]->URI = LV2_STATE__makePath;
  129. features[lv2_feature_id_state_make_path]->data = State_MakePath_Feature;
  130. features[lv2_feature_id_state_map_path] = new LV2_Feature;
  131. features[lv2_feature_id_state_map_path]->URI = LV2_STATE__mapPath;
  132. features[lv2_feature_id_state_map_path]->data = State_MapPath_Feature;
  133. features[lv2_feature_id_strict_bounds] = new LV2_Feature;
  134. features[lv2_feature_id_strict_bounds]->URI = LV2_PORT_PROPS__supportsStrictBounds;
  135. features[lv2_feature_id_strict_bounds]->data = nullptr;
  136. features[lv2_feature_id_uri_map] = new LV2_Feature;
  137. features[lv2_feature_id_uri_map]->URI = LV2_URI_MAP_URI;
  138. features[lv2_feature_id_uri_map]->data = URI_Map_Feature;
  139. features[lv2_feature_id_urid_map] = new LV2_Feature;
  140. features[lv2_feature_id_urid_map]->URI = LV2_URID__map;
  141. features[lv2_feature_id_urid_map]->data = URID_Map_Feature;
  142. features[lv2_feature_id_urid_unmap] = new LV2_Feature;
  143. features[lv2_feature_id_urid_unmap]->URI = LV2_URID__unmap;
  144. features[lv2_feature_id_urid_unmap]->data = URID_Unmap_Feature;
  145. features[lv2_feature_id_ui_parent] = new LV2_Feature;
  146. features[lv2_feature_id_ui_parent]->URI = LV2_UI__parent;
  147. #ifdef BRIDGE_LV2_X11
  148. features[lv2_feature_id_ui_parent]->data = (void*)x11_widget->winId();
  149. #else
  150. features[lv2_feature_id_ui_parent]->data = nullptr;
  151. #endif
  152. features[lv2_feature_id_ui_port_map] = new LV2_Feature;
  153. features[lv2_feature_id_ui_port_map]->URI = LV2_UI__portMap;
  154. features[lv2_feature_id_ui_port_map]->data = UI_PortMap_Feature;
  155. features[lv2_feature_id_ui_resize] = new LV2_Feature;
  156. features[lv2_feature_id_ui_resize]->URI = LV2_UI__resize;
  157. features[lv2_feature_id_ui_resize]->data = UI_Resize_Feature;
  158. }
  159. ~CarlaLv2Client()
  160. {
  161. if (rdf_descriptor)
  162. lv2_rdf_free(rdf_descriptor);
  163. delete (LV2_Event_Feature*)features[lv2_feature_id_event]->data;
  164. delete (LV2_Log_Log*)features[lv2_feature_id_logs]->data;
  165. delete (LV2_Programs_Host*)features[lv2_feature_id_programs]->data;
  166. delete (LV2_State_Make_Path*)features[lv2_feature_id_state_make_path]->data;
  167. delete (LV2_State_Map_Path*)features[lv2_feature_id_state_map_path]->data;
  168. delete (LV2_URI_Map_Feature*)features[lv2_feature_id_uri_map]->data;
  169. delete (LV2_URID_Map*)features[lv2_feature_id_urid_map]->data;
  170. delete (LV2_URID_Unmap*)features[lv2_feature_id_urid_unmap]->data;
  171. delete (LV2UI_Port_Map*)features[lv2_feature_id_ui_port_map]->data;
  172. delete (LV2UI_Resize*)features[lv2_feature_id_ui_resize]->data;
  173. for (uint32_t i=0; i < lv2_feature_count; i++)
  174. {
  175. if (features[i])
  176. delete features[i];
  177. }
  178. for (size_t i=0; i < customURIDs.size(); i++)
  179. {
  180. if (customURIDs[i])
  181. free((void*)customURIDs[i]);
  182. }
  183. customURIDs.clear();
  184. }
  185. // ---------------------------------------------------------------------
  186. // ui initialization
  187. bool init(const char* plugin_uri, const char* ui_uri)
  188. {
  189. // -----------------------------------------------------------------
  190. // get plugin from lv2_rdf (lilv)
  191. Lv2World.init();
  192. rdf_descriptor = lv2_rdf_new(plugin_uri);
  193. if (! rdf_descriptor)
  194. return false;
  195. // -----------------------------------------------------------------
  196. // find requested UI
  197. for (uint32_t i=0; i < rdf_descriptor->UICount; i++)
  198. {
  199. if (strcmp(rdf_descriptor->UIs[i].URI, ui_uri) == 0)
  200. {
  201. rdf_ui_descriptor = &rdf_descriptor->UIs[i];
  202. break;
  203. }
  204. }
  205. if (! rdf_ui_descriptor)
  206. return false;
  207. // -----------------------------------------------------------------
  208. // open DLL
  209. if (! libOpen(rdf_ui_descriptor->Binary))
  210. return false;
  211. // -----------------------------------------------------------------
  212. // get DLL main entry
  213. LV2UI_DescriptorFunction const ui_descfn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor");
  214. if (! ui_descfn)
  215. return false;
  216. // -----------------------------------------------------------
  217. // get descriptor that matches URI
  218. uint32_t i = 0;
  219. while ((descriptor = ui_descfn(i++)))
  220. {
  221. if (strcmp(descriptor->URI, ui_uri) == 0)
  222. break;
  223. }
  224. if (! descriptor)
  225. return false;
  226. // -----------------------------------------------------------
  227. // initialize UI
  228. handle = descriptor->instantiate(descriptor, plugin_uri, rdf_ui_descriptor->Bundle, carla_lv2_ui_write_function, this, &widget, features);
  229. if (! handle)
  230. return false;
  231. // -----------------------------------------------------------
  232. // check if not resizable
  233. #ifndef BRIDGE_LV2_X11
  234. for (uint32_t i=0; i < rdf_ui_descriptor->FeatureCount; i++)
  235. {
  236. if (strcmp(rdf_ui_descriptor->Features[i].URI, LV2_UI__fixedSize) == 0 || strcmp(rdf_ui_descriptor->Features[i].URI, LV2_UI__noUserResize) == 0)
  237. {
  238. m_resizable = false;
  239. break;
  240. }
  241. }
  242. #endif
  243. // -----------------------------------------------------------
  244. // check for known extensions
  245. for (uint32_t i=0; descriptor->extension_data && i < rdf_ui_descriptor->ExtensionCount; i++)
  246. {
  247. if (strcmp(rdf_ui_descriptor->Extensions[i], LV2_PROGRAMS__UIInterface) == 0)
  248. {
  249. programs = (LV2_Programs_UI_Interface*)descriptor->extension_data(LV2_PROGRAMS__UIInterface);
  250. break;
  251. }
  252. }
  253. return true;
  254. }
  255. void close()
  256. {
  257. if (handle && descriptor && descriptor->cleanup)
  258. descriptor->cleanup(handle);
  259. libClose();
  260. }
  261. // ---------------------------------------------------------------------
  262. // ui management
  263. void* getWidget() const
  264. {
  265. #ifdef BRIDGE_LV2_X11
  266. return x11_widget;
  267. #else
  268. return widget;
  269. #endif
  270. }
  271. bool isResizable() const
  272. {
  273. return m_resizable;
  274. }
  275. bool needsReparent() const
  276. {
  277. #ifdef BRIDGE_LV2_X11
  278. return true;
  279. #else
  280. return false;
  281. #endif
  282. }
  283. // ---------------------------------------------------------------------
  284. // processing
  285. void setParameter(const int32_t rindex, const double value)
  286. {
  287. Q_ASSERT(handle && descriptor);
  288. if (handle && descriptor && descriptor->port_event)
  289. {
  290. float fvalue = value;
  291. descriptor->port_event(handle, rindex, sizeof(float), 0, &fvalue);
  292. }
  293. }
  294. void setProgram(const uint32_t)
  295. {
  296. }
  297. void setMidiProgram(const uint32_t bank, const uint32_t program)
  298. {
  299. Q_ASSERT(handle);
  300. if (handle && programs)
  301. programs->select_program(handle, bank, program);
  302. }
  303. void noteOn(const uint8_t channel, const uint8_t note, const uint8_t velo)
  304. {
  305. Q_ASSERT(handle && descriptor);
  306. if (handle && descriptor && descriptor->port_event)
  307. {
  308. uint8_t buf[3] = { uint8_t(0x90 + channel), note, velo };
  309. descriptor->port_event(handle, 0, 3, CARLA_URI_MAP_ID_MIDI_EVENT, buf);
  310. }
  311. }
  312. void noteOff(const uint8_t channel, const uint8_t note)
  313. {
  314. Q_ASSERT(handle && descriptor);
  315. if (handle && descriptor && descriptor->port_event)
  316. {
  317. uint8_t buf[3] = { uint8_t(0x80 + channel), note, 0 };
  318. descriptor->port_event(handle, 0, 3, CARLA_URI_MAP_ID_MIDI_EVENT, buf);
  319. }
  320. }
  321. // ---------------------------------------------------------------------
  322. uint32_t getCustomURID(const char* const uri)
  323. {
  324. qDebug("CarlaLv2Client::getCustomURID(%s)", uri);
  325. Q_ASSERT(uri);
  326. for (size_t i=0; i < customURIDs.size(); i++)
  327. {
  328. if (customURIDs[i] && strcmp(customURIDs[i], uri) == 0)
  329. return i;
  330. }
  331. customURIDs.push_back(strdup(uri));
  332. return customURIDs.size()-1;
  333. }
  334. const char* getCustomURIString(LV2_URID urid)
  335. {
  336. qDebug("CarlaLv2Client::getCustomURIString(%i)", urid);
  337. Q_ASSERT(urid != 0);
  338. if (urid < customURIDs.size())
  339. return customURIDs[urid];
  340. return nullptr;
  341. }
  342. void handleTransferAtom(const int32_t portIndex, const char* const atomBuf)
  343. {
  344. qDebug("CarlaLv2Client::handleTransferEvent(%i, \"%s\")", portIndex, atomBuf);
  345. Q_ASSERT(portIndex >= 0);
  346. Q_ASSERT(atomBuf);
  347. }
  348. void handleTransferEvent(const int32_t portIndex, const char* const atomBuf)
  349. {
  350. qDebug("CarlaLv2Client::handleTransferEvent(%i, \"%s\")", portIndex, atomBuf);
  351. Q_ASSERT(portIndex >= 0);
  352. Q_ASSERT(atomBuf);
  353. #if 0
  354. if (handle && descriptor && descriptor->port_event)
  355. {
  356. LV2_URID_Map* const URID_Map = (LV2_URID_Map*)features[lv2_feature_id_urid_map]->data;
  357. const LV2_URID uridPatchSet = getCustomURID(LV2_PATCH__Set);
  358. const LV2_URID uridPatchBody = getCustomURID(LV2_PATCH__body);
  359. Sratom* sratom = sratom_new(URID_Map);
  360. SerdChunk chunk = { nullptr, 0 };
  361. LV2_Atom_Forge forge;
  362. lv2_atom_forge_init(&forge, URID_Map);
  363. lv2_atom_forge_set_sink(&forge, sratom_forge_sink, sratom_forge_deref, &chunk);
  364. LV2_Atom_Forge_Frame refFrame, bodyFrame;
  365. LV2_Atom_Forge_Ref ref = lv2_atom_forge_blank(&forge, &refFrame, 1, uridPatchSet);
  366. lv2_atom_forge_property_head(&forge, uridPatchBody, CARLA_URI_MAP_ID_NULL);
  367. lv2_atom_forge_blank(&forge, &bodyFrame, 2, CARLA_URI_MAP_ID_NULL);
  368. //lv2_atom_forge_property_head(&forge, getCustomURID(key), CARLA_URI_MAP_ID_NULL);
  369. if (strcmp(type, "string") == 0)
  370. lv2_atom_forge_string(&forge, value, strlen(value));
  371. else if (strcmp(type, "path") == 0)
  372. lv2_atom_forge_path(&forge, value, strlen(value));
  373. else if (strcmp(type, "chunk") == 0)
  374. lv2_atom_forge_literal(&forge, value, strlen(value), CARLA_URI_MAP_ID_ATOM_CHUNK, CARLA_URI_MAP_ID_NULL);
  375. //else
  376. // lv2_atom_forge_literal(&forge, value, strlen(value), getCustomURID(key), CARLA_URI_MAP_ID_NULL);
  377. lv2_atom_forge_pop(&forge, &bodyFrame);
  378. lv2_atom_forge_pop(&forge, &refFrame);
  379. const LV2_Atom* const atom = lv2_atom_forge_deref(&forge, ref);
  380. descriptor->port_event(handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
  381. free((void*)chunk.buf);
  382. sratom_free(sratom);
  383. }
  384. #endif
  385. }
  386. void handleProgramChanged(int32_t /*index*/)
  387. {
  388. sendOscConfigure("reloadprograms", "");
  389. }
  390. uint32_t handleUiPortMap(const char* const symbol)
  391. {
  392. Q_ASSERT(symbol);
  393. for (uint32_t i=0; i < rdf_descriptor->PortCount; i++)
  394. {
  395. if (strcmp(rdf_descriptor->Ports[i].Symbol, symbol) == 0)
  396. return i;
  397. }
  398. return LV2UI_INVALID_PORT_INDEX;
  399. }
  400. int handleUiResize(int width, int height)
  401. {
  402. Q_ASSERT(width > 0);
  403. Q_ASSERT(height > 0);
  404. quequeMessage(MESSAGE_RESIZE_GUI, width, height, 0.0);
  405. return 0;
  406. }
  407. void handleUiWrite(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
  408. {
  409. if (format == 0)
  410. {
  411. Q_ASSERT(bufferSize == sizeof(float));
  412. if (bufferSize == sizeof(float))
  413. {
  414. float value = *(float*)buffer;
  415. sendOscControl(portIndex, value);
  416. }
  417. }
  418. else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM)
  419. {
  420. //const LV2_Atom* const atom = (const LV2_Atom*)buffer;
  421. QByteArray chunk((const char*)buffer, bufferSize);
  422. sendOscLv2TransferAtom(portIndex, chunk.toBase64().constData());
  423. //if (descriptor && descriptor->port_event)
  424. // descriptor->port_event(handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM, atom);
  425. }
  426. else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
  427. {
  428. //const LV2_Atom* const atom = (const LV2_Atom*)buffer;
  429. QByteArray chunk((const char*)buffer, bufferSize);
  430. sendOscLv2TransferEvent(portIndex, chunk.toBase64().constData());
  431. //if (descriptor && descriptor->port_event)
  432. // descriptor->port_event(handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
  433. }
  434. }
  435. // ----------------- Event Feature ---------------------------------------------------
  436. static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event)
  437. {
  438. qDebug("CarlaLv2Client::carla_lv2_event_ref(%p, %p)", callback_data, event);
  439. Q_ASSERT(callback_data);
  440. Q_ASSERT(event);
  441. return 0;
  442. }
  443. static uint32_t carla_lv2_event_unref(LV2_Event_Callback_Data callback_data, LV2_Event* event)
  444. {
  445. qDebug("CarlaLv2Client::carla_lv2_event_unref(%p, %p)", callback_data, event);
  446. Q_ASSERT(callback_data);
  447. Q_ASSERT(event);
  448. return 0;
  449. }
  450. // ----------------- Logs Feature ----------------------------------------------------
  451. static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
  452. {
  453. qDebug("CarlaLv2Client::carla_lv2_log_printf(%p, %i, %s, ...)", handle, type, fmt);
  454. Q_ASSERT(handle);
  455. Q_ASSERT(type > 0);
  456. #ifndef DEBUG
  457. if (type == CARLA_URI_MAP_ID_LOG_TRACE)
  458. return 0;
  459. #endif
  460. va_list args;
  461. va_start(args, fmt);
  462. const int ret = carla_lv2_log_vprintf(handle, type, fmt, args);
  463. va_end(args);
  464. return ret;
  465. }
  466. static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
  467. {
  468. qDebug("CarlaLv2Client::carla_lv2_log_vprintf(%p, %i, %s, ...)", handle, type, fmt);
  469. Q_ASSERT(handle);
  470. Q_ASSERT(type > 0);
  471. #ifndef DEBUG
  472. if (type == CARLA_URI_MAP_ID_LOG_TRACE)
  473. return 0;
  474. #endif
  475. char buf[8196];
  476. vsprintf(buf, fmt, ap);
  477. if (*buf == 0)
  478. return 0;
  479. switch (type)
  480. {
  481. case CARLA_URI_MAP_ID_LOG_ERROR:
  482. qCritical("%s", buf);
  483. break;
  484. case CARLA_URI_MAP_ID_LOG_NOTE:
  485. printf("%s\n", buf);
  486. break;
  487. case CARLA_URI_MAP_ID_LOG_TRACE:
  488. qDebug("%s", buf);
  489. break;
  490. case CARLA_URI_MAP_ID_LOG_WARNING:
  491. qWarning("%s", buf);
  492. break;
  493. default:
  494. break;
  495. }
  496. return strlen(buf);
  497. }
  498. // ----------------- Programs Feature ------------------------------------------------
  499. static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
  500. {
  501. qDebug("CarlaLv2Client::carla_lv2_program_changed(%p, %i)", handle, index);
  502. Q_ASSERT(handle);
  503. CarlaLv2Client* const client = (CarlaLv2Client*)handle;
  504. client->handleProgramChanged(index);
  505. }
  506. // ----------------- State Feature ---------------------------------------------------
  507. static char* carla_lv2_state_make_path(LV2_State_Make_Path_Handle handle, const char* path)
  508. {
  509. qDebug("CarlaLv2Client::carla_lv2_state_make_path(%p, %p)", handle, path);
  510. Q_ASSERT(handle);
  511. Q_ASSERT(path);
  512. QDir dir;
  513. dir.mkpath(path);
  514. return strdup(path);
  515. }
  516. static char* carla_lv2_state_map_abstract_path(LV2_State_Map_Path_Handle handle, const char* absolute_path)
  517. {
  518. qDebug("CarlaLv2Client::carla_lv2_state_map_abstract_path(%p, %p)", handle, absolute_path);
  519. Q_ASSERT(handle);
  520. Q_ASSERT(absolute_path);
  521. QDir dir(absolute_path);
  522. return strdup(dir.canonicalPath().toUtf8().constData());
  523. }
  524. static char* carla_lv2_state_map_absolute_path(LV2_State_Map_Path_Handle handle, const char* abstract_path)
  525. {
  526. qDebug("CarlaLv2Client::carla_lv2_state_map_absolute_path(%p, %p)", handle, abstract_path);
  527. Q_ASSERT(handle);
  528. Q_ASSERT(abstract_path);
  529. QDir dir(abstract_path);
  530. return strdup(dir.absolutePath().toUtf8().constData());
  531. }
  532. // ----------------- URI-Map Feature ---------------------------------------
  533. static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
  534. {
  535. qDebug("CarlaLv2Client::carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri);
  536. return carla_lv2_urid_map(data, uri);
  537. }
  538. // ----------------- URID Feature ------------------------------------------
  539. static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri)
  540. {
  541. qDebug("CarlaLv2Client::carla_lv2_urid_map(%p, %s)", handle, uri);
  542. Q_ASSERT(handle);
  543. Q_ASSERT(uri);
  544. // Atom types
  545. if (strcmp(uri, LV2_ATOM__Chunk) == 0)
  546. return CARLA_URI_MAP_ID_ATOM_CHUNK;
  547. if (strcmp(uri, LV2_ATOM__Path) == 0)
  548. return CARLA_URI_MAP_ID_ATOM_PATH;
  549. if (strcmp(uri, LV2_ATOM__Sequence) == 0)
  550. return CARLA_URI_MAP_ID_ATOM_SEQUENCE;
  551. if (strcmp(uri, LV2_ATOM__String) == 0)
  552. return CARLA_URI_MAP_ID_ATOM_STRING;
  553. if (strcmp(uri, LV2_ATOM__atomTransfer) == 0)
  554. return CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM;
  555. if (strcmp(uri, LV2_ATOM__eventTransfer) == 0)
  556. return CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT;
  557. // Log types
  558. if (strcmp(uri, LV2_LOG__Error) == 0)
  559. return CARLA_URI_MAP_ID_LOG_ERROR;
  560. if (strcmp(uri, LV2_LOG__Note) == 0)
  561. return CARLA_URI_MAP_ID_LOG_NOTE;
  562. if (strcmp(uri, LV2_LOG__Trace) == 0)
  563. return CARLA_URI_MAP_ID_LOG_TRACE;
  564. if (strcmp(uri, LV2_LOG__Warning) == 0)
  565. return CARLA_URI_MAP_ID_LOG_WARNING;
  566. // Others
  567. if (strcmp(uri, LV2_MIDI__MidiEvent) == 0)
  568. return CARLA_URI_MAP_ID_MIDI_EVENT;
  569. // Custom types
  570. CarlaLv2Client* const client = (CarlaLv2Client*)handle;
  571. return client->getCustomURID(uri);
  572. }
  573. static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
  574. {
  575. qDebug("CarlaLv2Client::carla_lv2_urid_unmap(%p, %i)", handle, urid);
  576. Q_ASSERT(handle);
  577. Q_ASSERT(urid > 0);
  578. // Atom types
  579. if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK)
  580. return LV2_ATOM__Chunk;
  581. if (urid == CARLA_URI_MAP_ID_ATOM_PATH)
  582. return LV2_ATOM__Path;
  583. if (urid == CARLA_URI_MAP_ID_ATOM_SEQUENCE)
  584. return LV2_ATOM__Sequence;
  585. if (urid == CARLA_URI_MAP_ID_ATOM_STRING)
  586. return LV2_ATOM__String;
  587. if (urid == CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM)
  588. return LV2_ATOM__atomTransfer;
  589. if (urid == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
  590. return LV2_ATOM__eventTransfer;
  591. // Log types
  592. if (urid == CARLA_URI_MAP_ID_LOG_ERROR)
  593. return LV2_LOG__Error;
  594. if (urid == CARLA_URI_MAP_ID_LOG_NOTE)
  595. return LV2_LOG__Note;
  596. if (urid == CARLA_URI_MAP_ID_LOG_TRACE)
  597. return LV2_LOG__Trace;
  598. if (urid == CARLA_URI_MAP_ID_LOG_WARNING)
  599. return LV2_LOG__Warning;
  600. // Others
  601. if (urid == CARLA_URI_MAP_ID_MIDI_EVENT)
  602. return LV2_MIDI__MidiEvent;
  603. // Custom types
  604. CarlaLv2Client* const client = (CarlaLv2Client*)handle;
  605. return client->getCustomURIString(urid);
  606. }
  607. // ----------------- UI Port-Map Feature ---------------------------------------------
  608. static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
  609. {
  610. qDebug("CarlaLv2Client::carla_lv2_ui_port_map(%p, %s)", handle, symbol);
  611. Q_ASSERT(handle);
  612. CarlaLv2Client* const client = (CarlaLv2Client*)handle;
  613. return client->handleUiPortMap(symbol);
  614. }
  615. // ----------------- UI Resize Feature -------------------------------------
  616. static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
  617. {
  618. qDebug("CarlaLv2Client::carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);
  619. Q_ASSERT(handle);
  620. CarlaLv2Client* const client = (CarlaLv2Client*)handle;
  621. return client->handleUiResize(width, height);
  622. }
  623. // ----------------- UI Extension ------------------------------------------
  624. static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
  625. {
  626. qDebug("CarlaLv2Client::carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer);
  627. Q_ASSERT(controller);
  628. CarlaLv2Client* const client = (CarlaLv2Client*)controller;
  629. client->handleUiWrite(port_index, buffer_size, format, buffer);
  630. }
  631. private:
  632. LV2UI_Handle handle;
  633. LV2UI_Widget widget;
  634. const LV2UI_Descriptor* descriptor;
  635. LV2_Feature* features[lv2_feature_count+1];
  636. const LV2_RDF_Descriptor* rdf_descriptor;
  637. const LV2_RDF_UI* rdf_ui_descriptor;
  638. const LV2_Programs_UI_Interface* programs;
  639. #ifdef BRIDGE_LV2_X11
  640. QDialog* x11_widget;
  641. #endif
  642. bool m_resizable;
  643. std::vector<const char*> customURIDs;
  644. };
  645. int CarlaBridgeOsc::handleMsgLv2TransferAtom(CARLA_BRIDGE_OSC_HANDLE_ARGS)
  646. {
  647. qDebug("CarlaBridgeOsc::handleMsgLv2TransferAtom()");
  648. CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "is");
  649. if (! client)
  650. return 1;
  651. const int32_t portIndex = argv[0]->i;
  652. const char* const atomBuf = (const char*)&argv[1]->s;
  653. CarlaLv2Client* const lv2client = (CarlaLv2Client*)client;
  654. lv2client->handleTransferAtom(portIndex, atomBuf);
  655. return 0;
  656. }
  657. int CarlaBridgeOsc::handleMsgLv2TransferEvent(CARLA_BRIDGE_OSC_HANDLE_ARGS)
  658. {
  659. qDebug("CarlaBridgeOsc::handleMsgLv2TransferEvent()");
  660. CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "is");
  661. if (! client)
  662. return 1;
  663. const int32_t portIndex = argv[0]->i;
  664. const char* const atomBuf = (const char*)&argv[1]->s;
  665. CarlaLv2Client* const lv2client = (CarlaLv2Client*)client;
  666. lv2client->handleTransferEvent(portIndex, atomBuf);
  667. return 0;
  668. }
  669. CARLA_BRIDGE_END_NAMESPACE
  670. int main(int argc, char* argv[])
  671. {
  672. using namespace CarlaBridge;
  673. if (argc != 5)
  674. {
  675. qWarning("usage: %s <osc-url|\"null\"> <plugin-uri> <ui-uri> <ui-title>", argv[0]);
  676. return 1;
  677. }
  678. const char* oscUrl = argv[1];
  679. const char* pluginURI = argv[2];
  680. const char* uiURI = argv[3];
  681. const char* uiTitle = argv[4];
  682. const bool useOsc = strcmp(oscUrl, "null");
  683. // try to get sampleRate value
  684. const char* const sampleRateStr = getenv("CARLA_SAMPLE_RATE");
  685. if (sampleRateStr)
  686. sampleRate = atof(sampleRateStr);
  687. // Init toolkit
  688. CarlaToolkit* const toolkit = CarlaToolkit::createNew(uiTitle);
  689. toolkit->init();
  690. // Init LV2-UI
  691. CarlaLv2Client client(toolkit);
  692. // Init OSC
  693. if (useOsc && ! client.oscInit(oscUrl))
  694. {
  695. toolkit->quit();
  696. delete toolkit;
  697. return -1;
  698. }
  699. // Load UI
  700. int ret;
  701. if (client.init(pluginURI, uiURI))
  702. {
  703. toolkit->exec(&client, !useOsc);
  704. ret = 0;
  705. }
  706. else
  707. {
  708. qCritical("Failed to load LV2 UI");
  709. ret = 1;
  710. }
  711. // Close OSC
  712. if (useOsc)
  713. {
  714. client.sendOscExiting();
  715. client.oscClose();
  716. }
  717. // Close LV2-UI
  718. client.close();
  719. // Close toolkit
  720. toolkit->quit();
  721. delete toolkit;
  722. return ret;
  723. }
  724. #endif