diff options
Diffstat (limited to 'muse_qt4_evolution/synti/zynaddsubfx/Synth')
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C | 984 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.h | 258 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.C | 165 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.h | 58 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.C | 145 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.h | 52 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.C | 1182 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.h | 176 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C | 342 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.h | 106 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.C | 231 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.h | 68 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.C | 419 | ||||
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.h | 98 |
14 files changed, 4284 insertions, 0 deletions
diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.C new file mode 100644 index 00000000..574e2bea --- /dev/null +++ b/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); +}; + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.h new file mode 100644 index 00000000..28c18975 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/ADnote.h @@ -0,0 +1,258 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnote.h - 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 + +*/ + +#ifndef AD_NOTE_H +#define AD_NOTE_H + +#include "../globals.h" +#include "Envelope.h" +#include "LFO.h" +#include "../DSP/Filter.h" +#include "../Params/ADnoteParameters.h" +#include "../Params/Controller.h" + +//Globals + +//FM amplitude tune +#define FM_AMP_MULTIPLIER 14.71280603 + +#define OSCIL_SMP_EXTRA_SAMPLES 5 + +class ADnote{ //ADDitive note + public: + ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_); + ~ADnote(); + int noteout(REALTYPE *outl,REALTYPE *outr); + void relasekey(); + int finished(); + + + /*ready - this is 0 if it is not ready (the parameters has to be computed) + or other value if the parameters has been computed and if it is ready to output*/ + char ready; + + private: + + void setfreq(int nvoice,REALTYPE freq); + void setfreqFM(int nvoice,REALTYPE freq); + void computecurrentparameters(); + void initparameters(); + void KillVoice(int nvoice); + void KillNote(); + inline REALTYPE getvoicebasefreq(int nvoice); + inline REALTYPE getFMvoicebasefreq(int nvoice); + inline void ComputeVoiceOscillator_LinearInterpolation(int nvoice); + inline void ComputeVoiceOscillator_CubicInterpolation(int nvoice); + inline void ComputeVoiceOscillatorMorph(int nvoice); + inline void ComputeVoiceOscillatorRingModulation(int nvoice); + inline void ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode);//FMmode=0 for phase modulation, 1 for Frequency modulation +// inline void ComputeVoiceOscillatorFrequencyModulation(int nvoice); + inline void ComputeVoiceOscillatorPitchModulation(int nvoice); + + inline void ComputeVoiceNoise(int nvoice); + + inline void fadein(REALTYPE *smps); + + + //GLOBALS + ADnoteParameters *partparams; + unsigned char stereo;//if the note is stereo (allows note Panning) + int midinote; + REALTYPE velocity,basefreq; + + ONOFFTYPE NoteEnabled; + Controller *ctl; + + /*****************************************************************/ + /* GLOBAL PARAMETERS */ + /*****************************************************************/ + + struct ADnoteGlobal{ + /****************************************** + * FREQUENCY GLOBAL PARAMETERS * + ******************************************/ + REALTYPE Detune;//cents + + Envelope *FreqEnvelope; + LFO *FreqLfo; + + /******************************************** + * AMPLITUDE GLOBAL PARAMETERS * + ********************************************/ + REALTYPE Volume;// [ 0 .. 1 ] + + REALTYPE Panning;// [ 0 .. 1 ] + + Envelope *AmpEnvelope; + LFO *AmpLfo; + + struct { + int Enabled; + REALTYPE initialvalue,dt,t; + } Punch; + + /****************************************** + * FILTER GLOBAL PARAMETERS * + ******************************************/ + Filter *GlobalFilterL,*GlobalFilterR; + + REALTYPE FilterCenterPitch;//octaves + REALTYPE FilterQ; + REALTYPE FilterFreqTracking; + + Envelope *FilterEnvelope; + + LFO *FilterLfo; + } NoteGlobalPar; + + + + /***********************************************************/ + /* VOICE PARAMETERS */ + /***********************************************************/ + struct ADnoteVoice{ + /* If the voice is enabled */ + ONOFFTYPE Enabled; + + /* Voice Type (sound/noise)*/ + int noisetype; + + /* Filter Bypass */ + int filterbypass; + + /* Delay (ticks) */ + int DelayTicks; + + /* Waveform of the Voice */ + REALTYPE *OscilSmp; + + /************************************ + * FREQUENCY PARAMETERS * + ************************************/ + int fixedfreq;//if the frequency is fixed to 440 Hz + int fixedfreqET;//if the "fixed" frequency varies according to the note (ET) + + // cents = basefreq*VoiceDetune + REALTYPE Detune,FineDetune; + + Envelope *FreqEnvelope; + LFO *FreqLfo; + + + /*************************** + * AMPLITUDE PARAMETERS * + ***************************/ + + /* Panning 0.0=left, 0.5 - center, 1.0 = right */ + REALTYPE Panning; + REALTYPE Volume;// [-1.0 .. 1.0] + + Envelope *AmpEnvelope; + LFO *AmpLfo; + + /************************* + * FILTER PARAMETERS * + *************************/ + + Filter *VoiceFilter; + + REALTYPE FilterCenterPitch;/* Filter center Pitch*/ + REALTYPE FilterFreqTracking; + + Envelope *FilterEnvelope; + LFO *FilterLfo; + + + /**************************** + * MODULLATOR PARAMETERS * + ****************************/ + + FMTYPE FMEnabled; + + int FMVoice; + + // Voice Output used by other voices if use this as modullator + REALTYPE *VoiceOut; + + /* Wave of the Voice */ + REALTYPE *FMSmp; + + REALTYPE FMVolume; + REALTYPE FMDetune; //in cents + + Envelope *FMFreqEnvelope; + Envelope *FMAmpEnvelope; + } NoteVoicePar[NUM_VOICES]; + + + /********************************************************/ + /* INTERNAL VALUES OF THE NOTE AND OF THE VOICES */ + /********************************************************/ + + //time from the start of the note + REALTYPE time; + + //fractional part (skip) + REALTYPE oscposlo[NUM_VOICES],oscfreqlo[NUM_VOICES]; + + //integer part (skip) + int oscposhi[NUM_VOICES],oscfreqhi[NUM_VOICES]; + + //fractional part (skip) of the Modullator + REALTYPE oscposloFM[NUM_VOICES],oscfreqloFM[NUM_VOICES]; + + //integer part (skip) of the Modullator + unsigned short int oscposhiFM[NUM_VOICES],oscfreqhiFM[NUM_VOICES]; + + //used to compute and interpolate the amplitudes of voices and modullators + REALTYPE oldamplitude[NUM_VOICES], + newamplitude[NUM_VOICES], + FMoldamplitude[NUM_VOICES], + FMnewamplitude[NUM_VOICES]; + + //used by Frequency Modulation (for integration) + REALTYPE FMoldsmp[NUM_VOICES]; + + //temporary buffer + REALTYPE *tmpwave; + + //Filter bypass samples + REALTYPE *bypassl,*bypassr; + + //interpolate the amplitudes + REALTYPE globaloldamplitude,globalnewamplitude; + + //1 - if it is the fitst tick (used to fade in the sound) + char firsttick[NUM_VOICES]; + + //1 if the note has portamento + int portamento; + + //how the fine detunes are made bigger or smaller + REALTYPE bandwidthDetuneMultiplier; +}; + +#endif + + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.C new file mode 100644 index 00000000..a0194022 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.C @@ -0,0 +1,165 @@ +/* + 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 <stdio.h> +#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;i<MAX_ENVELOPE_POINTS;i++) { + REALTYPE tmp=envpars->getdt(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); +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.h new file mode 100644 index 00000000..d78eb16d --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Envelope.h @@ -0,0 +1,58 @@ +/* + ZynAddSubFX - a software synthesizer + + Envelope.h - 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 + +*/ + +#ifndef ENVELOPE_H +#define ENVELOPE_H + +#include <math.h> +#include "../globals.h" +#include "../Params/EnvelopeParams.h" + +class Envelope{ +public: + Envelope(EnvelopeParams *envpars,REALTYPE basefreq); + ~Envelope(); + void relasekey(); + REALTYPE envout(); + REALTYPE envout_dB(); + int finished();//returns 1 if the envelope is finished +private: + int envpoints; + int envsustain;//"-1" means disabled + REALTYPE envdt[MAX_ENVELOPE_POINTS];//millisecons + REALTYPE envval[MAX_ENVELOPE_POINTS];// [0.0 .. 1.0] + REALTYPE envstretch; + int linearenvelope; + + int currentpoint; //current envelope point (starts from 1) + int forcedrelase; + char keyreleased; //if the key was released + char envfinish; + REALTYPE t; // the time from the last point + REALTYPE inct;// the time increment + REALTYPE envoutval;//used to do the forced release +}; + + +#endif + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.C new file mode 100644 index 00000000..4ae548c1 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.C @@ -0,0 +1,145 @@ +/* + ZynAddSubFX - a software synthesizer + + LFO.C - LFO 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 <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "LFO.h" + + +LFO::LFO(LFOParams *lfopars,REALTYPE basefreq){ + if (lfopars->Pstretch==0) lfopars->Pstretch=1; + REALTYPE lfostretch=pow(basefreq/440.0,(lfopars->Pstretch-64.0)/63.0);//max 2x/octave + + REALTYPE lfofreq=(pow(2,lfopars->Pfreq*10.0)-1.0)/12.0*lfostretch; + incx=fabs(lfofreq)*(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + + if (lfopars->Pcontinous==0){ + if (lfopars->Pstartphase==0) x=RND; + else x=fmod((lfopars->Pstartphase-64.0)/127.0+1.0,1.0); + } else { + REALTYPE tmp=fmod(lfopars->time*incx,1.0); + x=fmod((lfopars->Pstartphase-64.0)/127.0+1.0+tmp,1.0); + }; + + //Limit the Frequency(or else...) + if (incx>0.49999999) incx=0.499999999; + + + lfornd=lfopars->Prandomness/127.0; + if (lfornd<0.0) lfornd=0.0; else if (lfornd>1.0) lfornd=1.0; + +// lfofreqrnd=pow(lfopars->Pfreqrand/127.0,2.0)*2.0*4.0; + lfofreqrnd=pow(lfopars->Pfreqrand/127.0,2.0)*4.0; + + switch (lfopars->fel){ + case 1:lfointensity=lfopars->Pintensity/127.0;break; + case 2:lfointensity=lfopars->Pintensity/127.0*4.0;break;//in octave + default:lfointensity=pow(2,lfopars->Pintensity/127.0*11.0)-1.0;//in centi + x-=0.25;//chance the starting phase + break; + }; + + amp1=(1-lfornd)+lfornd*RND; + amp2=(1-lfornd)+lfornd*RND; + lfotype=lfopars->PLFOtype; + lfodelay=lfopars->Pdelay/127.0*4.0;//0..4 sec + incrnd=nextincrnd=1.0; + freqrndenabled=(lfopars->Pfreqrand!=0); + computenextincrnd(); + computenextincrnd();//twice because I want incrnd & nextincrnd to be random +}; + +LFO::~LFO(){ +}; + +/* + * LFO out + */ +REALTYPE LFO::lfoout(){ + REALTYPE out; + switch (lfotype){ + case 1: //LFO_TRIANGLE + if ((x>=0.0)&&(x<0.25)) out=4.0*x; + else if ((x>0.25)&&(x<0.75)) out=2-4*x; + else out=4.0*x-4.0; + break; + case 2: //LFO_SQUARE + if (x<0.5) out=-1; + else out=1; + break; + case 3: //LFO_RAMPUP + out=(x-0.5)*2.0; + break; + case 4: //LFO_RAMPDOWN + out=(0.5-x)*2.0; + break; + case 5: //LFO_EXP_DOWN 1 + out=pow(0.05,x)*2.0-1.0; + break; + case 6: //LFO_EXP_DOWN 2 + out=pow(0.001,x)*2.0-1.0; + break; + default:out=cos(x*2.0*PI);//LFO_SINE + }; + + + if ((lfotype==0)||(lfotype==1)) out*=lfointensity*(amp1+x*(amp2-amp1)); + else out*=lfointensity*amp2; + if (lfodelay<0.00001) { + if (freqrndenabled==0) x+=incx; + else { + float tmp=(incrnd*(1.0-x)+nextincrnd*x); + if (tmp>1.0) tmp=1.0; + else if (tmp<0.0) tmp=0.0; + x+=incx*tmp; + }; + if (x>=1) { + x=fmod(x,1.0); + amp1=amp2; + amp2=(1-lfornd)+lfornd*RND; + + computenextincrnd(); + }; + } else lfodelay-=(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + return(out); +}; + +/* + * LFO out (for amplitude) + */ +REALTYPE LFO::amplfoout(){ + REALTYPE out; + out=1.0-lfointensity+lfoout(); + if (out<-1.0) out=-1.0; + else if (out>1.0) out=1.0; + return(out); +}; + + +void LFO::computenextincrnd(){ + if (freqrndenabled==0) return; + incrnd=nextincrnd; + nextincrnd=pow(0.5,lfofreqrnd)+RND*(pow(2.0,lfofreqrnd)-1.0); +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.h new file mode 100644 index 00000000..30d04f10 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/LFO.h @@ -0,0 +1,52 @@ +/* + ZynAddSubFX - a software synthesizer + + LFO.h - LFO 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 + +*/ + +#ifndef LFO_H +#define LFO_H + +#include "../globals.h" +#include "../Params/LFOParams.h" + + +class LFO{ + public: + LFO(LFOParams *lfopars, REALTYPE basefreq); + ~LFO(); + REALTYPE lfoout(); + REALTYPE amplfoout(); + private: + REALTYPE x; + REALTYPE incx,incrnd,nextincrnd; + REALTYPE amp1,amp2;// used for randomness + REALTYPE lfointensity; + REALTYPE lfornd,lfofreqrnd; + REALTYPE lfodelay; + char lfotype; + int freqrndenabled; + + + void computenextincrnd(); + +}; + + +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.C new file mode 100644 index 00000000..4e6a4dd3 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.C @@ -0,0 +1,1182 @@ +/* + ZynAddSubFX - a software synthesizer + + OscilGen.C - Waveform generator for ADnote + 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 <stdlib.h> +#include <math.h> +#include <stdio.h> + +#include "OscilGen.h" +#include "../Effects/Distorsion.h" + +REALTYPE *OscilGen::tmpsmps;//this array stores some termporary data and it has SOUND_BUFFER_SIZE elements +FFTFREQS OscilGen::outoscilFFTfreqs; + + +OscilGen::OscilGen(FFTwrapper *fft_,Resonance *res_):Presets(){ + setpresettype("Poscilgen"); + fft=fft_; + res=res_; + newFFTFREQS(&oscilFFTfreqs,OSCIL_SIZE/2); + newFFTFREQS(&basefuncFFTfreqs,OSCIL_SIZE/2); + + randseed=1; + ADvsPAD=false; + + defaults(); +}; + +OscilGen::~OscilGen(){ + deleteFFTFREQS(&basefuncFFTfreqs); + deleteFFTFREQS(&oscilFFTfreqs); +}; + + +void OscilGen::defaults(){ + + oldbasefunc=0;oldbasepar=64;oldhmagtype=0;oldwaveshapingfunction=0;oldwaveshaping=64; + oldbasefuncmodulation=0;oldharmonicshift=0;oldbasefuncmodulationpar1=0;oldbasefuncmodulationpar2=0;oldbasefuncmodulationpar3=0; + oldmodulation=0;oldmodulationpar1=0;oldmodulationpar2=0;oldmodulationpar3=0; + + for (int i=0;i<MAX_AD_HARMONICS;i++){ + hmag[i]=0.0; + hphase[i]=0.0; + Phmag[i]=64; + Phphase[i]=64; + }; + Phmag[0]=127; + Phmagtype=0; + if (ADvsPAD) Prand=127;//max phase randomness (usefull if the oscil will be imported to a ADsynth from a PADsynth + else Prand=64;//no randomness + + Pcurrentbasefunc=0; + Pbasefuncpar=64; + + Pbasefuncmodulation=0; + Pbasefuncmodulationpar1=64; + Pbasefuncmodulationpar2=64; + Pbasefuncmodulationpar3=32; + + Pmodulation=0; + Pmodulationpar1=64; + Pmodulationpar2=64; + Pmodulationpar3=32; + + Pwaveshapingfunction=0; + Pwaveshaping=64; + Pfiltertype=0; + Pfilterpar1=64; + Pfilterpar2=64; + Pfilterbeforews=0; + Psatype=0; + Psapar=64; + + Pamprandpower=64; + Pamprandtype=0; + + Pharmonicshift=0; + Pharmonicshiftfirst=0; + + Padaptiveharmonics=0; + Padaptiveharmonicspower=100; + Padaptiveharmonicsbasefreq=128; + Padaptiveharmonicspar=50; + + for (int i=0;i<OSCIL_SIZE/2;i++) { + oscilFFTfreqs.s[i]=0.0; + oscilFFTfreqs.c[i]=0.0; + basefuncFFTfreqs.s[i]=0.0; + basefuncFFTfreqs.c[i]=0.0; + }; + oscilprepared=0; + oldfilterpars=0;oldsapars=0; + prepare(); +}; + +void OscilGen::convert2sine(int magtype){ + REALTYPE mag[MAX_AD_HARMONICS],phase[MAX_AD_HARMONICS]; + REALTYPE oscil[OSCIL_SIZE]; + FFTFREQS freqs; + newFFTFREQS(&freqs,OSCIL_SIZE/2); + + get(oscil,-1.0); + FFTwrapper *fft=new FFTwrapper(OSCIL_SIZE); + fft->smps2freqs(oscil,freqs); + delete(fft); + + REALTYPE max=0.0; + + mag[0]=0; + phase[0]=0; + for (int i=0;i<MAX_AD_HARMONICS;i++){ + mag[i]=sqrt(pow(freqs.s[i+1],2)+pow(freqs.c[i+1],2.0)); + phase[i]=atan2(freqs.c[i+1],freqs.s[i+1]); + if (max<mag[i]) max=mag[i]; + }; + if (max<0.00001) max=1.0; + + defaults(); + + for (int i=0;i<MAX_AD_HARMONICS-1;i++){ + REALTYPE newmag=mag[i]/max; + REALTYPE newphase=phase[i]; + + Phmag[i]=(int) ((newmag)*64.0)+64; + + Phphase[i]=64-(int) (64.0*newphase/PI); + if (Phphase[i]>127) Phphase[i]=127; + + if (Phmag[i]==64) Phphase[i]=64; + }; + deleteFFTFREQS(&freqs); + prepare(); +}; + +/* + * Base Functions - START + */ +REALTYPE OscilGen::basefunc_pulse(REALTYPE x,REALTYPE a){ + return((fmod(x,1.0)<a)?-1.0:1.0); +}; + +REALTYPE OscilGen::basefunc_saw(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + x=fmod(x,1); + if (x<a) return(x/a*2.0-1.0); + else return((1.0-x)/(1.0-a)*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_triangle(REALTYPE x,REALTYPE a){ + x=fmod(x+0.25,1); + a=1-a; + if (a<0.00001) a=0.00001; + if (x<0.5) x=x*4-1.0; + else x=(1.0-x)*4-1.0; + x/=-a; + if (x<-1.0) x=-1.0; + if (x>1.0) x=1.0; + return(x); +}; + +REALTYPE OscilGen::basefunc_power(REALTYPE x,REALTYPE a){ + x=fmod(x,1); + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + return(pow(x,exp((a-0.5)*10.0))*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_gauss(REALTYPE x,REALTYPE a){ + x=fmod(x,1)*2.0-1.0; + if (a<0.00001) a=0.00001; + return(exp(-x*x*(exp(a*8)+5.0))*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_diode(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + a=a*2.0-1.0; + x=cos((x+0.5)*2.0*PI)-a; + if (x<0.0) x=0.0; + return(x/(1.0-a)*2-1.0); +}; + +REALTYPE OscilGen::basefunc_abssine(REALTYPE x,REALTYPE a){ + x=fmod(x,1); + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + return(sin(pow(x,exp((a-0.5)*5.0))*PI)*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_pulsesine(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + x=(fmod(x,1)-0.5)*exp((a-0.5)*log(128)); + if (x<-0.5) x=-0.5; + else if (x>0.5) x=0.5; + x=sin(x*PI*2.0); + return(x); +}; + +REALTYPE OscilGen::basefunc_stretchsine(REALTYPE x,REALTYPE a){ + x=fmod(x+0.5,1)*2.0-1.0; + a=(a-0.5)*4;if (a>0.0) a*=2; + a=pow(3.0,a); + REALTYPE b=pow(fabs(x),a); + if (x<0) b=-b; + return(-sin(b*PI)); +}; + +REALTYPE OscilGen::basefunc_chirp(REALTYPE x,REALTYPE a){ + x=fmod(x,1.0)*2.0*PI; + a=(a-0.5)*4;if (a<0.0) a*=2.0; + a=pow(3.0,a); + return(sin(x/2.0)*sin(a*x*x)); +}; + +REALTYPE OscilGen::basefunc_absstretchsine(REALTYPE x,REALTYPE a){ + x=fmod(x+0.5,1)*2.0-1.0; + a=(a-0.5)*9; + a=pow(3.0,a); + REALTYPE b=pow(fabs(x),a); + if (x<0) b=-b; + return(-pow(sin(b*PI),2)); +}; + +REALTYPE OscilGen::basefunc_chebyshev(REALTYPE x,REALTYPE a){ + a=a*a*a*30.0+1.0; + return(cos(acos(x*2.0-1.0)*a)); +}; + +REALTYPE OscilGen::basefunc_sqr(REALTYPE x,REALTYPE a){ + a=a*a*a*a*160.0+0.001; + return(-atan(sin(x*2.0*PI)*a)); +}; +/* + * Base Functions - END + */ + + +/* + * Get the base function + */ +void OscilGen::getbasefunction(REALTYPE *smps){ + int i; + REALTYPE par=(Pbasefuncpar+0.5)/128.0; + if (Pbasefuncpar==64) par=0.5; + + REALTYPE basefuncmodulationpar1=Pbasefuncmodulationpar1/127.0, + basefuncmodulationpar2=Pbasefuncmodulationpar2/127.0, + basefuncmodulationpar3=Pbasefuncmodulationpar3/127.0; + + switch(Pbasefuncmodulation){ + case 1:basefuncmodulationpar1=(pow(2,basefuncmodulationpar1*5.0)-1.0)/10.0; + basefuncmodulationpar3=floor((pow(2,basefuncmodulationpar3*5.0)-1.0)); + if (basefuncmodulationpar3<0.9999) basefuncmodulationpar3=-1.0; + break; + case 2:basefuncmodulationpar1=(pow(2,basefuncmodulationpar1*5.0)-1.0)/10.0; + basefuncmodulationpar3=1.0+floor((pow(2,basefuncmodulationpar3*5.0)-1.0)); + break; + case 3:basefuncmodulationpar1=(pow(2,basefuncmodulationpar1*7.0)-1.0)/10.0; + basefuncmodulationpar3=0.01+(pow(2,basefuncmodulationpar3*16.0)-1.0)/10.0; + break; + }; + +// printf("%.5f %.5f\n",basefuncmodulationpar1,basefuncmodulationpar3); + + for (i=0;i<OSCIL_SIZE;i++) { + REALTYPE t=i*1.0/OSCIL_SIZE; + + switch(Pbasefuncmodulation){ + case 1:t=t*basefuncmodulationpar3+sin((t+basefuncmodulationpar2)*2.0*PI)*basefuncmodulationpar1;//rev + break; + case 2:t=t+sin((t*basefuncmodulationpar3+basefuncmodulationpar2)*2.0*PI)*basefuncmodulationpar1;//sine + break; + case 3:t=t+pow((1.0-cos((t+basefuncmodulationpar2)*2.0*PI))*0.5,basefuncmodulationpar3)*basefuncmodulationpar1;//power + break; + }; + + t=t-floor(t); + + switch (Pcurrentbasefunc){ + case 1:smps[i]=basefunc_triangle(t,par); + break; + case 2:smps[i]=basefunc_pulse(t,par); + break; + case 3:smps[i]=basefunc_saw(t,par); + break; + case 4:smps[i]=basefunc_power(t,par); + break; + case 5:smps[i]=basefunc_gauss(t,par); + break; + case 6:smps[i]=basefunc_diode(t,par); + break; + case 7:smps[i]=basefunc_abssine(t,par); + break; + case 8:smps[i]=basefunc_pulsesine(t,par); + break; + case 9:smps[i]=basefunc_stretchsine(t,par); + break; + case 10:smps[i]=basefunc_chirp(t,par); + break; + case 11:smps[i]=basefunc_absstretchsine(t,par); + break; + case 12:smps[i]=basefunc_chebyshev(t,par); + break; + case 13:smps[i]=basefunc_sqr(t,par); + break; + default:smps[i]=-sin(2.0*PI*i/OSCIL_SIZE); + }; + }; +}; + +/* + * Filter the oscillator + */ +void OscilGen::oscilfilter(){ + if (Pfiltertype==0) return; + REALTYPE par=1.0-Pfilterpar1/128.0; + REALTYPE par2=Pfilterpar2/127.0; + REALTYPE max=0.0,tmp=0.0,p2,x; + for (int i=1;i<OSCIL_SIZE/2;i++){ + REALTYPE gain=1.0; + switch(Pfiltertype){ + case 1: gain=pow(1.0-par*par*par*0.99,i);//lp + tmp=par2*par2*par2*par2*0.5+0.0001; + if (gain<tmp) gain=pow(gain,10.0)/pow(tmp,9.0); + break; + case 2: gain=1.0-pow(1.0-par*par,i+1);//hp1 + gain=pow(gain,par2*2.0+0.1); + break; + case 3: if (par<0.2) par=par*0.25+0.15; + gain=1.0-pow(1.0-par*par*0.999+0.001,i*0.05*i+1.0);//hp1b + tmp=pow(5.0,par2*2.0); + gain=pow(gain,tmp); + break; + case 4: gain=i+1-pow(2,(1.0-par)*7.5);//bp1 + gain=1.0/(1.0+gain*gain/(i+1.0)); + tmp=pow(5.0,par2*2.0); + gain=pow(gain,tmp); + if (gain<1e-5) gain=1e-5; + break; + case 5: gain=i+1-pow(2,(1.0-par)*7.5);//bs1 + gain=pow(atan(gain/(i/10.0+1))/1.57,6); + gain=pow(gain,par2*par2*3.9+0.1); + break; + case 6: tmp=pow(par2,0.33); + gain=(i+1>pow(2,(1.0-par)*10)?0.0:1.0)*par2+(1.0-par2);//lp2 + break; + case 7: tmp=pow(par2,0.33); + //tmp=1.0-(1.0-par2)*(1.0-par2); + gain=(i+1>pow(2,(1.0-par)*7)?1.0:0.0)*par2+(1.0-par2);//hp2 + if (Pfilterpar1==0) gain=1.0; + break; + case 8: tmp=pow(par2,0.33); + //tmp=1.0-(1.0-par2)*(1.0-par2); + gain=(fabs(pow(2,(1.0-par)*7)-i)>i/2+1?0.0:1.0)*par2+(1.0-par2);//bp2 + break; + case 9: tmp=pow(par2,0.33); + gain=(fabs(pow(2,(1.0-par)*7)-i)<i/2+1?0.0:1.0)*par2+(1.0-par2);//bs2 + break; + case 10:tmp=pow(5.0,par2*2.0-1.0); + tmp=pow(i/32.0,tmp)*32.0; + if (Pfilterpar2==64) tmp=i; + gain=cos(par*par*PI/2.0*tmp);//cos + gain*=gain; + break; + case 11:tmp=pow(5.0,par2*2.0-1.0); + tmp=pow(i/32.0,tmp)*32.0; + if (Pfilterpar2==64) tmp=i; + gain=sin(par*par*PI/2.0*tmp);//sin + gain*=gain; + break; + case 12:p2=1.0-par+0.2; + x=i/(64.0*p2*p2); + if (x<0.0) x=0.0; + else if (x>1.0) x=1.0; + tmp=pow(1.0-par2,2.0); + gain=cos(x*PI)*(1.0-tmp)+1.01+tmp;//low shelf + break; + case 13:tmp=(int) (pow(2.0,(1.0-par)*7.2)); + gain=1.0; + if (i==(int) (tmp)) gain=pow(2.0,par2*par2*8.0); + break; + }; + + + oscilFFTfreqs.s[i]*=gain; + oscilFFTfreqs.c[i]*=gain; + REALTYPE tmp=oscilFFTfreqs.s[i]*oscilFFTfreqs.s[i]+ + oscilFFTfreqs.c[i]*oscilFFTfreqs.c[i]; + if (max<tmp) max=tmp; + }; + + max=sqrt(max); + if (max<1e-10) max=1.0; + REALTYPE imax=1.0/max; + for (int i=1;i<OSCIL_SIZE/2;i++) { + oscilFFTfreqs.s[i]*=imax; + oscilFFTfreqs.c[i]*=imax; + }; +}; + +/* + * Change the base function + */ +void OscilGen::changebasefunction(){ + if (Pcurrentbasefunc!=0) { + getbasefunction(tmpsmps); + fft->smps2freqs(tmpsmps,basefuncFFTfreqs); + basefuncFFTfreqs.c[0]=0.0; + } else { + for (int i=0;i<OSCIL_SIZE/2;i++){ + basefuncFFTfreqs.s[i]=0.0; + basefuncFFTfreqs.c[i]=0.0; + }; + //in this case basefuncFFTfreqs_ are not used + } + oscilprepared=0; + oldbasefunc=Pcurrentbasefunc; + oldbasepar=Pbasefuncpar; + oldbasefuncmodulation=Pbasefuncmodulation; + oldbasefuncmodulationpar1=Pbasefuncmodulationpar1; + oldbasefuncmodulationpar2=Pbasefuncmodulationpar2; + oldbasefuncmodulationpar3=Pbasefuncmodulationpar3; +}; + +/* + * Waveshape + */ +void OscilGen::waveshape(){ + int i; + + oldwaveshapingfunction=Pwaveshapingfunction; + oldwaveshaping=Pwaveshaping; + if (Pwaveshapingfunction==0) return; + + oscilFFTfreqs.c[0]=0.0;//remove the DC + //reduce the amplitude of the freqs near the nyquist + for (i=1;i<OSCIL_SIZE/8;i++) { + REALTYPE tmp=i/(OSCIL_SIZE/8.0); + oscilFFTfreqs.s[OSCIL_SIZE/2-i]*=tmp; + oscilFFTfreqs.c[OSCIL_SIZE/2-i]*=tmp; + }; + fft->freqs2smps(oscilFFTfreqs,tmpsmps); + + //Normalize + REALTYPE max=0.0; + for (i=0;i<OSCIL_SIZE;i++) + if (max<fabs(tmpsmps[i])) max=fabs(tmpsmps[i]); + if (max<0.00001) max=1.0; + max=1.0/max;for (i=0;i<OSCIL_SIZE;i++) tmpsmps[i]*=max; + + //Do the waveshaping + waveshapesmps(OSCIL_SIZE,tmpsmps,Pwaveshapingfunction,Pwaveshaping); + + fft->smps2freqs(tmpsmps,oscilFFTfreqs);//perform FFT +}; + + +/* + * Do the Frequency Modulation of the Oscil + */ +void OscilGen::modulation(){ + int i; + + oldmodulation=Pmodulation; + oldmodulationpar1=Pmodulationpar1; + oldmodulationpar2=Pmodulationpar2; + oldmodulationpar3=Pmodulationpar3; + if (Pmodulation==0) return; + + + REALTYPE modulationpar1=Pmodulationpar1/127.0, + modulationpar2=0.5-Pmodulationpar2/127.0, + modulationpar3=Pmodulationpar3/127.0; + + switch(Pmodulation){ + case 1:modulationpar1=(pow(2,modulationpar1*7.0)-1.0)/100.0; + modulationpar3=floor((pow(2,modulationpar3*5.0)-1.0)); + if (modulationpar3<0.9999) modulationpar3=-1.0; + break; + case 2:modulationpar1=(pow(2,modulationpar1*7.0)-1.0)/100.0; + modulationpar3=1.0+floor((pow(2,modulationpar3*5.0)-1.0)); + break; + case 3:modulationpar1=(pow(2,modulationpar1*9.0)-1.0)/100.0; + modulationpar3=0.01+(pow(2,modulationpar3*16.0)-1.0)/10.0; + break; + }; + + oscilFFTfreqs.c[0]=0.0;//remove the DC + //reduce the amplitude of the freqs near the nyquist + for (i=1;i<OSCIL_SIZE/8;i++) { + REALTYPE tmp=i/(OSCIL_SIZE/8.0); + oscilFFTfreqs.s[OSCIL_SIZE/2-i]*=tmp; + oscilFFTfreqs.c[OSCIL_SIZE/2-i]*=tmp; + }; + fft->freqs2smps(oscilFFTfreqs,tmpsmps); + int extra_points=2; + REALTYPE *in=new REALTYPE[OSCIL_SIZE+extra_points]; + + //Normalize + REALTYPE max=0.0; + for (i=0;i<OSCIL_SIZE;i++) if (max<fabs(tmpsmps[i])) max=fabs(tmpsmps[i]); + if (max<0.00001) max=1.0; + max=1.0/max;for (i=0;i<OSCIL_SIZE;i++) in[i]=tmpsmps[i]*max; + for (i=0;i<extra_points;i++) in[i+OSCIL_SIZE]=tmpsmps[i]*max; + + //Do the modulation + for (i=0;i<OSCIL_SIZE;i++) { + REALTYPE t=i*1.0/OSCIL_SIZE; + + switch(Pmodulation){ + case 1:t=t*modulationpar3+sin((t+modulationpar2)*2.0*PI)*modulationpar1;//rev + break; + case 2:t=t+sin((t*modulationpar3+modulationpar2)*2.0*PI)*modulationpar1;//sine + break; + case 3:t=t+pow((1.0-cos((t+modulationpar2)*2.0*PI))*0.5,modulationpar3)*modulationpar1;//power + break; + }; + + t=(t-floor(t))*OSCIL_SIZE; + + int poshi=(int) t; + REALTYPE poslo=t-floor(t); + + tmpsmps[i]=in[poshi]*(1.0-poslo)+in[poshi+1]*poslo; + }; + + delete(in); + fft->smps2freqs(tmpsmps,oscilFFTfreqs);//perform FFT +}; + + + +/* + * Adjust the spectrum + */ +void OscilGen::spectrumadjust(){ + if (Psatype==0) return; + REALTYPE par=Psapar/127.0; + switch(Psatype){ + case 1: par=1.0-par*2.0; + if (par>=0.0) par=pow(5.0,par); + else par=pow(8.0,par); + break; + case 2: par=pow(10.0,(1.0-par)*3.0)*0.25; + break; + case 3: par=pow(10.0,(1.0-par)*3.0)*0.25; + break; + }; + + + REALTYPE max=0.0; + for (int i=0;i<OSCIL_SIZE/2;i++){ + REALTYPE tmp=pow(oscilFFTfreqs.c[i],2)+pow(oscilFFTfreqs.s[i],2.0); + if (max<tmp) max=tmp; + }; + max=sqrt(max)/OSCIL_SIZE*2.0; + if (max<1e-8) max=1.0; + + + for (int i=0;i<OSCIL_SIZE/2;i++){ + REALTYPE mag=sqrt(pow(oscilFFTfreqs.s[i],2)+pow(oscilFFTfreqs.c[i],2.0))/max; + REALTYPE phase=atan2(oscilFFTfreqs.s[i],oscilFFTfreqs.c[i]); + + switch (Psatype){ + case 1: mag=pow(mag,par); + break; + case 2: if (mag<par) mag=0.0; + break; + case 3: mag/=par; + if (mag>1.0) mag=1.0; + break; + }; + oscilFFTfreqs.c[i]=mag*cos(phase); + oscilFFTfreqs.s[i]=mag*sin(phase); + }; + +}; + +void OscilGen::shiftharmonics(){ + if (Pharmonicshift==0) return; + + REALTYPE hc,hs; + int harmonicshift=-Pharmonicshift; + + if (harmonicshift>0){ + for (int i=OSCIL_SIZE/2-2;i>=0;i--){ + int oldh=i-harmonicshift; + if (oldh<0){ + hc=0.0; + hs=0.0; + } else { + hc=oscilFFTfreqs.c[oldh+1]; + hs=oscilFFTfreqs.s[oldh+1]; + }; + oscilFFTfreqs.c[i+1]=hc; + oscilFFTfreqs.s[i+1]=hs; + }; + } else { + for (int i=0;i<OSCIL_SIZE/2-1;i++){ + int oldh=i+abs(harmonicshift); + if (oldh>=(OSCIL_SIZE/2-1)){ + hc=0.0; + hs=0.0; + } else { + hc=oscilFFTfreqs.c[oldh+1]; + hs=oscilFFTfreqs.s[oldh+1]; + if (fabs(hc)<0.000001) hc=0.0; + if (fabs(hs)<0.000001) hs=0.0; + }; + + oscilFFTfreqs.c[i+1]=hc; + oscilFFTfreqs.s[i+1]=hs; + }; + }; + + oscilFFTfreqs.c[0]=0.0; +}; + +/* + * Prepare the Oscillator + */ +void OscilGen::prepare(){ + int i,j,k; + REALTYPE a,b,c,d,hmagnew; + + if ((oldbasepar!=Pbasefuncpar)||(oldbasefunc!=Pcurrentbasefunc)|| + (oldbasefuncmodulation!=Pbasefuncmodulation)|| + (oldbasefuncmodulationpar1!=Pbasefuncmodulationpar1)|| + (oldbasefuncmodulationpar2!=Pbasefuncmodulationpar2)|| + (oldbasefuncmodulationpar3!=Pbasefuncmodulationpar3)) + changebasefunction(); + + for (i=0;i<MAX_AD_HARMONICS;i++) hphase[i]=(Phphase[i]-64.0)/64.0*PI/(i+1); + + for (i=0;i<MAX_AD_HARMONICS;i++){ + hmagnew=1.0-fabs(Phmag[i]/64.0-1.0); + switch(Phmagtype){ + case 1:hmag[i]=exp(hmagnew*log(0.01)); break; + case 2:hmag[i]=exp(hmagnew*log(0.001));break; + case 3:hmag[i]=exp(hmagnew*log(0.0001));break; + case 4:hmag[i]=exp(hmagnew*log(0.00001));break; + default:hmag[i]=1.0-hmagnew; + break; + }; + + if (Phmag[i]<64) hmag[i]=-hmag[i]; + }; + + //remove the harmonics where Phmag[i]==64 + for (i=0;i<MAX_AD_HARMONICS;i++) if (Phmag[i]==64) hmag[i]=0.0; + + + for (i=0;i<OSCIL_SIZE/2;i++) { + oscilFFTfreqs.c[i]=0.0; + oscilFFTfreqs.s[i]=0.0; + }; + if (Pcurrentbasefunc==0) {//the sine case + for (i=0;i<MAX_AD_HARMONICS;i++){ + oscilFFTfreqs.c[i+1]=-hmag[i]*sin(hphase[i]*(i+1))/2.0; + oscilFFTfreqs.s[i+1]=hmag[i]*cos(hphase[i]*(i+1))/2.0; + }; + } else { + for (j=0;j<MAX_AD_HARMONICS;j++){ + if (Phmag[j]==64) continue; + for (i=1;i<OSCIL_SIZE/2;i++){ + k=i*(j+1);if (k>=OSCIL_SIZE/2) break; + a=basefuncFFTfreqs.c[i]; + b=basefuncFFTfreqs.s[i]; + c=hmag[j]*cos(hphase[j]*k); + d=hmag[j]*sin(hphase[j]*k); + oscilFFTfreqs.c[k]+=a*c-b*d; + oscilFFTfreqs.s[k]+=a*d+b*c; + }; + }; + + }; + + if (Pharmonicshiftfirst!=0) shiftharmonics(); + + + + if (Pfilterbeforews==0){ + waveshape(); + oscilfilter(); + } else { + oscilfilter(); + waveshape(); + }; + + modulation(); + spectrumadjust(); + if (Pharmonicshiftfirst==0) shiftharmonics(); + + oscilFFTfreqs.c[0]=0.0; + + oldhmagtype=Phmagtype; + oldharmonicshift=Pharmonicshift+Pharmonicshiftfirst*256; + + oscilprepared=1; +}; + +void OscilGen::adaptiveharmonic(FFTFREQS f,REALTYPE freq){ + if ((Padaptiveharmonics==0)/*||(freq<1.0)*/) return; + if (freq<1.0) freq=440.0; + + FFTFREQS inf; + newFFTFREQS(&inf,OSCIL_SIZE/2); + for (int i=0;i<OSCIL_SIZE/2;i++) { + inf.s[i]=f.s[i]; + inf.c[i]=f.c[i]; + f.s[i]=0.0; + f.c[i]=0.0; + }; + inf.c[0]=0.0;inf.s[0]=0.0; + + REALTYPE hc=0.0,hs=0.0; + REALTYPE basefreq=30.0*pow(10.0,Padaptiveharmonicsbasefreq/128.0); + REALTYPE power=(Padaptiveharmonicspower+1.0)/101.0; + + REALTYPE rap=freq/basefreq; + + rap=pow(rap,power); + + bool down=false; + if (rap>1.0) { + rap=1.0/rap; + down=true; + }; + + for (int i=0;i<OSCIL_SIZE/2-2;i++){ + REALTYPE h=i*rap; + int high=(int)(i*rap); + REALTYPE low=fmod(h,1.0); + + if (high>=(OSCIL_SIZE/2-2)){ + break; + } else { + if (down){ + f.c[high]+=inf.c[i]*(1.0-low); + f.s[high]+=inf.s[i]*(1.0-low); + f.c[high+1]+=inf.c[i]*low; + f.s[high+1]+=inf.s[i]*low; + } else { + hc=inf.c[high]*(1.0-low)+inf.c[high+1]*low; + hs=inf.s[high]*(1.0-low)+inf.s[high+1]*low; + }; + if (fabs(hc)<0.000001) hc=0.0; + if (fabs(hs)<0.000001) hs=0.0; + }; + + if (!down){ + if (i==0) {//corect the aplitude of the first harmonic + hc*=rap; + hs*=rap; + }; + f.c[i]=hc; + f.s[i]=hs; + }; + }; + + f.c[1]+=f.c[0];f.s[1]+=f.s[0]; + f.c[0]=0.0;f.s[0]=0.0; + deleteFFTFREQS(&inf); +}; + +void OscilGen::adaptiveharmonicpostprocess(REALTYPE *f,int size){ + if (Padaptiveharmonics<=1) return; + REALTYPE *inf=new REALTYPE[size]; + REALTYPE par=Padaptiveharmonicspar*0.01; + par=1.0-pow((1.0-par),1.5); + + for (int i=0;i<size;i++) { + inf[i]=f[i]*par; + f[i]=f[i]*(1.0-par); + }; + + + if (Padaptiveharmonics==2){//2n+1 + for (int i=0;i<size;i++) if ((i%2)==0) f[i]+=inf[i];//i=0 pt prima armonica,etc. + } else{//celelalte moduri + int nh=(Padaptiveharmonics-3)/2+2; + int sub_vs_add=(Padaptiveharmonics-3)%2; + if (sub_vs_add==0){ + for (int i=0;i<size;i++) { + if (((i+1)%nh)==0){ + f[i]+=inf[i]; + }; + }; + } else { + for (int i=0;i<size/nh-1;i++) { + f[(i+1)*nh-1]+=inf[i]; + }; + }; + }; + + delete(inf); +}; + + + +/* + * Get the oscillator function + */ +short int OscilGen::get(REALTYPE *smps,REALTYPE freqHz){ + return(this->get(smps,freqHz,0)); +}; + +void OscilGen::newrandseed(unsigned int randseed){ + this->randseed=randseed; +}; + +/* + * Get the oscillator function + */ +short int OscilGen::get(REALTYPE *smps,REALTYPE freqHz,int resonance){ + int i; + int nyquist,outpos; + + if ((oldbasepar!=Pbasefuncpar)||(oldbasefunc!=Pcurrentbasefunc)||(oldhmagtype!=Phmagtype) + ||(oldwaveshaping!=Pwaveshaping)||(oldwaveshapingfunction!=Pwaveshapingfunction)) oscilprepared=0; + if (oldfilterpars!=Pfiltertype*256+Pfilterpar1+Pfilterpar2*65536+Pfilterbeforews*16777216){ + oscilprepared=0; + oldfilterpars=Pfiltertype*256+Pfilterpar1+Pfilterpar2*65536+Pfilterbeforews*16777216; + }; + if (oldsapars!=Psatype*256+Psapar){ + oscilprepared=0; + oldsapars=Psatype*256+Psapar; + }; + + if ((oldbasefuncmodulation!=Pbasefuncmodulation)|| + (oldbasefuncmodulationpar1!=Pbasefuncmodulationpar1)|| + (oldbasefuncmodulationpar2!=Pbasefuncmodulationpar2)|| + (oldbasefuncmodulationpar3!=Pbasefuncmodulationpar3)) + oscilprepared=0; + + if ((oldmodulation!=Pmodulation)|| + (oldmodulationpar1!=Pmodulationpar1)|| + (oldmodulationpar2!=Pmodulationpar2)|| + (oldmodulationpar3!=Pmodulationpar3)) + oscilprepared=0; + + if (oldharmonicshift!=Pharmonicshift+Pharmonicshiftfirst*256) oscilprepared=0; + + if (oscilprepared!=1) prepare(); + + outpos=(int)((RND*2.0-1.0)*(REALTYPE) OSCIL_SIZE*(Prand-64.0)/64.0); + outpos=(outpos+2*OSCIL_SIZE) % OSCIL_SIZE; + + + for (i=0;i<OSCIL_SIZE/2;i++){ + outoscilFFTfreqs.c[i]=0.0; + outoscilFFTfreqs.s[i]=0.0; + }; + + nyquist=(int)(0.5*SAMPLE_RATE/fabs(freqHz))+2; + if (ADvsPAD) nyquist=(int)(OSCIL_SIZE/2); + if (nyquist>OSCIL_SIZE/2) nyquist=OSCIL_SIZE/2; + + + int realnyquist=nyquist; + + if (Padaptiveharmonics!=0) nyquist=OSCIL_SIZE/2; + for (i=1;i<nyquist-1;i++) { + outoscilFFTfreqs.c[i]=oscilFFTfreqs.c[i]; + outoscilFFTfreqs.s[i]=oscilFFTfreqs.s[i]; + }; + + adaptiveharmonic(outoscilFFTfreqs,freqHz); + adaptiveharmonicpostprocess(&outoscilFFTfreqs.c[1],OSCIL_SIZE/2-1); + adaptiveharmonicpostprocess(&outoscilFFTfreqs.s[1],OSCIL_SIZE/2-1); + + nyquist=realnyquist; + if (Padaptiveharmonics){//do the antialiasing in the case of adaptive harmonics + for (i=nyquist;i<OSCIL_SIZE/2;i++) { + outoscilFFTfreqs.s[i]=0; + outoscilFFTfreqs.c[i]=0; + }; + }; + + // Randomness (each harmonic), the block type is computed + // in ADnote by setting start position according to this setting + if ((Prand>64)&&(freqHz>=0.0)&&(!ADvsPAD)){ + REALTYPE rnd,angle,a,b,c,d; + rnd=PI*pow((Prand-64.0)/64.0,2.0); + for (i=1;i<nyquist-1;i++){//to Nyquist only for AntiAliasing + angle=rnd*i*RND; + a=outoscilFFTfreqs.c[i]; + b=outoscilFFTfreqs.s[i]; + c=cos(angle); + d=sin(angle); + outoscilFFTfreqs.c[i]=a*c-b*d; + outoscilFFTfreqs.s[i]=a*d+b*c; + }; + }; + + //Harmonic Amplitude Randomness + if ((freqHz>0.1)&&(!ADvsPAD)) { + unsigned int realrnd=rand(); + srand(randseed); + REALTYPE power=Pamprandpower/127.0; + REALTYPE normalize=1.0/(1.2-power); + switch (Pamprandtype){ + case 1: power=power*2.0-0.5; + power=pow(15.0,power); + for (i=1;i<nyquist-1;i++){ + REALTYPE amp=pow(RND,power)*normalize; + outoscilFFTfreqs.c[i]*=amp; + outoscilFFTfreqs.s[i]*=amp; + }; + break; + case 2: power=power*2.0-0.5; + power=pow(15.0,power)*2.0; + REALTYPE rndfreq=2*PI*RND; + for (i=1;i<nyquist-1;i++){ + REALTYPE amp=pow(fabs(sin(i*rndfreq)),power)*normalize; + outoscilFFTfreqs.c[i]*=amp; + outoscilFFTfreqs.s[i]*=amp; + }; + break; + }; + srand(realrnd+1); + }; + + if ((freqHz>0.1)&&(resonance!=0)) res->applyres(nyquist-1,outoscilFFTfreqs,freqHz); + + //Full RMS normalize + REALTYPE sum=0; + for (int j=1;j<OSCIL_SIZE/2;j++) { + REALTYPE term=outoscilFFTfreqs.c[j]*outoscilFFTfreqs.c[j] + +outoscilFFTfreqs.s[j]*outoscilFFTfreqs.s[j]; + sum+=term; + }; + if (sum<0.000001) sum=1.0; + sum=1.0/sqrt(sum); + for (int j=1;j<OSCIL_SIZE/2;j++) { + outoscilFFTfreqs.c[j]*=sum; + outoscilFFTfreqs.s[j]*=sum; + }; + + + if ((ADvsPAD)&&(freqHz>0.1)){//in this case the smps will contain the freqs + for (i=1;i<OSCIL_SIZE/2;i++) smps[i-1]=sqrt(outoscilFFTfreqs.c[i]*outoscilFFTfreqs.c[i] + +outoscilFFTfreqs.s[i]*outoscilFFTfreqs.s[i]); + } else { + fft->freqs2smps(outoscilFFTfreqs,smps); + for (i=0;i<OSCIL_SIZE;i++) smps[i]*=0.25;//correct the amplitude + }; + + if (Prand<64) return(outpos); + else return(0); +}; + + +/* + * Get the spectrum of the oscillator for the UI + */ +void OscilGen::getspectrum(int n, REALTYPE *spc,int what){ + if (n>OSCIL_SIZE/2) n=OSCIL_SIZE/2; + + for (int i=1;i<n;i++){ + if (what==0){ + spc[i-1]=sqrt(oscilFFTfreqs.c[i]*oscilFFTfreqs.c[i] + +oscilFFTfreqs.s[i]*oscilFFTfreqs.s[i]); + } else { + if (Pcurrentbasefunc==0) spc[i-1]=((i==1)?(1.0):(0.0)); + else spc[i-1]=sqrt(basefuncFFTfreqs.c[i]*basefuncFFTfreqs.c[i]+ + basefuncFFTfreqs.s[i]*basefuncFFTfreqs.s[i]); + }; + }; + + if (what==0) { + for (int i=0;i<n;i++) outoscilFFTfreqs.s[i]=outoscilFFTfreqs.c[i]=spc[i+1]; + for (int i=n;i<OSCIL_SIZE/2;i++) outoscilFFTfreqs.s[i]=outoscilFFTfreqs.c[i]=0.0; + adaptiveharmonic(outoscilFFTfreqs,0.0); + for (int i=1;i<n;i++) spc[i-1]=outoscilFFTfreqs.s[i]; + adaptiveharmonicpostprocess(spc,n-1); + }; +}; + + +/* + * Convert the oscillator as base function + */ +void OscilGen::useasbase(){ + int i; + + for (i=0;i<OSCIL_SIZE/2;i++) { + basefuncFFTfreqs.c[i]=oscilFFTfreqs.c[i]; + basefuncFFTfreqs.s[i]=oscilFFTfreqs.s[i]; + }; + + oldbasefunc=Pcurrentbasefunc=127; + + prepare(); +}; + + +/* + * Get the base function for UI + */ +void OscilGen::getcurrentbasefunction(REALTYPE *smps){ + if (Pcurrentbasefunc!=0) { + fft->freqs2smps(basefuncFFTfreqs,smps); + } else getbasefunction(smps);//the sine case +}; + + +void OscilGen::add2XML(XMLwrapper *xml){ + xml->addpar("harmonic_mag_type",Phmagtype); + + xml->addpar("base_function",Pcurrentbasefunc); + xml->addpar("base_function_par",Pbasefuncpar); + xml->addpar("base_function_modulation",Pbasefuncmodulation); + xml->addpar("base_function_modulation_par1",Pbasefuncmodulationpar1); + xml->addpar("base_function_modulation_par2",Pbasefuncmodulationpar2); + xml->addpar("base_function_modulation_par3",Pbasefuncmodulationpar3); + + xml->addpar("modulation",Pmodulation); + xml->addpar("modulation_par1",Pmodulationpar1); + xml->addpar("modulation_par2",Pmodulationpar2); + xml->addpar("modulation_par3",Pmodulationpar3); + + xml->addpar("wave_shaping",Pwaveshaping); + xml->addpar("wave_shaping_function",Pwaveshapingfunction); + + xml->addpar("filter_type",Pfiltertype); + xml->addpar("filter_par1",Pfilterpar1); + xml->addpar("filter_par2",Pfilterpar2); + xml->addpar("filter_before_wave_shaping",Pfilterbeforews); + + xml->addpar("spectrum_adjust_type",Psatype); + xml->addpar("spectrum_adjust_par",Psapar); + + xml->addpar("rand",Prand); + xml->addpar("amp_rand_type",Pamprandtype); + xml->addpar("amp_rand_power",Pamprandpower); + + xml->addpar("harmonic_shift",Pharmonicshift); + xml->addparbool("harmonic_shift_first",Pharmonicshiftfirst); + + xml->addpar("adaptive_harmonics",Padaptiveharmonics); + xml->addpar("adaptive_harmonics_base_frequency",Padaptiveharmonicsbasefreq); + xml->addpar("adaptive_harmonics_power",Padaptiveharmonicspower); + + xml->beginbranch("HARMONICS"); + for (int n=0;n<MAX_AD_HARMONICS;n++){ + if ((Phmag[n]==64)&&(Phphase[n]==64)) continue; + xml->beginbranch("HARMONIC",n+1); + xml->addpar("mag",Phmag[n]); + xml->addpar("phase",Phphase[n]); + xml->endbranch(); + }; + xml->endbranch(); + + if (Pcurrentbasefunc==127){ + REALTYPE max=0.0; + + for (int i=0;i<OSCIL_SIZE/2;i++){ + if (max<fabs(basefuncFFTfreqs.c[i])) max=fabs(basefuncFFTfreqs.c[i]); + if (max<fabs(basefuncFFTfreqs.s[i])) max=fabs(basefuncFFTfreqs.s[i]); + }; + if (max<0.00000001) max=1.0; + + xml->beginbranch("BASE_FUNCTION"); + for (int i=1;i<OSCIL_SIZE/2;i++){ + REALTYPE xc=basefuncFFTfreqs.c[i]/max; + REALTYPE xs=basefuncFFTfreqs.s[i]/max; + if ((fabs(xs)>0.00001)&&(fabs(xs)>0.00001)){ + xml->beginbranch("BF_HARMONIC",i); + xml->addparreal("cos",xc); + xml->addparreal("sin",xs); + xml->endbranch(); + }; + }; + xml->endbranch(); + }; +}; + + +void OscilGen::getfromXML(XMLwrapper *xml){ + + Phmagtype=xml->getpar127("harmonic_mag_type",Phmagtype); + + Pcurrentbasefunc=xml->getpar127("base_function",Pcurrentbasefunc); + Pbasefuncpar=xml->getpar127("base_function_par",Pbasefuncpar); + + Pbasefuncmodulation=xml->getpar127("base_function_modulation",Pbasefuncmodulation); + Pbasefuncmodulationpar1=xml->getpar127("base_function_modulation_par1",Pbasefuncmodulationpar1); + Pbasefuncmodulationpar2=xml->getpar127("base_function_modulation_par2",Pbasefuncmodulationpar2); + Pbasefuncmodulationpar3=xml->getpar127("base_function_modulation_par3",Pbasefuncmodulationpar3); + + Pmodulation=xml->getpar127("modulation",Pmodulation); + Pmodulationpar1=xml->getpar127("modulation_par1",Pmodulationpar1); + Pmodulationpar2=xml->getpar127("modulation_par2",Pmodulationpar2); + Pmodulationpar3=xml->getpar127("modulation_par3",Pmodulationpar3); + + Pwaveshaping=xml->getpar127("wave_shaping",Pwaveshaping); + Pwaveshapingfunction=xml->getpar127("wave_shaping_function",Pwaveshapingfunction); + + Pfiltertype=xml->getpar127("filter_type",Pfiltertype); + Pfilterpar1=xml->getpar127("filter_par1",Pfilterpar1); + Pfilterpar2=xml->getpar127("filter_par2",Pfilterpar2); + Pfilterbeforews=xml->getpar127("filter_before_wave_shaping",Pfilterbeforews); + + Psatype=xml->getpar127("spectrum_adjust_type",Psatype); + Psapar=xml->getpar127("spectrum_adjust_par",Psapar); + + Prand=xml->getpar127("rand",Prand); + Pamprandtype=xml->getpar127("amp_rand_type",Pamprandtype); + Pamprandpower=xml->getpar127("amp_rand_power",Pamprandpower); + + Pharmonicshift=xml->getpar("harmonic_shift",Pharmonicshift,-64,64); + Pharmonicshiftfirst=xml->getparbool("harmonic_shift_first",Pharmonicshiftfirst); + + Padaptiveharmonics=xml->getpar("adaptive_harmonics",Padaptiveharmonics,0,127); + Padaptiveharmonicsbasefreq=xml->getpar("adaptive_harmonics_base_frequency",Padaptiveharmonicsbasefreq,0,255); + Padaptiveharmonicspower=xml->getpar("adaptive_harmonics_power",Padaptiveharmonicspower,0,200); + + + if (xml->enterbranch("HARMONICS")){ + Phmag[0]=64;Phphase[0]=64; + for (int n=0;n<MAX_AD_HARMONICS;n++){ + if (xml->enterbranch("HARMONIC",n+1)==0) continue; + Phmag[n]=xml->getpar127("mag",64); + Phphase[n]=xml->getpar127("phase",64); + xml->exitbranch(); + }; + xml->exitbranch(); + }; + + if (Pcurrentbasefunc!=0) changebasefunction(); + + + if (xml->enterbranch("BASE_FUNCTION")){ + for (int i=1;i<OSCIL_SIZE/2;i++){ + if (xml->enterbranch("BF_HARMONIC",i)){ + basefuncFFTfreqs.c[i]=xml->getparreal("cos",0.0); + basefuncFFTfreqs.s[i]=xml->getparreal("sin",0.0); + xml->exitbranch(); + }; + + + }; + xml->exitbranch(); + + REALTYPE max=0.0; + + basefuncFFTfreqs.c[0]=0.0; + for (int i=0;i<OSCIL_SIZE/2;i++) { + if (max<fabs(basefuncFFTfreqs.c[i])) max=fabs(basefuncFFTfreqs.c[i]); + if (max<fabs(basefuncFFTfreqs.s[i])) max=fabs(basefuncFFTfreqs.s[i]); + }; + if (max<0.00000001) max=1.0; + + for (int i=0;i<OSCIL_SIZE/2;i++) { + if (basefuncFFTfreqs.c[i]) basefuncFFTfreqs.c[i]/=max; + if (basefuncFFTfreqs.s[i]) basefuncFFTfreqs.s[i]/=max; + }; + }; +}; + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.h new file mode 100644 index 00000000..1d9980a9 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/OscilGen.h @@ -0,0 +1,176 @@ +/* + ZynAddSubFX - a software synthesizer + + OscilGen.h - Waveform generator for ADnote + 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 + +*/ + +#ifndef OSCIL_GEN_H +#define OSCIL_GEN_H + +#include "../globals.h" +#include "../Misc/XMLwrapper.h" +#include "Resonance.h" +#include "../DSP/FFTwrapper.h" +#include "../Params/Presets.h" + +class OscilGen:public Presets{ + public: + OscilGen(FFTwrapper *fft_,Resonance *res_); + ~OscilGen(); + + //computes the full spectrum of oscil from harmonics,phases and basefunc + void prepare(); + + //do the antialiasing(cut off higher freqs.),apply randomness and do a IFFT + short get(REALTYPE *smps,REALTYPE freqHz);//returns where should I start getting samples, used in block type randomness + short get(REALTYPE *smps,REALTYPE freqHz,int resonance); + //if freqHz is smaller than 0, return the "un-randomized" sample for UI + + void getbasefunction(REALTYPE *smps); + + //called by UI + void getspectrum(int n,REALTYPE *spc,int what);//what=0 pt. oscil,1 pt. basefunc + void getcurrentbasefunction(REALTYPE *smps); + void useasbase();//convert oscil to base function + + void add2XML(XMLwrapper *xml); + void defaults(); + void getfromXML(XMLwrapper *xml); + + void convert2sine(int magtype); + + //Parameters + + /* + The hmag and hphase starts counting from 0, so the first harmonic(1) has the index 0, + 2-nd harmonic has index 1, ..the 128 harminic has index 127 + */ + unsigned char Phmag[MAX_AD_HARMONICS],Phphase[MAX_AD_HARMONICS];//the MIDI parameters for mag. and phases + + + /*The Type of magnitude: + 0 - Linear + 1 - dB scale (-40) + 2 - dB scale (-60) + 3 - dB scale (-80) + 4 - dB scale (-100)*/ + unsigned char Phmagtype; + + unsigned char Pcurrentbasefunc;//The base function used - 0=sin, 1=... + unsigned char Pbasefuncpar;//the parameter of the base function + + unsigned char Pbasefuncmodulation;//what modulation is applied to the basefunc + unsigned char Pbasefuncmodulationpar1,Pbasefuncmodulationpar2,Pbasefuncmodulationpar3;//the parameter of the base function modulation + + /*the Randomness: + 64=no randomness + 63..0 - block type randomness - 0 is maximum + 65..127 - each harmonic randomness - 127 is maximum*/ + unsigned char Prand; + unsigned char Pwaveshaping,Pwaveshapingfunction; + unsigned char Pfiltertype,Pfilterpar1,Pfilterpar2; + unsigned char Pfilterbeforews; + unsigned char Psatype,Psapar;//spectrum adjust + + unsigned char Pamprandpower, Pamprandtype;//amplitude randomness + int Pharmonicshift;//how the harmonics are shifted + int Pharmonicshiftfirst;//if the harmonic shift is done before waveshaping and filter + + unsigned char Padaptiveharmonics;//the adaptive harmonics status (off=0,on=1,etc..) + unsigned char Padaptiveharmonicsbasefreq;//the base frequency of the adaptive harmonic (30..3000Hz) + unsigned char Padaptiveharmonicspower;//the strength of the effect (0=off,100=full) + unsigned char Padaptiveharmonicspar;//the parameters in 2,3,4.. modes of adaptive harmonics + + unsigned char Pmodulation;//what modulation is applied to the oscil + unsigned char Pmodulationpar1,Pmodulationpar2,Pmodulationpar3;//the parameter of the parameters + + + //makes a new random seed for Amplitude Randomness + //this should be called every note on event + void newrandseed(unsigned int randseed); + + bool ADvsPAD;//if it is used by ADsynth or by PADsynth + + static REALTYPE *tmpsmps;//this array stores some termporary data and it has SOUND_BUFFER_SIZE elements + static FFTFREQS outoscilFFTfreqs; + + private: + + REALTYPE hmag[MAX_AD_HARMONICS],hphase[MAX_AD_HARMONICS];//the magnituides and the phases of the sine/nonsine harmonics +// private: + FFTwrapper *fft; + //computes the basefunction and make the FFT; newbasefunc<0 = same basefunc + void changebasefunction(); + //Waveshaping + void waveshape(); + + //Filter the oscillator accotding to Pfiltertype and Pfilterpar + void oscilfilter(); + + //Adjust the spectrum + void spectrumadjust(); + + //Shift the harmonics + void shiftharmonics(); + + //Do the oscil modulation stuff + void modulation(); + + //Do the adaptive harmonic stuff + void adaptiveharmonic(FFTFREQS f,REALTYPE freq); + + //Do the adaptive harmonic postprocessing (2n+1,2xS,2xA,etc..) + //this function is called even for the user interface + //this can be called for the sine and components, and for the spectrum + //(that's why the sine and cosine components should be processed with a separate call) + void adaptiveharmonicpostprocess(REALTYPE *f, int size); + + //Basic/base functions (Functiile De Baza) + REALTYPE basefunc_pulse(REALTYPE x,REALTYPE a); + REALTYPE basefunc_saw(REALTYPE x,REALTYPE a); + REALTYPE basefunc_triangle(REALTYPE x,REALTYPE a); + REALTYPE basefunc_power(REALTYPE x,REALTYPE a); + REALTYPE basefunc_gauss(REALTYPE x,REALTYPE a); + REALTYPE basefunc_diode(REALTYPE x,REALTYPE a); + REALTYPE basefunc_abssine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_pulsesine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_stretchsine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_chirp(REALTYPE x,REALTYPE a); + REALTYPE basefunc_absstretchsine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_chebyshev(REALTYPE x,REALTYPE a); + REALTYPE basefunc_sqr(REALTYPE x,REALTYPE a); + + //Internal Data + unsigned char oldbasefunc,oldbasepar,oldhmagtype,oldwaveshapingfunction,oldwaveshaping; + int oldfilterpars,oldsapars,oldbasefuncmodulation,oldbasefuncmodulationpar1,oldbasefuncmodulationpar2,oldbasefuncmodulationpar3,oldharmonicshift; + int oldmodulation,oldmodulationpar1,oldmodulationpar2,oldmodulationpar3; + + + FFTFREQS basefuncFFTfreqs;//Base Function Frequencies + FFTFREQS oscilFFTfreqs;//Oscillator Frequencies - this is different than the hamonics set-up by the user, it may contains time-domain data if the antialiasing is turned off + int oscilprepared;//1 if the oscil is prepared, 0 if it is not prepared and is need to call ::prepare() before ::get() + + Resonance *res; + + unsigned int randseed; + +}; + + +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.C new file mode 100644 index 00000000..9ecc8877 --- /dev/null +++ b/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(); +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.h new file mode 100644 index 00000000..2a99577f --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/PADnote.h @@ -0,0 +1,106 @@ +/* + ZynAddSubFX - a software synthesizer + + PADnote.h - 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 +*/ +#ifndef PAD_NOTE_H +#define PAD_NOTE_H + +#include "../globals.h" +#include "../Params/PADnoteParameters.h" +#include "../Params/Controller.h" +#include "Envelope.h" +#include "LFO.h" +#include "../DSP/Filter.h" +#include "../Params/Controller.h" + +class PADnote{ + public: + PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote); + ~PADnote(); + + int noteout(REALTYPE *outl,REALTYPE *outr); + int finished(); + void relasekey(); + + int ready; + + private: + void fadein(REALTYPE *smps); + void computecurrentparameters(); + bool finished_; + PADnoteParameters *pars; + + int poshi_l,poshi_r; + REALTYPE poslo; + + REALTYPE basefreq; + bool firsttime,released; + + int nsample,portamento; + + int Compute_Linear(REALTYPE *outl,REALTYPE *outr,int freqhi,REALTYPE freqlo); + int Compute_Cubic(REALTYPE *outl,REALTYPE *outr,int freqhi,REALTYPE freqlo); + + + struct{ + /****************************************** + * FREQUENCY GLOBAL PARAMETERS * + ******************************************/ + REALTYPE Detune;//cents + + Envelope *FreqEnvelope; + LFO *FreqLfo; + + /******************************************** + * AMPLITUDE GLOBAL PARAMETERS * + ********************************************/ + REALTYPE Volume;// [ 0 .. 1 ] + + REALTYPE Panning;// [ 0 .. 1 ] + + Envelope *AmpEnvelope; + LFO *AmpLfo; + + struct { + int Enabled; + REALTYPE initialvalue,dt,t; + } Punch; + + /****************************************** + * FILTER GLOBAL PARAMETERS * + ******************************************/ + Filter *GlobalFilterL,*GlobalFilterR; + + REALTYPE FilterCenterPitch;//octaves + REALTYPE FilterQ; + REALTYPE FilterFreqTracking; + + Envelope *FilterEnvelope; + + LFO *FilterLfo; + } NoteGlobalPar; + + + REALTYPE globaloldamplitude,globalnewamplitude,velocity,realfreq; + REALTYPE *tmpwave; + Controller *ctl; +}; + + +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.C new file mode 100644 index 00000000..fb741055 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.C @@ -0,0 +1,231 @@ +/* + ZynAddSubFX - a software synthesizer + + Resonance.C - Resonance + 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 "Resonance.h" + + +#include <stdio.h> + +Resonance::Resonance():Presets(){ + setpresettype("Presonance"); + defaults(); +}; + +Resonance::~Resonance(){ +}; + + +void Resonance::defaults(){ + Penabled=0; + PmaxdB=20; + Pcenterfreq=64;//1 kHz + Poctavesfreq=64; + Pprotectthefundamental=0; + ctlcenter=1.0; + ctlbw=1.0; + for (int i=0;i<N_RES_POINTS;i++) Prespoints[i]=64; +}; + +/* + * Set a point of resonance function with a value + */ +void Resonance::setpoint(int n,unsigned char p){ + if ((n<0)||(n>=N_RES_POINTS)) return; + Prespoints[n]=p; +}; + +/* + * Apply the resonance to FFT data + */ +void Resonance::applyres(int n,FFTFREQS fftdata,REALTYPE freq){ + if (Penabled==0) return;//if the resonance is disabled + REALTYPE sum=0.0, + l1=log(getfreqx(0.0)*ctlcenter), + l2=log(2.0)*getoctavesfreq()*ctlbw; + + for (int i=0;i<N_RES_POINTS;i++) if (sum<Prespoints[i]) sum=Prespoints[i]; + if (sum<1.0) sum=1.0; + + for (int i=1;i<n;i++){ + REALTYPE x=(log(freq*i)-l1)/l2;//compute where the n-th hamonics fits to the graph + if (x<0.0) x=0.0; + + x*=N_RES_POINTS; + REALTYPE dx=x-floor(x);x=floor(x); + int kx1=(int)x; if (kx1>=N_RES_POINTS) kx1=N_RES_POINTS-1; + int kx2=kx1+1;if (kx2>=N_RES_POINTS) kx2=N_RES_POINTS-1; + REALTYPE y=(Prespoints[kx1]*(1.0-dx)+Prespoints[kx2]*dx)/127.0-sum/127.0; + + y=pow(10.0,y*PmaxdB/20.0); + + if ((Pprotectthefundamental!=0)&&(i==1)) y=1.0; + + fftdata.c[i]*=y; + fftdata.s[i]*=y; + }; +}; + +/* + * Gets the response at the frequency "freq" + */ + +REALTYPE Resonance::getfreqresponse(REALTYPE freq){ + REALTYPE l1=log(getfreqx(0.0)*ctlcenter), + l2=log(2.0)*getoctavesfreq()*ctlbw,sum=0.0; + + for (int i=0;i<N_RES_POINTS;i++) if (sum<Prespoints[i]) sum=Prespoints[i]; + if (sum<1.0) sum=1.0; + + REALTYPE x=(log(freq)-l1)/l2;//compute where the n-th hamonics fits to the graph + if (x<0.0) x=0.0; + x*=N_RES_POINTS; + REALTYPE dx=x-floor(x);x=floor(x); + int kx1=(int)x; if (kx1>=N_RES_POINTS) kx1=N_RES_POINTS-1; + int kx2=kx1+1;if (kx2>=N_RES_POINTS) kx2=N_RES_POINTS-1; + REALTYPE result=(Prespoints[kx1]*(1.0-dx)+Prespoints[kx2]*dx)/127.0-sum/127.0; + result=pow(10.0,result*PmaxdB/20.0); + return(result); +}; + + +/* + * Smooth the resonance function + */ +void Resonance::smooth(){ + REALTYPE old=Prespoints[0]; + for (int i=0;i<N_RES_POINTS;i++){ + old=old*0.4+Prespoints[i]*0.6; + Prespoints[i]=(int) old; + }; + old=Prespoints[N_RES_POINTS-1]; + for (int i=N_RES_POINTS-1;i>0;i--){ + old=old*0.4+Prespoints[i]*0.6; + Prespoints[i]=(int) old+1; + if (Prespoints[i]>127) Prespoints[i]=127; + }; +}; + +/* + * Randomize the resonance function + */ +void Resonance::randomize(int type){ + int r=(int)(RND*127.0); + for (int i=0;i<N_RES_POINTS;i++){ + Prespoints[i]=r; + if ((RND<0.1)&&(type==0)) r=(int)(RND*127.0); + if ((RND<0.3)&&(type==1)) r=(int)(RND*127.0); + if (type==2) r=(int)(RND*127.0); + }; + smooth(); +}; + +/* + * Interpolate the peaks + */ +void Resonance::interpolatepeaks(int type){ + int x1=0,y1=Prespoints[0]; + for (int i=1;i<N_RES_POINTS;i++){ + if ((Prespoints[i]!=64)||(i+1==N_RES_POINTS)){ + int y2=Prespoints[i]; + for (int k=0;k<i-x1;k++){ + float x=(float) k/(i-x1); + if (type==0) x=(1-cos(x*PI))*0.5; + Prespoints[x1+k]=(int)(y1*(1.0-x)+y2*x); + }; + x1=i; + y1=y2; + }; + }; +}; + +/* + * Get the frequency from x, where x is [0..1]; x is the x coordinate + */ +REALTYPE Resonance::getfreqx(REALTYPE x){ + if (x>1.0) x=1.0; + REALTYPE octf=pow(2.0,getoctavesfreq()); + return(getcenterfreq()/sqrt(octf)*pow(octf,x)); +}; + +/* + * Get the x coordinate from frequency (used by the UI) + */ +REALTYPE Resonance::getfreqpos(REALTYPE freq){ + return((log(freq)-log(getfreqx(0.0)))/log(2.0)/getoctavesfreq()); +}; + +/* + * Get the center frequency of the resonance graph + */ +REALTYPE Resonance::getcenterfreq(){ + return(10000.0*pow(10,-(1.0-Pcenterfreq/127.0)*2.0)); +}; + +/* + * Get the number of octave that the resonance functions applies to + */ +REALTYPE Resonance::getoctavesfreq(){ + return(0.25+10.0*Poctavesfreq/127.0); +}; + +void Resonance::sendcontroller(MidiControllers ctl,REALTYPE par){ + if (ctl==C_resonance_center) ctlcenter=par; + else ctlbw=par; +}; + + + + +void Resonance::add2XML(XMLwrapper *xml){ + xml->addparbool("enabled",Penabled); + + if ((Penabled==0)&&(xml->minimal)) return; + + xml->addpar("max_db",PmaxdB); + xml->addpar("center_freq",Pcenterfreq); + xml->addpar("octaves_freq",Poctavesfreq); + xml->addparbool("protect_fundamental_frequency",Pprotectthefundamental); + xml->addpar("resonance_points",N_RES_POINTS); + for (int i=0;i<N_RES_POINTS;i++){ + xml->beginbranch("RESPOINT",i); + xml->addpar("val",Prespoints[i]); + xml->endbranch(); + }; +}; + + +void Resonance::getfromXML(XMLwrapper *xml){ + Penabled=xml->getparbool("enabled",Penabled); + + PmaxdB=xml->getpar127("max_db",PmaxdB); + Pcenterfreq=xml->getpar127("center_freq",Pcenterfreq); + Poctavesfreq=xml->getpar127("octaves_freq",Poctavesfreq); + Pprotectthefundamental=xml->getparbool("protect_fundamental_frequency",Pprotectthefundamental); + for (int i=0;i<N_RES_POINTS;i++){ + if (xml->enterbranch("RESPOINT",i)==0) continue; + Prespoints[i]=xml->getpar127("val",Prespoints[i]); + xml->exitbranch(); + }; +}; + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.h new file mode 100644 index 00000000..7b09e295 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/Resonance.h @@ -0,0 +1,68 @@ +/* + ZynAddSubFX - a software synthesizer + + Resonance.h - Resonance + 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 + +*/ +#ifndef RESONANCE_H +#define RESONANCE_H + +#include "../globals.h" +#include "../Misc/Util.h" +#include "../Misc/XMLwrapper.h" +#include "../Params/Presets.h" + +#define N_RES_POINTS 256 + +class Resonance:public Presets{ + public: + Resonance(); + ~Resonance(); + void setpoint(int n,unsigned char p); + void applyres(int n,FFTFREQS fftdata,REALTYPE freq); + void smooth(); + void interpolatepeaks(int type); + void randomize(int type); + + void add2XML(XMLwrapper *xml); + void defaults(); + void getfromXML(XMLwrapper *xml); + + + REALTYPE getfreqpos(REALTYPE freq); + REALTYPE getfreqx(REALTYPE x); + REALTYPE getfreqresponse(REALTYPE freq); + REALTYPE getcenterfreq(); + REALTYPE getoctavesfreq(); + void sendcontroller(MidiControllers ctl,REALTYPE par); + + //parameters + unsigned char Penabled; //if the ressonance is enabled + unsigned char Prespoints[N_RES_POINTS]; //how many points define the resonance function + unsigned char PmaxdB; //how many dB the signal may be amplified + unsigned char Pcenterfreq,Poctavesfreq; //the center frequency of the res. func., and the number of octaves + unsigned char Pprotectthefundamental; //the fundamental (1-st harmonic) is not damped, even it resonance function is low + + //controllers + REALTYPE ctlcenter;//center frequency(relative) + REALTYPE ctlbw;//bandwidth(relative) + + private: +}; + +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.C b/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.C new file mode 100644 index 00000000..f198ba04 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.C @@ -0,0 +1,419 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnote.C - The "subtractive" 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 "SUBnote.h" +#include "../Misc/Util.h" + +SUBnote::SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote){ + ready=0; + + tmpsmp=new REALTYPE[SOUND_BUFFER_SIZE]; + tmprnd=new REALTYPE[SOUND_BUFFER_SIZE]; + + pars=parameters; + ctl=ctl_; + portamento=portamento_; + NoteEnabled=ON; + volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB + volume*=VelF(velocity,pars->PAmpVelocityScaleFunction); + if (pars->PPanning!=0) panning=pars->PPanning/127.0; + else panning=RND; + numstages=pars->Pnumstages; + stereo=pars->Pstereo; + start=pars->Pstart; + firsttick=1; + int pos[MAX_SUB_HARMONICS]; + + 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); + }; + + }; + REALTYPE detune=getdetune(pars->PDetuneType,pars->PCoarseDetune,pars->PDetune); + basefreq*=pow(2.0,detune/1200.0);//detune +// basefreq*=ctl->pitchwheel.relfreq;//pitch wheel + + //global filter + GlobalFilterCenterPitch=pars->GlobalFilter->getfreq()+//center freq + (pars->PGlobalFilterVelocityScale/127.0*6.0)* //velocity sensing + (VelF(velocity,pars->PGlobalFilterVelocityScaleFunction)-1); + + GlobalFilterL=NULL;GlobalFilterR=NULL; + GlobalFilterEnvelope=NULL; + + //select only harmonics that desire to compute + numharmonics=0; + for (int n=0;n<MAX_SUB_HARMONICS;n++){ + if (pars->Phmag[n]==0)continue; + if (n*basefreq>SAMPLE_RATE/2.0) break;//remove the freqs above the Nyquist freq + pos[numharmonics++]=n; + }; + + if (numharmonics==0) { + NoteEnabled=OFF; + return; + }; + + + lfilter=new bpfilter[numstages*numharmonics]; + if (stereo!=0) rfilter=new bpfilter[numstages*numharmonics]; + + //how much the amplitude is normalised (because the harmonics) + REALTYPE reduceamp=0.0; + + for (int n=0;n<numharmonics;n++){ + + REALTYPE freq=basefreq*(pos[n]+1); + + //the bandwidth is not absolute(Hz); it is relative to frequency + REALTYPE bw=pow(10,(pars->Pbandwidth-127.0)/127.0*4)*numstages; + + //Bandwidth Scale + bw*=pow(1000/freq,(pars->Pbwscale-64.0)/64.0*3.0); + + //Relative BandWidth + bw*=pow(100,(pars->Phrelbw[pos[n]]-64.0)/64.0); + + if (bw>25.0) bw=25.0; + + //try to keep same amplitude on all freqs and bw. (empirically) + REALTYPE gain=sqrt(1500.0/(bw*freq)); + + REALTYPE hmagnew=1.0-pars->Phmag[pos[n]]/127.0; + REALTYPE hgain; + + switch(pars->Phmagtype){ + case 1:hgain=exp(hmagnew*log(0.01)); break; + case 2:hgain=exp(hmagnew*log(0.001));break; + case 3:hgain=exp(hmagnew*log(0.0001));break; + case 4:hgain=exp(hmagnew*log(0.00001));break; + default:hgain=1.0-hmagnew; + }; + gain*=hgain; + reduceamp+=hgain; + + for (int nph=0;nph<numstages;nph++){ + REALTYPE amp=1.0; + if (nph==0) amp=gain; + initfilter(lfilter[nph+n*numstages],freq,bw,amp,hgain); + if (stereo!=0) initfilter(rfilter[nph+n*numstages],freq,bw,amp,hgain); + }; + }; + + if (reduceamp<0.001) reduceamp=1.0; + volume/=reduceamp; + + oldpitchwheel=0; + oldbandwidth=64; + if (pars->Pfixedfreq==0) initparameters(basefreq); + else initparameters(basefreq/440.0*freq); + + oldamplitude=newamplitude; + ready=1; +}; + +SUBnote::~SUBnote(){ + if (NoteEnabled!=OFF) KillNote(); + delete [] tmpsmp; + delete [] tmprnd; +}; + +/* + * Kill the note + */ +void SUBnote::KillNote(){ + if (NoteEnabled!=OFF){ + delete [] lfilter; + lfilter=NULL; + if (stereo!=0) delete [] rfilter; + rfilter=NULL; + delete(AmpEnvelope); + if (FreqEnvelope!=NULL) delete(FreqEnvelope); + if (BandWidthEnvelope!=NULL) delete(BandWidthEnvelope); + NoteEnabled=OFF; + }; + +}; + + +/* + * Compute the filters coefficients + */ +void SUBnote::computefiltercoefs(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE gain){ + if (freq>SAMPLE_RATE/2.0-200.0) { + freq=SAMPLE_RATE/2.0-200.0; + }; + + REALTYPE omega=2.0*PI*freq/SAMPLE_RATE; + REALTYPE sn=sin(omega);REALTYPE cs=cos(omega); + REALTYPE alpha=sn*sinh(LOG_2/2.0*bw*omega/sn); + + if (alpha>1) alpha=1; + if (alpha>bw) alpha=bw; + + filter.b0=alpha/(1.0+alpha)*filter.amp*gain; + filter.b2=-alpha/(1.0+alpha)*filter.amp*gain; + filter.a1=-2.0*cs/(1.0+alpha); + filter.a2=(1.0-alpha)/(1.0+alpha); + +}; + + +/* + * Initialise the filters + */ +void SUBnote::initfilter(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE amp,REALTYPE mag){ + filter.xn1=0.0;filter.xn2=0.0; + + if (start==0) { + filter.yn1=0.0; + filter.yn2=0.0; + } else { + REALTYPE a=0.1*mag;//empirically + REALTYPE p=RND*2.0*PI; + if (start==1) a*=RND; + filter.yn1=a*cos(p); + filter.yn2=a*cos(p+freq*2.0*PI/SAMPLE_RATE); + + //correct the error of computation the start amplitude + //at very high frequencies + if (freq>SAMPLE_RATE*0.96) { + filter.yn1=0.0; + filter.yn2=0.0; + + }; + }; + + filter.amp=amp; + filter.freq=freq; + filter.bw=bw; + computefiltercoefs(filter,freq,bw,1.0); +}; + +/* + * Do the filtering + */ +void SUBnote::filter(bpfilter &filter,REALTYPE *smps){ + int i; + REALTYPE out; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + out=smps[i] * filter.b0 + filter.b2 * filter.xn2 + -filter.a1 * filter.yn1 - filter.a2 * filter.yn2; + filter.xn2=filter.xn1; + filter.xn1=smps[i]; + filter.yn2=filter.yn1; + filter.yn1=out; + smps[i]=out; + + }; +}; + +/* + * Init Parameters + */ +void SUBnote::initparameters(REALTYPE freq){ + AmpEnvelope=new Envelope(pars->AmpEnvelope,freq); + if (pars->PFreqEnvelopeEnabled!=0) FreqEnvelope=new Envelope(pars->FreqEnvelope,freq); + else FreqEnvelope=NULL; + if (pars->PBandWidthEnvelopeEnabled!=0) BandWidthEnvelope=new Envelope(pars->BandWidthEnvelope,freq); + else BandWidthEnvelope=NULL; + if (pars->PGlobalFilterEnabled!=0){ + globalfiltercenterq=pars->GlobalFilter->getq(); + GlobalFilterL=new Filter(pars->GlobalFilter); + if (stereo!=0) GlobalFilterR=new Filter(pars->GlobalFilter); + GlobalFilterEnvelope=new Envelope(pars->GlobalFilterEnvelope,freq); + GlobalFilterFreqTracking=pars->GlobalFilter->getfreqtracking(basefreq); + }; + computecurrentparameters(); +}; + + +/* + * Compute Parameters of SUBnote for each tick + */ +void SUBnote::computecurrentparameters(){ + if ((FreqEnvelope!=NULL)||(BandWidthEnvelope!=NULL)|| + (oldpitchwheel!=ctl->pitchwheel.data)|| + (oldbandwidth!=ctl->bandwidth.data)|| + (portamento!=0)){ + REALTYPE envfreq=1.0; + REALTYPE envbw=1.0; + REALTYPE gain=1.0; + + if (FreqEnvelope!=NULL) { + envfreq=FreqEnvelope->envout()/1200; + envfreq=pow(2.0,envfreq); + }; + envfreq*=ctl->pitchwheel.relfreq;//pitch wheel + if (portamento!=0) {//portamento is used + envfreq*=ctl->portamento.freqrap; + if (ctl->portamento.used==0){//the portamento has finished + portamento=0;//this note is no longer "portamented" + }; + }; + + if (BandWidthEnvelope!=NULL) { + envbw=BandWidthEnvelope->envout(); + envbw=pow(2,envbw); + }; + envbw*=ctl->bandwidth.relbw;//bandwidth controller + + REALTYPE tmpgain=1.0/sqrt(envbw*envfreq); + + for (int n=0;n<numharmonics;n++){ + for (int nph=0;nph<numstages;nph++) { + if (nph==0) gain=tmpgain;else gain=1.0; + computefiltercoefs( lfilter[nph+n*numstages], + lfilter[nph+n*numstages].freq*envfreq, + lfilter[nph+n*numstages].bw*envbw,gain); + }; + }; + if (stereo!=0) + for (int n=0;n<numharmonics;n++){ + for (int nph=0;nph<numstages;nph++) { + if (nph==0) gain=tmpgain;else gain=1.0; + computefiltercoefs( rfilter[nph+n*numstages], + rfilter[nph+n*numstages].freq*envfreq, + rfilter[nph+n*numstages].bw*envbw,gain); + }; + }; + oldbandwidth=ctl->bandwidth.data; + oldpitchwheel=ctl->pitchwheel.data; + }; + newamplitude=volume*AmpEnvelope->envout_dB()*2.0; + + //Filter + if (GlobalFilterL!=NULL){ + REALTYPE globalfilterpitch=GlobalFilterCenterPitch+GlobalFilterEnvelope->envout(); + REALTYPE filterfreq=globalfilterpitch+ctl->filtercutoff.relfreq+GlobalFilterFreqTracking; + filterfreq=GlobalFilterL->getrealfreq(filterfreq); + + GlobalFilterL->setfreq_and_q(filterfreq,globalfiltercenterq*ctl->filterq.relq); + if (GlobalFilterR!=NULL) GlobalFilterR->setfreq_and_q(filterfreq,globalfiltercenterq*ctl->filterq.relq); + }; + +}; + +/* + * Note Output + */ +int SUBnote::noteout(REALTYPE *outl,REALTYPE *outr){ + int i; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + outl[i]=denormalkillbuf[i]; + outr[i]=denormalkillbuf[i]; + }; + + if (NoteEnabled==OFF) return(0); + + //left channel + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmprnd[i]=RND*2.0-1.0; + for (int n=0;n<numharmonics;n++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpsmp[i]=tmprnd[i]; + for (int nph=0;nph<numstages;nph++) + filter(lfilter[nph+n*numstages],tmpsmp); + for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpsmp[i]; + }; + + if (GlobalFilterL!=NULL) GlobalFilterL->filterout(&outl[0]); + + //right channel + if (stereo!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmprnd[i]=RND*2.0-1.0; + for (int n=0;n<numharmonics;n++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpsmp[i]=tmprnd[i]; + for (int nph=0;nph<numstages;nph++) + filter(rfilter[nph+n*numstages],tmpsmp); + for (i=0;i<SOUND_BUFFER_SIZE;i++) outr[i]+=tmpsmp[i]; + }; + if (GlobalFilterR!=NULL) GlobalFilterR->filterout(&outr[0]); + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) outr[i]=outl[i]; + + if (firsttick!=0){ + int n=10;if (n>SOUND_BUFFER_SIZE) n=SOUND_BUFFER_SIZE; + for (i=0;i<n;i++) { + REALTYPE ampfadein=0.5-0.5*cos((REALTYPE) i/(REALTYPE) n*PI); + outl[i]*=ampfadein; + outr[i]*=ampfadein; + }; + firsttick=0; + }; + + if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude,newamplitude)){ + // Amplitude interpolation + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE tmpvol=INTERPOLATE_AMPLITUDE(oldamplitude + ,newamplitude,i,SOUND_BUFFER_SIZE); + outl[i]*=tmpvol*panning; + outr[i]*=tmpvol*(1.0-panning); + }; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=newamplitude*panning; + outr[i]*=newamplitude*(1.0-panning); + }; + }; + + oldamplitude=newamplitude; + computecurrentparameters(); + + // Check if the note needs to be computed more + if (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 Key (Note Off) + */ +void SUBnote::relasekey(){ + AmpEnvelope->relasekey(); + if (FreqEnvelope!=NULL) FreqEnvelope->relasekey(); + if (BandWidthEnvelope!=NULL) BandWidthEnvelope->relasekey(); + if (GlobalFilterEnvelope!=NULL) GlobalFilterEnvelope->relasekey(); +}; + +/* + * Check if the note is finished + */ +int SUBnote::finished(){ + if (NoteEnabled==OFF) return(1); + else return(0); +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.h b/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.h new file mode 100644 index 00000000..6e4e2991 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Synth/SUBnote.h @@ -0,0 +1,98 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnote.h - The subtractive 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 + +*/ + +#ifndef SUB_NOTE_H +#define SUB_NOTE_H + +#include "../globals.h" +#include "../Params/SUBnoteParameters.h" +#include "../Params/Controller.h" +#include "Envelope.h" +#include "../DSP/Filter.h" + +class SUBnote{ + public: + SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote); + ~SUBnote(); + int noteout(REALTYPE *outl,REALTYPE *outr);//note output,return 0 if the note is finished + void relasekey(); + int finished(); + + int ready; //if I can get the sampledata + + private: + + void computecurrentparameters(); + void initparameters(REALTYPE freq); + void KillNote(); + + SUBnoteParameters *pars; + + //parameters + int stereo; + int numstages;//number of stages of filters + int numharmonics;//number of harmonics (after the too higher hamonics are removed) + int start;//how the harmonics start + REALTYPE basefreq; + REALTYPE panning; + Envelope *AmpEnvelope; + Envelope *FreqEnvelope; + Envelope *BandWidthEnvelope; + + Filter *GlobalFilterL,*GlobalFilterR; + + Envelope *GlobalFilterEnvelope; + + //internal values + ONOFFTYPE NoteEnabled; + int firsttick,portamento; + REALTYPE volume,oldamplitude,newamplitude; + + REALTYPE GlobalFilterCenterPitch;//octaves + REALTYPE GlobalFilterFreqTracking; + + struct bpfilter{ + REALTYPE freq,bw,amp; //filter parameters + REALTYPE a1,a2,b0,b2;//filter coefs. b1=0 + REALTYPE xn1,xn2,yn1,yn2; //filter internal values + }; + + void initfilter(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE amp,REALTYPE mag); + void computefiltercoefs(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE gain); + void filter(bpfilter &filter,REALTYPE *smps); + + bpfilter *lfilter,*rfilter; + + REALTYPE *tmpsmp; + REALTYPE *tmprnd;//this is filled with random numbers + + Controller *ctl; + int oldpitchwheel,oldbandwidth; + REALTYPE globalfiltercenterq; + +}; + + + + +#endif + |