SUBnote.cpp (19219B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 SUBnote.cpp - The "subtractive" synthesizer 5 Copyright (C) 2002-2005 Nasca Octavian Paul 6 Author: Nasca Octavian Paul 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License 10 as published by the Free Software Foundation; either version 2 11 of the License, or (at your option) any later version. 12 */ 13 14 #include <cmath> 15 #include <cstdlib> 16 #include <cstdio> 17 #include <cassert> 18 #include <iostream> 19 #include "../globals.h" 20 #include "SUBnote.h" 21 #include "Envelope.h" 22 #include "ModFilter.h" 23 #include "Portamento.h" 24 #include "../Containers/ScratchString.h" 25 #include "../Containers/NotePool.h" 26 #include "../Params/Controller.h" 27 #include "../Params/SUBnoteParameters.h" 28 #include "../Params/FilterParams.h" 29 #include "../Misc/Time.h" 30 #include "../Misc/Util.h" 31 #include "../Misc/Allocator.h" 32 33 #ifndef M_PI 34 # define M_PI 3.14159265358979323846 /* pi */ 35 #endif 36 37 namespace zyn { 38 39 SUBnote::SUBnote(const SUBnoteParameters *parameters, const SynthParams &spars, 40 WatchManager *wm, const char *prefix) : 41 SynthNote(spars), 42 watch_filter(wm, prefix, "noteout/filter"), watch_amp_int(wm,prefix,"noteout/amp_int"), 43 watch_legato(wm, prefix, "noteout/legato"), 44 pars(*parameters), 45 AmpEnvelope(nullptr), 46 FreqEnvelope(nullptr), 47 BandWidthEnvelope(nullptr), 48 GlobalFilter(nullptr), 49 GlobalFilterEnvelope(nullptr), 50 NoteEnabled(true), 51 lfilter(nullptr), rfilter(nullptr), 52 filterupdate(false) 53 { 54 setup(spars.velocity, spars.portamento, spars.note_log2_freq, false, wm, prefix); 55 } 56 57 float SUBnote::setupFilters(float basefreq, int *pos, bool automation) 58 { 59 //how much the amplitude is normalised (because the harmonics) 60 float reduceamp = 0.0f; 61 62 for(int n = 0; n < numharmonics; ++n) { 63 const float freq = basefreq * pars.POvertoneFreqMult[pos[n]]; 64 overtone_freq[n] = freq; 65 overtone_rolloff[n] = computerolloff(freq); 66 67 //the bandwidth is not absolute(Hz); it is relative to frequency 68 const float bw = SUBnoteParameters::convertBandwidth(pars.Pbandwidth, 69 numstages, freq, pars.Pbwscale, pars.Phrelbw[pos[n]]); 70 71 //try to keep same amplitude on all freqs and bw. (empirically) 72 const float hgain = SUBnoteParameters::convertHarmonicMag(pars.Phmag[pos[n]], 73 pars.Phmagtype); 74 const float gain = hgain * sqrt(1500.0f / (bw * freq)); 75 76 reduceamp += hgain; 77 78 for(int nph = 0; nph < numstages; ++nph) { 79 float amp = 1.0f; 80 if(nph == 0) 81 amp = gain; 82 initfilter(lfilter[nph + n * numstages], freq + OffsetHz, bw, 83 amp, hgain, automation); 84 if(stereo) 85 initfilter(rfilter[nph + n * numstages], freq + OffsetHz, bw, 86 amp, hgain, automation); 87 } 88 } 89 90 if(reduceamp < 0.001f) 91 reduceamp = 1.0f; 92 93 return reduceamp; 94 } 95 96 void SUBnote::setup(float velocity_, 97 Portamento *portamento_, 98 float note_log2_freq_, 99 bool legato, 100 WatchManager *wm, 101 const char *prefix) 102 { 103 velocity = velocity_; 104 portamento = portamento_; 105 NoteEnabled = ON; 106 volume = powf(10.0, pars.Volume / 20.0f); 107 volume *= VelF(velocity_, pars.AmpVelocityScaleFunction); 108 if(pars.PPanning != 0) 109 panning = pars.PPanning / 127.0f; 110 else if (!legato) 111 panning = RND; 112 113 if(!legato) { //normal note 114 numstages = pars.Pnumstages; 115 stereo = pars.Pstereo; 116 start = pars.Pstart; 117 firsttick = 1; 118 } 119 120 if(pars.Pfixedfreq == 0) { 121 note_log2_freq = note_log2_freq_; 122 } 123 else { //the fixed freq is enabled 124 const int fixedfreqET = pars.PfixedfreqET; 125 float fixedfreq_log2 = log2f(440.0f); 126 127 if(fixedfreqET != 0) { //if the frequency varies according the keyboard note 128 float tmp_log2 = (note_log2_freq_ - fixedfreq_log2) * 129 (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f); 130 if(fixedfreqET <= 64) 131 fixedfreq_log2 += tmp_log2; 132 else 133 fixedfreq_log2 += tmp_log2 * log2f(3.0f); 134 } 135 note_log2_freq = fixedfreq_log2; 136 } 137 138 int BendAdj = pars.PBendAdjust - 64; 139 if (BendAdj % 24 == 0) 140 BendAdjust = BendAdj / 24; 141 else 142 BendAdjust = BendAdj / 24.0f; 143 const float offset_val = (pars.POffsetHz - 64)/64.0f; 144 OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val))); 145 const float detune = getdetune(pars.PDetuneType, 146 pars.PCoarseDetune, 147 pars.PDetune); 148 149 note_log2_freq += detune / 1200.0f; //detune 150 151 const float basefreq = powf(2.0f, note_log2_freq); 152 153 int pos[MAX_SUB_HARMONICS]; 154 int harmonics; 155 156 pars.activeHarmonics(pos, harmonics); 157 158 if(!legato) //normal note 159 firstnumharmonics = numharmonics = harmonics; 160 else { 161 if(harmonics > firstnumharmonics) 162 numharmonics = firstnumharmonics; 163 else 164 numharmonics = harmonics; 165 } 166 167 168 if(numharmonics == 0) { 169 NoteEnabled = false; 170 return; 171 } 172 173 174 if(!legato) { //normal note 175 lfilter = memory.valloc<bpfilter>(numstages * numharmonics); 176 if(stereo) 177 rfilter = memory.valloc<bpfilter>(numstages * numharmonics); 178 } 179 180 //how much the amplitude is normalised (because the harmonics) 181 const float reduceamp = setupFilters(basefreq, pos, legato); 182 oldreduceamp = reduceamp; 183 volume /= reduceamp; 184 185 oldpitchwheel = 0; 186 oldbandwidth = 64; 187 188 const float freq = powf(2.0f, note_log2_freq_); 189 if(!legato) { //normal note 190 if(pars.Pfixedfreq == 0) 191 initparameters(basefreq, wm, prefix); 192 else 193 initparameters(basefreq / 440.0f * freq, wm, prefix); 194 } 195 else { 196 if(GlobalFilter) { 197 if(pars.Pfixedfreq == 0) 198 GlobalFilter->updateNoteFreq(basefreq); 199 else 200 GlobalFilter->updateNoteFreq(basefreq / 440.0f * freq); 201 202 GlobalFilter->updateSense(velocity, pars.PGlobalFilterVelocityScale, 203 pars.PGlobalFilterVelocityScaleFunction); 204 } 205 } 206 } 207 208 SynthNote *SUBnote::cloneLegato(void) 209 { 210 SynthParams sp{memory, ctl, synth, time, velocity, 211 portamento, legato.param.note_log2_freq, true, legato.param.seed}; 212 return memory.alloc<SUBnote>(&pars, sp); 213 } 214 215 void SUBnote::legatonote(const LegatoParams &pars) 216 { 217 // Manage legato stuff 218 if(legato.update(pars)) 219 return; 220 221 try { 222 setup(pars.velocity, pars.portamento, pars.note_log2_freq, true, wm); 223 } catch (std::bad_alloc &ba) { 224 std::cerr << "failed to set legato note parameter in SUBnote: " << ba.what() << std::endl; 225 } 226 } 227 228 SUBnote::~SUBnote() 229 { 230 if(NoteEnabled) 231 KillNote(); 232 } 233 234 /* 235 * Kill the note 236 */ 237 void SUBnote::KillNote() 238 { 239 if(NoteEnabled) { 240 memory.devalloc(numstages * numharmonics, lfilter); 241 if(stereo) 242 memory.devalloc(numstages * numharmonics, rfilter); 243 memory.dealloc(AmpEnvelope); 244 memory.dealloc(FreqEnvelope); 245 memory.dealloc(BandWidthEnvelope); 246 memory.dealloc(GlobalFilter); 247 memory.dealloc(GlobalFilterEnvelope); 248 NoteEnabled = false; 249 } 250 } 251 252 253 /* 254 * Compute the filters coefficients 255 */ 256 void SUBnote::computefiltercoefs(bpfilter &filter, 257 float freq, 258 float bw, 259 float gain) 260 { 261 if(freq > synth.samplerate_f / 2.0f - 200.0f) 262 freq = synth.samplerate_f / 2.0f - 200.0f; 263 264 265 float omega = 2.0f * PI * freq / synth.samplerate_f; 266 float sn = sinf(omega); 267 float cs = cosf(omega); 268 float alpha = sn * sinh(LOG_2 / 2.0f * bw * omega / sn); 269 270 if(alpha > 1) 271 alpha = 1; 272 if(alpha > bw) 273 alpha = bw; 274 275 filter.b0 = alpha / (1.0f + alpha) * filter.amp * gain; 276 filter.b2 = -alpha / (1.0f + alpha) * filter.amp * gain; 277 filter.a1 = -2.0f * cs / (1.0f + alpha); 278 filter.a2 = (1.0f - alpha) / (1.0f + alpha); 279 } 280 281 282 /* 283 * Initialise the filters 284 */ 285 void SUBnote::initfilter(bpfilter &filter, 286 float freq, 287 float bw, 288 float amp, 289 float mag, 290 bool automation) 291 { 292 if(!automation) { 293 filter.xn1 = 0.0f; 294 filter.xn2 = 0.0f; 295 296 if(start == 0) { 297 filter.yn1 = 0.0f; 298 filter.yn2 = 0.0f; 299 } 300 else { 301 float a = 0.1f * mag; //empirically 302 float p = RND * 2.0f * PI; 303 if(start == 1) 304 a *= RND; 305 filter.yn1 = a * cosf(p); 306 filter.yn2 = a * cosf(p + freq * 2.0f * PI / synth.samplerate_f); 307 308 //correct the error of computation the start amplitude 309 //at very high frequencies 310 if(freq > synth.samplerate_f * 0.96f) { 311 filter.yn1 = 0.0f; 312 filter.yn2 = 0.0f; 313 } 314 } 315 } 316 317 filter.amp = amp; 318 filter.freq = freq; 319 filter.bw = bw; 320 321 if (!automation) 322 computefiltercoefs(filter, freq, bw, 1.0f); 323 else 324 filterupdate = true; 325 } 326 327 /* 328 * Do the filtering 329 */ 330 331 inline void SubFilterA(const float coeff[4], float &src, float work[4]) 332 { 333 work[3] = src*coeff[0]+work[1]*coeff[1]+work[2]*coeff[2]+work[3]*coeff[3]; 334 work[1] = src; 335 src = work[3]; 336 } 337 338 inline void SubFilterB(const float coeff[4], float &src, float work[4]) 339 { 340 work[2] = src*coeff[0]+work[0]*coeff[1]+work[3]*coeff[2]+work[2]*coeff[3]; 341 work[0] = src; 342 src = work[2]; 343 } 344 345 //This dance is designed to minimize unneeded memory operations which can result 346 //in quite a bit of wasted time 347 void SUBnote::filter(bpfilter &filter, float *smps) 348 { 349 assert(synth.buffersize % 8 == 0); 350 float coeff[4] = {filter.b0, filter.b2, -filter.a1, -filter.a2}; 351 float work[4] = {filter.xn1, filter.xn2, filter.yn1, filter.yn2}; 352 353 for(int i = 0; i < synth.buffersize; i += 8) { 354 SubFilterA(coeff, smps[i + 0], work); 355 SubFilterB(coeff, smps[i + 1], work); 356 SubFilterA(coeff, smps[i + 2], work); 357 SubFilterB(coeff, smps[i + 3], work); 358 SubFilterA(coeff, smps[i + 4], work); 359 SubFilterB(coeff, smps[i + 5], work); 360 SubFilterA(coeff, smps[i + 6], work); 361 SubFilterB(coeff, smps[i + 7], work); 362 } 363 filter.xn1 = work[0]; 364 filter.xn2 = work[1]; 365 filter.yn1 = work[2]; 366 filter.yn2 = work[3]; 367 } 368 369 /* 370 * Init Parameters 371 */ 372 void SUBnote::initparameters(float freq, WatchManager *wm, const char *prefix) 373 { 374 ScratchString pre = prefix; 375 AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, freq, 376 synth.dt(), wm, (pre+"AmpEnvelope/").c_str); 377 378 if(pars.PFreqEnvelopeEnabled) 379 FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, freq, 380 synth.dt(), wm, (pre+"FreqEnvelope/").c_str); 381 382 if(pars.PBandWidthEnvelopeEnabled) 383 BandWidthEnvelope = memory.alloc<Envelope>(*pars.BandWidthEnvelope, 384 freq, synth.dt(), wm, (pre+"BandWidthEnvelope/").c_str); 385 386 if(pars.PGlobalFilterEnabled) { 387 GlobalFilterEnvelope = 388 memory.alloc<Envelope>(*pars.GlobalFilterEnvelope, freq, 389 synth.dt(), wm, (pre+"GlobalFilterEnvelope/").c_str); 390 391 GlobalFilter = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, stereo, freq); 392 393 GlobalFilter->updateSense(velocity, pars.PGlobalFilterVelocityScale, 394 pars.PGlobalFilterVelocityScaleFunction); 395 396 GlobalFilter->addMod(*GlobalFilterEnvelope); 397 } 398 computecurrentparameters(); 399 oldamplitude = newamplitude; 400 } 401 402 /* 403 * Compute how much to reduce amplitude near nyquist or subaudible frequencies. 404 */ 405 float SUBnote::computerolloff(float freq) 406 { 407 const float lower_limit = 10.0f; 408 const float lower_width = 10.0f; 409 const float upper_width = 200.0f; 410 float upper_limit = synth.samplerate / 2.0f; 411 412 if (freq > lower_limit + lower_width && 413 freq < upper_limit - upper_width) 414 return 1.0f; 415 if (freq <= lower_limit || freq >= upper_limit) 416 return 0.0f; 417 if (freq <= lower_limit + lower_width) 418 return (1.0f - cosf(M_PI * (freq - lower_limit) / lower_width)) / 2.0f; 419 return (1.0f - cosf(M_PI * (freq - upper_limit) / upper_width)) / 2.0f; 420 } 421 422 /* 423 * Compute Parameters of SUBnote for each tick 424 */ 425 void SUBnote::computecurrentparameters() 426 { 427 //Recompute parameters for realtime automation 428 if(pars.time && pars.last_update_timestamp == pars.time->time()) { 429 //A little bit of copy/paste for now 430 431 int pos[MAX_SUB_HARMONICS]; 432 int harmonics; 433 434 pars.activeHarmonics(pos, harmonics); 435 436 bool delta_harmonics = (harmonics != numharmonics); 437 if(delta_harmonics) { 438 memory.devalloc(lfilter); 439 memory.devalloc(rfilter); 440 441 firstnumharmonics = numharmonics = harmonics; 442 lfilter = memory.valloc<bpfilter>(numstages * numharmonics); 443 if(stereo) 444 rfilter = memory.valloc<bpfilter>(numstages * numharmonics); 445 } 446 447 const float basefreq = powf(2.0f, note_log2_freq); 448 const float reduceamp = setupFilters(basefreq, pos, !delta_harmonics); 449 volume = volume*oldreduceamp/reduceamp; 450 oldreduceamp = reduceamp; 451 } 452 453 if(FreqEnvelope || BandWidthEnvelope 454 || (oldpitchwheel != ctl.pitchwheel.data) 455 || (oldbandwidth != ctl.bandwidth.data) 456 || (portamento != NULL) 457 || filterupdate) { 458 float envfreq = 1.0f; 459 float envbw = 1.0f; 460 461 if(FreqEnvelope) { 462 envfreq = FreqEnvelope->envout() / 1200.0f; 463 envfreq = powf(2.0f, envfreq); 464 } 465 466 envfreq *= 467 powf(ctl.pitchwheel.relfreq, BendAdjust); //pitch wheel 468 469 //Update frequency while portamento is converging 470 if(portamento) { 471 envfreq *= powf(2.0f, portamento->freqdelta_log2); 472 if(!portamento->active) //the portamento has finished 473 portamento = NULL; 474 } 475 476 if(BandWidthEnvelope) { 477 envbw = BandWidthEnvelope->envout(); 478 envbw = powf(2, envbw); 479 } 480 481 envbw *= ctl.bandwidth.relbw; //bandwidth controller 482 483 484 //Recompute High Frequency Dampening Terms 485 for(int n = 0; n < numharmonics; ++n) 486 overtone_rolloff[n] = computerolloff(overtone_freq[n] * envfreq); 487 488 489 //Recompute Filter Coefficients 490 float tmpgain = 1.0f / sqrt(envbw * envfreq); 491 computeallfiltercoefs(lfilter, envfreq, envbw, tmpgain); 492 if(stereo) 493 computeallfiltercoefs(rfilter, envfreq, envbw, tmpgain); 494 495 496 oldbandwidth = ctl.bandwidth.data; 497 oldpitchwheel = ctl.pitchwheel.data; 498 filterupdate = false; 499 } 500 newamplitude = volume * AmpEnvelope->envout_dB() * 2.0f; 501 502 //Filter 503 if(GlobalFilter) { 504 const float relfreq = getFilterCutoffRelFreq(); 505 GlobalFilter->update(relfreq, ctl.filterq.relq); 506 } 507 } 508 509 void SUBnote::computeallfiltercoefs(bpfilter *filters, float envfreq, 510 float envbw, float gain) 511 { 512 for(int n = 0; n < numharmonics; ++n) 513 for(int nph = 0; nph < numstages; ++nph) 514 computefiltercoefs(filters[nph + n * numstages], 515 filters[nph + n * numstages].freq * envfreq, 516 filters[nph + n * numstages].bw * envbw, 517 nph == 0 ? gain : 1.0); 518 } 519 520 void SUBnote::chanOutput(float *out, bpfilter *bp, int buffer_size) 521 { 522 float tmprnd[buffer_size]; 523 float tmpsmp[buffer_size]; 524 525 //Initialize Random Input 526 for(int i = 0; i < buffer_size; ++i) 527 tmprnd[i] = RND * 2.0f - 1.0f; 528 529 //For each harmonic apply the filter on the random input stream 530 //Sum the filter outputs to obtain the output signal 531 for(int n = 0; n < numharmonics; ++n) { 532 float rolloff = overtone_rolloff[n]; 533 memcpy(tmpsmp, tmprnd, synth.bufferbytes); 534 535 for(int nph = 0; nph < numstages; ++nph) 536 filter(bp[nph + n * numstages], tmpsmp); 537 538 for(int i = 0; i < synth.buffersize; ++i) 539 out[i] += tmpsmp[i] * rolloff; 540 } 541 } 542 543 /* 544 * Note Output 545 */ 546 int SUBnote::noteout(float *outl, float *outr) 547 { 548 memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); 549 memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); 550 551 if(!NoteEnabled) 552 return 0; 553 554 if(stereo) { 555 chanOutput(outl, lfilter, synth.buffersize); 556 chanOutput(outr, rfilter, synth.buffersize); 557 558 if(GlobalFilter) 559 GlobalFilter->filter(outl, outr); 560 561 } else { 562 chanOutput(outl, lfilter, synth.buffersize); 563 564 if(GlobalFilter) 565 GlobalFilter->filter(outl, 0); 566 567 memcpy(outr, outl, synth.bufferbytes); 568 } 569 watch_filter(outl,synth.buffersize); 570 if(firsttick) { 571 int n = 10; 572 if(n > synth.buffersize) 573 n = synth.buffersize; 574 for(int i = 0; i < n; ++i) { 575 float ampfadein = 0.5f - 0.5f * cosf( 576 (float) i / (float) n * PI); 577 outl[i] *= ampfadein; 578 outr[i] *= ampfadein; 579 } 580 firsttick = false; 581 } 582 583 if(ABOVE_AMPLITUDE_THRESHOLD(oldamplitude, newamplitude)) 584 // Amplitude interpolation 585 for(int i = 0; i < synth.buffersize; ++i) { 586 float tmpvol = INTERPOLATE_AMPLITUDE(oldamplitude, 587 newamplitude, 588 i, 589 synth.buffersize); 590 outl[i] *= tmpvol * (1.0f - panning); 591 outr[i] *= tmpvol * panning; 592 } 593 else 594 for(int i = 0; i < synth.buffersize; ++i) { 595 outl[i] *= newamplitude * (1.0f - panning); 596 outr[i] *= newamplitude * panning; 597 } 598 watch_amp_int(outl,synth.buffersize); 599 oldamplitude = newamplitude; 600 computecurrentparameters(); 601 602 // Apply legato-specific sound signal modifications 603 legato.apply(*this, outl, outr); 604 watch_legato(outl,synth.buffersize); 605 // Check if the note needs to be computed more 606 if(AmpEnvelope->finished() != 0) { 607 for(int i = 0; i < synth.buffersize; ++i) { //fade-out 608 float tmp = 1.0f - (float)i / synth.buffersize_f; 609 outl[i] *= tmp; 610 outr[i] *= tmp; 611 } 612 KillNote(); 613 } 614 return 1; 615 } 616 617 /* 618 * Release Key (Note Off) 619 */ 620 void SUBnote::releasekey() 621 { 622 AmpEnvelope->releasekey(); 623 if(FreqEnvelope) 624 FreqEnvelope->releasekey(); 625 if(BandWidthEnvelope) 626 BandWidthEnvelope->releasekey(); 627 if(GlobalFilterEnvelope) 628 GlobalFilterEnvelope->releasekey(); 629 } 630 631 /* 632 * Check if the note is finished 633 */ 634 bool SUBnote::finished() const 635 { 636 return !NoteEnabled; 637 } 638 639 void SUBnote::entomb(void) 640 { 641 AmpEnvelope->forceFinish(); 642 } 643 644 }