commit 4c93218559ec43945b4d708f75939669fb9fc086
parent 38a80b06c8d3d5b97d4bc87ea612ece2f4e60692
Author: fundamental <mark.d.mccurry@gmail.com>
Date: Sat, 11 Jul 2009 10:32:33 -0400
Merge branch 'portamento'
Conflicts:
src/Tests/make.sh
Added Proportional Portamento to 'master'
Diffstat:
7 files changed, 204 insertions(+), 45 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -873,3 +873,6 @@
10 Iul 2009 (Paul Nasca)
- Update copyright info
+
+11 Jul 2009 (Mark McCurry)
+ - Added Proportinal Portamento
diff --git a/src/Params/Controller.cpp b/src/Params/Controller.cpp
@@ -52,6 +52,9 @@ void Controller::defaults()
portamento.portamento=0;
portamento.used=0;
+ portamento.proportional=0;
+ portamento.propRate=80;
+ portamento.propDepth=90;
portamento.receive=1;
portamento.time=64;
portamento.updowntimestretch=64;
@@ -179,8 +182,6 @@ void Controller::setportamento(int value)
if (portamento.receive!=0) portamento.portamento=((value<64) ? 0 : 1 );
};
-// I added a third argument to pass legato status,
-// when legatoflag is true it means "there's a legato in progress".
int Controller::initportamento(REALTYPE oldfreq,REALTYPE newfreq,bool legatoflag)
{
portamento.x=0.0;
@@ -192,6 +193,18 @@ int Controller::initportamento(REALTYPE oldfreq,REALTYPE newfreq,bool legatoflag
};
REALTYPE portamentotime=pow(100.0,portamento.time/127.0)/50.0;//portamento time in seconds
+
+ if (portamento.proportional) {
+ //If there is a min(float,float) and a max(float,float) then they
+ //could be used here
+ //Linear functors could also make this nicer
+ if(oldfreq > newfreq) //2 is the center of propRate
+ portamentotime *= pow(oldfreq/newfreq/(portamento.propRate/127.0*3+.05),
+ (portamento.propDepth/127.0*1.6+.2));
+ else //1 is the center of propDepth
+ portamentotime *= pow(newfreq/oldfreq/(portamento.propRate/127.0*3+.05),
+ (portamento.propDepth/127.0*1.6+.2));
+ }
if ((portamento.updowntimestretch>=64)&&(newfreq<oldfreq)) {
if (portamento.updowntimestretch==127) return(0);
@@ -202,6 +215,8 @@ int Controller::initportamento(REALTYPE oldfreq,REALTYPE newfreq,bool legatoflag
portamentotime*=pow(0.1,(64.0-portamento.updowntimestretch)/64.0);
};
+ //printf("%f->%f : Time %f\n",oldfreq,newfreq,portamentotime);
+
portamento.dx=SOUND_BUFFER_SIZE/(portamentotime*SAMPLE_RATE);
portamento.origfreqrap=oldfreq/newfreq;
@@ -303,6 +318,9 @@ void Controller::add2XML(XMLwrapper *xml)
xml->addpar("portamento_pitchthreshtype",portamento.pitchthreshtype);
xml->addpar("portamento_portamento",portamento.portamento);
xml->addpar("portamento_updowntimestretch",portamento.updowntimestretch);
+ xml->addpar("portamento_proportional",portamento.proportional);
+ xml->addpar("portamento_proprate",portamento.propRate);
+ xml->addpar("portamento_propdepth",portamento.propDepth);
xml->addpar("resonance_center_depth",resonancecenter.depth);
xml->addpar("resonance_bandwidth_depth",resonancebandwidth.depth);
@@ -329,6 +347,10 @@ void Controller::getfromXML(XMLwrapper *xml)
portamento.pitchthreshtype=xml->getpar127("portamento_pitchthreshtype",portamento.pitchthreshtype);
portamento.portamento=xml->getpar127("portamento_portamento",portamento.portamento);
portamento.updowntimestretch=xml->getpar127("portamento_updowntimestretch",portamento.updowntimestretch);
+ portamento.proportional=xml->getpar127("portamento_proportional",portamento.proportional);
+ portamento.propRate=xml->getpar127("portamento_proprate",portamento.propRate);
+ portamento.propDepth=xml->getpar127("portamento_propdepth",portamento.propDepth);
+
resonancecenter.depth=xml->getpar127("resonance_center_depth",resonancecenter.depth);
resonancebandwidth.depth=xml->getpar127("resonance_bandwidth_depth",resonancebandwidth.depth);
diff --git a/src/Params/Controller.h b/src/Params/Controller.h
@@ -51,6 +51,8 @@ public:
void setfmamp(int value);
void setvolume(int value);
void setsustain(int value);
+ /**Enable or disable portamento
+ * @param value 0-127 MIDI value (greater than 64 enables)*/
void setportamento(int value);
void setresonancecenter(int value);
void setresonancebw(int value);
@@ -59,8 +61,16 @@ public:
void setparameternumber(unsigned int type,int value);//used for RPN and NRPN's
int getnrpn(int *parhi, int *parlo, int *valhi, int *vallo);
- int initportamento(REALTYPE oldfreq,REALTYPE newfreq,bool legatoflag);//returns 1 if the portamento's conditions are true, else return 0
- void updateportamento(); //update portamento values
+ /**
+ * Initialize a portamento
+ *
+ * @param oldfreq Starting frequency of the portamento (Hz)
+ * @param newfreq Ending frequency of the portamento (Hz)
+ * @param legatoflag true when legato is in progress, false otherwise
+ * @returns 1 if properly initialized, 0 otherwise*/
+ int initportamento(REALTYPE oldfreq,REALTYPE newfreq,bool legatoflag);
+ /**Update portamento's freqrap to next value based upon dx*/
+ void updateportamento();
// Controllers values
struct {//Pitch Wheel
@@ -129,29 +139,59 @@ public:
//parameters
int data;
unsigned char portamento;
-
- unsigned char receive,time;
- /**pitchthresh is the threshold of enabling protamento \todo see if this should be an int*/
+ /**Whether the portamento midi events are received or not*/
+ unsigned char receive;
+ /** The time that it takes for the portamento to complete
+ *
+ * Translates in an expontal fashion to 0 Seconds to 1.93 Seconds
+ * of completion time*/
+ unsigned char time;
+ /**If the portamento is proportinal to the distance spanned
+ *
+ * 0 - constant time(default)
+ * 1 - proportional*/
+ unsigned char proportional;
+ /**Rate of proportinal portamento*/
+ unsigned char propRate;
+ /**Depth of proportinal portamento*/
+ unsigned char propDepth;
+ /**pitchthresh is the threshold of enabling protamento*/
unsigned char pitchthresh;
- /**pitchthreshtype -> enable the portamento only below(0)/above(1) the threshold*/
+ /**enable the portamento only below(0)/above(1) the threshold*/
unsigned char pitchthreshtype;
/**this value represent how the portamento time is reduced
- * 0 - for down portamento, 1..63 - the up portamento's time is smaller than the down portamento
- * 64 - the portamento time is always the same
- * 64-126 - the down portamento's time is smaller than the up portamento
- * 127 - for upper portamento
- * 'up portanemto' means when the frequency is rising (eg: the portamento is from 200Hz to 300 Hz)
- * 'down portanemto' means when the frequency is lowering (eg: the portamento is from 300Hz to 200 Hz)
+ * 0 - for down portamento
+ * 1-63 - the up portamento's time is smaller than the down portamento
+ * 64 - the portamento time is always the same
+ * 64-126 - the down portamento's time is smaller than the up portamento
+ * 127 - for upper portamento
+ * 'up portamento' means when the frequency is rising
+ * (eg: the portamento is from 200Hz to 300 Hz)
+ * 'down portamento' means when the frequency is lowering
+ * (eg: the portamento is from 300Hz to 200 Hz)
*/
unsigned char updowntimestretch;
-
- REALTYPE freqrap;/**<this value is used to compute the actual portamento*/
- int noteusing;/**this is used by the Part for knowing which note uses the portamento*/
- int used;/**<if a the portamento is used by a note \todo see if this can be a bool*/
- //internal data
- REALTYPE x,dx;//x is from 0.0 (start portamento) to 1.0 (finished portamento), dx is x increment
- REALTYPE origfreqrap;// this is used for computing oldfreq value from x
+ /**this value is used to compute the actual portamento
+ *
+ * This is a multiplyer to change the frequency of the newer
+ * frequency to fit the profile of the portamento.
+ * This will be linear with respect to x.*/
+ REALTYPE freqrap;
+ /**this is used by the Part for knowing which note uses the portamento*/
+ int noteusing;
+ /**if a the portamento is used by a note
+ * \todo see if this can be a bool*/
+ int used;
+
+ //Internal data
+
+ /**x is from 0.0 (start portamento) to 1.0 (finished portamento)*/
+ REALTYPE x;
+ /**dx is the increment to x when updateportamento is called*/
+ REALTYPE dx;
+ /** this is used for computing oldfreq value from x*/
+ REALTYPE origfreqrap;
} portamento;
struct {//Resonance Center Frequency
diff --git a/src/Tests/ControllerTest.h b/src/Tests/ControllerTest.h
@@ -0,0 +1,73 @@
+/*
+ ZynAddSubFX - a software synthesizer
+
+ ControllerTest.h - CxxTest for Params/Controller
+ Copyright (C) 2009-2009 Mark McCurry
+ Author: Mark McCurry
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (version 2 or later) for more details.
+
+ You should have received a copy of the GNU General Public License (version 2)
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+#include <cxxtest/TestSuite.h>
+#include <iostream>
+#include "../Params/Controller.h"
+
+class ControllerTest : public CxxTest::TestSuite
+{
+public:
+ void setUp() {
+ testCtl=new Controller();
+ }
+
+ void tearDown() {
+ delete testCtl;
+ }
+
+
+ void testPortamentoRange() {
+ //Initialize portamento
+ testCtl->setportamento(127);
+ testCtl->portamento.time=127;
+ testCtl->initportamento(40.0,400.0,false);
+ //Bounds Check
+ while(testCtl->portamento.used){
+ TS_ASSERT((0.0<=testCtl->portamento.x)&&
+ (testCtl->portamento.x<=1.0));
+ TS_ASSERT((0.1<=testCtl->portamento.freqrap)&&
+ (testCtl->portamento.freqrap<=1.0));
+ testCtl->updateportamento();
+ }
+ TS_ASSERT((0.0<=testCtl->portamento.x)&&
+ (testCtl->portamento.x<=1.0));
+ TS_ASSERT((0.1<=testCtl->portamento.freqrap)&&
+ (testCtl->portamento.freqrap<=1.0));
+ }
+
+ void testPortamentoValue() {
+ testCtl->setportamento(127);
+ testCtl->portamento.time=127;
+ testCtl->initportamento(40.0,400.0,false);
+ int i;
+ for(i=0;i<10;++i){
+ testCtl->updateportamento();
+ }
+ //Assert that the numbers are the same as they were at release
+ TS_ASSERT_DELTA(testCtl->portamento.x,0.0290249,0.000001)
+ TS_ASSERT_DELTA(testCtl->portamento.freqrap,0.126122,0.000001)
+ }
+
+private:
+ Controller *testCtl;
+
+};
diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h
@@ -24,9 +24,6 @@
#include "../Effects/Echo.h"
#include "../globals.h"
-int SOUND_BUFFER_SIZE=256;
-int SAMPLE_RATE=1024;
-
class EchoTest : public CxxTest::TestSuite
{
public:
@@ -59,10 +56,10 @@ public:
//Make sure that the output will be zero at start
//(given a zero input)
testFX->out(inL,inR);
- for (int i=0;i<SOUND_BUFFER_SIZE;++i)
- TS_ASSERT_EQUALS(outL[i],0.0);
- for (int i=0;i<SOUND_BUFFER_SIZE;++i)
- TS_ASSERT_EQUALS(outR[i],0.0);
+ for (int i=0;i<SOUND_BUFFER_SIZE;++i){
+ TS_ASSERT_DELTA(outL[i],0.0,0.0001);
+ TS_ASSERT_DELTA(outR[i],0.0,0.0001);
+ }
}
void testClear() {
@@ -72,7 +69,7 @@ public:
*(inL+i)=1.0;
for (int i=0;i<SOUND_BUFFER_SIZE;++i)
*(inR+i)=1.0;
- for (int i=0;i<50;++i)
+ for (int i=0;i<500;++i)
testFX->out(inL,inR);
for (int i=0;i<SOUND_BUFFER_SIZE;++i) {
TS_ASSERT_DIFFERS(outL[i],0.0);
@@ -97,7 +94,7 @@ public:
*(inR+i)=1.0;
char FEEDBACK=5;
testFX->changepar(FEEDBACK,127);
- for (int i=0;i<4;++i)
+ for (int i=0;i<100;++i)
testFX->out(inL,inR);
for (int i=0;i<SOUND_BUFFER_SIZE;++i) {
TS_ASSERT_DIFFERS(outL[i],0.0);
diff --git a/src/Tests/make.sh b/src/Tests/make.sh
@@ -1,5 +1,5 @@
cd ../
make
cd Tests
-cxxtestgen.py --error-printer -o runner.cpp SampleTest.h EchoTest.h
-g++ -g -o runner runner.cpp ../Samples/AuSample.o ../Samples/Sample.o ../Effects/Echo.o ../Effects/Effect.o ../Controls/Control.o ../Controls/DelayCtl.o
+cxxtestgen.py --error-printer -o runner.cpp SampleTest.h EchoTest.h ControllerTest.h
+g++ -g -o runner runner.cpp ../Samples/AuSample.o ../Samples/Sample.o ../Effects/Echo.o ../Effects/Effect.o ../Controls/Control.o ../Controls/DelayCtl.o ../Params/Controller.o ../Misc/XMLwrapper.o ../Misc/Config.o ../Misc/Util.o -lmxml -lm -lz -lpthread
diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl
@@ -42,9 +42,9 @@ decl {\#include "../Misc/Master.h"} {public
decl {\#include "../Misc/Part.h"} {public
}
-class PartSysEffSend {open : {public Fl_Group}
+class PartSysEffSend {: {public Fl_Group}
} {
- Function {make_window()} {open private
+ Function {make_window()} {private
} {
Fl_Window syseffsend {
private xywh {584 83 90 35} type Double hide
@@ -52,7 +52,7 @@ class PartSysEffSend {open : {public Fl_Group}
} {
Fl_Dial {} {
label 01
- callback {master->setPsysefxvol(npart,neff,(int) o->value());} selected
+ callback {master->setPsysefxvol(npart,neff,(int) o->value());}
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]);}
@@ -274,9 +274,9 @@ end();} {}
decl {PartUI_ *partui;} {}
}
-class PartUI {open : {public Fl_Group,PartUI_}
+class PartUI {: {public Fl_Group,PartUI_}
} {
- Function {make_window()} {open private
+ Function {make_window()} {private
} {
Fl_Window partgroup {
private xywh {424 178 385 180} type Double hide
@@ -457,7 +457,7 @@ if (part->Penabled==0) partgroupui->deactivate();
}
Fl_Window ctlwindow {
label Controllers
- private xywh {198 472 460 130} type Double hide
+ private xywh {542 212 500 130} type Double hide
} {
Fl_Check_Button {} {
label Expr
@@ -540,8 +540,8 @@ if (part->ctl.sustain.receive==0) {
xywh {5 105 210 20} box THIN_UP_BOX
}
Fl_Group {} {
- label Portamento open
- xywh {280 15 120 85} box ENGRAVED_FRAME labelfont 1 labelsize 10
+ label Portamento
+ xywh {280 15 160 90} box ENGRAVED_FRAME labelfont 1 labelsize 10
} {
Fl_Check_Button {} {
label Rcv
@@ -565,7 +565,7 @@ if (part->ctl.sustain.receive==0) {
Fl_Check_Button {} {
label {th.type}
callback {part->ctl.portamento.pitchthreshtype=(int) o->value();}
- tooltip {Threshold type (min/max)} xywh {370 70 15 15} down_box DOWN_BOX labelsize 10 align 2
+ tooltip {Threshold type (min/max)} xywh {365 70 15 15} down_box DOWN_BOX labelsize 10 align 2
code0 {o->value(part->ctl.portamento.pitchthreshtype);}
}
Fl_Box {} {
@@ -581,22 +581,46 @@ part->ctl.portamento.updowntimestretch=x;}
code0 {o->value(part->ctl.portamento.updowntimestretch);}
class WidgetPDial
}
+ Fl_Dial propta {
+ label {Prp.Rate}
+ callback {part->ctl.portamento.propRate=(int) o->value();}
+ tooltip {Distance required to double change from nonpropotinal portamento time} xywh {405 20 25 25} labelsize 9 maximum 127 step 1
+ code0 {o->value(part->ctl.portamento.propRate);}
+ class WidgetPDial
+ }
+ Fl_Dial proptb {
+ label {Prp.Dpth}
+ callback {part->ctl.portamento.propDepth=(int) o->value();} selected
+ 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
+ }
+ Fl_Check_Button {} {
+ label {Proprt.}
+ callback {part->ctl.portamento.proportional=(int) o->value();
+if(o->value()){propta->activate();proptb->activate();}
+else {propta->deactivate();proptb->deactivate();}}
+ tooltip {Enable Proportinal Portamento (over fixed Portamento)} xywh {285 40 50 15} box THIN_UP_BOX down_box DOWN_BOX labelsize 9
+ code0 {o->value(part->ctl.portamento.proportional);}
+ code1 {if(o->value()){propta->activate();proptb->activate();}}
+ code2 {else {propta->deactivate();proptb->deactivate();}}
+ }
}
Fl_Group {} {
- label Resonance open
- xywh {400 15 45 85} box ENGRAVED_BOX labelfont 1 labelsize 10
+ label Resonance
+ xywh {440 15 50 90} box ENGRAVED_BOX labelfont 1 labelsize 10
} {
Fl_Dial {} {
label BWdpth
callback {part->ctl.resonancebandwidth.depth=(int) o->value();}
- tooltip {BandWidth controller depth} xywh {410 60 25 25} labelsize 10 maximum 127 step 1
+ tooltip {BandWidth controller depth} xywh {450 60 25 25} labelsize 10 maximum 127 step 1
code0 {o->value(part->ctl.resonancebandwidth.depth);}
class WidgetPDial
}
Fl_Dial {} {
label CFdpth
callback {part->ctl.resonancecenter.depth=(int) o->value();}
- tooltip {Center Frequency controller Depth} xywh {410 20 25 25} labelsize 10 maximum 127 step 1
+ tooltip {Center Frequency controller Depth} xywh {450 20 25 25} labelsize 10 maximum 127 step 1
code0 {o->value(part->ctl.resonancecenter.depth);}
class WidgetPDial
}