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.

Connection.cpp 14KB

9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. #include "Connection.h"
  2. #include "Fl_Osc_Interface.h"
  3. #include "../globals.h"
  4. #include <map>
  5. #include <cassert>
  6. #include <rtosc/rtosc.h>
  7. #include <rtosc/ports.h>
  8. #include <FL/Fl.H>
  9. #include "Fl_Osc_Tree.H"
  10. #include "common.H"
  11. #include "MasterUI.h"
  12. #include "../Misc/MiddleWare.h"
  13. #ifdef NTK_GUI
  14. #include <FL/Fl_Shared_Image.H>
  15. #include <FL/Fl_Tiled_Image.H>
  16. #include <FL/Fl_Dial.H>
  17. #include <err.h>
  18. #endif // NTK_GUI
  19. #ifndef NO_UI
  20. #include "Fl_Osc_Widget.H"
  21. #endif
  22. using namespace GUI;
  23. class MasterUI *ui;
  24. #ifdef NTK_GUI
  25. static Fl_Tiled_Image *module_backdrop;
  26. #endif
  27. int undo_redo_handler(int)
  28. {
  29. const bool undo_ = Fl::event_ctrl() && Fl::event_key() == 'z';
  30. const bool redo = Fl::event_ctrl() && Fl::event_key() == 'r';
  31. if(undo_)
  32. ui->osc->write("/undo", "");
  33. else if(redo)
  34. ui->osc->write("/redo", "");
  35. return undo_ || redo;
  36. }
  37. void
  38. set_module_parameters ( Fl_Widget *o )
  39. {
  40. #ifdef NTK_GUI
  41. o->box( FL_DOWN_FRAME );
  42. o->align( o->align() | FL_ALIGN_IMAGE_BACKDROP );
  43. o->color( FL_BLACK );
  44. o->image( module_backdrop );
  45. o->labeltype( FL_SHADOW_LABEL );
  46. if(o->parent()) {
  47. o->parent()->labeltype(FL_NO_LABEL);
  48. o->parent()->box(FL_NO_BOX);
  49. }
  50. #else
  51. o->box( FL_PLASTIC_UP_BOX );
  52. o->color( FL_CYAN );
  53. o->labeltype( FL_EMBOSSED_LABEL );
  54. #endif
  55. }
  56. ui_handle_t GUI::createUi(Fl_Osc_Interface *osc, void *exit)
  57. {
  58. #ifdef NTK_GUI
  59. fl_register_images();
  60. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  61. #ifdef CARLA_VERSION_STRING
  62. if(Fl_Shared_Image *img = Fl_Shared_Image::get(gUiPixmapPath + "knob.png"))
  63. Fl_Dial::default_image(img);
  64. #else
  65. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/knob.png"))
  66. Fl_Dial::default_image(img);
  67. #endif
  68. else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/knob.png"))
  69. Fl_Dial::default_image(img);
  70. else
  71. errx(1, "ERROR: Cannot find pixmaps/knob.png");
  72. #ifdef CARLA_VERSION_STRING
  73. if(Fl_Shared_Image *img = Fl_Shared_Image::get(gUiPixmapPath + "/window_backdrop.png"))
  74. Fl::scheme_bg(new Fl_Tiled_Image(img));
  75. #else
  76. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/window_backdrop.png"))
  77. Fl::scheme_bg(new Fl_Tiled_Image(img));
  78. #endif
  79. else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/window_backdrop.png"))
  80. Fl::scheme_bg(new Fl_Tiled_Image(img));
  81. else
  82. errx(1, "ERROR: Cannot find pixmaps/window_backdrop.png");
  83. #ifdef CARLA_VERSION_STRING
  84. if(Fl_Shared_Image *img = Fl_Shared_Image::get(gUiPixmapPath + "/module_backdrop.png"))
  85. module_backdrop = new Fl_Tiled_Image(img);
  86. #else
  87. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/module_backdrop.png"))
  88. module_backdrop = new Fl_Tiled_Image(img);
  89. #endif
  90. else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/module_backdrop.png"))
  91. module_backdrop = new Fl_Tiled_Image(img);
  92. else
  93. errx(1, "ERROR: Cannot find pixmaps/module_backdrop");
  94. Fl::background(50, 50, 50);
  95. Fl::background2(70, 70, 70);
  96. Fl::foreground(255, 255, 255);
  97. #endif
  98. //Fl_Window *midi_win = new Fl_Double_Window(400, 400, "Midi connections");
  99. //Fl_Osc_Tree *tree = new Fl_Osc_Tree(0,0,400,400);
  100. //midi_win->resizable(tree);
  101. //tree->root_ports = &Master::ports;
  102. //tree->osc = osc;
  103. //midi_win->show();
  104. Fl::add_handler(undo_redo_handler);
  105. return (void*) (ui = new MasterUI((int*)exit, osc));
  106. }
  107. void GUI::destroyUi(ui_handle_t ui)
  108. {
  109. delete static_cast<MasterUI*>(ui);
  110. }
  111. #define BEGIN(x) {x,":non-realtime\0",NULL,[](const char *m, rtosc::RtData d){ \
  112. MasterUI *ui = static_cast<MasterUI*>(d.obj); \
  113. rtosc_arg_t a0 = {0}, a1 = {0}; \
  114. if(rtosc_narguments(m) > 0) \
  115. a0 = rtosc_argument(m,0); \
  116. if(rtosc_narguments(m) > 1) \
  117. a1 = rtosc_argument(m,1); \
  118. (void)ui;(void)a1;(void)a0;
  119. #define END }},
  120. struct uiPorts {
  121. static rtosc::Ports ports;
  122. };
  123. //DSL based ports
  124. rtosc::Ports uiPorts::ports = {
  125. BEGIN("show:i") {
  126. ui->showUI(a0.i);
  127. } END
  128. BEGIN("alert:s") {
  129. fl_alert("%s",a0.s);
  130. } END
  131. BEGIN("session-type:s") {
  132. if(strcmp(a0.s,"LASH"))
  133. return;
  134. ui->sm_indicator1->value(1);
  135. ui->sm_indicator2->value(1);
  136. ui->sm_indicator1->tooltip("LASH");
  137. ui->sm_indicator2->tooltip("LASH");
  138. } END
  139. BEGIN("save-master:s") {
  140. ui->do_save_master(a0.s);
  141. } END
  142. BEGIN("load-master:s") {
  143. ui->do_load_master(a0.s);
  144. } END
  145. BEGIN("vu-meter:bb") {
  146. if(a0.b.len == sizeof(vuData) &&
  147. a1.b.len == sizeof(float)*NUM_MIDI_PARTS) {
  148. //Refresh the primary VU meters
  149. ui->simplemastervu->update((vuData*)a0.b.data);
  150. ui->mastervu->update((vuData*)a0.b.data);
  151. float *partvu = (float*)a1.b.data;
  152. for(int i=0; i<NUM_MIDI_PARTS; ++i)
  153. ui->panellistitem[i]->partvu->update(partvu[i]);
  154. }
  155. } END
  156. BEGIN("close-ui") {
  157. ui->close();
  158. } END
  159. };
  160. void GUI::raiseUi(ui_handle_t gui, const char *message)
  161. {
  162. if(!gui)
  163. return;
  164. MasterUI *mui = (MasterUI*)gui;
  165. if(string("/damage") == message && rtosc_type(message, 0) == 's') {
  166. string damage_str = rtosc_argument(message,0).s;
  167. int npart = -1;
  168. if(sscanf(damage_str.c_str(), "/part%d", &npart) == 1 && damage_str.size() < 10) {
  169. if(mui->npartcounter->value()-1 == npart) {
  170. mui->partui->showparameters(0,-1);
  171. mui->npartcounter->do_callback();
  172. }
  173. }
  174. mui->osc->damage(rtosc_argument(message,0).s);
  175. }
  176. mui->osc->tryLink(message);
  177. //printf("got message for UI '%s'\n", message);
  178. char buffer[1024];
  179. memset(buffer, 0, sizeof(buffer));
  180. rtosc::RtData d;
  181. d.loc = buffer;
  182. d.loc_size = 1024;
  183. d.obj = gui;
  184. uiPorts::ports.dispatch(message+1, d);
  185. }
  186. void GUI::raiseUi(ui_handle_t gui, const char *dest, const char *args, ...)
  187. {
  188. char buffer[1024];
  189. va_list va;
  190. va_start(va,args);
  191. if(rtosc_vmessage(buffer,1024,dest,args,va))
  192. raiseUi(gui, buffer);
  193. va_end(va);
  194. }
  195. void GUI::tickUi(ui_handle_t)
  196. {
  197. Fl::wait(0.02f);
  198. }
  199. /******************************************************************************
  200. * OSC Interface For User Interface *
  201. * *
  202. * This is a largely out of date section of code *
  203. * Most type specific write methods are no longer used *
  204. * See UI/Fl_Osc_* to see what is actually used in this interface *
  205. ******************************************************************************/
  206. class UI_Interface:public Fl_Osc_Interface
  207. {
  208. public:
  209. UI_Interface(MiddleWare *impl_)
  210. :impl(impl_)
  211. {}
  212. void requestValue(string s) override
  213. {
  214. assert(s!="/Psysefxvol-1/part0");
  215. //Fl_Osc_Interface::requestValue(s);
  216. if(impl->activeUrl() != "GUI") {
  217. impl->transmitMsg("/echo", "ss", "OSC_URL", "GUI");
  218. impl->activeUrl("GUI");
  219. }
  220. impl->transmitMsg(s.c_str(),"");
  221. }
  222. void write(string s, const char *args, ...) override
  223. {
  224. va_list va;
  225. va_start(va, args);
  226. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
  227. ////fprintf(stderr, ".");
  228. //fprintf(stderr, "write(%s:%s)\n", s.c_str(), args);
  229. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  230. impl->transmitMsg(s.c_str(), args, va);
  231. va_end(va);
  232. }
  233. void writeRaw(const char *msg) override
  234. {
  235. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
  236. ////fprintf(stderr, ".");
  237. //fprintf(stderr, "rawWrite(%s:%s)\n", msg, rtosc_argument_string(msg));
  238. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  239. impl->transmitMsg(msg);
  240. }
  241. void writeValue(string s, string ss) override
  242. {
  243. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
  244. //fprintf(stderr, "writevalue<string>(%s,%s)\n", s.c_str(),ss.c_str());
  245. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  246. impl->transmitMsg(s.c_str(), "s", ss.c_str());
  247. }
  248. void writeValue(string s, char c) override
  249. {
  250. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
  251. //fprintf(stderr, "writevalue<char>(%s,%d)\n", s.c_str(),c);
  252. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  253. impl->transmitMsg(s.c_str(), "c", c);
  254. }
  255. void writeValue(string s, float f) override
  256. {
  257. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
  258. //fprintf(stderr, "writevalue<float>(%s,%f)\n", s.c_str(),f);
  259. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  260. impl->transmitMsg(s.c_str(), "f", f);
  261. }
  262. void createLink(string s, class Fl_Osc_Widget*w) override
  263. {
  264. assert(s.length() != 0);
  265. Fl_Osc_Interface::createLink(s,w);
  266. assert(!strstr(s.c_str(), "/part0/kit-1"));
  267. map.insert(std::pair<string,Fl_Osc_Widget*>(s,w));
  268. }
  269. void renameLink(string old, string newer, Fl_Osc_Widget *w) override
  270. {
  271. //fprintf(stdout, "renameLink('%s','%s',%p)\n",
  272. // old.c_str(), newer.c_str(), w);
  273. removeLink(old, w);
  274. createLink(newer, w);
  275. }
  276. void removeLink(string s, class Fl_Osc_Widget*w) override
  277. {
  278. for(auto i = map.begin(); i != map.end(); ++i) {
  279. if(i->first == s && i->second == w) {
  280. map.erase(i);
  281. break;
  282. }
  283. }
  284. //printf("[%d] removing '%s' (%p)...\n", map.size(), s.c_str(), w);
  285. }
  286. virtual void removeLink(class Fl_Osc_Widget *w) override
  287. {
  288. bool processing = true;
  289. while(processing)
  290. {
  291. //Verify Iterator invalidation sillyness
  292. processing = false;//Exit if no new elements are found
  293. for(auto i = map.begin(); i != map.end(); ++i) {
  294. if(i->second == w) {
  295. //printf("[%d] removing '%s' (%p)...\n", map.size()-1,
  296. // i->first.c_str(), w);
  297. map.erase(i);
  298. processing = true;
  299. break;
  300. }
  301. }
  302. }
  303. }
  304. //A very simplistic implementation of a UI agnostic refresh method
  305. virtual void damage(const char *path) override
  306. {
  307. #ifndef NO_UI
  308. printf("\n\nDamage(\"%s\")\n", path);
  309. for(auto pair:map) {
  310. if(strstr(pair.first.c_str(), path)) {
  311. auto *tmp = dynamic_cast<Fl_Widget*>(pair.second);
  312. if(!tmp || tmp->visible_r()) {
  313. pair.second->update();
  314. }
  315. }
  316. }
  317. #endif
  318. }
  319. void tryLink(const char *msg) override
  320. {
  321. //DEBUG
  322. //if(strcmp(msg, "/vu-meter"))//Ignore repeated message
  323. // printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg));
  324. const char *handle = rindex(msg,'/');
  325. if(handle)
  326. ++handle;
  327. int found_count = 0;
  328. auto range = map.equal_range(msg);
  329. for(auto itr = range.first; itr != range.second; ++itr) {
  330. auto widget = itr->second;
  331. found_count++;
  332. const char *arg_str = rtosc_argument_string(msg);
  333. //Always provide the raw message
  334. widget->OSC_raw(msg);
  335. if(!strcmp(arg_str, "b")) {
  336. widget->OSC_value(rtosc_argument(msg,0).b.len,
  337. rtosc_argument(msg,0).b.data,
  338. handle);
  339. } else if(!strcmp(arg_str, "c")) {
  340. widget->OSC_value((char)rtosc_argument(msg,0).i,
  341. handle);
  342. } else if(!strcmp(arg_str, "s")) {
  343. widget->OSC_value((const char*)rtosc_argument(msg,0).s,
  344. handle);
  345. } else if(!strcmp(arg_str, "i")) {
  346. widget->OSC_value((int)rtosc_argument(msg,0).i,
  347. handle);
  348. } else if(!strcmp(arg_str, "f")) {
  349. widget->OSC_value((float)rtosc_argument(msg,0).f,
  350. handle);
  351. } else if(!strcmp(arg_str, "T") || !strcmp(arg_str, "F")) {
  352. widget->OSC_value((bool)rtosc_argument(msg,0).T, handle);
  353. }
  354. }
  355. if(found_count == 0
  356. && strcmp(msg, "/vu-meter")
  357. && strcmp(msg, "undo_change")
  358. && !strstr(msg, "parameter")
  359. && !strstr(msg, "Prespoint")) {
  360. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  361. //fprintf(stderr, "Unknown widget '%s'\n", msg);
  362. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  363. }
  364. };
  365. void dumpLookupTable(void)
  366. {
  367. if(!map.empty()) {
  368. printf("Leaked controls:\n");
  369. for(auto i = map.begin(); i != map.end(); ++i) {
  370. printf("Known control '%s' (%p)...\n", i->first.c_str(), i->second);
  371. }
  372. }
  373. }
  374. private:
  375. std::multimap<string,Fl_Osc_Widget*> map;
  376. MiddleWare *impl;
  377. };
  378. Fl_Osc_Interface *GUI::genOscInterface(MiddleWare *mw)
  379. {
  380. return new UI_Interface(mw);
  381. }