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