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.

SUBnote.cpp 19KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. SUBnote.cpp - The "subtractive" 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 <cstdlib>
  19. #include <cstdio>
  20. #include <cassert>
  21. #include <iostream>
  22. #include "../globals.h"
  23. #include "SUBnote.h"
  24. #include "Envelope.h"
  25. #include "../Params/Controller.h"
  26. #include "../Params/SUBnoteParameters.h"
  27. #include "../Params/FilterParams.h"
  28. #include "../Misc/Util.h"
  29. #include "../Misc/Allocator.h"
  30. SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
  31. :SynthNote(spars), pars(*parameters)
  32. {
  33. NoteEnabled = ON;
  34. setup(spars.frequency, spars.velocity, spars.portamento, spars.note);
  35. }
  36. void SUBnote::setup(float freq,
  37. float velocity,
  38. int portamento_,
  39. int midinote,
  40. bool legato)
  41. {
  42. this->velocity = velocity;
  43. portamento = portamento_;
  44. NoteEnabled = ON;
  45. volume = powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)); //-60 dB .. 0 dB
  46. volume *= VelF(velocity, pars.PAmpVelocityScaleFunction);
  47. if(pars.PPanning != 0)
  48. panning = pars.PPanning / 127.0f;
  49. else
  50. panning = RND;
  51. if(!legato) {
  52. numstages = pars.Pnumstages;
  53. stereo = pars.Pstereo;
  54. start = pars.Pstart;
  55. firsttick = 1;
  56. }
  57. int pos[MAX_SUB_HARMONICS];
  58. if(pars.Pfixedfreq == 0)
  59. basefreq = freq;
  60. else {
  61. basefreq = 440.0f;
  62. int fixedfreqET = pars.PfixedfreqET;
  63. if(fixedfreqET) { //if the frequency varies according the keyboard note
  64. float tmp = (midinote - 69.0f) / 12.0f
  65. * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
  66. if(fixedfreqET <= 64)
  67. basefreq *= powf(2.0f, tmp);
  68. else
  69. basefreq *= powf(3.0f, tmp);
  70. }
  71. }
  72. int BendAdj = pars.PBendAdjust - 64;
  73. if (BendAdj % 24 == 0)
  74. BendAdjust = BendAdj / 24;
  75. else
  76. BendAdjust = BendAdj / 24.0f;
  77. float offset_val = (pars.POffsetHz - 64)/64.0f;
  78. OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val)));
  79. float detune = getdetune(pars.PDetuneType,
  80. pars.PCoarseDetune,
  81. pars.PDetune);
  82. basefreq *= powf(2.0f, detune / 1200.0f); //detune
  83. // basefreq*=ctl.pitchwheel.relfreq;//pitch wheel
  84. //global filter
  85. GlobalFilterCenterPitch = pars.GlobalFilter->getfreq() //center freq
  86. + (pars.PGlobalFilterVelocityScale / 127.0f
  87. * 6.0f) //velocity sensing
  88. * (VelF(velocity,
  89. pars.PGlobalFilterVelocityScaleFunction)
  90. - 1);
  91. if(!legato) {
  92. GlobalFilterL = NULL;
  93. GlobalFilterR = NULL;
  94. GlobalFilterEnvelope = NULL;
  95. }
  96. int harmonics = 0;
  97. //select only harmonics that desire to compute
  98. for(int n = 0; n < MAX_SUB_HARMONICS; ++n) {
  99. if(pars.Phmag[n] == 0)
  100. continue;
  101. pos[harmonics++] = n;
  102. }
  103. if(!legato)
  104. firstnumharmonics = numharmonics = harmonics;
  105. else {
  106. if(harmonics > firstnumharmonics)
  107. numharmonics = firstnumharmonics;
  108. else
  109. numharmonics = harmonics;
  110. }
  111. if(numharmonics == 0) {
  112. NoteEnabled = OFF;
  113. return;
  114. }
  115. if(!legato) {
  116. lfilter = memory.valloc<bpfilter>(numstages * numharmonics);
  117. if(stereo)
  118. rfilter = memory.valloc<bpfilter>(numstages * numharmonics);
  119. }
  120. //how much the amplitude is normalised (because the harmonics)
  121. float reduceamp = 0.0f;
  122. for(int n = 0; n < numharmonics; ++n) {
  123. float freq = basefreq * pars.POvertoneFreqMult[pos[n]];
  124. overtone_freq[n] = freq;
  125. overtone_rolloff[n] = computerolloff(freq);
  126. //the bandwidth is not absolute(Hz); it is relative to frequency
  127. float bw =
  128. powf(10, (pars.Pbandwidth - 127.0f) / 127.0f * 4) * numstages;
  129. //Bandwidth Scale
  130. bw *= powf(1000 / freq, (pars.Pbwscale - 64.0f) / 64.0f * 3.0f);
  131. //Relative BandWidth
  132. bw *= powf(100, (pars.Phrelbw[pos[n]] - 64.0f) / 64.0f);
  133. if(bw > 25.0f)
  134. bw = 25.0f;
  135. //try to keep same amplitude on all freqs and bw. (empirically)
  136. float gain = sqrt(1500.0f / (bw * freq));
  137. float hmagnew = 1.0f - pars.Phmag[pos[n]] / 127.0f;
  138. float hgain;
  139. switch(pars.Phmagtype) {
  140. case 1:
  141. hgain = expf(hmagnew * logf(0.01f));
  142. break;
  143. case 2:
  144. hgain = expf(hmagnew * logf(0.001f));
  145. break;
  146. case 3:
  147. hgain = expf(hmagnew * logf(0.0001f));
  148. break;
  149. case 4:
  150. hgain = expf(hmagnew * logf(0.00001f));
  151. break;
  152. default:
  153. hgain = 1.0f - hmagnew;
  154. }
  155. gain *= hgain;
  156. reduceamp += hgain;
  157. for(int nph = 0; nph < numstages; ++nph) {
  158. float amp = 1.0f;
  159. if(nph == 0)
  160. amp = gain;
  161. initfilter(lfilter[nph + n * numstages], freq + OffsetHz, bw,
  162. amp, hgain);
  163. if(stereo)
  164. initfilter(rfilter[nph + n * numstages], freq + OffsetHz, bw,
  165. amp, hgain);
  166. }
  167. }
  168. if(reduceamp < 0.001f)
  169. reduceamp = 1.0f;
  170. volume /= reduceamp;
  171. oldpitchwheel = 0;
  172. oldbandwidth = 64;
  173. if(!legato) {
  174. if(pars.Pfixedfreq == 0)
  175. initparameters(basefreq);
  176. else
  177. initparameters(basefreq / 440.0f * freq);
  178. }
  179. else {
  180. if(pars.Pfixedfreq == 0)
  181. freq = basefreq;
  182. else
  183. freq *= basefreq / 440.0f;
  184. if(pars.PGlobalFilterEnabled) {
  185. globalfiltercenterq = pars.GlobalFilter->getq();
  186. GlobalFilterFreqTracking = pars.GlobalFilter->getfreqtracking(
  187. basefreq);
  188. }
  189. }
  190. oldamplitude = newamplitude;
  191. }
  192. SynthNote *SUBnote::cloneLegato(void)
  193. {
  194. SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
  195. (bool)portamento, legato.param.midinote, true};
  196. return memory.alloc<SUBnote>(&pars, sp);
  197. }
  198. void SUBnote::legatonote(LegatoParams pars)
  199. {
  200. // Manage legato stuff
  201. if(legato.update(pars))
  202. return;
  203. try {
  204. setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote,
  205. true);
  206. } catch (std::bad_alloc &ba) {
  207. std::cerr << "failed to set legato note parameter in SUBnote: " << ba.what() << std::endl;
  208. }
  209. }
  210. SUBnote::~SUBnote()
  211. {
  212. if(NoteEnabled != OFF)
  213. KillNote();
  214. }
  215. /*
  216. * Kill the note
  217. */
  218. void SUBnote::KillNote()
  219. {
  220. if(NoteEnabled != OFF) {
  221. memory.devalloc(numstages * numharmonics, lfilter);
  222. if(stereo)
  223. memory.devalloc(numstages * numharmonics, rfilter);
  224. memory.dealloc(AmpEnvelope);
  225. memory.dealloc(FreqEnvelope);
  226. memory.dealloc(BandWidthEnvelope);
  227. memory.dealloc(GlobalFilterL);
  228. memory.dealloc(GlobalFilterR);
  229. memory.dealloc(GlobalFilterEnvelope);
  230. NoteEnabled = OFF;
  231. }
  232. }
  233. /*
  234. * Compute the filters coefficients
  235. */
  236. void SUBnote::computefiltercoefs(bpfilter &filter,
  237. float freq,
  238. float bw,
  239. float gain)
  240. {
  241. if(freq > synth.samplerate_f / 2.0f - 200.0f)
  242. freq = synth.samplerate_f / 2.0f - 200.0f;
  243. float omega = 2.0f * PI * freq / synth.samplerate_f;
  244. float sn = sinf(omega);
  245. float cs = cosf(omega);
  246. float alpha = sn * sinh(LOG_2 / 2.0f * bw * omega / sn);
  247. if(alpha > 1)
  248. alpha = 1;
  249. if(alpha > bw)
  250. alpha = bw;
  251. filter.b0 = alpha / (1.0f + alpha) * filter.amp * gain;
  252. filter.b2 = -alpha / (1.0f + alpha) * filter.amp * gain;
  253. filter.a1 = -2.0f * cs / (1.0f + alpha);
  254. filter.a2 = (1.0f - alpha) / (1.0f + alpha);
  255. }
  256. /*
  257. * Initialise the filters
  258. */
  259. void SUBnote::initfilter(bpfilter &filter,
  260. float freq,
  261. float bw,
  262. float amp,
  263. float mag)
  264. {
  265. filter.xn1 = 0.0f;
  266. filter.xn2 = 0.0f;
  267. if(start == 0) {
  268. filter.yn1 = 0.0f;
  269. filter.yn2 = 0.0f;
  270. }
  271. else {
  272. float a = 0.1f * mag; //empirically
  273. float p = RND * 2.0f * PI;
  274. if(start == 1)
  275. a *= RND;
  276. filter.yn1 = a * cosf(p);
  277. filter.yn2 = a * cosf(p + freq * 2.0f * PI / synth.samplerate_f);
  278. //correct the error of computation the start amplitude
  279. //at very high frequencies
  280. if(freq > synth.samplerate_f * 0.96f) {
  281. filter.yn1 = 0.0f;
  282. filter.yn2 = 0.0f;
  283. }
  284. }
  285. filter.amp = amp;
  286. filter.freq = freq;
  287. filter.bw = bw;
  288. computefiltercoefs(filter, freq, bw, 1.0f);
  289. }
  290. /*
  291. * Do the filtering
  292. */
  293. inline void SubFilterA(const float coeff[4], float &src, float work[4])
  294. {
  295. work[3] = src*coeff[0]+work[1]*coeff[1]+work[2]*coeff[2]+work[3]*coeff[3];
  296. work[1] = src;
  297. src = work[3];
  298. }
  299. inline void SubFilterB(const float coeff[4], float &src, float work[4])
  300. {
  301. work[2] = src*coeff[0]+work[0]*coeff[1]+work[3]*coeff[2]+work[2]*coeff[3];
  302. work[0] = src;
  303. src = work[2];
  304. }
  305. //This dance is designed to minimize unneeded memory operations which can result
  306. //in quite a bit of wasted time
  307. void SUBnote::filter(bpfilter &filter, float *smps)
  308. {
  309. assert(synth.buffersize % 8 == 0);
  310. float coeff[4] = {filter.b0, filter.b2, -filter.a1, -filter.a2};
  311. float work[4] = {filter.xn1, filter.xn2, filter.yn1, filter.yn2};
  312. for(int i = 0; i < synth.buffersize; i += 8) {
  313. SubFilterA(coeff, smps[i + 0], work);
  314. SubFilterB(coeff, smps[i + 1], work);
  315. SubFilterA(coeff, smps[i + 2], work);
  316. SubFilterB(coeff, smps[i + 3], work);
  317. SubFilterA(coeff, smps[i + 4], work);
  318. SubFilterB(coeff, smps[i + 5], work);
  319. SubFilterA(coeff, smps[i + 6], work);
  320. SubFilterB(coeff, smps[i + 7], work);
  321. }
  322. filter.xn1 = work[0];
  323. filter.xn2 = work[1];
  324. filter.yn1 = work[2];
  325. filter.yn2 = work[3];
  326. }
  327. /*
  328. * Init Parameters
  329. */
  330. void SUBnote::initparameters(float freq)
  331. {
  332. AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, freq, synth.dt());
  333. if(pars.PFreqEnvelopeEnabled)
  334. FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, freq, synth.dt());
  335. else
  336. FreqEnvelope = NULL;
  337. if(pars.PBandWidthEnvelopeEnabled)
  338. BandWidthEnvelope = memory.alloc<Envelope>(*pars.BandWidthEnvelope, freq, synth.dt());
  339. else
  340. BandWidthEnvelope = NULL;
  341. if(pars.PGlobalFilterEnabled) {
  342. globalfiltercenterq = pars.GlobalFilter->getq();
  343. GlobalFilterL = Filter::generate(memory, pars.GlobalFilter,
  344. synth.samplerate, synth.buffersize);
  345. if(stereo)
  346. GlobalFilterR = Filter::generate(memory, pars.GlobalFilter,
  347. synth.samplerate, synth.buffersize);
  348. GlobalFilterEnvelope = memory.alloc<Envelope>(*pars.GlobalFilterEnvelope, freq, synth.dt());
  349. GlobalFilterFreqTracking = pars.GlobalFilter->getfreqtracking(basefreq);
  350. }
  351. computecurrentparameters();
  352. }
  353. /*
  354. * Compute how much to reduce amplitude near nyquist or subaudible frequencies.
  355. */
  356. float SUBnote::computerolloff(float freq)
  357. {
  358. const float lower_limit = 10.0f;
  359. const float lower_width = 10.0f;
  360. const float upper_width = 200.0f;
  361. float upper_limit = synth.samplerate / 2.0f;
  362. if (freq > lower_limit + lower_width &&
  363. freq < upper_limit - upper_width)
  364. return 1.0f;
  365. if (freq <= lower_limit || freq >= upper_limit)
  366. return 0.0f;
  367. if (freq <= lower_limit + lower_width)
  368. return (1.0f - cosf(M_PI * (freq - lower_limit) / lower_width)) / 2.0f;
  369. return (1.0f - cosf(M_PI * (freq - upper_limit) / upper_width)) / 2.0f;
  370. }
  371. /*
  372. * Compute Parameters of SUBnote for each tick
  373. */
  374. void SUBnote::computecurrentparameters()
  375. {
  376. if(FreqEnvelope || BandWidthEnvelope
  377. || (oldpitchwheel != ctl.pitchwheel.data)
  378. || (oldbandwidth != ctl.bandwidth.data)
  379. || portamento) {
  380. float envfreq = 1.0f;
  381. float envbw = 1.0f;
  382. float gain = 1.0f;
  383. if(FreqEnvelope) {
  384. envfreq = FreqEnvelope->envout() / 1200;
  385. envfreq = powf(2.0f, envfreq);
  386. }
  387. envfreq *=
  388. powf(ctl.pitchwheel.relfreq, BendAdjust); //pitch wheel
  389. if(portamento) { //portamento is used
  390. envfreq *= ctl.portamento.freqrap;
  391. if(!ctl.portamento.used) //the portamento has finished
  392. portamento = false; //this note is no longer "portamented"
  393. }
  394. if(BandWidthEnvelope) {
  395. envbw = BandWidthEnvelope->envout();
  396. envbw = powf(2, envbw);
  397. }
  398. envbw *= ctl.bandwidth.relbw; //bandwidth controller
  399. float tmpgain = 1.0f / sqrt(envbw * envfreq);
  400. for(int n = 0; n < numharmonics; ++n) {
  401. overtone_rolloff[n] = computerolloff(overtone_freq[n] * envfreq);
  402. }
  403. for(int n = 0; n < numharmonics; ++n)
  404. for(int nph = 0; nph < numstages; ++nph) {
  405. if(nph == 0)
  406. gain = tmpgain;
  407. else
  408. gain = 1.0f;
  409. computefiltercoefs(lfilter[nph + n * numstages],
  410. lfilter[nph + n * numstages].freq * envfreq,
  411. lfilter[nph + n * numstages].bw * envbw,
  412. gain);
  413. }
  414. if(stereo)
  415. for(int n = 0; n < numharmonics; ++n)
  416. for(int nph = 0; nph < numstages; ++nph) {
  417. if(nph == 0)
  418. gain = tmpgain;
  419. else
  420. gain = 1.0f;
  421. computefiltercoefs(
  422. rfilter[nph + n * numstages],
  423. rfilter[nph + n * numstages].freq * envfreq,
  424. rfilter[nph + n * numstages].bw * envbw,
  425. gain);
  426. }
  427. oldbandwidth = ctl.bandwidth.data;
  428. oldpitchwheel = ctl.pitchwheel.data;
  429. }
  430. newamplitude = volume * AmpEnvelope->envout_dB() * 2.0f;
  431. //Filter
  432. if(GlobalFilterL != NULL) {
  433. float globalfilterpitch = GlobalFilterCenterPitch
  434. + GlobalFilterEnvelope->envout();
  435. float filterfreq = globalfilterpitch + ctl.filtercutoff.relfreq
  436. + GlobalFilterFreqTracking;
  437. filterfreq = Filter::getrealfreq(filterfreq);
  438. GlobalFilterL->setfreq_and_q(filterfreq,
  439. globalfiltercenterq * ctl.filterq.relq);
  440. if(GlobalFilterR != NULL)
  441. GlobalFilterR->setfreq_and_q(
  442. filterfreq,
  443. globalfiltercenterq
  444. * ctl.filterq.relq);
  445. }
  446. }
  447. /*
  448. * Note Output
  449. */
  450. int SUBnote::noteout(float *outl, float *outr)
  451. {
  452. memcpy(outl, synth.denormalkillbuf, synth.bufferbytes);
  453. memcpy(outr, synth.denormalkillbuf, synth.bufferbytes);
  454. if(NoteEnabled == OFF)
  455. return 0;
  456. float tmprnd[synth.buffersize];
  457. float tmpsmp[synth.buffersize];
  458. //left channel
  459. for(int i = 0; i < synth.buffersize; ++i)
  460. tmprnd[i] = RND * 2.0f - 1.0f;
  461. for(int n = 0; n < numharmonics; ++n) {
  462. float rolloff = overtone_rolloff[n];
  463. memcpy(tmpsmp, tmprnd, synth.bufferbytes);
  464. for(int nph = 0; nph < numstages; ++nph)
  465. filter(lfilter[nph + n * numstages], tmpsmp);
  466. for(int i = 0; i < synth.buffersize; ++i)
  467. outl[i] += tmpsmp[i] * rolloff;
  468. }
  469. if(GlobalFilterL != NULL)
  470. GlobalFilterL->filterout(&outl[0]);
  471. //right channel
  472. if(stereo) {
  473. for(int i = 0; i < synth.buffersize; ++i)
  474. tmprnd[i] = RND * 2.0f - 1.0f;
  475. for(int n = 0; n < numharmonics; ++n) {
  476. float rolloff = overtone_rolloff[n];
  477. memcpy(tmpsmp, tmprnd, synth.bufferbytes);
  478. for(int nph = 0; nph < numstages; ++nph)
  479. filter(rfilter[nph + n * numstages], tmpsmp);
  480. for(int i = 0; i < synth.buffersize; ++i)
  481. outr[i] += tmpsmp[i] * rolloff;
  482. }
  483. if(GlobalFilterR != NULL)
  484. GlobalFilterR->filterout(&outr[0]);
  485. }
  486. else
  487. memcpy(outr, outl, synth.bufferbytes);
  488. if(firsttick != 0) {
  489. int n = 10;
  490. if(n > synth.buffersize)
  491. n = synth.buffersize;
  492. for(int i = 0; i < n; ++i) {
  493. float ampfadein = 0.5f - 0.5f * cosf(
  494. (float) i / (float) n * PI);
  495. outl[i] *= ampfadein;
  496. outr[i] *= ampfadein;
  497. }
  498. firsttick = 0;
  499. }
  500. if(ABOVE_AMPLITUDE_THRESHOLD(oldamplitude, newamplitude))
  501. // Amplitude interpolation
  502. for(int i = 0; i < synth.buffersize; ++i) {
  503. float tmpvol = INTERPOLATE_AMPLITUDE(oldamplitude,
  504. newamplitude,
  505. i,
  506. synth.buffersize);
  507. outl[i] *= tmpvol * panning;
  508. outr[i] *= tmpvol * (1.0f - panning);
  509. }
  510. else
  511. for(int i = 0; i < synth.buffersize; ++i) {
  512. outl[i] *= newamplitude * panning;
  513. outr[i] *= newamplitude * (1.0f - panning);
  514. }
  515. oldamplitude = newamplitude;
  516. computecurrentparameters();
  517. // Apply legato-specific sound signal modifications
  518. legato.apply(*this, outl, outr);
  519. // Check if the note needs to be computed more
  520. if(AmpEnvelope->finished() != 0) {
  521. for(int i = 0; i < synth.buffersize; ++i) { //fade-out
  522. float tmp = 1.0f - (float)i / synth.buffersize_f;
  523. outl[i] *= tmp;
  524. outr[i] *= tmp;
  525. }
  526. KillNote();
  527. }
  528. return 1;
  529. }
  530. /*
  531. * Release Key (Note Off)
  532. */
  533. void SUBnote::releasekey()
  534. {
  535. AmpEnvelope->releasekey();
  536. if(FreqEnvelope)
  537. FreqEnvelope->releasekey();
  538. if(BandWidthEnvelope)
  539. BandWidthEnvelope->releasekey();
  540. if(GlobalFilterEnvelope)
  541. GlobalFilterEnvelope->releasekey();
  542. }
  543. /*
  544. * Check if the note is finished
  545. */
  546. int SUBnote::finished() const
  547. {
  548. if(NoteEnabled == OFF)
  549. return 1;
  550. else
  551. return 0;
  552. }