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.

1335 lines
44KB

  1. #include "MiddleWare.h"
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <fstream>
  6. #include <rtosc/undo-history.h>
  7. #include <rtosc/thread-link.h>
  8. #include <rtosc/ports.h>
  9. #include <lo/lo.h>
  10. #include <unistd.h>
  11. #include <dirent.h>
  12. #include "../UI/Connection.h"
  13. #include "../UI/Fl_Osc_Interface.h"
  14. #include <map>
  15. #include "Util.h"
  16. #include "Master.h"
  17. #include "Part.h"
  18. #include "PresetExtractor.h"
  19. #include "../Params/PresetsStore.h"
  20. #include "../Params/ADnoteParameters.h"
  21. #include "../Params/SUBnoteParameters.h"
  22. #include "../Params/PADnoteParameters.h"
  23. #include "../DSP/FFTwrapper.h"
  24. #include "../Synth/OscilGen.h"
  25. #include <string>
  26. #include <future>
  27. #include <atomic>
  28. #include <list>
  29. #include <err.h>
  30. using std::string;
  31. extern rtosc::ThreadLink *the_bToU;//XXX
  32. /******************************************************************************
  33. * LIBLO And Reflection Code *
  34. * *
  35. * All messages that are handled are handled in a serial fashion. *
  36. * Thus, changes in the current interface sending messages can be encoded *
  37. * into the stream via events which simply echo back the active interface *
  38. ******************************************************************************/
  39. static void liblo_error_cb(int i, const char *m, const char *loc)
  40. {
  41. fprintf(stderr, "liblo :-( %d-%s@%s\n",i,m,loc);
  42. }
  43. void path_search(const char *m, const char *url)
  44. {
  45. using rtosc::Ports;
  46. using rtosc::Port;
  47. //assumed upper bound of 32 ports (may need to be resized)
  48. char types[129];
  49. rtosc_arg_t args[128];
  50. size_t pos = 0;
  51. const Ports *ports = NULL;
  52. const char *str = rtosc_argument(m,0).s;
  53. const char *needle = rtosc_argument(m,1).s;
  54. //zero out data
  55. memset(types, 0, sizeof(types));
  56. memset(args, 0, sizeof(args));
  57. if(!*str) {
  58. ports = &Master::ports;
  59. } else {
  60. const Port *port = Master::ports.apropos(rtosc_argument(m,0).s);
  61. if(port)
  62. ports = port->ports;
  63. }
  64. if(ports) {
  65. //RTness not confirmed here
  66. for(const Port &p:*ports) {
  67. if(strstr(p.name, needle)!=p.name)
  68. continue;
  69. types[pos] = 's';
  70. args[pos++].s = p.name;
  71. types[pos] = 'b';
  72. if(p.metadata && *p.metadata) {
  73. args[pos].b.data = (unsigned char*) p.metadata;
  74. auto tmp = rtosc::Port::MetaContainer(p.metadata);
  75. args[pos++].b.len = tmp.length();
  76. } else {
  77. args[pos].b.data = (unsigned char*) NULL;
  78. args[pos++].b.len = 0;
  79. }
  80. }
  81. }
  82. //Reply to requester [wow, these messages are getting huge...]
  83. char buffer[1024*20];
  84. size_t length = rtosc_amessage(buffer, sizeof(buffer), "/paths", types, args);
  85. if(length) {
  86. lo_message msg = lo_message_deserialise((void*)buffer, length, NULL);
  87. lo_address addr = lo_address_new_from_url(url);
  88. if(addr)
  89. lo_send_message(addr, buffer, msg);
  90. }
  91. }
  92. static int handler_function(const char *path, const char *types, lo_arg **argv,
  93. int argc, lo_message msg, void *user_data)
  94. {
  95. (void) types;
  96. (void) argv;
  97. (void) argc;
  98. MiddleWare *mw = (MiddleWare*)user_data;
  99. lo_address addr = lo_message_get_source(msg);
  100. if(addr) {
  101. const char *tmp = lo_address_get_url(addr);
  102. if(tmp != mw->activeUrl()) {
  103. mw->transmitMsg("/echo", "ss", "OSC_URL", tmp);
  104. mw->activeUrl(tmp);
  105. }
  106. }
  107. char buffer[2048];
  108. memset(buffer, 0, sizeof(buffer));
  109. size_t size = 2048;
  110. lo_message_serialise(msg, path, buffer, &size);
  111. if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) {
  112. path_search(buffer, mw->activeUrl().c_str());
  113. } else if(buffer[0]=='/' && rindex(buffer, '/')[1])
  114. mw->transmitMsg(buffer);
  115. return 0;
  116. }
  117. typedef void(*cb_t)(void*,const char*);
  118. /*****************************************************************************
  119. * Memory Deallocation *
  120. *****************************************************************************/
  121. void deallocate(const char *str, void *v)
  122. {
  123. //printf("deallocating a '%s' at '%p'\n", str, v);
  124. if(!strcmp(str, "Part"))
  125. delete (Part*)v;
  126. else if(!strcmp(str, "Master"))
  127. delete (Master*)v;
  128. else if(!strcmp(str, "fft_t"))
  129. delete[] (fft_t*)v;
  130. else
  131. fprintf(stderr, "Unknown type '%s', leaking pointer %p!!\n", str, v);
  132. }
  133. /*****************************************************************************
  134. * PadSynth Setup *
  135. *****************************************************************************/
  136. void preparePadSynth(string path, PADnoteParameters *p, rtosc::ThreadLink *uToB)
  137. {
  138. //printf("preparing padsynth parameters\n");
  139. assert(!path.empty());
  140. path += "sample";
  141. unsigned max = 0;
  142. p->sampleGenerator([&max,&path,uToB]
  143. (unsigned N, PADnoteParameters::Sample &s)
  144. {
  145. max = max<N ? N : max;
  146. //printf("sending info to '%s'\n", (path+to_s(N)).c_str());
  147. uToB->write((path+to_s(N)).c_str(), "ifb",
  148. s.size, s.basefreq, sizeof(float*), &s.smp);
  149. }, []{return false;});
  150. //clear out unused samples
  151. for(unsigned i = max+1; i < PAD_MAX_SAMPLES; ++i) {
  152. uToB->write((path+to_s(i)).c_str(), "ifb",
  153. 0, 440.0f, sizeof(float*), NULL);
  154. }
  155. }
  156. /*****************************************************************************
  157. * Instrument Banks *
  158. * *
  159. * Banks and presets in general are not classed as realtime safe *
  160. * *
  161. * The supported operations are: *
  162. * - Load Names *
  163. * - Load Bank *
  164. * - Refresh List of Banks *
  165. *****************************************************************************/
  166. void refreshBankView(const Bank &bank, unsigned loc, Fl_Osc_Interface *osc)
  167. {
  168. if(loc >= BANK_SIZE)
  169. return;
  170. char response[2048];
  171. if(!rtosc_message(response, 1024, "/bankview", "iss",
  172. loc, bank.ins[loc].name.c_str(),
  173. bank.ins[loc].filename.c_str()))
  174. errx(1, "Failure to handle bank update properly...");
  175. if (osc)
  176. osc->tryLink(response);
  177. }
  178. void bankList(Bank &bank, Fl_Osc_Interface *osc)
  179. {
  180. if (! osc)
  181. return;
  182. char response[2048];
  183. int i = 0;
  184. for(auto &elm : bank.banks) {
  185. if(!rtosc_message(response, 2048, "/bank-list", "iss",
  186. i++, elm.name.c_str(), elm.dir.c_str()))
  187. errx(1, "Failure to handle bank update properly...");
  188. if (osc)
  189. osc->tryLink(response);
  190. }
  191. }
  192. void rescanForBanks(Bank &bank, Fl_Osc_Interface *osc)
  193. {
  194. bank.rescanforbanks();
  195. bankList(bank, osc);
  196. }
  197. void loadBank(Bank &bank, int pos, Fl_Osc_Interface *osc)
  198. {
  199. if(bank.bankpos != pos) {
  200. bank.bankpos = pos;
  201. bank.loadbank(bank.banks[pos].dir);
  202. for(int i=0; i<BANK_SIZE; ++i)
  203. refreshBankView(bank, i, osc);
  204. }
  205. }
  206. void bankPos(Bank &bank, Fl_Osc_Interface *osc)
  207. {
  208. char response[2048];
  209. if(!rtosc_message(response, 2048, "/loadbank", "i", bank.bankpos))
  210. errx(1, "Failure to handle bank update properly...");
  211. if (osc)
  212. osc->tryLink(response);
  213. }
  214. /*****************************************************************************
  215. * Data Object for Non-RT Class Dispatch *
  216. *****************************************************************************/
  217. class DummyDataObj:public rtosc::RtData
  218. {
  219. public:
  220. DummyDataObj(char *loc_, size_t loc_size_, void *obj_, MiddleWareImpl *mwi_,
  221. rtosc::ThreadLink *uToB_)
  222. {
  223. memset(loc_, 0, sizeof(loc_size_));
  224. buffer = new char[4*4096];
  225. memset(buffer, 0, 4*4096);
  226. loc = loc_;
  227. loc_size = loc_size_;
  228. obj = obj_;
  229. mwi = mwi_;
  230. uToB = uToB_;
  231. }
  232. ~DummyDataObj(void)
  233. {
  234. delete[] buffer;
  235. }
  236. virtual void reply(const char *path, const char *args, ...)
  237. {
  238. //printf("reply building '%s'\n", path);
  239. va_list va;
  240. va_start(va,args);
  241. if(!strcmp(path, "/forward")) { //forward the information to the backend
  242. args++;
  243. path = va_arg(va, const char *);
  244. //fprintf(stderr, "forwarding information to the backend on '%s'<%s>\n",
  245. // path, args);
  246. rtosc_vmessage(buffer,4*4096,path,args,va);
  247. uToB->raw_write(buffer);
  248. } else {
  249. //printf("path = '%s' args = '%s'\n", path, args);
  250. //printf("buffer = '%p'\n", buffer);
  251. rtosc_vmessage(buffer,4*4096,path,args,va);
  252. //printf("buffer = '%s'\n", buffer);
  253. reply(buffer);
  254. }
  255. va_end(va);
  256. }
  257. virtual void reply(const char *msg);
  258. //virtual void broadcast(const char *path, const char *args, ...){(void)path;(void)args;};
  259. //virtual void broadcast(const char *msg){(void)msg;};
  260. private:
  261. char *buffer;
  262. MiddleWareImpl *mwi;
  263. rtosc::ThreadLink *uToB;
  264. };
  265. /******************************************************************************
  266. * Non-RealTime Object Store *
  267. * *
  268. * *
  269. * Storage For Objects which need to be interfaced with outside the realtime *
  270. * thread (aka they have long lived operations which can be done out-of-band) *
  271. * *
  272. * - OscilGen instances as prepare() cannot be done in realtime and PAD *
  273. * depends on these instances *
  274. * - PADnoteParameter instances as applyparameters() cannot be done in *
  275. * realtime *
  276. * *
  277. * These instances are collected on every part change and kit change *
  278. ******************************************************************************/
  279. struct NonRtObjStore
  280. {
  281. std::map<std::string, void*> objmap;
  282. void extractMaster(Master *master)
  283. {
  284. for(int i=0; i < NUM_MIDI_PARTS; ++i) {
  285. extractPart(master->part[i], i);
  286. }
  287. }
  288. void extractPart(Part *part, int i)
  289. {
  290. for(int j=0; j < NUM_KIT_ITEMS; ++j) {
  291. auto &obj = part->kit[j];
  292. extractAD(obj.adpars, i, j);
  293. extractPAD(obj.padpars, i, j);
  294. }
  295. }
  296. void extractAD(ADnoteParameters *adpars, int i, int j)
  297. {
  298. std::string base = "/part"+to_s(i)+"/kit"+to_s(j)+"/";
  299. for(int k=0; k<NUM_VOICES; ++k) {
  300. std::string nbase = base+"adpars/voice"+to_s(k)+"/";
  301. if(adpars) {
  302. auto &nobj = adpars->VoicePar[k];
  303. objmap[nbase+"oscil/"] = nobj.OscilSmp;
  304. objmap[nbase+"mod-oscil/"] = nobj.FMSmp;
  305. } else {
  306. objmap[nbase+"oscil/"] = nullptr;
  307. objmap[nbase+"mod-oscil/"] = nullptr;
  308. }
  309. }
  310. }
  311. void extractPAD(PADnoteParameters *padpars, int i, int j)
  312. {
  313. std::string base = "/part"+to_s(i)+"/kit"+to_s(j)+"/";
  314. for(int k=0; k<NUM_VOICES; ++k) {
  315. if(padpars) {
  316. objmap[base+"padpars/"] = padpars;
  317. objmap[base+"padpars/oscil/"] = padpars->oscilgen;
  318. } else {
  319. objmap[base+"padpars/"] = nullptr;
  320. objmap[base+"padpars/oscil/"] = nullptr;
  321. }
  322. }
  323. }
  324. void clear(void)
  325. {
  326. objmap.clear();
  327. }
  328. bool has(std::string loc)
  329. {
  330. return objmap.find(loc) != objmap.end();
  331. }
  332. void *get(std::string loc)
  333. {
  334. return objmap[loc];
  335. }
  336. };
  337. /******************************************************************************
  338. * Realtime Parameter Store *
  339. * *
  340. * Storage for AD/PAD/SUB parameters which are allocated as needed by kits. *
  341. * Two classes of events affect this: *
  342. * 1. When a message to enable a kit is observed, then the kit is allocated *
  343. * and sent prior to the enable message. *
  344. * 2. When a part is allocated all part information is rebuilt *
  345. * *
  346. * (NOTE pointers aren't really needed here, just booleans on whether it has *
  347. * been allocated) *
  348. * This may be later utilized for copy/paste support *
  349. ******************************************************************************/
  350. struct ParamStore
  351. {
  352. ParamStore(void)
  353. {
  354. memset(add, 0, sizeof(add));
  355. memset(pad, 0, sizeof(pad));
  356. memset(sub, 0, sizeof(sub));
  357. }
  358. void extractPart(Part *part, int i)
  359. {
  360. for(int j=0; j < NUM_KIT_ITEMS; ++j) {
  361. auto kit = part->kit[j];
  362. add[i][j] = kit.adpars;
  363. sub[i][j] = kit.subpars;
  364. pad[i][j] = kit.padpars;
  365. }
  366. }
  367. ADnoteParameters *add[NUM_MIDI_PARTS][NUM_KIT_ITEMS];
  368. SUBnoteParameters *sub[NUM_MIDI_PARTS][NUM_KIT_ITEMS];
  369. PADnoteParameters *pad[NUM_MIDI_PARTS][NUM_KIT_ITEMS];
  370. };
  371. /* Implementation */
  372. class MiddleWareImpl
  373. {
  374. static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_";
  375. MiddleWare *parent;
  376. //! returns file name to where UDP port is saved
  377. std::string get_tmp_nam() const
  378. {
  379. return tmp_nam_prefix + to_s(getpid());
  380. }
  381. void create_tmp_file(unsigned server_port)
  382. {
  383. std::string tmp_nam = get_tmp_nam();
  384. if(0 == access(tmp_nam.c_str(), F_OK)) {
  385. fprintf(stderr, "Error: Cannot overwrite file %s. "
  386. "You should probably remove it.", tmp_nam.c_str());
  387. exit(EXIT_FAILURE);
  388. }
  389. FILE* tmp_fp = fopen(tmp_nam.c_str(), "w");
  390. if(!tmp_fp)
  391. fprintf(stderr, "Warning: could not create new file %s.\n",
  392. tmp_nam.c_str());
  393. else
  394. fprintf(tmp_fp, "%u", server_port);
  395. fclose(tmp_fp);
  396. }
  397. void clean_up_tmp_nams() const
  398. {
  399. DIR *dir;
  400. struct dirent *entry;
  401. if ((dir = opendir ("/tmp/")) != nullptr)
  402. {
  403. while ((entry = readdir (dir)) != nullptr)
  404. {
  405. std::string name = std::string("/tmp/") + entry->d_name;
  406. if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix))
  407. {
  408. std::string pid = name.substr(strlen(tmp_nam_prefix));
  409. std::string proc_file = "/proc/" + std::move(pid) +
  410. "/comm";
  411. std::ifstream ifs(proc_file);
  412. bool remove = false;
  413. if(!ifs.good())
  414. {
  415. fprintf(stderr, "Note: trying to remove %s - the "
  416. "process does not exist anymore.\n",
  417. name.c_str());
  418. remove = true;
  419. }
  420. else
  421. {
  422. std::string comm_name;
  423. ifs >> comm_name;
  424. if(comm_name == "zynaddsubfx")
  425. fprintf(stderr, "Note: detected running "
  426. "zynaddsubfx with PID %s.\n",
  427. name.c_str() + strlen(tmp_nam_prefix));
  428. else {
  429. fprintf(stderr, "Note: trying to remove %s - the "
  430. "PID is owned by\n another "
  431. "process: %s\n",
  432. name.c_str(), comm_name.c_str());
  433. remove = true;
  434. }
  435. }
  436. if(remove)
  437. {
  438. // make sure this file contains only one unsigned
  439. unsigned udp_port;
  440. std::ifstream ifs2(name);
  441. if(!ifs2.good())
  442. fprintf(stderr, "Warning: could not open %s.\n",
  443. name.c_str());
  444. else
  445. {
  446. ifs2 >> udp_port;
  447. if(ifs.good())
  448. fprintf(stderr, "Warning: could not remove "
  449. "%s, \n it has not been "
  450. "written by zynaddsubfx\n",
  451. name.c_str());
  452. else
  453. {
  454. if(std::remove(name.c_str()) != 0)
  455. fprintf(stderr, "Warning: can not remove "
  456. "%s.\n", name.c_str());
  457. }
  458. }
  459. }
  460. /* one might want to connect to zyn here,
  461. but it is not necessary:
  462. lo_address la = lo_address_new(nullptr, udp_port.c_str());
  463. if(lo_send(la, "/echo", nullptr) <= 0)
  464. fputs("Note: found crashed file %s\n", stderr);
  465. lo_address_free(la);*/
  466. }
  467. }
  468. closedir (dir);
  469. } else {
  470. fputs("Warning: can not read /tmp.\n", stderr);
  471. }
  472. }
  473. public:
  474. MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, int prefered_port);
  475. ~MiddleWareImpl(void);
  476. void warnMemoryLeaks(void);
  477. //Apply function while parameters are write locked
  478. void doReadOnlyOp(std::function<void()> read_only_fn);
  479. void saveBankSlot(int npart, int nslot, Master *master, Fl_Osc_Interface *osc)
  480. {
  481. int err = 0;
  482. doReadOnlyOp([master,nslot,npart,&err](){
  483. err = master->bank.savetoslot(nslot, master->part[npart]);});
  484. if(err) {
  485. char buffer[1024];
  486. rtosc_message(buffer, 1024, "/alert", "s",
  487. "Failed To Save To Bank Slot, please check file permissions");
  488. GUI::raiseUi(ui, buffer);
  489. }
  490. }
  491. void renameBankSlot(int slot, string name, Master *master, Fl_Osc_Interface *osc)
  492. {
  493. int err = master->bank.setname(slot, name, -1);
  494. if(err) {
  495. char buffer[1024];
  496. rtosc_message(buffer, 1024, "/alert", "s",
  497. "Failed To Rename Bank Slot, please check file permissions");
  498. GUI::raiseUi(ui, buffer);
  499. }
  500. }
  501. void swapBankSlot(int slota, int slotb, Master *master, Fl_Osc_Interface *osc)
  502. {
  503. int err = master->bank.swapslot(slota, slotb);
  504. if(err) {
  505. char buffer[1024];
  506. rtosc_message(buffer, 1024, "/alert", "s",
  507. "Failed To Swap Bank Slots, please check file permissions");
  508. GUI::raiseUi(ui, buffer);
  509. }
  510. }
  511. void clearBankSlot(int slot, Master *master, Fl_Osc_Interface *osc)
  512. {
  513. int err = master->bank.clearslot(slot);
  514. if(err) {
  515. char buffer[1024];
  516. rtosc_message(buffer, 1024, "/alert", "s",
  517. "Failed To Clear Bank Slot, please check file permissions");
  518. GUI::raiseUi(ui, buffer);
  519. }
  520. }
  521. void saveMaster(const char *filename)
  522. {
  523. //Copy is needed as filename WILL get trashed during the rest of the run
  524. std::string fname = filename;
  525. //printf("saving master('%s')\n", filename);
  526. doReadOnlyOp([this,fname](){
  527. int res = master->saveXML(fname.c_str());
  528. (void)res;
  529. /*printf("results: '%s' '%d'\n",fname.c_str(), res);*/});
  530. }
  531. void savePart(int npart, const char *filename)
  532. {
  533. //Copy is needed as filename WILL get trashed during the rest of the run
  534. std::string fname = filename;
  535. //printf("saving part(%d,'%s')\n", npart, filename);
  536. doReadOnlyOp([this,fname,npart](){
  537. int res = master->part[npart]->saveXML(fname.c_str());
  538. (void)res;
  539. /*printf("results: '%s' '%d'\n",fname.c_str(), res);*/});
  540. }
  541. void loadPart(int npart, const char *filename, Master *master, Fl_Osc_Interface *osc)
  542. {
  543. actual_load[npart]++;
  544. if(actual_load[npart] != pending_load[npart])
  545. return;
  546. assert(actual_load[npart] <= pending_load[npart]);
  547. auto alloc = std::async(std::launch::async,
  548. [master,filename,this,npart](){
  549. Part *p = new Part(*master->memory, synth, &master->microtonal, master->fft);
  550. if(p->loadXMLinstrument(filename))
  551. fprintf(stderr, "Warning: failed to load part!\n");
  552. auto isLateLoad = [this,npart]{
  553. return actual_load[npart] != pending_load[npart];
  554. };
  555. p->applyparameters(isLateLoad);
  556. return p;});
  557. //Load the part
  558. if(idle) {
  559. while(alloc.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
  560. idle();
  561. }
  562. }
  563. Part *p = alloc.get();
  564. obj_store.extractPart(p, npart);
  565. kits.extractPart(p, npart);
  566. //Give it to the backend and wait for the old part to return for
  567. //deallocation
  568. uToB->write("/load-part", "ib", npart, sizeof(Part*), &p);
  569. GUI::raiseUi(ui, "/damage", "s", ("/part"+to_s(npart)+"/").c_str());
  570. }
  571. //Load a new cleared Part instance
  572. void loadClearPart(int npart)
  573. {
  574. if(npart == -1)
  575. return;
  576. Part *p = new Part(*master->memory, synth, &master->microtonal, master->fft);
  577. p->applyparameters();
  578. obj_store.extractPart(p, npart);
  579. kits.extractPart(p, npart);
  580. //Give it to the backend and wait for the old part to return for
  581. //deallocation
  582. uToB->write("/load-part", "ib", npart, sizeof(Part*), &p);
  583. GUI::raiseUi(ui, "/damage", "s", ("/part"+to_s(npart)+"/").c_str());
  584. //if(osc)
  585. // osc->damage(("/part"+to_s(npart)+"/").c_str());
  586. }
  587. //Well, you don't get much crazier than changing out all of your RT
  588. //structures at once... TODO error handling
  589. void loadMaster(const char *filename)
  590. {
  591. Master *m = new Master(synth);
  592. m->uToB = uToB;
  593. m->bToU = bToU;
  594. if(filename) {
  595. m->loadXML(filename);
  596. m->applyparameters();
  597. }
  598. //Update resource locator table
  599. updateResources(m);
  600. master = m;
  601. //Give it to the backend and wait for the old part to return for
  602. //deallocation
  603. uToB->write("/load-master", "b", sizeof(Master*), &m);
  604. }
  605. void updateResources(Master *m)
  606. {
  607. obj_store.clear();
  608. obj_store.extractMaster(m);
  609. for(int i=0; i<NUM_MIDI_PARTS; ++i)
  610. kits.extractPart(m->part[i], i);
  611. }
  612. //If currently broadcasting messages
  613. bool broadcast = false;
  614. //If accepting undo events as user driven
  615. bool recording_undo = true;
  616. void bToUhandle(const char *rtmsg, bool dummy=false);
  617. void tick(void)
  618. {
  619. while(lo_server_recv_noblock(server, 0));
  620. while(bToU->hasNext()) {
  621. const char *rtmsg = bToU->read();
  622. bToUhandle(rtmsg);
  623. }
  624. }
  625. bool handlePAD(string path, const char *msg, void *v)
  626. {
  627. if(!v)
  628. return true;
  629. char buffer[1024];
  630. memset(buffer, 0, sizeof(buffer));
  631. DummyDataObj d(buffer, 1024, v, this, uToB);
  632. strcpy(buffer, path.c_str());
  633. PADnoteParameters::ports.dispatch(msg, d);
  634. if(!d.matches) {
  635. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  636. fprintf(stderr, "Unknown location '%s%s'<%s>\n",
  637. path.c_str(), msg, rtosc_argument_string(msg));
  638. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  639. }
  640. return true;
  641. }
  642. void handlePresets(const char *msg)
  643. {
  644. char buffer[1024];
  645. memset(buffer, 0, sizeof(buffer));
  646. DummyDataObj d(buffer, 1024, (void*)parent, this, uToB);
  647. strcpy(buffer, "/presets/");
  648. //012345678
  649. ///presets/
  650. real_preset_ports.dispatch(msg+9, d);
  651. //printf("Something <%s>\n", msg+9);
  652. if(strstr(msg, "paste") && rtosc_argument_string(msg)[0] == 's') {
  653. char buffer[1024];
  654. rtosc_message(buffer, 1024, "/damage", "s",
  655. rtosc_argument(msg, 0).s);
  656. GUI::raiseUi(ui, buffer);
  657. }
  658. if(!d.matches) {
  659. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  660. fprintf(stderr, "Unknown location '%s'<%s>\n",
  661. msg, rtosc_argument_string(msg));
  662. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  663. }
  664. }
  665. void handleConfig(const char *msg)
  666. {
  667. char buffer[1024];
  668. memset(buffer, 0, sizeof(buffer));
  669. DummyDataObj d(buffer, 1024, (void*)&config, this, uToB);
  670. strcpy(buffer, "/config/");
  671. Config::ports.dispatch(msg+8, d);
  672. if(!d.matches) {
  673. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  674. fprintf(stderr, "Unknown location '%s'<%s>\n",
  675. msg, rtosc_argument_string(msg));
  676. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  677. }
  678. }
  679. bool handleOscil(string path, const char *msg, void *v);
  680. void kitEnable(const char *msg);
  681. void kitEnable(int part, int kit, int type);
  682. // Handle an event with special cases
  683. void handleMsg(const char *msg);
  684. void write(const char *path, const char *args, ...);
  685. void write(const char *path, const char *args, va_list va);
  686. /*
  687. * Provides a mapping for non-RT objects stored inside the backend
  688. * - Oscilgen almost all parameters can be safely set
  689. * - Padnote can have anything set on its oscilgen and a very small set
  690. * of general parameters
  691. */
  692. NonRtObjStore obj_store;
  693. //This code will own the pointer to master, be prepared for odd things if
  694. //this assumption is broken
  695. Master *master;
  696. //The ONLY means that any chunk of UI code should have for interacting with the
  697. //backend
  698. Fl_Osc_Interface *osc;
  699. //Synth Engine Parameters
  700. ParamStore kits;
  701. //Callback When Waiting on async events
  702. void(*idle)(void);
  703. //General UI callback
  704. cb_t cb;
  705. //UI handle
  706. void *ui;
  707. std::atomic_int pending_load[NUM_MIDI_PARTS];
  708. std::atomic_int actual_load[NUM_MIDI_PARTS];
  709. rtosc::UndoHistory undo;
  710. //Link To the Realtime
  711. rtosc::ThreadLink *bToU;
  712. rtosc::ThreadLink *uToB;
  713. //LIBLO
  714. lo_server server;
  715. string last_url, curr_url;
  716. //Synthesis Rate Parameters
  717. const SYNTH_T synth;
  718. };
  719. MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, int prefered_port)
  720. :parent(mw), synth(synth_)
  721. {
  722. bToU = new rtosc::ThreadLink(4096*2,1024);
  723. uToB = new rtosc::ThreadLink(4096*2,1024);
  724. if(prefered_port != -1)
  725. server = lo_server_new_with_proto(to_s(prefered_port).c_str(), LO_UDP, liblo_error_cb);
  726. else
  727. server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb);
  728. lo_server_add_method(server, NULL, NULL, handler_function, mw);
  729. fprintf(stderr, "lo server running on %d\n", lo_server_get_port(server));
  730. #ifndef CARLA_VERSION_STRING
  731. clean_up_tmp_nams();
  732. create_tmp_file((unsigned)lo_server_get_port(server));
  733. #endif
  734. //dummy callback for starters
  735. cb = [](void*, const char*){};
  736. idle = 0;
  737. the_bToU = bToU;
  738. master = new Master(synth);
  739. master->bToU = bToU;
  740. master->uToB = uToB;
  741. osc = GUI::genOscInterface(mw);
  742. //Grab objects of interest from master
  743. updateResources(master);
  744. //Null out Load IDs
  745. for(int i=0; i < NUM_MIDI_PARTS; ++i) {
  746. pending_load[i] = 0;
  747. actual_load[i] = 0;
  748. }
  749. //Setup Undo
  750. undo.setCallback([this](const char *msg) {
  751. // printf("undo callback <%s>\n", msg);
  752. char buf[1024];
  753. rtosc_message(buf, 1024, "/undo_pause","");
  754. handleMsg(buf);
  755. handleMsg(msg);
  756. rtosc_message(buf, 1024, "/undo_resume","");
  757. handleMsg(buf);
  758. });
  759. }
  760. void DummyDataObj::reply(const char *msg)
  761. {
  762. mwi->bToUhandle(msg, true);
  763. }
  764. MiddleWareImpl::~MiddleWareImpl(void)
  765. {
  766. remove(get_tmp_nam().c_str());
  767. warnMemoryLeaks();
  768. delete master;
  769. delete osc;
  770. delete bToU;
  771. delete uToB;
  772. }
  773. /** Threading When Saving
  774. * ----------------------
  775. *
  776. * Procedure Middleware:
  777. * 1) Middleware sends /freeze_state to backend
  778. * 2) Middleware waits on /state_frozen from backend
  779. * All intervening commands are held for out of order execution
  780. * 3) Aquire memory
  781. * At this time by the memory barrier we are guarenteed that all old
  782. * writes are done and assuming the freezing logic is sound, then it is
  783. * impossible for any other parameter to change at this time
  784. * 3) Middleware performs saving operation
  785. * 4) Middleware sends /thaw_state to backend
  786. * 5) Restore in order execution
  787. *
  788. * Procedure Backend:
  789. * 1) Observe /freeze_state and disable all mutating events (MIDI CC)
  790. * 2) Run a memory release to ensure that all writes are complete
  791. * 3) Send /state_frozen to Middleware
  792. * time...
  793. * 4) Observe /thaw_state and resume normal processing
  794. */
  795. void MiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn)
  796. {
  797. uToB->write("/freeze_state","");
  798. std::list<const char *> fico;
  799. int tries = 0;
  800. while(tries++ < 10000) {
  801. if(!bToU->hasNext()) {
  802. usleep(500);
  803. continue;
  804. }
  805. const char *msg = bToU->read();
  806. if(!strcmp("/state_frozen", msg))
  807. break;
  808. size_t bytes = rtosc_message_length(msg, bToU->buffer_size());
  809. char *save_buf = new char[bytes];
  810. memcpy(save_buf, msg, bytes);
  811. fico.push_back(save_buf);
  812. }
  813. assert(tries < 10000);//if this happens, the backend must be dead
  814. std::atomic_thread_fence(std::memory_order_acquire);
  815. //Now it is safe to do any read only operation
  816. read_only_fn();
  817. //Now to resume normal operations
  818. uToB->write("/thaw_state","");
  819. for(auto x:fico) {
  820. uToB->raw_write(x);
  821. delete [] x;
  822. }
  823. }
  824. void MiddleWareImpl::bToUhandle(const char *rtmsg, bool dummy)
  825. {
  826. assert(strcmp(rtmsg, "/part0/kit0/Ppadenableda"));
  827. assert(strcmp(rtmsg, "/ze_state"));
  828. //Dump Incomming Events For Debugging
  829. if(strcmp(rtmsg, "/vu-meter") && false) {
  830. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 1 + 30, 0 + 40);
  831. fprintf(stdout, "frontend: '%s'<%s>\n", rtmsg,
  832. rtosc_argument_string(rtmsg));
  833. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  834. }
  835. //Activity dot
  836. //printf(".");fflush(stdout);
  837. if(!strcmp(rtmsg, "/echo")
  838. && !strcmp(rtosc_argument_string(rtmsg),"ss")
  839. && !strcmp(rtosc_argument(rtmsg,0).s, "OSC_URL"))
  840. curr_url = rtosc_argument(rtmsg,1).s;
  841. else if(!strcmp(rtmsg, "/free")
  842. && !strcmp(rtosc_argument_string(rtmsg),"sb")) {
  843. deallocate(rtosc_argument(rtmsg, 0).s, *((void**)rtosc_argument(rtmsg, 1).b.data));
  844. } else if(!strcmp(rtmsg, "/request-memory")) {
  845. //Generate out more memory for the RT memory pool
  846. //5MBi chunk
  847. size_t N = 5*1024*1024;
  848. void *mem = malloc(N);
  849. uToB->write("/add-rt-memory", "bi", sizeof(void*), &mem, N);
  850. } else if(!strcmp(rtmsg, "/setprogram")
  851. && !strcmp(rtosc_argument_string(rtmsg),"cc")) {
  852. loadPart(rtosc_argument(rtmsg,0).i, master->bank.ins[rtosc_argument(rtmsg,1).i].filename.c_str(), master, osc);
  853. } else if(!strcmp("/undo_pause", rtmsg)) {
  854. recording_undo = false;
  855. } else if(!strcmp("/undo_resume", rtmsg)) {
  856. recording_undo = true;
  857. } else if(!strcmp("undo_change", rtmsg) && recording_undo) {
  858. undo.recordEvent(rtmsg);
  859. } else if(!strcmp(rtmsg, "/broadcast")) {
  860. broadcast = true;
  861. } else if(broadcast) {
  862. broadcast = false;
  863. cb(ui, rtmsg);
  864. if(curr_url != "GUI") {
  865. lo_message msg = lo_message_deserialise((void*)rtmsg,
  866. rtosc_message_length(rtmsg, bToU->buffer_size()), NULL);
  867. //Send to known url
  868. if(!curr_url.empty()) {
  869. lo_address addr = lo_address_new_from_url(curr_url.c_str());
  870. lo_send_message(addr, rtmsg, msg);
  871. }
  872. }
  873. } else if((dummy?last_url:curr_url) == "GUI" || !strcmp(rtmsg, "/close-ui")) {
  874. cb(ui, rtmsg);
  875. } else{
  876. lo_message msg = lo_message_deserialise((void*)rtmsg,
  877. rtosc_message_length(rtmsg, bToU->buffer_size()), NULL);
  878. //Send to known url
  879. if(!curr_url.empty()) {
  880. lo_address addr = lo_address_new_from_url(dummy?last_url.c_str():curr_url.c_str());
  881. lo_send_message(addr, rtmsg, msg);
  882. }
  883. }
  884. }
  885. bool MiddleWareImpl::handleOscil(string path, const char *msg, void *v)
  886. {
  887. //printf("handleOscil...\n");
  888. char buffer[1024];
  889. memset(buffer, 0, sizeof(buffer));
  890. DummyDataObj d(buffer, 1024, v, this, uToB);
  891. strcpy(buffer, path.c_str());
  892. if(!v)
  893. return true;
  894. //Paste To Non-Realtime Parameters and then forward
  895. if(strstr(msg, "paste") && !strstr(msg, "padpars")) {
  896. }
  897. if(!strstr(msg, "padpars")) {
  898. for(auto &p:OscilGen::ports.ports) {
  899. if(strstr(p.name,msg) && strstr(p.metadata, "realtime") &&
  900. !strcmp("b", rtosc_argument_string(msg))) {
  901. //printf("sending along packet '%s'...\n", msg);
  902. return false;
  903. }
  904. }
  905. }
  906. OscilGen::ports.dispatch(msg, d);
  907. if(!d.matches) {
  908. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  909. //fprintf(stderr, "Unknown location '%s%s'<%s>\n",
  910. // path.c_str(), msg, rtosc_argument_string(msg));
  911. //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  912. }
  913. return true;
  914. }
  915. //Allocate kits on a as needed basis
  916. void MiddleWareImpl::kitEnable(const char *msg)
  917. {
  918. const string argv = rtosc_argument_string(msg);
  919. if(argv != "T")
  920. return;
  921. //Extract fields from:
  922. //BASE/part#/kit#/Pxxxenabled
  923. int type = -1;
  924. if(strstr(msg, "Padenabled"))
  925. type = 0;
  926. else if(strstr(msg, "Ppadenabled"))
  927. type = 1;
  928. else if(strstr(msg, "Psubenabled"))
  929. type = 2;
  930. if(type == -1)
  931. return;
  932. const char *tmp = strstr(msg, "part");
  933. if(tmp == NULL)
  934. return;
  935. const int part = atoi(tmp+4);
  936. tmp = strstr(msg, "kit");
  937. if(tmp == NULL)
  938. return;
  939. const int kit = atoi(tmp+3);
  940. kitEnable(part, kit, type);
  941. }
  942. void MiddleWareImpl::kitEnable(int part, int kit, int type)
  943. {
  944. //printf("attempting a kit enable<%d,%d,%d>\n", part, kit, type);
  945. string url = "/part"+to_s(part)+"/kit"+to_s(kit)+"/";
  946. void *ptr = NULL;
  947. if(type == 0 && kits.add[part][kit] == NULL) {
  948. ptr = kits.add[part][kit] = new ADnoteParameters(synth, master->fft);
  949. url += "adpars-data";
  950. obj_store.extractAD(kits.add[part][kit], part, kit);
  951. } else if(type == 1 && kits.pad[part][kit] == NULL) {
  952. ptr = kits.pad[part][kit] = new PADnoteParameters(synth, master->fft);
  953. url += "padpars-data";
  954. obj_store.extractPAD(kits.pad[part][kit], part, kit);
  955. } else if(type == 2 && kits.sub[part][kit] == NULL) {
  956. ptr = kits.sub[part][kit] = new SUBnoteParameters();
  957. url += "subpars-data";
  958. }
  959. //Send the new memory
  960. if(ptr)
  961. uToB->write(url.c_str(), "b", sizeof(void*), &ptr);
  962. }
  963. /* BASE/part#/kititem#
  964. * BASE/part#/kit#/adpars/voice#/oscil/\*
  965. * BASE/part#/kit#/adpars/voice#/mod-oscil/\*
  966. * BASE/part#/kit#/padpars/prepare
  967. * BASE/part#/kit#/padpars/oscil/\*
  968. */
  969. void MiddleWareImpl::handleMsg(const char *msg)
  970. {
  971. assert(!strstr(msg,"free"));
  972. assert(msg && *msg && rindex(msg, '/')[1]);
  973. assert(strcmp(msg, "/part0/Psysefxvol"));
  974. assert(strcmp(msg, "/Penabled"));
  975. assert(strcmp(msg, "part0/part0/Ppanning"));
  976. assert(strcmp(msg, "sysefx0sysefx0/preset"));
  977. assert(strcmp(msg, "/sysefx0preset"));
  978. assert(strcmp(msg, "Psysefxvol0/part0"));
  979. //fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 6 + 30, 0 + 40);
  980. //fprintf(stdout, "middleware: '%s':%s\n", msg, rtosc_argument_string(msg));
  981. //fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  982. const char *last_path = rindex(msg, '/');
  983. if(!last_path)
  984. return;
  985. //printf("watching '%s' go by\n", msg);
  986. //Get the object resource locator
  987. string obj_rl(msg, last_path+1);
  988. int npart = -1;
  989. char testchr = 0;
  990. if(!strcmp(msg, "/refresh_bank") && !strcmp(rtosc_argument_string(msg), "i")) {
  991. refreshBankView(master->bank, rtosc_argument(msg,0).i, osc);
  992. } else if(!strcmp(msg, "/bank-list") && !strcmp(rtosc_argument_string(msg), "")) {
  993. bankList(master->bank, osc);
  994. } else if(!strcmp(msg, "/rescanforbanks") && !strcmp(rtosc_argument_string(msg), "")) {
  995. rescanForBanks(master->bank, osc);
  996. } else if(!strcmp(msg, "/loadbank") && !strcmp(rtosc_argument_string(msg), "i")) {
  997. loadBank(master->bank, rtosc_argument(msg, 0).i, osc);
  998. } else if(!strcmp(msg, "/loadbank") && !strcmp(rtosc_argument_string(msg), "")) {
  999. bankPos(master->bank, osc);
  1000. } else if(obj_store.has(obj_rl)) {
  1001. //try some over simplified pattern matching
  1002. if(strstr(msg, "oscilgen/") || strstr(msg, "FMSmp/") || strstr(msg, "OscilSmp/")) {
  1003. if(!handleOscil(obj_rl, last_path+1, obj_store.get(obj_rl)))
  1004. uToB->raw_write(msg);
  1005. //else if(strstr(obj_rl.c_str(), "kititem"))
  1006. // handleKitItem(obj_rl, objmap[obj_rl],atoi(rindex(msg,'m')+1),rtosc_argument(msg,0).T);
  1007. } else if(strstr(msg, "padpars/prepare"))
  1008. preparePadSynth(obj_rl,(PADnoteParameters *) obj_store.get(obj_rl), uToB);
  1009. else if(strstr(msg, "padpars")) {
  1010. if(!handlePAD(obj_rl, last_path+1, obj_store.get(obj_rl)))
  1011. uToB->raw_write(msg);
  1012. } else //just forward the message
  1013. uToB->raw_write(msg);
  1014. } else if(strstr(msg, "/save_xmz") && !strcmp(rtosc_argument_string(msg), "s")) {
  1015. saveMaster(rtosc_argument(msg,0).s);
  1016. } else if(strstr(msg, "/save_xiz") && !strcmp(rtosc_argument_string(msg), "is")) {
  1017. savePart(rtosc_argument(msg,0).i,rtosc_argument(msg,1).s);
  1018. } else if(strstr(msg, "/load_xmz") && !strcmp(rtosc_argument_string(msg), "s")) {
  1019. loadMaster(rtosc_argument(msg,0).s);
  1020. } else if(strstr(msg, "/reset_master") && !strcmp(rtosc_argument_string(msg), "")) {
  1021. loadMaster(NULL);
  1022. } else if(!strcmp(msg, "/load_xiz") && !strcmp(rtosc_argument_string(msg), "is")) {
  1023. pending_load[rtosc_argument(msg,0).i]++;
  1024. loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
  1025. } else if(strstr(msg, "load-part") && !strcmp(rtosc_argument_string(msg), "is")) {
  1026. pending_load[rtosc_argument(msg,0).i]++;
  1027. loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
  1028. } else if(!strcmp(msg, "/setprogram")
  1029. && !strcmp(rtosc_argument_string(msg),"c")) {
  1030. pending_load[0]++;
  1031. loadPart(0, master->bank.ins[rtosc_argument(msg,0).i].filename.c_str(), master, osc);
  1032. } else if(strstr(msg, "save-bank-part") && !strcmp(rtosc_argument_string(msg), "ii")) {
  1033. saveBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master, osc);
  1034. } else if(strstr(msg, "bank-rename") && !strcmp(rtosc_argument_string(msg), "is")) {
  1035. renameBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
  1036. } else if(strstr(msg, "swap-bank-slots") && !strcmp(rtosc_argument_string(msg), "ii")) {
  1037. swapBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master, osc);
  1038. } else if(strstr(msg, "clear-bank-slot") && !strcmp(rtosc_argument_string(msg), "i")) {
  1039. clearBankSlot(rtosc_argument(msg,0).i, master, osc);
  1040. } else if(strstr(msg, "/config/")) {
  1041. handleConfig(msg);
  1042. } else if(strstr(msg, "/presets/")) {
  1043. handlePresets(msg);
  1044. } else if(strstr(msg, "Padenabled") || strstr(msg, "Ppadenabled") || strstr(msg, "Psubenabled")) {
  1045. kitEnable(msg);
  1046. uToB->raw_write(msg);
  1047. } else if(sscanf(msg, "/part%d/clea%c", &npart, &testchr) == 2 && testchr == 'r') {
  1048. loadClearPart(npart);
  1049. } else if(!strcmp(msg, "/undo")) {
  1050. undo.seekHistory(-1);
  1051. } else if(!strcmp(msg, "/redo")) {
  1052. undo.seekHistory(+1);
  1053. } else
  1054. uToB->raw_write(msg);
  1055. }
  1056. void MiddleWareImpl::write(const char *path, const char *args, ...)
  1057. {
  1058. //We have a free buffer in the threadlink, so use it
  1059. va_list va;
  1060. va_start(va, args);
  1061. write(path, args, va);
  1062. va_end(va);
  1063. }
  1064. void MiddleWareImpl::write(const char *path, const char *args, va_list va)
  1065. {
  1066. //printf("is that a '%s' I see there?\n", path);
  1067. char *buffer = uToB->buffer();
  1068. unsigned len = uToB->buffer_size();
  1069. bool success = rtosc_vmessage(buffer, len, path, args, va);
  1070. //printf("working on '%s':'%s'\n",path, args);
  1071. if(success)
  1072. handleMsg(buffer);
  1073. else
  1074. warnx("Failed to write message to '%s'", path);
  1075. }
  1076. void MiddleWareImpl::warnMemoryLeaks(void)
  1077. {}
  1078. /******************************************************************************
  1079. * MidleWare Forwarding Stubs *
  1080. ******************************************************************************/
  1081. MiddleWare::MiddleWare(SYNTH_T synth, int prefered_port)
  1082. :impl(new MiddleWareImpl(this, synth, prefered_port))
  1083. {}
  1084. MiddleWare::~MiddleWare(void)
  1085. {
  1086. delete impl;
  1087. }
  1088. void MiddleWare::updateResources(Master *m)
  1089. {
  1090. impl->updateResources(m);
  1091. }
  1092. Master *MiddleWare::spawnMaster(void)
  1093. {
  1094. return impl->master;
  1095. }
  1096. Fl_Osc_Interface *MiddleWare::spawnUiApi(void)
  1097. {
  1098. return impl->osc;
  1099. }
  1100. void MiddleWare::tick(void)
  1101. {
  1102. impl->tick();
  1103. }
  1104. void MiddleWare::doReadOnlyOp(std::function<void()> fn)
  1105. {
  1106. impl->doReadOnlyOp(fn);
  1107. }
  1108. void MiddleWare::setUiCallback(void(*cb)(void*,const char *),void *ui)
  1109. {
  1110. impl->cb = cb;
  1111. impl->ui = ui;
  1112. }
  1113. void MiddleWare::setIdleCallback(void(*cb)(void))
  1114. {
  1115. impl->idle = cb;
  1116. }
  1117. void MiddleWare::transmitMsg(const char *msg)
  1118. {
  1119. impl->handleMsg(msg);
  1120. }
  1121. void MiddleWare::transmitMsg(const char *path, const char *args, ...)
  1122. {
  1123. char buffer[1024];
  1124. va_list va;
  1125. va_start(va,args);
  1126. if(rtosc_vmessage(buffer,1024,path,args,va))
  1127. transmitMsg(buffer);
  1128. else
  1129. fprintf(stderr, "Error in transmitMsg(...)\n");
  1130. va_end(va);
  1131. }
  1132. void MiddleWare::transmitMsg(const char *path, const char *args, va_list va)
  1133. {
  1134. char buffer[1024];
  1135. if(rtosc_vmessage(buffer, 1024, path, args, va))
  1136. transmitMsg(buffer);
  1137. else
  1138. fprintf(stderr, "Error in transmitMsg(va)n");
  1139. }
  1140. void MiddleWare::pendingSetProgram(int part, int program)
  1141. {
  1142. impl->pending_load[part]++;
  1143. impl->bToU->write("/setprogram", "cc", part, program);
  1144. }
  1145. std::string MiddleWare::activeUrl(void)
  1146. {
  1147. return impl->last_url;
  1148. }
  1149. void MiddleWare::activeUrl(std::string u)
  1150. {
  1151. impl->last_url = u;
  1152. }
  1153. const SYNTH_T &MiddleWare::getSynth(void) const
  1154. {
  1155. return impl->synth;
  1156. }
  1157. const char* MiddleWare::getServerAddress(void) const
  1158. {
  1159. return lo_server_get_url(impl->server);
  1160. }