/* ZynAddSubFX - a software synthesizer Envelope.C - Envelope implementation 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 #include "Envelope.h" Envelope::Envelope(EnvelopeParams *envpars,REALTYPE basefreq){ int i; envpoints=envpars->Penvpoints; if (envpoints>MAX_ENVELOPE_POINTS) envpoints=MAX_ENVELOPE_POINTS; envsustain=(envpars->Penvsustain==0)?-1:envpars->Penvsustain; forcedrelase=envpars->Pforcedrelease; envstretch=pow(440.0/basefreq,envpars->Penvstretch/64.0); linearenvelope=envpars->Plinearenvelope; if (envpars->Pfreemode==0) envpars->converttofree(); REALTYPE bufferdt=SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; int mode=envpars->Envmode; //for amplitude envelopes if ((mode==1)&&(linearenvelope==0)) mode=2;//change to log envelope if ((mode==2)&&(linearenvelope!=0)) mode=1;//change to linear for (i=0;igetdt(i)/1000.0*envstretch; if (tmp>bufferdt) envdt[i]=bufferdt/tmp; else envdt[i]=2.0;//any value larger than 1 switch (mode){ case 2:envval[i]=(1.0-envpars->Penvval[i]/127.0)*MIN_ENVELOPE_DB; break; case 3:envval[i]=(pow(2,6.0*fabs(envpars->Penvval[i]-64.0)/64.0)-1.0)*100.0; if (envpars->Penvval[i]<64) envval[i]=-envval[i]; break; case 4:envval[i]=(envpars->Penvval[i]-64.0)/64.0*6.0;//6 octaves (filtru) break; case 5:envval[i]=(envpars->Penvval[i]-64.0)/64.0*10; break; default:envval[i]=envpars->Penvval[i]/127.0; }; }; envdt[0]=1.0; currentpoint=1;//the envelope starts from 1 keyreleased=0; t=0.0; envfinish=0; inct=envdt[1]; envoutval=0.0; }; Envelope::~Envelope(){ }; /* * Relase the key (note envelope) */ void Envelope::relasekey(){ if (keyreleased==1) return; keyreleased=1; if (forcedrelase!=0) t=0.0; }; /* * Envelope Output */ REALTYPE Envelope::envout(){ REALTYPE out; if (envfinish!=0) {//if the envelope is finished envoutval=envval[envpoints-1]; return(envoutval); }; if ((currentpoint==envsustain+1)&&(keyreleased==0)) {//if it is sustaining now envoutval=envval[envsustain]; return(envoutval); }; if ((keyreleased!=0) && (forcedrelase!=0)){//do the forced release int tmp=(envsustain<0) ? (envpoints-1):(envsustain+1);//if there is no sustain point, use the last point for release if (envdt[tmp]<0.00000001) out=envval[tmp]; else out=envoutval+(envval[tmp]-envoutval)*t; t+=envdt[tmp]*envstretch; if (t>=1.0) { currentpoint=envsustain+2; forcedrelase=0; t=0.0; inct=envdt[currentpoint]; if ((currentpoint>=envpoints)||(envsustain<0)) envfinish=1; }; return(out); }; if (inct>=1.0) out=envval[currentpoint]; else out=envval[currentpoint-1]+(envval[currentpoint]-envval[currentpoint-1])*t; t+=inct; if (t>=1.0){ if (currentpoint>=envpoints-1) envfinish=1; else currentpoint++; t=0.0; inct=envdt[currentpoint]; }; envoutval=out; return (out); }; /* * Envelope Output (dB) */ REALTYPE Envelope::envout_dB(){ REALTYPE out; if (linearenvelope!=0) return (envout()); if ((currentpoint==1)&&((keyreleased==0)||(forcedrelase==0))) {//first point is always lineary interpolated REALTYPE v1=dB2rap(envval[0]); REALTYPE v2=dB2rap(envval[1]); out=v1+(v2-v1)*t; t+=inct; if (t>=1.0) { t=0.0; inct=envdt[2]; currentpoint++; out=v2; }; if (out>0.001) envoutval=rap2dB(out); else envoutval=-40.0; } else out=dB2rap(envout()); return(out); }; int Envelope::finished(){ return(envfinish); };