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.

500 lines
17KB

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