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.

442 lines
15KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. pADnote.cpp - The "pad" synthesizer
  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 <cmath>
  18. #include "PADnote.h"
  19. #include "../Misc/Config.h"
  20. #include "../Misc/Allocator.h"
  21. #include "../DSP/Filter.h"
  22. #include "../Params/PADnoteParameters.h"
  23. #include "../Params/Controller.h"
  24. #include "../Params/FilterParams.h"
  25. #include "../Misc/Util.h"
  26. PADnote::PADnote(const PADnoteParameters *parameters,
  27. SynthParams pars, const int& interpolation)
  28. :SynthNote(pars), pars(*parameters), interpolation(interpolation)
  29. {
  30. firsttime = true;
  31. setup(pars.frequency, pars.velocity, pars.portamento, pars.note);
  32. }
  33. void PADnote::setup(float freq,
  34. float velocity_,
  35. int portamento_,
  36. int midinote,
  37. bool legato)
  38. {
  39. portamento = portamento_;
  40. velocity = velocity_;
  41. finished_ = false;
  42. if(!pars.Pfixedfreq)
  43. basefreq = freq;
  44. else {
  45. basefreq = 440.0f;
  46. int fixedfreqET = pars.PfixedfreqET;
  47. if(fixedfreqET != 0) { //if the frequency varies according the keyboard note
  48. float tmp =
  49. (midinote
  50. - 69.0f) / 12.0f
  51. * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
  52. if(fixedfreqET <= 64)
  53. basefreq *= powf(2.0f, tmp);
  54. else
  55. basefreq *= powf(3.0f, tmp);
  56. }
  57. }
  58. int BendAdj = pars.PBendAdjust - 64;
  59. if (BendAdj % 24 == 0)
  60. BendAdjust = BendAdj / 24;
  61. else
  62. BendAdjust = BendAdj / 24.0f;
  63. float offset_val = (pars.POffsetHz - 64)/64.0f;
  64. OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val)));
  65. firsttime = true;
  66. realfreq = basefreq;
  67. if(!legato)
  68. NoteGlobalPar.Detune = getdetune(pars.PDetuneType, pars.PCoarseDetune,
  69. pars.PDetune);
  70. //find out the closest note
  71. float logfreq = logf(basefreq * powf(2.0f, NoteGlobalPar.Detune / 1200.0f));
  72. float mindist = fabs(logfreq - logf(pars.sample[0].basefreq + 0.0001f));
  73. nsample = 0;
  74. for(int i = 1; i < PAD_MAX_SAMPLES; ++i) {
  75. if(pars.sample[i].smp == NULL)
  76. break;
  77. float dist = fabs(logfreq - logf(pars.sample[i].basefreq + 0.0001f));
  78. if(dist < mindist) {
  79. nsample = i;
  80. mindist = dist;
  81. }
  82. }
  83. int size = pars.sample[nsample].size;
  84. if(size == 0)
  85. size = 1;
  86. if(!legato) { //not sure
  87. poshi_l = (int)(RND * (size - 1));
  88. if(pars.PStereo)
  89. poshi_r = (poshi_l + size / 2) % size;
  90. else
  91. poshi_r = poshi_l;
  92. poslo = 0.0f;
  93. }
  94. if(pars.PPanning == 0)
  95. NoteGlobalPar.Panning = RND;
  96. else
  97. NoteGlobalPar.Panning = pars.PPanning / 128.0f;
  98. NoteGlobalPar.FilterCenterPitch = pars.GlobalFilter->getfreq() //center freq
  99. + pars.PFilterVelocityScale / 127.0f
  100. * 6.0f //velocity sensing
  101. * (VelF(velocity,
  102. pars.
  103. PFilterVelocityScaleFunction) - 1);
  104. if(!legato) {
  105. NoteGlobalPar.Fadein_adjustment =
  106. pars.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE;
  107. NoteGlobalPar.Fadein_adjustment *= NoteGlobalPar.Fadein_adjustment;
  108. if(pars.PPunchStrength != 0) {
  109. NoteGlobalPar.Punch.Enabled = 1;
  110. NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f
  111. NoteGlobalPar.Punch.initialvalue =
  112. ((powf(10, 1.5f * pars.PPunchStrength / 127.0f) - 1.0f)
  113. * VelF(velocity,
  114. pars.PPunchVelocitySensing));
  115. const float time =
  116. powf(10, 3.0f * pars.PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms
  117. const float stretch = powf(440.0f / freq, pars.PPunchStretch / 64.0f);
  118. NoteGlobalPar.Punch.dt = 1.0f
  119. / (time * synth.samplerate_f * stretch);
  120. }
  121. else
  122. NoteGlobalPar.Punch.Enabled = 0;
  123. NoteGlobalPar.FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, basefreq, synth.dt());
  124. NoteGlobalPar.FreqLfo = memory.alloc<LFO>(*pars.FreqLfo, basefreq, time);
  125. NoteGlobalPar.AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, basefreq, synth.dt());
  126. NoteGlobalPar.AmpLfo = memory.alloc<LFO>(*pars.AmpLfo, basefreq, time);
  127. }
  128. NoteGlobalPar.Volume = 4.0f
  129. * powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)) //-60 dB .. 0 dB
  130. * VelF(velocity, pars.PAmpVelocityScaleFunction); //velocity sensing
  131. NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output
  132. globaloldamplitude = globalnewamplitude = NoteGlobalPar.Volume
  133. * NoteGlobalPar.AmpEnvelope->
  134. envout_dB()
  135. * NoteGlobalPar.AmpLfo->amplfoout();
  136. if(!legato) {
  137. NoteGlobalPar.GlobalFilterL = Filter::generate(memory, pars.GlobalFilter,
  138. synth.samplerate, synth.buffersize);
  139. NoteGlobalPar.GlobalFilterR = Filter::generate(memory, pars.GlobalFilter,
  140. synth.samplerate, synth.buffersize);
  141. NoteGlobalPar.FilterEnvelope = memory.alloc<Envelope>(*pars.FilterEnvelope, basefreq, synth.dt());
  142. NoteGlobalPar.FilterLfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, time);
  143. }
  144. NoteGlobalPar.FilterQ = pars.GlobalFilter->getq();
  145. NoteGlobalPar.FilterFreqTracking = pars.GlobalFilter->getfreqtracking(
  146. basefreq);
  147. if(!pars.sample[nsample].smp) {
  148. finished_ = true;
  149. return;
  150. }
  151. }
  152. SynthNote *PADnote::cloneLegato(void)
  153. {
  154. SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
  155. (bool)portamento, legato.param.midinote, true};
  156. return memory.alloc<PADnote>(&pars, sp, interpolation);
  157. }
  158. void PADnote::legatonote(LegatoParams pars)
  159. {
  160. // Manage legato stuff
  161. if(legato.update(pars))
  162. return;
  163. setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote, true);
  164. }
  165. PADnote::~PADnote()
  166. {
  167. memory.dealloc(NoteGlobalPar.FreqEnvelope);
  168. memory.dealloc(NoteGlobalPar.FreqLfo);
  169. memory.dealloc(NoteGlobalPar.AmpEnvelope);
  170. memory.dealloc(NoteGlobalPar.AmpLfo);
  171. memory.dealloc(NoteGlobalPar.GlobalFilterL);
  172. memory.dealloc(NoteGlobalPar.GlobalFilterR);
  173. memory.dealloc(NoteGlobalPar.FilterEnvelope);
  174. memory.dealloc(NoteGlobalPar.FilterLfo);
  175. }
  176. inline void PADnote::fadein(float *smps)
  177. {
  178. int zerocrossings = 0;
  179. for(int i = 1; i < synth.buffersize; ++i)
  180. if((smps[i - 1] < 0.0f) && (smps[i] > 0.0f))
  181. zerocrossings++; //this is only the possitive crossings
  182. float tmp = (synth.buffersize_f - 1.0f) / (zerocrossings + 1) / 3.0f;
  183. if(tmp < 8.0f)
  184. tmp = 8.0f;
  185. tmp *= NoteGlobalPar.Fadein_adjustment;
  186. int n;
  187. F2I(tmp, n); //how many samples is the fade-in
  188. if(n > synth.buffersize)
  189. n = synth.buffersize;
  190. for(int i = 0; i < n; ++i) { //fade-in
  191. float tmp = 0.5f - cosf((float)i / (float) n * PI) * 0.5f;
  192. smps[i] *= tmp;
  193. }
  194. }
  195. void PADnote::computecurrentparameters()
  196. {
  197. float globalpitch, globalfilterpitch;
  198. globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout()
  199. + NoteGlobalPar.FreqLfo->lfoout()
  200. * ctl.modwheel.relmod + NoteGlobalPar.Detune);
  201. globaloldamplitude = globalnewamplitude;
  202. globalnewamplitude = NoteGlobalPar.Volume
  203. * NoteGlobalPar.AmpEnvelope->envout_dB()
  204. * NoteGlobalPar.AmpLfo->amplfoout();
  205. globalfilterpitch = NoteGlobalPar.FilterEnvelope->envout()
  206. + NoteGlobalPar.FilterLfo->lfoout()
  207. + NoteGlobalPar.FilterCenterPitch;
  208. float tmpfilterfreq = globalfilterpitch + ctl.filtercutoff.relfreq
  209. + NoteGlobalPar.FilterFreqTracking;
  210. tmpfilterfreq = Filter::getrealfreq(tmpfilterfreq);
  211. float globalfilterq = NoteGlobalPar.FilterQ * ctl.filterq.relq;
  212. NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq, globalfilterq);
  213. NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq, globalfilterq);
  214. //compute the portamento, if it is used by this note
  215. float portamentofreqrap = 1.0f;
  216. if(portamento) { //this voice use portamento
  217. portamentofreqrap = ctl.portamento.freqrap;
  218. if(ctl.portamento.used == 0) //the portamento has finished
  219. portamento = false; //this note is no longer "portamented"
  220. }
  221. realfreq = basefreq * portamentofreqrap
  222. * powf(2.0f, globalpitch / 12.0f)
  223. * powf(ctl.pitchwheel.relfreq, BendAdjust) + OffsetHz;
  224. }
  225. int PADnote::Compute_Linear(float *outl,
  226. float *outr,
  227. int freqhi,
  228. float freqlo)
  229. {
  230. float *smps = pars.sample[nsample].smp;
  231. if(smps == NULL) {
  232. finished_ = true;
  233. return 1;
  234. }
  235. int size = pars.sample[nsample].size;
  236. for(int i = 0; i < synth.buffersize; ++i) {
  237. poshi_l += freqhi;
  238. poshi_r += freqhi;
  239. poslo += freqlo;
  240. if(poslo >= 1.0f) {
  241. poshi_l += 1;
  242. poshi_r += 1;
  243. poslo -= 1.0f;
  244. }
  245. if(poshi_l >= size)
  246. poshi_l %= size;
  247. if(poshi_r >= size)
  248. poshi_r %= size;
  249. outl[i] = smps[poshi_l] * (1.0f - poslo) + smps[poshi_l + 1] * poslo;
  250. outr[i] = smps[poshi_r] * (1.0f - poslo) + smps[poshi_r + 1] * poslo;
  251. }
  252. return 1;
  253. }
  254. int PADnote::Compute_Cubic(float *outl,
  255. float *outr,
  256. int freqhi,
  257. float freqlo)
  258. {
  259. float *smps = pars.sample[nsample].smp;
  260. if(smps == NULL) {
  261. finished_ = true;
  262. return 1;
  263. }
  264. int size = pars.sample[nsample].size;
  265. float xm1, x0, x1, x2, a, b, c;
  266. for(int i = 0; i < synth.buffersize; ++i) {
  267. poshi_l += freqhi;
  268. poshi_r += freqhi;
  269. poslo += freqlo;
  270. if(poslo >= 1.0f) {
  271. poshi_l += 1;
  272. poshi_r += 1;
  273. poslo -= 1.0f;
  274. }
  275. if(poshi_l >= size)
  276. poshi_l %= size;
  277. if(poshi_r >= size)
  278. poshi_r %= size;
  279. //left
  280. xm1 = smps[poshi_l];
  281. x0 = smps[poshi_l + 1];
  282. x1 = smps[poshi_l + 2];
  283. x2 = smps[poshi_l + 3];
  284. a = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
  285. b = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
  286. c = (x1 - xm1) * 0.5f;
  287. outl[i] = (((a * poslo) + b) * poslo + c) * poslo + x0;
  288. //right
  289. xm1 = smps[poshi_r];
  290. x0 = smps[poshi_r + 1];
  291. x1 = smps[poshi_r + 2];
  292. x2 = smps[poshi_r + 3];
  293. a = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
  294. b = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
  295. c = (x1 - xm1) * 0.5f;
  296. outr[i] = (((a * poslo) + b) * poslo + c) * poslo + x0;
  297. }
  298. return 1;
  299. }
  300. int PADnote::noteout(float *outl, float *outr)
  301. {
  302. computecurrentparameters();
  303. float *smps = pars.sample[nsample].smp;
  304. if(smps == NULL) {
  305. for(int i = 0; i < synth.buffersize; ++i) {
  306. outl[i] = 0.0f;
  307. outr[i] = 0.0f;
  308. }
  309. return 1;
  310. }
  311. float smpfreq = pars.sample[nsample].basefreq;
  312. float freqrap = realfreq / smpfreq;
  313. int freqhi = (int) (floor(freqrap));
  314. float freqlo = freqrap - floor(freqrap);
  315. if(interpolation)
  316. Compute_Cubic(outl, outr, freqhi, freqlo);
  317. else
  318. Compute_Linear(outl, outr, freqhi, freqlo);
  319. if(firsttime) {
  320. fadein(outl);
  321. fadein(outr);
  322. firsttime = false;
  323. }
  324. NoteGlobalPar.GlobalFilterL->filterout(outl);
  325. NoteGlobalPar.GlobalFilterR->filterout(outr);
  326. //Apply the punch
  327. if(NoteGlobalPar.Punch.Enabled != 0)
  328. for(int i = 0; i < synth.buffersize; ++i) {
  329. float punchamp = NoteGlobalPar.Punch.initialvalue
  330. * NoteGlobalPar.Punch.t + 1.0f;
  331. outl[i] *= punchamp;
  332. outr[i] *= punchamp;
  333. NoteGlobalPar.Punch.t -= NoteGlobalPar.Punch.dt;
  334. if(NoteGlobalPar.Punch.t < 0.0f) {
  335. NoteGlobalPar.Punch.Enabled = 0;
  336. break;
  337. }
  338. }
  339. if(ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude, globalnewamplitude))
  340. // Amplitude Interpolation
  341. for(int i = 0; i < synth.buffersize; ++i) {
  342. float tmpvol = INTERPOLATE_AMPLITUDE(globaloldamplitude,
  343. globalnewamplitude,
  344. i,
  345. synth.buffersize);
  346. outl[i] *= tmpvol * NoteGlobalPar.Panning;
  347. outr[i] *= tmpvol * (1.0f - NoteGlobalPar.Panning);
  348. }
  349. else
  350. for(int i = 0; i < synth.buffersize; ++i) {
  351. outl[i] *= globalnewamplitude * NoteGlobalPar.Panning;
  352. outr[i] *= globalnewamplitude * (1.0f - NoteGlobalPar.Panning);
  353. }
  354. // Apply legato-specific sound signal modifications
  355. legato.apply(*this, outl, outr);
  356. // Check if the global amplitude is finished.
  357. // If it does, disable the note
  358. if(NoteGlobalPar.AmpEnvelope->finished()) {
  359. for(int i = 0; i < synth.buffersize; ++i) { //fade-out
  360. float tmp = 1.0f - (float)i / synth.buffersize_f;
  361. outl[i] *= tmp;
  362. outr[i] *= tmp;
  363. }
  364. finished_ = 1;
  365. }
  366. return 1;
  367. }
  368. int PADnote::finished() const
  369. {
  370. return finished_;
  371. }
  372. void PADnote::releasekey()
  373. {
  374. NoteGlobalPar.FreqEnvelope->releasekey();
  375. NoteGlobalPar.FilterEnvelope->releasekey();
  376. NoteGlobalPar.AmpEnvelope->releasekey();
  377. }