zynaddsubfx

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

commit 93bb99e57561c5b72d2074a233c513e9da6bf9d4
parent 4f1d4f4c182aebb5bccefdb403011185cfaf5d62
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Thu, 24 Sep 2009 18:33:10 -0400

Merge branch 'master' of ssh://zynaddsubfx.git.sourceforge.net/gitroot/zynaddsubfx/zynaddsubfx

Conflicts:
	ChangeLog

Diffstat:
MChangeLog | 13++++++++++++-
Msrc/Effects/Reverb.cpp | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/Effects/Reverb.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/Params/ADnoteParameters.cpp | 30++++++++++++++++++++++++++----
Msrc/Params/ADnoteParameters.h | 7+++++++
Msrc/Synth/ADnote.cpp | 53++++++++++++++++++++++++++++++++++++++---------------
Msrc/Synth/ADnote.h | 3+++
Msrc/UI/ADnoteUI.fl | 47++++++++++++++++++++++++++++++++++-------------
Msrc/UI/EffUI.fl | 42+++++++++++++++++++++++++-----------------
9 files changed, 434 insertions(+), 76 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,4 +1,4 @@ -6 Mar 2002 -(dupamasa - in jur de ora 4) Mi-a venit ideea exact cum sa fac cand ma plimbam pe strada Rolirudnap +6 Mar 2002 -(dupamasa - in jur de ora 4) Mi-a venit ideea exact cum sa fac cand ma plimbam pe strada Pandurilor 7/8 Mar 2002 - Started to do diagrams 10 Mar 2002 - Started to write "voice" 11 Mar 2002 - Heard first sound @@ -903,3 +903,14 @@ - Changed temporary data for Oscilgen from static to instance recommended by Tobias Doerffel - Fixed Memory leaks in UI based upon James Morris' patch + +23 Sep 2009 (Paul Nasca) + - Added unison invert phase + - Made unison frequency spread to depend on Bandwidth controllers and parameters + - Added unison vibratto speed control and other improvements + - bugfixes: Voice Amplitude Envelope and FM + +24 Sep 2009 (Paul Nasca) + - Small enhancements and bugfixes to Unison + - Started to implement Bandwidth to the Reverb effect + diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp @@ -25,11 +25,121 @@ /**\todo: EarlyReflections,Prdelay,Perbalance */ +ReverbBandwidth::ReverbBandwidth (int small_buffer_size_,int n_small_buffers_per_half_big_buffer_): + OverlapAdd (small_buffer_size_,n_small_buffers_per_half_big_buffer_){ + bandwidth=0.1; + fft=new FFTwrapper(big_buffer_size); + newFFTFREQS(&freqs,half_big_buffer_size); + srcfreq=new REALTYPE[half_big_buffer_size]; + destfreq=new REALTYPE[half_big_buffer_size]; + tmpfreq=new REALTYPE[half_big_buffer_size]; + window=new REALTYPE[big_buffer_size]; + ZERO(srcfreq,half_big_buffer_size); + ZERO(destfreq,half_big_buffer_size); + ZERO(tmpfreq,half_big_buffer_size); + + for (int i=0;i<big_buffer_size;i++) window[i]=0.5*(1.0-cos(2*M_PI*i/(big_buffer_size-1.0))); +}; + +ReverbBandwidth::~ReverbBandwidth(){ + delete fft; + deleteFFTFREQS(&freqs); + delete []srcfreq; + delete []destfreq; + delete []tmpfreq; + delete []window; +}; + +void ReverbBandwidth::do_process_big_buffer(){ + + for (int i=0;i<big_buffer_size;i++) big_buffer[i]*=window[i]; + + fft->smps2freqs(big_buffer,freqs); + for (int i=0;i<half_big_buffer_size;i++){ + srcfreq[i]=sqrt(freqs.c[i]*freqs.c[i]+freqs.s[i]*freqs.s[i])/half_big_buffer_size; + }; + + + //spread + do_spread(half_big_buffer_size,srcfreq,destfreq,bandwidth); + + unsigned int rand_seed=rand(); + REALTYPE inv_2p15_2pi=1.0/16384.0*M_PI; + freqs.c[0]=freqs.s[0]=0.0; + for (int i=1;i<half_big_buffer_size;i++) { + rand_seed=(rand_seed*1103515245+12345); + unsigned int rand=(rand_seed>>16)&0x7fff; + REALTYPE phase=rand*inv_2p15_2pi; + freqs.c[i]=destfreq[i]*cos(phase); + freqs.s[i]=destfreq[i]*sin(phase); + }; + + + fft->freqs2smps(freqs,big_buffer); + for (int i=0;i<big_buffer_size;i++) big_buffer[i]*=window[i]; +}; + +void ReverbBandwidth::do_spread(int nfreq,REALTYPE *freq1,REALTYPE *freq2,REALTYPE bandwidth){ + //convert to log spectrum + REALTYPE minfreq=20.0; + REALTYPE maxfreq=0.5*SAMPLE_RATE; + + REALTYPE log_minfreq=log(minfreq); + REALTYPE log_maxfreq=log(maxfreq); + + for (int i=0;i<nfreq;i++){ + REALTYPE freqx=i/(REALTYPE) nfreq; + REALTYPE x=exp(log_minfreq+freqx*(log_maxfreq-log_minfreq))/maxfreq*nfreq; + REALTYPE y=0.0; + int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1; + int x1=x0+1; if (x1>=nfreq) x1=nfreq-1; + REALTYPE xp=x-x0; + if (x<nfreq){ + y=freq1[x0]*(1.0-xp)+freq1[x1]*xp; + }; + tmpfreq[i]=y; + }; + + //increase the bandwidth of each harmonic (by smoothing the log spectrum) + int n=2; + REALTYPE a=1.0-pow(2.0,-bandwidth*bandwidth*10.0); + a=pow(a,8192.0/nfreq*n); + + for (int k=0;k<n;k++){ + tmpfreq[0]=0.0; + for (int i=1;i<nfreq;i++){ + tmpfreq[i]=tmpfreq[i-1]*a+tmpfreq[i]*(1.0-a); + }; + tmpfreq[nfreq-1]=0.0; + for (int i=nfreq-2;i>0;i--){ + tmpfreq[i]=tmpfreq[i+1]*a+tmpfreq[i]*(1.0-a); + }; + }; + + freq2[0]=0; + REALTYPE log_maxfreq_d_minfreq=log(maxfreq/minfreq); + for (int i=1;i<nfreq;i++){ + REALTYPE freqx=i/(REALTYPE) nfreq; + REALTYPE x=log((freqx*maxfreq)/minfreq)/log_maxfreq_d_minfreq*nfreq; + REALTYPE y=0.0; + if ((x>0.0)&&(x<nfreq)){ + int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1; + int x1=x0+1; if (x1>=nfreq) x1=nfreq-1; + REALTYPE xp=x-x0; + y=tmpfreq[x0]*(1.0-xp)+tmpfreq[x1]*xp; + }; + freq2[i]=y; + }; +}; + + Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_) :Effect(insertion_,efxoutl_,efxoutr_,NULL,0) { inputbuf=new REALTYPE[SOUND_BUFFER_SIZE]; + bandwidth=NULL; + //defaults Pvolume=48; Ppan=64; @@ -43,6 +153,7 @@ Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_) Plohidamp=80; Ptype=1; Proomsize=64; + Pbandwidth=30; roomsize=1.0; rs=1.0; @@ -80,6 +191,7 @@ Reverb::~Reverb() for (i=0;i<REV_COMBS*2;i++) delete [] comb[i]; delete [] inputbuf; + if (bandwidth) delete bandwidth; }; /* @@ -156,15 +268,19 @@ void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r) for (i=0;i<SOUND_BUFFER_SIZE;i++) { inputbuf[i]=(smps_l[i]+smps_r[i])/2.0; - //Initial delay r - if (idelay!=NULL) { - REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb; - inputbuf[i]=idelay[idelayk]; - idelay[idelayk]=tmp; - idelayk++; - if (idelayk>=idelaylen) idelayk=0; - }; - }; + }; + if (idelay!=NULL) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + //Initial delay r + REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb; + inputbuf[i]=idelay[idelayk]; + idelay[idelayk]=tmp; + idelayk++; + if (idelayk>=idelaylen) idelayk=0; + }; + }; + + if (bandwidth) bandwidth->process(inputbuf); if (lpf!=NULL) lpf->filterout(inputbuf); if (hpf!=NULL) hpf->filterout(inputbuf); @@ -288,17 +404,21 @@ void Reverb::setlpf(const unsigned char &Plpf) void Reverb::settype(unsigned char Ptype) { - const int NUM_TYPES=2; + const int NUM_TYPES=3; int combtunings[NUM_TYPES][REV_COMBS]={ //this is unused (for random) {0,0,0,0,0,0,0,0}, //Freeverb by Jezar at Dreampoint + {1116,1188,1277,1356,1422,1491,1557,1617}, + //Freeverb by Jezar at Dreampoint //duplicate {1116,1188,1277,1356,1422,1491,1557,1617} }; int aptunings[NUM_TYPES][REV_APS]={ //this is unused (for random) {0,0,0,0}, //Freeverb by Jezar at Dreampoint + {225,341,441,556}, + //Freeverb by Jezar at Dreampoint (duplicate) {225,341,441,556} }; @@ -335,6 +455,15 @@ void Reverb::settype(unsigned char Ptype) }; settime(Ptime); cleanup(); + if (bandwidth) delete bandwidth; + bandwidth=NULL; + if (Ptype==2){//bandwidth + +#warning sa calculez numarul optim de buffere + bandwidth=new ReverbBandwidth(SOUND_BUFFER_SIZE,32); + + + }; }; void Reverb::setroomsize(const unsigned char &Proomsize) @@ -348,37 +477,42 @@ void Reverb::setroomsize(const unsigned char &Proomsize) settype(Ptype); }; +void Reverb::setbandwidth(const unsigned char &Pbandwidth){ + this->Pbandwidth=Pbandwidth; + if (bandwidth) bandwidth->set_bandwidth(Pbandwidth/127.0); +}; + void Reverb::setpreset(unsigned char npreset) { - const int PRESET_SIZE=12; + const int PRESET_SIZE=13; const int NUM_PRESETS=13; unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ //Cathedral1 - {80,64,63,24,0,0,0,85,5,83,1,64}, + {80,64,63,24,0,0,0,85,5,83,1,64,0}, //Cathedral2 - {80,64,69,35,0,0,0,127,0,71,0,64}, + {80,64,69,35,0,0,0,127,0,71,0,64,0}, //Cathedral3 - {80,64,69,24,0,0,0,127,75,78,1,85}, + {80,64,69,24,0,0,0,127,75,78,1,85,0}, //Hall1 - {90,64,51,10,0,0,0,127,21,78,1,64}, + {90,64,51,10,0,0,0,127,21,78,1,64,0}, //Hall2 - {90,64,53,20,0,0,0,127,75,71,1,64}, + {90,64,53,20,0,0,0,127,75,71,1,64,0}, //Room1 - {100,64,33,0,0,0,0,127,0,106,0,30}, + {100,64,33,0,0,0,0,127,0,106,0,30,0}, //Room2 - {100,64,21,26,0,0,0,62,0,77,1,45}, + {100,64,21,26,0,0,0,62,0,77,1,45,0}, //Basement - {110,64,14,0,0,0,0,127,5,71,0,25}, + {110,64,14,0,0,0,0,127,5,71,0,25,0}, //Tunnel - {85,80,84,20,42,0,0,51,0,78,1,105}, + {85,80,84,20,42,0,0,51,0,78,1,105,0}, //Echoed1 - {95,64,26,60,71,0,0,114,0,64,1,64}, + {95,64,26,60,71,0,0,114,0,64,1,64,0}, //Echoed2 - {90,64,40,88,71,0,0,114,0,88,1,64}, + {90,64,40,88,71,0,0,114,0,88,1,64,0}, //VeryLong1 - {90,64,93,15,0,0,0,114,0,77,0,95}, + {90,64,93,15,0,0,0,114,0,77,0,95,0}, //VeryLong2 - {90,64,111,30,0,0,0,114,90,74,1,80} + {90,64,111,30,0,0,0,114,90,74,1,80,0} }; if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; @@ -425,6 +559,9 @@ void Reverb::changepar(const int &npar,const unsigned char &value) case 11: setroomsize(value); break; + case 12: + setbandwidth(value); + break; }; }; @@ -465,6 +602,9 @@ unsigned char Reverb::getpar(const int &npar)const case 11: return(Proomsize); break; + case 12: + return(Pbandwidth); + break; }; return(0);//in case of bogus "parameter" }; diff --git a/src/Effects/Reverb.h b/src/Effects/Reverb.h @@ -2,7 +2,7 @@ ZynAddSubFX - a software synthesizer Reverb.h - Reverberation effect - Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2002-2009 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify @@ -23,15 +23,133 @@ #ifndef REVERB_H #define REVERB_H - +#include <math.h> #include "../globals.h" #include "../DSP/AnalogFilter.h" +#include "../DSP/FFTwrapper.h" #include "Effect.h" #define REV_COMBS 8 #define REV_APS 4 /**Creates Reverberation Effects*/ + +class OverlapAdd{//50% overlap + public: + OverlapAdd(int small_buffer_size_,int n_small_buffers_per_half_big_buffer_){ + small_buffer_size=small_buffer_size_; + n_small_buffers_per_half_big_buffer=n_small_buffers_per_half_big_buffer_; + half_big_buffer_size=small_buffer_size*n_small_buffers_per_half_big_buffer; + big_buffer_size=half_big_buffer_size*2; + + new_half_big_buffer_input=new REALTYPE[half_big_buffer_size]; + old_half_big_buffer_input=new REALTYPE[half_big_buffer_size]; + new_half_big_buffer_processed=new REALTYPE[half_big_buffer_size]; + half_big_buffer_output=new REALTYPE[half_big_buffer_size]; + big_buffer=new REALTYPE[big_buffer_size]; + for (int i=0;i<half_big_buffer_size;i++){ + new_half_big_buffer_input[i]=0.0; + old_half_big_buffer_input[i]=0.0; + new_half_big_buffer_processed[i]=0.0; + half_big_buffer_output[i]=0.0; + }; + for (int i=0;i<big_buffer_size;i++){ + big_buffer[i]=0.0; + }; + small_buffer_k=0; + }; + virtual ~OverlapAdd(){ + delete []new_half_big_buffer_input; + delete []old_half_big_buffer_input; + delete []new_half_big_buffer_processed; + delete []half_big_buffer_output; + delete []big_buffer; + }; + + + void process(REALTYPE *small_buffer){ + + int input_start_pos=small_buffer_size*small_buffer_k; + + for (int i=0;i<small_buffer_size;i++){ + new_half_big_buffer_input[input_start_pos+i]=small_buffer[i]; + }; + small_buffer_k++; + if (small_buffer_k>=n_small_buffers_per_half_big_buffer){ + small_buffer_k=0; + process_big_buffer(); + }; + + int output_start_pos=small_buffer_size*small_buffer_k; //check if this is correct + + for (int i=0;i<small_buffer_size;i++){ + small_buffer[i]=half_big_buffer_output[output_start_pos+i]; + }; + + + }; + protected: + int half_big_buffer_size; + int big_buffer_size; + REALTYPE *big_buffer; + + virtual void do_process_big_buffer(){//the resulting buffer must be windowed + for (int i=0;i<big_buffer_size;i++){ + big_buffer[i]*=(1.0-cos(i*M_PI*2.0/big_buffer_size))*0.5; +// big_buffer[i]*=0.5; + }; +// printf("BIG_BUFFER:\n"); for (int i=0;i<big_buffer_size;i++) printf(" %g ",big_buffer[i]); printf("\n\n"); + }; + private: + void process_big_buffer(){ + for (int i=0;i<half_big_buffer_size;i++){ + big_buffer[i]=old_half_big_buffer_input[i]; + big_buffer[i+half_big_buffer_size]=new_half_big_buffer_input[i]; + }; + + do_process_big_buffer();//process input buffer and get windowed buffer + + for (int i=0;i<half_big_buffer_size;i++){ + old_half_big_buffer_input[i]=new_half_big_buffer_input[i]; + }; + +// printf("OUT1:\n"); for (int i=0;i<half_big_buffer_size;i++) printf(" %g,%g ",big_buffer[i],new_half_big_buffer_processed[i]); printf("\n\n"); + for (int i=0;i<half_big_buffer_size;i++){ + half_big_buffer_output[i]=big_buffer[i]+new_half_big_buffer_processed[i]; + new_half_big_buffer_processed[i]=big_buffer[i+half_big_buffer_size]; + }; + + }; + + int small_buffer_size; + int n_small_buffers_per_half_big_buffer; + int small_buffer_k; + + REALTYPE *old_half_big_buffer_input,*new_half_big_buffer_input; + REALTYPE *new_half_big_buffer_processed; + + REALTYPE *half_big_buffer_output; +}; + +class ReverbBandwidth: public OverlapAdd{ + public: + ReverbBandwidth (int small_buffer_size_,int n_small_buffers_per_half_big_buffer_); + ~ReverbBandwidth(); + void do_spread(int nfreq,REALTYPE *freq1,REALTYPE *freq2, REALTYPE bandwidth); + void set_bandwidth(REALTYPE par){ + if (par<0.0) par=0.0; + if (par>1.0) par=1.0; + bandwidth=par; + }; + private: + void do_process_big_buffer(); + FFTwrapper *fft; + FFTFREQS freqs; + REALTYPE *srcfreq,*destfreq,*tmpfreq; + REALTYPE *window; + REALTYPE bandwidth; +}; + class Reverb:public Effect { public: @@ -83,6 +201,9 @@ private: /**Room Size*/ unsigned char Proomsize; + /**Bandwidth */ + unsigned char Pbandwidth; + //parameter control void setvolume(const unsigned char &Pvolume); void setpan(const unsigned char &Ppan); @@ -94,6 +215,7 @@ private: void setlpf(const unsigned char &Plpf); void settype( unsigned char Ptype); void setroomsize(const unsigned char &Proomsize); + void setbandwidth(const unsigned char &Pbandwidth); REALTYPE pan,erbalance; //Parametrii 2 @@ -103,6 +225,7 @@ private: REALTYPE lohifb,idelayfb,roomsize,rs;//rs is used to "normalise" the volume according to the roomsize int comblen[REV_COMBS*2]; int aplen[REV_APS*2]; + ReverbBandwidth *bandwidth; //Internal Variables diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -25,7 +25,7 @@ #include <math.h> #include "ADnoteParameters.h" -int ADnote_unison_sizes[]={1,2,3,4,6,8,12,16,24,32,48,64,0}; +int ADnote_unison_sizes[]={1,2,3,4,5,6,8,10,12,15,20,25,30,40,50,0}; ADnoteParameters::ADnoteParameters(FFTwrapper *fft_):Presets() { @@ -99,9 +99,11 @@ void ADnoteParameters::defaults(int n) VoicePar[nvoice].Enabled=0; VoicePar[nvoice].Unison_size=1; - VoicePar[nvoice].Unison_frequency_spread=30; + VoicePar[nvoice].Unison_frequency_spread=60; VoicePar[nvoice].Unison_stereo_spread=64; VoicePar[nvoice].Unison_vibratto=64; + VoicePar[nvoice].Unison_vibratto_speed=64; + VoicePar[nvoice].Unison_invert_phase=0; VoicePar[nvoice].Type=0; VoicePar[nvoice].Pfixedfreq=0; @@ -198,6 +200,16 @@ REALTYPE ADnoteParameters::getBandwidthDetuneMultiplier() return(bw); }; +/* + * Get the unison spread in cents for a voice + */ + +REALTYPE ADnoteParameters::getUnisonFrequencySpreadCents(int nvoice){ + REALTYPE unison_spread=VoicePar[nvoice].Unison_frequency_spread/127.0; + unison_spread=pow(unison_spread*2.0,2.0)*50.0;//cents + return unison_spread; + +}; /* * Kill the voice @@ -241,8 +253,14 @@ int ADnoteParameters::get_unison_size_index(int nvoice){ int index=0; if (nvoice>=NUM_VOICES) return 0; int unison=VoicePar[nvoice].Unison_size; - while(1){ - if ((ADnote_unison_sizes[index]<=unison)||(ADnote_unison_sizes[index]==0)) return index; + + while(1){ + if (ADnote_unison_sizes[index]>=unison) { + return index; + }; + if (ADnote_unison_sizes[index]==0) { + return index-1; + }; index++; }; return 0; @@ -285,6 +303,8 @@ void ADnoteParameters::add2XMLsection(XMLwrapper *xml,int n) xml->addpar("unison_frequency_spread",VoicePar[nvoice].Unison_frequency_spread); xml->addpar("unison_stereo_spread",VoicePar[nvoice].Unison_stereo_spread); xml->addpar("unison_vibratto",VoicePar[nvoice].Unison_vibratto); + xml->addpar("unison_vibratto_speed",VoicePar[nvoice].Unison_vibratto_speed); + xml->addpar("unison_invert_phase",VoicePar[nvoice].Unison_invert_phase); xml->addpar("delay",VoicePar[nvoice].PDelay); xml->addparbool("resonance",VoicePar[nvoice].Presonance); @@ -566,6 +586,8 @@ void ADnoteParameters::getfromXMLsection(XMLwrapper *xml,int n) VoicePar[nvoice].Unison_frequency_spread=xml->getpar127("unison_frequency_spread",VoicePar[nvoice].Unison_frequency_spread); VoicePar[nvoice].Unison_stereo_spread=xml->getpar127("unison_stereo_spread",VoicePar[nvoice].Unison_stereo_spread); VoicePar[nvoice].Unison_vibratto=xml->getpar127("unison_vibratto",VoicePar[nvoice].Unison_vibratto); + VoicePar[nvoice].Unison_vibratto_speed=xml->getpar127("unison_vibratto_speed",VoicePar[nvoice].Unison_vibratto_speed); + VoicePar[nvoice].Unison_invert_phase=xml->getpar127("unison_invert_phase",VoicePar[nvoice].Unison_invert_phase); VoicePar[nvoice].Type=xml->getpar127("type",VoicePar[nvoice].Type); VoicePar[nvoice].PDelay=xml->getpar127("delay",VoicePar[nvoice].PDelay); diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -128,6 +128,12 @@ struct ADnoteVoiceParam { /** Vibratto of the subvoices (which makes the unison more "natural")*/ unsigned char Unison_vibratto; + /** Medium speed of the vibratto of the subvoices*/ + unsigned char Unison_vibratto_speed; + + /** Unison invert phase */ + unsigned char Unison_invert_phase;//0=none,1=random,2=50%,3=33%,4=25% + /** Type of the voice (0=Sound,1=Noise)*/ unsigned char Type; @@ -282,6 +288,7 @@ public: void getfromXML(XMLwrapper *xml); REALTYPE getBandwidthDetuneMultiplier(); + REALTYPE getUnisonFrequencySpreadCents(int nvoice); int get_unison_size_index(int nvoice); void set_unison_size_index(int nvoice,int index); private: diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -106,10 +106,11 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve unison_base_freq_rap[nvoice]=new REALTYPE[unison]; unison_freq_rap[nvoice]=new REALTYPE[unison]; - REALTYPE unison_spread=pars->VoicePar[nvoice].Unison_frequency_spread/127.0; - unison_spread=pow(unison_spread*2.0,2.0)*100.0;//cents + unison_invert_phase[nvoice]=new bool[unison]; + REALTYPE unison_spread=pars->getUnisonFrequencySpreadCents(nvoice); REALTYPE unison_real_spread=pow(2.0,(unison_spread*0.5)/1200.0); REALTYPE unison_vibratto_a=pars->VoicePar[nvoice].Unison_vibratto/127.0;//0.0 .. 1.0 + switch (unison){ case 1: @@ -133,13 +134,12 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve REALTYPE diff=max-min; for (int k=0;k<unison;k++){ unison_values[k]=(unison_values[k]-(max+min)*0.5)/diff;//the lowest value will be -1 and the highest will be 1 - unison_base_freq_rap[nvoice][k]=pow(2.0,(unison_spread*unison_values[k]*0.5)/1200); + unison_base_freq_rap[nvoice][k]=pow(2.0,(unison_spread*unison_values[k])/1200); }; }; }; //unison vibrattos - if (unison>1){ for (int k=0;k<unison;k++){//reduce the frequency difference for larger vibrattos unison_base_freq_rap[nvoice][k]=1.0+(unison_base_freq_rap[nvoice][k]-1.0)*(1.0-unison_vibratto_a); @@ -147,15 +147,14 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve }; unison_vibratto[nvoice].step=new REALTYPE[unison]; unison_vibratto[nvoice].position=new REALTYPE[unison]; - unison_vibratto[nvoice].amplitude=(unison_real_spread-1.0)*unison_vibratto_a*0.5; + unison_vibratto[nvoice].amplitude=(unison_real_spread-1.0)*unison_vibratto_a; REALTYPE increments_per_second=SAMPLE_RATE/(REALTYPE)SOUND_BUFFER_SIZE; + REALTYPE vibratto_base_period=0.25*pow(2.0,(1.0-pars->VoicePar[nvoice].Unison_vibratto_speed/127.0)*4.0); for (int k=0;k<unison;k++){ - unison_vibratto[nvoice].position[k]=RND*0.9-0.45; - REALTYPE vibratto_period=0.5+RND*2.5; - + unison_vibratto[nvoice].position[k]=RND*1.8-0.9; + REALTYPE vibratto_period=vibratto_base_period*pow(2.0,RND*2.0-1.0);//make period to vary randomly from 50% to 200% vibratto base period - unison_vibratto[nvoice].position[k]=0; REALTYPE m=4.0/(vibratto_period*increments_per_second); if (RND<0.5) m=-m; unison_vibratto[nvoice].step[k]=m; @@ -166,6 +165,21 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve unison_vibratto[nvoice].position[0]=0.0; unison_vibratto[nvoice].amplitude=0.0; }; + + //phase invert for unison + unison_invert_phase[nvoice][0]=false; + if (unison!=1){ + int inv=pars->VoicePar[nvoice].Unison_invert_phase; + switch(inv){ + case 0: for (int k=0;k<unison;k++) unison_invert_phase[nvoice][k]=false; + break; + case 1: for (int k=0;k<unison;k++) unison_invert_phase[nvoice][k]=(RND>0.5); + break; + default:for (int k=0;k<unison;k++) unison_invert_phase[nvoice][k]=(k%inv==0)?true:false; + break; + }; + }; + oscfreqhi[nvoice]=new int[unison]; oscfreqlo[nvoice]=new REALTYPE[unison]; @@ -513,7 +527,6 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int if ((NoteVoicePar[i].FMVoice==nvoice)&&(tmp[i]==0)) { tmp[i]=1; }; - /// if (NoteVoicePar[nvoice].VoiceOut!=NULL) for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0; }; /////////////// @@ -539,6 +552,7 @@ void ADnote::KillVoice(int nvoice) delete []NoteVoicePar[nvoice].OscilSmp; delete []unison_base_freq_rap[nvoice]; delete []unison_freq_rap[nvoice]; + delete []unison_invert_phase[nvoice]; delete []FMoldsmp[nvoice]; delete []unison_vibratto[nvoice].step; delete []unison_vibratto[nvoice].position; @@ -760,6 +774,7 @@ void ADnote::compute_unison_freq_rap(int nvoice){ unison_freq_rap[nvoice][0]=1.0; return; }; + REALTYPE relbw=ctl->bandwidth.relbw*bandwidthDetuneMultiplier; for (int k=0;k<unison_size[nvoice];k++){ REALTYPE pos=unison_vibratto[nvoice].position[k]; REALTYPE step=unison_vibratto[nvoice].step[k]; @@ -772,7 +787,8 @@ void ADnote::compute_unison_freq_rap(int nvoice){ pos=1.0; step=-step; }; - unison_freq_rap[nvoice][k]=unison_base_freq_rap[nvoice][k]+pos*unison_vibratto[nvoice].amplitude; + REALTYPE vibratto_val=pos-0.3*pos*pos*pos;//make the vibratto lfo smoother + unison_freq_rap[nvoice][k]=1.0+((unison_base_freq_rap[nvoice][k]-1.0)+vibratto_val*unison_vibratto[nvoice].amplitude)*relbw; unison_vibratto[nvoice].position[k]=pos; step=unison_vibratto[nvoice].step[k]=step; @@ -1196,7 +1212,7 @@ inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMm }; - //normalize makes all sample-rates, oscil_sizes toproduce same sound + //normalize: makes all sample-rates, oscil_sizes to produce same sound if (FMmode!=0) {//Frequency modulation REALTYPE normalize=OSCIL_SIZE/262144.0*44100.0/(REALTYPE)SAMPLE_RATE; for (int k=0;k<unison_size[nvoice];k++){ @@ -1244,7 +1260,7 @@ inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMm poslo+=freqlo; if (poslo>=1.0) { - poslo=fmod(freqlo,1.0); + poslo=fmod(poslo,1.0); poshi++; }; @@ -1325,7 +1341,7 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) // Voice Processing - //mix subvoices into + //mix subvoices into voice 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++){ @@ -1350,6 +1366,11 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) REALTYPE rvol=panning*2.0; if (rvol>1.0) rvol=1.0; + if (unison_invert_phase[nvoice][k]) { + lvol=-lvol; + rvol=-rvol; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwavel[i]+=tw[i]*lvol; for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwaver[i]+=tw[i]*rvol; }else{ @@ -1363,6 +1384,7 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) // Amplitude 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 @@ -1397,9 +1419,10 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) //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) + if (NoteVoicePar[nvoice].AmpEnvelope->finished()!=0){ 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 }; diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h @@ -239,6 +239,9 @@ private: //how the unison subvoice's frequency is changed (1.0 for no change) REALTYPE *unison_freq_rap[NUM_VOICES]; + + //which subvoice has phase inverted + bool *unison_invert_phase[NUM_VOICES]; //unison vibratto struct { diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.fl @@ -177,7 +177,7 @@ class ADvoiceUI {open : {public Fl_Group} Function {make_window()} {open } { Fl_Window ADnoteVoiceParameters { - label Voice open + label Voice xywh {69 185 765 575} type Double class Fl_Group visible } { @@ -549,35 +549,56 @@ voiceonbutton->redraw();} open code3 {o->value(pars->VoicePar[nvoice].Pextoscil+1);} } {} Fl_Group {} {open - xywh {5 525 475 45} box ENGRAVED_BOX + xywh {5 525 515 45} box ENGRAVED_BOX } { Fl_Dial {} { label Stereo callback {pars->VoicePar[nvoice].Unison_stereo_spread=(int)o->value();} - tooltip {Stereo Spread} xywh {265 540 25 25} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 + tooltip {Stereo Spread} xywh {285 540 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1 code0 {o->value(pars->VoicePar[nvoice].Unison_stereo_spread);} class WidgetPDial } - Fl_Value_Slider {} { - label {Frequency Spread} - callback {pars->VoicePar[nvoice].Unison_frequency_spread=(int)o->value();} - tooltip {Frequency Spread of the Unison} xywh {90 548 155 17} type {Horz Knob} box FLAT_BOX labelsize 11 align 5 maximum 127 step 1 value 64 - code0 {o->value(pars->VoicePar[nvoice].Unison_frequency_spread);} - } Fl_Choice {} { label Unison - callback {pars->set_unison_size_index(nvoice,(int) o->value());} open + callback {pars->set_unison_size_index(nvoice,(int) o->value());} open selected tooltip {Unison size} xywh {10 545 75 20} down_box BORDER_BOX labelfont 1 align 5 textfont 1 textsize 10 code0 {o->add("OFF");char tmp[100];for (int i=1;ADnote_unison_sizes[i];i++){snprintf(tmp,100,"size %d",ADnote_unison_sizes[i]);o->add(tmp);};} - code1 {o->value(pars->VoicePar[nvoice].PDetuneType);} + code1 {o->value(pars->get_unison_size_index(nvoice));} } {} Fl_Dial {} { label Vibratto - callback {pars->VoicePar[nvoice].Unison_vibratto=(int)o->value();} selected - tooltip Vibratto xywh {340 540 25 25} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 + callback {pars->VoicePar[nvoice].Unison_vibratto=(int)o->value();} + tooltip Vibratto xywh {340 540 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1 code0 {o->value(pars->VoicePar[nvoice].Unison_vibratto);} class WidgetPDial } + Fl_Choice {} { + label Invert + callback {pars->VoicePar[nvoice].Unison_invert_phase=(int) o->value();} open + tooltip {Phase Invert} xywh {445 545 65 15} down_box BORDER_BOX labelsize 11 align 5 textfont 1 textsize 10 + code0 {o->add("None");o->add("Random");char tmp[100];for (int i=2;i<=5;i++){snprintf(tmp,100,"%d %%",100/i);o->add(tmp);};} + code1 {o->value(pars->VoicePar[nvoice].Unison_invert_phase);} + } {} + Fl_Slider {} { + label {Frequency Spread} + callback {pars->VoicePar[nvoice].Unison_frequency_spread=(int)o->value(); +unisonspreadoutput->do_callback();} + tooltip {Frequency Spread of the Unison} xywh {95 547 125 13} type {Horz Knob} box FLAT_BOX labelsize 12 align 1 maximum 127 step 1 value 64 + code0 {o->value(pars->VoicePar[nvoice].Unison_frequency_spread);} + } + Fl_Value_Output unisonspreadoutput { + label {(cents)} + callback {o->value(pars->getUnisonFrequencySpreadCents(nvoice));} + xywh {225 545 40 15} labelsize 10 align 5 maximum 1000 step 0.1 textfont 1 textsize 10 + code0 {o->value(pars->getUnisonFrequencySpreadCents(nvoice));} + } + Fl_Dial {} { + label {Vib.speed} + callback {pars->VoicePar[nvoice].Unison_vibratto_speed=(int)o->value();} + tooltip {Vibratto Average Speed} xywh {390 540 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].Unison_vibratto_speed);} + class WidgetPDial + } } } Fl_Group {} { diff --git a/src/UI/EffUI.fl b/src/UI/EffUI.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0107 +version 1.0109 header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} @@ -36,7 +36,7 @@ decl {\#include "../Effects/EffectMgr.h"} {public decl {\#include "PresetsUI.h"} {public } -class EQGraph {selected : {public Fl_Box} +class EQGraph {: {public Fl_Box} } { Function {EQGraph(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { code {eff=NULL; @@ -155,7 +155,7 @@ return(log(freq/20.0)/log(1000.0));} {} decl {int maxdB;} {} } -class EffUI {: {public Fl_Group,public PresetsUI_} +class EffUI {open : {public Fl_Group,public PresetsUI_} } { Function {EffUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { code {eff=NULL; @@ -188,10 +188,11 @@ if (filterwindow!=NULL){ } } } - Function {make_reverb_window()} {} { - Fl_Window effreverbwindow { - xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide - class Fl_Group + Function {make_reverb_window()} {open + } { + Fl_Window effreverbwindow {open + xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 + class Fl_Group visible } { Fl_Text_Display {} { label {Reverb } @@ -259,8 +260,8 @@ refresh(eff);} } Fl_Choice revp10 { label Type - callback {eff->seteffectpar(10,(int) o->value());} - xywh {110 15 75 15} down_box BORDER_BOX color 14 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10 textcolor 7 + callback {eff->seteffectpar(10,(int) o->value());} open + xywh {110 15 85 15} down_box BORDER_BOX color 14 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10 textcolor 7 } { MenuItem {} { label Random @@ -270,6 +271,10 @@ refresh(eff);} label Freeverb xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 } + MenuItem {} { + label Bandwidth + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } } Fl_Dial revp0 { label Vol @@ -301,10 +306,10 @@ refresh(eff);} tooltip {Initial Delay Feedback} xywh {155 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 class WidgetPDial } - Fl_Dial revp5 { - label {R.delay} - callback {eff->seteffectpar(5,(int) o->value());} - xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 when 4 maximum 127 deactivate + Fl_Dial revp12 { + label bw + callback {eff->seteffectpar(12,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 when 4 maximum 127 class WidgetPDial } Fl_Dial revp6 { @@ -337,7 +342,7 @@ refresh(eff);} if (Fl::event_button1()) x=(int)o->value(); else o->value(x); eff->seteffectpar(11,x);} - tooltip RoomSize xywh {190 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 + tooltip RoomSize xywh {200 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 class WidgetPDial } } @@ -1263,7 +1268,8 @@ effdynamicfilterwindow->position(px,py); refresh(eff);} {} } - Function {refresh(EffectMgr *eff_)} {} { + Function {refresh(EffectMgr *eff_)} {open + } { code {eff=eff_; this->hide(); @@ -1293,13 +1299,14 @@ switch(eff->geteffect()){ revp2->value(eff->geteffectpar(2)); revp3->value(eff->geteffectpar(3)); revp4->value(eff->geteffectpar(4)); - revp5->value(eff->geteffectpar(5)); + //revp5->value(eff->geteffectpar(5)); revp6->value(eff->geteffectpar(6)); revp7->value(eff->geteffectpar(7)); revp8->value(eff->geteffectpar(8)); revp9->value(eff->geteffectpar(9)); revp10->value(eff->geteffectpar(10)); revp11->value(eff->geteffectpar(11)); + revp12->value(eff->geteffectpar(12)); effreverbwindow->show(); break; @@ -1410,7 +1417,8 @@ switch(eff->geteffect()){ break; }; -this->show();} {} +this->show();} {selected + } } Function {refresh()} {} { code {refresh(eff);} {}