/*
  ZynAddSubFX - a software synthesizer

  ADnote.cpp - The "additive" 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 the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  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 <cstring>
#include <cassert>
#include <stdint.h>

#include "../globals.h"
#include "../Misc/Util.h"
#include "../DSP/Filter.h"
#include "OscilGen.h"
#include "ADnote.h"


ADnote::ADnote(ADnoteParameters *pars,
               Controller *ctl_,
               float freq,
               float velocity,
               int portamento_,
               int midinote_,
               bool besilent)
    :SynthNote(freq, velocity, portamento_, midinote_, besilent)
{
    tmpwavel = new float [synth->buffersize];
    tmpwaver = new float [synth->buffersize];
    bypassl  = new float [synth->buffersize];
    bypassr  = new float [synth->buffersize];

    partparams = pars;
    ctl = ctl_;
    portamento  = portamento_;
    midinote    = midinote_;
    NoteEnabled = ON;
    basefreq    = freq;
    if(velocity > 1.0f)
        velocity = 1.0f;
    this->velocity = velocity;
    time   = 0.0f;
    stereo = pars->GlobalPar.PStereo;

    NoteGlobalPar.Detune = getdetune(pars->GlobalPar.PDetuneType,
                                     pars->GlobalPar.PCoarseDetune,
                                     pars->GlobalPar.PDetune);
    bandwidthDetuneMultiplier = pars->getBandwidthDetuneMultiplier();

    if(pars->GlobalPar.PPanning == 0)
        NoteGlobalPar.Panning = RND;
    else
        NoteGlobalPar.Panning = pars->GlobalPar.PPanning / 128.0f;


    NoteGlobalPar.FilterCenterPitch = pars->GlobalPar.GlobalFilter->getfreq() //center freq
                                      + pars->GlobalPar.PFilterVelocityScale
                                      / 127.0f * 6.0f                                  //velocity sensing
                                      * (VelF(velocity,
                                              pars->GlobalPar.
                                              PFilterVelocityScaleFunction) - 1);

    if(pars->GlobalPar.PPunchStrength != 0) {
        NoteGlobalPar.Punch.Enabled = 1;
        NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f
        NoteGlobalPar.Punch.initialvalue =
            ((powf(10, 1.5f * pars->GlobalPar.PPunchStrength / 127.0f) - 1.0f)
             * VelF(velocity,
                    pars->GlobalPar.PPunchVelocitySensing));
        float time =
            powf(10, 3.0f * pars->GlobalPar.PPunchTime / 127.0f) / 10000.0f;   //0.1f .. 100 ms
        float stretch = powf(440.0f / freq,
                             pars->GlobalPar.PPunchStretch / 64.0f);
        NoteGlobalPar.Punch.dt = 1.0f / (time * synth->samplerate_f * stretch);
    }
    else
        NoteGlobalPar.Punch.Enabled = 0;

    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        pars->VoicePar[nvoice].OscilSmp->newrandseed(prng());
        NoteVoicePar[nvoice].OscilSmp = NULL;
        NoteVoicePar[nvoice].FMSmp    = NULL;
        NoteVoicePar[nvoice].VoiceOut = NULL;

        NoteVoicePar[nvoice].FMVoice = -1;
        unison_size[nvoice] = 1;

        if(pars->VoicePar[nvoice].Enabled == 0) {
            NoteVoicePar[nvoice].Enabled = OFF;
            continue; //the voice is disabled
        }

        unison_stereo_spread[nvoice] =
            pars->VoicePar[nvoice].Unison_stereo_spread / 127.0f;
        int unison = pars->VoicePar[nvoice].Unison_size;
        if(unison < 1)
            unison = 1;

        //compute unison
        unison_size[nvoice] = unison;

        unison_base_freq_rap[nvoice] = new float[unison];
        unison_freq_rap[nvoice]      = new float[unison];
        unison_invert_phase[nvoice]  = new bool[unison];
        float unison_spread = pars->getUnisonFrequencySpreadCents(
            nvoice);
        float unison_real_spread = powf(2.0f, (unison_spread * 0.5f) / 1200.0f);
        float unison_vibratto_a  = pars->VoicePar[nvoice].Unison_vibratto
                                   / 127.0f;                                     //0.0f .. 1.0f


        switch(unison) {
            case 1:
                unison_base_freq_rap[nvoice][0] = 1.0f; //if the unison is not used, always make the only subvoice to have the default note
                break;
            case 2: { //unison for 2 subvoices
                unison_base_freq_rap[nvoice][0] = 1.0f / unison_real_spread;
                unison_base_freq_rap[nvoice][1] = unison_real_spread;
            };
                break;
            default: { //unison for more than 2 subvoices
                float unison_values[unison];
                float min = -1e-6, max = 1e-6;
                for(int k = 0; k < unison; ++k) {
                    float step = (k / (float) (unison - 1)) * 2.0f - 1.0f; //this makes the unison spread more uniform
                    float val  = step + (RND * 2.0f - 1.0f) / (unison - 1);
                    unison_values[k] = val;
                    if (min > val) {
                        min = val;
                    }
                    if (max < val) {
                        max = val;
                    }
                }
                float diff = max - min;
                for(int k = 0; k < unison; ++k) {
                    unison_values[k] =
                        (unison_values[k] - (max + min) * 0.5f) / diff;             //the lowest value will be -1 and the highest will be 1
                    unison_base_freq_rap[nvoice][k] =
                        powf(2.0f, (unison_spread * unison_values[k]) / 1200);
                }
            };
        }

        //unison vibrattos
        if(unison > 1)
            for(int k = 0; k < unison; ++k) //reduce the frequency difference for larger vibrattos
                unison_base_freq_rap[nvoice][k] = 1.0f
                                                  + (unison_base_freq_rap[
                                                         nvoice][k] - 1.0f)
                                                  * (1.0f - unison_vibratto_a);
        unison_vibratto[nvoice].step      = new float[unison];
        unison_vibratto[nvoice].position  = new float[unison];
        unison_vibratto[nvoice].amplitude =
            (unison_real_spread - 1.0f) * unison_vibratto_a;

        float increments_per_second = synth->samplerate_f / synth->buffersize_f;
        float vibratto_base_period  = 0.25f
                                      * powf(
            2.0f,
            (1.0f
             - pars->VoicePar[nvoice].
             Unison_vibratto_speed
             / 127.0f) * 4.0f);
        for(int k = 0; k < unison; ++k) {
            unison_vibratto[nvoice].position[k] = RND * 1.8f - 0.9f;
            //make period to vary randomly from 50% to 200% vibratto base period
            float vibratto_period = vibratto_base_period
                                    * powf(2.0f, RND * 2.0f - 1.0f);

            float m = 4.0f / (vibratto_period * increments_per_second);
            if(RND < 0.5f)
                m = -m;
            unison_vibratto[nvoice].step[k] = m;
        }

        if(unison == 1) { //no vibratto for a single voice
            unison_vibratto[nvoice].step[0]     = 0.0f;
            unison_vibratto[nvoice].position[0] = 0.0f;
            unison_vibratto[nvoice].amplitude   = 0.0f;
        }

        //phase invert for unison
        unison_invert_phase[nvoice][0] = false;
        if(unison != 1) {
            int inv = pars->VoicePar[nvoice].Unison_invert_phase;
            switch(inv) {
                case 0: for(int k = 0; k < unison; ++k)
                        unison_invert_phase[nvoice][k] = false;
                    break;
                case 1: for(int k = 0; k < unison; ++k)
                        unison_invert_phase[nvoice][k] = (RND > 0.5f);
                    break;
                default: for(int k = 0; k < unison; ++k)
                        unison_invert_phase[nvoice][k] =
                            (k % inv == 0) ? true : false;
                    break;
            }
        }


        oscfreqhi[nvoice]   = new int[unison];
        oscfreqlo[nvoice]   = new float[unison];
        oscfreqhiFM[nvoice] = new unsigned int[unison];
        oscfreqloFM[nvoice] = new float[unison];
        oscposhi[nvoice]    = new int[unison];
        oscposlo[nvoice]    = new float[unison];
        oscposhiFM[nvoice]  = new unsigned int[unison];
        oscposloFM[nvoice]  = new float[unison];

        NoteVoicePar[nvoice].Enabled     = ON;
        NoteVoicePar[nvoice].fixedfreq   = pars->VoicePar[nvoice].Pfixedfreq;
        NoteVoicePar[nvoice].fixedfreqET = pars->VoicePar[nvoice].PfixedfreqET;

        //use the Globalpars.detunetype if the detunetype is 0
        if(pars->VoicePar[nvoice].PDetuneType != 0) {
            NoteVoicePar[nvoice].Detune = getdetune(
                pars->VoicePar[nvoice].PDetuneType,
                pars->VoicePar[nvoice].
                PCoarseDetune,
                8192); //coarse detune
            NoteVoicePar[nvoice].FineDetune = getdetune(
                pars->VoicePar[nvoice].PDetuneType,
                0,
                pars->VoicePar[nvoice].PDetune); //fine detune
        }
        else {
            NoteVoicePar[nvoice].Detune = getdetune(
                pars->GlobalPar.PDetuneType,
                pars->VoicePar[nvoice].
                PCoarseDetune,
                8192); //coarse detune
            NoteVoicePar[nvoice].FineDetune = getdetune(
                pars->GlobalPar.PDetuneType,
                0,
                pars->VoicePar[nvoice].PDetune); //fine detune
        }
        if(pars->VoicePar[nvoice].PFMDetuneType != 0)
            NoteVoicePar[nvoice].FMDetune = getdetune(
                pars->VoicePar[nvoice].PFMDetuneType,
                pars->VoicePar[nvoice].
                PFMCoarseDetune,
                pars->VoicePar[nvoice].PFMDetune);
        else
            NoteVoicePar[nvoice].FMDetune = getdetune(
                pars->GlobalPar.PDetuneType,
                pars->VoicePar[nvoice].
                PFMCoarseDetune,
                pars->VoicePar[nvoice].PFMDetune);



        for(int k = 0; k < unison; ++k) {
            oscposhi[nvoice][k]   = 0;
            oscposlo[nvoice][k]   = 0.0f;
            oscposhiFM[nvoice][k] = 0;
            oscposloFM[nvoice][k] = 0.0f;
        }

        //the extra points contains the first point
        NoteVoicePar[nvoice].OscilSmp =
            new float[synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES];

        //Get the voice's oscil or external's voice oscil
        int vc = nvoice;
        if(pars->VoicePar[nvoice].Pextoscil != -1)
            vc = pars->VoicePar[nvoice].Pextoscil;
        if(!pars->GlobalPar.Hrandgrouping)
            pars->VoicePar[vc].OscilSmp->newrandseed(prng());
        int oscposhi_start =
            pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp,
                                             getvoicebasefreq(nvoice),
                                             pars->VoicePar[nvoice].Presonance);

        //I store the first elments to the last position for speedups
        for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i)
            NoteVoicePar[nvoice].OscilSmp[synth->oscilsize
                                          + i] =
                NoteVoicePar[nvoice].OscilSmp[i];

        oscposhi_start +=
            (int)((pars->VoicePar[nvoice].Poscilphase
                   - 64.0f) / 128.0f * synth->oscilsize + synth->oscilsize * 4);
        oscposhi_start %= synth->oscilsize;

        for(int k = 0; k < unison; ++k) {
            oscposhi[nvoice][k] = oscposhi_start;
            //put random starting point for other subvoices
            oscposhi_start      =
                (int)(RND * pars->VoicePar[nvoice].Unison_phase_randomness /
                        127.0f * (synth->oscilsize - 1));
        }

        NoteVoicePar[nvoice].FreqLfo      = NULL;
        NoteVoicePar[nvoice].FreqEnvelope = NULL;

        NoteVoicePar[nvoice].AmpLfo      = NULL;
        NoteVoicePar[nvoice].AmpEnvelope = NULL;

        NoteVoicePar[nvoice].VoiceFilterL   = NULL;
        NoteVoicePar[nvoice].VoiceFilterR   = NULL;
        NoteVoicePar[nvoice].FilterEnvelope = NULL;
        NoteVoicePar[nvoice].FilterLfo      = NULL;

        NoteVoicePar[nvoice].FilterCenterPitch =
            pars->VoicePar[nvoice].VoiceFilter->getfreq();
        NoteVoicePar[nvoice].filterbypass =
            pars->VoicePar[nvoice].Pfilterbypass;

        switch(pars->VoicePar[nvoice].PFMEnabled) {
            case 1:
                NoteVoicePar[nvoice].FMEnabled = MORPH;
                break;
            case 2:
                NoteVoicePar[nvoice].FMEnabled = RING_MOD;
                break;
            case 3:
                NoteVoicePar[nvoice].FMEnabled = PHASE_MOD;
                break;
            case 4:
                NoteVoicePar[nvoice].FMEnabled = FREQ_MOD;
                break;
            case 5:
                NoteVoicePar[nvoice].FMEnabled = PITCH_MOD;
                break;
            default:
                NoteVoicePar[nvoice].FMEnabled = NONE;
        }

        NoteVoicePar[nvoice].FMVoice = pars->VoicePar[nvoice].PFMVoice;
        NoteVoicePar[nvoice].FMFreqEnvelope = NULL;
        NoteVoicePar[nvoice].FMAmpEnvelope  = NULL;

        //Compute the Voice's modulator volume (incl. damping)
        float fmvoldamp = powf(440.0f / getvoicebasefreq(
                                   nvoice),
                               pars->VoicePar[nvoice].PFMVolumeDamp / 64.0f
                               - 1.0f);
        switch(NoteVoicePar[nvoice].FMEnabled) {
            case PHASE_MOD:
                fmvoldamp =
                    powf(440.0f / getvoicebasefreq(
                             nvoice), pars->VoicePar[nvoice].PFMVolumeDamp
                         / 64.0f);
                NoteVoicePar[nvoice].FMVolume =
                    (expf(pars->VoicePar[nvoice].PFMVolume / 127.0f
                          * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f;
                break;
            case FREQ_MOD:
                NoteVoicePar[nvoice].FMVolume =
                    (expf(pars->VoicePar[nvoice].PFMVolume / 127.0f
                          * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f;
                break;
            //    case PITCH_MOD:NoteVoicePar[nvoice].FMVolume=(pars->VoicePar[nvoice].PFMVolume/127.0f*8.0f)*fmvoldamp;//???????????
            //	          break;
            default:
                if(fmvoldamp > 1.0f)
                    fmvoldamp = 1.0f;
                NoteVoicePar[nvoice].FMVolume =
                    pars->VoicePar[nvoice].PFMVolume
                    / 127.0f * fmvoldamp;
        }

        //Voice's modulator velocity sensing
        NoteVoicePar[nvoice].FMVolume *=
            VelF(velocity,
                 partparams->VoicePar[nvoice].PFMVelocityScaleFunction);

        FMoldsmp[nvoice] = new float [unison];
        for(int k = 0; k < unison; ++k)
            FMoldsmp[nvoice][k] = 0.0f;                     //this is for FM (integration)

        firsttick[nvoice] = 1;
        NoteVoicePar[nvoice].DelayTicks =
            (int)((expf(pars->VoicePar[nvoice].PDelay / 127.0f
                        * logf(50.0f))
                   - 1.0f) / synth->buffersize_f / 10.0f * synth->samplerate_f);
    }

    max_unison = 1;
    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice)
        if(unison_size[nvoice] > max_unison)
            max_unison = unison_size[nvoice];


    tmpwave_unison = new float *[max_unison];
    for(int k = 0; k < max_unison; ++k) {
        tmpwave_unison[k] = new float[synth->buffersize];
        memset(tmpwave_unison[k], 0, synth->bufferbytes);
    }

    initparameters();
}

// ADlegatonote: This function is (mostly) a copy of ADnote(...) and
// initparameters() stuck together with some lines removed so that it
// only alter the already playing note (to perform legato). It is
// possible I left stuff that is not required for this.
void ADnote::legatonote(float freq, float velocity, int portamento_,
                        int midinote_, bool externcall)
{
    ADnoteParameters *pars = partparams;

    // Manage legato stuff
    if(legato.update(freq, velocity, portamento_, midinote_, externcall))
        return;

    portamento = portamento_;
    midinote   = midinote_;
    basefreq   = freq;

    if(velocity > 1.0f)
        velocity = 1.0f;
    this->velocity = velocity;

    NoteGlobalPar.Detune = getdetune(pars->GlobalPar.PDetuneType,
                                     pars->GlobalPar.PCoarseDetune,
                                     pars->GlobalPar.PDetune);
    bandwidthDetuneMultiplier = pars->getBandwidthDetuneMultiplier();

    if(pars->GlobalPar.PPanning == 0)
        NoteGlobalPar.Panning = RND;
    else
        NoteGlobalPar.Panning = pars->GlobalPar.PPanning / 128.0f;

    //center freq
    NoteGlobalPar.FilterCenterPitch = pars->GlobalPar.GlobalFilter->getfreq()
                                      + pars->GlobalPar.PFilterVelocityScale
                                      / 127.0f * 6.0f          //velocity sensing
                                      * (VelF(velocity,
                                              pars->GlobalPar.
                                              PFilterVelocityScaleFunction) - 1);


    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        if(NoteVoicePar[nvoice].Enabled == OFF)
            continue;  //(gf) Stay the same as first note in legato.

        NoteVoicePar[nvoice].fixedfreq   = pars->VoicePar[nvoice].Pfixedfreq;
        NoteVoicePar[nvoice].fixedfreqET = pars->VoicePar[nvoice].PfixedfreqET;

        //use the Globalpars.detunetype if the detunetype is 0
        if(pars->VoicePar[nvoice].PDetuneType != 0) {
            NoteVoicePar[nvoice].Detune = getdetune(
                pars->VoicePar[nvoice].PDetuneType,
                pars->VoicePar[nvoice].PCoarseDetune,
                8192); //coarse detune
            NoteVoicePar[nvoice].FineDetune = getdetune(
                pars->VoicePar[nvoice].PDetuneType,
                0,
                pars->VoicePar[nvoice].PDetune); //fine detune
        }
        else {
            NoteVoicePar[nvoice].Detune = getdetune(
                pars->GlobalPar.PDetuneType,
                pars->VoicePar[nvoice].PCoarseDetune,
                8192); //coarse detune
            NoteVoicePar[nvoice].FineDetune = getdetune(
                pars->GlobalPar.PDetuneType,
                0,
                pars->VoicePar[nvoice].PDetune); //fine detune
        }
        if(pars->VoicePar[nvoice].PFMDetuneType != 0)
            NoteVoicePar[nvoice].FMDetune = getdetune(
                pars->VoicePar[nvoice].PFMDetuneType,
                pars->VoicePar[nvoice].PFMCoarseDetune,
                pars->VoicePar[nvoice].PFMDetune);
        else
            NoteVoicePar[nvoice].FMDetune = getdetune(
                pars->GlobalPar.PDetuneType,
                pars->VoicePar[nvoice].PFMCoarseDetune,
                pars->VoicePar[nvoice].PFMDetune);


        //Get the voice's oscil or external's voice oscil
        int vc = nvoice;
        if(pars->VoicePar[nvoice].Pextoscil != -1)
            vc = pars->VoicePar[nvoice].Pextoscil;
        if(!pars->GlobalPar.Hrandgrouping)
            pars->VoicePar[vc].OscilSmp->newrandseed(prng());

        pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp,
                                         getvoicebasefreq(nvoice),
                                         pars->VoicePar[nvoice].Presonance); //(gf)Modif of the above line.

        //I store the first elments to the last position for speedups
        for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i)
            NoteVoicePar[nvoice].OscilSmp[synth->oscilsize
                                          + i] =
                NoteVoicePar[nvoice].OscilSmp[i];


        NoteVoicePar[nvoice].FilterCenterPitch =
            pars->VoicePar[nvoice].VoiceFilter->getfreq();
        NoteVoicePar[nvoice].filterbypass =
            pars->VoicePar[nvoice].Pfilterbypass;


        NoteVoicePar[nvoice].FMVoice = pars->VoicePar[nvoice].PFMVoice;

        //Compute the Voice's modulator volume (incl. damping)
        float fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice),
                               pars->VoicePar[nvoice].PFMVolumeDamp / 64.0f
                               - 1.0f);

        switch(NoteVoicePar[nvoice].FMEnabled) {
            case PHASE_MOD:
                fmvoldamp =
                    powf(440.0f / getvoicebasefreq(
                             nvoice), pars->VoicePar[nvoice].PFMVolumeDamp
                         / 64.0f);
                NoteVoicePar[nvoice].FMVolume =
                    (expf(pars->VoicePar[nvoice].PFMVolume / 127.0f
                          * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f;
                break;
            case FREQ_MOD:
                NoteVoicePar[nvoice].FMVolume =
                    (expf(pars->VoicePar[nvoice].PFMVolume / 127.0f
                          * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f;
                break;
            //    case PITCH_MOD:NoteVoicePar[nvoice].FMVolume=(pars->VoicePar[nvoice].PFMVolume/127.0f*8.0f)*fmvoldamp;//???????????
            //	          break;
            default:
                if(fmvoldamp > 1.0f)
                    fmvoldamp = 1.0f;
                NoteVoicePar[nvoice].FMVolume =
                    pars->VoicePar[nvoice].PFMVolume
                    / 127.0f * fmvoldamp;
        }

        //Voice's modulator velocity sensing
        NoteVoicePar[nvoice].FMVolume *=
            VelF(velocity,
                 partparams->VoicePar[nvoice].PFMVelocityScaleFunction);

        NoteVoicePar[nvoice].DelayTicks =
            (int)((expf(pars->VoicePar[nvoice].PDelay / 127.0f
                        * logf(50.0f))
                   - 1.0f) / synth->buffersize_f / 10.0f * synth->samplerate_f);
    }

    ///    initparameters();

    ///////////////
    // Altered content of initparameters():

    int tmp[NUM_VOICES];

    NoteGlobalPar.Volume = 4.0f
                           * powf(0.1f, 3.0f
                                  * (1.0f - partparams->GlobalPar.PVolume
                                     / 96.0f))                                      //-60 dB .. 0 dB
                           * VelF(
        velocity,
        partparams->GlobalPar.
        PAmpVelocityScaleFunction);                                                      //velocity sensing

    globalnewamplitude = NoteGlobalPar.Volume
                         * NoteGlobalPar.AmpEnvelope->envout_dB()
                         * NoteGlobalPar.AmpLfo->amplfoout();

    NoteGlobalPar.FilterQ = partparams->GlobalPar.GlobalFilter->getq();
    NoteGlobalPar.FilterFreqTracking =
        partparams->GlobalPar.GlobalFilter->getfreqtracking(basefreq);

    // Forbids the Modulation Voice to be greater or equal than voice
    for(int i = 0; i < NUM_VOICES; ++i)
        if(NoteVoicePar[i].FMVoice >= i)
            NoteVoicePar[i].FMVoice = -1;

    // Voice Parameter init
    for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        if(NoteVoicePar[nvoice].Enabled == 0)
            continue;

        NoteVoicePar[nvoice].noisetype = partparams->VoicePar[nvoice].Type;
        /* Voice Amplitude Parameters Init */
        NoteVoicePar[nvoice].Volume =
            powf(0.1f, 3.0f
                 * (1.0f - partparams->VoicePar[nvoice].PVolume / 127.0f))             // -60 dB .. 0 dB
            * VelF(velocity,
                   partparams->VoicePar[nvoice].PAmpVelocityScaleFunction); //velocity

        if(partparams->VoicePar[nvoice].PVolumeminus != 0)
            NoteVoicePar[nvoice].Volume = -NoteVoicePar[nvoice].Volume;

        if(partparams->VoicePar[nvoice].PPanning == 0)
            NoteVoicePar[nvoice].Panning = RND;  // random panning
        else
            NoteVoicePar[nvoice].Panning =
                partparams->VoicePar[nvoice].PPanning / 128.0f;

        newamplitude[nvoice] = 1.0f;
        if((partparams->VoicePar[nvoice].PAmpEnvelopeEnabled != 0)
           && (NoteVoicePar[nvoice].AmpEnvelope != NULL))
            newamplitude[nvoice] *= NoteVoicePar[nvoice].AmpEnvelope->envout_dB();


        if((partparams->VoicePar[nvoice].PAmpLfoEnabled != 0)
           && (NoteVoicePar[nvoice].AmpLfo != NULL))
            newamplitude[nvoice] *= NoteVoicePar[nvoice].AmpLfo->amplfoout();



        NoteVoicePar[nvoice].FilterFreqTracking =
            partparams->VoicePar[nvoice].VoiceFilter->getfreqtracking(basefreq);

        /* Voice Modulation Parameters Init */
        if((NoteVoicePar[nvoice].FMEnabled != NONE)
           && (NoteVoicePar[nvoice].FMVoice < 0)) {
            partparams->VoicePar[nvoice].FMSmp->newrandseed(prng());

            //Perform Anti-aliasing only on MORPH or RING MODULATION

            int vc = nvoice;
            if(partparams->VoicePar[nvoice].PextFMoscil != -1)
                vc = partparams->VoicePar[nvoice].PextFMoscil;

            if(!partparams->GlobalPar.Hrandgrouping)
                partparams->VoicePar[vc].FMSmp->newrandseed(prng());

            for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i)
                NoteVoicePar[nvoice].FMSmp[synth->oscilsize + i] =
                    NoteVoicePar[nvoice].FMSmp[i];
        }

        FMnewamplitude[nvoice] = NoteVoicePar[nvoice].FMVolume
                                 * ctl->fmamp.relamp;

        if((partparams->VoicePar[nvoice].PFMAmpEnvelopeEnabled != 0)
           && (NoteVoicePar[nvoice].FMAmpEnvelope != NULL))
            FMnewamplitude[nvoice] *=
                NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB();
    }

    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        for(unsigned i = nvoice + 1; i < NUM_VOICES; ++i)
            tmp[i] = 0;
        for(unsigned i = nvoice + 1; i < NUM_VOICES; ++i)
            if((NoteVoicePar[i].FMVoice == nvoice) && (tmp[i] == 0))
                tmp[i] = 1;
    }
}


/*
 * Kill a voice of ADnote
 */
void ADnote::KillVoice(int nvoice)
{
    delete [] oscfreqhi[nvoice];
    delete [] oscfreqlo[nvoice];
    delete [] oscfreqhiFM[nvoice];
    delete [] oscfreqloFM[nvoice];
    delete [] oscposhi[nvoice];
    delete [] oscposlo[nvoice];
    delete [] oscposhiFM[nvoice];
    delete [] oscposloFM[nvoice];

    delete [] unison_base_freq_rap[nvoice];
    delete [] unison_freq_rap[nvoice];
    delete [] unison_invert_phase[nvoice];
    delete [] FMoldsmp[nvoice];
    delete [] unison_vibratto[nvoice].step;
    delete [] unison_vibratto[nvoice].position;

    NoteVoicePar[nvoice].kill();
}

/*
 * Kill the note
 */
void ADnote::KillNote()
{
    for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        if(NoteVoicePar[nvoice].Enabled == ON)
            KillVoice(nvoice);

        if(NoteVoicePar[nvoice].VoiceOut)
            delete NoteVoicePar[nvoice].VoiceOut;
        NoteVoicePar[nvoice].VoiceOut = NULL;
    }

    NoteGlobalPar.kill();

    NoteEnabled = OFF;
}

ADnote::~ADnote()
{
    if(NoteEnabled == ON)
        KillNote();
    delete [] tmpwavel;
    delete [] tmpwaver;
    delete [] bypassl;
    delete [] bypassr;
    for(int k = 0; k < max_unison; ++k)
        delete[] tmpwave_unison[k];
    delete[] tmpwave_unison;
}


/*
 * Init the parameters
 */
void ADnote::initparameters()
{
    int tmp[NUM_VOICES];

    // Global Parameters
    NoteGlobalPar.initparameters(partparams->GlobalPar, basefreq, velocity,
                                 stereo);

    NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output
    globalnewamplitude = NoteGlobalPar.Volume
                         * NoteGlobalPar.AmpEnvelope->envout_dB()
                         * NoteGlobalPar.AmpLfo->amplfoout();

    // Forbids the Modulation Voice to be greater or equal than voice
    for(int i = 0; i < NUM_VOICES; ++i)
        if(NoteVoicePar[i].FMVoice >= i)
            NoteVoicePar[i].FMVoice = -1;

    // Voice Parameter init
    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        Voice &vce = NoteVoicePar[nvoice];
        ADnoteVoiceParam &param = partparams->VoicePar[nvoice];

        if(vce.Enabled == 0)
            continue;

        vce.noisetype = param.Type;
        /* Voice Amplitude Parameters Init */
        vce.Volume = powf(0.1f, 3.0f * (1.0f - param.PVolume / 127.0f)) // -60dB..0dB
                     * VelF(velocity, param.PAmpVelocityScaleFunction);

        if(param.PVolumeminus)
            vce.Volume = -vce.Volume;

        if(param.PPanning == 0)
            vce.Panning = RND;  // random panning
        else
            vce.Panning = param.PPanning / 128.0f;

        newamplitude[nvoice] = 1.0f;
        if(param.PAmpEnvelopeEnabled) {
            vce.AmpEnvelope = new Envelope(param.AmpEnvelope, basefreq);
            vce.AmpEnvelope->envout_dB(); //discard the first envelope sample
            newamplitude[nvoice] *= vce.AmpEnvelope->envout_dB();
        }

        if(param.PAmpLfoEnabled) {
            vce.AmpLfo = new LFO(param.AmpLfo, basefreq);
            newamplitude[nvoice] *= vce.AmpLfo->amplfoout();
        }

        /* Voice Frequency Parameters Init */
        if(param.PFreqEnvelopeEnabled != 0)
            vce.FreqEnvelope = new Envelope(param.FreqEnvelope, basefreq);

        if(param.PFreqLfoEnabled != 0)
            vce.FreqLfo = new LFO(param.FreqLfo, basefreq);

        /* Voice Filter Parameters Init */
        if(param.PFilterEnabled != 0) {
            vce.VoiceFilterL = Filter::generate(param.VoiceFilter);
            vce.VoiceFilterR = Filter::generate(param.VoiceFilter);
        }

        if(param.PFilterEnvelopeEnabled != 0)
            vce.FilterEnvelope = new Envelope(param.FilterEnvelope, basefreq);

        if(param.PFilterLfoEnabled != 0)
            vce.FilterLfo = new LFO(param.FilterLfo, basefreq);

        vce.FilterFreqTracking =
            param.VoiceFilter->getfreqtracking(basefreq);

        /* Voice Modulation Parameters Init */
        if((vce.FMEnabled != NONE) && (vce.FMVoice < 0)) {
            param.FMSmp->newrandseed(prng());
            vce.FMSmp = new float[synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES];

            //Perform Anti-aliasing only on MORPH or RING MODULATION

            int vc = nvoice;
            if(param.PextFMoscil != -1)
                vc = param.PextFMoscil;

            float tmp = 1.0f;
            if((partparams->VoicePar[vc].FMSmp->Padaptiveharmonics != 0)
               || (vce.FMEnabled == MORPH)
               || (vce.FMEnabled == RING_MOD))
                tmp = getFMvoicebasefreq(nvoice);

            if(!partparams->GlobalPar.Hrandgrouping)
                partparams->VoicePar[vc].FMSmp->newrandseed(prng());

            for(int k = 0; k < unison_size[nvoice]; ++k)
                oscposhiFM[nvoice][k] = (oscposhi[nvoice][k]
                                         + partparams->VoicePar[vc].FMSmp->get(
                                             vce.FMSmp, tmp))
                                        % synth->oscilsize;

            for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i)
                vce.FMSmp[synth->oscilsize + i] = vce.FMSmp[i];
            int oscposhiFM_add =
                (int)((param.PFMoscilphase
                       - 64.0f) / 128.0f * synth->oscilsize
                      + synth->oscilsize * 4);
            for(int k = 0; k < unison_size[nvoice]; ++k) {
                oscposhiFM[nvoice][k] += oscposhiFM_add;
                oscposhiFM[nvoice][k] %= synth->oscilsize;
            }
        }

        if(param.PFMFreqEnvelopeEnabled != 0)
            vce.FMFreqEnvelope = new Envelope(param.FMFreqEnvelope, basefreq);

        FMnewamplitude[nvoice] = vce.FMVolume * ctl->fmamp.relamp;

        if(param.PFMAmpEnvelopeEnabled != 0) {
            vce.FMAmpEnvelope = new Envelope(param.FMAmpEnvelope,
                                             basefreq);
            FMnewamplitude[nvoice] *= vce.FMAmpEnvelope->envout_dB();
        }
    }

    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        for(int i = nvoice + 1; i < NUM_VOICES; ++i)
            tmp[i] = 0;
        for(int i = nvoice + 1; i < NUM_VOICES; ++i)
            if((NoteVoicePar[i].FMVoice == nvoice) && (tmp[i] == 0)) {
                NoteVoicePar[nvoice].VoiceOut = new float[synth->buffersize];
                tmp[i] = 1;
            }

        if(NoteVoicePar[nvoice].VoiceOut)
            memset(NoteVoicePar[nvoice].VoiceOut, 0, synth->bufferbytes);
    }
}


/*
 * Computes the relative frequency of each unison voice and it's vibratto
 * This must be called before setfreq* functions
 */
void ADnote::compute_unison_freq_rap(int nvoice) {
    if(unison_size[nvoice] == 1) { //no unison
        unison_freq_rap[nvoice][0] = 1.0f;
        return;
    }
    float relbw = ctl->bandwidth.relbw * bandwidthDetuneMultiplier;
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        float pos  = unison_vibratto[nvoice].position[k];
        float step = unison_vibratto[nvoice].step[k];
        pos += step;
        if(pos <= -1.0f) {
            pos  = -1.0f;
            step = -step;
        }
        if(pos >= 1.0f) {
            pos  = 1.0f;
            step = -step;
        }
        float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother
        unison_freq_rap[nvoice][k] = 1.0f
                                     + ((unison_base_freq_rap[nvoice][k]
                                         - 1.0f) + vibratto_val
                                        * unison_vibratto[nvoice].amplitude)
                                     * relbw;

        unison_vibratto[nvoice].position[k] = pos;
        step = unison_vibratto[nvoice].step[k] = step;
    }
}


/*
 * Computes the frequency of an oscillator
 */
void ADnote::setfreq(int nvoice, float in_freq)
{
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        float freq  = fabs(in_freq) * unison_freq_rap[nvoice][k];
        float speed = freq * synth->oscilsize_f / synth->samplerate_f;
        if(speed > synth->oscilsize_f)
            speed = synth->oscilsize_f;

        F2I(speed, oscfreqhi[nvoice][k]);
        oscfreqlo[nvoice][k] = speed - floor(speed);
    }
}

/*
 * Computes the frequency of an modullator oscillator
 */
void ADnote::setfreqFM(int nvoice, float in_freq)
{
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        float freq  = fabs(in_freq) * unison_freq_rap[nvoice][k];
        float speed = freq * synth->oscilsize_f / synth->samplerate_f;
        if(speed > synth->samplerate_f)
            speed = synth->samplerate_f;

        F2I(speed, oscfreqhiFM[nvoice][k]);
        oscfreqloFM[nvoice][k] = speed - floor(speed);
    }
}

/*
 * Get Voice base frequency
 */
float ADnote::getvoicebasefreq(int nvoice) const
{
    float detune = NoteVoicePar[nvoice].Detune / 100.0f
                   + NoteVoicePar[nvoice].FineDetune / 100.0f
                   * ctl->bandwidth.relbw * bandwidthDetuneMultiplier
                   + NoteGlobalPar.Detune / 100.0f;

    if(NoteVoicePar[nvoice].fixedfreq == 0)
        return this->basefreq * powf(2, detune / 12.0f);
    else { //the fixed freq is enabled
        float fixedfreq   = 440.0f;
        int   fixedfreqET = NoteVoicePar[nvoice].fixedfreqET;
        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)
                fixedfreq *= powf(2.0f, tmp);
            else
                fixedfreq *= powf(3.0f, tmp);
        }
        return fixedfreq * powf(2.0f, detune / 12.0f);
    }
}

/*
 * Get Voice's Modullator base frequency
 */
float ADnote::getFMvoicebasefreq(int nvoice) const
{
    float detune = NoteVoicePar[nvoice].FMDetune / 100.0f;
    return getvoicebasefreq(nvoice) * powf(2, detune / 12.0f);
}

/*
 * Computes all the parameters for each tick
 */
void ADnote::computecurrentparameters()
{
    int   nvoice;
    float voicefreq, voicepitch, filterpitch, filterfreq, FMfreq,
          FMrelativepitch, globalpitch, globalfilterpitch;
    globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout()
                           + NoteGlobalPar.FreqLfo->lfoout()
                           * ctl->modwheel.relmod);
    globaloldamplitude = globalnewamplitude;
    globalnewamplitude = NoteGlobalPar.Volume
                         * NoteGlobalPar.AmpEnvelope->envout_dB()
                         * NoteGlobalPar.AmpLfo->amplfoout();

    globalfilterpitch = NoteGlobalPar.FilterEnvelope->envout()
                        + NoteGlobalPar.FilterLfo->lfoout()
                        + NoteGlobalPar.FilterCenterPitch;

    float tmpfilterfreq = globalfilterpitch + ctl->filtercutoff.relfreq
                          + NoteGlobalPar.FilterFreqTracking;

    tmpfilterfreq = Filter::getrealfreq(tmpfilterfreq);

    float globalfilterq = NoteGlobalPar.FilterQ * ctl->filterq.relq;
    NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq, globalfilterq);
    if(stereo != 0)
        NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq, globalfilterq);

    //compute the portamento, if it is used by this note
    float portamentofreqrap = 1.0f;
    if(portamento != 0) { //this voice use portamento
        portamentofreqrap = ctl->portamento.freqrap;
        if(ctl->portamento.used == 0) //the portamento has finished
            portamento = 0;  //this note is no longer "portamented"
    }

    //compute parameters for all voices
    for(nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        if(NoteVoicePar[nvoice].Enabled != ON)
            continue;
        NoteVoicePar[nvoice].DelayTicks -= 1;
        if(NoteVoicePar[nvoice].DelayTicks > 0)
            continue;

        compute_unison_freq_rap(nvoice);

        /*******************/
        /* Voice Amplitude */
        /*******************/
        oldamplitude[nvoice] = newamplitude[nvoice];
        newamplitude[nvoice] = 1.0f;

        if(NoteVoicePar[nvoice].AmpEnvelope != NULL)
            newamplitude[nvoice] *= NoteVoicePar[nvoice].AmpEnvelope->envout_dB();

        if(NoteVoicePar[nvoice].AmpLfo != NULL)
            newamplitude[nvoice] *= NoteVoicePar[nvoice].AmpLfo->amplfoout();

        /****************/
        /* Voice Filter */
        /****************/
        if(NoteVoicePar[nvoice].VoiceFilterL != NULL) {
            filterpitch = NoteVoicePar[nvoice].FilterCenterPitch;

            if(NoteVoicePar[nvoice].FilterEnvelope != NULL)
                filterpitch += NoteVoicePar[nvoice].FilterEnvelope->envout();

            if(NoteVoicePar[nvoice].FilterLfo != NULL)
                filterpitch += NoteVoicePar[nvoice].FilterLfo->lfoout();

            filterfreq = filterpitch + NoteVoicePar[nvoice].FilterFreqTracking;
            filterfreq = Filter::getrealfreq(filterfreq);

            NoteVoicePar[nvoice].VoiceFilterL->setfreq(filterfreq);
            if(stereo && NoteVoicePar[nvoice].VoiceFilterR)
                NoteVoicePar[nvoice].VoiceFilterR->setfreq(filterfreq);
        }

        if(NoteVoicePar[nvoice].noisetype == 0) { //compute only if the voice isn't noise
            /*******************/
            /* Voice Frequency */
            /*******************/
            voicepitch = 0.0f;
            if(NoteVoicePar[nvoice].FreqLfo != NULL)
                voicepitch += NoteVoicePar[nvoice].FreqLfo->lfoout() / 100.0f
                              * ctl->bandwidth.relbw;

            if(NoteVoicePar[nvoice].FreqEnvelope != NULL)
                voicepitch += NoteVoicePar[nvoice].FreqEnvelope->envout()
                              / 100.0f;
            voicefreq = getvoicebasefreq(nvoice)
                        * powf(2, (voicepitch + globalpitch) / 12.0f);                //Hz frequency
            voicefreq *= ctl->pitchwheel.relfreq; //change the frequency by the controller
            setfreq(nvoice, voicefreq * portamentofreqrap);

            /***************/
            /*  Modulator */
            /***************/
            if(NoteVoicePar[nvoice].FMEnabled != NONE) {
                FMrelativepitch = NoteVoicePar[nvoice].FMDetune / 100.0f;
                if(NoteVoicePar[nvoice].FMFreqEnvelope != NULL)
                    FMrelativepitch +=
                        NoteVoicePar[nvoice].FMFreqEnvelope->envout() / 100;
                FMfreq =
                    powf(2.0f, FMrelativepitch
                         / 12.0f) * voicefreq * portamentofreqrap;
                setfreqFM(nvoice, FMfreq);

                FMoldamplitude[nvoice] = FMnewamplitude[nvoice];
                FMnewamplitude[nvoice] = NoteVoicePar[nvoice].FMVolume
                                         * ctl->fmamp.relamp;
                if(NoteVoicePar[nvoice].FMAmpEnvelope != NULL)
                    FMnewamplitude[nvoice] *=
                        NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB();
            }
        }
    }
    time += synth->buffersize_f / synth->samplerate_f;
}


/*
 * Fadein in a way that removes clicks but keep sound "punchy"
 */
inline void ADnote::fadein(float *smps) const
{
    int zerocrossings = 0;
    for(int i = 1; i < synth->buffersize; ++i)
        if((smps[i - 1] < 0.0f) && (smps[i] > 0.0f))
            zerocrossings++;  //this is only the possitive crossings

    float tmp = (synth->buffersize_f - 1.0f) / (zerocrossings + 1) / 3.0f;
    if(tmp < 8.0f)
        tmp = 8.0f;

    int n;
    F2I(tmp, n); //how many samples is the fade-in
    if(n > synth->buffersize)
        n = synth->buffersize;
    for(int i = 0; i < n; ++i) { //fade-in
        float tmp = 0.5f - cosf((float)i / (float) n * PI) * 0.5f;
        smps[i] *= tmp;
    }
}

/*
 * Computes the Oscillator (Without Modulation) - LinearInterpolation
 */

/* As the code here is a bit odd due to optimization, here is what happens
 * First the current possition and frequency are retrieved from the running
 * state. These are broken up into high and low portions to indicate how many
 * samples are skipped in one step and how many fractional samples are skipped.
 * Outside of this method the fractional samples are just handled with floating
 * point code, but that's a bit slower than it needs to be. In this code the low
 * portions are known to exist between 0.0 and 1.0 and it is known that they are
 * stored in single precision floating point IEEE numbers. This implies that
 * a maximum of 24 bits are significant. The below code does your standard
 * linear interpolation that you'll see throughout this codebase, but by
 * sticking to integers for tracking the overflow of the low portion, around 15%
 * of the execution time was shaved off in the ADnote test.
 */
inline void ADnote::ComputeVoiceOscillator_LinearInterpolation(int nvoice)
{
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        int    poshi  = oscposhi[nvoice][k];
        int    poslo  = oscposlo[nvoice][k] * (1<<24);
        int    freqhi = oscfreqhi[nvoice][k];
        int    freqlo = oscfreqlo[nvoice][k] * (1<<24);
        float *smps   = NoteVoicePar[nvoice].OscilSmp;
        float *tw     = tmpwave_unison[k];
        assert(oscfreqlo[nvoice][k] < 1.0f);
        for(int i = 0; i < synth->buffersize; ++i) {
            tw[i]  = (smps[poshi] * ((1<<24) - poslo) + smps[poshi + 1] * poslo)/(1.0f*(1<<24));
            poslo += freqlo;
            poshi += freqhi + (poslo>>24);
            poslo &= 0xffffff;
            poshi &= synth->oscilsize - 1;
        }
        oscposhi[nvoice][k] = poshi;
        oscposlo[nvoice][k] = poslo/(1.0f*(1<<24));
    }
}



/*
 * Computes the Oscillator (Without Modulation) - CubicInterpolation
 *
 The differences from the Linear are to little to deserve to be used. This is because I am using a large synth->oscilsize (>512)
inline void ADnote::ComputeVoiceOscillator_CubicInterpolation(int nvoice){
    int i,poshi;
    float poslo;

    poshi=oscposhi[nvoice];
    poslo=oscposlo[nvoice];
    float *smps=NoteVoicePar[nvoice].OscilSmp;
    float xm1,x0,x1,x2,a,b,c;
    for (i=0;i<synth->buffersize;i++){
    xm1=smps[poshi];
    x0=smps[poshi+1];
    x1=smps[poshi+2];
    x2=smps[poshi+3];
    a=(3.0f * (x0-x1) - xm1 + x2) / 2.0f;
    b = 2.0f*x1 + xm1 - (5.0f*x0 + x2) / 2.0f;
    c = (x1 - xm1) / 2.0f;
    tmpwave[i]=(((a * poslo) + b) * poslo + c) * poslo + x0;
    printf("a\n");
    //tmpwave[i]=smps[poshi]*(1.0f-poslo)+smps[poshi+1]*poslo;
    poslo+=oscfreqlo[nvoice];
    if (poslo>=1.0f) {
            poslo-=1.0f;
        poshi++;
    };
        poshi+=oscfreqhi[nvoice];
        poshi&=synth->oscilsize-1;
    };
    oscposhi[nvoice]=poshi;
    oscposlo[nvoice]=poslo;
};
*/
/*
 * Computes the Oscillator (Morphing)
 */
inline void ADnote::ComputeVoiceOscillatorMorph(int nvoice)
{
    int   i;
    float amp;
    ComputeVoiceOscillator_LinearInterpolation(nvoice);
    if(FMnewamplitude[nvoice] > 1.0f)
        FMnewamplitude[nvoice] = 1.0f;
    if(FMoldamplitude[nvoice] > 1.0f)
        FMoldamplitude[nvoice] = 1.0f;

    if(NoteVoicePar[nvoice].FMVoice >= 0) {
        //if I use VoiceOut[] as modullator
        int FMVoice = NoteVoicePar[nvoice].FMVoice;
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            for(i = 0; i < synth->buffersize; ++i) {
                amp = INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice],
                                            FMnewamplitude[nvoice],
                                            i,
                                            synth->buffersize);
                tw[i] = tw[i]
                        * (1.0f
                           - amp) + amp * NoteVoicePar[FMVoice].VoiceOut[i];
            }
        }
    }
    else
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            int    poshiFM  = oscposhiFM[nvoice][k];
            float  posloFM  = oscposloFM[nvoice][k];
            int    freqhiFM = oscfreqhiFM[nvoice][k];
            float  freqloFM = oscfreqloFM[nvoice][k];
            float *tw = tmpwave_unison[k];

            for(i = 0; i < synth->buffersize; ++i) {
                amp = INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice],
                                            FMnewamplitude[nvoice],
                                            i,
                                            synth->buffersize);
                tw[i] = tw[i] * (1.0f - amp) + amp
                        * (NoteVoicePar[nvoice].FMSmp[poshiFM] * (1 - posloFM)
                           + NoteVoicePar[nvoice].FMSmp[poshiFM + 1] * posloFM);
                posloFM += freqloFM;
                if(posloFM >= 1.0f) {
                    posloFM -= 1.0f;
                    poshiFM++;
                }
                poshiFM += freqhiFM;
                poshiFM &= synth->oscilsize - 1;
            }
            oscposhiFM[nvoice][k] = poshiFM;
            oscposloFM[nvoice][k] = posloFM;
        }
}

/*
 * Computes the Oscillator (Ring Modulation)
 */
inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice)
{
    int   i;
    float amp;
    ComputeVoiceOscillator_LinearInterpolation(nvoice);
    if(FMnewamplitude[nvoice] > 1.0f)
        FMnewamplitude[nvoice] = 1.0f;
    if(FMoldamplitude[nvoice] > 1.0f)
        FMoldamplitude[nvoice] = 1.0f;
    if(NoteVoicePar[nvoice].FMVoice >= 0)
        // if I use VoiceOut[] as modullator
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            for(i = 0; i < synth->buffersize; ++i) {
                amp = INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice],
                                            FMnewamplitude[nvoice],
                                            i,
                                            synth->buffersize);
                int FMVoice = NoteVoicePar[nvoice].FMVoice;
                tw[i] *= (1.0f - amp) + amp * NoteVoicePar[FMVoice].VoiceOut[i];
            }
        }
    else
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            int    poshiFM  = oscposhiFM[nvoice][k];
            float  posloFM  = oscposloFM[nvoice][k];
            int    freqhiFM = oscfreqhiFM[nvoice][k];
            float  freqloFM = oscfreqloFM[nvoice][k];
            float *tw = tmpwave_unison[k];

            for(i = 0; i < synth->buffersize; ++i) {
                amp = INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice],
                                            FMnewamplitude[nvoice],
                                            i,
                                            synth->buffersize);
                tw[i] *= (NoteVoicePar[nvoice].FMSmp[poshiFM] * (1.0f - posloFM)
                          + NoteVoicePar[nvoice].FMSmp[poshiFM
                                                       + 1] * posloFM) * amp
                         + (1.0f - amp);
                posloFM += freqloFM;
                if(posloFM >= 1.0f) {
                    posloFM -= 1.0f;
                    poshiFM++;
                }
                poshiFM += freqhiFM;
                poshiFM &= synth->oscilsize - 1;
            }
            oscposhiFM[nvoice][k] = poshiFM;
            oscposloFM[nvoice][k] = posloFM;
        }
}



/*
 * Computes the Oscillator (Phase Modulation or Frequency Modulation)
 */
inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,
                                                              int FMmode)
{
    int   carposhi = 0;
    int   i, FMmodfreqhi = 0;
    float FMmodfreqlo = 0, carposlo = 0;

    if(NoteVoicePar[nvoice].FMVoice >= 0)
        //if I use VoiceOut[] as modulator
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            memcpy(tw, NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut,
                   synth->bufferbytes);
        }
    else
        //Compute the modulator and store it in tmpwave_unison[][]
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            int    poshiFM  = oscposhiFM[nvoice][k];
            float  posloFM  = oscposloFM[nvoice][k];
            int    freqhiFM = oscfreqhiFM[nvoice][k];
            float  freqloFM = oscfreqloFM[nvoice][k];
            float *tw = tmpwave_unison[k];

            for(i = 0; i < synth->buffersize; ++i) {
                tw[i] =
                    (NoteVoicePar[nvoice].FMSmp[poshiFM] * (1.0f - posloFM)
                     + NoteVoicePar[nvoice].FMSmp[poshiFM + 1] * posloFM);
                posloFM += freqloFM;
                if(posloFM >= 1.0f) {
                    posloFM = fmod(posloFM, 1.0f);
                    poshiFM++;
                }
                poshiFM += freqhiFM;
                poshiFM &= synth->oscilsize - 1;
            }
            oscposhiFM[nvoice][k] = poshiFM;
            oscposloFM[nvoice][k] = posloFM;
        }
    // Amplitude interpolation
    if(ABOVE_AMPLITUDE_THRESHOLD(FMoldamplitude[nvoice],
                                 FMnewamplitude[nvoice]))
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            for(i = 0; i < synth->buffersize; ++i)
                tw[i] *= INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice],
                                               FMnewamplitude[nvoice],
                                               i,
                                               synth->buffersize);
        }
    else
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            for(i = 0; i < synth->buffersize; ++i)
                tw[i] *= FMnewamplitude[nvoice];
        }


    //normalize: makes all sample-rates, oscil_sizes to produce same sound
    if(FMmode != 0) { //Frequency modulation
        float normalize = synth->oscilsize_f / 262144.0f * 44100.0f
                          / synth->samplerate_f;
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw    = tmpwave_unison[k];
            float  fmold = FMoldsmp[nvoice][k];
            for(i = 0; i < synth->buffersize; ++i) {
                fmold = fmod(fmold + tw[i] * normalize, synth->oscilsize);
                tw[i] = fmold;
            }
            FMoldsmp[nvoice][k] = fmold;
        }
    }
    else {  //Phase modulation
        float normalize = synth->oscilsize_f / 262144.0f;
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            for(i = 0; i < synth->buffersize; ++i)
                tw[i] *= normalize;
        }
    }

    //do the modulation
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        float *tw     = tmpwave_unison[k];
        int    poshi  = oscposhi[nvoice][k];
        float  poslo  = oscposlo[nvoice][k];
        int    freqhi = oscfreqhi[nvoice][k];
        float  freqlo = oscfreqlo[nvoice][k];

        for(i = 0; i < synth->buffersize; ++i) {
            F2I(tw[i], FMmodfreqhi);
            FMmodfreqlo = fmod(tw[i] + 0.0000000001f, 1.0f);
            if(FMmodfreqhi < 0)
                FMmodfreqlo++;

            //carrier
            carposhi = poshi + FMmodfreqhi;
            carposlo = poslo + FMmodfreqlo;

            if(carposlo >= 1.0f) {
                carposhi++;
                carposlo = fmod(carposlo, 1.0f);
            }
            carposhi &= (synth->oscilsize - 1);

            tw[i] = NoteVoicePar[nvoice].OscilSmp[carposhi]
                    * (1.0f - carposlo)
                    + NoteVoicePar[nvoice].OscilSmp[carposhi
                                                    + 1] * carposlo;

            poslo += freqlo;
            if(poslo >= 1.0f) {
                poslo = fmod(poslo, 1.0f);
                poshi++;
            }

            poshi += freqhi;
            poshi &= synth->oscilsize - 1;
        }
        oscposhi[nvoice][k] = poshi;
        oscposlo[nvoice][k] = poslo;
    }
}


/*Calculeaza Oscilatorul cu PITCH MODULATION*/
inline void ADnote::ComputeVoiceOscillatorPitchModulation(int /*nvoice*/)
{
//TODO
}

/*
 * Computes the Noise
 */
inline void ADnote::ComputeVoiceNoise(int nvoice)
{
    for(int k = 0; k < unison_size[nvoice]; ++k) {
        float *tw = tmpwave_unison[k];
        for(int i = 0; i < synth->buffersize; ++i)
            tw[i] = RND * 2.0f - 1.0f;
    }
}



/*
 * Compute the ADnote samples
 * Returns 0 if the note is finished
 */
int ADnote::noteout(float *outl, float *outr)
{
    memcpy(outl, denormalkillbuf, synth->bufferbytes);
    memcpy(outr, denormalkillbuf, synth->bufferbytes);

    if(NoteEnabled == OFF)
        return 0;

    memset(bypassl, 0, synth->bufferbytes);
    memset(bypassr, 0, synth->bufferbytes);
    computecurrentparameters();

    for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
        if((NoteVoicePar[nvoice].Enabled != ON)
           || (NoteVoicePar[nvoice].DelayTicks > 0))
            continue;
        if(NoteVoicePar[nvoice].noisetype == 0) //voice mode=sound
            switch(NoteVoicePar[nvoice].FMEnabled) {
                case MORPH:
                    ComputeVoiceOscillatorMorph(nvoice);
                    break;
                case RING_MOD:
                    ComputeVoiceOscillatorRingModulation(nvoice);
                    break;
                case PHASE_MOD:
                    ComputeVoiceOscillatorFrequencyModulation(nvoice, 0);
                    break;
                case FREQ_MOD:
                    ComputeVoiceOscillatorFrequencyModulation(nvoice, 1);
                    break;
                //case PITCH_MOD:ComputeVoiceOscillatorPitchModulation(nvoice);break;
                default:
                    ComputeVoiceOscillator_LinearInterpolation(nvoice);
                    //if (config.cfg.Interpolation) ComputeVoiceOscillator_CubicInterpolation(nvoice);
            }
        else
            ComputeVoiceNoise(nvoice);
        // Voice Processing


        //mix subvoices into voice
        memset(tmpwavel, 0, synth->bufferbytes);
        if(stereo)
            memset(tmpwaver, 0, synth->bufferbytes);
        for(int k = 0; k < unison_size[nvoice]; ++k) {
            float *tw = tmpwave_unison[k];
            if(stereo) {
                float stereo_pos = 0;
                if(unison_size[nvoice] > 1)
                    stereo_pos = k
                                 / (float)(unison_size[nvoice]
                                           - 1) * 2.0f - 1.0f;
                float stereo_spread = unison_stereo_spread[nvoice] * 2.0f; //between 0 and 2.0f
                if(stereo_spread > 1.0f) {
                    float stereo_pos_1 = (stereo_pos >= 0.0f) ? 1.0f : -1.0f;
                    stereo_pos =
                        (2.0f
                         - stereo_spread) * stereo_pos
                        + (stereo_spread - 1.0f) * stereo_pos_1;
                }
                else
                    stereo_pos *= stereo_spread;

                if(unison_size[nvoice] == 1)
                    stereo_pos = 0.0f;
                float panning = (stereo_pos + 1.0f) * 0.5f;


                float lvol = (1.0f - panning) * 2.0f;
                if(lvol > 1.0f)
                    lvol = 1.0f;

                float rvol = panning * 2.0f;
                if(rvol > 1.0f)
                    rvol = 1.0f;

                if(unison_invert_phase[nvoice][k]) {
                    lvol = -lvol;
                    rvol = -rvol;
                }

                for(int i = 0; i < synth->buffersize; ++i)
                    tmpwavel[i] += tw[i] * lvol;
                for(int i = 0; i < synth->buffersize; ++i)
                    tmpwaver[i] += tw[i] * rvol;
            }
            else
                for(int i = 0; i < synth->buffersize; ++i)
                    tmpwavel[i] += tw[i];
        }


        float unison_amplitude = 1.0f / sqrt(unison_size[nvoice]); //reduce the amplitude for large unison sizes
        // Amplitude
        float oldam = oldamplitude[nvoice] * unison_amplitude;
        float newam = newamplitude[nvoice] * unison_amplitude;

        if(ABOVE_AMPLITUDE_THRESHOLD(oldam, newam)) {
            int rest = synth->buffersize;
            //test if the amplitude if raising and the difference is high
            if((newam > oldam) && ((newam - oldam) > 0.25f)) {
                rest = 10;
                if(rest > synth->buffersize)
                    rest = synth->buffersize;
                for(int i = 0; i < synth->buffersize - rest; ++i)
                    tmpwavel[i] *= oldam;
                if(stereo)
                    for(int i = 0; i < synth->buffersize - rest; ++i)
                        tmpwaver[i] *= oldam;
            }
            // Amplitude interpolation
            for(int i = 0; i < rest; ++i) {
                float amp = INTERPOLATE_AMPLITUDE(oldam, newam, i, rest);
                tmpwavel[i + (synth->buffersize - rest)] *= amp;
                if(stereo)
                    tmpwaver[i + (synth->buffersize - rest)] *= amp;
            }
        }
        else {
            for(int i = 0; i < synth->buffersize; ++i)
                tmpwavel[i] *= newam;
            if(stereo)
                for(int i = 0; i < synth->buffersize; ++i)
                    tmpwaver[i] *= newam;
        }

        // Fade in
        if(firsttick[nvoice] != 0) {
            fadein(&tmpwavel[0]);
            if(stereo)
                fadein(&tmpwaver[0]);
            firsttick[nvoice] = 0;
        }


        // Filter
        if(NoteVoicePar[nvoice].VoiceFilterL != NULL)
            NoteVoicePar[nvoice].VoiceFilterL->filterout(&tmpwavel[0]);
        if((stereo) && (NoteVoicePar[nvoice].VoiceFilterR != NULL))
            NoteVoicePar[nvoice].VoiceFilterR->filterout(&tmpwaver[0]);

        //check if the amplitude envelope is finished, if yes, the voice will be fadeout
        if(NoteVoicePar[nvoice].AmpEnvelope != NULL)
            if(NoteVoicePar[nvoice].AmpEnvelope->finished() != 0) {
                for(int i = 0; i < synth->buffersize; ++i)
                    tmpwavel[i] *= 1.0f - (float)i / synth->buffersize_f;
                if(stereo)
                    for(int i = 0; i < synth->buffersize; ++i)
                        tmpwaver[i] *= 1.0f - (float)i / synth->buffersize_f;
            }
        //the voice is killed later


        // Put the ADnote samples in VoiceOut (without appling Global volume, because I wish to use this voice as a modullator)
        if(NoteVoicePar[nvoice].VoiceOut != NULL) {
            if(stereo)
                for(int i = 0; i < synth->buffersize; ++i)
                    NoteVoicePar[nvoice].VoiceOut[i] = tmpwavel[i]
                                                       + tmpwaver[i];
            else   //mono
                for(int i = 0; i < synth->buffersize; ++i)
                    NoteVoicePar[nvoice].VoiceOut[i] = tmpwavel[i];
        }


        // Add the voice that do not bypass the filter to out
        if(NoteVoicePar[nvoice].filterbypass == 0) { //no bypass
            if(stereo)
                for(int i = 0; i < synth->buffersize; ++i) { //stereo
                    outl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume
                               * NoteVoicePar[nvoice].Panning * 2.0f;
                    outr[i] += tmpwaver[i] * NoteVoicePar[nvoice].Volume
                               * (1.0f - NoteVoicePar[nvoice].Panning) * 2.0f;
                }
            else
                for(int i = 0; i < synth->buffersize; ++i) //mono
                    outl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume;
        }
        else {  //bypass the filter
            if(stereo)
                for(int i = 0; i < synth->buffersize; ++i) { //stereo
                    bypassl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume
                                  * NoteVoicePar[nvoice].Panning * 2.0f;
                    bypassr[i] += tmpwaver[i] * NoteVoicePar[nvoice].Volume
                                  * (1.0f
                                     - NoteVoicePar[nvoice].Panning) * 2.0f;
                }
            else
                for(int i = 0; i < synth->buffersize; ++i) //mono
                    bypassl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume;
        }
        // chech if there is necesary to proces the voice longer (if the Amplitude envelope isn't finished)
        if(NoteVoicePar[nvoice].AmpEnvelope != NULL)
            if(NoteVoicePar[nvoice].AmpEnvelope->finished() != 0)
                KillVoice(nvoice);
    }


    //Processing Global parameters
    NoteGlobalPar.GlobalFilterL->filterout(&outl[0]);

    if(stereo == 0) { //set the right channel=left channel
        memcpy(outr, outl, synth->bufferbytes);
        memcpy(bypassr, bypassl, synth->bufferbytes);
    }
    else
        NoteGlobalPar.GlobalFilterR->filterout(&outr[0]);

    for(int i = 0; i < synth->buffersize; ++i) {
        outl[i] += bypassl[i];
        outr[i] += bypassr[i];
    }

    if(ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude, globalnewamplitude))
        // Amplitude Interpolation
        for(int i = 0; i < synth->buffersize; ++i) {
            float tmpvol = INTERPOLATE_AMPLITUDE(globaloldamplitude,
                                                 globalnewamplitude,
                                                 i,
                                                 synth->buffersize);
            outl[i] *= tmpvol * NoteGlobalPar.Panning;
            outr[i] *= tmpvol * (1.0f - NoteGlobalPar.Panning);
        }
    else
        for(int i = 0; i < synth->buffersize; ++i) {
            outl[i] *= globalnewamplitude * NoteGlobalPar.Panning;
            outr[i] *= globalnewamplitude * (1.0f - NoteGlobalPar.Panning);
        }

    //Apply the punch
    if(NoteGlobalPar.Punch.Enabled != 0)
        for(int i = 0; i < synth->buffersize; ++i) {
            float punchamp = NoteGlobalPar.Punch.initialvalue
                             * NoteGlobalPar.Punch.t + 1.0f;
            outl[i] *= punchamp;
            outr[i] *= punchamp;
            NoteGlobalPar.Punch.t -= NoteGlobalPar.Punch.dt;
            if(NoteGlobalPar.Punch.t < 0.0f) {
                NoteGlobalPar.Punch.Enabled = 0;
                break;
            }
        }


    // Apply legato-specific sound signal modifications
    legato.apply(*this, outl, outr);


    // Check if the global amplitude is finished.
    // If it does, disable the note
    if(NoteGlobalPar.AmpEnvelope->finished()) {
        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 the key (NoteOff)
 */
void ADnote::relasekey()
{
    for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice)
        NoteVoicePar[nvoice].releasekey();
    NoteGlobalPar.FreqEnvelope->relasekey();
    NoteGlobalPar.FilterEnvelope->relasekey();
    NoteGlobalPar.AmpEnvelope->relasekey();
}

/*
 * Check if the note is finished
 */
int ADnote::finished() const
{
    if(NoteEnabled == ON)
        return 0;
    else
        return 1;
}

void ADnote::Voice::releasekey()
{
    if(!Enabled)
        return;
    if(AmpEnvelope)
        AmpEnvelope->relasekey();
    if(FreqEnvelope)
        FreqEnvelope->relasekey();
    if(FilterEnvelope)
        FilterEnvelope->relasekey();
    if(FMFreqEnvelope)
        FMFreqEnvelope->relasekey();
    if(FMAmpEnvelope)
        FMAmpEnvelope->relasekey();
}

template<class T>
static inline void nullify(T &t) {delete t; t = NULL; }
template<class T>
static inline void arrayNullify(T &t) {delete [] t; t = NULL; }

void ADnote::Voice::kill()
{
    arrayNullify(OscilSmp);
    nullify(FreqEnvelope);
    nullify(FreqLfo);
    nullify(AmpEnvelope);
    nullify(AmpLfo);
    nullify(VoiceFilterL);
    nullify(VoiceFilterR);
    nullify(FilterEnvelope);
    nullify(FilterLfo);
    nullify(FMFreqEnvelope);
    nullify(FMAmpEnvelope);

    if((FMEnabled != NONE) && (FMVoice < 0)) {
        delete[] FMSmp;
        FMSmp = NULL;
    }

    if(VoiceOut)
        memset(VoiceOut, 0, synth->bufferbytes);
    //do not delete, yet: perhaps is used by another voice

    Enabled = OFF;
}

void ADnote::Global::kill()
{
    nullify(FreqEnvelope);
    nullify(FreqLfo);
    nullify(AmpEnvelope);
    nullify(AmpLfo);
    nullify(GlobalFilterL);
    nullify(GlobalFilterR);
    nullify(FilterEnvelope);
    nullify(FilterLfo);
}

void ADnote::Global::initparameters(const ADnoteGlobalParam &param,
                                    float basefreq, float velocity,
                                    bool stereo)
{
    FreqEnvelope = new Envelope(param.FreqEnvelope, basefreq);
    FreqLfo      = new LFO(param.FreqLfo, basefreq);

    AmpEnvelope = new Envelope(param.AmpEnvelope, basefreq);
    AmpLfo      = new LFO(param.AmpLfo, basefreq);

    Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB
             * VelF(velocity, param.PAmpVelocityScaleFunction);     //sensing

    GlobalFilterL = Filter::generate(param.GlobalFilter);
    if(stereo)
        GlobalFilterR = Filter::generate(param.GlobalFilter);
    else
        GlobalFilterR = NULL;

    FilterEnvelope = new Envelope(param.FilterEnvelope, basefreq);
    FilterLfo      = new LFO(param.FilterLfo, basefreq);
    FilterQ = param.GlobalFilter->getq();
    FilterFreqTracking = param.GlobalFilter->getfreqtracking(basefreq);
}
