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:
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;