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:
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);} {}