zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit ae7d0b438ab9082d32b3e551657fab1012d9d2c3
parent 5bf008e390b86944b8175c21f2a021a4d6863de2
Author: Paul <nop@nop-desktop.(none)>
Date:   Mon, 21 Sep 2009 00:03:56 +0300

Started to add the unison effect to ADsynth

Diffstat:
Msrc/Synth/ADnote.cpp | 585+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/Synth/ADnote.h | 25++++++++++++++++++-------
2 files changed, 397 insertions(+), 213 deletions(-)

diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -33,7 +33,8 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve { ready=0; - tmpwave=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpwavel=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpwaver=new REALTYPE [SOUND_BUFFER_SIZE]; bypassl=new REALTYPE [SOUND_BUFFER_SIZE]; bypassr=new REALTYPE [SOUND_BUFFER_SIZE]; @@ -83,18 +84,40 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve } else NoteGlobalPar.Punch.Enabled=0; for (int nvoice=0;nvoice<NUM_VOICES;nvoice++) { - pars->VoicePar[nvoice].OscilSmp->newrandseed(rand()); + pars->VoicePar[nvoice].OscilSmp->newrandseed(rand()); NoteVoicePar[nvoice].OscilSmp=NULL; NoteVoicePar[nvoice].FMSmp=NULL; NoteVoicePar[nvoice].VoiceOut=NULL; NoteVoicePar[nvoice].FMVoice=-1; + unison_size[nvoice]=1; if (pars->VoicePar[nvoice].Enabled==0) { NoteVoicePar[nvoice].Enabled=OFF; continue; //the voice is disabled }; +#warning get from parameter + int unison=30; + unison_size[nvoice]=unison; + + unison_freq_rap[nvoice]=new REALTYPE[unison]; + for (int k=0;k<unison;k++){ + unison_freq_rap[nvoice][k]=1.0*pow(1.0001,k); + }; + + if (unison==1) unison_freq_rap[nvoice][0]=1.0;//if the unison is not used, always make the only subvoice to have the default note + + + oscfreqhi[nvoice]=new int[unison]; + oscfreqlo[nvoice]=new REALTYPE[unison]; + oscfreqhiFM[nvoice]=new unsigned int[unison]; + oscfreqloFM[nvoice]=new REALTYPE[unison]; + oscposhi[nvoice]=new int[unison]; + oscposlo[nvoice]=new REALTYPE[unison]; + oscposhiFM[nvoice]=new unsigned int[unison]; + oscposloFM[nvoice]=new REALTYPE[unison]; + NoteVoicePar[nvoice].Enabled=ON; NoteVoicePar[nvoice].fixedfreq=pars->VoicePar[nvoice].Pfixedfreq; NoteVoicePar[nvoice].fixedfreqET=pars->VoicePar[nvoice].PfixedfreqET; @@ -119,10 +142,13 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve ,pars->VoicePar[nvoice].PFMCoarseDetune,pars->VoicePar[nvoice].PFMDetune); }; - oscposhi[nvoice]=0; - oscposlo[nvoice]=0.0; - oscposhiFM[nvoice]=0; - oscposloFM[nvoice]=0.0; + + for (int k=0;k<unison;k++){ + oscposhi[nvoice][k]=0; + oscposlo[nvoice][k]=0.0; + oscposhiFM[nvoice][k]=0; + oscposloFM[nvoice][k]=0.0; + }; NoteVoicePar[nvoice].OscilSmp=new REALTYPE[OSCIL_SIZE+OSCIL_SMP_EXTRA_SAMPLES];//the extra points contains the first point @@ -130,15 +156,18 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve 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); + int oscposhi_start=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; + oscposhi_start+=(int)((pars->VoicePar[nvoice].Poscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + oscposhi_start%=OSCIL_SIZE; + for (int k=0;k<unison;k++){ + oscposhi[nvoice][k]=oscposhi_start; + oscposhi_start=(int)(RND*(OSCIL_SIZE-1));//put random starting point for other subvoices + }; NoteVoicePar[nvoice].FreqLfo=NULL; NoteVoicePar[nvoice].FreqEnvelope=NULL; @@ -146,7 +175,8 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve NoteVoicePar[nvoice].AmpLfo=NULL; NoteVoicePar[nvoice].AmpEnvelope=NULL; - NoteVoicePar[nvoice].VoiceFilter=NULL; + NoteVoicePar[nvoice].VoiceFilterL=NULL; + NoteVoicePar[nvoice].VoiceFilterR=NULL; NoteVoicePar[nvoice].FilterEnvelope=NULL; NoteVoicePar[nvoice].FilterLfo=NULL; @@ -197,17 +227,30 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve //Voice's modulator velocity sensing NoteVoicePar[nvoice].FMVolume*=VelF(velocity,partparams->VoicePar[nvoice].PFMVelocityScaleFunction); - FMoldsmp[nvoice]=0.0;//this is for FM (integration) + FMoldsmp[nvoice]=new REALTYPE [unison]; + for (int k=0;k<unison;k++) FMoldsmp[nvoice][k]=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); + + }; + max_unison=1; + for (int nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (unison_size[nvoice]>max_unison) max_unison=unison_size[nvoice]; + }; + + tmpwave_unison=new REALTYPE*[max_unison]; + for (int k=0;k<max_unison;k++){ + tmpwave_unison[k]=new REALTYPE[SOUND_BUFFER_SIZE]; + for (int i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave_unison[k][i]=0.0; + }; + initparameters(); ready=1; }; - // ADlegatonote: This function is (mostly) a copy of ADnote(...) and // initparameters() stuck together with some lines removed so that it // only alter the already playing note (to perform legato). It is @@ -290,7 +333,6 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int 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); pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp,getvoicebasefreq(nvoice),pars->VoicePar[nvoice].Presonance);//(gf)Modif of the above line. //I store the first elments to the last position for speedups @@ -325,6 +367,10 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int NoteVoicePar[nvoice].FMVolume*=VelF(velocity,partparams->VoicePar[nvoice].PFMVelocityScaleFunction); NoteVoicePar[nvoice].DelayTicks=(int)((exp(pars->VoicePar[nvoice].PDelay/127.0*log(50.0))-1.0)/SOUND_BUFFER_SIZE/10.0*SAMPLE_RATE); + + +#warning TODO: ADD HERE THE CODE FOR UNISON + }; /// initparameters(); @@ -426,22 +472,36 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int void ADnote::KillVoice(int nvoice) { - delete []NoteVoicePar[nvoice].OscilSmp; + delete []oscfreqhi[nvoice]; + delete []oscfreqlo[nvoice]; + delete []oscfreqhiFM[nvoice]; + delete []oscfreqloFM[nvoice]; + delete []oscposhi[nvoice]; + delete []oscposlo[nvoice]; + delete []oscposhiFM[nvoice]; + delete []oscposloFM[nvoice]; - if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); - NoteVoicePar[nvoice].FreqEnvelope=NULL; + delete []NoteVoicePar[nvoice].OscilSmp; + delete []unison_freq_rap[nvoice]; + delete []FMoldsmp[nvoice]; - if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo); - NoteVoicePar[nvoice].FreqLfo=NULL; + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); + NoteVoicePar[nvoice].FreqEnvelope=NULL; - if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope); + 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].VoiceFilterL!=NULL) delete (NoteVoicePar[nvoice].VoiceFilterL); + NoteVoicePar[nvoice].VoiceFilterL=NULL; + + if (NoteVoicePar[nvoice].VoiceFilterR!=NULL) delete (NoteVoicePar[nvoice].VoiceFilterR); + NoteVoicePar[nvoice].VoiceFilterR=NULL; if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) delete (NoteVoicePar[nvoice].FilterEnvelope); NoteVoicePar[nvoice].FilterEnvelope=NULL; @@ -492,9 +552,14 @@ void ADnote::KillNote() ADnote::~ADnote() { if (NoteEnabled==ON) KillNote(); - delete [] tmpwave; + delete [] tmpwavel; + delete [] tmpwaver; delete [] bypassl; delete [] bypassr; + for (int k=0;k<max_unison;k++) delete[]tmpwave_unison[k]; + delete[]tmpwave_unison; + + }; @@ -564,7 +629,8 @@ void ADnote::initparameters() /* Voice Filter Parameters Init */ if (partparams->VoicePar[nvoice].PFilterEnabled!=0) { - NoteVoicePar[nvoice].VoiceFilter=new Filter(partparams->VoicePar[nvoice].VoiceFilter); + NoteVoicePar[nvoice].VoiceFilterL=new Filter(partparams->VoicePar[nvoice].VoiceFilter); + NoteVoicePar[nvoice].VoiceFilterR=new Filter(partparams->VoicePar[nvoice].VoiceFilter); }; if (partparams->VoicePar[nvoice].PFilterEnvelopeEnabled!=0) @@ -593,10 +659,15 @@ void ADnote::initparameters() }; 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 k=0;k<unison_size[nvoice];k++){ + oscposhiFM[nvoice][k]=(oscposhi[nvoice][k]+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; + int oscposhiFM_add=(int)((partparams->VoicePar[nvoice].PFMoscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + for (int k=0;k<unison_size[nvoice];k++){ + oscposhiFM[nvoice][k]+=oscposhiFM_add; + oscposhiFM[nvoice][k]%=OSCIL_SIZE; + }; }; if (partparams->VoicePar[nvoice].PFMFreqEnvelopeEnabled!=0) @@ -628,13 +699,15 @@ void ADnote::initparameters() */ 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); + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE speed; + freq=fabs(freq)*unison_freq_rap[nvoice][k]; + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhi[nvoice][k]); + oscfreqlo[nvoice][k]=speed-floor(speed); + }; }; /* @@ -642,13 +715,15 @@ void ADnote::setfreq(int nvoice,REALTYPE freq) */ 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); + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE speed; + freq=fabs(freq)*unison_freq_rap[nvoice][k]; + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhiFM[nvoice][k]); + oscfreqloFM[nvoice][k]=speed-floor(speed); + }; }; /* @@ -736,7 +811,7 @@ void ADnote::computecurrentparameters() /****************/ /* Voice Filter */ /****************/ - if (NoteVoicePar[nvoice].VoiceFilter!=NULL) { + if (NoteVoicePar[nvoice].VoiceFilterL!=NULL) { filterpitch=NoteVoicePar[nvoice].FilterCenterPitch; if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) @@ -746,9 +821,10 @@ void ADnote::computecurrentparameters() filterpitch+=NoteVoicePar[nvoice].FilterLfo->lfoout(); filterfreq=filterpitch+NoteVoicePar[nvoice].FilterFreqTracking; - filterfreq=NoteVoicePar[nvoice].VoiceFilter->getrealfreq(filterfreq); + filterfreq=NoteVoicePar[nvoice].VoiceFilterL->getrealfreq(filterfreq); - NoteVoicePar[nvoice].VoiceFilter->setfreq(filterfreq); + NoteVoicePar[nvoice].VoiceFilterL->setfreq(filterfreq); + if (stereo&&NoteVoicePar[nvoice].VoiceFilterR) NoteVoicePar[nvoice].VoiceFilterR->setfreq(filterfreq); }; if (NoteVoicePar[nvoice].noisetype==0) {//compute only if the voice isn't noise @@ -815,22 +891,27 @@ 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; + + for (int k=0;k<unison_size[nvoice];k++){ + poshi=oscposhi[nvoice][k]; + poslo=oscposlo[nvoice][k]; + int freqhi=oscfreqhi[nvoice][k]; + REALTYPE freqlo=oscfreqlo[nvoice][k]; + REALTYPE *smps=NoteVoicePar[nvoice].OscilSmp; + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tw[i]=smps[poshi]*(1.0-poslo)+smps[poshi+1]*poslo; + poslo+=freqlo; + if (poslo>=1.0) { + poslo-=1.0; + poshi++; + }; + poshi+=freqhi; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice][k]=poshi; + oscposlo[nvoice][k]=poslo; + }; }; @@ -881,35 +962,43 @@ inline void ADnote::ComputeVoiceOscillatorMorph(int 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; - }; + if (NoteVoicePar[nvoice].FMVoice>=0) { + //if I use VoiceOut[] as modullator + int FMVoice=NoteVoicePar[nvoice].FMVoice; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tw[i]=tw[i]*(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + }; + } else { + for (int k=0;k<unison_size[nvoice];k++){ + int poshiFM=oscposhiFM[nvoice][k]; + REALTYPE posloFM=oscposloFM[nvoice][k]; + int freqhiFM=oscfreqhiFM[nvoice][k]; + REALTYPE freqloFM=oscfreqloFM[nvoice][k]; + REALTYPE *tw=tmpwave_unison[k]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tw[i]=tw[i]*(1.0-amp)+amp + *(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=freqloFM; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=freqhiFM; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice][k]=poshiFM; + oscposloFM[nvoice][k]=posloFM; + }; + }; }; /* @@ -922,36 +1011,44 @@ inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice) 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; - }; + if (NoteVoicePar[nvoice].FMVoice>=0) { + // if I use VoiceOut[] as modullator + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + 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++) + tw[i]*=(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + }; + } else { + for (int k=0;k<unison_size[nvoice];k++){ + int poshiFM=oscposhiFM[nvoice][k]; + REALTYPE posloFM=oscposloFM[nvoice][k]; + int freqhiFM=oscfreqhiFM[nvoice][k]; + REALTYPE freqloFM=oscfreqloFM[nvoice][k]; + REALTYPE *tw=tmpwave_unison[k]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tw[i]*=( NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM)*amp + +(1.0-amp); + posloFM+=freqloFM; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=freqhiFM; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice][k]=poshiFM; + oscposloFM[nvoice][k]=posloFM; + }; + }; }; @@ -961,80 +1058,116 @@ inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice) */ inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode) { - int carposhi; - int i,FMmodfreqhi; - REALTYPE FMmodfreqlo,carposlo; + int carposhi=0; + int i,FMmodfreqhi=0; + REALTYPE FMmodfreqlo=0,carposlo=0; 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; - }; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tw[i]=NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut[i]; + }; + } else { + //Compute the modulator and store it in tmpwave_unison[][] + for (int k=0;k<unison_size[nvoice];k++){ + int poshiFM=oscposhiFM[nvoice][k]; + REALTYPE posloFM=oscposloFM[nvoice][k]; + int freqhiFM=oscfreqhiFM[nvoice][k]; + REALTYPE freqloFM=oscfreqloFM[nvoice][k]; + REALTYPE *tw=tmpwave_unison[k]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tw[i]=(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=freqloFM; + if (posloFM>=1.0) { + posloFM=fmod(posloFM,1.0); + poshiFM++; + }; + poshiFM+=freqhiFM; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice][k]=poshiFM; + oscposloFM[nvoice][k]=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]; + if (ABOVE_AMPLITUDE_THRESHOLD(FMoldamplitude[nvoice],FMnewamplitude[nvoice])) { + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tw[i]*=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + }; + }; + } else { + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tw[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]; - }; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + REALTYPE fmold=FMoldsmp[nvoice][k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + fmold=fmod(fmold+tw[i]*normalize,OSCIL_SIZE); + tw[i]=fmold; + }; + FMoldsmp[nvoice][k]=fmold; + }; } else {//Phase modulation REALTYPE normalize=OSCIL_SIZE/262144.0; - for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=normalize; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tw[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; - }; + //do the modulation + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + int poshi=oscposhi[nvoice][k]; + REALTYPE poslo=oscposlo[nvoice][k]; + int freqhi=oscfreqhi[nvoice][k]; + REALTYPE freqlo=oscfreqlo[nvoice][k]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + F2I(tw[i],FMmodfreqhi); + FMmodfreqlo=fmod(tw[i]+0.0000000001,1.0); + if (FMmodfreqhi<0) FMmodfreqlo++; + + //carrier + carposhi=poshi+FMmodfreqhi; + carposlo=poslo+FMmodfreqlo; + + if (carposlo>=1.0) { + carposhi++; + carposlo=fmod(carposlo,1.0); + }; + carposhi&=(OSCIL_SIZE-1); + + tw[i]=NoteVoicePar[nvoice].OscilSmp[carposhi]*(1.0-carposlo) + +NoteVoicePar[nvoice].OscilSmp[carposhi+1]*carposlo; + + poslo+=freqlo; + if (poslo>=1.0) { + poslo=fmod(freqlo,1.0); + poshi++; + }; + + poshi+=freqhi; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice][k]=poshi; + oscposlo[nvoice][k]=poslo; + + }; }; @@ -1049,7 +1182,10 @@ inline void ADnote::ComputeVoiceOscillatorPitchModulation(int nvoice) */ inline void ADnote::ComputeVoiceNoise(int nvoice) { - for (int i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=RND*2.0-1.0; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + for (int i=0;i<SOUND_BUFFER_SIZE;i++) tw[i]=RND*2.0-1.0; + }; }; @@ -1101,60 +1237,97 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) } else ComputeVoiceNoise(nvoice); // Voice Processing + + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]=0.0; + if (stereo) for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwaver[i]=0.0; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE *tw=tmpwave_unison[k]; + if (stereo){ +#warning #make stereo mixing + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]+=tw[i]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwaver[i]+=tw[i]; + }else{ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]+=tw[i]; + }; + + }; + + + REALTYPE unison_amplitude=1.0/sqrt(unison_size[nvoice]);//reduce the amplitude for large unison sizes // Amplitude - if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude[nvoice],newamplitude[nvoice])) { + REALTYPE oldam=oldamplitude[nvoice]*unison_amplitude; + REALTYPE newam=newamplitude[nvoice]*unison_amplitude; + if (ABOVE_AMPLITUDE_THRESHOLD(oldam,newam)) { 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)) { + if ((newam>oldam)&&((newam-oldam)>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]; + for (int i=0;i<SOUND_BUFFER_SIZE-rest;i++) tmpwavel[i]*=oldam; + if (stereo) for (int i=0;i<SOUND_BUFFER_SIZE-rest;i++) tmpwaver[i]*=oldam; }; // Amplitude interpolation for (i=0;i<rest;i++) { - tmpwave[i+(SOUND_BUFFER_SIZE-rest)]*=INTERPOLATE_AMPLITUDE(oldamplitude[nvoice] - ,newamplitude[nvoice],i,rest); + REALTYPE amp=INTERPOLATE_AMPLITUDE(oldam,newam,i,rest); + tmpwavel[i+(SOUND_BUFFER_SIZE-rest)]*=amp; + if (stereo) tmpwaver[i+(SOUND_BUFFER_SIZE-rest)]*=amp; }; - } else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=newamplitude[nvoice]; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]*=newam; + if (stereo) for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwaver[i]*=newam; + }; // Fade in if (firsttick[nvoice]!=0) { - fadein(&tmpwave[0]); + fadein(&tmpwavel[0]); + if (stereo) fadein(&tmpwaver[0]); firsttick[nvoice]=0; }; // Filter - if (NoteVoicePar[nvoice].VoiceFilter!=NULL) NoteVoicePar[nvoice].VoiceFilter->filterout(&tmpwave[0]); + if (NoteVoicePar[nvoice].VoiceFilterL!=NULL) NoteVoicePar[nvoice].VoiceFilterL->filterout(&tmpwavel[0]); + if ((stereo)&&(NoteVoicePar[nvoice].VoiceFilterR!=NULL)) NoteVoicePar[nvoice].VoiceFilterR->filterout(&tmpwaver[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; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]*=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + if (stereo) for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwaver[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]; + if (NoteVoicePar[nvoice].VoiceOut!=NULL){ + if (stereo) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=tmpwavel[i]+tmpwaver[i]; + }else {//mono + for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=tmpwavel[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; - }; - }; + if (NoteVoicePar[nvoice].filterbypass==0) {//no bypass + if (stereo) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + outl[i]+=tmpwavel[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + outr[i]+=tmpwaver[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + }else{ + for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpwavel[i]*NoteVoicePar[nvoice].Volume;//mono + }; + } else {//bypass the filter + if (stereo) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + bypassl[i]+=tmpwavel[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + bypassr[i]+=tmpwaver[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + }else{ + for (i=0;i<SOUND_BUFFER_SIZE;i++) bypassl[i]+=tmpwavel[i]*NoteVoicePar[nvoice].Volume;//mono + }; + }; // 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); diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h @@ -178,7 +178,8 @@ private: * FILTER PARAMETERS * *************************/ - Filter *VoiceFilter; + Filter *VoiceFilterL; + Filter *VoiceFilterR; REALTYPE FilterCenterPitch;/* Filter center Pitch*/ REALTYPE FilterFreqTracking; @@ -206,6 +207,7 @@ private: Envelope *FMFreqEnvelope; Envelope *FMAmpEnvelope; + } NoteVoicePar[NUM_VOICES]; @@ -216,17 +218,23 @@ private: //time from the start of the note REALTYPE time; + //the size of unison for a single voice + int unison_size[NUM_VOICES]; + //fractional part (skip) - REALTYPE oscposlo[NUM_VOICES],oscfreqlo[NUM_VOICES]; + REALTYPE *oscposlo[NUM_VOICES],*oscfreqlo[NUM_VOICES]; //integer part (skip) - int oscposhi[NUM_VOICES],oscfreqhi[NUM_VOICES]; + int *oscposhi[NUM_VOICES],*oscfreqhi[NUM_VOICES]; //fractional part (skip) of the Modullator - REALTYPE oscposloFM[NUM_VOICES],oscfreqloFM[NUM_VOICES]; + REALTYPE *oscposloFM[NUM_VOICES],*oscfreqloFM[NUM_VOICES]; + + //how the unison subvoice's frequency is changed (1.0 for no change) + REALTYPE *unison_freq_rap[NUM_VOICES]; //integer part (skip) of the Modullator - unsigned short int oscposhiFM[NUM_VOICES],oscfreqhiFM[NUM_VOICES]; + unsigned int *oscposhiFM[NUM_VOICES],*oscfreqhiFM[NUM_VOICES]; //used to compute and interpolate the amplitudes of voices and modullators REALTYPE oldamplitude[NUM_VOICES], @@ -235,10 +243,13 @@ private: FMnewamplitude[NUM_VOICES]; //used by Frequency Modulation (for integration) - REALTYPE FMoldsmp[NUM_VOICES]; + REALTYPE *FMoldsmp[NUM_VOICES]; //temporary buffer - REALTYPE *tmpwave; + REALTYPE *tmpwavel; + REALTYPE *tmpwaver; + int max_unison; + REALTYPE **tmpwave_unison; //Filter bypass samples REALTYPE *bypassl,*bypassr;