commit d1513405b098b4223fe56f3d4d8885efda7f306c
parent 858c0930dacdaa46ff3488920384834c549e8db5
Author: paulnasca <paulnasca>
Date: Tue, 14 Nov 2006 16:26:36 +0000
*** empty log message ***
Diffstat:
10 files changed, 605 insertions(+), 196 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -814,6 +814,8 @@
01 Nov 2006 - Adaugat patch-urile de Jack Midi si LASH de Lars Luthman
06 Nov 2006 - Aplicat un patch "Fix for ALSA system lockup" de Lars Luthman
10 Nov 2006 - Aplicat un patch "zyn-extendedmono_v4_update-061110.diff.gz" de Gerald Folcher
+14 Nov 2006 - Aplicat un patch "zyn-CVS-extendedmono_v5_update-061113.diff.gz" de Gerald Folcher
+
diff --git a/src/Misc/Part.C b/src/Misc/Part.C
@@ -78,6 +78,7 @@ Part::Part(Microtonal *microtonal_,FFTwrapper *fft_, pthread_mutex_t *mutex_){
oldvolumel=oldvolumer=0.5;
lastnote=-1;
lastpos=0; // lastpos will store previously used NoteOn(...)'s pos.
+ lastlegatomodevalid=false; // To store previous legatomodevalid value.
defaults();
@@ -185,16 +186,18 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
int i,pos;
// Legato and MonoMem used vars:
+ int posb=POLIPHONY-1; // Just a dummy initial value.
+ bool legatomodevalid=false;//true when legato mode is determined applicable.
bool doinglegato=false; // true when we determined we do a legato note.
bool ismonofirstnote=false; /*(In Mono/Legato) true when we determined
no other notes are held down or sustained.*/
- int lastnotecopy=lastnote; // Useful after lastnote has been changed.
+ int lastnotecopy=lastnote;//Useful after lastnote has been changed.
- if (Pnoteon==0) return; // (This check was performed later)
+ if (Pnoteon==0) return;
if ((note<Pminkey)||(note>Pmaxkey)) return;
// MonoMem stuff:
- if (Ppolymode==0){ // If Poly is off (should we check for drummode too ?).
+ if (Ppolymode==0){ // If Poly is off
monomemnotes.push_back(note); // Add note to the list.
monomem[note].velocity=velocity; // Store this note's velocity.
monomem[note].mkeyshift=masterkeyshift; /* Store masterkeyshift too,
@@ -219,21 +222,35 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
};
if ((Plegatomode!=0) && (Pdrummode==0)){
- // Legato mode is on and applicable.
if (Ppolymode!=0){
fprintf(stderr, "ZynAddSubFX WARNING: Poly and Legato modes are both On, that should not happen ! ... Disabling Legato mode ! - (Part.C::NoteOn(..))\n");
Plegatomode=0;
} else {
- if (not ismonofirstnote){
- // At least one other key is held or sustained
+ // Legato mode is on and applicable.
+ legatomodevalid=true;
+ if ((not ismonofirstnote)&&(lastlegatomodevalid)){
+ // At least one other key is held or sustained, and the
+ // previous note was played while in valid legato mode.
doinglegato=true; // So we'll do a legato note.
- pos=lastpos; // A legato note uses same pos as previous.
+ pos=lastpos; // A legato note uses same pos as previous..
+ posb=lastposb; // .. same goes for posb.
} else {
+ // Legato mode is valid, but this is only a first note.
for (i=0;i<POLIPHONY;i++)
if ((partnote[i].status==KEY_PLAYING) ||
(partnote[i].status==KEY_RELASED_AND_SUSTAINED))
RelaseNotePos(i);
+
+ // Set posb
+ posb=(pos+1)%POLIPHONY;//We really want it (if the following fails)
+ for (i=0;i<POLIPHONY;i++){
+ if ((partnote[i].status==KEY_OFF) && (pos!=i)){
+ posb=i;
+ break;
+ }
+ }
}
+ lastposb=posb;// Keep a trace of used posb
}
} else { // Legato mode is either off or non-applicable.
if (Ppolymode==0){//if the mode is 'mono' turn off all other notes
@@ -242,16 +259,20 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
RelaseSustainedKeys();
}
}
+ lastlegatomodevalid=legatomodevalid;
if (pos==-1){
//test
fprintf(stderr,"%s","NOTES TOO MANY (> POLIPHONY) - (Part.C::NoteOn(..))\n");
} else {
- /// if (Pnoteon!=0){
//start the note
partnote[pos].status=KEY_PLAYING;
partnote[pos].note=note;
+ if (legatomodevalid){
+ partnote[posb].status=KEY_PLAYING;
+ partnote[posb].note=note;
+ }
//this computes the velocity sensing of the part
REALTYPE vel=VelF(velocity/127.0,Pvelsns);
@@ -297,16 +318,25 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
// Do Legato note
if (Pkitmode==0){ // "normal mode" legato note
if ((kit[0].Padenabled!=0)
- && (partnote[pos].kititem[0].adnote!=NULL))
- partnote[pos].kititem[0].adnote->ADlegatonote(notebasefreq, vel, portamento, note);
+ && (partnote[pos].kititem[0].adnote!=NULL)
+ && (partnote[posb].kititem[0].adnote!=NULL)){
+ partnote[pos].kititem[0].adnote->ADlegatonote(notebasefreq, vel, portamento, note, true);//'true' is to tell it it's being called from here.
+ partnote[posb].kititem[0].adnote->ADlegatonote(notebasefreq, vel, portamento, note, true);
+ }
if ((kit[0].Psubenabled!=0)
- && (partnote[pos].kititem[0].subnote!=NULL))
- partnote[pos].kititem[0].subnote->SUBlegatonote(notebasefreq, vel, portamento, note);
+ && (partnote[pos].kititem[0].subnote!=NULL)
+ && (partnote[posb].kititem[0].subnote!=NULL)){
+ partnote[pos].kititem[0].subnote->SUBlegatonote(notebasefreq, vel, portamento, note, true);
+ partnote[posb].kititem[0].subnote->SUBlegatonote(notebasefreq, vel, portamento, note, true);
+ }
if ((kit[0].Ppadenabled!=0)
- && (partnote[pos].kititem[0].padnote!=NULL))
- partnote[pos].kititem[0].padnote->PADlegatonote(notebasefreq, vel, portamento, note);
+ && (partnote[pos].kititem[0].padnote!=NULL)
+ && (partnote[posb].kititem[0].padnote!=NULL)){
+ partnote[pos].kititem[0].padnote->PADlegatonote(notebasefreq, vel, portamento, note, true);
+ partnote[posb].kititem[0].padnote->PADlegatonote(notebasefreq, vel, portamento, note, true);
+ }
} else { // "kit mode" legato note
int ci=0;
@@ -318,23 +348,28 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
||(lastnotecopy>kit[item].Pmaxkey))
continue; // We will not perform legato across 2 key regions.
- partnote[pos].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ?
- kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed"
+ partnote[pos].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ? kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed"
+ partnote[posb].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ? kit[item].Psendtoparteffect: NUM_PART_EFX);
if ((kit[item].Padenabled!=0) && (kit[item].adpars!=NULL)
- && (partnote[pos].kititem[ci].adnote!=NULL))
- partnote[pos].kititem[ci].adnote->ADlegatonote(notebasefreq,vel,portamento,note);
-
+ && (partnote[pos].kititem[ci].adnote!=NULL)
+ && (partnote[posb].kititem[ci].adnote!=NULL)){
+ partnote[pos].kititem[ci].adnote->ADlegatonote(notebasefreq,vel,portamento,note,true);
+ partnote[posb].kititem[ci].adnote->ADlegatonote(notebasefreq,vel,portamento,note,true);
+ }
if ((kit[item].Psubenabled!=0) && (kit[item].subpars!=NULL)
- && (partnote[pos].kititem[ci].subnote!=NULL))
- partnote[pos].kititem[ci].subnote->SUBlegatonote(notebasefreq,vel,portamento,note);
-
+ && (partnote[pos].kititem[ci].subnote!=NULL)
+ && (partnote[posb].kititem[ci].subnote!=NULL)){
+ partnote[pos].kititem[ci].subnote->SUBlegatonote(notebasefreq,vel,portamento,note,true);
+ partnote[posb].kititem[ci].subnote->SUBlegatonote(notebasefreq,vel,portamento,note,true);
+ }
if ((kit[item].Ppadenabled!=0) && (kit[item].padpars!=NULL)
- && (partnote[pos].kititem[ci].padnote!=NULL))
- partnote[pos].kititem[ci].padnote->PADlegatonote(notebasefreq,vel,portamento,note);
+ && (partnote[pos].kititem[ci].padnote!=NULL)
+ && (partnote[posb].kititem[ci].padnote!=NULL)){
+ partnote[pos].kititem[ci].padnote->PADlegatonote(notebasefreq,vel,portamento,note,true);
+ partnote[posb].kititem[ci].padnote->PADlegatonote(notebasefreq,vel,portamento,note,true);
+ }
- /* In the non-legato equivalent, (kit[item].padpars!=NULL)
- is not checked, is there a reason for that or is it a bug ? */
if ((kit[item].adpars!=NULL)||(kit[item].subpars!=NULL)||(kit[item].padpars!=NULL)) {
ci++;
if ( ((kit[item].Padenabled!=0)||(kit[item].Psubenabled!=0)||(kit[item].Ppadenabled!=0)) && (Pkitmode==2) ) break;
@@ -346,17 +381,28 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
lastnote=lastnotecopy; // Set lastnote back to previous value.
}
}
- return; // Ok, Legato note stuff done, return.
+ return; // Ok, Legato note done, return.
}
partnote[pos].itemsplaying=0;
+ if (legatomodevalid) partnote[posb].itemsplaying=0;
if (Pkitmode==0){//init the notes for the "normal mode"
partnote[pos].kititem[0].sendtoparteffect=0;
- if (kit[0].Padenabled!=0) partnote[pos].kititem[0].adnote=new ADnote(kit[0].adpars,&ctl,notebasefreq,vel,portamento,note);
- if (kit[0].Psubenabled!=0) partnote[pos].kititem[0].subnote=new SUBnote(kit[0].subpars,&ctl,notebasefreq,vel,portamento,note);
- if (kit[0].Ppadenabled!=0) partnote[pos].kititem[0].padnote=new PADnote(kit[0].padpars,&ctl,notebasefreq,vel,portamento,note);
+ if (kit[0].Padenabled!=0) partnote[pos].kititem[0].adnote=new ADnote(kit[0].adpars,&ctl,notebasefreq,vel,portamento,note,false);
+ if (kit[0].Psubenabled!=0) partnote[pos].kititem[0].subnote=new SUBnote(kit[0].subpars,&ctl,notebasefreq,vel,portamento,note,false);
+ if (kit[0].Ppadenabled!=0) partnote[pos].kititem[0].padnote=new PADnote(kit[0].padpars,&ctl,notebasefreq,vel,portamento,note,false);
if ((kit[0].Padenabled!=0)||(kit[0].Psubenabled!=0)||(kit[0].Ppadenabled!=0)) partnote[pos].itemsplaying++;
+
+ // Spawn another note (but silent) if legatomodevalid==true
+ if (legatomodevalid){
+ partnote[posb].kititem[0].sendtoparteffect=0;
+ if (kit[0].Padenabled!=0) partnote[posb].kititem[0].adnote=new ADnote(kit[0].adpars,&ctl,notebasefreq,vel,portamento,note,true);//true for silent.
+ if (kit[0].Psubenabled!=0) partnote[posb].kititem[0].subnote=new SUBnote(kit[0].subpars,&ctl,notebasefreq,vel,portamento,note,true);
+ if (kit[0].Ppadenabled!=0) partnote[posb].kititem[0].padnote=new PADnote(kit[0].padpars,&ctl,notebasefreq,vel,portamento,note,true);
+ if ((kit[0].Padenabled!=0)||(kit[0].Psubenabled!=0)||(kit[0].Ppadenabled!=0)) partnote[posb].itemsplaying++;
+ }
+
} else {//init the notes for the "kit mode"
for (int item=0;item<NUM_KIT_ITEMS;item++){
if (kit[item].Pmuted!=0) continue;
@@ -368,13 +414,28 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed"
if ((kit[item].adpars!=NULL)&&(kit[item].Padenabled)!=0)
- partnote[pos].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note);
+ partnote[pos].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note,false);
if ((kit[item].subpars!=NULL)&&(kit[item].Psubenabled)!=0)
- partnote[pos].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note);
+ partnote[pos].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note,false);
if ((kit[item].padpars!=NULL)&&(kit[item].Ppadenabled)!=0)
- partnote[pos].kititem[ci].padnote=new PADnote(kit[item].padpars,&ctl,notebasefreq,vel,portamento,note);
+ partnote[pos].kititem[ci].padnote=new PADnote(kit[item].padpars,&ctl,notebasefreq,vel,portamento,note,false);
+
+ // Spawn another note (but silent) if legatomodevalid==true
+ if (legatomodevalid){
+ partnote[posb].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ? kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed"
+
+ if ((kit[item].adpars!=NULL)&&(kit[item].Padenabled)!=0)
+ partnote[posb].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note,true);//true for silent.
+ if ((kit[item].subpars!=NULL)&&(kit[item].Psubenabled)!=0)
+ partnote[posb].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note,true);
+ if ((kit[item].padpars!=NULL)&&(kit[item].Ppadenabled)!=0)
+ partnote[posb].kititem[ci].padnote=new PADnote(kit[item].padpars,&ctl,notebasefreq,vel,portamento,note,true);
+
+ if ((kit[item].adpars!=NULL)|| (kit[item].subpars!=NULL))
+ partnote[posb].itemsplaying++;
+ }
if ((kit[item].adpars!=NULL)|| (kit[item].subpars!=NULL)) {
partnote[pos].itemsplaying++;
@@ -383,7 +444,6 @@ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){
};
};
};
- /// };
};
//this only relase the keys if there is maximum number of keys allowed
diff --git a/src/Misc/Part.h b/src/Misc/Part.h
@@ -41,152 +41,154 @@
#include <list> // For the monomemnotes list.
class Part{
- public:
- Part(Microtonal *microtonal_,FFTwrapper *fft_,pthread_mutex_t *mutex_);
- ~Part();
- /* Midi commands implemented */
- void NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift);
- void NoteOff(unsigned char note);
- void AllNotesOff();//panic
- void SetController(unsigned int type,int par);
- void RelaseSustainedKeys();//this is called when the sustain pedal is relased
- void RelaseAllKeys();//this is called on AllNotesOff controller
-
- /* The synthesizer part output */
- void ComputePartSmps();//Part output
-
- //instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank)
-
-
- //saves the instrument settings to a XML file
- //returns 0 for ok or <0 if there is an error
- int saveXML(char *filename);
- int loadXMLinstrument(const char *filename);
-
- void add2XML(XMLwrapper *xml);
- void add2XMLinstrument(XMLwrapper *xml);
-
- void defaults();
- void defaultsinstrument();
-
- void applyparameters();
-
- void getfromXML(XMLwrapper *xml);
- void getfromXMLinstrument(XMLwrapper *xml);
-
- void cleanup();
-
- // ADnoteParameters *ADPartParameters;
- // SUBnoteParameters *SUBPartParameters;
-
- //the part's kit
- struct {
- unsigned char Penabled,Pmuted,Pminkey,Pmaxkey;
- unsigned char *Pname;
- unsigned char Padenabled,Psubenabled,Ppadenabled;
- unsigned char Psendtoparteffect;
- ADnoteParameters *adpars;
- SUBnoteParameters *subpars;
- PADnoteParameters *padpars;
- } kit[NUM_KIT_ITEMS];
-
-
- //Part parameters
- void setkeylimit(unsigned char Pkeylimit);
- void setkititemstatus(int kititem,int Penabled_);
-
- unsigned char Penabled;//if the part is enabled
- unsigned char Pvolume;//part volume
- unsigned char Pminkey;//the minimum key that the part receives noteon messages
- unsigned char Pmaxkey;//the maximum key that the part receives noteon messages
- void setPvolume(char Pvolume);
- unsigned char Pkeyshift;//Part keyshift
- unsigned char Prcvchn;//from what midi channel it receive commnads
- unsigned char Ppanning;//part panning
- void setPpanning(char Ppanning);
- unsigned char Pvelsns;//velocity sensing (amplitude velocity scale)
- unsigned char Pveloffs;//velocity offset
- unsigned char Pnoteon;//if the part receives NoteOn messages
- unsigned char Pkitmode;//if the kitmode is enabled
- unsigned char Pdrummode;//if all keys are mapped and the system is 12tET (used for drums)
-
- unsigned char Ppolymode;//Part mode - 0=monophonic , 1=polyphonic
- unsigned char Plegatomode;// 0=normal, 1=legato
- unsigned char Pkeylimit;//how many keys are alowed to be played same time (0=off), the older will be relased
-
- unsigned char *Pname; //name of the instrument
- struct{//instrument additional information
- unsigned char Ptype;
- unsigned char Pauthor[MAX_INFO_TEXT_SIZE+1];
- unsigned char Pcomments[MAX_INFO_TEXT_SIZE+1];
- } info;
-
-
- REALTYPE *partoutl;//Left channel output of the part
- REALTYPE *partoutr;//Right channel output of the part
-
- REALTYPE *partfxinputl[NUM_PART_EFX+1],*partfxinputr[NUM_PART_EFX+1];//Left and right signal that pass thru part effects; partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer
-
- enum NoteStatus{KEY_OFF,KEY_PLAYING,KEY_RELASED_AND_SUSTAINED,KEY_RELASED};
-
- REALTYPE volume,oldvolumel,oldvolumer;//this is applied by Master
- REALTYPE panning;//this is applied by Master, too
-
- Controller ctl;//Part controllers
-
- EffectMgr *partefx[NUM_PART_EFX];//insertion part effects (they are part of the instrument)
- unsigned char Pefxroute[NUM_PART_EFX];//how the effect's output is routed(to next effect/to out)
- bool Pefxbypass[NUM_PART_EFX];//if the effects are bypassed
-
-
- pthread_mutex_t *mutex;
-
- int lastnote;
-
- private:
- void KillNotePos(int pos);
- void RelaseNotePos(int pos);
- void MonoMemRenote(); // MonoMem stuff.
-
- int killallnotes;//is set to 1 if I want to kill all notes
-
- struct PartNotes{
- NoteStatus status;
- int note;//if there is no note playing, the "note"=-1
- int itemsplaying;
- struct {
- ADnote *adnote;
- SUBnote *subnote;
- PADnote *padnote;
- int sendtoparteffect;
- } kititem[NUM_KIT_ITEMS];
- int time;
- };
-
- int lastpos; // To keep track of previously used pos.
-
- // MonoMem stuff
- std::list<unsigned char> monomemnotes; // A list to remember held notes.
- struct {
- unsigned char velocity;
- int mkeyshift;// I'm not sure masterkeyshift should be remembered.
- } monomem[256]; /* 256 is to cover all possible note values.
- monomem[] is used in conjunction with the list to
- store the velocity and masterkeyshift values of a
- given note (the list only store note values).
- For example 'monomem[note].velocity' would be the
- velocity value of the note 'note'.
- */
-
- PartNotes partnote[POLIPHONY];
-
- REALTYPE *tmpoutl;//used to get the note
- REALTYPE *tmpoutr;
-
- REALTYPE oldfreq;//this is used for portamento
- Microtonal *microtonal;
- FFTwrapper *fft;
+ public:
+ Part(Microtonal *microtonal_,FFTwrapper *fft_,pthread_mutex_t *mutex_);
+ ~Part();
+
+ /* Midi commands implemented */
+ void NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift);
+ void NoteOff(unsigned char note);
+ void AllNotesOff();//panic
+ void SetController(unsigned int type,int par);
+ void RelaseSustainedKeys();//this is called when the sustain pedal is relased
+ void RelaseAllKeys();//this is called on AllNotesOff controller
+
+ /* The synthesizer part output */
+ void ComputePartSmps();//Part output
+
+ //instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank)
+
+
+ //saves the instrument settings to a XML file
+ //returns 0 for ok or <0 if there is an error
+ int saveXML(char *filename);
+ int loadXMLinstrument(const char *filename);
+
+ void add2XML(XMLwrapper *xml);
+ void add2XMLinstrument(XMLwrapper *xml);
+
+ void defaults();
+ void defaultsinstrument();
+
+ void applyparameters();
+
+ void getfromXML(XMLwrapper *xml);
+ void getfromXMLinstrument(XMLwrapper *xml);
+
+ void cleanup();
+
+// ADnoteParameters *ADPartParameters;
+// SUBnoteParameters *SUBPartParameters;
+
+ //the part's kit
+ struct {
+ unsigned char Penabled,Pmuted,Pminkey,Pmaxkey;
+ unsigned char *Pname;
+ unsigned char Padenabled,Psubenabled,Ppadenabled;
+ unsigned char Psendtoparteffect;
+ ADnoteParameters *adpars;
+ SUBnoteParameters *subpars;
+ PADnoteParameters *padpars;
+ } kit[NUM_KIT_ITEMS];
+
+
+ //Part parameters
+ void setkeylimit(unsigned char Pkeylimit);
+ void setkititemstatus(int kititem,int Penabled_);
+
+ unsigned char Penabled;//if the part is enabled
+ unsigned char Pvolume;//part volume
+ unsigned char Pminkey;//the minimum key that the part receives noteon messages
+ unsigned char Pmaxkey;//the maximum key that the part receives noteon messages
+ void setPvolume(char Pvolume);
+ unsigned char Pkeyshift;//Part keyshift
+ unsigned char Prcvchn;//from what midi channel it receive commnads
+ unsigned char Ppanning;//part panning
+ void setPpanning(char Ppanning);
+ unsigned char Pvelsns;//velocity sensing (amplitude velocity scale)
+ unsigned char Pveloffs;//velocity offset
+ unsigned char Pnoteon;//if the part receives NoteOn messages
+ unsigned char Pkitmode;//if the kitmode is enabled
+ unsigned char Pdrummode;//if all keys are mapped and the system is 12tET (used for drums)
+
+ unsigned char Ppolymode;//Part mode - 0=monophonic , 1=polyphonic
+ unsigned char Plegatomode;// 0=normal, 1=legato
+ unsigned char Pkeylimit;//how many keys are alowed to be played same time (0=off), the older will be relased
+
+ unsigned char *Pname; //name of the instrument
+ struct{//instrument additional information
+ unsigned char Ptype;
+ unsigned char Pauthor[MAX_INFO_TEXT_SIZE+1];
+ unsigned char Pcomments[MAX_INFO_TEXT_SIZE+1];
+ } info;
+
+
+ REALTYPE *partoutl;//Left channel output of the part
+ REALTYPE *partoutr;//Right channel output of the part
+
+ REALTYPE *partfxinputl[NUM_PART_EFX+1],*partfxinputr[NUM_PART_EFX+1];//Left and right signal that pass thru part effects; partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer
+
+ enum NoteStatus{KEY_OFF,KEY_PLAYING,KEY_RELASED_AND_SUSTAINED,KEY_RELASED};
+
+ REALTYPE volume,oldvolumel,oldvolumer;//this is applied by Master
+ REALTYPE panning;//this is applied by Master, too
+
+ Controller ctl;//Part controllers
+
+ EffectMgr *partefx[NUM_PART_EFX];//insertion part effects (they are part of the instrument)
+ unsigned char Pefxroute[NUM_PART_EFX];//how the effect's output is routed(to next effect/to out)
+ bool Pefxbypass[NUM_PART_EFX];//if the effects are bypassed
+
+
+ pthread_mutex_t *mutex;
+
+ int lastnote;
+
+ private:
+ void KillNotePos(int pos);
+ void RelaseNotePos(int pos);
+ void MonoMemRenote(); // MonoMem stuff.
+
+ int killallnotes;//is set to 1 if I want to kill all notes
+
+ struct PartNotes{
+ NoteStatus status;
+ int note;//if there is no note playing, the "note"=-1
+ int itemsplaying;
+ struct {
+ ADnote *adnote;
+ SUBnote *subnote;
+ PADnote *padnote;
+ int sendtoparteffect;
+ } kititem[NUM_KIT_ITEMS];
+ int time;
+ };
+
+ int lastpos, lastposb; // To keep track of previously used pos and posb.
+ bool lastlegatomodevalid; // To keep track of previous legatomodevalid.
+
+ // MonoMem stuff
+ std::list<unsigned char> monomemnotes; // A list to remember held notes.
+ struct {
+ unsigned char velocity;
+ int mkeyshift;// I'm not sure masterkeyshift should be remembered.
+ } monomem[256]; /* 256 is to cover all possible note values.
+ monomem[] is used in conjunction with the list to
+ store the velocity and masterkeyshift values of a
+ given note (the list only store note values).
+ For example 'monomem[note].velocity' would be the
+ velocity value of the note 'note'.
+ */
+
+ PartNotes partnote[POLIPHONY];
+
+ REALTYPE *tmpoutl;//used to get the note
+ REALTYPE *tmpoutr;
+
+ REALTYPE oldfreq;//this is used for portamento
+ Microtonal *microtonal;
+ FFTwrapper *fft;
};
#endif
diff --git a/src/Synth/ADnote.C b/src/Synth/ADnote.C
@@ -29,13 +29,25 @@
#include "ADnote.h"
-ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_){
+ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_,bool besilent){
ready=0;
-
+
tmpwave=new REALTYPE [SOUND_BUFFER_SIZE];
bypassl=new REALTYPE [SOUND_BUFFER_SIZE];
bypassr=new REALTYPE [SOUND_BUFFER_SIZE];
+ // Initialise some legato-specific vars
+ Legato.msg=LM_Norm;
+ Legato.fade.length=(int)(SAMPLE_RATE*0.005);// 0.005 seems ok.
+ if (Legato.fade.length<1) Legato.fade.length=1;// (if something's fishy)
+ Legato.fade.step=(1.0/Legato.fade.length);
+ Legato.decounter=-10;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote_;
+ Legato.silent=besilent;
+
partparams=pars;
ctl=ctl_;
portamento=portamento_;
@@ -183,10 +195,31 @@ ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE ve
// initparameters() stuck together with some lines removed so that it
// only alter the already playing note (to perform legato). It is
// possible I left stuff that is not required for this.
-void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote_){
+void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote_, bool externcall){
ADnoteParameters *pars=partparams;
//Controller *ctl_=ctl;
+ // Manage legato stuff
+ if (externcall) Legato.msg=LM_Norm;
+ if (Legato.msg!=LM_CatchUp){
+ Legato.lastfreq=Legato.param.freq;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote_;
+ if (Legato.msg==LM_Norm){
+ if (Legato.silent){
+ Legato.fade.m=0.0;
+ Legato.msg=LM_FadeIn;
+ } else {
+ Legato.fade.m=1.0;
+ Legato.msg=LM_FadeOut;
+ return;
+ }
+ }
+ if (Legato.msg==LM_ToNorm) Legato.msg=LM_Norm;
+ }
+
portamento=portamento_;
midinote=midinote_;
basefreq=freq;
@@ -194,7 +227,6 @@ void ADnote::ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int
if (velocity>1.0) velocity=1.0;
this->velocity=velocity;
-
NoteGlobalPar.Detune=getdetune(pars->GlobalPar.PDetuneType
,pars->GlobalPar.PCoarseDetune,pars->GlobalPar.PDetune);
bandwidthDetuneMultiplier=pars->getBandwidthDetuneMultiplier();
@@ -1126,7 +1158,74 @@ int ADnote::noteout(REALTYPE *outl,REALTYPE *outr){
};
};
};
-
+
+
+ // Apply legato-specific sound signal modifications
+ if (Legato.silent){ // Silencer
+ if (Legato.msg!=LM_FadeIn){
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ outl[i]=0.0;
+ outr[i]=0.0;
+ }
+ }
+ }
+ switch (Legato.msg){
+ case LM_CatchUp : // Continue the catch-up...
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){//Yea, could be done without the loop...
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ // Catching-up done, we can finally set
+ // the note to the actual parameters.
+ Legato.decounter=-10;
+ Legato.msg=LM_ToNorm;
+ ADlegatonote(Legato.param.freq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ }
+ break;
+ case LM_FadeIn : // Fade-in
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ Legato.silent=false;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ Legato.decounter=-10;
+ Legato.msg=LM_Norm;
+ break;
+ }
+ Legato.fade.m+=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ case LM_FadeOut : // Fade-out, then set the catch-up
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ for (int j=i;j<SOUND_BUFFER_SIZE;j++){
+ outl[j]=0.0;
+ outr[j]=0.0;
+ }
+ Legato.decounter=-10;
+ Legato.silent=true;
+ // Fading-out done, now set the catch-up :
+ Legato.decounter=Legato.fade.length;
+ Legato.msg=LM_CatchUp;
+ REALTYPE catchupfreq=Legato.param.freq*(Legato.param.freq/Legato.lastfreq);//This freq should make this now silent note to catch-up (or should I say resync ?) with the heard note for the same length it stayed at the previous freq during the fadeout.
+ ADlegatonote(catchupfreq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ Legato.fade.m-=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ default : break;
+ }
+
+
// Check if the global amplitude is finished.
// If it does, disable the note
if (NoteGlobalPar.AmpEnvelope->finished()!=0) {
diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h
@@ -39,10 +39,10 @@
class ADnote{ //ADDitive note
public:
- ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_);
+ ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_,bool besilent);//(gf)Added the besilent parameter to tell it to start silent (if true).
~ADnote();
- void ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote_);
+ void ADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote_, bool externcall);
int noteout(REALTYPE *outl,REALTYPE *outr);
void relasekey();
@@ -252,6 +252,22 @@ class ADnote{ //ADDitive note
//how the fine detunes are made bigger or smaller
REALTYPE bandwidthDetuneMultiplier;
+
+ // Legato vars
+ struct {
+ bool silent;
+ REALTYPE lastfreq;
+ LegatoMsg msg;
+ int decounter;
+ struct { // Fade In/Out vars
+ int length;
+ REALTYPE m, step;
+ } fade;
+ struct { // Note parameters
+ REALTYPE freq, vel;
+ int portamento, midinote;
+ } param;
+ } Legato;
};
#endif
diff --git a/src/Synth/PADnote.C b/src/Synth/PADnote.C
@@ -22,8 +22,21 @@
#include "PADnote.h"
#include "../Misc/Config.h"
-PADnote::PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote){
+PADnote::PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool besilent){
ready=0;
+
+ // Initialise some legato-specific vars
+ Legato.msg=LM_Norm;
+ Legato.fade.length=(int)(SAMPLE_RATE*0.005);// 0.005 seems ok.
+ if (Legato.fade.length<1) Legato.fade.length=1;// (if something's fishy)
+ Legato.fade.step=(1.0/Legato.fade.length);
+ Legato.decounter=-10;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote;
+ Legato.silent=besilent;
+
pars=parameters;
portamento=portamento_;
ctl=ctl_;
@@ -130,10 +143,31 @@ PADnote::PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq,
// with some lines removed so that it only alter the already playing
// note (to perform legato). It is possible I left stuff that is not
// required for this.
-void PADnote::PADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote){
+void PADnote::PADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall){
PADnoteParameters *parameters=pars;
//Controller *ctl_=ctl;
+ // Manage legato stuff
+ if (externcall) Legato.msg=LM_Norm;
+ if (Legato.msg!=LM_CatchUp){
+ Legato.lastfreq=Legato.param.freq;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote;
+ if (Legato.msg==LM_Norm){
+ if (Legato.silent){
+ Legato.fade.m=0.0;
+ Legato.msg=LM_FadeIn;
+ } else {
+ Legato.fade.m=1.0;
+ Legato.msg=LM_FadeOut;
+ return;
+ }
+ }
+ if (Legato.msg==LM_ToNorm) Legato.msg=LM_Norm;
+ }
+
portamento=portamento_;
this->velocity=velocity;
finished_=false;
@@ -389,7 +423,73 @@ int PADnote::noteout(REALTYPE *outl,REALTYPE *outr){
};
};
-
+
+ // Apply legato-specific sound signal modifications
+ if (Legato.silent){ // Silencer
+ if (Legato.msg!=LM_FadeIn){
+ for (int i=0;i<SOUND_BUFFER_SIZE;i++){
+ outl[i]=0.0;
+ outr[i]=0.0;
+ }
+ }
+ }
+ switch (Legato.msg){
+ case LM_CatchUp : // Continue the catch-up...
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (int i=0;i<SOUND_BUFFER_SIZE;i++){//Yea, could be done without the loop...
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ // Catching-up done, we can finally set
+ // the note to the actual parameters.
+ Legato.decounter=-10;
+ Legato.msg=LM_ToNorm;
+ PADlegatonote(Legato.param.freq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ }
+ break;
+ case LM_FadeIn : // Fade-in
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ Legato.silent=false;
+ for (int i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ Legato.decounter=-10;
+ Legato.msg=LM_Norm;
+ break;
+ }
+ Legato.fade.m+=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ case LM_FadeOut : // Fade-out, then set the catch-up
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (int i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ for (int j=i;j<SOUND_BUFFER_SIZE;j++){
+ outl[j]=0.0;
+ outr[j]=0.0;
+ }
+ Legato.decounter=-10;
+ Legato.silent=true;
+ // Fading-out done, now set the catch-up :
+ Legato.decounter=Legato.fade.length;
+ Legato.msg=LM_CatchUp;
+ REALTYPE catchupfreq=Legato.param.freq*(Legato.param.freq/Legato.lastfreq);//This freq should make this now silent note to catch-up (or should I say resync ?) with the heard note for the same length it stayed at the previous freq during the fadeout.
+ PADlegatonote(catchupfreq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ Legato.fade.m-=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ default : break;
+ }
+
+
// Check if the global amplitude is finished.
// If it does, disable the note
if (NoteGlobalPar.AmpEnvelope->finished()!=0) {
diff --git a/src/Synth/PADnote.h b/src/Synth/PADnote.h
@@ -31,10 +31,10 @@
class PADnote{
public:
- PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote);
+ PADnote(PADnoteParameters *parameters, Controller *ctl_,REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool besilent);
~PADnote();
- void PADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote);
+ void PADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall);
int noteout(REALTYPE *outl,REALTYPE *outr);
int finished();
@@ -102,6 +102,22 @@ class PADnote{
REALTYPE globaloldamplitude,globalnewamplitude,velocity,realfreq;
REALTYPE *tmpwave;
Controller *ctl;
+
+ // Legato vars
+ struct {
+ bool silent;
+ REALTYPE lastfreq;
+ LegatoMsg msg;
+ int decounter;
+ struct { // Fade In/Out vars
+ int length;
+ REALTYPE m, step;
+ } fade;
+ struct { // Note parameters
+ REALTYPE freq, vel;
+ int portamento, midinote;
+ } param;
+ } Legato;
};
diff --git a/src/Synth/SUBnote.C b/src/Synth/SUBnote.C
@@ -27,11 +27,23 @@
#include "SUBnote.h"
#include "../Misc/Util.h"
-SUBnote::SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote){
+SUBnote::SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote,bool besilent){
ready=0;
tmpsmp=new REALTYPE[SOUND_BUFFER_SIZE];
tmprnd=new REALTYPE[SOUND_BUFFER_SIZE];
+
+ // Initialise some legato-specific vars
+ Legato.msg=LM_Norm;
+ Legato.fade.length=(int)(SAMPLE_RATE*0.005);// 0.005 seems ok.
+ if (Legato.fade.length<1) Legato.fade.length=1;// (if something's fishy)
+ Legato.fade.step=(1.0/Legato.fade.length);
+ Legato.decounter=-10;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote;
+ Legato.silent=besilent;
pars=parameters;
ctl=ctl_;
@@ -147,10 +159,31 @@ SUBnote::SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,RE
// initparameters(...) stuck together with some lines removed so that
// it only alter the already playing note (to perform legato). It is
// possible I left stuff that is not required for this.
-void SUBnote::SUBlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote){
+void SUBnote::SUBlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall){
//SUBnoteParameters *parameters=pars;
//Controller *ctl_=ctl;
+ // Manage legato stuff
+ if (externcall) Legato.msg=LM_Norm;
+ if (Legato.msg!=LM_CatchUp){
+ Legato.lastfreq=Legato.param.freq;
+ Legato.param.freq=freq;
+ Legato.param.vel=velocity;
+ Legato.param.portamento=portamento_;
+ Legato.param.midinote=midinote;
+ if (Legato.msg==LM_Norm){
+ if (Legato.silent){
+ Legato.fade.m=0.0;
+ Legato.msg=LM_FadeIn;
+ } else {
+ Legato.fade.m=1.0;
+ Legato.msg=LM_FadeOut;
+ return;
+ }
+ }
+ if (Legato.msg==LM_ToNorm) Legato.msg=LM_Norm;
+ }
+
portamento=portamento_;
volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB
@@ -510,7 +543,72 @@ int SUBnote::noteout(REALTYPE *outl,REALTYPE *outr){
oldamplitude=newamplitude;
computecurrentparameters();
-
+
+ // Apply legato-specific sound signal modifications
+ if (Legato.silent){ // Silencer
+ if (Legato.msg!=LM_FadeIn){
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ outl[i]=0.0;
+ outr[i]=0.0;
+ }
+ }
+ }
+ switch (Legato.msg){
+ case LM_CatchUp : // Continue the catch-up...
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){//Yea, could be done without the loop...
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ // Catching-up done, we can finally set
+ // the note to the actual parameters.
+ Legato.decounter=-10;
+ Legato.msg=LM_ToNorm;
+ SUBlegatonote(Legato.param.freq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ }
+ break;
+ case LM_FadeIn : // Fade-in
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ Legato.silent=false;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ Legato.decounter=-10;
+ Legato.msg=LM_Norm;
+ break;
+ }
+ Legato.fade.m+=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ case LM_FadeOut : // Fade-out, then set the catch-up
+ if (Legato.decounter==-10) Legato.decounter=Legato.fade.length;
+ for (i=0;i<SOUND_BUFFER_SIZE;i++){
+ Legato.decounter--;
+ if (Legato.decounter<1){
+ for (int j=i;j<SOUND_BUFFER_SIZE;j++){
+ outl[j]=0.0;
+ outr[j]=0.0;
+ }
+ Legato.decounter=-10;
+ Legato.silent=true;
+ // Fading-out done, now set the catch-up :
+ Legato.decounter=Legato.fade.length;
+ Legato.msg=LM_CatchUp;
+ REALTYPE catchupfreq=Legato.param.freq*(Legato.param.freq/Legato.lastfreq);//This freq should make this now silent note to catch-up (or should I say resync ?) with the heard note for the same length it stayed at the previous freq during the fadeout.
+ SUBlegatonote(catchupfreq, Legato.param.vel, Legato.param.portamento, Legato.param.midinote, false);
+ break;
+ }
+ Legato.fade.m-=Legato.fade.step;
+ outl[i]*=Legato.fade.m;
+ outr[i]*=Legato.fade.m;
+ }
+ break;
+ default : break;
+ }
+
// Check if the note needs to be computed more
if (AmpEnvelope->finished()!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//fade-out
diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h
@@ -31,10 +31,10 @@
class SUBnote{
public:
- SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote);
+ SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote,bool besilent);
~SUBnote();
- void SUBlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote);
+ void SUBlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall);
int noteout(REALTYPE *outl,REALTYPE *outr);//note output,return 0 if the note is finished
void relasekey();
@@ -93,6 +93,21 @@ class SUBnote{
int oldpitchwheel,oldbandwidth;
REALTYPE globalfiltercenterq;
+ // Legato vars
+ struct {
+ bool silent;
+ REALTYPE lastfreq;
+ LegatoMsg msg;
+ int decounter;
+ struct { // Fade In/Out vars
+ int length;
+ REALTYPE m, step;
+ } fade;
+ struct { // Note parameters
+ REALTYPE freq, vel;
+ int portamento, midinote;
+ } param;
+ } Legato;
};
diff --git a/src/globals.h b/src/globals.h
@@ -194,6 +194,7 @@ enum MidiControllers{C_NULL=0,C_pitchwheel=1000,C_expression=11,C_panning=10,
C_dataentryhi=0x06,C_dataentrylo=0x26,C_nrpnhi=99,C_nrpnlo=98};
+enum LegatoMsg{LM_Norm, LM_FadeIn, LM_FadeOut, LM_CatchUp, LM_ToNorm};
//is like i=(int)(floor(f))
#ifdef ASM_F2I_YES