diff options
| author | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 | 
|---|---|---|
| committer | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 | 
| commit | e40fc849149dd97c248866a4a1d026dda5e57b62 (patch) | |
| tree | b12b358f3b3a0608001d30403358f8443118ec5f /attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C | |
| parent | 1bd4f2e8d9745cabb667b043171cad22c8577768 (diff) | |
clean3
Diffstat (limited to 'attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C')
| -rw-r--r-- | attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C | 342 | 
1 files changed, 342 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C new file mode 100644 index 00000000..9ecc8877 --- /dev/null +++ b/attic/muse_qt4_evolution/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(); +}; +  | 
