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.

1251 lines
39KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Master.cpp - It sends Midi Messages to Parts, receives samples from parts,
  4. process them with system/insertion effects and mix them
  5. Copyright (C) 2002-2005 Nasca Octavian Paul
  6. Author: Nasca Octavian Paul
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. */
  12. #include "Master.h"
  13. #include "Part.h"
  14. #include "../Misc/Stereo.h"
  15. #include "../Misc/Util.h"
  16. #include "../Params/LFOParams.h"
  17. #include "../Effects/EffectMgr.h"
  18. #include "../DSP/FFTwrapper.h"
  19. #include "../Misc/Allocator.h"
  20. #include "../Containers/ScratchString.h"
  21. #include "../Nio/Nio.h"
  22. #include "PresetExtractor.h"
  23. #include <rtosc/ports.h>
  24. #include <rtosc/port-sugar.h>
  25. #include <rtosc/thread-link.h>
  26. #include <stdio.h>
  27. #include <sys/stat.h>
  28. #include <sys/types.h>
  29. #include <iostream>
  30. #include <algorithm>
  31. #include <cmath>
  32. #include <atomic>
  33. #include <unistd.h>
  34. using namespace std;
  35. using namespace rtosc;
  36. #define rObject Master
  37. static const Ports sysefxPort =
  38. {
  39. {"part#" STRINGIFY(NUM_MIDI_PARTS) "::i", rProp(parameter)
  40. rDoc("gain on part to sysefx routing"), 0,
  41. [](const char *m, RtData&d)
  42. {
  43. //ok, this is going to be an ugly workaround
  44. //we know that if we are here the message previously MUST have
  45. //matched Psysefxvol#/
  46. //and the number is one or two digits at most
  47. const char *index_1 = m;
  48. index_1 -=2;
  49. assert(isdigit(*index_1));
  50. if(isdigit(index_1[-1]))
  51. index_1--;
  52. int ind1 = atoi(index_1);
  53. //Now get the second index like normal
  54. while(!isdigit(*m)) m++;
  55. int ind2 = atoi(m);
  56. Master &mast = *(Master*)d.obj;
  57. if(rtosc_narguments(m)) {
  58. mast.setPsysefxvol(ind2, ind1, rtosc_argument(m,0).i);
  59. d.broadcast(d.loc, "i", mast.Psysefxvol[ind1][ind2]);
  60. } else
  61. d.reply(d.loc, "i", mast.Psysefxvol[ind1][ind2]);
  62. }}
  63. };
  64. static const Ports sysefsendto =
  65. {
  66. {"to#" STRINGIFY(NUM_SYS_EFX) "::i",
  67. rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d)
  68. {
  69. //same ugly workaround as before
  70. const char *index_1 = m;
  71. index_1 -=2;
  72. assert(isdigit(*index_1));
  73. if(isdigit(index_1[-1]))
  74. index_1--;
  75. int ind1 = atoi(index_1);
  76. //Now get the second index like normal
  77. while(!isdigit(*m)) m++;
  78. int ind2 = atoi(m);
  79. Master &master = *(Master*)d.obj;
  80. if(rtosc_narguments(m))
  81. master.setPsysefxsend(ind1, ind2, rtosc_argument(m,0).i);
  82. else
  83. d.reply(d.loc, "i", master.Psysefxsend[ind1][ind2]);
  84. }}
  85. };
  86. #define rBegin [](const char *msg, RtData &d) { Master *m = (Master*)d.obj
  87. #define rEnd }
  88. static const Ports watchPorts = {
  89. {"add:s", rDoc("Add synthesis state to watch"), 0,
  90. rBegin;
  91. m->watcher.add_watch(rtosc_argument(msg,0).s);
  92. rEnd},
  93. };
  94. extern const Ports bankPorts;
  95. static const Ports master_ports = {
  96. rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."),
  97. rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS
  98. rRecursp(sysefx, 4, "System Effect"),//NUM_SYS_EFX
  99. rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX
  100. rRecur(microtonal, "Micrtonal Mapping Functionality"),
  101. rRecur(ctl, "Controller"),
  102. rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off)
  103. rOptions(Part1, Part2, Part3, Part4, Part5, Part6,
  104. Part7, Part8, Part9, Part10, Part11, Part12,
  105. Part13, Part14, Part15, Part16),
  106. "Part to insert part onto"),
  107. {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) {
  108. if(rtosc_narguments(m)==0) {
  109. d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift);
  110. } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
  111. ((Master*)d.obj)->setPkeyshift(limit<char>(rtosc_argument(m,0).i,0,127));
  112. d.broadcast(d.loc, "i", ((Master*)d.obj)->Pkeyshift);}}},
  113. {"echo", rDoc("Hidden port to echo messages"), 0, [](const char *m, RtData&d) {
  114. d.reply(m-1);}},
  115. {"get-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
  116. Master *m = (Master*)d.obj;
  117. d.reply("/vu-meter", "bb", sizeof(m->vu), &m->vu, sizeof(float)*NUM_MIDI_PARTS, m->vuoutpeakpart);}},
  118. {"vu-meter:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
  119. Master *m = (Master*)d.obj;
  120. char types[6+NUM_MIDI_PARTS+1] = {0};
  121. rtosc_arg_t args[6+NUM_MIDI_PARTS+1];
  122. for(int i=0; i<6+NUM_MIDI_PARTS; ++i)
  123. types[i] = 'f';
  124. args[0].f = m->vu.outpeakl;
  125. args[1].f = m->vu.outpeakr;
  126. args[2].f = m->vu.maxoutpeakl;
  127. args[3].f = m->vu.maxoutpeakr;
  128. args[4].f = m->vu.rmspeakl;
  129. args[5].f = m->vu.rmspeakr;
  130. for(int i=0; i<NUM_MIDI_PARTS; ++i)
  131. args[6+i].f = m->vuoutpeakpart[i];
  132. d.replyArray("/vu-meter", types, args);}},
  133. {"reset-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
  134. Master *m = (Master*)d.obj;
  135. m->vuresetpeaks();}},
  136. {"load-part:ib", rProp(internal) rDoc("Load Part From Middleware"), 0, [](const char *msg, RtData &d) {
  137. Master *m = (Master*)d.obj;
  138. Part *p = *(Part**)rtosc_argument(msg, 1).b.data;
  139. int i = rtosc_argument(msg, 0).i;
  140. m->part[i]->cloneTraits(*p);
  141. m->part[i]->kill_rt();
  142. d.reply("/free", "sb", "Part", sizeof(void*), &m->part[i]);
  143. m->part[i] = p;
  144. p->initialize_rt();
  145. }},
  146. {"active_keys:", rProp("Obtain a list of active notes"), 0,
  147. rBegin;
  148. char keys[129] = {0};
  149. for(int i=0; i<128; ++i)
  150. keys[i] = m->activeNotes[i] ? 'T' : 'F';
  151. d.broadcast(d.loc, keys);
  152. rEnd},
  153. {"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0,
  154. [](const char *m, rtosc::RtData &d) {
  155. if(rtosc_narguments(m)==0) {
  156. d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
  157. } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
  158. ((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127));
  159. d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}},
  160. {"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0,
  161. [](const char *m, rtosc::RtData &d) {
  162. if(rtosc_narguments(m)==0) {
  163. d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
  164. } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
  165. ((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127));
  166. d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}},
  167. {"Psysefxvol#" STRINGIFY(NUM_SYS_EFX) "/::i", 0, &sysefxPort,
  168. [](const char *msg, rtosc::RtData &d) {
  169. SNIP;
  170. sysefxPort.dispatch(msg, d);
  171. }},
  172. {"sysefxfrom#" STRINGIFY(NUM_SYS_EFX) "/", rDoc("Routing Between System Effects"), &sysefsendto,
  173. [](const char *msg, RtData&d) {
  174. SNIP;
  175. sysefsendto.dispatch(msg, d);
  176. }},
  177. {"noteOn:iii", rDoc("Noteon Event"), 0,
  178. [](const char *m,RtData &d){
  179. Master *M = (Master*)d.obj;
  180. M->noteOn(rtosc_argument(m,0).i,rtosc_argument(m,1).i,rtosc_argument(m,2).i);}},
  181. {"noteOff:ii", rDoc("Noteoff Event"), 0,
  182. [](const char *m,RtData &d){
  183. Master *M = (Master*)d.obj;
  184. M->noteOff(rtosc_argument(m,0).i,rtosc_argument(m,1).i);}},
  185. {"virtual_midi_cc:iii", rDoc("MIDI CC Event"), 0,
  186. [](const char *m,RtData &d){
  187. Master *M = (Master*)d.obj;
  188. M->setController(rtosc_argument(m,0).i,rtosc_argument(m,1).i,rtosc_argument(m,2).i);}},
  189. {"setController:iii", rDoc("MIDI CC Event"), 0,
  190. [](const char *m,RtData &d){
  191. Master *M = (Master*)d.obj;
  192. M->setController(rtosc_argument(m,0).i,rtosc_argument(m,1).i,rtosc_argument(m,2).i);}},
  193. {"Panic:", rDoc("Stop all sound"), 0,
  194. [](const char *, RtData &d) {
  195. Master &M = *(Master*)d.obj;
  196. M.ShutUp();
  197. }},
  198. {"freeze_state:", rProp(internal) rDoc("Disable OSC event handling\n"
  199. "This sets up a read-only mode from which it's safe for another"
  200. " thread to save parameters"), 0,
  201. [](const char *,RtData &d) {
  202. Master *M = (Master*)d.obj;
  203. std::atomic_thread_fence(std::memory_order_release);
  204. M->frozenState = true;
  205. d.reply("/state_frozen", "");}},
  206. {"thaw_state:", rProp(internal) rDoc("Resume handling OSC messages\n"
  207. "See /freeze_state for more information"), 0,
  208. [](const char *,RtData &d) {
  209. Master *M = (Master*)d.obj;
  210. M->frozenState = false;}},
  211. {"midi-learn/", 0, &rtosc::MidiMapperRT::ports,
  212. [](const char *msg, RtData &d) {
  213. Master *M = (Master*)d.obj;
  214. SNIP;
  215. printf("residue message = <%s>\n", msg);
  216. d.obj = &M->midi;
  217. rtosc::MidiMapperRT::ports.dispatch(msg,d);}},
  218. {"close-ui:", rDoc("Request to close any connection named \"GUI\""), 0,
  219. [](const char *, RtData &d) {
  220. d.reply("/close-ui", "");}},
  221. {"add-rt-memory:bi", rProp(internal) rDoc("Add Additional Memory To RT MemPool"), 0,
  222. [](const char *msg, RtData &d)
  223. {
  224. Master &m = *(Master*)d.obj;
  225. char *mem = *(char**)rtosc_argument(msg, 0).b.data;
  226. int i = rtosc_argument(msg, 1).i;
  227. m.memory->addMemory(mem, i);
  228. m.pendingMemory = false;
  229. }},
  230. {"samplerate:", rMap(unit, Hz) rDoc("Get synthesizer sample rate"), 0, [](const char *, RtData &d) {
  231. Master &m = *(Master*)d.obj;
  232. d.reply("/samplerate", "f", m.synth.samplerate_f);
  233. }},
  234. {"oscilsize:", rDoc("Get synthesizer oscillator size"), 0, [](const char *, RtData &d) {
  235. Master &m = *(Master*)d.obj;
  236. d.reply("/oscilsize", "f", m.synth.oscilsize_f);
  237. d.reply("/oscilsize", "i", m.synth.oscilsize);
  238. }},
  239. {"undo_pause:",rProp(internal) rDoc("pause undo event recording"),0,
  240. [](const char *, rtosc::RtData &d) {d.reply("/undo_pause", "");}},
  241. {"undo_resume:",rProp(internal) rDoc("resume undo event recording"),0,
  242. [](const char *, rtosc::RtData &d) {d.reply("/undo_resume", "");}},
  243. {"config/", rDoc("Top Level Application CarlaConfiguration Parameters"), &CarlaConfig::ports,
  244. [](const char *, rtosc::RtData &d){d.forward();}},
  245. {"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN
  246. SNIP
  247. preset_ports.dispatch(msg, data);
  248. rBOIL_END},
  249. {"HDDRecorder/preparefile:s", rDoc("Init WAV file"), 0, [](const char *msg, RtData &d) {
  250. Master *m = (Master*)d.obj;
  251. m->HDDRecorder.preparefile(rtosc_argument(msg, 0).s, 1);}},
  252. {"HDDRecorder/start:", rDoc("Start recording"), 0, [](const char *, RtData &d) {
  253. Master *m = (Master*)d.obj;
  254. m->HDDRecorder.start();}},
  255. {"HDDRecorder/stop:", rDoc("Stop recording"), 0, [](const char *, RtData &d) {
  256. Master *m = (Master*)d.obj;
  257. m->HDDRecorder.stop();}},
  258. {"HDDRecorder/pause:", rDoc("Pause recording"), 0, [](const char *, RtData &d) {
  259. Master *m = (Master*)d.obj;
  260. m->HDDRecorder.pause();}},
  261. {"watch/", rDoc("Interface to grab out live synthesis state"), &watchPorts,
  262. rBOIL_BEGIN;
  263. SNIP;
  264. watchPorts.dispatch(msg, data);
  265. rBOIL_END},
  266. {"bank/", rDoc("Controls for instrument banks"), &bankPorts,
  267. [](const char*,RtData&) {}},
  268. };
  269. #undef rBegin
  270. #undef rEnd
  271. const Ports &Master::ports = master_ports;
  272. class DataObj:public rtosc::RtData
  273. {
  274. public:
  275. DataObj(char *loc_, size_t loc_size_, void *obj_, rtosc::ThreadLink *bToU_)
  276. {
  277. memset(loc_, 0, loc_size_);
  278. loc = loc_;
  279. loc_size = loc_size_;
  280. obj = obj_;
  281. bToU = bToU_;
  282. forwarded = false;
  283. }
  284. virtual void replyArray(const char *path, const char *args, rtosc_arg_t *vals) override
  285. {
  286. char *buffer = bToU->buffer();
  287. rtosc_amessage(buffer,bToU->buffer_size(),path,args,vals);
  288. reply(buffer);
  289. }
  290. virtual void reply(const char *path, const char *args, ...) override
  291. {
  292. va_list va;
  293. va_start(va,args);
  294. char *buffer = bToU->buffer();
  295. rtosc_vmessage(buffer,bToU->buffer_size(),path,args,va);
  296. reply(buffer);
  297. va_end(va);
  298. }
  299. virtual void reply(const char *msg) override
  300. {
  301. if(rtosc_message_length(msg, -1) == 0)
  302. fprintf(stderr, "Warning: Invalid Rtosc message '%s'\n", msg);
  303. bToU->raw_write(msg);
  304. }
  305. virtual void broadcast(const char *path, const char *args, ...) override{
  306. va_list va;
  307. va_start(va,args);
  308. reply("/broadcast", "");
  309. char *buffer = bToU->buffer();
  310. rtosc_vmessage(buffer,bToU->buffer_size(),path,args,va);
  311. reply(buffer);
  312. va_end(va);
  313. }
  314. virtual void broadcast(const char *msg) override
  315. {
  316. reply("/broadcast", "");
  317. reply(msg);
  318. }
  319. virtual void forward(const char *reason) override
  320. {
  321. assert(message);
  322. reply("/forward", "");
  323. printf("forwarding '%s'\n", message);
  324. forwarded = true;
  325. }
  326. bool forwarded;
  327. private:
  328. rtosc::ThreadLink *bToU;
  329. };
  330. vuData::vuData(void)
  331. :outpeakl(0.0f), outpeakr(0.0f), maxoutpeakl(0.0f), maxoutpeakr(0.0f),
  332. rmspeakl(0.0f), rmspeakr(0.0f), clipped(0)
  333. {}
  334. Master::Master(const SYNTH_T &synth_, CarlaConfig* config)
  335. :HDDRecorder(synth_), time(synth_), ctl(synth_, &time),
  336. microtonal(config->cfg.GzipCompression), bank(config),
  337. frozenState(false), pendingMemory(false),
  338. synth(synth_), gzip_compression(config->cfg.GzipCompression)
  339. {
  340. bToU = NULL;
  341. uToB = NULL;
  342. //Setup MIDI
  343. midi.frontend = [this](const char *msg) {bToU->raw_write(msg);};
  344. midi.backend = [this](const char *msg) {applyOscEvent(msg);};
  345. memory = new AllocatorClass();
  346. swaplr = 0;
  347. off = 0;
  348. smps = 0;
  349. bufl = new float[synth.buffersize];
  350. bufr = new float[synth.buffersize];
  351. last_xmz[0] = 0;
  352. fft = new FFTwrapper(synth.oscilsize);
  353. shutup = 0;
  354. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  355. vuoutpeakpart[npart] = 1e-9;
  356. fakepeakpart[npart] = 0;
  357. }
  358. ScratchString ss;
  359. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  360. part[npart] = new Part(*memory, synth, time, config->cfg.GzipCompression,
  361. config->cfg.Interpolation, &microtonal, fft, &watcher,
  362. (ss+"/part"+npart+"/").c_str);
  363. //Insertion Effects init
  364. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  365. insefx[nefx] = new EffectMgr(*memory, synth, 1, &time);
  366. //System Effects init
  367. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
  368. sysefx[nefx] = new EffectMgr(*memory, synth, 0, &time);
  369. //Note Visualization
  370. for(int i=0; i<128; ++i)
  371. activeNotes[i] = 0;
  372. defaults();
  373. mastercb = 0;
  374. mastercb_ptr = 0;
  375. }
  376. void Master::applyOscEvent(const char *msg)
  377. {
  378. char loc_buf[1024];
  379. DataObj d{loc_buf, 1024, this, bToU};
  380. memset(loc_buf, 0, sizeof(loc_buf));
  381. d.matches = 0;
  382. if(strcmp(msg, "/get-vu") && false) {
  383. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40);
  384. fprintf(stdout, "backend[*]: '%s'<%s>\n", msg,
  385. rtosc_argument_string(msg));
  386. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  387. }
  388. ports.dispatch(msg, d, true);
  389. if(d.matches == 0 && !d.forwarded)
  390. fprintf(stderr, "Unknown path '%s:%s'\n", msg, rtosc_argument_string(msg));
  391. if(d.forwarded)
  392. bToU->raw_write(msg);
  393. }
  394. void Master::defaults()
  395. {
  396. volume = 1.0f;
  397. setPvolume(80);
  398. setPkeyshift(64);
  399. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  400. part[npart]->defaults();
  401. part[npart]->Prcvchn = npart % NUM_MIDI_CHANNELS;
  402. }
  403. partonoff(0, 1); //enable the first part
  404. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) {
  405. insefx[nefx]->defaults();
  406. Pinsparts[nefx] = -1;
  407. }
  408. //System Effects init
  409. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) {
  410. sysefx[nefx]->defaults();
  411. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  412. setPsysefxvol(npart, nefx, 0);
  413. for(int nefxto = 0; nefxto < NUM_SYS_EFX; ++nefxto)
  414. setPsysefxsend(nefx, nefxto, 0);
  415. }
  416. microtonal.defaults();
  417. ShutUp();
  418. }
  419. /*
  420. * Note On Messages (velocity=0 for NoteOff)
  421. */
  422. void Master::noteOn(char chan, char note, char velocity)
  423. {
  424. if(velocity) {
  425. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  426. if(chan == part[npart]->Prcvchn) {
  427. fakepeakpart[npart] = velocity * 2;
  428. if(part[npart]->Penabled)
  429. part[npart]->NoteOn(note, velocity, keyshift);
  430. }
  431. }
  432. activeNotes[(int)note] = 1;
  433. }
  434. else
  435. this->noteOff(chan, note);
  436. HDDRecorder.triggernow();
  437. }
  438. /*
  439. * Note Off Messages
  440. */
  441. void Master::noteOff(char chan, char note)
  442. {
  443. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  444. if((chan == part[npart]->Prcvchn) && part[npart]->Penabled)
  445. part[npart]->NoteOff(note);
  446. activeNotes[(int)note] = 0;
  447. }
  448. /*
  449. * Pressure Messages (velocity=0 for NoteOff)
  450. */
  451. void Master::polyphonicAftertouch(char chan, char note, char velocity)
  452. {
  453. if(velocity) {
  454. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  455. if(chan == part[npart]->Prcvchn)
  456. if(part[npart]->Penabled)
  457. part[npart]->PolyphonicAftertouch(note, velocity, keyshift);
  458. }
  459. else
  460. this->noteOff(chan, note);
  461. }
  462. /*
  463. * Controllers
  464. */
  465. void Master::setController(char chan, int type, int par)
  466. {
  467. if(frozenState)
  468. return;
  469. //TODO add chan back
  470. midi.handleCC(type,par);
  471. if((type == C_dataentryhi) || (type == C_dataentrylo)
  472. || (type == C_nrpnhi) || (type == C_nrpnlo)) { //Process RPN and NRPN by the Master (ignore the chan)
  473. ctl.setparameternumber(type, par);
  474. int parhi = -1, parlo = -1, valhi = -1, vallo = -1;
  475. if(ctl.getnrpn(&parhi, &parlo, &valhi, &vallo) == 0) { //this is NRPN
  476. switch(parhi) {
  477. case 0x04: //System Effects
  478. if(parlo < NUM_SYS_EFX)
  479. sysefx[parlo]->seteffectparrt(valhi, vallo);
  480. break;
  481. case 0x08: //Insertion Effects
  482. if(parlo < NUM_INS_EFX)
  483. insefx[parlo]->seteffectparrt(valhi, vallo);
  484. break;
  485. }
  486. }
  487. } else { //other controllers
  488. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) //Send the controller to all part assigned to the channel
  489. if((chan == part[npart]->Prcvchn) && (part[npart]->Penabled != 0))
  490. part[npart]->SetController(type, par);
  491. if(type == C_allsoundsoff) { //cleanup insertion/system FX
  492. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
  493. sysefx[nefx]->cleanup();
  494. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  495. insefx[nefx]->cleanup();
  496. }
  497. }
  498. }
  499. void Master::vuUpdate(const float *outl, const float *outr)
  500. {
  501. //Peak computation (for vumeters)
  502. vu.outpeakl = 1e-12;
  503. vu.outpeakr = 1e-12;
  504. for(int i = 0; i < synth.buffersize; ++i) {
  505. if(fabs(outl[i]) > vu.outpeakl)
  506. vu.outpeakl = fabs(outl[i]);
  507. if(fabs(outr[i]) > vu.outpeakr)
  508. vu.outpeakr = fabs(outr[i]);
  509. }
  510. if((vu.outpeakl > 1.0f) || (vu.outpeakr > 1.0f))
  511. vu.clipped = 1;
  512. if(vu.maxoutpeakl < vu.outpeakl)
  513. vu.maxoutpeakl = vu.outpeakl;
  514. if(vu.maxoutpeakr < vu.outpeakr)
  515. vu.maxoutpeakr = vu.outpeakr;
  516. //RMS Peak computation (for vumeters)
  517. vu.rmspeakl = 1e-12;
  518. vu.rmspeakr = 1e-12;
  519. for(int i = 0; i < synth.buffersize; ++i) {
  520. vu.rmspeakl += outl[i] * outl[i];
  521. vu.rmspeakr += outr[i] * outr[i];
  522. }
  523. vu.rmspeakl = sqrt(vu.rmspeakl / synth.buffersize_f);
  524. vu.rmspeakr = sqrt(vu.rmspeakr / synth.buffersize_f);
  525. //Part Peak computation (for Part vumeters or fake part vumeters)
  526. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  527. vuoutpeakpart[npart] = 1.0e-12f;
  528. if(part[npart]->Penabled != 0) {
  529. float *outl = part[npart]->partoutl,
  530. *outr = part[npart]->partoutr;
  531. for(int i = 0; i < synth.buffersize; ++i) {
  532. float tmp = fabs(outl[i] + outr[i]);
  533. if(tmp > vuoutpeakpart[npart])
  534. vuoutpeakpart[npart] = tmp;
  535. }
  536. vuoutpeakpart[npart] *= volume;
  537. }
  538. else
  539. if(fakepeakpart[npart] > 1)
  540. fakepeakpart[npart]--;
  541. }
  542. }
  543. /*
  544. * Enable/Disable a part
  545. */
  546. void Master::partonoff(int npart, int what)
  547. {
  548. if(npart >= NUM_MIDI_PARTS)
  549. return;
  550. if(what == 0) { //disable part
  551. fakepeakpart[npart] = 0;
  552. part[npart]->Penabled = 0;
  553. part[npart]->cleanup();
  554. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) {
  555. if(Pinsparts[nefx] == npart)
  556. insefx[nefx]->cleanup();
  557. }
  558. }
  559. else { //enabled
  560. part[npart]->Penabled = 1;
  561. fakepeakpart[npart] = 0;
  562. }
  563. }
  564. void Master::setMasterChangedCallback(void(*cb)(void*,Master*), void *ptr)
  565. {
  566. mastercb = cb;
  567. mastercb_ptr = ptr;
  568. }
  569. #if 0
  570. template <class T>
  571. struct def_skip
  572. {
  573. static void skip(const char*& argptr) { argptr += sizeof(T); }
  574. };
  575. template <class T>
  576. struct str_skip
  577. {
  578. static void skip(const char*& argptr) { while(argptr++); /*TODO: 4 padding */ }
  579. };
  580. template<class T, class Display = T, template<class TMP> class SkipsizeFunc = def_skip>
  581. void _dump_prim_arg(const char*& argptr, std::ostream& os)
  582. {
  583. os << ' ' << (Display)*(const T*)argptr;
  584. SkipsizeFunc<T>::skip(argptr);
  585. }
  586. void dump_msg(const char* ptr, std::ostream& os = std::cerr)
  587. {
  588. assert(*ptr == '/');
  589. os << ptr;
  590. while(*++ptr) ; // skip address
  591. while(!*++ptr) ; // skip 0s
  592. assert(*ptr == ',');
  593. os << ' ' << (ptr + 1);
  594. const char* argptr = ptr;
  595. while(*++argptr) ; // skip type string
  596. while(!*++argptr) ; // skip 0s
  597. char c;
  598. while((c = *++ptr))
  599. {
  600. switch(c)
  601. {
  602. case 'i':
  603. _dump_prim_arg<int32_t>(argptr, os); break;
  604. case 'c':
  605. _dump_prim_arg<int32_t, char>(argptr, os); break;
  606. // case 's':
  607. // _dump_prim_arg<char, const char*>(argptr, os); break;
  608. default:
  609. exit(1);
  610. }
  611. }
  612. }
  613. #endif
  614. int msg_id=0;
  615. bool Master::runOSC(float *outl, float *outr, bool offline)
  616. {
  617. //Handle user events TODO move me to a proper location
  618. char loc_buf[1024];
  619. DataObj d{loc_buf, 1024, this, bToU};
  620. memset(loc_buf, 0, sizeof(loc_buf));
  621. int events = 0;
  622. while(uToB && uToB->hasNext() && events < 100) {
  623. const char *msg = uToB->read();
  624. if(!strcmp(msg, "/load-master")) {
  625. Master *this_master = this;
  626. Master *new_master = *(Master**)rtosc_argument(msg, 0).b.data;
  627. if(!offline)
  628. new_master->AudioOut(outl, outr);
  629. Nio::masterSwap(new_master);
  630. if (mastercb)
  631. mastercb(mastercb_ptr, new_master);
  632. bToU->write("/free", "sb", "Master", sizeof(Master*), &this_master);
  633. return false;
  634. }
  635. //XXX yes, this is not realtime safe, but it is useful...
  636. if(strcmp(msg, "/get-vu") && false) {
  637. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40);
  638. fprintf(stdout, "backend[%d]: '%s'<%s>\n", msg_id++, msg,
  639. rtosc_argument_string(msg));
  640. fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  641. }
  642. ports.dispatch(msg, d, true);
  643. events++;
  644. if(!d.matches) {
  645. //workaround for requesting voice status
  646. int a=0, b=0, c=0;
  647. char e=0;
  648. if(4 == sscanf(msg, "/part%d/kit%d/adpars/VoicePar%d/Enable%c", &a, &b, &c, &e)) {
  649. d.reply(msg, "F");
  650. d.matches++;
  651. }
  652. }
  653. if(!d.matches) {// && !ports.apropos(msg)) {
  654. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
  655. fprintf(stderr, "Unknown address<BACKEND:%s> '%s:%s'\n",
  656. offline ? "offline" : "online",
  657. uToB->peak(),
  658. rtosc_argument_string(uToB->peak()));
  659. fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
  660. }
  661. }
  662. if(events>1 && false)
  663. fprintf(stderr, "backend: %d events per cycle\n",events);
  664. return true;
  665. }
  666. /*
  667. * Master audio out (the final sound)
  668. */
  669. bool Master::AudioOut(float *outr, float *outl)
  670. {
  671. //Danger Limits
  672. if(memory->lowMemory(2,1024*1024))
  673. printf("QUITE LOW MEMORY IN THE RT POOL BE PREPARED FOR WEIRD BEHAVIOR!!\n");
  674. //Normal Limits
  675. if(!pendingMemory && memory->lowMemory(4,1024*1024)) {
  676. printf("Requesting more memory\n");
  677. bToU->write("/request-memory", "");
  678. pendingMemory = true;
  679. }
  680. //work through events
  681. if(!runOSC(outl, outr, false))
  682. return false;
  683. //Handle watch points
  684. if(bToU)
  685. watcher.write_back = bToU;
  686. watcher.tick();
  687. //Swaps the Left channel with Right Channel
  688. if(swaplr)
  689. swap(outl, outr);
  690. //clean up the output samples (should not be needed?)
  691. memset(outl, 0, synth.bufferbytes);
  692. memset(outr, 0, synth.bufferbytes);
  693. //Compute part samples and store them part[npart]->partoutl,partoutr
  694. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  695. if(part[npart]->Penabled)
  696. part[npart]->ComputePartSmps();
  697. //Insertion effects
  698. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  699. if(Pinsparts[nefx] >= 0) {
  700. int efxpart = Pinsparts[nefx];
  701. if(part[efxpart]->Penabled)
  702. insefx[nefx]->out(part[efxpart]->partoutl,
  703. part[efxpart]->partoutr);
  704. }
  705. //Apply the part volumes and pannings (after insertion effects)
  706. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  707. if(!part[npart]->Penabled)
  708. continue;
  709. Stereo<float> newvol(part[npart]->volume),
  710. oldvol(part[npart]->oldvolumel,
  711. part[npart]->oldvolumer);
  712. float pan = part[npart]->panning;
  713. if(pan < 0.5f)
  714. newvol.l *= pan * 2.0f;
  715. else
  716. newvol.r *= (1.0f - pan) * 2.0f;
  717. //if(npart==0)
  718. //printf("[%d]vol = %f->%f\n", npart, oldvol.l, newvol.l);
  719. //the volume or the panning has changed and needs interpolation
  720. if(ABOVE_AMPLITUDE_THRESHOLD(oldvol.l, newvol.l)
  721. || ABOVE_AMPLITUDE_THRESHOLD(oldvol.r, newvol.r)) {
  722. for(int i = 0; i < synth.buffersize; ++i) {
  723. Stereo<float> vol(INTERPOLATE_AMPLITUDE(oldvol.l, newvol.l,
  724. i, synth.buffersize),
  725. INTERPOLATE_AMPLITUDE(oldvol.r, newvol.r,
  726. i, synth.buffersize));
  727. part[npart]->partoutl[i] *= vol.l;
  728. part[npart]->partoutr[i] *= vol.r;
  729. }
  730. part[npart]->oldvolumel = newvol.l;
  731. part[npart]->oldvolumer = newvol.r;
  732. }
  733. else {
  734. for(int i = 0; i < synth.buffersize; ++i) { //the volume did not changed
  735. part[npart]->partoutl[i] *= newvol.l;
  736. part[npart]->partoutr[i] *= newvol.r;
  737. }
  738. }
  739. }
  740. //System effects
  741. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) {
  742. if(sysefx[nefx]->geteffect() == 0)
  743. continue; //the effect is disabled
  744. float tmpmixl[synth.buffersize];
  745. float tmpmixr[synth.buffersize];
  746. //Clean up the samples used by the system effects
  747. memset(tmpmixl, 0, synth.bufferbytes);
  748. memset(tmpmixr, 0, synth.bufferbytes);
  749. //Mix the channels according to the part settings about System Effect
  750. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  751. //skip if the part has no output to effect
  752. if(Psysefxvol[nefx][npart] == 0)
  753. continue;
  754. //skip if the part is disabled
  755. if(part[npart]->Penabled == 0)
  756. continue;
  757. //the output volume of each part to system effect
  758. const float vol = sysefxvol[nefx][npart];
  759. for(int i = 0; i < synth.buffersize; ++i) {
  760. tmpmixl[i] += part[npart]->partoutl[i] * vol;
  761. tmpmixr[i] += part[npart]->partoutr[i] * vol;
  762. }
  763. }
  764. // system effect send to next ones
  765. for(int nefxfrom = 0; nefxfrom < nefx; ++nefxfrom)
  766. if(Psysefxsend[nefxfrom][nefx] != 0) {
  767. const float vol = sysefxsend[nefxfrom][nefx];
  768. for(int i = 0; i < synth.buffersize; ++i) {
  769. tmpmixl[i] += sysefx[nefxfrom]->efxoutl[i] * vol;
  770. tmpmixr[i] += sysefx[nefxfrom]->efxoutr[i] * vol;
  771. }
  772. }
  773. sysefx[nefx]->out(tmpmixl, tmpmixr);
  774. //Add the System Effect to sound output
  775. const float outvol = sysefx[nefx]->sysefxgetvolume();
  776. for(int i = 0; i < synth.buffersize; ++i) {
  777. outl[i] += tmpmixl[i] * outvol;
  778. outr[i] += tmpmixr[i] * outvol;
  779. }
  780. }
  781. //Mix all parts
  782. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  783. if(part[npart]->Penabled) //only mix active parts
  784. for(int i = 0; i < synth.buffersize; ++i) { //the volume did not changed
  785. outl[i] += part[npart]->partoutl[i];
  786. outr[i] += part[npart]->partoutr[i];
  787. }
  788. //Insertion effects for Master Out
  789. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  790. if(Pinsparts[nefx] == -2)
  791. insefx[nefx]->out(outl, outr);
  792. //Master Volume
  793. for(int i = 0; i < synth.buffersize; ++i) {
  794. outl[i] *= volume;
  795. outr[i] *= volume;
  796. }
  797. vuUpdate(outl, outr);
  798. //Shutup if it is asked (with fade-out)
  799. if(shutup) {
  800. for(int i = 0; i < synth.buffersize; ++i) {
  801. float tmp = (synth.buffersize_f - i) / synth.buffersize_f;
  802. outl[i] *= tmp;
  803. outr[i] *= tmp;
  804. }
  805. ShutUp();
  806. }
  807. //update the global frame timer
  808. time++;
  809. #ifdef DEMO_VERSION
  810. double seconds = time.time()*synth.buffersize_f/synth.samplerate_f;
  811. if(seconds > 10*60) {//10 minute trial
  812. shutup = true;
  813. for(int i = 0; i < synth.buffersize; ++i) {
  814. float tmp = (synth.buffersize_f - i) / synth.buffersize_f;
  815. outl[i] *= 0.0f;
  816. outr[i] *= 0.0f;
  817. }
  818. }
  819. #endif
  820. //Update pulse
  821. last_ack = last_beat;
  822. return true;
  823. }
  824. //TODO review the respective code from yoshimi for this
  825. //If memory serves correctly, libsamplerate was used
  826. void Master::GetAudioOutSamples(size_t nsamples,
  827. unsigned samplerate,
  828. float *outl,
  829. float *outr)
  830. {
  831. off_t out_off = 0;
  832. //Fail when resampling rather than doing a poor job
  833. if(synth.samplerate != samplerate) {
  834. printf("darn it: %d vs %d\n", synth.samplerate, samplerate);
  835. return;
  836. }
  837. while(nsamples) {
  838. //use all available samples
  839. if(nsamples >= smps) {
  840. memcpy(outl + out_off, bufl + off, sizeof(float) * smps);
  841. memcpy(outr + out_off, bufr + off, sizeof(float) * smps);
  842. nsamples -= smps;
  843. //generate samples
  844. if (! AudioOut(bufl, bufr))
  845. return;
  846. off = 0;
  847. out_off += smps;
  848. smps = synth.buffersize;
  849. }
  850. else { //use some samples
  851. memcpy(outl + out_off, bufl + off, sizeof(float) * nsamples);
  852. memcpy(outr + out_off, bufr + off, sizeof(float) * nsamples);
  853. smps -= nsamples;
  854. off += nsamples;
  855. nsamples = 0;
  856. }
  857. }
  858. }
  859. Master::~Master()
  860. {
  861. delete []bufl;
  862. delete []bufr;
  863. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  864. delete part[npart];
  865. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  866. delete insefx[nefx];
  867. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
  868. delete sysefx[nefx];
  869. delete fft;
  870. delete memory;
  871. }
  872. /*
  873. * Parameter control
  874. */
  875. void Master::setPvolume(char Pvolume_)
  876. {
  877. Pvolume = Pvolume_;
  878. volume = dB2rap((Pvolume - 96.0f) / 96.0f * 40.0f);
  879. }
  880. void Master::setPkeyshift(char Pkeyshift_)
  881. {
  882. Pkeyshift = Pkeyshift_;
  883. keyshift = (int)Pkeyshift - 64;
  884. }
  885. void Master::setPsysefxvol(int Ppart, int Pefx, char Pvol)
  886. {
  887. Psysefxvol[Pefx][Ppart] = Pvol;
  888. sysefxvol[Pefx][Ppart] = powf(0.1f, (1.0f - Pvol / 96.0f) * 2.0f);
  889. }
  890. void Master::setPsysefxsend(int Pefxfrom, int Pefxto, char Pvol)
  891. {
  892. Psysefxsend[Pefxfrom][Pefxto] = Pvol;
  893. sysefxsend[Pefxfrom][Pefxto] = powf(0.1f, (1.0f - Pvol / 96.0f) * 2.0f);
  894. }
  895. /*
  896. * Panic! (Clean up all parts and effects)
  897. */
  898. void Master::ShutUp()
  899. {
  900. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  901. part[npart]->cleanup();
  902. fakepeakpart[npart] = 0;
  903. }
  904. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)
  905. insefx[nefx]->cleanup();
  906. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
  907. sysefx[nefx]->cleanup();
  908. for(int i = 0; i < int(sizeof(activeNotes)/sizeof(activeNotes[0])); ++i)
  909. activeNotes[i] = 0;
  910. vuresetpeaks();
  911. shutup = 0;
  912. }
  913. /*
  914. * Reset peaks and clear the "cliped" flag (for VU-meter)
  915. */
  916. void Master::vuresetpeaks()
  917. {
  918. vu.outpeakl = 1e-9;
  919. vu.outpeakr = 1e-9;
  920. vu.maxoutpeakl = 1e-9;
  921. vu.maxoutpeakr = 1e-9;
  922. vu.clipped = 0;
  923. }
  924. void Master::applyparameters(void)
  925. {
  926. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
  927. part[npart]->applyparameters();
  928. }
  929. void Master::initialize_rt(void)
  930. {
  931. for(int i=0; i<NUM_SYS_EFX; ++i)
  932. sysefx[i]->init();
  933. for(int i=0; i<NUM_INS_EFX; ++i)
  934. insefx[i]->init();
  935. for(int i=0; i<NUM_MIDI_PARTS; ++i)
  936. part[i]->initialize_rt();
  937. }
  938. void Master::add2XML(XMLwrapper& xml)
  939. {
  940. xml.addpar("volume", Pvolume);
  941. xml.addpar("key_shift", Pkeyshift);
  942. xml.addparbool("nrpn_receive", ctl.NRPN.receive);
  943. xml.beginbranch("MICROTONAL");
  944. microtonal.add2XML(xml);
  945. xml.endbranch();
  946. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  947. xml.beginbranch("PART", npart);
  948. part[npart]->add2XML(xml);
  949. xml.endbranch();
  950. }
  951. xml.beginbranch("SYSTEM_EFFECTS");
  952. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) {
  953. xml.beginbranch("SYSTEM_EFFECT", nefx);
  954. xml.beginbranch("EFFECT");
  955. sysefx[nefx]->add2XML(xml);
  956. xml.endbranch();
  957. for(int pefx = 0; pefx < NUM_MIDI_PARTS; ++pefx) {
  958. xml.beginbranch("VOLUME", pefx);
  959. xml.addpar("vol", Psysefxvol[nefx][pefx]);
  960. xml.endbranch();
  961. }
  962. for(int tonefx = nefx + 1; tonefx < NUM_SYS_EFX; ++tonefx) {
  963. xml.beginbranch("SENDTO", tonefx);
  964. xml.addpar("send_vol", Psysefxsend[nefx][tonefx]);
  965. xml.endbranch();
  966. }
  967. xml.endbranch();
  968. }
  969. xml.endbranch();
  970. xml.beginbranch("INSERTION_EFFECTS");
  971. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) {
  972. xml.beginbranch("INSERTION_EFFECT", nefx);
  973. xml.addpar("part", Pinsparts[nefx]);
  974. xml.beginbranch("EFFECT");
  975. insefx[nefx]->add2XML(xml);
  976. xml.endbranch();
  977. xml.endbranch();
  978. }
  979. xml.endbranch();
  980. }
  981. int Master::getalldata(char **data)
  982. {
  983. XMLwrapper xml;
  984. xml.beginbranch("MASTER");
  985. add2XML(xml);
  986. xml.endbranch();
  987. *data = xml.getXMLdata();
  988. return strlen(*data) + 1;
  989. }
  990. void Master::putalldata(const char *data)
  991. {
  992. XMLwrapper xml;
  993. if(!xml.putXMLdata(data)) {
  994. return;
  995. }
  996. if(xml.enterbranch("MASTER") == 0)
  997. return;
  998. getfromXML(xml);
  999. xml.exitbranch();
  1000. }
  1001. int Master::saveXML(const char *filename)
  1002. {
  1003. XMLwrapper xml;
  1004. xml.beginbranch("MASTER");
  1005. add2XML(xml);
  1006. xml.endbranch();
  1007. return xml.saveXMLfile(filename, gzip_compression);
  1008. }
  1009. int Master::loadXML(const char *filename)
  1010. {
  1011. XMLwrapper xml;
  1012. if(xml.loadXMLfile(filename) < 0) {
  1013. return -1;
  1014. }
  1015. if(xml.enterbranch("MASTER") == 0)
  1016. return -10;
  1017. getfromXML(xml);
  1018. xml.exitbranch();
  1019. initialize_rt();
  1020. return 0;
  1021. }
  1022. void Master::getfromXML(XMLwrapper& xml)
  1023. {
  1024. setPvolume(xml.getpar127("volume", Pvolume));
  1025. setPkeyshift(xml.getpar127("key_shift", Pkeyshift));
  1026. ctl.NRPN.receive = xml.getparbool("nrpn_receive", ctl.NRPN.receive);
  1027. part[0]->Penabled = 0;
  1028. for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
  1029. if(xml.enterbranch("PART", npart) == 0)
  1030. continue;
  1031. part[npart]->getfromXML(xml);
  1032. xml.exitbranch();
  1033. }
  1034. if(xml.enterbranch("MICROTONAL")) {
  1035. microtonal.getfromXML(xml);
  1036. xml.exitbranch();
  1037. }
  1038. sysefx[0]->changeeffect(0);
  1039. if(xml.enterbranch("SYSTEM_EFFECTS")) {
  1040. for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) {
  1041. if(xml.enterbranch("SYSTEM_EFFECT", nefx) == 0)
  1042. continue;
  1043. if(xml.enterbranch("EFFECT")) {
  1044. sysefx[nefx]->getfromXML(xml);
  1045. xml.exitbranch();
  1046. }
  1047. for(int partefx = 0; partefx < NUM_MIDI_PARTS; ++partefx) {
  1048. if(xml.enterbranch("VOLUME", partefx) == 0)
  1049. continue;
  1050. setPsysefxvol(partefx, nefx,
  1051. xml.getpar127("vol", Psysefxvol[partefx][nefx]));
  1052. xml.exitbranch();
  1053. }
  1054. for(int tonefx = nefx + 1; tonefx < NUM_SYS_EFX; ++tonefx) {
  1055. if(xml.enterbranch("SENDTO", tonefx) == 0)
  1056. continue;
  1057. setPsysefxsend(nefx, tonefx,
  1058. xml.getpar127("send_vol",
  1059. Psysefxsend[nefx][tonefx]));
  1060. xml.exitbranch();
  1061. }
  1062. xml.exitbranch();
  1063. }
  1064. xml.exitbranch();
  1065. }
  1066. if(xml.enterbranch("INSERTION_EFFECTS")) {
  1067. for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) {
  1068. if(xml.enterbranch("INSERTION_EFFECT", nefx) == 0)
  1069. continue;
  1070. Pinsparts[nefx] = xml.getpar("part",
  1071. Pinsparts[nefx],
  1072. -2,
  1073. NUM_MIDI_PARTS);
  1074. if(xml.enterbranch("EFFECT")) {
  1075. insefx[nefx]->getfromXML(xml);
  1076. xml.exitbranch();
  1077. }
  1078. xml.exitbranch();
  1079. }
  1080. xml.exitbranch();
  1081. }
  1082. }