| 
							- /*
 -   ZynAddSubFX - a software synthesizer
 - 
 -   SUBnote.cpp - The "subtractive" synthesizer
 -   Copyright (C) 2002-2005 Nasca Octavian Paul
 -   Author: Nasca Octavian Paul
 - 
 -   This program is free software; you can redistribute it and/or modify
 -   it under the terms of version 2 of the GNU General Public License
 -   as published by the Free Software Foundation.
 - 
 -   This program is distributed in the hope that it will be useful,
 -   but WITHOUT ANY WARRANTY; without even the implied warranty of
 -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -   GNU General Public License (version 2 or later) for more details.
 - 
 -   You should have received a copy of the GNU General Public License (version 2)
 -   along with this program; if not, write to the Free Software Foundation,
 -   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 - 
 - */
 - 
 - #include <cmath>
 - #include <cstdlib>
 - #include <cstdio>
 - #include <cassert>
 - #include "../globals.h"
 - #include "SUBnote.h"
 - #include "../Misc/Util.h"
 - 
 - SUBnote::SUBnote(SUBnoteParameters *parameters,
 -                  Controller *ctl_,
 -                  float freq,
 -                  float velocity,
 -                  int portamento_,
 -                  int midinote,
 -                  bool besilent)
 -     :SynthNote(freq, velocity, portamento_, midinote, besilent)
 - {
 -     pars = parameters;
 -     ctl  = ctl_;
 -     NoteEnabled = ON;
 -     setup(freq, velocity, portamento_, midinote);
 - }
 - 
 - void SUBnote::setup(float freq,
 -                     float velocity,
 -                     int portamento_,
 -                     int midinote,
 -                     bool legato)
 - {
 -     portamento  = portamento_;
 -     NoteEnabled = ON;
 -     volume      = powf(0.1f, 3.0f * (1.0f - pars->PVolume / 96.0f)); //-60 dB .. 0 dB
 -     volume     *= VelF(velocity, pars->PAmpVelocityScaleFunction);
 -     if(pars->PPanning != 0)
 -         panning = pars->PPanning / 127.0f;
 -     else
 -         panning = RND;
 -     if(!legato) {
 -         numstages = pars->Pnumstages;
 -         stereo    = pars->Pstereo;
 -         start     = pars->Pstart;
 -         firsttick = 1;
 -     }
 -     int pos[MAX_SUB_HARMONICS];
 - 
 -     if(pars->Pfixedfreq == 0)
 -         basefreq = freq;
 -     else {
 -         basefreq = 440.0f;
 -         int fixedfreqET = pars->PfixedfreqET;
 -         if(fixedfreqET != 0) { //if the frequency varies according the keyboard note
 -             float tmp =
 -                 (midinote
 -                  - 69.0f) / 12.0f
 -                 * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
 -             if(fixedfreqET <= 64)
 -                 basefreq *= powf(2.0f, tmp);
 -             else
 -                 basefreq *= powf(3.0f, tmp);
 -         }
 -     }
 -     float detune = getdetune(pars->PDetuneType,
 -                              pars->PCoarseDetune,
 -                              pars->PDetune);
 -     basefreq *= powf(2.0f, detune / 1200.0f); //detune
 - //    basefreq*=ctl->pitchwheel.relfreq;//pitch wheel
 - 
 -     //global filter
 -     GlobalFilterCenterPitch = pars->GlobalFilter->getfreq() //center freq
 -                               + (pars->PGlobalFilterVelocityScale / 127.0f
 -                                  * 6.0f)                                           //velocity sensing
 -                               * (VelF(velocity,
 -                                       pars->PGlobalFilterVelocityScaleFunction)
 -                                  - 1);
 - 
 -     if(!legato) {
 -         GlobalFilterL = NULL;
 -         GlobalFilterR = NULL;
 -         GlobalFilterEnvelope = NULL;
 -     }
 - 
 -     //select only harmonics that desire to compute
 -     int harmonics = 0;
 -     for(int n = 0; n < MAX_SUB_HARMONICS; ++n) {
 -         if(pars->Phmag[n] == 0)
 -             continue;
 -         if(n * basefreq > synth->samplerate_f / 2.0f)
 -             break;                            //remove the freqs above the Nyquist freq
 -         pos[harmonics++] = n;
 -     }
 -     if(!legato)
 -         firstnumharmonics = numharmonics = harmonics;
 -     else {
 -         if(harmonics > firstnumharmonics)
 -             numharmonics = firstnumharmonics;
 -         else
 -             numharmonics = harmonics;
 -     }
 - 
 - 
 -     if(numharmonics == 0) {
 -         NoteEnabled = OFF;
 -         return;
 -     }
 - 
 - 
 -     if(!legato) {
 -         lfilter = new bpfilter[numstages * numharmonics];
 -         if(stereo != 0)
 -             rfilter = new bpfilter[numstages * numharmonics];
 -     }
 - 
 -     //how much the amplitude is normalised (because the harmonics)
 -     float reduceamp = 0.0f;
 - 
 -     for(int n = 0; n < numharmonics; ++n) {
 -         float freq = basefreq * (pos[n] + 1);
 - 
 -         //the bandwidth is not absolute(Hz); it is relative to frequency
 -         float bw =
 -             powf(10, (pars->Pbandwidth - 127.0f) / 127.0f * 4) * numstages;
 - 
 -         //Bandwidth Scale
 -         bw *= powf(1000 / freq, (pars->Pbwscale - 64.0f) / 64.0f * 3.0f);
 - 
 -         //Relative BandWidth
 -         bw *= powf(100, (pars->Phrelbw[pos[n]] - 64.0f) / 64.0f);
 - 
 -         if(bw > 25.0f)
 -             bw = 25.0f;
 - 
 -         //try to keep same amplitude on all freqs and bw. (empirically)
 -         float gain = sqrt(1500.0f / (bw * freq));
 - 
 -         float hmagnew = 1.0f - pars->Phmag[pos[n]] / 127.0f;
 -         float hgain;
 - 
 -         switch(pars->Phmagtype) {
 -             case 1:
 -                 hgain = expf(hmagnew * logf(0.01f));
 -                 break;
 -             case 2:
 -                 hgain = expf(hmagnew * logf(0.001f));
 -                 break;
 -             case 3:
 -                 hgain = expf(hmagnew * logf(0.0001f));
 -                 break;
 -             case 4:
 -                 hgain = expf(hmagnew * logf(0.00001f));
 -                 break;
 -             default:
 -                 hgain = 1.0f - hmagnew;
 -         }
 -         gain      *= hgain;
 -         reduceamp += hgain;
 - 
 -         for(int nph = 0; nph < numstages; ++nph) {
 -             float amp = 1.0f;
 -             if(nph == 0)
 -                 amp = gain;
 -             initfilter(lfilter[nph + n * numstages], freq, bw, amp, hgain);
 -             if(stereo != 0)
 -                 initfilter(rfilter[nph + n * numstages], freq, bw, amp, hgain);
 -         }
 -     }
 - 
 -     if(reduceamp < 0.001f)
 -         reduceamp = 1.0f;
 -     volume /= reduceamp;
 - 
 -     oldpitchwheel = 0;
 -     oldbandwidth  = 64;
 -     if(!legato) {
 -         if(pars->Pfixedfreq == 0)
 -             initparameters(basefreq);
 -         else
 -             initparameters(basefreq / 440.0f * freq);
 -     }
 -     else {
 -         if(pars->Pfixedfreq == 0)
 -             freq = basefreq;
 -         else
 -             freq *= basefreq / 440.0f;
 - 
 -         if(pars->PGlobalFilterEnabled != 0) {
 -             globalfiltercenterq      = pars->GlobalFilter->getq();
 -             GlobalFilterFreqTracking = pars->GlobalFilter->getfreqtracking(
 -                 basefreq);
 -         }
 -     }
 - 
 -     oldamplitude = newamplitude;
 - }
 - 
 - void SUBnote::legatonote(float freq, float velocity, int portamento_,
 -                          int midinote, bool externcall)
 - {
 -     // Manage legato stuff
 -     if(legato.update(freq, velocity, portamento_, midinote, externcall))
 -         return;
 - 
 -     setup(freq, velocity, portamento_, midinote, true);
 - }
 - 
 - SUBnote::~SUBnote()
 - {
 -     if(NoteEnabled != OFF)
 -         KillNote();
 - }
 - 
 - /*
 -  * Kill the note
 -  */
 - void SUBnote::KillNote()
 - {
 -     if(NoteEnabled != OFF) {
 -         delete [] lfilter;
 -         lfilter = NULL;
 -         if(stereo != 0)
 -             delete [] rfilter;
 -         rfilter = NULL;
 -         delete AmpEnvelope;
 -         delete FreqEnvelope;
 -         delete BandWidthEnvelope;
 -         delete GlobalFilterL;
 -         delete GlobalFilterR;
 -         delete GlobalFilterEnvelope;
 -         NoteEnabled = OFF;
 -     }
 - }
 - 
 - 
 - /*
 -  * Compute the filters coefficients
 -  */
 - void SUBnote::computefiltercoefs(bpfilter &filter,
 -                                  float freq,
 -                                  float bw,
 -                                  float gain)
 - {
 -     if(freq > synth->samplerate_f / 2.0f - 200.0f)
 -         freq = synth->samplerate_f / 2.0f - 200.0f;
 - 
 - 
 -     float omega = 2.0f * PI * freq / synth->samplerate_f;
 -     float sn    = sinf(omega);
 -     float cs    = cosf(omega);
 -     float alpha = sn * sinh(LOG_2 / 2.0f * bw * omega / sn);
 - 
 -     if(alpha > 1)
 -         alpha = 1;
 -     if(alpha > bw)
 -         alpha = bw;
 - 
 -     filter.b0 = alpha / (1.0f + alpha) * filter.amp * gain;
 -     filter.b2 = -alpha / (1.0f + alpha) * filter.amp * gain;
 -     filter.a1 = -2.0f * cs / (1.0f + alpha);
 -     filter.a2 = (1.0f - alpha) / (1.0f + alpha);
 - }
 - 
 - 
 - /*
 -  * Initialise the filters
 -  */
 - void SUBnote::initfilter(bpfilter &filter,
 -                          float freq,
 -                          float bw,
 -                          float amp,
 -                          float mag)
 - {
 -     filter.xn1 = 0.0f;
 -     filter.xn2 = 0.0f;
 - 
 -     if(start == 0) {
 -         filter.yn1 = 0.0f;
 -         filter.yn2 = 0.0f;
 -     }
 -     else {
 -         float a = 0.1f * mag; //empirically
 -         float p = RND * 2.0f * PI;
 -         if(start == 1)
 -             a *= RND;
 -         filter.yn1 = a * cosf(p);
 -         filter.yn2 = a * cosf(p + freq * 2.0f * PI / synth->samplerate_f);
 - 
 -         //correct the error of computation the start amplitude
 -         //at very high frequencies
 -         if(freq > synth->samplerate_f * 0.96f) {
 -             filter.yn1 = 0.0f;
 -             filter.yn2 = 0.0f;
 -         }
 -     }
 - 
 -     filter.amp  = amp;
 -     filter.freq = freq;
 -     filter.bw   = bw;
 -     computefiltercoefs(filter, freq, bw, 1.0f);
 - }
 - 
 - /*
 -  * Do the filtering
 -  */
 - 
 - inline void SubFilterA(const float coeff[4], float &src, float work[4])
 - {
 -     work[3] = src*coeff[0]+work[1]*coeff[1]+work[2]*coeff[2]+work[3]*coeff[3];
 -     work[1] = src;
 -     src     = work[3];
 - }
 - 
 - inline void SubFilterB(const float coeff[4], float &src, float work[4])
 - {
 -     work[2] = src*coeff[0]+work[0]*coeff[1]+work[3]*coeff[2]+work[2]*coeff[3];
 -     work[0] = src;
 -     src     = work[2];
 - }
 - 
 - //This dance is designed to minimize unneeded memory operations which can result
 - //in quite a bit of wasted time
 - void SUBnote::filter(bpfilter &filter, float *smps)
 - {
 -     assert(synth->buffersize % 8 == 0);
 -     float coeff[4] = {filter.b0, filter.b2,  -filter.a1, -filter.a2};
 -     float work[4]  = {filter.xn1, filter.xn2, filter.yn1, filter.yn2};
 - 
 -     for(int i = 0; i < synth->buffersize; i += 8) {
 -         SubFilterA(coeff, smps[i + 0], work);
 -         SubFilterB(coeff, smps[i + 1], work);
 -         SubFilterA(coeff, smps[i + 2], work);
 -         SubFilterB(coeff, smps[i + 3], work);
 -         SubFilterA(coeff, smps[i + 4], work);
 -         SubFilterB(coeff, smps[i + 5], work);
 -         SubFilterA(coeff, smps[i + 6], work);
 -         SubFilterB(coeff, smps[i + 7], work);
 -     }
 -     filter.xn1 = work[0];
 -     filter.xn2 = work[1];
 -     filter.yn1 = work[2];
 -     filter.yn2 = work[3];
 - }
 - 
 - /*
 -  * Init Parameters
 -  */
 - void SUBnote::initparameters(float freq)
 - {
 -     AmpEnvelope = new Envelope(pars->AmpEnvelope, freq);
 -     if(pars->PFreqEnvelopeEnabled != 0)
 -         FreqEnvelope = new Envelope(pars->FreqEnvelope, freq);
 -     else
 -         FreqEnvelope = NULL;
 -     if(pars->PBandWidthEnvelopeEnabled != 0)
 -         BandWidthEnvelope = new Envelope(pars->BandWidthEnvelope, freq);
 -     else
 -         BandWidthEnvelope = NULL;
 -     if(pars->PGlobalFilterEnabled != 0) {
 -         globalfiltercenterq = pars->GlobalFilter->getq();
 -         GlobalFilterL = Filter::generate(pars->GlobalFilter);
 -         if(stereo)
 -             GlobalFilterR = Filter::generate(pars->GlobalFilter);
 -         GlobalFilterEnvelope = new Envelope(pars->GlobalFilterEnvelope,
 -                                             freq);
 -         GlobalFilterFreqTracking = pars->GlobalFilter->getfreqtracking(basefreq);
 -     }
 -     computecurrentparameters();
 - }
 - 
 - 
 - /*
 -  * Compute Parameters of SUBnote for each tick
 -  */
 - void SUBnote::computecurrentparameters()
 - {
 -     if((FreqEnvelope != NULL) || (BandWidthEnvelope != NULL)
 -        || (oldpitchwheel != ctl->pitchwheel.data)
 -        || (oldbandwidth != ctl->bandwidth.data)
 -        || (portamento != 0)) {
 -         float envfreq = 1.0f;
 -         float envbw   = 1.0f;
 -         float gain    = 1.0f;
 - 
 -         if(FreqEnvelope != NULL) {
 -             envfreq = FreqEnvelope->envout() / 1200;
 -             envfreq = powf(2.0f, envfreq);
 -         }
 -         envfreq *= ctl->pitchwheel.relfreq; //pitch wheel
 -         if(portamento != 0) { //portamento is used
 -             envfreq *= ctl->portamento.freqrap;
 -             if(ctl->portamento.used == 0) //the portamento has finished
 -                 portamento = 0;  //this note is no longer "portamented"
 -             ;
 -         }
 - 
 -         if(BandWidthEnvelope != NULL) {
 -             envbw = BandWidthEnvelope->envout();
 -             envbw = powf(2, envbw);
 -         }
 -         envbw *= ctl->bandwidth.relbw; //bandwidth controller
 - 
 -         float tmpgain = 1.0f / sqrt(envbw * envfreq);
 - 
 -         for(int n = 0; n < numharmonics; ++n)
 -             for(int nph = 0; nph < numstages; ++nph) {
 -                 if(nph == 0)
 -                     gain = tmpgain;
 -                 else
 -                     gain = 1.0f;
 -                 computefiltercoefs(lfilter[nph + n * numstages],
 -                                    lfilter[nph + n * numstages].freq * envfreq,
 -                                    lfilter[nph + n * numstages].bw * envbw,
 -                                    gain);
 -             }
 -         if(stereo != 0)
 -             for(int n = 0; n < numharmonics; ++n)
 -                 for(int nph = 0; nph < numstages; ++nph) {
 -                     if(nph == 0)
 -                         gain = tmpgain;
 -                     else
 -                         gain = 1.0f;
 -                     computefiltercoefs(
 -                         rfilter[nph + n * numstages],
 -                         rfilter[nph + n
 -                                 * numstages].freq * envfreq,
 -                         rfilter[nph + n * numstages].bw * envbw,
 -                         gain);
 -                 }
 - 
 - 
 -         oldbandwidth  = ctl->bandwidth.data;
 -         oldpitchwheel = ctl->pitchwheel.data;
 -     }
 -     newamplitude = volume * AmpEnvelope->envout_dB() * 2.0f;
 - 
 -     //Filter
 -     if(GlobalFilterL != NULL) {
 -         float globalfilterpitch = GlobalFilterCenterPitch
 -                                   + GlobalFilterEnvelope->envout();
 -         float filterfreq = globalfilterpitch + ctl->filtercutoff.relfreq
 -                            + GlobalFilterFreqTracking;
 -         filterfreq = Filter::getrealfreq(filterfreq);
 - 
 -         GlobalFilterL->setfreq_and_q(filterfreq,
 -                                      globalfiltercenterq * ctl->filterq.relq);
 -         if(GlobalFilterR != NULL)
 -             GlobalFilterR->setfreq_and_q(
 -                 filterfreq,
 -                 globalfiltercenterq
 -                 * ctl->filterq.relq);
 -     }
 - }
 - 
 - /*
 -  * Note Output
 -  */
 - int SUBnote::noteout(float *outl, float *outr)
 - {
 -     memcpy(outl, denormalkillbuf, synth->bufferbytes);
 -     memcpy(outr, denormalkillbuf, synth->bufferbytes);
 - 
 -     if(NoteEnabled == OFF)
 -         return 0;
 - 
 -     float *tmprnd = getTmpBuffer();
 -     float *tmpsmp = getTmpBuffer();
 -     //left channel
 -     for(int i = 0; i < synth->buffersize; ++i)
 -         tmprnd[i] = RND * 2.0f - 1.0f;
 -     for(int n = 0; n < numharmonics; ++n) {
 -         memcpy(tmpsmp, tmprnd, synth->bufferbytes);
 -         for(int nph = 0; nph < numstages; ++nph)
 -             filter(lfilter[nph + n * numstages], tmpsmp);
 -         for(int i = 0; i < synth->buffersize; ++i)
 -             outl[i] += tmpsmp[i];
 -     }
 - 
 -     if(GlobalFilterL != NULL)
 -         GlobalFilterL->filterout(&outl[0]);
 - 
 -     //right channel
 -     if(stereo != 0) {
 -         for(int i = 0; i < synth->buffersize; ++i)
 -             tmprnd[i] = RND * 2.0f - 1.0f;
 -         for(int n = 0; n < numharmonics; ++n) {
 -             memcpy(tmpsmp, tmprnd, synth->bufferbytes);
 -             for(int nph = 0; nph < numstages; ++nph)
 -                 filter(rfilter[nph + n * numstages], tmpsmp);
 -             for(int i = 0; i < synth->buffersize; ++i)
 -                 outr[i] += tmpsmp[i];
 -         }
 -         if(GlobalFilterR != NULL)
 -             GlobalFilterR->filterout(&outr[0]);
 -     }
 -     else
 -         memcpy(outr, outl, synth->bufferbytes);
 -     returnTmpBuffer(tmprnd);
 -     returnTmpBuffer(tmpsmp);
 - 
 -     if(firsttick != 0) {
 -         int n = 10;
 -         if(n > synth->buffersize)
 -             n = synth->buffersize;
 -         for(int i = 0; i < n; ++i) {
 -             float ampfadein = 0.5f - 0.5f * cosf(
 -                 (float) i / (float) n * PI);
 -             outl[i] *= ampfadein;
 -             outr[i] *= ampfadein;
 -         }
 -         firsttick = 0;
 -     }
 - 
 -     if(ABOVE_AMPLITUDE_THRESHOLD(oldamplitude, newamplitude))
 -         // Amplitude interpolation
 -         for(int i = 0; i < synth->buffersize; ++i) {
 -             float tmpvol = INTERPOLATE_AMPLITUDE(oldamplitude,
 -                                                  newamplitude,
 -                                                  i,
 -                                                  synth->buffersize);
 -             outl[i] *= tmpvol * panning;
 -             outr[i] *= tmpvol * (1.0f - panning);
 -         }
 -     else
 -         for(int i = 0; i < synth->buffersize; ++i) {
 -             outl[i] *= newamplitude * panning;
 -             outr[i] *= newamplitude * (1.0f - panning);
 -         }
 - 
 -     oldamplitude = newamplitude;
 -     computecurrentparameters();
 - 
 -     // Apply legato-specific sound signal modifications
 -     legato.apply(*this, outl, outr);
 - 
 -     // Check if the note needs to be computed more
 -     if(AmpEnvelope->finished() != 0) {
 -         for(int i = 0; i < synth->buffersize; ++i) { //fade-out
 -             float tmp = 1.0f - (float)i / synth->buffersize_f;
 -             outl[i] *= tmp;
 -             outr[i] *= tmp;
 -         }
 -         KillNote();
 -     }
 -     return 1;
 - }
 - 
 - /*
 -  * Relase Key (Note Off)
 -  */
 - void SUBnote::relasekey()
 - {
 -     AmpEnvelope->relasekey();
 -     if(FreqEnvelope)
 -         FreqEnvelope->relasekey();
 -     if(BandWidthEnvelope)
 -         BandWidthEnvelope->relasekey();
 -     if(GlobalFilterEnvelope)
 -         GlobalFilterEnvelope->relasekey();
 - }
 - 
 - /*
 -  * Check if the note is finished
 -  */
 - int SUBnote::finished() const
 - {
 -     if(NoteEnabled == OFF)
 -         return 1;
 -     else
 -         return 0;
 - }
 
 
  |