diff options
Diffstat (limited to 'attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C')
-rw-r--r-- | attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C new file mode 100644 index 00000000..574e2bea --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C @@ -0,0 +1,984 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnote.C - 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 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) 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 <math.h> +#include <stdlib.h> +#include <stdio.h> + + +#include "../globals.h" +#include "../Misc/Util.h" +#include "ADnote.h" + + +ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_){ + ready=0; + + tmpwave=new REALTYPE [SOUND_BUFFER_SIZE]; + bypassl=new REALTYPE [SOUND_BUFFER_SIZE]; + bypassr=new REALTYPE [SOUND_BUFFER_SIZE]; + + partparams=pars; + ctl=ctl_; + portamento=portamento_; + midinote=midinote_; + NoteEnabled=ON; + basefreq=freq; + if (velocity>1.0) velocity=1.0; + this->velocity=velocity; + time=0.0; + 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.0; + + + NoteGlobalPar.FilterCenterPitch=pars->GlobalPar.GlobalFilter->getfreq()+//center freq + pars->GlobalPar.PFilterVelocityScale/127.0*6.0* //velocity sensing + (VelF(velocity,pars->GlobalPar.PFilterVelocityScaleFunction)-1); + + if (pars->GlobalPar.PPunchStrength!=0) { + NoteGlobalPar.Punch.Enabled=1; + NoteGlobalPar.Punch.t=1.0;//start from 1.0 and to 0.0 + NoteGlobalPar.Punch.initialvalue=( (pow(10,1.5*pars->GlobalPar.PPunchStrength/127.0)-1.0) + *VelF(velocity,pars->GlobalPar.PPunchVelocitySensing) ); + REALTYPE time=pow(10,3.0*pars->GlobalPar.PPunchTime/127.0)/10000.0;//0.1 .. 100 ms + REALTYPE stretch=pow(440.0/freq,pars->GlobalPar.PPunchStretch/64.0); + NoteGlobalPar.Punch.dt=1.0/(time*SAMPLE_RATE*stretch); + } else NoteGlobalPar.Punch.Enabled=0; + + for (int nvoice=0;nvoice<NUM_VOICES;nvoice++){ + pars->VoicePar[nvoice].OscilSmp->newrandseed(rand()); + NoteVoicePar[nvoice].OscilSmp=NULL; + NoteVoicePar[nvoice].FMSmp=NULL; + NoteVoicePar[nvoice].VoiceOut=NULL; + + NoteVoicePar[nvoice].FMVoice=-1; + + if (pars->VoicePar[nvoice].Enabled==0) { + NoteVoicePar[nvoice].Enabled=OFF; + continue; //the voice is disabled + }; + + 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); + }; + + oscposhi[nvoice]=0;oscposlo[nvoice]=0.0; + oscposhiFM[nvoice]=0;oscposloFM[nvoice]=0.0; + + NoteVoicePar[nvoice].OscilSmp=new REALTYPE[OSCIL_SIZE+OSCIL_SMP_EXTRA_SAMPLES];//the extra points contains the first point + + //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(rand()); + oscposhi[nvoice]=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[OSCIL_SIZE+i]=NoteVoicePar[nvoice].OscilSmp[i]; + + oscposhi[nvoice]+=(int)((pars->VoicePar[nvoice].Poscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + oscposhi[nvoice]%=OSCIL_SIZE; + + + NoteVoicePar[nvoice].FreqLfo=NULL; + NoteVoicePar[nvoice].FreqEnvelope=NULL; + + NoteVoicePar[nvoice].AmpLfo=NULL; + NoteVoicePar[nvoice].AmpEnvelope=NULL; + + NoteVoicePar[nvoice].VoiceFilter=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) + REALTYPE fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0-1.0); + switch (NoteVoicePar[nvoice].FMEnabled){ + case PHASE_MOD:fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0); + NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0; + break; + case FREQ_MOD:NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0; + break; + // case PITCH_MOD:NoteVoicePar[nvoice].FMVolume=(pars->VoicePar[nvoice].PFMVolume/127.0*8.0)*fmvoldamp;//??????????? + // break; + default:if (fmvoldamp>1.0) fmvoldamp=1.0; + NoteVoicePar[nvoice].FMVolume=pars->VoicePar[nvoice].PFMVolume/127.0*fmvoldamp; + }; + + //Voice's modulator velocity sensing + NoteVoicePar[nvoice].FMVolume*=VelF(velocity,partparams->VoicePar[nvoice].PFMVelocityScaleFunction); + + FMoldsmp[nvoice]=0.0;//this is for FM (integration) + + firsttick[nvoice]=1; + NoteVoicePar[nvoice].DelayTicks=(int)((exp(pars->VoicePar[nvoice].PDelay/127.0*log(50.0))-1.0)/SOUND_BUFFER_SIZE/10.0*SAMPLE_RATE); + }; + + initparameters(); + ready=1; +}; + + +/* + * Kill a voice of ADnote + */ +void ADnote::KillVoice(int nvoice){ + + delete (NoteVoicePar[nvoice].OscilSmp); + + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); + NoteVoicePar[nvoice].FreqEnvelope=NULL; + + if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo); + NoteVoicePar[nvoice].FreqLfo=NULL; + + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope); + NoteVoicePar[nvoice].AmpEnvelope=NULL; + + if (NoteVoicePar[nvoice].AmpLfo!=NULL) delete (NoteVoicePar[nvoice].AmpLfo); + NoteVoicePar[nvoice].AmpLfo=NULL; + + if (NoteVoicePar[nvoice].VoiceFilter!=NULL) delete (NoteVoicePar[nvoice].VoiceFilter); + NoteVoicePar[nvoice].VoiceFilter=NULL; + + if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) delete (NoteVoicePar[nvoice].FilterEnvelope); + NoteVoicePar[nvoice].FilterEnvelope=NULL; + + if (NoteVoicePar[nvoice].FilterLfo!=NULL) delete (NoteVoicePar[nvoice].FilterLfo); + NoteVoicePar[nvoice].FilterLfo=NULL; + + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMFreqEnvelope); + NoteVoicePar[nvoice].FMFreqEnvelope=NULL; + + if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMAmpEnvelope); + NoteVoicePar[nvoice].FMAmpEnvelope=NULL; + + if ((NoteVoicePar[nvoice].FMEnabled!=NONE)&&(NoteVoicePar[nvoice].FMVoice<0)) delete NoteVoicePar[nvoice].FMSmp; + + if (NoteVoicePar[nvoice].VoiceOut!=NULL) + for (int i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0;//do not delete, yet: perhaps is used by another voice + + NoteVoicePar[nvoice].Enabled=OFF; +}; + +/* + * Kill the note + */ +void ADnote::KillNote(){ + int nvoice; + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled==ON) KillVoice(nvoice); + + //delete VoiceOut + if (NoteVoicePar[nvoice].VoiceOut!=NULL) delete(NoteVoicePar[nvoice].VoiceOut); + NoteVoicePar[nvoice].VoiceOut=NULL; + }; + + delete (NoteGlobalPar.FreqEnvelope); + delete (NoteGlobalPar.FreqLfo); + delete (NoteGlobalPar.AmpEnvelope); + delete (NoteGlobalPar.AmpLfo); + delete (NoteGlobalPar.GlobalFilterL); + if (stereo!=0) delete (NoteGlobalPar.GlobalFilterR); + delete (NoteGlobalPar.FilterEnvelope); + delete (NoteGlobalPar.FilterLfo); + + NoteEnabled=OFF; +}; + +ADnote::~ADnote(){ + if (NoteEnabled==ON) KillNote(); + delete [] tmpwave; + delete [] bypassl; + delete [] bypassr; +}; + + +/* + * Init the parameters + */ +void ADnote::initparameters(){ + int nvoice,i,tmp[NUM_VOICES]; + + // Global Parameters + NoteGlobalPar.FreqEnvelope=new Envelope(partparams->GlobalPar.FreqEnvelope,basefreq); + NoteGlobalPar.FreqLfo=new LFO(partparams->GlobalPar.FreqLfo,basefreq); + + NoteGlobalPar.AmpEnvelope=new Envelope(partparams->GlobalPar.AmpEnvelope,basefreq); + NoteGlobalPar.AmpLfo=new LFO(partparams->GlobalPar.AmpLfo,basefreq); + + NoteGlobalPar.Volume=4.0*pow(0.1,3.0*(1.0-partparams->GlobalPar.PVolume/96.0))//-60 dB .. 0 dB + *VelF(velocity,partparams->GlobalPar.PAmpVelocityScaleFunction);//velocity sensing + + NoteGlobalPar.AmpEnvelope->envout_dB();//discard the first envelope output + globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout(); + + NoteGlobalPar.GlobalFilterL=new Filter(partparams->GlobalPar.GlobalFilter); + if (stereo!=0) NoteGlobalPar.GlobalFilterR=new Filter(partparams->GlobalPar.GlobalFilter); + + NoteGlobalPar.FilterEnvelope=new Envelope(partparams->GlobalPar.FilterEnvelope,basefreq); + NoteGlobalPar.FilterLfo=new LFO(partparams->GlobalPar.FilterLfo,basefreq); + 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 (i=0;i<NUM_VOICES;i++) if (NoteVoicePar[i].FMVoice>=i) NoteVoicePar[i].FMVoice=-1; + + // Voice Parameter init + for (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=pow(0.1,3.0*(1.0-partparams->VoicePar[nvoice].PVolume/127.0)) // -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.0; + + newamplitude[nvoice]=1.0; + if (partparams->VoicePar[nvoice].PAmpEnvelopeEnabled!=0) { + NoteVoicePar[nvoice].AmpEnvelope=new Envelope(partparams->VoicePar[nvoice].AmpEnvelope,basefreq); + NoteVoicePar[nvoice].AmpEnvelope->envout_dB();//discard the first envelope sample + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpEnvelope->envout_dB(); + }; + + if (partparams->VoicePar[nvoice].PAmpLfoEnabled!=0){ + NoteVoicePar[nvoice].AmpLfo=new LFO(partparams->VoicePar[nvoice].AmpLfo,basefreq); + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpLfo->amplfoout(); + }; + + /* Voice Frequency Parameters Init */ + if (partparams->VoicePar[nvoice].PFreqEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FreqEnvelope,basefreq); + + if (partparams->VoicePar[nvoice].PFreqLfoEnabled!=0) NoteVoicePar[nvoice].FreqLfo=new LFO(partparams->VoicePar[nvoice].FreqLfo,basefreq); + + /* Voice Filter Parameters Init */ + if (partparams->VoicePar[nvoice].PFilterEnabled!=0){ + NoteVoicePar[nvoice].VoiceFilter=new Filter(partparams->VoicePar[nvoice].VoiceFilter); + }; + + if (partparams->VoicePar[nvoice].PFilterEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FilterEnvelope=new Envelope(partparams->VoicePar[nvoice].FilterEnvelope,basefreq); + + if (partparams->VoicePar[nvoice].PFilterLfoEnabled!=0) + NoteVoicePar[nvoice].FilterLfo=new LFO(partparams->VoicePar[nvoice].FilterLfo,basefreq); + + 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(rand()); + NoteVoicePar[nvoice].FMSmp=new REALTYPE[OSCIL_SIZE+OSCIL_SMP_EXTRA_SAMPLES]; + + //Perform Anti-aliasing only on MORPH or RING MODULATION + + int vc=nvoice; + if (partparams->VoicePar[nvoice].PextFMoscil!=-1) vc=partparams->VoicePar[nvoice].PextFMoscil; + + REALTYPE tmp=1.0; + if ((partparams->VoicePar[vc].FMSmp->Padaptiveharmonics!=0)|| + (NoteVoicePar[nvoice].FMEnabled==MORPH)|| + (NoteVoicePar[nvoice].FMEnabled==RING_MOD)){ + tmp=getFMvoicebasefreq(nvoice); + }; + if (!partparams->GlobalPar.Hrandgrouping) partparams->VoicePar[vc].FMSmp->newrandseed(rand()); + + oscposhiFM[nvoice]=(oscposhi[nvoice]+partparams->VoicePar[vc].FMSmp->get(NoteVoicePar[nvoice].FMSmp,tmp)) % OSCIL_SIZE; + for (int i=0;i<OSCIL_SMP_EXTRA_SAMPLES;i++) NoteVoicePar[nvoice].FMSmp[OSCIL_SIZE+i]=NoteVoicePar[nvoice].FMSmp[i]; + oscposhiFM[nvoice]+=(int)((partparams->VoicePar[nvoice].PFMoscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + oscposhiFM[nvoice]%=OSCIL_SIZE; + }; + + if (partparams->VoicePar[nvoice].PFMFreqEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FMFreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FMFreqEnvelope,basefreq); + + FMnewamplitude[nvoice]=NoteVoicePar[nvoice].FMVolume*ctl->fmamp.relamp; + + if (partparams->VoicePar[nvoice].PFMAmpEnvelopeEnabled!=0){ + NoteVoicePar[nvoice].FMAmpEnvelope=new Envelope(partparams->VoicePar[nvoice].FMAmpEnvelope,basefreq); + FMnewamplitude[nvoice]*=NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB(); + }; + }; + + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + for (i=nvoice+1;i<NUM_VOICES;i++) tmp[i]=0; + for (i=nvoice+1;i<NUM_VOICES;i++) + if ((NoteVoicePar[i].FMVoice==nvoice)&&(tmp[i]==0)){ + NoteVoicePar[nvoice].VoiceOut=new REALTYPE[SOUND_BUFFER_SIZE]; + tmp[i]=1; + }; + if (NoteVoicePar[nvoice].VoiceOut!=NULL) for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0; + }; +}; + + + +/* + * Computes the frequency of an oscillator + */ +void ADnote::setfreq(int nvoice,REALTYPE freq){ + REALTYPE speed; + freq=fabs(freq); + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhi[nvoice]); + oscfreqlo[nvoice]=speed-floor(speed); +}; + +/* + * Computes the frequency of an modullator oscillator + */ +void ADnote::setfreqFM(int nvoice,REALTYPE freq){ + REALTYPE speed; + freq=fabs(freq); + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhiFM[nvoice]); + oscfreqloFM[nvoice]=speed-floor(speed); +}; + +/* + * Get Voice base frequency + */ +REALTYPE ADnote::getvoicebasefreq(int nvoice){ + REALTYPE detune=NoteVoicePar[nvoice].Detune/100.0+ + NoteVoicePar[nvoice].FineDetune/100.0*ctl->bandwidth.relbw*bandwidthDetuneMultiplier+ + NoteGlobalPar.Detune/100.0; + + if (NoteVoicePar[nvoice].fixedfreq==0) return(this->basefreq*pow(2,detune/12.0)); + else {//the fixed freq is enabled + REALTYPE fixedfreq=440.0; + int fixedfreqET=NoteVoicePar[nvoice].fixedfreqET; + if (fixedfreqET!=0) {//if the frequency varies according the keyboard note + REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0); + if (fixedfreqET<=64) fixedfreq*=pow(2.0,tmp); + else fixedfreq*=pow(3.0,tmp); + }; + return(fixedfreq*pow(2.0,detune/12.0)); + }; +}; + +/* + * Get Voice's Modullator base frequency + */ +REALTYPE ADnote::getFMvoicebasefreq(int nvoice){ + REALTYPE detune=NoteVoicePar[nvoice].FMDetune/100.0; + return(getvoicebasefreq(nvoice)*pow(2,detune/12.0)); +}; + +/* + * Computes all the parameters for each tick + */ +void ADnote::computecurrentparameters(){ + int nvoice; + REALTYPE voicefreq,voicepitch,filterpitch,filterfreq,FMfreq,FMrelativepitch,globalpitch,globalfilterpitch; + globalpitch=0.01*(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; + + REALTYPE tmpfilterfreq=globalfilterpitch+ctl->filtercutoff.relfreq + +NoteGlobalPar.FilterFreqTracking; + + tmpfilterfreq=NoteGlobalPar.GlobalFilterL->getrealfreq(tmpfilterfreq); + + REALTYPE 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 + REALTYPE portamentofreqrap=1.0; + 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; + + /*******************/ + /* Voice Amplitude */ + /*******************/ + oldamplitude[nvoice]=newamplitude[nvoice]; + newamplitude[nvoice]=1.0; + + 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].VoiceFilter!=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=NoteVoicePar[nvoice].VoiceFilter->getrealfreq(filterfreq); + + NoteVoicePar[nvoice].VoiceFilter->setfreq(filterfreq); + }; + + if (NoteVoicePar[nvoice].noisetype==0){//compute only if the voice isn't noise + + /*******************/ + /* Voice Frequency */ + /*******************/ + voicepitch=0.0; + if (NoteVoicePar[nvoice].FreqLfo!=NULL) + voicepitch+=NoteVoicePar[nvoice].FreqLfo->lfoout()/100.0 + *ctl->bandwidth.relbw; + + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) voicepitch+=NoteVoicePar[nvoice].FreqEnvelope->envout()/100.0; + voicefreq=getvoicebasefreq(nvoice)*pow(2,(voicepitch+globalpitch)/12.0);//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.0; + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) FMrelativepitch+=NoteVoicePar[nvoice].FMFreqEnvelope->envout()/100; + FMfreq=pow(2.0,FMrelativepitch/12.0)*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+=(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; +}; + + +/* + * Fadein in a way that removes clicks but keep sound "punchy" + */ +inline void ADnote::fadein(REALTYPE *smps){ + int zerocrossings=0; + for (int i=1;i<SOUND_BUFFER_SIZE;i++) + if ((smps[i-1]<0.0) && (smps[i]>0.0)) zerocrossings++;//this is only the possitive crossings + + REALTYPE tmp=(SOUND_BUFFER_SIZE-1.0)/(zerocrossings+1)/3.0; + if (tmp<8.0) tmp=8.0; + + int n; + F2I(tmp,n);//how many samples is the fade-in + if (n>SOUND_BUFFER_SIZE) n=SOUND_BUFFER_SIZE; + for (int i=0;i<n;i++) {//fade-in + REALTYPE tmp=0.5-cos((REALTYPE)i/(REALTYPE) n*PI)*0.5; + smps[i]*=tmp; + }; +}; + +/* + * Computes the Oscillator (Without Modulation) - LinearInterpolation + */ +inline void ADnote::ComputeVoiceOscillator_LinearInterpolation(int nvoice){ + int i,poshi; + REALTYPE poslo; + + poshi=oscposhi[nvoice]; + poslo=oscposlo[nvoice]; + REALTYPE *smps=NoteVoicePar[nvoice].OscilSmp; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]=smps[poshi]*(1.0-poslo)+smps[poshi+1]*poslo; + poslo+=oscfreqlo[nvoice]; + if (poslo>=1.0) { + poslo-=1.0; + poshi++; + }; + poshi+=oscfreqhi[nvoice]; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice]=poshi; + oscposlo[nvoice]=poslo; +}; + + + +/* + * 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 OSCIL_SIZE (>512) +inline void ADnote::ComputeVoiceOscillator_CubicInterpolation(int nvoice){ + int i,poshi; + REALTYPE poslo; + + poshi=oscposhi[nvoice]; + poslo=oscposlo[nvoice]; + REALTYPE *smps=NoteVoicePar[nvoice].OscilSmp; + REALTYPE xm1,x0,x1,x2,a,b,c; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + xm1=smps[poshi]; + x0=smps[poshi+1]; + x1=smps[poshi+2]; + x2=smps[poshi+3]; + a=(3.0 * (x0-x1) - xm1 + x2) / 2.0; + b = 2.0*x1 + xm1 - (5.0*x0 + x2) / 2.0; + c = (x1 - xm1) / 2.0; + tmpwave[i]=(((a * poslo) + b) * poslo + c) * poslo + x0; + printf("a\n"); + //tmpwave[i]=smps[poshi]*(1.0-poslo)+smps[poshi+1]*poslo; + poslo+=oscfreqlo[nvoice]; + if (poslo>=1.0) { + poslo-=1.0; + poshi++; + }; + poshi+=oscfreqhi[nvoice]; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice]=poshi; + oscposlo[nvoice]=poslo; +}; +*/ +/* + * Computes the Oscillator (Morphing) + */ +inline void ADnote::ComputeVoiceOscillatorMorph(int nvoice){ + int i; + REALTYPE amp; + ComputeVoiceOscillator_LinearInterpolation(nvoice); + if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0; + if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0; + + if (NoteVoicePar[nvoice].FMVoice>=0){ + //if I use VoiceOut[] as modullator + int FMVoice=NoteVoicePar[nvoice].FMVoice; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]=tmpwave[i]*(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + } else { + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]=tmpwave[i]*(1.0-amp)+amp + *(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; +}; + +/* + * Computes the Oscillator (Ring Modulation) + */ +inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice){ + int i; + REALTYPE amp; + ComputeVoiceOscillator_LinearInterpolation(nvoice); + if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0; + if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0; + if (NoteVoicePar[nvoice].FMVoice>=0){ + // if I use VoiceOut[] as modullator + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + int FMVoice=NoteVoicePar[nvoice].FMVoice; + for (i=0;i<SOUND_BUFFER_SIZE;i++) + tmpwave[i]*=(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + } else { + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]*=( NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM)*amp + +(1.0-amp); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; +}; + + + +/* + * Computes the Oscillator (Phase Modulation or Frequency Modulation) + */ +inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode){ + int carposhi; + int i,FMmodfreqhi; + REALTYPE FMmodfreqlo,carposlo; + + if (NoteVoicePar[nvoice].FMVoice>=0){ + //if I use VoiceOut[] as modulator + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut[i]; + } else { + //Compute the modulator and store it in tmpwave[] + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]=(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM=fmod(posloFM,1.0); + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; + // Amplitude interpolation + if (ABOVE_AMPLITUDE_THRESHOLD(FMoldamplitude[nvoice],FMnewamplitude[nvoice])){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]*=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + }; + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=FMnewamplitude[nvoice]; + + + //normalize makes all sample-rates, oscil_sizes toproduce same sound + if (FMmode!=0){//Frequency modulation + REALTYPE normalize=OSCIL_SIZE/262144.0*44100.0/(REALTYPE)SAMPLE_RATE; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + FMoldsmp[nvoice]=fmod(FMoldsmp[nvoice]+tmpwave[i]*normalize,OSCIL_SIZE); + tmpwave[i]=FMoldsmp[nvoice]; + }; + } else {//Phase modulation + REALTYPE normalize=OSCIL_SIZE/262144.0; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=normalize; + }; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + F2I(tmpwave[i],FMmodfreqhi); + FMmodfreqlo=fmod(tmpwave[i]+0.0000000001,1.0); + if (FMmodfreqhi<0) FMmodfreqlo++; + + //carrier + carposhi=oscposhi[nvoice]+FMmodfreqhi; + carposlo=oscposlo[nvoice]+FMmodfreqlo; + + if (carposlo>=1.0) { + carposhi++; + carposlo=fmod(carposlo,1.0); + }; + carposhi&=(OSCIL_SIZE-1); + + tmpwave[i]=NoteVoicePar[nvoice].OscilSmp[carposhi]*(1.0-carposlo) + +NoteVoicePar[nvoice].OscilSmp[carposhi+1]*carposlo; + + oscposlo[nvoice]+=oscfreqlo[nvoice]; + if (oscposlo[nvoice]>=1.0) { + oscposlo[nvoice]=fmod(oscposlo[nvoice],1.0); + oscposhi[nvoice]++; + }; + + oscposhi[nvoice]+=oscfreqhi[nvoice]; + oscposhi[nvoice]&=OSCIL_SIZE-1; + }; +}; + + +/*Calculeaza Oscilatorul cu PITCH MODULATION*/ +inline void ADnote::ComputeVoiceOscillatorPitchModulation(int nvoice){ +//TODO +}; + +/* + * Computes the Noise + */ +inline void ADnote::ComputeVoiceNoise(int nvoice){ + for (int i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=RND*2.0-1.0; +}; + + + +/* + * Compute the ADnote samples + * Returns 0 if the note is finished + */ +int ADnote::noteout(REALTYPE *outl,REALTYPE *outr){ + int i,nvoice; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]=denormalkillbuf[i]; + outr[i]=denormalkillbuf[i]; + }; + + if (NoteEnabled==OFF) return(0); + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + bypassl[i]=0.0; + bypassr[i]=0.0; + }; + + computecurrentparameters(); + + for (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 + + // Amplitude + if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude[nvoice],newamplitude[nvoice])){ + int rest=SOUND_BUFFER_SIZE; + //test if the amplitude if raising and the difference is high + if ((newamplitude[nvoice]>oldamplitude[nvoice])&&((newamplitude[nvoice]-oldamplitude[nvoice])>0.25)){ + rest=10; + if (rest>SOUND_BUFFER_SIZE) rest=SOUND_BUFFER_SIZE; + for (int i=0;i<SOUND_BUFFER_SIZE-rest;i++) tmpwave[i]*=oldamplitude[nvoice]; + }; + // Amplitude interpolation + for (i=0;i<rest;i++){ + tmpwave[i+(SOUND_BUFFER_SIZE-rest)]*=INTERPOLATE_AMPLITUDE(oldamplitude[nvoice] + ,newamplitude[nvoice],i,rest); + }; + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=newamplitude[nvoice]; + + // Fade in + if (firsttick[nvoice]!=0){ + fadein(&tmpwave[0]); + firsttick[nvoice]=0; + }; + + + // Filter + if (NoteVoicePar[nvoice].VoiceFilter!=NULL) NoteVoicePar[nvoice].VoiceFilter->filterout(&tmpwave[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 (i=0;i<SOUND_BUFFER_SIZE;i++) + tmpwave[i]*=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + //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) + for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=tmpwave[i]; + + + // Add the voice that do not bypass the filter to out + if (NoteVoicePar[nvoice].filterbypass==0){//no bypass + if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono + else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + outr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + } else {//bypass the filter + if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono + else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + bypassr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + }; + // 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) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//set the right channel=left channel + outr[i]=outl[i]; + bypassr[i]=bypassl[i]; + } + } else NoteGlobalPar.GlobalFilterR->filterout(&outr[0]); + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]+=bypassl[i]; + outr[i]+=bypassr[i]; + }; + + if (ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude,globalnewamplitude)){ + // Amplitude Interpolation + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE tmpvol=INTERPOLATE_AMPLITUDE(globaloldamplitude + ,globalnewamplitude,i,SOUND_BUFFER_SIZE); + outl[i]*=tmpvol*NoteGlobalPar.Panning; + outr[i]*=tmpvol*(1.0-NoteGlobalPar.Panning); + }; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=globalnewamplitude*NoteGlobalPar.Panning; + outr[i]*=globalnewamplitude*(1.0-NoteGlobalPar.Panning); + }; + }; + + //Apply the punch + if (NoteGlobalPar.Punch.Enabled!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE punchamp=NoteGlobalPar.Punch.initialvalue*NoteGlobalPar.Punch.t+1.0; + outl[i]*=punchamp; + outr[i]*=punchamp; + NoteGlobalPar.Punch.t-=NoteGlobalPar.Punch.dt; + if (NoteGlobalPar.Punch.t<0.0) { + NoteGlobalPar.Punch.Enabled=0; + break; + }; + }; + }; + + // Check if the global amplitude is finished. + // If it does, disable the note + if (NoteGlobalPar.AmpEnvelope->finished()!=0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//fade-out + REALTYPE tmp=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + outl[i]*=tmp; + outr[i]*=tmp; + }; + KillNote(); + }; + return(1); +}; + + +/* + * Relase the key (NoteOff) + */ +void ADnote::relasekey(){ +int nvoice; + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled==0) continue; + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) NoteVoicePar[nvoice].AmpEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) NoteVoicePar[nvoice].FreqEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) NoteVoicePar[nvoice].FilterEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) NoteVoicePar[nvoice].FMFreqEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) NoteVoicePar[nvoice].FMAmpEnvelope->relasekey(); + }; + NoteGlobalPar.FreqEnvelope->relasekey(); + NoteGlobalPar.FilterEnvelope->relasekey(); + NoteGlobalPar.AmpEnvelope->relasekey(); + +}; + +/* + * Check if the note is finished + */ +int ADnote::finished(){ + if (NoteEnabled==ON) return(0); + else return(1); +}; + + + |