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.

EffectMgr.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. EffectMgr.cpp - Effect manager, an interface betwen the program and effects
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include <rtosc/ports.h>
  12. #include <rtosc/port-sugar.h>
  13. #include <iostream>
  14. #include <cassert>
  15. #include "EffectMgr.h"
  16. #include "Effect.h"
  17. #include "Alienwah.h"
  18. #include "Reverb.h"
  19. #include "Echo.h"
  20. #include "Chorus.h"
  21. #include "Distorsion.h"
  22. #include "EQ.h"
  23. #include "DynamicFilter.h"
  24. #include "Phaser.h"
  25. #include "../Misc/XMLwrapper.h"
  26. #include "../Misc/Util.h"
  27. #include "../Params/FilterParams.h"
  28. #include "../Misc/Allocator.h"
  29. namespace zyncarla {
  30. #define rObject EffectMgr
  31. #define rSubtype(name) \
  32. {STRINGIFY(name)"/", NULL, &name::ports,\
  33. [](const char *msg, rtosc::RtData &data){\
  34. rObject &o = *(rObject*)data.obj; \
  35. data.obj = dynamic_cast<name*>(o.efx); \
  36. if(!data.obj) \
  37. return; \
  38. SNIP \
  39. name::ports.dispatch(msg, data); \
  40. }}
  41. static const rtosc::Ports local_ports = {
  42. rSelf(EffectMgr, rEnabledByCondition(self-enabled)),
  43. rPaste,
  44. rEnabledCondition(self-enabled, obj->geteffect()),
  45. rRecurp(filterpars, "Filter Parameter for Dynamic Filter"),
  46. {"Pvolume::i", rProp(parameter) rLinear(0,127) rShort("amt") rDoc("amount of effect"),
  47. 0,
  48. [](const char *msg, rtosc::RtData &d)
  49. {
  50. EffectMgr *eff = (EffectMgr*)d.obj;
  51. if(!rtosc_narguments(msg))
  52. d.reply(d.loc, "i", eff->geteffectparrt(0));
  53. else if(rtosc_type(msg, 0) == 'i'){
  54. eff->seteffectparrt(0, rtosc_argument(msg, 0).i);
  55. d.broadcast(d.loc, "i", eff->geteffectparrt(0));
  56. }
  57. }},
  58. {"Ppanning::i", rProp(parameter) rLinear(0,127) rShort("pan") rDoc("panning"),
  59. 0,
  60. [](const char *msg, rtosc::RtData &d)
  61. {
  62. EffectMgr *eff = (EffectMgr*)d.obj;
  63. if(!rtosc_narguments(msg))
  64. d.reply(d.loc, "i", eff->geteffectparrt(1));
  65. else if(rtosc_type(msg, 0) == 'i'){
  66. eff->seteffectparrt(1, rtosc_argument(msg, 0).i);
  67. d.broadcast(d.loc, "i", eff->geteffectparrt(1));
  68. }
  69. }},
  70. {"parameter#128::i:T:F", rProp(parameter) rProp(alias) rLinear(0,127) rDoc("Parameter Accessor"),
  71. NULL,
  72. [](const char *msg, rtosc::RtData &d)
  73. {
  74. EffectMgr *eff = (EffectMgr*)d.obj;
  75. const char *mm = msg;
  76. while(!isdigit(*mm))++mm;
  77. if(!rtosc_narguments(msg))
  78. d.reply(d.loc, "i", eff->geteffectparrt(atoi(mm)));
  79. else if(rtosc_type(msg, 0) == 'i'){
  80. eff->seteffectparrt(atoi(mm), rtosc_argument(msg, 0).i);
  81. d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
  82. } else if(rtosc_type(msg, 0) == 'T'){
  83. eff->seteffectparrt(atoi(mm), 127);
  84. d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
  85. } else if(rtosc_type(msg, 0) == 'F'){
  86. eff->seteffectparrt(atoi(mm), 0);
  87. d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
  88. }
  89. }},
  90. {"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector")
  91. rDefault(0), NULL,
  92. [](const char *msg, rtosc::RtData &d)
  93. {
  94. char loc[1024];
  95. EffectMgr *eff = (EffectMgr*)d.obj;
  96. if(!rtosc_narguments(msg))
  97. d.reply(d.loc, "i", eff->getpreset());
  98. else {
  99. eff->changepresetrt(rtosc_argument(msg, 0).i);
  100. d.broadcast(d.loc, "i", eff->getpreset());
  101. //update parameters as well
  102. strncpy(loc, d.loc, 1024);
  103. char *tail = strrchr(loc, '/');
  104. if(!tail)
  105. return;
  106. for(int i=0;i<128;++i) {
  107. sprintf(tail+1, "parameter%d", i);
  108. d.broadcast(loc, "i", eff->geteffectparrt(i));
  109. }
  110. }
  111. }},
  112. {"eq-coeffs:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL,
  113. [](const char *, rtosc::RtData &d)
  114. {
  115. EffectMgr *eff = (EffectMgr*)d.obj;
  116. if(eff->nefx != 7)
  117. return;
  118. EQ *eq = (EQ*)eff->efx;
  119. float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
  120. float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
  121. memset(a, 0, sizeof(a));
  122. memset(b, 0, sizeof(b));
  123. eq->getFilter(a,b);
  124. d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b);
  125. }},
  126. {"efftype::i:c:S", rOptions(Disabled, Reverb, Echo, Chorus,
  127. Phaser, Alienwah, Distortion, EQ, DynFilter) rDefault(Disabled)
  128. rProp(parameter) rDoc("Get Effect Type"), NULL,
  129. rCOptionCb(obj->nefx, obj->changeeffectrt(var))},
  130. {"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL,
  131. [](const char *msg, rtosc::RtData &d)
  132. {
  133. printf("OBSOLETE METHOD CALLED\n");
  134. EffectMgr *eff = (EffectMgr*)d.obj;
  135. EffectMgr *eff_ = *(EffectMgr**)rtosc_argument(msg,0).b.data;
  136. //Lets trade data
  137. std::swap(eff->nefx,eff_->nefx);
  138. std::swap(eff->efx,eff_->efx);
  139. std::swap(eff->filterpars,eff_->filterpars);
  140. std::swap(eff->efxoutl, eff_->efxoutl);
  141. std::swap(eff->efxoutr, eff_->efxoutr);
  142. //Return the old data for distruction
  143. d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_);
  144. }},
  145. rSubtype(Alienwah),
  146. rSubtype(Chorus),
  147. rSubtype(Distorsion),
  148. rSubtype(DynamicFilter),
  149. rSubtype(Echo),
  150. rSubtype(EQ),
  151. rSubtype(Phaser),
  152. rSubtype(Reverb),
  153. };
  154. const rtosc::Ports &EffectMgr::ports = local_ports;
  155. EffectMgr::EffectMgr(Allocator &alloc, const SYNTH_T &synth_,
  156. const bool insertion_, const AbsTime *time_)
  157. :insertion(insertion_),
  158. efxoutl(new float[synth_.buffersize]),
  159. efxoutr(new float[synth_.buffersize]),
  160. filterpars(new FilterParams(time_)),
  161. nefx(0),
  162. efx(NULL),
  163. time(time_),
  164. dryonly(false),
  165. memory(alloc),
  166. synth(synth_)
  167. {
  168. setpresettype("Peffect");
  169. memset(efxoutl, 0, synth.bufferbytes);
  170. memset(efxoutr, 0, synth.bufferbytes);
  171. memset(settings, 0, sizeof(settings));
  172. defaults();
  173. }
  174. EffectMgr::~EffectMgr()
  175. {
  176. memory.dealloc(efx);
  177. delete filterpars;
  178. delete [] efxoutl;
  179. delete [] efxoutr;
  180. }
  181. void EffectMgr::defaults(void)
  182. {
  183. changeeffect(0);
  184. setdryonly(false);
  185. }
  186. //Change the effect
  187. void EffectMgr::changeeffectrt(int _nefx, bool avoidSmash)
  188. {
  189. cleanup();
  190. if(nefx == _nefx && efx != NULL)
  191. return;
  192. nefx = _nefx;
  193. memset(efxoutl, 0, synth.bufferbytes);
  194. memset(efxoutr, 0, synth.bufferbytes);
  195. memory.dealloc(efx);
  196. EffectParams pars(memory, insertion, efxoutl, efxoutr, 0,
  197. synth.samplerate, synth.buffersize, filterpars, avoidSmash);
  198. try {
  199. switch (nefx) {
  200. case 1:
  201. efx = memory.alloc<Reverb>(pars);
  202. break;
  203. case 2:
  204. efx = memory.alloc<Echo>(pars);
  205. break;
  206. case 3:
  207. efx = memory.alloc<Chorus>(pars);
  208. break;
  209. case 4:
  210. efx = memory.alloc<Phaser>(pars);
  211. break;
  212. case 5:
  213. efx = memory.alloc<Alienwah>(pars);
  214. break;
  215. case 6:
  216. efx = memory.alloc<Distorsion>(pars);
  217. break;
  218. case 7:
  219. efx = memory.alloc<EQ>(pars);
  220. break;
  221. case 8:
  222. efx = memory.alloc<DynamicFilter>(pars, time);
  223. break;
  224. //put more effect here
  225. default:
  226. efx = NULL;
  227. break; //no effect (thru)
  228. }
  229. } catch (std::bad_alloc &ba) {
  230. std::cerr << "failed to change effect " << _nefx << ": " << ba.what() << std::endl;
  231. return;
  232. }
  233. if(!avoidSmash)
  234. for(int i=0; i<128; ++i)
  235. settings[i] = geteffectparrt(i);
  236. }
  237. void EffectMgr::changeeffect(int _nefx)
  238. {
  239. nefx = _nefx;
  240. //preset = 0;
  241. //memset(settings, 0, sizeof(settings));
  242. }
  243. //Obtain the effect number
  244. int EffectMgr::geteffect(void)
  245. {
  246. return nefx;
  247. }
  248. // Initialize An Effect in RT context
  249. void EffectMgr::init(void)
  250. {
  251. kill();
  252. changeeffectrt(nefx, true);
  253. changepresetrt(preset, true);
  254. for(int i=0; i<128; ++i)
  255. seteffectparrt(i, settings[i]);
  256. }
  257. //Strip effect manager of it's realtime memory
  258. void EffectMgr::kill(void)
  259. {
  260. //printf("Killing Effect(%d)\n", nefx);
  261. memory.dealloc(efx);
  262. }
  263. // Cleanup the current effect
  264. void EffectMgr::cleanup(void)
  265. {
  266. if(efx)
  267. efx->cleanup();
  268. }
  269. // Get the preset of the current effect
  270. unsigned char EffectMgr::getpreset(void)
  271. {
  272. if(efx)
  273. return efx->Ppreset;
  274. else
  275. return 0;
  276. }
  277. // Change the preset of the current effect
  278. void EffectMgr::changepreset(unsigned char npreset)
  279. {
  280. preset = npreset;
  281. }
  282. // Change the preset of the current effect
  283. void EffectMgr::changepresetrt(unsigned char npreset, bool avoidSmash)
  284. {
  285. preset = npreset;
  286. if(avoidSmash && dynamic_cast<DynamicFilter*>(efx)) {
  287. efx->Ppreset = npreset;
  288. return;
  289. }
  290. if(efx)
  291. efx->setpreset(npreset);
  292. if(!avoidSmash)
  293. for(int i=0; i<128; ++i)
  294. settings[i] = geteffectparrt(i);
  295. }
  296. //Change a parameter of the current effect
  297. void EffectMgr::seteffectparrt(int npar, unsigned char value)
  298. {
  299. if(npar<128)
  300. settings[npar] = value;
  301. if(!efx)
  302. return;
  303. try {
  304. efx->changepar(npar, value);
  305. } catch (std::bad_alloc &ba) {
  306. std::cerr << "failed to change effect parameter " << npar << " to " << value << ": " << ba.what() << std::endl;
  307. }
  308. }
  309. //Change a parameter of the current effect
  310. void EffectMgr::seteffectpar(int npar, unsigned char value)
  311. {
  312. settings[npar] = value;
  313. }
  314. //Get a parameter of the current effect
  315. unsigned char EffectMgr::geteffectpar(int npar)
  316. {
  317. if(npar<128)
  318. return settings[npar];
  319. if(!efx)
  320. return 0;
  321. return efx->getpar(npar);
  322. }
  323. unsigned char EffectMgr::geteffectparrt(int npar)
  324. {
  325. if(!efx)
  326. return 0;
  327. return efx->getpar(npar);
  328. }
  329. // Apply the effect
  330. void EffectMgr::out(float *smpsl, float *smpsr)
  331. {
  332. if(!efx) {
  333. if(!insertion)
  334. for(int i = 0; i < synth.buffersize; ++i) {
  335. smpsl[i] = 0.0f;
  336. smpsr[i] = 0.0f;
  337. efxoutl[i] = 0.0f;
  338. efxoutr[i] = 0.0f;
  339. }
  340. return;
  341. }
  342. for(int i = 0; i < synth.buffersize; ++i) {
  343. smpsl[i] += synth.denormalkillbuf[i];
  344. smpsr[i] += synth.denormalkillbuf[i];
  345. efxoutl[i] = 0.0f;
  346. efxoutr[i] = 0.0f;
  347. }
  348. efx->out(smpsl, smpsr);
  349. float volume = efx->volume;
  350. if(nefx == 7) { //this is need only for the EQ effect
  351. memcpy(smpsl, efxoutl, synth.bufferbytes);
  352. memcpy(smpsr, efxoutr, synth.bufferbytes);
  353. return;
  354. }
  355. //Insertion effect
  356. if(insertion != 0) {
  357. float v1, v2;
  358. if(volume < 0.5f) {
  359. v1 = 1.0f;
  360. v2 = volume * 2.0f;
  361. }
  362. else {
  363. v1 = (1.0f - volume) * 2.0f;
  364. v2 = 1.0f;
  365. }
  366. if((nefx == 1) || (nefx == 2))
  367. v2 *= v2; //for Reverb and Echo, the wet function is not liniar
  368. if(dryonly) //this is used for instrument effect only
  369. for(int i = 0; i < synth.buffersize; ++i) {
  370. smpsl[i] *= v1;
  371. smpsr[i] *= v1;
  372. efxoutl[i] *= v2;
  373. efxoutr[i] *= v2;
  374. }
  375. else // normal instrument/insertion effect
  376. for(int i = 0; i < synth.buffersize; ++i) {
  377. smpsl[i] = smpsl[i] * v1 + efxoutl[i] * v2;
  378. smpsr[i] = smpsr[i] * v1 + efxoutr[i] * v2;
  379. }
  380. }
  381. else // System effect
  382. for(int i = 0; i < synth.buffersize; ++i) {
  383. efxoutl[i] *= 2.0f * volume;
  384. efxoutr[i] *= 2.0f * volume;
  385. smpsl[i] = efxoutl[i];
  386. smpsr[i] = efxoutr[i];
  387. }
  388. }
  389. // Get the effect volume for the system effect
  390. float EffectMgr::sysefxgetvolume(void)
  391. {
  392. return efx ? efx->outvolume : 1.0f;
  393. }
  394. // Get the EQ response
  395. float EffectMgr::getEQfreqresponse(float freq)
  396. {
  397. return (nefx == 7) ? efx->getfreqresponse(freq) : 0.0f;
  398. }
  399. void EffectMgr::setdryonly(bool value)
  400. {
  401. dryonly = value;
  402. }
  403. void EffectMgr::paste(EffectMgr &e)
  404. {
  405. changeeffectrt(e.nefx, true);
  406. changepresetrt(e.preset, true);
  407. for(int i=0;i<128;++i)
  408. seteffectparrt(i, e.settings[i]);
  409. if(dynamic_cast<DynamicFilter*>(efx)) {
  410. std::swap(filterpars, e.filterpars);
  411. efx->filterpars = filterpars;
  412. }
  413. cleanup(); // cleanup the effect and recompute its parameters
  414. }
  415. void EffectMgr::add2XML(XMLwrapper& xml)
  416. {
  417. xml.addpar("type", geteffect());
  418. if(!geteffect())
  419. return;
  420. xml.addpar("preset", preset);
  421. xml.beginbranch("EFFECT_PARAMETERS");
  422. for(int n = 0; n < 128; ++n) {
  423. int par = 0;
  424. if(efx)
  425. par = efx->getpar(n);
  426. else if(n<128)
  427. par = settings[n];
  428. if(par == 0)
  429. continue;
  430. xml.beginbranch("par_no", n);
  431. xml.addpar("par", par);
  432. xml.endbranch();
  433. }
  434. assert(filterpars);
  435. if(nefx == 8) {
  436. xml.beginbranch("FILTER");
  437. filterpars->add2XML(xml);
  438. xml.endbranch();
  439. }
  440. xml.endbranch();
  441. }
  442. void EffectMgr::getfromXML(XMLwrapper& xml)
  443. {
  444. changeeffect(xml.getpar127("type", geteffect()));
  445. if(!geteffect())
  446. return;
  447. preset = xml.getpar127("preset", preset);
  448. if(xml.enterbranch("EFFECT_PARAMETERS")) {
  449. for(int n = 0; n < 128; ++n) {
  450. seteffectpar(n, 0); //erase effect parameter
  451. if(xml.enterbranch("par_no", n) == 0)
  452. continue;
  453. int par = geteffectpar(n);
  454. seteffectpar(n, xml.getpar127("par", par));
  455. xml.exitbranch();
  456. }
  457. assert(filterpars);
  458. if(xml.enterbranch("FILTER")) {
  459. filterpars->getfromXML(xml);
  460. xml.exitbranch();
  461. }
  462. xml.exitbranch();
  463. }
  464. cleanup();
  465. }
  466. }