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.

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