zynaddsubfx

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

commit aa79e53f0be4308b3cf693c029023bebaaa369ca
parent e471ce83b7e980da47cc0b3d999dc54720998833
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Fri, 25 Sep 2009 09:38:49 -0400

Merge branch 'master' into newXML

Conflicts:
	ChangeLog

Diffstat:
MAUTHORS.txt | 2++
MChangeLog | 23++++++++++++++++++++++-
Msrc/Effects/Reverb.cpp | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/Effects/Reverb.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/Params/ADnoteParameters.cpp | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/Params/ADnoteParameters.h | 22++++++++++++++++++++++
Msrc/Synth/ADnote.cpp | 726++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/Synth/ADnote.h | 47++++++++++++++++++++++++++++++++++++++---------
Msrc/Synth/OscilGen.cpp | 9+++++----
Msrc/Synth/OscilGen.h | 6+++---
Msrc/UI/ADnoteUI.fl | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/UI/EffUI.fl | 42+++++++++++++++++++++++++-----------------
Msrc/UI/MasterUI.fl | 52++++++++++++++++++++++++++++------------------------
Msrc/UI/PartUI.fl | 8++++----
Msrc/UI/VirKeyboard.fl | 11+++++++----
Msrc/UI/WidgetPDial.fl | 12+++++++-----
Msrc/main.cpp | 8+-------
17 files changed, 1108 insertions(+), 340 deletions(-)

diff --git a/AUTHORS.txt b/AUTHORS.txt @@ -13,4 +13,6 @@ Contributors: Achim Settelmeier (QUERTZ keyboard layout for virtual keyboard) Jérémie Andréi (AZERTY keyboard layout, Array index fix) Alexis Ballier (const char* <-> string mismatch, NULLMidi prototype fix) + Tobias Doerffel (static vs instance variables alteration) + James Morris (Memory leaks in FLTK GUI) 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 @@ -910,6 +910,27 @@ - Remove last of stack helper functions in XMLwrapper - Added std::string retreval to XMLwrapper +20 Sep 2009 (Paul Nasca) + - Started to implement the Unison effect for ADsynth + +22 Sep 2009 (Paul Nasca) + - Added vibratto and other features to Unison effect + +22 Sep 2009 (Mark McCurry) + - 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 + 25 Sep 2009 (Mark McCurry) - Allowed for XMLwrapper to retrieve strings stored in mxml TEXT fields 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,6 +25,7 @@ #include <math.h> #include "ADnoteParameters.h" +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() { @@ -96,6 +97,14 @@ void ADnoteParameters::defaults(int n) { int nvoice=n; VoicePar[nvoice].Enabled=0; + + VoicePar[nvoice].Unison_size=1; + 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; VoicePar[nvoice].PfixedfreqET=0; @@ -191,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 @@ -230,6 +249,35 @@ ADnoteParameters::~ADnoteParameters() }; }; +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) { + return index; + }; + if (ADnote_unison_sizes[index]==0) { + return index-1; + }; + index++; + }; + return 0; +}; + +void ADnoteParameters::set_unison_size_index(int nvoice,int index){ + int unison=1; + for (int i=0;i<=index;i++){ + unison=ADnote_unison_sizes[i]; + if (unison==0) { + unison=ADnote_unison_sizes[i-1]; + break; + }; + }; + + VoicePar[nvoice].Unison_size=unison; +}; @@ -248,8 +296,17 @@ void ADnoteParameters::add2XMLsection(XMLwrapper *xml,int n) xml->addparbool("enabled",VoicePar[nvoice].Enabled); if (((VoicePar[nvoice].Enabled==0)&&(oscilused==0)&&(fmoscilused==0))&&(xml->minimal)) return; + xml->addpar("type",VoicePar[nvoice].Type); - xml->addpar("delay",VoicePar[nvoice].PDelay); + + xml->addpar("unison_size",VoicePar[nvoice].Unison_size); + 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); xml->addpar("ext_oscil",VoicePar[nvoice].Pextoscil); @@ -525,7 +582,14 @@ void ADnoteParameters::getfromXMLsection(XMLwrapper *xml,int n) VoicePar[nvoice].Enabled=xml->getparbool("enabled",0); - VoicePar[nvoice].Type=xml->getpar127("type",VoicePar[nvoice].Type); + VoicePar[nvoice].Unison_size=xml->getpar127("unison_size",VoicePar[nvoice].Unison_size); + 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); VoicePar[nvoice].Presonance=xml->getparbool("resonance",VoicePar[nvoice].Presonance); diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -36,6 +36,7 @@ #include "Presets.h" enum FMTYPE {NONE,MORPH,RING_MOD,PHASE_MOD,FREQ_MOD,PITCH_MOD}; +extern int ADnote_unison_sizes[]; /*****************************************************************/ /* GLOBAL PARAMETERS */ @@ -115,6 +116,24 @@ struct ADnoteVoiceParam { /** If the voice is enabled */ unsigned char Enabled; + /** How many subvoices are used in this voice */ + unsigned char Unison_size; + + /** How subvoices are spread */ + unsigned char Unison_frequency_spread; + + /** Stereo spread of the subvoices*/ + unsigned char Unison_stereo_spread; + + /** 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; @@ -269,6 +288,9 @@ 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: void defaults(int n);//n is the nvoice 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,112 @@ 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 }; + unison_stereo_spread[nvoice]=pars->VoicePar[nvoice].Unison_stereo_spread/127.0; + int unison=pars->VoicePar[nvoice].Unison_size; + if (unison<1) unison=1; + + //compute unison + unison_size[nvoice]=unison; + + unison_base_freq_rap[nvoice]=new REALTYPE[unison]; + unison_freq_rap[nvoice]=new REALTYPE[unison]; + 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: + unison_base_freq_rap[nvoice][0]=1.0;//if the unison is not used, always make the only subvoice to have the default note + break; + case 2:{//unison for 2 subvoices + unison_base_freq_rap[nvoice][0]=1.0/unison_real_spread; + unison_base_freq_rap[nvoice][1]=unison_real_spread; + }; + break; + default:{//unison for more than 2 subvoices + REALTYPE unison_values[unison]; + REALTYPE min=-1e-6,max=1e-6; + for (int k=0;k<unison;k++){ + REALTYPE step=(k/(REALTYPE) (unison-1))*2.0-1.0;//this makes the unison spread more uniform + REALTYPE val=step+(RND*2.0-1.0)/(unison-1); + unison_values[k]=val; + if (val>max) max=val; + if (val<min) min=val; + }; + 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])/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); + }; + }; + 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; + + 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*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 + + REALTYPE m=4.0/(vibratto_period*increments_per_second); + if (RND<0.5) m=-m; + unison_vibratto[nvoice].step[k]=m; + }; + + if (unison==1) {//no vibratto for a single voice + unison_vibratto[nvoice].step[0]=0.0; + 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]; + 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 +214,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 +228,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 +247,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 +299,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 +405,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 +439,7 @@ 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); + }; /// initparameters(); @@ -412,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; }; /////////////// @@ -426,22 +540,40 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int void ADnote::KillVoice(int nvoice) { - delete []NoteVoicePar[nvoice].OscilSmp; - - if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); - NoteVoicePar[nvoice].FreqEnvelope=NULL; - - if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo); - NoteVoicePar[nvoice].FreqLfo=NULL; - - if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope); + delete []oscfreqhi[nvoice]; + delete []oscfreqlo[nvoice]; + delete []oscfreqhiFM[nvoice]; + delete []oscfreqloFM[nvoice]; + delete []oscposhi[nvoice]; + delete []oscposlo[nvoice]; + delete []oscposhiFM[nvoice]; + delete []oscposloFM[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; + + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); + NoteVoicePar[nvoice].FreqEnvelope=NULL; + + if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo); + NoteVoicePar[nvoice].FreqLfo=NULL; + + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope); NoteVoicePar[nvoice].AmpEnvelope=NULL; if (NoteVoicePar[nvoice].AmpLfo!=NULL) delete (NoteVoicePar[nvoice].AmpLfo); NoteVoicePar[nvoice].AmpLfo=NULL; - if (NoteVoicePar[nvoice].VoiceFilter!=NULL) delete (NoteVoicePar[nvoice].VoiceFilter); - NoteVoicePar[nvoice].VoiceFilter=NULL; + if (NoteVoicePar[nvoice].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 +624,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 +701,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 +731,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) @@ -621,34 +764,67 @@ void ADnote::initparameters() }; }; + +/* + * Computes the relative frequency of each unison voice and it's vibratto + * This must be called before setfreq* functions + */ +void ADnote::compute_unison_freq_rap(int nvoice){ + if (unison_size[nvoice]==1){//no unison + 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]; + pos+=step; + if (pos<=-1.0) { + pos=-1.0; + step=-step; + }; + if (pos>=1.0){ + pos=1.0; + step=-step; + }; + 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; + }; + +}; /* * Computes the frequency of an oscillator */ -void ADnote::setfreq(int nvoice,REALTYPE freq) +void ADnote::setfreq(int nvoice,REALTYPE in_freq) { - REALTYPE speed; - freq=fabs(freq); - speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; - if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE freq=fabs(in_freq)*unison_freq_rap[nvoice][k]; + REALTYPE speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; - F2I(speed,oscfreqhi[nvoice]); - oscfreqlo[nvoice]=speed-floor(speed); + F2I(speed,oscfreqhi[nvoice][k]); + oscfreqlo[nvoice][k]=speed-floor(speed); + }; }; /* * Computes the frequency of an modullator oscillator */ -void ADnote::setfreqFM(int nvoice,REALTYPE freq) +void ADnote::setfreqFM(int nvoice,REALTYPE in_freq) { - REALTYPE speed; - freq=fabs(freq); - speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; - if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + for (int k=0;k<unison_size[nvoice];k++){ + REALTYPE freq=fabs(in_freq)*unison_freq_rap[nvoice][k]; + REALTYPE speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; - F2I(speed,oscfreqhiFM[nvoice]); - oscfreqloFM[nvoice]=speed-floor(speed); + F2I(speed,oscfreqhiFM[nvoice][k]); + oscfreqloFM[nvoice][k]=speed-floor(speed); + }; }; /* @@ -721,6 +897,8 @@ void ADnote::computecurrentparameters() NoteVoicePar[nvoice].DelayTicks-=1; if (NoteVoicePar[nvoice].DelayTicks>0) continue; + compute_unison_freq_rap(nvoice); + /*******************/ /* Voice Amplitude */ /*******************/ @@ -736,7 +914,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 +924,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 +994,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 +1065,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 +1114,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 +1161,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 + //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 (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(poslo,1.0); + poshi++; + }; + + poshi+=freqhi; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice][k]=poshi; + oscposlo[nvoice][k]=poslo; + + }; }; @@ -1049,7 +1285,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 +1340,123 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr) } else ComputeVoiceNoise(nvoice); // Voice Processing + + //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++){ + REALTYPE *tw=tmpwave_unison[k]; + if (stereo){ + REALTYPE stereo_pos=0; + if (unison_size[nvoice]>1) stereo_pos=k/(REALTYPE)(unison_size[nvoice]-1)*2.0-1.0; + REALTYPE stereo_spread=unison_stereo_spread[nvoice]*2.0;//between 0 and 2.0 + if (stereo_spread>1.0){ + REALTYPE stereo_pos_1=(stereo_pos>=0.0)?1.0:-1.0; + stereo_pos=(2.0-stereo_spread)*stereo_pos+(stereo_spread-1.0)*stereo_pos_1; + }else{ + stereo_pos*=stereo_spread; + }; + if (unison_size[nvoice]==1) stereo_pos=0.0; + REALTYPE panning=(stereo_pos+1.0)*0.5; + + + REALTYPE lvol=(1.0-panning)*2.0; + if (lvol>1.0) lvol=1.0; + + 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{ + 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; + 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 }; // 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 @@ -57,8 +57,9 @@ public: private: - void setfreq(int nvoice,REALTYPE freq); - void setfreqFM(int nvoice,REALTYPE freq); + void setfreq(int nvoice,REALTYPE in_freq); + void setfreqFM(int nvoice,REALTYPE in_freq); + void compute_unison_freq_rap(int nvoice); void computecurrentparameters(); void initparameters(); void KillVoice(int nvoice); @@ -178,7 +179,8 @@ private: * FILTER PARAMETERS * *************************/ - Filter *VoiceFilter; + Filter *VoiceFilterL; + Filter *VoiceFilterR; REALTYPE FilterCenterPitch;/* Filter center Pitch*/ REALTYPE FilterFreqTracking; @@ -206,6 +208,7 @@ private: Envelope *FMFreqEnvelope; Envelope *FMAmpEnvelope; + } NoteVoicePar[NUM_VOICES]; @@ -216,17 +219,40 @@ private: //time from the start of the note REALTYPE time; + //the size of unison for a single voice + int unison_size[NUM_VOICES]; + + //the stereo spread of the unison subvoices (0.0=mono,1.0=max) + REALTYPE unison_stereo_spread[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]; + + //the unison base_value + REALTYPE *unison_base_freq_rap[NUM_VOICES]; + + //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 { + REALTYPE amplitude; //amplitude which be added to unison_freq_rap + REALTYPE *step; //value which increments the position + REALTYPE *position;//between -1.0 and 1.0 + }unison_vibratto[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 +261,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; diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -27,15 +27,14 @@ #include "OscilGen.h" #include "../Effects/Distorsion.h" -REALTYPE *OscilGen::tmpsmps;//this array stores some termporary data and it has SOUND_BUFFER_SIZE elements -FFTFREQS OscilGen::outoscilFFTfreqs; - - OscilGen::OscilGen(FFTwrapper *fft_,Resonance *res_):Presets() { setpresettype("Poscilgen"); fft=fft_; res=res_; + + tmpsmps = new REALTYPE[OSCIL_SIZE]; + newFFTFREQS(&outoscilFFTfreqs, OSCIL_SIZE/2); newFFTFREQS(&oscilFFTfreqs,OSCIL_SIZE/2); newFFTFREQS(&basefuncFFTfreqs,OSCIL_SIZE/2); @@ -47,6 +46,8 @@ OscilGen::OscilGen(FFTwrapper *fft_,Resonance *res_):Presets() OscilGen::~OscilGen() { + delete[] tmpsmps; + deleteFFTFREQS(&outoscilFFTfreqs); deleteFFTFREQS(&basefuncFFTfreqs); deleteFFTFREQS(&oscilFFTfreqs); }; diff --git a/src/Synth/OscilGen.h b/src/Synth/OscilGen.h @@ -109,10 +109,10 @@ public: bool ADvsPAD;//if it is used by ADsynth or by PADsynth - static REALTYPE *tmpsmps;//this array stores some termporary data and it has SOUND_BUFFER_SIZE elements - static FFTFREQS outoscilFFTfreqs; - private: + //This array stores some termporary data and it has OSCIL_SIZE elements + REALTYPE *tmpsmps; + FFTFREQS outoscilFFTfreqs; REALTYPE hmag[MAX_AD_HARMONICS],hphase[MAX_AD_HARMONICS];//the magnituides and the phases of the sine/nonsine harmonics // private: diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.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} {} @@ -178,19 +178,19 @@ class ADvoiceUI {open : {public Fl_Group} } { Fl_Window ADnoteVoiceParameters { label Voice - xywh {225 174 765 525} type Double hide - class Fl_Group + xywh {69 185 765 575} type Double + class Fl_Group visible } { - Fl_Group voiceparametersgroup { - xywh {0 0 765 525} box THIN_UP_BOX color 48 + Fl_Group voiceparametersgroup {open + xywh {0 0 765 580} box THIN_UP_BOX color 48 code0 {if (pars->VoicePar[nvoice].Enabled==0) o->deactivate();} } { - Fl_Group voicemodegroup { - xywh {0 5 760 515} + Fl_Group voicemodegroup {open + xywh {0 5 760 575} } { Fl_Group voiceFMparametersgroup { label MODULATOR - xywh {530 5 230 515} box THIN_UP_FRAME color 48 labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 17 + xywh {530 5 230 565} box THIN_UP_FRAME color 48 labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 17 code0 {if (pars->VoicePar[nvoice].PFMEnabled==0) o->deactivate();} } { Fl_Group modfrequency { @@ -209,7 +209,7 @@ class ADvoiceUI {open : {public Fl_Group} callback {pars->VoicePar[nvoice].PFMFreqEnvelopeEnabled=(int)o->value(); if (o->value()==0) voiceFMfreqenvgroup->deactivate(); else voiceFMfreqenvgroup->activate(); -o->redraw();} selected +o->redraw();} tooltip {Forced Relase} xywh {545 295 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 code0 {o->value(pars->VoicePar[nvoice].PFMFreqEnvelopeEnabled);} } @@ -298,10 +298,10 @@ o->redraw();} } } Fl_Group modoscil { - xywh {535 365 220 150} + xywh {535 365 220 200} } { Fl_Group fmoscil {open - xywh {535 405 220 110} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + xywh {535 425 220 140} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 code0 {oscFM=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} code1 {int nv=nvoice; if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil;} code2 {oscFM->init(pars->VoicePar[nv].FMSmp,0,pars->VoicePar[nvoice].PFMoscilphase,master);} @@ -326,7 +326,7 @@ oscedit=new OscilEditor(pars->VoicePar[nv].FMSmp,fmoscil,NULL,NULL,master);} callback {pars->VoicePar[nvoice].PFMoscilphase=64-(int)o->value(); oscFM->phase=64-(int) o->value(); fmoscil->redraw();} - xywh {665 395 65 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + xywh {665 400 65 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 code0 {o->value(64-pars->VoicePar[nvoice].PFMoscilphase);} } Fl_Choice {} { @@ -340,7 +340,7 @@ if ((int) o->value() != 0) { changeFMoscilbutton->labelcolor(FL_BLACK); }; voiceFMparametersgroup->redraw();} open - xywh {560 390 75 15} down_box BORDER_BOX labelsize 10 textfont 1 textsize 10 + xywh {560 395 75 15} down_box BORDER_BOX labelsize 10 textfont 1 textsize 10 code0 {o->add("Internal");} code1 {char tmp[50]; for (int i=0;i<nvoice;i++) {sprintf(tmp,"ExtM.%2d",i+1);o->add(tmp);};} code3 {o->value(pars->VoicePar[nvoice].PextFMoscil+1);} @@ -548,6 +548,58 @@ voiceonbutton->redraw();} open code1 {char tmp[50]; for (int i=0;i<nvoice;i++) {sprintf(tmp,"Ext.%2d",i+1);o->add(tmp);};} code3 {o->value(pars->VoicePar[nvoice].Pextoscil+1);} } {} + Fl_Group {} {open + 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 {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_Choice {} { + label Unison + 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->get_unison_size_index(nvoice));} + } {} + Fl_Dial {} { + label Vibratto + 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 {} { label AMPLITUDE @@ -728,7 +780,8 @@ o->redraw();} pars=NULL; oscedit=NULL;} {} } - Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {} { + Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {open + } { code {pars=parameters; nvoice=nvoice_; master=master_; @@ -752,7 +805,7 @@ if (oscedit!=NULL) { decl {Master *master;} {} } -class ADnoteUI {: {public PresetsUI_} +class ADnoteUI {open : {public PresetsUI_} } { Function {make_window()} {open private } { @@ -967,10 +1020,10 @@ resui->resonancewindow->show();} } Fl_Window ADnoteVoice { label {ADsynth Voice Parameters} - xywh {53 58 765 560} type Double hide + xywh {152 271 765 620} type Double visible } { Fl_Group advoice { - xywh {0 0 760 525} box BORDER_BOX + xywh {0 0 760 575} box BORDER_BOX code0 {o->init(pars,nvoice,master);} code1 {o->show();} class ADvoiceUI @@ -978,7 +1031,7 @@ resui->resonancewindow->show();} Fl_Button {} { label {Close Window} callback {ADnoteVoice->hide();} - xywh {300 530 195 25} box THIN_UP_BOX labelfont 1 + xywh {300 585 195 25} box THIN_UP_BOX labelfont 1 } Fl_Counter currentvoicecounter { label {Current Voice} @@ -986,23 +1039,23 @@ resui->resonancewindow->show();} advoice->hide(); ADnoteVoice->remove(advoice); delete advoice; -advoice=new ADvoiceUI(0,0,765,525); +advoice=new ADvoiceUI(0,0,765,585); ADnoteVoice->add(advoice); advoice->init(pars,nvoice,master); advoice->show(); ADnoteVoice->redraw();} - xywh {5 530 130 25} type Simple labelfont 1 align 8 minimum 0 maximum 2 step 1 value 1 textfont 1 textsize 13 + xywh {5 585 130 25} type Simple labelfont 1 align 8 minimum 0 maximum 2 step 1 value 1 textfont 1 textsize 13 code0 {o->bounds(1,NUM_VOICES);} } Fl_Button {} { label C callback {presetsui->copy(pars,nvoice);} - xywh {700 535 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 + xywh {700 590 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 } Fl_Button {} { label P callback {presetsui->paste(pars,this,nvoice);} - xywh {730 535 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 + xywh {730 590 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 } } Fl_Window ADnoteVoiceList { 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);} {} diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -1,9 +1,8 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0109 +version 1.0107 header_name {.h} code_name {.cc} -decl {//Copyright (c) 2002-2009 Nasca Octavian Paul} {selected -} +decl {//Copyright (c) 2002-2009 Nasca Octavian Paul} {} decl {//License: GNU GPL version 2 or later} {} @@ -275,7 +274,8 @@ labelsize(10); align(FL_ALIGN_TOP); value(master->Psysefxsend[neff1][neff2]); -char tmp[20];snprintf(tmp,20,"%d->%d",neff1+1,neff2+1);this->label(strdup(tmp));} {} +char tmp[20];snprintf(tmp,20,"%d->%d",neff1+1,neff2+1); +this->copy_label(tmp);} {} } Function {~SysEffSend()} {} { code {hide();} {} @@ -344,7 +344,7 @@ bankui->show();} xywh {15 235 40 20} box PLASTIC_UP_BOX labelsize 10 } Fl_Choice partrcv { - callback {master->part[npart]->Prcvchn=(int) o->value();} open + callback {master->part[npart]->Prcvchn=(int) o->value();} tooltip {receive from Midi channel} xywh {10 213 50 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {char nrstr[10]; for(int i=0;i<NUM_MIDI_CHANNELS;i++){sprintf(nrstr,"Ch%d",i+1);if (i!=9) o->add(nrstr); else o->add("Dr10");};} code1 {o->value(master->part[npart]->Prcvchn);} @@ -367,7 +367,7 @@ if ((int) o->value()==0) panellistitemgroup->deactivate(); o->redraw();} private xywh {5 0 45 20} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 24 - code0 {char tmp[10];snprintf(tmp,10,"%d",npart+1);o->label(strdup(tmp));} + code0 {char tmp[10];snprintf(tmp,10,"%d",npart+1);o->copy_label(tmp);} code1 {o->value(master->part[npart]->Penabled);} } } @@ -386,8 +386,7 @@ make_window(); panellistitem->show(); end();} {} } - Function {refresh()} {open - } { + Function {refresh()} {} { code {partenabled->value(master->part[npart]->Penabled); if (master->part[npart]->Penabled!=0) panellistitemgroup->activate(); else panellistitemgroup->deactivate(); @@ -415,7 +414,8 @@ panellistitemgroup->redraw();} {} } class MasterUI {} { - Function {make_window()} {} { + Function {make_window()} {selected + } { Fl_Window masterwindow { label zynaddsubfx callback {\#ifdef VSTAUDIOOUT @@ -426,7 +426,7 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL)) { *exitprogram=1; }; \#endif} - xywh {31 206 390 465} type Double xclass zynaddsubfx visible + xywh {31 206 390 465} type Double hide xclass zynaddsubfx } { Fl_Menu_Bar mastermenu { xywh {-5 0 690 25} @@ -1043,18 +1043,18 @@ GNU General Public License for details.} label {ZynAddSubFX Panel} xywh {89 59 630 635} type Double hide } { - Fl_Scroll {} {open + Fl_Scroll {} { xywh {0 5 570 310} type HORIZONTAL box THIN_UP_BOX } { - Fl_Pack {} {open + Fl_Pack {} { xywh {5 10 560 285} type HORIZONTAL code0 {for (int i=0;i<NUM_MIDI_PARTS/2;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(master,i,bankui);}} } {} } - Fl_Scroll {} {open + Fl_Scroll {} { xywh {0 320 570 310} type HORIZONTAL box THIN_UP_BOX } { - Fl_Pack {} {open + Fl_Pack {} { xywh {5 325 560 285} type HORIZONTAL code0 {for (int i=NUM_MIDI_PARTS/2;i<NUM_MIDI_PARTS;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(master,i,bankui);}} } {} @@ -1288,7 +1288,7 @@ if ((int) o->value()==0) simplelistitemgroup->deactivate(); o->redraw();} private xywh {250 40 85 20} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 24 - code0 {//char tmp[10];snprintf(tmp,10,"%d",npart+1);o->label(strdup(tmp));} + code0 {//char tmp[10];snprintf(tmp,10,"%d",npart+1);o->copy_label(tmp);} code1 {o->value(master->part[npart]->Penabled);} } Fl_Box virkeys { @@ -1643,19 +1643,23 @@ simplerefresh();} {} } Function {~MasterUI()} {} { code {masterwindow->hide(); -delete (masterwindow); +delete masterwindow; +simplemasterwindow->hide(); +delete simplemasterwindow; aboutwindow->hide(); -delete (aboutwindow); +delete aboutwindow; syseffsendwindow->hide(); -delete(syseffsendwindow); +delete syseffsendwindow; -delete (virkeyboard); -delete (microtonalui); -delete (bankui); -delete (configui); -delete (sequi); +delete virkeyboard; +delete microtonalui; +delete bankui; +delete configui; +delete sequi; -delete(presetsui);} {} +delete presetsui; +delete panelwindow; +delete selectuiwindow;} {} } Function {showUI()} {} { code {switch (config.cfg.UserInterfaceMode){ diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl @@ -56,7 +56,7 @@ class PartSysEffSend {: {public Fl_Group} xywh {0 0 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 align 130 maximum 127 step 1 code0 {o->size(25,25);} code1 {o->value(master->Psysefxvol[neff][npart]);} - code2 {char tmp[10];snprintf(tmp,10,"%d",neff+1);o->label(strdup(tmp));} + code2 {char tmp[10];snprintf(tmp,10,"%d",neff+1);o->copy_label(tmp);} class WidgetPDial } } @@ -212,7 +212,7 @@ o->redraw(); partui->showparameters(n,-1);//use to delete the ui, if it is not to item 0 } else o->value(1);} private xywh {30 0 20 15} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 4 - code0 {snprintf(label,10,"%d",n+1);o->label(strdup(label));} + code0 {snprintf(label,10,"%d",n+1);o->label(label);} code1 {o->value(part->kit[n].Penabled);} code2 {if (n==0) o->deactivate();} } @@ -590,7 +590,7 @@ part->ctl.portamento.updowntimestretch=x;} } Fl_Dial proptb { label {Prp.Dpth} - callback {part->ctl.portamento.propDepth=(int) o->value();} selected + callback {part->ctl.portamento.propDepth=(int) o->value();} tooltip {The difference from nonproportinal portamento} xywh {405 60 25 25} labelsize 9 maximum 127 step 1 code0 {o->value(part->ctl.portamento.propDepth);} class WidgetPDial @@ -841,7 +841,7 @@ if (part->Pkitmode==0) { } } Fl_Window instrumenteditwindow { - label {Instrument Edit} + label {Instrument Edit} selected xywh {182 214 395 360} type Double hide } { Fl_Group {} { diff --git a/src/UI/VirKeyboard.fl b/src/UI/VirKeyboard.fl @@ -41,9 +41,9 @@ decl {const int keysoct1qwertz[]={'q','2','w','3','e','r','5','t','6','z','7','u decl {const int keysoct2qwertz[]={'y','s','x','d','c','v','g','b','h','n','j','m',',','l','.',246,'-',0};} {} -decl {const int keysoct1az[]={'a',233,'z','\\"','e','r','(','t','-','y',232,'u','i',231,'o',224,'p',65106,'=','$',0};} {} +decl {const int keysoct1az[]={'a',233,'z','\\"','e','r','(','t','-','y',232,'u','i',231,'o',224,'p',65106,'=','$',0};} {} -decl {const int keysoct2az[]={'w','s','x','d','c','v','g','b','h','n','j',',',';','l',':','m','!',0};} {} +decl {const int keysoct2az[]={'w','s','x','d','c','v','g','b','h','n','j',',',';','l',':','m','!',0};} {} class VirKeys {: {public Fl_Box} } { @@ -184,8 +184,7 @@ if ((event==FL_KEYDOWN)||(event==FL_KEYUP)){ return(1);} {} } - Function {presskey(int nk,int exclusive,int type)} {selected - } { + Function {presskey(int nk,int exclusive,int type)} {} { code {//Exclusive means that multiple keys can be pressed at once //when the user uses the shift key if (nk>=N_OCT*12) return; @@ -410,6 +409,10 @@ virkeys->take_focus();} open midictl=75; make_window();} {} } + Function {~VirKeyboard()} {} { + code {delete virkeyboardwindow;} {selected + } + } Function {show()} {} { code {virkeyboardwindow->show();} {} } diff --git a/src/UI/WidgetPDial.fl b/src/UI/WidgetPDial.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0109 +version 1.0107 header_name {.h} code_name {.cc} decl {//Copyright (c) 2003-2005 Nasca Octavian Paul} {} @@ -61,7 +61,8 @@ textmode=false; } Function {setText(const char * c)} {return_type void } { - code {strcpy(text,c); + code {strncpy(text, c, max_tooltip_len-1); +text[max_tooltip_len-1] = 0; textmode=true; // Recalc size of window fl_font(labelfont(), labelsize()); @@ -84,7 +85,9 @@ textmode=true; } decl {char tip[40];} {} decl {bool textmode;} {} - decl {char text[400];//bad stuff will happen if too much is put in this (perhaps dynamically allocate?)} {} + decl {enum { max_tooltip_len = 400 };} {selected + } + decl {char text[max_tooltip_len];} {} } class WidgetPDial {: {public Fl_Dial} @@ -153,8 +156,7 @@ case FL_RELEASE: return(1); break; }; -return(0);} {selected - } +return(0);} {} } Function {drawgradient(int cx,int cy,int sx,double m1,double m2)} {return_type void } { diff --git a/src/main.cpp b/src/main.cpp @@ -301,9 +301,6 @@ void initprogram() denormalkillbuf=new REALTYPE [SOUND_BUFFER_SIZE]; for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5)*1e-16; - OscilGen::tmpsmps=new REALTYPE[OSCIL_SIZE]; - newFFTFREQS(&OscilGen::outoscilFFTfreqs,OSCIL_SIZE/2); - master=new Master(); master->swaplr=swaplr; @@ -375,10 +372,7 @@ void exitprogram() // pthread_mutex_unlock(&master->mutex); delete [] denormalkillbuf; - delete [] OscilGen::tmpsmps; - deleteFFTFREQS(&OscilGen::outoscilFFTfreqs); - -}; +} #ifdef OS_WINDOWS #define ARGSIZE 100