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.

440 lines
14KB

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