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.

Controller.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Controller.cpp - (Midi) Controllers implementation
  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 modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include "Controller.h"
  18. #include "../Misc/Util.h"
  19. #include "../Misc/XMLwrapper.h"
  20. #include <cmath>
  21. #include <cstdio>
  22. #include <rtosc/ports.h>
  23. #include <rtosc/port-sugar.h>
  24. using namespace rtosc;
  25. #define rObject Controller
  26. const rtosc::Ports Controller::ports = {
  27. rParamZyn(panning.depth, "Depth of Panning MIDI Control"),
  28. rParamZyn(filtercutoff.depth, "Depth of Filter Cutoff MIDI Control"),
  29. rParamZyn(filterq.depth, "Depth of Filter Q MIDI Control"),
  30. rParamZyn(bandwidth.depth, "Depth of Bandwidth MIDI Control"),
  31. rToggle(bandwidth.exponential, "Bandwidth Exponential Mode"),
  32. rParamZyn(modwheel.depth, "Depth of Modwheel MIDI Control"),
  33. rToggle(modwheel.exponential, "Modwheel Exponential Mode"),
  34. rToggle(pitchwheel.is_split, "If PitchWheel Has unified blendrange or not"),
  35. rParamI(pitchwheel.bendrange, "Range of MIDI Pitch Wheel"),
  36. rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"),
  37. rToggle(expression.receive, "Expression MIDI Receive"),
  38. rToggle(fmamp.receive, "FM amplitude MIDI Receive"),
  39. rToggle(volume.receive, "Volume MIDI Receive"),
  40. rToggle(sustain.receive, "Sustain MIDI Receive"),
  41. rToggle(portamento.receive, "Portamento MIDI Receive"),
  42. rToggle(portamento.portamento, "UNDOCUMENTED"),
  43. rParamZyn(portamento.time, "Portamento Length"),
  44. rToggle(portamento.proportional, "If all portamentos are proportional to the distance they span"),
  45. rParamZyn(portamento.propRate, "Portamento proportional rate"),
  46. rParamZyn(portamento.propDepth, "Portamento proportional depth"),
  47. rParamZyn(portamento.pitchthresh, "Threshold for portamento"),
  48. rToggle(portamento.pitchthreshtype, "Type of threshold"),
  49. rParamZyn(portamento.updowntimestretch, "UNDOCUMENTED"),
  50. rParamZyn(resonancecenter.depth, "Resonance Center MIDI Depth"),
  51. rParamZyn(resonancebandwidth.depth, "Resonance Bandwidth MIDI Depth"),
  52. rToggle(NRPN.receive, "NRPN MIDI Enable"),
  53. rAction(defaults),
  54. };
  55. Controller::Controller(const SYNTH_T &synth_)
  56. :synth(synth_)
  57. {
  58. defaults();
  59. resetall();
  60. }
  61. Controller &Controller::operator=(const Controller &c)
  62. {
  63. //just pretend that undefined behavior doesn't exist...
  64. memcpy(this, &c, sizeof(Controller));
  65. return *this;
  66. }
  67. Controller::~Controller()
  68. {}
  69. void Controller::defaults()
  70. {
  71. pitchwheel.bendrange = 200; //2 halftones
  72. pitchwheel.bendrange_down = 0; //Unused by default
  73. pitchwheel.is_split = false;
  74. expression.receive = 1;
  75. panning.depth = 64;
  76. filtercutoff.depth = 64;
  77. filterq.depth = 64;
  78. bandwidth.depth = 64;
  79. bandwidth.exponential = 0;
  80. modwheel.depth = 80;
  81. modwheel.exponential = 0;
  82. fmamp.receive = 1;
  83. volume.receive = 1;
  84. sustain.receive = 1;
  85. NRPN.receive = 1;
  86. portamento.portamento = 0;
  87. portamento.used = 0;
  88. portamento.proportional = 0;
  89. portamento.propRate = 80;
  90. portamento.propDepth = 90;
  91. portamento.receive = 1;
  92. portamento.time = 64;
  93. portamento.updowntimestretch = 64;
  94. portamento.pitchthresh = 3;
  95. portamento.pitchthreshtype = 1;
  96. portamento.noteusing = -1;
  97. resonancecenter.depth = 64;
  98. resonancebandwidth.depth = 64;
  99. initportamento(440.0f, 440.0f, false); // Now has a third argument
  100. setportamento(0);
  101. }
  102. void Controller::resetall()
  103. {
  104. setpitchwheel(0); //center
  105. setexpression(127);
  106. setpanning(64);
  107. setfiltercutoff(64);
  108. setfilterq(64);
  109. setbandwidth(64);
  110. setmodwheel(64);
  111. setfmamp(127);
  112. setvolume(127);
  113. setsustain(0);
  114. setresonancecenter(64);
  115. setresonancebw(64);
  116. //reset the NRPN
  117. NRPN.parhi = -1;
  118. NRPN.parlo = -1;
  119. NRPN.valhi = -1;
  120. NRPN.vallo = -1;
  121. }
  122. void Controller::setpitchwheel(int value)
  123. {
  124. pitchwheel.data = value;
  125. float cents = value / 8192.0f;
  126. if(pitchwheel.is_split && cents < 0)
  127. cents *= pitchwheel.bendrange_down;
  128. else
  129. cents *= pitchwheel.bendrange;
  130. pitchwheel.relfreq = powf(2, cents / 1200.0f);
  131. //fprintf(stderr,"%ld %ld -> %.3f\n",pitchwheel.bendrange,pitchwheel.data,pitchwheel.relfreq);fflush(stderr);
  132. }
  133. void Controller::setexpression(int value)
  134. {
  135. expression.data = value;
  136. if(expression.receive != 0)
  137. expression.relvolume = value / 127.0f;
  138. else
  139. expression.relvolume = 1.0f;
  140. }
  141. void Controller::setpanning(int value)
  142. {
  143. panning.data = value;
  144. panning.pan = (value / 128.0f - 0.5f) * (panning.depth / 64.0f);
  145. }
  146. void Controller::setfiltercutoff(int value)
  147. {
  148. filtercutoff.data = value;
  149. filtercutoff.relfreq =
  150. (value - 64.0f) * filtercutoff.depth / 4096.0f * 3.321928f; //3.3219f..=ln2(10)
  151. }
  152. void Controller::setfilterq(int value)
  153. {
  154. filterq.data = value;
  155. filterq.relq = powf(30.0f, (value - 64.0f) / 64.0f * (filterq.depth / 64.0f));
  156. }
  157. void Controller::setbandwidth(int value)
  158. {
  159. bandwidth.data = value;
  160. if(bandwidth.exponential == 0) {
  161. float tmp = powf(25.0f, powf(bandwidth.depth / 127.0f, 1.5f)) - 1.0f;
  162. if((value < 64) && (bandwidth.depth >= 64))
  163. tmp = 1.0f;
  164. bandwidth.relbw = (value / 64.0f - 1.0f) * tmp + 1.0f;
  165. if(bandwidth.relbw < 0.01f)
  166. bandwidth.relbw = 0.01f;
  167. }
  168. else
  169. bandwidth.relbw =
  170. powf(25.0f, (value - 64.0f) / 64.0f * (bandwidth.depth / 64.0f));
  171. ;
  172. }
  173. void Controller::setmodwheel(int value)
  174. {
  175. modwheel.data = value;
  176. if(modwheel.exponential == 0) {
  177. float tmp =
  178. powf(25.0f, powf(modwheel.depth / 127.0f, 1.5f) * 2.0f) / 25.0f;
  179. if((value < 64) && (modwheel.depth >= 64))
  180. tmp = 1.0f;
  181. modwheel.relmod = (value / 64.0f - 1.0f) * tmp + 1.0f;
  182. if(modwheel.relmod < 0.0f)
  183. modwheel.relmod = 0.0f;
  184. }
  185. else
  186. modwheel.relmod =
  187. powf(25.0f, (value - 64.0f) / 64.0f * (modwheel.depth / 80.0f));
  188. }
  189. void Controller::setfmamp(int value)
  190. {
  191. fmamp.data = value;
  192. fmamp.relamp = value / 127.0f;
  193. if(fmamp.receive != 0)
  194. fmamp.relamp = value / 127.0f;
  195. else
  196. fmamp.relamp = 1.0f;
  197. }
  198. void Controller::setvolume(int value)
  199. {
  200. volume.data = value;
  201. if(volume.receive != 0)
  202. volume.volume = powf(0.1f, (127 - value) / 127.0f * 2.0f);
  203. else
  204. volume.volume = 1.0f;
  205. }
  206. void Controller::setsustain(int value)
  207. {
  208. sustain.data = value;
  209. if(sustain.receive != 0)
  210. sustain.sustain = ((value < 64) ? 0 : 1);
  211. else
  212. sustain.sustain = 0;
  213. }
  214. void Controller::setportamento(int value)
  215. {
  216. portamento.data = value;
  217. if(portamento.receive != 0)
  218. portamento.portamento = ((value < 64) ? 0 : 1);
  219. }
  220. int Controller::initportamento(float oldfreq,
  221. float newfreq,
  222. bool legatoflag)
  223. {
  224. portamento.x = 0.0f;
  225. if(legatoflag) { // Legato in progress
  226. if(portamento.portamento == 0)
  227. return 0;
  228. }
  229. else // No legato, do the original if...return
  230. if((portamento.used != 0) || (portamento.portamento == 0))
  231. return 0;
  232. ;
  233. float portamentotime = powf(100.0f, portamento.time / 127.0f) / 50.0f; //portamento time in seconds
  234. if(portamento.proportional) {
  235. //If there is a min(float,float) and a max(float,float) then they
  236. //could be used here
  237. //Linear functors could also make this nicer
  238. if(oldfreq > newfreq) //2 is the center of propRate
  239. portamentotime *=
  240. powf(oldfreq / newfreq
  241. / (portamento.propRate / 127.0f * 3 + .05),
  242. (portamento.propDepth / 127.0f * 1.6f + .2));
  243. else //1 is the center of propDepth
  244. portamentotime *=
  245. powf(newfreq / oldfreq
  246. / (portamento.propRate / 127.0f * 3 + .05),
  247. (portamento.propDepth / 127.0f * 1.6f + .2));
  248. }
  249. if((portamento.updowntimestretch >= 64) && (newfreq < oldfreq)) {
  250. if(portamento.updowntimestretch == 127)
  251. return 0;
  252. portamentotime *= powf(0.1f,
  253. (portamento.updowntimestretch - 64) / 63.0f);
  254. }
  255. if((portamento.updowntimestretch < 64) && (newfreq > oldfreq)) {
  256. if(portamento.updowntimestretch == 0)
  257. return 0;
  258. portamentotime *= powf(0.1f,
  259. (64.0f - portamento.updowntimestretch) / 64.0f);
  260. }
  261. //printf("%f->%f : Time %f\n",oldfreq,newfreq,portamentotime);
  262. portamento.dx = synth.buffersize_f / (portamentotime * synth.samplerate_f);
  263. portamento.origfreqrap = oldfreq / newfreq;
  264. float tmprap = ((portamento.origfreqrap > 1.0f) ?
  265. (portamento.origfreqrap) :
  266. (1.0f / portamento.origfreqrap));
  267. float thresholdrap = powf(2.0f, portamento.pitchthresh / 12.0f);
  268. if((portamento.pitchthreshtype == 0) && (tmprap - 0.00001f > thresholdrap))
  269. return 0;
  270. if((portamento.pitchthreshtype == 1) && (tmprap + 0.00001f < thresholdrap))
  271. return 0;
  272. portamento.used = 1;
  273. portamento.freqrap = portamento.origfreqrap;
  274. return 1;
  275. }
  276. void Controller::updateportamento()
  277. {
  278. if(portamento.used == 0)
  279. return;
  280. portamento.x += portamento.dx;
  281. if(portamento.x > 1.0f) {
  282. portamento.x = 1.0f;
  283. portamento.used = 0;
  284. }
  285. portamento.freqrap =
  286. (1.0f - portamento.x) * portamento.origfreqrap + portamento.x;
  287. }
  288. void Controller::setresonancecenter(int value)
  289. {
  290. resonancecenter.data = value;
  291. resonancecenter.relcenter =
  292. powf(3.0f, (value - 64.0f) / 64.0f * (resonancecenter.depth / 64.0f));
  293. }
  294. void Controller::setresonancebw(int value)
  295. {
  296. resonancebandwidth.data = value;
  297. resonancebandwidth.relbw =
  298. powf(1.5f, (value - 64.0f) / 64.0f * (resonancebandwidth.depth / 127.0f));
  299. }
  300. //Returns 0 if there is NRPN or 1 if there is not
  301. int Controller::getnrpn(int *parhi, int *parlo, int *valhi, int *vallo)
  302. {
  303. if(NRPN.receive == 0)
  304. return 1;
  305. if((NRPN.parhi < 0) || (NRPN.parlo < 0) || (NRPN.valhi < 0)
  306. || (NRPN.vallo < 0))
  307. return 1;
  308. *parhi = NRPN.parhi;
  309. *parlo = NRPN.parlo;
  310. *valhi = NRPN.valhi;
  311. *vallo = NRPN.vallo;
  312. return 0;
  313. }
  314. void Controller::setparameternumber(unsigned int type, int value)
  315. {
  316. switch(type) {
  317. case C_nrpnhi:
  318. NRPN.parhi = value;
  319. NRPN.valhi = -1;
  320. NRPN.vallo = -1; //clear the values
  321. break;
  322. case C_nrpnlo:
  323. NRPN.parlo = value;
  324. NRPN.valhi = -1;
  325. NRPN.vallo = -1; //clear the values
  326. break;
  327. case C_dataentryhi:
  328. if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
  329. NRPN.valhi = value;
  330. break;
  331. case C_dataentrylo:
  332. if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
  333. NRPN.vallo = value;
  334. break;
  335. }
  336. }
  337. void Controller::add2XML(XMLwrapper *xml)
  338. {
  339. xml->addpar("pitchwheel_bendrange", pitchwheel.bendrange);
  340. xml->addpar("pitchwheel_bendrange_down", pitchwheel.bendrange_down);
  341. xml->addparbool("pitchwheel_split", pitchwheel.is_split);
  342. xml->addparbool("expression_receive", expression.receive);
  343. xml->addpar("panning_depth", panning.depth);
  344. xml->addpar("filter_cutoff_depth", filtercutoff.depth);
  345. xml->addpar("filter_q_depth", filterq.depth);
  346. xml->addpar("bandwidth_depth", bandwidth.depth);
  347. xml->addpar("mod_wheel_depth", modwheel.depth);
  348. xml->addparbool("mod_wheel_exponential", modwheel.exponential);
  349. xml->addparbool("fm_amp_receive", fmamp.receive);
  350. xml->addparbool("volume_receive", volume.receive);
  351. xml->addparbool("sustain_receive", sustain.receive);
  352. xml->addparbool("portamento_receive", portamento.receive);
  353. xml->addpar("portamento_time", portamento.time);
  354. xml->addpar("portamento_pitchthresh", portamento.pitchthresh);
  355. xml->addpar("portamento_pitchthreshtype", portamento.pitchthreshtype);
  356. xml->addpar("portamento_portamento", portamento.portamento);
  357. xml->addpar("portamento_updowntimestretch", portamento.updowntimestretch);
  358. xml->addpar("portamento_proportional", portamento.proportional);
  359. xml->addpar("portamento_proprate", portamento.propRate);
  360. xml->addpar("portamento_propdepth", portamento.propDepth);
  361. xml->addpar("resonance_center_depth", resonancecenter.depth);
  362. xml->addpar("resonance_bandwidth_depth", resonancebandwidth.depth);
  363. }
  364. void Controller::getfromXML(XMLwrapper *xml)
  365. {
  366. pitchwheel.bendrange = xml->getpar("pitchwheel_bendrange",
  367. pitchwheel.bendrange,
  368. -6400,
  369. 6400);
  370. pitchwheel.bendrange_down = xml->getpar("pitchwheel_bendrange_down",
  371. pitchwheel.bendrange_down,
  372. -6400,
  373. 6400);
  374. pitchwheel.is_split = xml->getparbool("pitchwheel_split",
  375. pitchwheel.is_split);
  376. expression.receive = xml->getparbool("expression_receive",
  377. expression.receive);
  378. panning.depth = xml->getpar127("panning_depth", panning.depth);
  379. filtercutoff.depth = xml->getpar127("filter_cutoff_depth",
  380. filtercutoff.depth);
  381. filterq.depth = xml->getpar127("filter_q_depth", filterq.depth);
  382. bandwidth.depth = xml->getpar127("bandwidth_depth", bandwidth.depth);
  383. modwheel.depth = xml->getpar127("mod_wheel_depth", modwheel.depth);
  384. modwheel.exponential = xml->getparbool("mod_wheel_exponential",
  385. modwheel.exponential);
  386. fmamp.receive = xml->getparbool("fm_amp_receive",
  387. fmamp.receive);
  388. volume.receive = xml->getparbool("volume_receive",
  389. volume.receive);
  390. sustain.receive = xml->getparbool("sustain_receive",
  391. sustain.receive);
  392. portamento.receive = xml->getparbool("portamento_receive",
  393. portamento.receive);
  394. portamento.time = xml->getpar127("portamento_time",
  395. portamento.time);
  396. portamento.pitchthresh = xml->getpar127("portamento_pitchthresh",
  397. portamento.pitchthresh);
  398. portamento.pitchthreshtype = xml->getpar127("portamento_pitchthreshtype",
  399. portamento.pitchthreshtype);
  400. portamento.portamento = xml->getpar127("portamento_portamento",
  401. portamento.portamento);
  402. portamento.updowntimestretch = xml->getpar127(
  403. "portamento_updowntimestretch",
  404. portamento.updowntimestretch);
  405. portamento.proportional = xml->getpar127("portamento_proportional",
  406. portamento.proportional);
  407. portamento.propRate = xml->getpar127("portamento_proprate",
  408. portamento.propRate);
  409. portamento.propDepth = xml->getpar127("portamento_propdepth",
  410. portamento.propDepth);
  411. resonancecenter.depth = xml->getpar127("resonance_center_depth",
  412. resonancecenter.depth);
  413. resonancebandwidth.depth = xml->getpar127("resonance_bandwidth_depth",
  414. resonancebandwidth.depth);
  415. }