diff options
Diffstat (limited to 'muse/synti/zynaddsubfx/Synth/PADnote.C')
-rw-r--r-- | muse/synti/zynaddsubfx/Synth/PADnote.C | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/muse/synti/zynaddsubfx/Synth/PADnote.C b/muse/synti/zynaddsubfx/Synth/PADnote.C new file mode 100644 index 00000000..9ecc8877 --- /dev/null +++ b/muse/synti/zynaddsubfx/Synth/PADnote.C @@ -0,0 +1,342 @@ +/* + ZynAddSubFX - a software synthesizer + + PADnote.C - The "pad" 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 "PADnote.h" +#include "../Misc/Config.h" + +PADnote::PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote){ + ready=0; + pars=parameters; + portamento=portamento_; + ctl=ctl_; + this->velocity=velocity; + finished_=false; + + + if (pars->Pfixedfreq==0) basefreq=freq; + else { + basefreq=440.0; + int fixedfreqET=pars->PfixedfreqET; + 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) basefreq*=pow(2.0,tmp); + else basefreq*=pow(3.0,tmp); + }; + + }; + + firsttime=true; + released=false; + realfreq=basefreq; + NoteGlobalPar.Detune=getdetune(pars->PDetuneType + ,pars->PCoarseDetune,pars->PDetune); + + + //find out the closest note + REALTYPE logfreq=log(basefreq*pow(2.0,NoteGlobalPar.Detune/1200.0)); + REALTYPE mindist=fabs(logfreq-log(pars->sample[0].basefreq+0.0001)); + nsample=0; + for (int i=1;i<PAD_MAX_SAMPLES;i++){ + if (pars->sample[i].smp==NULL) break; + REALTYPE dist=fabs(logfreq-log(pars->sample[i].basefreq+0.0001)); +// printf("(mindist=%g) %i %g %g\n",mindist,i,dist,pars->sample[i].basefreq); + + if (dist<mindist){ + nsample=i; + mindist=dist; + }; + }; + + int size=pars->sample[nsample].size; + if (size==0) size=1; + + + poshi_l=(int)(RND*(size-1)); + if (pars->PStereo!=0) poshi_r=(poshi_l+size/2)%size; + else poshi_r=poshi_l; + poslo=0.0; + + tmpwave=new REALTYPE [SOUND_BUFFER_SIZE]; + + + + if (pars->PPanning==0) NoteGlobalPar.Panning=RND; + else NoteGlobalPar.Panning=pars->PPanning/128.0; + + NoteGlobalPar.FilterCenterPitch=pars->GlobalFilter->getfreq()+//center freq + pars->PFilterVelocityScale/127.0*6.0* //velocity sensing + (VelF(velocity,pars->PFilterVelocityScaleFunction)-1); + + if (pars->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->PPunchStrength/127.0)-1.0) + *VelF(velocity,pars->PPunchVelocitySensing) ); + REALTYPE time=pow(10,3.0*pars->PPunchTime/127.0)/10000.0;//0.1 .. 100 ms + REALTYPE stretch=pow(440.0/freq,pars->PPunchStretch/64.0); + NoteGlobalPar.Punch.dt=1.0/(time*SAMPLE_RATE*stretch); + } else NoteGlobalPar.Punch.Enabled=0; + + + + NoteGlobalPar.FreqEnvelope=new Envelope(pars->FreqEnvelope,basefreq); + NoteGlobalPar.FreqLfo=new LFO(pars->FreqLfo,basefreq); + + NoteGlobalPar.AmpEnvelope=new Envelope(pars->AmpEnvelope,basefreq); + NoteGlobalPar.AmpLfo=new LFO(pars->AmpLfo,basefreq); + + NoteGlobalPar.Volume=4.0*pow(0.1,3.0*(1.0-pars->PVolume/96.0))//-60 dB .. 0 dB + *VelF(velocity,pars->PAmpVelocityScaleFunction);//velocity sensing + + NoteGlobalPar.AmpEnvelope->envout_dB();//discard the first envelope output + globaloldamplitude=globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout(); + + NoteGlobalPar.GlobalFilterL=new Filter(pars->GlobalFilter); + NoteGlobalPar.GlobalFilterR=new Filter(pars->GlobalFilter); + + NoteGlobalPar.FilterEnvelope=new Envelope(pars->FilterEnvelope,basefreq); + NoteGlobalPar.FilterLfo=new LFO(pars->FilterLfo,basefreq); + NoteGlobalPar.FilterQ=pars->GlobalFilter->getq(); + NoteGlobalPar.FilterFreqTracking=pars->GlobalFilter->getfreqtracking(basefreq); + + ready=1;///sa il pun pe asta doar cand e chiar gata + + if (parameters->sample[nsample].smp==NULL){ + finished_=true; + return; + }; +}; + +PADnote::~PADnote(){ + delete (NoteGlobalPar.FreqEnvelope); + delete (NoteGlobalPar.FreqLfo); + delete (NoteGlobalPar.AmpEnvelope); + delete (NoteGlobalPar.AmpLfo); + delete (NoteGlobalPar.GlobalFilterL); + delete (NoteGlobalPar.GlobalFilterR); + delete (NoteGlobalPar.FilterEnvelope); + delete (NoteGlobalPar.FilterLfo); + delete (tmpwave); +}; + + +inline void PADnote::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; + }; +}; + + +void PADnote::computecurrentparameters(){ + REALTYPE globalpitch,globalfilterpitch; + globalpitch=0.01*(NoteGlobalPar.FreqEnvelope->envout()+ + NoteGlobalPar.FreqLfo->lfoout()*ctl->modwheel.relmod+NoteGlobalPar.Detune); + 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); + 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" + }; + }; + + realfreq=basefreq*portamentofreqrap*pow(2.0,globalpitch/12.0)*ctl->pitchwheel.relfreq; +}; + + +int PADnote::Compute_Linear(REALTYPE *outl,REALTYPE *outr,int freqhi,REALTYPE freqlo){ + REALTYPE *smps=pars->sample[nsample].smp; + if (smps==NULL){ + finished_=true; + return(1); + }; + int size=pars->sample[nsample].size; + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + poshi_l+=freqhi; + poshi_r+=freqhi; + poslo+=freqlo; + if (poslo>=1.0){ + poshi_l+=1; + poshi_r+=1; + poslo-=1.0; + }; + if (poshi_l>=size) poshi_l%=size; + if (poshi_r>=size) poshi_r%=size; + + outl[i]=smps[poshi_l]*(1.0-poslo)+smps[poshi_l+1]*poslo; + outr[i]=smps[poshi_r]*(1.0-poslo)+smps[poshi_r+1]*poslo; + }; + return(1); +}; +int PADnote::Compute_Cubic(REALTYPE *outl,REALTYPE *outr,int freqhi,REALTYPE freqlo){ + REALTYPE *smps=pars->sample[nsample].smp; + if (smps==NULL){ + finished_=true; + return(1); + }; + int size=pars->sample[nsample].size; + REALTYPE xm1,x0,x1,x2,a,b,c; + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + poshi_l+=freqhi; + poshi_r+=freqhi; + poslo+=freqlo; + if (poslo>=1.0){ + poshi_l+=1; + poshi_r+=1; + poslo-=1.0; + }; + if (poshi_l>=size) poshi_l%=size; + if (poshi_r>=size) poshi_r%=size; + + + //left + xm1=smps[poshi_l]; + x0=smps[poshi_l + 1]; + x1=smps[poshi_l + 2]; + x2=smps[poshi_l + 3]; + a = (3.0 * (x0-x1) - xm1 + x2)*0.5; + b = 2.0*x1 + xm1 - (5.0*x0 + x2)*0.5; + c = (x1 - xm1)*0.5; + outl[i] = (((a * poslo) + b) * poslo + c) * poslo + x0; + //right + xm1=smps[poshi_r]; + x0=smps[poshi_r + 1]; + x1=smps[poshi_r + 2]; + x2=smps[poshi_r + 3]; + a = (3.0 * (x0-x1) - xm1 + x2)*0.5; + b = 2.0*x1 + xm1 - (5.0*x0 + x2)*0.5; + c = (x1 - xm1)*0.5; + outr[i] = (((a * poslo) + b) * poslo + c) * poslo + x0; + }; + return(1); +}; + + +int PADnote::noteout(REALTYPE *outl,REALTYPE *outr){ + computecurrentparameters(); + REALTYPE *smps=pars->sample[nsample].smp; + if (smps==NULL){ + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + outl[i]=0.0; + outr[i]=0.0; + }; + return(1); + }; + REALTYPE smpfreq=pars->sample[nsample].basefreq; + + + REALTYPE freqrap=realfreq/smpfreq; + int freqhi=(int) (floor(freqrap)); + REALTYPE freqlo=freqrap-floor(freqrap); + + + if (config.cfg.Interpolation) Compute_Cubic(outl,outr,freqhi,freqlo); + else Compute_Linear(outl,outr,freqhi,freqlo); + + + if (firsttime){ + fadein(outl); + fadein(outr); + firsttime=false; + }; + + NoteGlobalPar.GlobalFilterL->filterout(outl); + NoteGlobalPar.GlobalFilterR->filterout(outr); + + //Apply the punch + if (NoteGlobalPar.Punch.Enabled!=0){ + for (int 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; + }; + }; + }; + + if (ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude,globalnewamplitude)){ + // Amplitude Interpolation + for (int 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 (int i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=globalnewamplitude*NoteGlobalPar.Panning; + outr[i]*=globalnewamplitude*(1.0-NoteGlobalPar.Panning); + }; + }; + + + // Check if the global amplitude is finished. + // If it does, disable the note + if (NoteGlobalPar.AmpEnvelope->finished()!=0) { + for (int 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; + }; + finished_=1; + }; + + return(1); +}; + +int PADnote::finished(){ + return(finished_); +}; + +void PADnote::relasekey(){ + NoteGlobalPar.FreqEnvelope->relasekey(); + NoteGlobalPar.FilterEnvelope->relasekey(); + NoteGlobalPar.AmpEnvelope->relasekey(); +}; + |