1 /*
2
3 SUBnote.cpp - The "subtractive" synthesizer
4
5 Original ZynAddSubFX author Nasca Octavian Paul
6 Copyright (C) 2002-2009 Nasca Octavian Paul
7 Copyright 2009-2011, Alan Calvert
8 Copyright 2014-2019, Will Godfrey & others
9 Copyright 2020 Kristian Amlie & others
10
11 This file is part of yoshimi, which is free software: you can redistribute
12 it and/or modify it under the terms of the GNU Library General Public
13 License as published by the Free Software Foundation; either version 2 of
14 the License, or (at your option) any later version.
15
16 yoshimi is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License (version 2 or
19 later) for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 yoshimi; if not, write to the Free Software Foundation, Inc., 51 Franklin
23 Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
25 This file is derivative of ZynAddSubFX original code
26
27 */
28
29 #include <cmath>
30 #include <iostream>
31
32 #include "DSP/FFTwrapper.h"
33 #include "Params/SUBnoteParameters.h"
34 #include "Params/Controller.h"
35 #include "Synth/SUBnote.h"
36 #include "Synth/Envelope.h"
37 #include "DSP/Filter.h"
38 #include "Misc/SynthEngine.h"
39 #include "Misc/SynthHelper.h"
40 #include "Misc/NumericFuncs.h"
41
42 using func::power;
43 using func::powFrac;
44 using func::decibel;
45 using synth::velF;
46 using synth::getDetune;
47 using synth::interpolateAmplitude;
48 using synth::aboveAmplitudeThreshold;
49
50 using func::setRandomPan;
51
52
53
SUBnote(SUBnoteParameters * parameters,Controller * ctl_,float basefreq_,float velocity_,int portamento_,int midinote_,SynthEngine * _synth)54 SUBnote::SUBnote(SUBnoteParameters *parameters, Controller *ctl_, float basefreq_,
55 float velocity_, int portamento_, int midinote_, SynthEngine *_synth) :
56 pars(parameters),
57 velocity(velocity_ > 1.0f ? 1.0f : velocity_),
58 portamento(portamento_),
59 midinote(midinote_),
60 GlobalFilterL(NULL),
61 GlobalFilterR(NULL),
62 GlobalFilterEnvelope(NULL),
63 ctl(ctl_),
64 subNoteChange(parameters),
65 synth(_synth),
66 filterStep(0)
67 {
68 // Initialise some legato-specific vars
69 legatoFade = 1.0f; // Full volume
70 legatoFadeStep = 0.0f; // Legato disabled
71
72 NoteStatus = NOTE_ENABLED;
73
74 numstages = pars->Pnumstages;
75 stereo = pars->Pstereo;
76 start = pars->Pstart;
77 firsttick = 1;
78
79 setRandomPan(synth->numRandom(), randpanL, randpanR, synth->getRuntime().panLaw, pars->PPanning, pars->PWidth);
80
81 numharmonics = 0;
82 lfilter = NULL;
83 rfilter = NULL;
84
85 basefreq = basefreq_;
86 computeNoteFreq();
87
88 oldpitchwheel = 0;
89 oldbandwidth = 64;
90
91 if (pars->Pfixedfreq == 0)
92 initparameters(notefreq);
93 else
94 initparameters(notefreq / 440.0f * basefreq);
95
96 computeNoteParameters();
97 computecurrentparameters();
98
99 oldamplitude = newamplitude;
100 }
101
102
103 // Copy constructor, currently only exists for legato
SUBnote(const SUBnote & orig)104 SUBnote::SUBnote(const SUBnote &orig) :
105 pars(orig.pars),
106 stereo(orig.stereo),
107 numstages(orig.numstages),
108 numharmonics(orig.numharmonics),
109 start(orig.start),
110 basefreq(orig.basefreq),
111 notefreq(orig.notefreq),
112 velocity(orig.velocity),
113 portamento(orig.portamento),
114 midinote(orig.midinote),
115 BendAdjust(orig.BendAdjust),
116 OffsetHz(orig.OffsetHz),
117 randpanL(orig.randpanL),
118 randpanR(orig.randpanR),
119 FreqEnvelope(NULL),
120 BandWidthEnvelope(NULL),
121 GlobalFilterL(NULL),
122 GlobalFilterR(NULL),
123 GlobalFilterEnvelope(NULL),
124 // For legato. Move this somewhere else if copying
125 // notes gets used for another purpose
126 NoteStatus(NOTE_KEEPALIVE),
127 firsttick(orig.firsttick),
128 volume(orig.volume),
129 oldamplitude(orig.oldamplitude),
130 newamplitude(orig.newamplitude),
131 lfilter(NULL),
132 rfilter(NULL),
133 tmpsmp(NULL),
134 tmprnd(NULL),
135 ctl(orig.ctl),
136 oldpitchwheel(orig.oldpitchwheel),
137 oldbandwidth(orig.oldbandwidth),
138 legatoFade(0.0f), // Silent by default
139 legatoFadeStep(0.0f), // Legato disabled
140 subNoteChange(pars),
141 synth(orig.synth),
142 filterStep(orig.filterStep)
143 {
144 memcpy(pos, orig.pos, MAX_SUB_HARMONICS * sizeof(int));
145 memcpy(overtone_rolloff, orig.overtone_rolloff,
146 numharmonics * sizeof(float));
147 memcpy(overtone_freq, orig.overtone_freq,
148 numharmonics * sizeof(float));
149
150 AmpEnvelope = new Envelope(*orig.AmpEnvelope);
151
152 if (orig.FreqEnvelope != NULL)
153 FreqEnvelope = new Envelope(*orig.FreqEnvelope);
154 if (orig.BandWidthEnvelope != NULL)
155 BandWidthEnvelope = new Envelope(*orig.BandWidthEnvelope);
156 if (pars->PGlobalFilterEnabled != 0)
157 {
158 GlobalFilterL = new Filter(*orig.GlobalFilterL);
159 GlobalFilterR = new Filter(*orig.GlobalFilterR);
160 GlobalFilterEnvelope = new Envelope(*orig.GlobalFilterEnvelope);
161 }
162
163 if (orig.lfilter != NULL)
164 {
165 lfilter = new bpfilter[numstages * numharmonics];
166 memcpy(lfilter, orig.lfilter,
167 numstages * numharmonics * sizeof(bpfilter));
168 }
169 if (orig.rfilter != NULL)
170 {
171 rfilter = new bpfilter[numstages * numharmonics];
172 memcpy(rfilter, orig.rfilter,
173 numstages * numharmonics * sizeof(bpfilter));
174 }
175 }
176
177
legatoFadeIn(float basefreq_,float velocity_,int portamento_,int midinote_)178 void SUBnote::legatoFadeIn(float basefreq_, float velocity_, int portamento_, int midinote_)
179 {
180 velocity = velocity_ > 1.0f ? 1.0f : velocity_;
181 portamento = portamento_;
182 midinote = midinote_;
183
184 basefreq = basefreq_;
185 computeNoteFreq();
186
187 if (!portamento) // Do not crossfade portamento
188 {
189 legatoFade = 0.0f; // Start silent
190 legatoFadeStep = synth->fadeStepShort; // Positive steps
191
192 // I'm not sure if these are necessary or even beneficial
193 oldpitchwheel = 0;
194 oldbandwidth = 64;
195 oldamplitude = newamplitude;
196
197 }
198
199 computeNoteParameters();
200 }
201
202
legatoFadeOut(const SUBnote & orig)203 void SUBnote::legatoFadeOut(const SUBnote &orig)
204 {
205 velocity = orig.velocity;
206 portamento = orig.portamento;
207 midinote = orig.midinote;
208
209 firsttick = orig.firsttick;
210 volume = orig.volume;
211
212 basefreq = orig.basefreq;
213 notefreq = orig.notefreq;
214
215 // Not sure if this is necessary
216 oldamplitude = orig.oldamplitude;
217 newamplitude = orig.newamplitude;
218
219 // AmpEnvelope should never be null
220 *AmpEnvelope = *orig.AmpEnvelope;
221
222 if (orig.FreqEnvelope != NULL)
223 *FreqEnvelope = *orig.FreqEnvelope;
224 if (orig.BandWidthEnvelope != NULL)
225 *BandWidthEnvelope = *orig.BandWidthEnvelope;
226 if (pars->PGlobalFilterEnabled)
227 {
228 *GlobalFilterEnvelope = *orig.GlobalFilterEnvelope;
229
230 // Supporting virtual copy assignment would be hairy
231 // so we have to use the copy constructor here
232 delete GlobalFilterL;
233 GlobalFilterL = new Filter(*orig.GlobalFilterL);
234 delete GlobalFilterR;
235 GlobalFilterR = new Filter(*orig.GlobalFilterR);
236 }
237
238 // This assumes that numstages and numharmonics don't change
239 // while notes exist, or if they do change, they change for
240 // all notes equally and simultaneously. If this is ever not
241 // the case, this code needs to be changed.
242 if (orig.lfilter != NULL)
243 {
244 memcpy(lfilter, orig.lfilter,
245 numstages * numharmonics * sizeof(bpfilter));
246 }
247 if (orig.rfilter != NULL)
248 {
249 memcpy(rfilter, orig.rfilter,
250 numstages * numharmonics * sizeof(bpfilter));
251 }
252
253 memcpy(overtone_rolloff, orig.overtone_rolloff,
254 numharmonics * sizeof(float));
255 memcpy(overtone_freq, orig.overtone_freq,
256 numharmonics * sizeof(float));
257
258 legatoFade = 1.0f; // Start at full volume
259 legatoFadeStep = -synth->fadeStepShort; // Negative steps
260 }
261
262
~SUBnote()263 SUBnote::~SUBnote()
264 {
265 KillNote();
266 }
267
268
269 // Kill the note
KillNote(void)270 void SUBnote::KillNote(void)
271 {
272 if (NoteStatus != NOTE_DISABLED)
273 {
274 delete [] lfilter;
275 lfilter = NULL;
276 if (stereo)
277 delete [] rfilter;
278 rfilter = NULL;
279 delete AmpEnvelope;
280 if (FreqEnvelope != NULL)
281 delete FreqEnvelope;
282 if (BandWidthEnvelope != NULL)
283 delete BandWidthEnvelope;
284 NoteStatus = NOTE_DISABLED;
285 }
286 }
287
createNewFilters()288 int SUBnote::createNewFilters()
289 {
290 bool alreadyEnabled[MAX_SUB_HARMONICS];
291 memset(alreadyEnabled, 0, sizeof(alreadyEnabled));
292 for (int p = 0; p < numharmonics; ++p)
293 alreadyEnabled[pos[p]] = true;
294
295 // select only harmonics that desire to compute
296 int origNumHarmonics = numharmonics;
297 for (int n = 0; n < MAX_SUB_HARMONICS; ++n)
298 {
299 if (pars->Phmag[n] == 0 || alreadyEnabled[n])
300 continue;
301 if (n * notefreq > synth->halfsamplerate_f)
302 break; // remove the freqs above the Nyquist freq
303 pos[numharmonics++] = n;
304 alreadyEnabled[n] = true;
305 }
306
307 if (numharmonics == origNumHarmonics)
308 return 0;
309
310 bpfilter *newFilter = new bpfilter[numstages * numharmonics];
311 if (lfilter != NULL)
312 {
313 memcpy(newFilter, lfilter, numstages * origNumHarmonics * sizeof(bpfilter));
314 delete [] lfilter;
315 }
316 lfilter = newFilter;
317 if (stereo != 0)
318 {
319 newFilter = new bpfilter[numstages * numharmonics];
320 if (rfilter != NULL)
321 {
322 memcpy(newFilter, rfilter, numstages * origNumHarmonics * sizeof(bpfilter));
323 delete [] rfilter;
324 }
325 rfilter = newFilter;
326 }
327
328 return numharmonics - origNumHarmonics;
329 }
330
computeNoteFreq()331 void SUBnote::computeNoteFreq()
332 {
333 if (pars->Pfixedfreq == 0)
334 notefreq = basefreq;
335 else
336 {
337 notefreq = 440.0f;
338 int fixedfreqET = pars->PfixedfreqET;
339 if (fixedfreqET)
340 { // if the frequency varies according the keyboard note
341 float tmp =
342 (midinote - 69.0f) / 12.0f * power<2>((((fixedfreqET - 1) / 63.0f) - 1.0f));
343 if (fixedfreqET <= 64)
344 notefreq *= power<2>(tmp);
345 else
346 notefreq *= power<3>(tmp);
347 }
348 }
349
350 float detune = getDetune(pars->PDetuneType, pars->PCoarseDetune, pars->PDetune);
351 notefreq *= power<2>(detune / 1200.0f); // detune
352 }
353
computeNoteParameters()354 void SUBnote::computeNoteParameters()
355 {
356 volume = 2.0f // +6dB boost (note ADDnote and PADnote apply a +12dB boost)
357 * decibel<-60>(1.0f - pars->PVolume / 96.0f) // -60 dB .. +19.375 dB
358 * velF(velocity, pars->PAmpVelocityScaleFunction);
359
360 int BendAdj = pars->PBendAdjust - 64;
361 if (BendAdj % 24 == 0)
362 BendAdjust = BendAdj / 24;
363 else
364 BendAdjust = BendAdj / 24.0f;
365 float offset_val = (pars->POffsetHz - 64)/64.0f;
366 OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val)));
367
368 updatefilterbank();
369 }
370
371 // Compute the filters coefficients
computefiltercoefs(bpfilter & filter,float freq,float bw,float gain)372 void SUBnote::computefiltercoefs(bpfilter &filter, float freq, float bw, float gain)
373 {
374 if (freq > synth->halfsamplerate_f - 200.0f)
375 {
376 freq = synth->halfsamplerate_f - 200.0f;
377 }
378
379 float omega = TWOPI * freq / synth->samplerate_f;
380 float sn = sinf(omega);
381 float cs = cosf(omega);
382 float alpha = sn * sinhf(LOG_2 / 2.0f * bw * omega / sn);
383
384 if (alpha > 1)
385 alpha = 1;
386 if (alpha > bw)
387 alpha = bw;
388
389 filter.b0 = alpha / (1.0f + alpha) * filter.amp * gain;
390 filter.b2 = -alpha / (1.0f + alpha) * filter.amp * gain;
391 filter.a1 = -2.0f * cs / (1.0f + alpha);
392 filter.a2 = (1.0f - alpha) / (1.0f + alpha);
393 }
394
395
396 // Initialise the filters
initfilters(int startIndex)397 void SUBnote::initfilters(int startIndex)
398 {
399 for (int n = startIndex; n < numharmonics; ++n)
400 {
401 float hgain = getHgain(n);
402
403 for (int nph = 0; nph < numstages; ++nph)
404 {
405 initfilter(lfilter[nph + n * numstages], hgain);
406 if (stereo)
407 initfilter(rfilter[nph + n * numstages], hgain);
408 }
409 }
410 }
411
initfilter(bpfilter & filter,float mag)412 void SUBnote::initfilter(bpfilter &filter, float mag)
413 {
414 filter.xn1 = 0.0f;
415 filter.xn2 = 0.0f;
416
417 if (start == 0)
418 {
419 filter.yn1 = 0.0f;
420 filter.yn2 = 0.0f;
421 }
422 else
423 {
424 float a = 0.1f * mag; // empirically
425 float p = synth->numRandom() * TWOPI;
426 if (start == 1)
427 a *= synth->numRandom();
428 filter.yn1 = a * cosf(p);
429 filter.yn2 = a * cosf(p + filter.freq * TWOPI / synth->samplerate_f);
430
431 // correct the error of computation the start amplitude
432 // at very high frequencies
433 if (filter.freq > synth->samplerate_f * 0.96f)
434 {
435 filter.yn1 = 0.0f;
436 filter.yn2 = 0.0f;
437 }
438 }
439 }
440
441
442 // Do the filtering
SubFilterA(const float coeff[4],float & src,float work[4])443 inline void SubFilterA(const float coeff[4], float &src, float work[4])
444 {
445 work[3] = src*coeff[0]+work[1]*coeff[1]+work[2]*coeff[2]+work[3]*coeff[3];
446 work[1] = src;
447 src = work[3];
448 }
449
450
SubFilterB(const float coeff[4],float & src,float work[4])451 inline void SubFilterB(const float coeff[4], float &src, float work[4])
452 {
453 work[2] = src*coeff[0]+work[0]*coeff[1]+work[3]*coeff[2]+work[2]*coeff[3];
454 work[0] = src;
455 src = work[2];
456 }
457
458
459 // ported from zynaddsubfx V 2.4.4
460 //This dance is designed to minimize unneeded memory operations which can result
461 //in quite a bit of wasted time
filter(bpfilter & filter,float * smps)462 void SUBnote::filter(bpfilter &filter, float *smps)
463 {
464 if (synth->getIsLV2Plugin()){
465 filterVarRun(filter, smps);
466 return;
467 }
468
469 int remainder = synth->sent_buffersize % 8;
470 int blocksize = synth->sent_buffersize - remainder;
471 float coeff[4] = {filter.b0, filter.b2, -filter.a1, -filter.a2};
472 float work[4] = {filter.xn1, filter.xn2, filter.yn1, filter.yn2};
473
474 for (int i = 0; i < blocksize; i += 8)
475 {
476 SubFilterA(coeff, smps[i + 0], work);
477 SubFilterB(coeff, smps[i + 1], work);
478 SubFilterA(coeff, smps[i + 2], work);
479 SubFilterB(coeff, smps[i + 3], work);
480 SubFilterA(coeff, smps[i + 4], work);
481 SubFilterB(coeff, smps[i + 5], work);
482 SubFilterA(coeff, smps[i + 6], work);
483 SubFilterB(coeff, smps[i + 7], work);
484 }
485 if (remainder > 0)
486 {
487 for (int i = blocksize; i < blocksize + remainder ; i += 2)
488 {
489 SubFilterA(coeff, smps[i + 0], work);
490 SubFilterB(coeff, smps[i + 1], work);
491 }
492 }
493 filter.xn1 = work[0];
494 filter.xn2 = work[1];
495 filter.yn1 = work[2];
496 filter.yn2 = work[3];
497 }
498
499
500 //Andrew Deryabin: support for variable-length runs
501 //currently only for lv2 plugin
filterVarRun(SUBnote::bpfilter & filter,float * smps)502 void SUBnote::filterVarRun(SUBnote::bpfilter &filter, float *smps)
503 {
504 float tmpout;
505 int runLength = synth->sent_buffersize;
506 int i = 0;
507 if (runLength >= 8){
508 float coeff[4] = {filter.b0, filter.b2, -filter.a1, -filter.a2};
509 float work[4] = {filter.xn1, filter.xn2, filter.yn1, filter.yn2};
510 while (runLength >= 8){
511 SubFilterA(coeff, smps[i + 0], work);
512 SubFilterB(coeff, smps[i + 1], work);
513 SubFilterA(coeff, smps[i + 2], work);
514 SubFilterB(coeff, smps[i + 3], work);
515 SubFilterA(coeff, smps[i + 4], work);
516 SubFilterB(coeff, smps[i + 5], work);
517 SubFilterA(coeff, smps[i + 6], work);
518 SubFilterB(coeff, smps[i + 7], work);
519 i += 8;
520 runLength -= 8;
521 }
522 filter.xn1 = work[0];
523 filter.xn2 = work[1];
524 filter.yn1 = work[2];
525 filter.yn2 = work[3];
526 }
527
528 for (; i < synth->sent_buffersize; ++i){
529 tmpout=smps[i] * filter.b0 + filter.b2 * filter.xn2
530 -filter.a1 * filter.yn1 - filter.a2 * filter.yn2;
531 filter.xn2=filter.xn1;
532 filter.xn1=smps[i];
533 filter.yn2=filter.yn1;
534 filter.yn1=tmpout;
535 smps[i]=tmpout;
536 }
537
538 }
539
540
541 // Init Parameters
initparameters(float freq)542 void SUBnote::initparameters(float freq)
543 {
544 AmpEnvelope = new Envelope(pars->AmpEnvelope, freq, synth);
545 if (pars->PFreqEnvelopeEnabled != 0)
546 FreqEnvelope = new Envelope(pars->FreqEnvelope, freq, synth);
547 else
548 FreqEnvelope = NULL;
549 if (pars->PBandWidthEnvelopeEnabled != 0)
550 BandWidthEnvelope = new Envelope(pars->BandWidthEnvelope, freq, synth);
551 else
552 BandWidthEnvelope = NULL;
553 if (pars->PGlobalFilterEnabled != 0)
554 {
555 GlobalFilterL = new Filter(pars->GlobalFilter, synth);
556 if (stereo != 0)
557 GlobalFilterR = new Filter(pars->GlobalFilter, synth);
558 GlobalFilterEnvelope = new Envelope(pars->GlobalFilterEnvelope, freq, synth);
559 }
560 }
561 //end of port
562
563
564 // Compute how much to reduce amplitude near nyquist or subaudible frequencies.
computerolloff(float freq)565 float SUBnote::computerolloff(float freq)
566 {
567 const float lower_limit = 10.0f;
568 const float lower_width = 10.0f;
569 const float upper_width = 200.0f;
570 float upper_limit = synth->samplerate / 2.0f;
571
572 if (freq > lower_limit + lower_width &&
573 freq < upper_limit - upper_width)
574 return 1.0f;
575 if (freq <= lower_limit || freq >= upper_limit)
576 return 0.0f;
577 if (freq <= lower_limit + lower_width)
578 return (1.0f - cosf(PI * (freq - lower_limit) / lower_width)) / 2.0f;
579 return (1.0f - cosf(PI * (freq - upper_limit) / upper_width)) / 2.0f;
580 }
581
computeallfiltercoefs()582 void SUBnote::computeallfiltercoefs()
583 {
584 float envfreq = 1.0f;
585 float envbw = 1.0f;
586 float gain = 1.0f;
587
588 if (FreqEnvelope != NULL)
589 {
590 envfreq = FreqEnvelope->envout() / 1200;
591 envfreq = power<2>(envfreq);
592 }
593
594 envfreq *= powf(ctl->pitchwheel.relfreq, BendAdjust); // pitch wheel
595
596 if (portamento != 0)
597 { // portamento is used
598 envfreq *= ctl->portamento.freqrap;
599 if (ctl->portamento.used == 0)
600 { // the portamento has finished
601 portamento = 0; // this note is no longer "portamented"
602 }
603 }
604
605 if (BandWidthEnvelope != NULL)
606 {
607 envbw = BandWidthEnvelope->envout();
608 envbw = power<2>(envbw);
609 }
610 envbw *= ctl->bandwidth.relbw; // bandwidth controller
611
612 float tmpgain = 1.0f / sqrtf(envbw * envfreq);
613
614 for (int n = 0; n < numharmonics; ++n)
615 {
616 for (int nph = 0; nph < numstages; ++nph)
617 {
618 if (nph == 0)
619 gain = tmpgain;
620 else
621 gain = 1.0f;
622 computefiltercoefs(lfilter[nph + n * numstages],
623 lfilter[nph + n *numstages].freq * envfreq,
624 lfilter[nph + n * numstages].bw * envbw, gain);
625 }
626 }
627 if (stereo)
628 for (int n = 0; n < numharmonics; ++n)
629 {
630 for (int nph = 0; nph < numstages; ++nph)
631 {
632 if (nph == 0)
633 gain = tmpgain;
634 else
635 gain = 1.0f;
636 computefiltercoefs(rfilter[nph + n * numstages],
637 rfilter[nph + n * numstages].freq * envfreq,
638 rfilter[nph + n * numstages].bw * envbw, gain);
639 }
640 }
641 oldbandwidth = ctl->bandwidth.data;
642 oldpitchwheel = ctl->pitchwheel.data;
643 }
644
645 // Compute Parameters of SUBnote for each tick
computecurrentparameters(void)646 void SUBnote::computecurrentparameters(void)
647 {
648 if (FreqEnvelope != NULL
649 || BandWidthEnvelope != NULL
650 || oldpitchwheel != ctl->pitchwheel.data
651 || oldbandwidth != ctl->bandwidth.data
652 || portamento != 0)
653 computeallfiltercoefs();
654
655 // Envelope
656 newamplitude = volume * AmpEnvelope->envout_dB();
657
658 // Filter
659 if (GlobalFilterL != NULL)
660 {
661 float filterCenterPitch =
662 pars->GlobalFilter->getfreq()
663 + // center freq
664 (pars->PGlobalFilterVelocityScale / 127.0f * 6.0f)
665 * // velocity sensing
666 (velF(velocity, pars->PGlobalFilterVelocityScaleFunction) - 1);
667 float filtercenterq = pars->GlobalFilter->getq();
668 float filterFreqTracking = pars->GlobalFilter->getfreqtracking(basefreq);
669 float globalfilterpitch = filterCenterPitch + GlobalFilterEnvelope->envout();
670 float filterfreq = globalfilterpitch + ctl->filtercutoff.relfreq + filterFreqTracking;
671 filterfreq = GlobalFilterL->getrealfreq(filterfreq);
672
673 GlobalFilterL->setfreq_and_q(filterfreq, filtercenterq * ctl->filterq.relq);
674 if (GlobalFilterR != NULL)
675 GlobalFilterR->setfreq_and_q(filterfreq, filtercenterq * ctl->filterq.relq);
676 }
677 }
678
679
680 // Note Output
noteout(float * outl,float * outr)681 int SUBnote::noteout(float *outl, float *outr)
682 {
683 tmpsmp = synth->getRuntime().genTmp1;
684 tmprnd = synth->getRuntime().genTmp2;
685 memset(outl, 0, synth->sent_bufferbytes);
686 memset(outr, 0, synth->sent_bufferbytes);
687 if (NoteStatus == NOTE_DISABLED)
688 return 0;
689
690 if (subNoteChange.checkUpdated())
691 {
692 computeNoteFreq();
693 computeNoteParameters();
694 }
695
696 // left channel
697 for (int i = 0; i < synth->sent_buffersize; ++i)
698 tmprnd[i] = synth->numRandom() * 2.0f - 1.0f;
699 for (int n = 0; n < numharmonics; ++n)
700 {
701 float rolloff = overtone_rolloff[n];
702 memcpy(tmpsmp, tmprnd, synth->sent_bufferbytes);
703 for (int nph = 0; nph < numstages; ++nph)
704 filter(lfilter[nph + n * numstages], tmpsmp);
705 for (int i = 0; i < synth->sent_buffersize; ++i)
706 outl[i] += tmpsmp[i] * rolloff;
707 }
708
709 if (GlobalFilterL != NULL)
710 GlobalFilterL->filterout(outl);
711
712 // right channel
713 if (stereo)
714 {
715 for (int i = 0; i < synth->sent_buffersize; ++i)
716 tmprnd[i] = synth->numRandom() * 2.0f - 1.0f;
717 for (int n = 0; n < numharmonics; ++n)
718 {
719 float rolloff = overtone_rolloff[n];
720 memcpy(tmpsmp, tmprnd, synth->sent_bufferbytes);
721 for (int nph = 0; nph < numstages; ++nph)
722 filter(rfilter[nph + n * numstages], tmpsmp);
723 for (int i = 0; i < synth->sent_buffersize; ++i)
724 outr[i] += tmpsmp[i] * rolloff;
725 }
726 if (GlobalFilterR != NULL)
727 GlobalFilterR->filterout(outr);
728 }
729 else
730 memcpy(outr, outl, synth->sent_bufferbytes);
731
732 if (firsttick)
733 {
734 int n = 10;
735 if (n > synth->sent_buffersize)
736 n = synth->sent_buffersize;
737 for (int i = 0; i < n; ++i)
738 {
739 float ampfadein = 0.5f - 0.5f * cosf((float)i / (float)n * PI);
740 outl[i] *= ampfadein;
741 outr[i] *= ampfadein;
742 }
743 firsttick = 0;
744 }
745
746
747 float pangainL = pars->pangainL; // assume non random pan
748 float pangainR = pars->pangainR;
749 if (pars->PRandom)
750 {
751 pangainL = randpanL;
752 pangainR = randpanR;
753 }
754
755 if (aboveAmplitudeThreshold(oldamplitude, newamplitude))
756 {
757 // Amplitude interpolation
758 for (int i = 0; i < synth->sent_buffersize; ++i)
759 {
760 float tmpvol = interpolateAmplitude(oldamplitude, newamplitude, i,
761 synth->sent_buffersize);
762 outl[i] *= tmpvol * pangainL;
763 outr[i] *= tmpvol * pangainR;
764 }
765 }
766 else
767 {
768 for (int i = 0; i < synth->sent_buffersize; ++i)
769 {
770 outl[i] *= newamplitude * pangainL;
771 outr[i] *= newamplitude * pangainR;
772 }
773 }
774 oldamplitude = newamplitude;
775 computecurrentparameters();
776
777 // Apply legato fading if any
778 if (legatoFadeStep != 0.0f)
779 {
780 for (int i = 0; i < synth->sent_buffersize; ++i)
781 {
782 legatoFade += legatoFadeStep;
783 if (legatoFade <= 0.0f)
784 {
785 legatoFade = 0.0f;
786 legatoFadeStep = 0.0f;
787 memset(outl + i, 0, (synth->sent_buffersize - i) * sizeof(float));
788 memset(outr + i, 0, (synth->sent_buffersize - i) * sizeof(float));
789 break;
790 }
791 else if (legatoFade >= 1.0f)
792 {
793 legatoFade = 1.0f;
794 legatoFadeStep = 0.0f;
795 break;
796 }
797 outl[i] *= legatoFade;
798 outr[i] *= legatoFade;
799 }
800 }
801
802 // Check if the note needs to be computed more
803 if (AmpEnvelope->finished() != 0)
804 {
805 for (int i = 0; i < synth->sent_buffersize; ++i)
806 { // fade-out
807 float tmp = 1.0f - (float)i / synth->sent_buffersize_f;
808 outl[i] *= tmp;
809 outr[i] *= tmp;
810 }
811 KillNote();
812 }
813 return 1;
814 }
815
816
817 // Release Key (Note Off)
releasekey(void)818 void SUBnote::releasekey(void)
819 {
820 AmpEnvelope->releasekey();
821 if (FreqEnvelope != NULL)
822 FreqEnvelope->releasekey();
823 if (BandWidthEnvelope != NULL)
824 BandWidthEnvelope->releasekey();
825 if (GlobalFilterEnvelope != NULL)
826 GlobalFilterEnvelope->releasekey();
827 if (NoteStatus == NOTE_KEEPALIVE)
828 NoteStatus = NOTE_ENABLED;
829 }
830
getHgain(int harmonic)831 float SUBnote::getHgain(int harmonic)
832 {
833 if (pars->Phmag[pos[harmonic]] == 0)
834 return 0.0f;
835
836 float hmagnew = 1.0f - pars->Phmag[pos[harmonic]] / 127.0f;
837 float hgain;
838
839 switch (pars->Phmagtype)
840 {
841 case 1:
842 hgain = powFrac<100>(hmagnew);
843 break;
844
845 case 2:
846 hgain = powFrac<1000>(hmagnew);
847 break;
848
849 case 3:
850 hgain = powFrac<10000>(hmagnew);
851 break;
852
853 case 4:
854 hgain = powFrac<100000>(hmagnew);
855 break;
856
857 default:
858 hgain = 1.0f - hmagnew;
859 break;
860 }
861
862 return hgain;
863 }
864
updatefilterbank(void)865 void SUBnote::updatefilterbank(void)
866 {
867 int createdFilters = createNewFilters();
868
869 // moved from noteon
870 // how much the amplitude is normalised (because the harmonics)
871 float reduceamp = 0.0;
872
873 for (int n = 0; n < numharmonics; ++n)
874 {
875 float freq = notefreq * pars->POvertoneFreqMult[pos[n]];
876 overtone_freq[n] = freq;
877 overtone_rolloff[n] = computerolloff(freq);
878
879 // the bandwidth is not absolute(Hz); it is relative to frequency
880 float bw = power<10>((pars->Pbandwidth - 127.0f) / 127.0f * 4.0f) * numstages;
881
882 // Bandwidth Scale
883 bw *= powf(1000.0f / freq, (pars->Pbwscale - 64.0f) / 64.0f * 3.0f);
884
885 // Relative BandWidth
886 bw *= power<100>((pars->Phrelbw[pos[n]] - 64.0f) / 64.0f);
887
888 if (bw > 25.0f)
889 bw = 25.0f;
890
891 // try to keep same amplitude on all freqs and bw. (empirically)
892 float gain = sqrtf(1500.0f / (bw * freq));
893
894 float hgain = getHgain(n);
895
896 gain *= hgain;
897 reduceamp += hgain;
898
899 for (int nph = 0; nph < numstages; ++nph)
900 {
901 float amp = 1.0f;
902 if (nph == 0)
903 amp = gain;
904 bpfilter *filter = &lfilter[nph + n * numstages];
905 filter->amp = amp;
906 filter->freq = freq + OffsetHz;
907 filter->bw = bw;
908 if (stereo)
909 {
910 filter = &rfilter[nph + n * numstages];
911 filter->amp = amp;
912 filter->freq = freq + OffsetHz;
913 filter->bw = bw;
914 }
915 }
916 }
917
918 initfilters(numharmonics - createdFilters);
919 computeallfiltercoefs();
920
921 if (reduceamp < 0.001f)
922 reduceamp = 1.0f;
923 volume /= reduceamp;
924 }
925