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.

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