diff options
Diffstat (limited to 'muse_qt4_evolution/synti/zynaddsubfx/Misc')
16 files changed, 4571 insertions, 0 deletions
diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.C new file mode 100644 index 00000000..9b2e8f75 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.C @@ -0,0 +1,565 @@ +/* + ZynAddSubFX - a software synthesizer + + Bank.h - Instrument Bank + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 "Bank.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <sys/stat.h> + +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "Config.h" + +#define INSTRUMENT_EXTENSION ".xiz" + +//if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file +#define FORCE_BANK_DIR_FILE ".bankdir" + +Bank::Bank(){ + + + ZERO(defaultinsname,PART_MAX_NAME_LEN); + snprintf(defaultinsname,PART_MAX_NAME_LEN,"%s"," "); + + for (int i=0;i<BANK_SIZE;i++){ + ins[i].used=false; + ins[i].filename=NULL; + ins[i].info.PADsynth_used=false; + }; + dirname=NULL; + clearbank(); + + + + for (int i=0;i<MAX_NUM_BANKS;i++){ + banks[i].dir=NULL; + banks[i].name=NULL; + }; + + bankfiletitle=dirname; + + loadbank(config.cfg.currentBankDir); + +}; + +Bank::~Bank(){ + for (int i=0;i<MAX_NUM_BANKS;i++){ + if (banks[i].dir!=NULL) delete (banks[i].dir); + if (banks[i].name!=NULL) delete (banks[i].name); + }; + + clearbank(); +}; + +/* + * Get the name of an instrument from the bank + */ +char *Bank::getname (unsigned int ninstrument){ + if (emptyslot(ninstrument)) return (defaultinsname); + return (ins[ninstrument].name); +}; + +/* + * Get the numbered name of an instrument from the bank + */ +char *Bank::getnamenumbered (unsigned int ninstrument){ + if (emptyslot(ninstrument)) return (defaultinsname); + snprintf(tmpinsname[ninstrument],PART_MAX_NAME_LEN+15,"%d. %s",ninstrument+1,getname(ninstrument)); + return(tmpinsname[ninstrument]); +}; + +/* + * Changes the name of an instrument (and the filename) + */ +void Bank::setname(unsigned int ninstrument,const char *newname,int newslot){ + if (emptyslot(ninstrument)) return; + + char newfilename[1000+1],tmpfilename[100+1]; + + ZERO(newfilename,1001); + ZERO(tmpfilename,101); + if (newslot>=0) snprintf(tmpfilename,100,"%4d-%s",newslot+1,newname); + else snprintf(tmpfilename,100,"%4d-%s",ninstrument+1,newname); + + //add the zeroes at the start of filename + for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0'; + + //make the filenames legal + for (int i=0;i<(int) strlen(tmpfilename);i++) { + char c=tmpfilename[i]; + if ((c>='0')&&(c<='9')) continue; + if ((c>='A')&&(c<='Z')) continue; + if ((c>='a')&&(c<='z')) continue; + if ((c=='-')||(c==' ')) continue; + + tmpfilename[i]='_'; + }; + + snprintf(newfilename,1000,"%s/%s.xiz",dirname,tmpfilename); + +// printf("rename %s -> %s\n",ins[ninstrument].filename,newfilename);////////////// + + rename(ins[ninstrument].filename,newfilename); + if (ins[ninstrument].filename) delete(ins[ninstrument].filename); + ins[ninstrument].filename=new char[strlen(newfilename)+5]; + snprintf(ins[ninstrument].filename,strlen(newfilename)+1,"%s",newfilename); + snprintf(ins[ninstrument].name,PART_MAX_NAME_LEN,"%s",&tmpfilename[5]); + +}; + +/* + * Check if there is no instrument on a slot from the bank + */ +int Bank::emptyslot(unsigned int ninstrument){ + if (ninstrument>=BANK_SIZE) return (1); + if (ins[ninstrument].filename==NULL) return(1); + + if (ins[ninstrument].used) return (0); + else return(1); +}; + +/* + * Removes the instrument from the bank + */ +void Bank::clearslot(unsigned int ninstrument){ + if (emptyslot(ninstrument)) return; + +// printf("remove %s \n",ins[ninstrument].filename);//////////////////////// + + + remove(ins[ninstrument].filename); + deletefrombank(ninstrument); +}; + +/* + * Save the instrument to a slot + */ +void Bank::savetoslot(unsigned int ninstrument,Part *part){ + clearslot(ninstrument); + + const int maxfilename=200; + char tmpfilename[maxfilename+20]; + ZERO(tmpfilename,maxfilename+20); + + snprintf(tmpfilename,maxfilename,"%4d-%s",ninstrument+1,(char *)part->Pname); + + //add the zeroes at the start of filename + for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0'; + + //make the filenames legal + for (int i=0;i<(int)strlen(tmpfilename);i++) { + char c=tmpfilename[i]; + if ((c>='0')&&(c<='9')) continue; + if ((c>='A')&&(c<='Z')) continue; + if ((c>='a')&&(c<='z')) continue; + if ((c=='-')||(c==' ')) continue; + + tmpfilename[i]='_'; + }; + + strncat(tmpfilename,".xiz",maxfilename+10); + + int fnsize=strlen(dirname)+strlen(tmpfilename)+10; + char *filename=new char[fnsize+4]; + ZERO(filename,fnsize+2); + + snprintf(filename,fnsize,"%s/%s",dirname,tmpfilename); + + remove(filename); + part->saveXML(filename); + addtobank(ninstrument,tmpfilename,(char *) part->Pname); + + delete(filename); +}; + +/* + * Loads the instrument from the bank + */ +void Bank::loadfromslot(unsigned int ninstrument,Part *part){ + if (emptyslot(ninstrument)) return; + + part->defaultsinstrument(); + +// printf("load: %s\n",ins[ninstrument].filename); + + part->loadXMLinstrument(ins[ninstrument].filename); + +}; + + +/* + * Makes current a bank directory + */ +int Bank::loadbank(const char *bankdirname) + { + DIR *dir = opendir(bankdirname); + clearbank(); + + if (dir==NULL) + return -1; + + if (dirname!=NULL) + delete(dirname); + dirname = new char[strlen(bankdirname)+1]; + snprintf(dirname, strlen(bankdirname)+1, "%s",bankdirname); + + bankfiletitle=dirname; + + // printf("loadbank %s/\n",bankdirname); + struct dirent *fn; + + while ((fn=readdir(dir))){ + const char *filename= fn->d_name; + + //sa verific daca e si extensia dorita + if (strstr(filename,INSTRUMENT_EXTENSION)==NULL) continue; + + //verify if the name is like this NNNN-name (where N is a digit) + int no=0; + unsigned int startname=0; + + for (unsigned int i=0;i<4;i++) { + if (strlen(filename)<=i) break; + + if ((filename[i]>='0')&&(filename[i]<='9')) { + no=no*10+(filename[i]-'0'); + startname++; + }; + }; + + + if ((startname+1)<strlen(filename)) startname++;//to take out the "-" + + char name[PART_MAX_NAME_LEN+1]; + ZERO(name,PART_MAX_NAME_LEN+1); + snprintf(name,PART_MAX_NAME_LEN,"%s",filename); + + //remove the file extension + for (int i=strlen(name)-1;i>=2;i--){ + if (name[i]=='.') { + name[i]='\0'; + break; + }; + }; + + if (no!=0){//the instrument position in the bank is found + addtobank(no-1,filename,&name[startname]); + } else { + addtobank(-1,filename,name); + }; + + }; + + + closedir(dir); + + if (dirname!=NULL) { + sprintf(config.cfg.currentBankDir,"%s",dirname); + }; + + return(0); +}; + +/* + * Makes a new bank, put it on a file and makes it current bank + */ +int Bank::newbank(const char *newbankdirname){ + int result; + char tmpfilename[MAX_STRING_SIZE]; + char bankdir[MAX_STRING_SIZE]; + snprintf(bankdir,MAX_STRING_SIZE,"%s",config.cfg.bankRootDirList[0]); + + if (((bankdir[strlen(bankdir)-1])!='/')&&((bankdir[strlen(bankdir)-1])!='\\')){ + strncat(bankdir,"/",MAX_STRING_SIZE); + }; + strncat(bankdir,newbankdirname,MAX_STRING_SIZE); +#ifdef OS_WINDOWS + result=mkdir(bankdir); +#else + result=mkdir(bankdir,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + if (result<0) return(-1); + + snprintf(tmpfilename,MAX_STRING_SIZE,"%s/%s",bankdir,FORCE_BANK_DIR_FILE); +// printf("%s\n",tmpfilename); + FILE *tmpfile=fopen(tmpfilename,"w+"); + fclose(tmpfile); + + return(loadbank(bankdir)); +}; + +/* + * Check if the bank is locked (i.e. the file opened was readonly) + */ +int Bank::locked(){ + return(dirname==NULL); +}; + +/* + * Swaps a slot with another + */ +void Bank::swapslot(unsigned int n1, unsigned int n2){ + if ((n1==n2)||(locked())) return; + if (emptyslot(n1)&&(emptyslot(n2))) return; + if (emptyslot(n1)){//change n1 to n2 in order to make + int tmp=n2;n2=n1;n1=tmp; + }; + + if (emptyslot(n2)){//this is just a movement from slot1 to slot2 + setname(n1,getname(n1),n2); + ins[n2]=ins[n1]; + ins[n1].used=false; + ins[n1].name[0]='\0'; + ins[n1].filename=NULL; + ins[n1].info.PADsynth_used=0; + } else {//if both slots are used + if (strcmp(ins[n1].name,ins[n2].name)==0){//change the name of the second instrument if the name are equal + strncat(ins[n2].name,"2",PART_MAX_NAME_LEN); + }; + setname(n1,getname(n1),n2); + setname(n2,getname(n2),n1); + ins_t tmp; + tmp.used=true; + strcpy(tmp.name,ins[n2].name); + char *tmpfilename=ins[n2].filename; + bool padsynth_used=ins[n2].info.PADsynth_used; + + ins[n2]=ins[n1]; + strcpy(ins[n1].name,tmp.name); + ins[n1].filename=tmpfilename; + ins[n1].info.PADsynth_used=padsynth_used; + }; + +}; + + +//a helper function that compares 2 banks[] arrays +int Bank_compar(const void *a,const void *b){ + struct Bank::bankstruct *bank1= (Bank::bankstruct *)a; + struct Bank::bankstruct *bank2= (Bank::bankstruct *)b; + if (((bank1->name)==NULL)||((bank2->name)==NULL)) return(0); + + int result=strcasecmp(bank1->name,bank2->name); + return(result<0); +}; + + +/* + * Re-scan for directories containing instrument banks + */ + +void Bank::rescanforbanks(){ + for (int i=0;i<MAX_NUM_BANKS;i++){ + if (banks[i].dir!=NULL) delete (banks[i].dir); + if (banks[i].name!=NULL) delete (banks[i].name); + banks[i].dir=NULL; + banks[i].name=NULL; + }; + + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (config.cfg.bankRootDirList[i]!=NULL) scanrootdir(config.cfg.bankRootDirList[i]); + + //sort the banks + for (int j=0;j<MAX_NUM_BANKS-1;j++){ + for (int i=j+1;i<MAX_NUM_BANKS;i++){ + if (Bank_compar(&banks[i],&banks[j])) { + char *tmpname=banks[i].name; + char *tmpdir=banks[i].dir; + + banks[i].name=banks[j].name; + banks[i].dir=banks[j].dir; + + banks[j].name=tmpname; + banks[j].dir=tmpdir; + + }; + }; + }; + + //remove duplicate bank names + int dupl=0; + for (int j=0;j<MAX_NUM_BANKS-1;j++){ + for (int i=j+1;i<MAX_NUM_BANKS;i++){ + if ((banks[i].name==NULL)||(banks[j].name==NULL)) continue; + if (strcmp(banks[i].name,banks[j].name)==0) {//add a [1] to the first bankname and [n] to others + char *tmpname=banks[i].name; + banks[i].name=new char[strlen(tmpname)+100]; + sprintf(banks[i].name,"%s[%d]",tmpname,dupl+2); + delete(tmpname); + + if (dupl==0){ + char *tmpname=banks[j].name; + banks[j].name=new char[strlen(tmpname)+100]; + sprintf(banks[j].name,"%s[1]",tmpname); + delete(tmpname); + }; + + dupl++; + } else dupl=0; + }; + }; + +}; + + + +// private stuff + +void Bank::scanrootdir(char *rootdir){ +// printf("Scanning root dir:%s\n",rootdir); + DIR *dir=opendir(rootdir); + if (dir==NULL) return; + + const int maxdirsize=1000; + struct { + char dir[maxdirsize]; + char name[maxdirsize]; + }bank; + + char *separator="/"; + if (strlen(rootdir)) { + char tmp=rootdir[strlen(rootdir)-1]; + if ((tmp=='/') || (tmp=='\\')) separator=""; + }; + + struct dirent *fn; + while ((fn=readdir(dir))){ + const char *dirname=fn->d_name; + if (dirname[0]=='.') continue; + + snprintf(bank.dir,maxdirsize,"%s%s%s/",rootdir,separator,dirname); + snprintf(bank.name,maxdirsize,"%s",dirname); + //find out if the directory contains at least 1 instrument + bool isbank=false; + + DIR *d=opendir(bank.dir); + if (d==NULL) continue; + + struct dirent *fname; + + while((fname=readdir(d))){ + if ((strstr(fname->d_name,INSTRUMENT_EXTENSION)!=NULL)|| + (strstr(fname->d_name,FORCE_BANK_DIR_FILE)!=NULL)){ + isbank=true; + break;//aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank + }; + }; + + closedir(d); + + if (isbank) { + int pos=-1; + for (int i=1;i<MAX_NUM_BANKS;i++){ //banks[0] e liber intotdeauna + if (banks[i].name==NULL) { + pos=i; + break; + }; + }; + + if (pos>=0) { + banks[pos].name=new char[maxdirsize]; + banks[pos].dir=new char[maxdirsize]; + snprintf(banks[pos].name,maxdirsize,"%s",bank.name); + snprintf(banks[pos].dir,maxdirsize,"%s",bank.dir); + }; + + }; + + }; + + closedir(dir); + +}; + +void Bank::clearbank(){ + for (int i=0;i<BANK_SIZE;i++) deletefrombank(i); + if (dirname!=NULL) delete(dirname); + bankfiletitle=NULL; + dirname=NULL; +}; + +int Bank::addtobank(int pos, const char *filename, const char* name){ + if ((pos>=0)&&(pos<BANK_SIZE)){ + if (ins[pos].used) pos=-1;//force it to find a new free position + } else if (pos>=BANK_SIZE) pos=-1; + + + if (pos<0) {//find a free position + for (int i=BANK_SIZE-1;i>=0;i--) + if (!ins[i].used) { + pos=i; + break; + }; + + }; + + if (pos<0) return (-1);//the bank is full + + // printf("%s %d\n",filename,pos); + + deletefrombank(pos); + + ins[pos].used=true; + snprintf(ins[pos].name,PART_MAX_NAME_LEN,"%s",name); + + snprintf(tmpinsname[pos],PART_MAX_NAME_LEN+10," "); + + int len=strlen(filename)+1+strlen(dirname); + ins[pos].filename=new char[len+2]; + ins[pos].filename[len+1]=0; + snprintf(ins[pos].filename,len+1,"%s/%s",dirname,filename); + + //see if PADsynth is used + if (config.cfg.CheckPADsynth){ + XMLwrapper *xml=new XMLwrapper(); + xml->checkfileinformation(ins[pos].filename); + + ins[pos].info.PADsynth_used=xml->information.PADsynth_used; + delete(xml); + } else ins[pos].info.PADsynth_used=false; + + return(0); +}; + +bool Bank::isPADsynth_used(unsigned int ninstrument){ + if (config.cfg.CheckPADsynth==0) return(0); + else return(ins[ninstrument].info.PADsynth_used); +}; + + +void Bank::deletefrombank(int pos){ + if ((pos<0)||(pos>=BANK_SIZE)) return; + ins[pos].used=false; + ZERO(ins[pos].name,PART_MAX_NAME_LEN+1); + if (ins[pos].filename!=NULL) { + delete (ins[pos].filename); + ins[pos].filename=NULL; + }; + + ZERO(tmpinsname[pos],PART_MAX_NAME_LEN+20); + +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.h new file mode 100644 index 00000000..1a2f4382 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Bank.h @@ -0,0 +1,100 @@ +/* + ZynAddSubFX - a software synthesizer + + Bank.C - Instrument Bank + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef BANK_H +#define BANK_H + +#include "../globals.h" +#include "XMLwrapper.h" +#include "Part.h" + +#define BANK_SIZE 160 + +/* + * The max. number of banks that are used + */ +#define MAX_NUM_BANKS 400 + + +class Bank{ + public: + Bank(); + ~Bank(); + char *getname(unsigned int ninstrument); + char *getnamenumbered(unsigned int ninstrument); + void setname(unsigned int ninstrument,const char *newname,int newslot);//if newslot==-1 then this is ignored, else it will be put on that slot + bool isPADsynth_used(unsigned int ninstrument); + + //returns 0 if the slot is not empty or 1 if the slot is empty + int emptyslot(unsigned int ninstrument); + + void clearslot(unsigned int ninstrument); + void savetoslot(unsigned int ninstrument,Part *part); + void loadfromslot(unsigned int ninstrument,Part *part); + + void swapslot(unsigned int n1,unsigned int n2); + + int loadbank(const char *bankdirname); + int newbank(const char *newbankdirname); + + char *bankfiletitle; //this is shown on the UI of the bank (the title of the window) + int locked(); + + void rescanforbanks(); + + struct bankstruct{ + char *dir; + char *name; + }; + + bankstruct banks[MAX_NUM_BANKS]; + + private: + + //it adds a filename to the bank + //if pos is -1 it try to find a position + //returns -1 if the bank is full, or 0 if the instrument was added + int addtobank(int pos,const char* filename,const char* name); + + void deletefrombank(int pos); + + void clearbank(); + + char defaultinsname[PART_MAX_NAME_LEN]; + char tmpinsname[BANK_SIZE][PART_MAX_NAME_LEN+20];//this keeps the numbered names + + struct ins_t{ + bool used; + char name[PART_MAX_NAME_LEN+1]; + char *filename; + struct{ + bool PADsynth_used; + } info; + }ins[BANK_SIZE]; + + char *dirname; + + void scanrootdir(char *rootdir);//scans a root dir for banks +}; + +#endif + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.C new file mode 100644 index 00000000..f04a32ac --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.C @@ -0,0 +1,303 @@ +/* + ZynAddSubFX - a software synthesizer + + Config.C - Configuration file functions + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#ifdef OS_WINDOWS +#include <windows.h> +#include <mmsystem.h> +#endif + +#include "Config.h" +#include "XMLwrapper.h" +#include "config.h" + +Config::Config(){ +}; +void Config::init(){ + maxstringsize=MAX_STRING_SIZE;//for ui + //defaults + cfg.SampleRate=44100; + cfg.SoundBufferSize=256; + cfg.OscilSize=512; + cfg.SwapStereo=0; + + cfg.LinuxOSSWaveOutDev=new char[MAX_STRING_SIZE]; + snprintf(cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE,"/dev/dsp"); + cfg.LinuxOSSSeqInDev=new char[MAX_STRING_SIZE]; + snprintf(cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE,"/dev/sequencer"); + + cfg.DumpFile=new char[MAX_STRING_SIZE]; + snprintf(cfg.DumpFile,MAX_STRING_SIZE,"zynaddsubfx_dump.txt"); + + cfg.WindowsWaveOutId=0; + cfg.WindowsMidiInId=0; + + cfg.BankUIAutoClose=0; + cfg.DumpNotesToFile=0; + cfg.DumpAppend=1; + + cfg.GzipCompression=3; + + cfg.Interpolation=0; + cfg.CheckPADsynth=1; + + cfg.UserInterfaceMode=1; + cfg.VirKeybLayout=1; + winwavemax=1;winmidimax=1; +//try to find out how many input midi devices are there + winmididevices=new winmidionedevice[winmidimax]; + for (int i=0;i<winmidimax;i++) { + winmididevices[i].name=new char[MAX_STRING_SIZE]; + for (int j=0;j<MAX_STRING_SIZE;j++) winmididevices[i].name[j]='\0'; + }; + + +//get the midi input devices name + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.bankRootDirList[i]=NULL; + cfg.currentBankDir=new char[MAX_STRING_SIZE]; + sprintf(cfg.currentBankDir,"./testbnk"); + + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.presetsDirList[i]=NULL; + +// char filename[MAX_STRING_SIZE]; +// getConfigFileName(filename,MAX_STRING_SIZE); +// readConfig(filename); + + if (cfg.bankRootDirList[0]==NULL){ + //banks + cfg.bankRootDirList[0]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[0],"~/banks"); + + cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[1], INSTPREFIX "/share/" INSTALL_NAME "/presets/zynaddsubfx/banks"); + + cfg.bankRootDirList[2]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[2],"/usr/share/zynaddsubfx/banks"); + + cfg.bankRootDirList[3]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[3],"/usr/local/share/zynaddsubfx/banks"); + + cfg.bankRootDirList[4]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[4],"../banks"); + + cfg.bankRootDirList[5]=new char[MAX_STRING_SIZE]; + sprintf(cfg.bankRootDirList[5],"banks"); + }; + + if (cfg.presetsDirList[0]==NULL){ +#if defined(OS_LINUX) + //presets + cfg.presetsDirList[0]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[0],"./"); + + cfg.presetsDirList[1]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[1],"../presets"); + + cfg.presetsDirList[2]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[2],"presets"); + + cfg.presetsDirList[3]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[3],"/usr/share/zynaddsubfx/presets"); + + cfg.presetsDirList[4]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[4],"/usr/local/share/zynaddsubfx/presets"); + +#else + //presets + cfg.presetsDirList[0]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[0],"./"); + +#ifdef VSTAUDIOOUT + cfg.presetsDirList[1]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[1],"c:/Program Files/ZynAddSubFX/presets"); +#else + cfg.presetsDirList[1]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[1],"../presets"); +#endif + + cfg.presetsDirList[2]=new char[MAX_STRING_SIZE]; + sprintf(cfg.presetsDirList[2],"presets"); +#endif + }; + +}; + +Config::~Config(){ + + delete(cfg.LinuxOSSWaveOutDev); + delete(cfg.LinuxOSSSeqInDev); + delete(cfg.DumpFile); + + for (int i=0;i<winmidimax;i++) delete (winmididevices[i].name); + delete(winmididevices); +}; + + +void Config::save(){ + char filename[MAX_STRING_SIZE]; + getConfigFileName(filename,MAX_STRING_SIZE); + saveConfig(filename); +}; + +void Config::clearbankrootdirlist(){ + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) { + if (cfg.bankRootDirList[i]==NULL) delete(cfg.bankRootDirList[i]); + cfg.bankRootDirList[i]=NULL; + }; +}; + +void Config::clearpresetsdirlist(){ + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) { + if (cfg.presetsDirList[i]==NULL) delete(cfg.presetsDirList[i]); + cfg.presetsDirList[i]=NULL; + }; +}; + +void Config::readConfig(char *filename){ + XMLwrapper *xmlcfg=new XMLwrapper(); + if (xmlcfg->loadXMLfile(filename)<0) return; + if (xmlcfg->enterbranch("CONFIGURATION")){ + cfg.SampleRate=xmlcfg->getpar("sample_rate",cfg.SampleRate,4000,1024000); + cfg.SoundBufferSize=xmlcfg->getpar("sound_buffer_size",cfg.SoundBufferSize,16,8192); + cfg.OscilSize=xmlcfg->getpar("oscil_size",cfg.OscilSize,MAX_AD_HARMONICS*2,131072); + cfg.SwapStereo=xmlcfg->getpar("swap_stereo",cfg.SwapStereo,0,1); + cfg.BankUIAutoClose=xmlcfg->getpar("bank_window_auto_close",cfg.BankUIAutoClose,0,1); + + cfg.DumpNotesToFile=xmlcfg->getpar("dump_notes_to_file",cfg.DumpNotesToFile,0,1); + cfg.DumpAppend=xmlcfg->getpar("dump_append",cfg.DumpAppend,0,1); + xmlcfg->getparstr("dump_file",cfg.DumpFile,MAX_STRING_SIZE); + + cfg.GzipCompression=xmlcfg->getpar("gzip_compression",cfg.GzipCompression,0,9); + + xmlcfg->getparstr("bank_current",cfg.currentBankDir,MAX_STRING_SIZE); + cfg.Interpolation=xmlcfg->getpar("interpolation",cfg.Interpolation,0,1); + + cfg.CheckPADsynth=xmlcfg->getpar("check_pad_synth",cfg.CheckPADsynth,0,1); + + + cfg.UserInterfaceMode=xmlcfg->getpar("user_interface_mode",cfg.UserInterfaceMode,0,2); + cfg.VirKeybLayout=xmlcfg->getpar("virtual_keyboard_layout",cfg.VirKeybLayout,0,10); + + //get bankroot dirs + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){ + if (xmlcfg->enterbranch("BANKROOT",i)){ + cfg.bankRootDirList[i]=new char[MAX_STRING_SIZE]; + xmlcfg->getparstr("bank_root",cfg.bankRootDirList[i],MAX_STRING_SIZE); + xmlcfg->exitbranch(); + }; + }; + + //get preset root dirs + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){ + if (xmlcfg->enterbranch("PRESETSROOT",i)){ + cfg.presetsDirList[i]=new char[MAX_STRING_SIZE]; + xmlcfg->getparstr("presets_root",cfg.presetsDirList[i],MAX_STRING_SIZE); + xmlcfg->exitbranch(); + }; + }; + + //linux stuff + xmlcfg->getparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE); + xmlcfg->getparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE); + + //windows stuff + cfg.WindowsWaveOutId=xmlcfg->getpar("windows_wave_out_id",cfg.WindowsWaveOutId,0,winwavemax); + cfg.WindowsMidiInId=xmlcfg->getpar("windows_midi_in_id",cfg.WindowsMidiInId,0,winmidimax); + + xmlcfg->exitbranch(); + }; + delete(xmlcfg); + + cfg.OscilSize=(int) pow(2,ceil(log (cfg.OscilSize-1.0)/log(2.0))); + +}; + +void Config::saveConfig(char *filename){ + XMLwrapper *xmlcfg=new XMLwrapper(); + + xmlcfg->beginbranch("CONFIGURATION"); + + xmlcfg->addpar("sample_rate",cfg.SampleRate); + xmlcfg->addpar("sound_buffer_size",cfg.SoundBufferSize); + xmlcfg->addpar("oscil_size",cfg.OscilSize); + xmlcfg->addpar("swap_stereo",cfg.SwapStereo); + xmlcfg->addpar("bank_window_auto_close",cfg.BankUIAutoClose); + + xmlcfg->addpar("dump_notes_to_file",cfg.DumpNotesToFile); + xmlcfg->addpar("dump_append",cfg.DumpAppend); + xmlcfg->addparstr("dump_file",cfg.DumpFile); + + xmlcfg->addpar("gzip_compression",cfg.GzipCompression); + + xmlcfg->addpar("check_pad_synth",cfg.CheckPADsynth); + + xmlcfg->addparstr("bank_current",cfg.currentBankDir); + + xmlcfg->addpar("user_interface_mode",cfg.UserInterfaceMode); + xmlcfg->addpar("virtual_keyboard_layout",cfg.VirKeybLayout); + + + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.bankRootDirList[i]!=NULL) { + xmlcfg->beginbranch("BANKROOT",i); + xmlcfg->addparstr("bank_root",cfg.bankRootDirList[i]); + xmlcfg->endbranch(); + }; + + for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.presetsDirList[i]!=NULL) { + xmlcfg->beginbranch("PRESETSROOT",i); + xmlcfg->addparstr("presets_root",cfg.presetsDirList[i]); + xmlcfg->endbranch(); + }; + + xmlcfg->addpar("interpolation",cfg.Interpolation); + + //linux stuff + xmlcfg->addparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev); + xmlcfg->addparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev); + + //windows stuff + xmlcfg->addpar("windows_wave_out_id",cfg.WindowsWaveOutId); + xmlcfg->addpar("windows_midi_in_id",cfg.WindowsMidiInId); + + xmlcfg->endbranch(); + + int tmp=cfg.GzipCompression; + cfg.GzipCompression=0; + xmlcfg->saveXMLfile(filename); + cfg.GzipCompression=tmp; + + delete(xmlcfg); +}; + +void Config::getConfigFileName(char *name, int namesize){ + name[0]=0; +#ifdef OS_LINUX + snprintf(name,namesize,"%s%s",getenv("HOME"),"/.zynaddsubfxXML.cfg"); +#else + snprintf(name,namesize,"%s","zynaddsubfxXML.cfg"); +#endif + +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.h new file mode 100644 index 00000000..800a1823 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Config.h @@ -0,0 +1,67 @@ +/* + ZynAddSubFX - a software synthesizer + + Config.h - Configuration file functions + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef CONFIG_H +#define CONFIG_H +#include "../globals.h" +#define MAX_STRING_SIZE 4000 +#define MAX_BANK_ROOT_DIRS 100 + +class Config{ + public: + Config(); + ~Config(); + struct { + char *LinuxOSSWaveOutDev,*LinuxOSSSeqInDev; + int SampleRate,SoundBufferSize,OscilSize,SwapStereo; + int WindowsWaveOutId,WindowsMidiInId; + int BankUIAutoClose; + int DumpNotesToFile,DumpAppend; + int GzipCompression; + int Interpolation; + char *DumpFile; + char *bankRootDirList[MAX_BANK_ROOT_DIRS],*currentBankDir; + char *presetsDirList[MAX_BANK_ROOT_DIRS]; + int CheckPADsynth; + int UserInterfaceMode; + int VirKeybLayout; + } cfg; + int winwavemax,winmidimax;//number of wave/midi devices on Windows + int maxstringsize; + + struct winmidionedevice{ + char *name; + }; + winmidionedevice *winmididevices; + + void clearbankrootdirlist(); + void clearpresetsdirlist(); + void init(); + void save(); + + private: + void readConfig(char *filename); + void saveConfig(char *filename); + void getConfigFileName(char *name,int namesize); +}; +#endif + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.C new file mode 100644 index 00000000..2b5bd810 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.C @@ -0,0 +1,99 @@ +/* + ZynAddSubFX - a software synthesizer + + Dump.C - It dumps the notes to a text file + + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 <stdlib.h> +#include <time.h> +#include "Util.h" +#include "Dump.h" + +Dump dump; + +Dump::Dump(){ + file=NULL; + tick=0; + k=0; + keyspressed=0; +}; + +Dump::~Dump(){ + if (file!=NULL) { + double duration=(double)tick*(double) SOUND_BUFFER_SIZE/(double) SAMPLE_RATE; + fprintf(file,"\n# statistics: duration = %d seconds; keyspressed = %d\n\n\n\n",(int) duration,keyspressed); + fclose(file); + }; +}; + +void Dump::startnow(){ + if (file!=NULL) return;//the file is already open + + if (config.cfg.DumpNotesToFile!=0){ + if (config.cfg.DumpAppend!=0) file=fopen(config.cfg.DumpFile,"a"); + else file=fopen(config.cfg.DumpFile,"w"); + if (file==NULL) return; + if (config.cfg.DumpAppend!=0) fprintf(file,"%s","#************************************\n"); + + time_t tm=time(NULL); + + fprintf(file,"#date/time = %s\n",ctime(&tm)); + fprintf(file,"#1 tick = %g milliseconds\n",SOUND_BUFFER_SIZE*1000.0/SAMPLE_RATE); + fprintf(file,"SAMPLERATE = %d\n",SAMPLE_RATE); + fprintf(file,"TICKSIZE = %d #samples\n",SOUND_BUFFER_SIZE); + fprintf(file,"\n\nSTART\n"); + }; +}; + +void Dump::inctick(){ + tick++; +}; + + +void Dump::dumpnote(char chan,char note, char vel){ + if (file==NULL) return; + if (note==0) return; + if (vel==0) fprintf(file,"n %d -> %d %d \n",tick,chan,note);//note off + else fprintf(file,"N %d -> %d %d %d \n",tick,chan,note,vel);//note on + + if (vel!=0) keyspressed++; +#ifndef JACKAUDIOOUT + if (k++>25) { + fflush(file); + k=0; + }; +#endif +}; + +void Dump::dumpcontroller(char chan,unsigned int type,int par){ + if (file==NULL) return; + switch(type){ + case C_pitchwheel:fprintf(file,"P %d -> %d %d\n",tick,chan,par); + break; + default:fprintf(file,"C %d -> %d %d %d\n",tick,chan,type,par); + break; + }; +#ifndef JACKAUDIOOUT + if (k++>25) { + fflush(file); + k=0; + }; +#endif +}; + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.h new file mode 100644 index 00000000..e5a49570 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Dump.h @@ -0,0 +1,43 @@ +/* + ZynAddSubFX - a software synthesizer + + Dump.h - It dumps the notes to a text file + + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 +*/ +#ifndef DUMP_H +#define DUMP_H + +#include <stdio.h> + +class Dump{ + public: + Dump(); + ~Dump(); + void startnow(); + void inctick(); + + void dumpnote(char chan,char note, char vel); + void dumpcontroller(char chan,unsigned int type,int par); + + private: + FILE *file; + int tick; + int k; + int keyspressed; +}; +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C new file mode 100644 index 00000000..99a1ac28 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C @@ -0,0 +1,680 @@ +/* + ZynAddSubFX - a software synthesizer + + Master.C - It sends Midi Messages to Parts, receives samples from parts, + process them with system/insertion effects and mix them + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 "Master.h" + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + +Master::Master(){ + swaplr=0; + + busy = false; + fft=new FFTwrapper(OSCIL_SIZE); + + tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE]; + tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutl=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutr=new REALTYPE[SOUND_BUFFER_SIZE]; + + ksoundbuffersamples=0; + ksoundbuffersamplelow=0.0; + oldsamplel=0.0;oldsampler=0.0; + shutup=0; + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + vuoutpeakpart[npart]=1e-9; + fakepeakpart[npart]=0; + }; + + memset(audiooutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(audiooutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) + part[npart]=new Part(µtonal,fft,this); + + + //Insertion Effects init + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) + insefx[nefx]=new EffectMgr(1,this); + + //System Effects init + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) { + sysefx[nefx]=new EffectMgr(0,this); + }; + + + defaults(); +}; + +void Master::defaults(){ + volume=1.0; + setPvolume(80); + setPkeyshift(64); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + part[npart]->defaults(); + part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS; + }; + + partonoff(0,1);//enable the first part + + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) { + insefx[nefx]->defaults(); + Pinsparts[nefx]=-1; + }; + + //System Effects init + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) { + sysefx[nefx]->defaults(); + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (nefx==0) setPsysefxvol(npart,nefx,64); + else setPsysefxvol(npart,nefx,0); + }; + for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++) + setPsysefxsend(nefx,nefxto,0); + }; + + sysefx[0]->changeeffect(1); + microtonal.defaults(); + ShutUp(); +}; + +/* + * Note On Messages (velocity=0 for NoteOff) + */ +void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity){ + dump.dumpnote(chan,note,velocity); + + noteon(chan,note,velocity); +}; + +/* + * Internal Note On (velocity=0 for NoteOff) + */ +void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity){ + int npart; + if (velocity!=0){ + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (chan==part[npart]->Prcvchn){ + fakepeakpart[npart]=velocity*2; + if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift); + }; + }; + }else{ + this->NoteOff(chan,note); + }; + HDDRecorder.triggernow(); +}; + +/* + * Note Off Messages + */ +void Master::NoteOff(unsigned char chan,unsigned char note){ + dump.dumpnote(chan,note,0); + + noteoff(chan,note); +}; + +/* + * Internal Note Off + */ +void Master::noteoff(unsigned char chan,unsigned char note){ + int npart; + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->NoteOff(note); + }; +}; + +/* + * Controllers + */ +void Master::SetController(unsigned char chan,unsigned int type,int par){ + dump.dumpcontroller(chan,type,par); + + setcontroller(chan,type,par); +}; + +/* + * Internal Controllers + */ +void Master::setcontroller(unsigned char chan,unsigned int type,int par){ + if ((type==C_dataentryhi)||(type==C_dataentrylo)|| + (type==C_nrpnhi)||(type==C_nrpnlo)){//Process RPN and NRPN by the Master (ignore the chan) + ctl.setparameternumber(type,par); + + int parhi=-1,parlo=-1,valhi=-1,vallo=-1; + if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0){//this is NRPN + //fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo); + switch (parhi){ + case 0x04://System Effects + if (parlo<NUM_SYS_EFX) { + sysefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + case 0x08://Insertion Effects + if (parlo<NUM_INS_EFX) { + insefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + + }; + }; + } else {//other controllers + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){//Send the controller to all part assigned to the channel + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->SetController(type,par); + }; + }; +}; + + +/* + * Enable/Disable a part + */ +void Master::partonoff(int npart,int what){ + if (npart>=NUM_MIDI_PARTS) return; + if (what==0){//disable part + fakepeakpart[npart]=0; + part[npart]->Penabled=0; + part[npart]->cleanup(); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]==npart) { + insefx[nefx]->cleanup(); + }; + }; + } else {//enabled + part[npart]->Penabled=1; + fakepeakpart[npart]=0; + }; +}; + +/* + * Master audio out (the final sound) + */ + +void Master::AudioOut(REALTYPE* outl, REALTYPE* outr) + { + int i,npart,nefx; + + //Swaps the Left channel with Right Channel (if it is asked for) + if (swaplr != 0) { + REALTYPE *tmp=outl; + outl = outr; + outr = tmp; + } + + //clean up the output samples + memset(outl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(outr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + //Compute part samples and store them part[npart]->partoutl,partoutr + for (npart=0; npart<NUM_MIDI_PARTS; npart++) + if (part[npart]->Penabled != 0) + part[npart]->ComputePartSmps(); + + //Insertion effects + for (nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]>=0) { + int efxpart=Pinsparts[nefx]; + if (part[efxpart]->Penabled!=0) + insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr); + } + } + + + //Apply the part volumes and pannings (after insertion effects) + for (npart = 0; npart < NUM_MIDI_PARTS; npart++) { + if (part[npart]->Penabled==0) + continue; + + REALTYPE newvol_l=part[npart]->volume; + REALTYPE newvol_r=part[npart]->volume; + REALTYPE oldvol_l=part[npart]->oldvolumel; + REALTYPE oldvol_r=part[npart]->oldvolumer; + REALTYPE pan=part[npart]->panning; + if (pan < 0.5) + newvol_l *= pan*2.0; + else + newvol_r *= (1.0-pan)*2.0; + + if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)|| + ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)){//the volume or the panning has changed and needs interpolation + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE vol_l = INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE); + REALTYPE vol_r = INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE); + part[npart]->partoutl[i]*=vol_l; + part[npart]->partoutr[i]*=vol_r; + } + part[npart]->oldvolumel=newvol_l; + part[npart]->oldvolumer=newvol_r; + + } + else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed + part[npart]->partoutl[i] *= newvol_l; + part[npart]->partoutr[i] *= newvol_r; + } + } + } + + + //System effects + for (nefx=0;nefx<NUM_SYS_EFX;nefx++){ + if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled + + //Clean up the samples used by the system effects + memset(tmpmixl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpmixr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + //Mix the channels according to the part settings about System Effect + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + //skip if the part has no output to effect + if (Psysefxvol[nefx][npart]==0) continue; + + //skip if the part is disabled + if (part[npart]->Penabled==0) continue; + + //the output volume of each part to system effect + REALTYPE vol=sysefxvol[nefx][npart]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=part[npart]->partoutl[i]*vol; + tmpmixr[i]+=part[npart]->partoutr[i]*vol; + }; + }; + + // system effect send to next ones + for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++){ + if (Psysefxsend[nefxfrom][nefx]!=0){ + REALTYPE v=sysefxsend[nefxfrom][nefx]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v; + tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v; + }; + }; + }; + + sysefx[nefx]->out(tmpmixl,tmpmixr); + + //Add the System Effect to sound output + REALTYPE outvol=sysefx[nefx]->sysefxgetvolume(); + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]+=tmpmixl[i]*outvol; + outr[i]+=tmpmixr[i]*outvol; + }; + + }; + + //Mix all parts + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) { //the volume did not changed + outl[i] += part[npart]->partoutl[i]; + outr[i] += part[npart]->partoutr[i]; + } + } + + //Insertion effects for Master Out + for (nefx=0;nefx<NUM_INS_EFX;nefx++) { + if (Pinsparts[nefx] == -2) + insefx[nefx]->out(outl, outr); + } + + //Master Volume + for (i = 0; i < SOUND_BUFFER_SIZE; i++) { + outl[i] *= volume; + outr[i] *= volume; + } + + //Peak computation (for vumeters) + vuoutpeakl=1e-12;vuoutpeakr=1e-12; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]); + if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]); + }; + if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1; + if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl; + if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr; + + //RMS Peak computation (for vumeters) + vurmspeakl=1e-12;vurmspeakr=1e-12; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + vurmspeakl+=outl[i]*outl[i]; + vurmspeakr+=outr[i]*outr[i]; + }; + vurmspeakl=sqrt(vurmspeakl/SOUND_BUFFER_SIZE); + vurmspeakr=sqrt(vurmspeakr/SOUND_BUFFER_SIZE); + + //Part Peak computation (for Part vumeters or fake part vumeters) + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + vuoutpeakpart[npart]=1.0e-12; + if (part[npart]->Penabled!=0) { + REALTYPE *outl=part[npart]->partoutl, + *outr=part[npart]->partoutr; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=fabs(outl[i]+outr[i]); + if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp; + }; + vuoutpeakpart[npart]*=volume; + } else { + if (fakepeakpart[npart]>1) fakepeakpart[npart]--; + }; + }; + + + //Shutup if it is asked (with fade-out) + if (shutup != 0) { + for (i = 0; i < SOUND_BUFFER_SIZE; i++) { + REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; + outl[i] *= tmp; + outr[i] *= tmp; + } + ShutUp(); + } + + //update the LFO's time + LFOParams::time++; + + if (HDDRecorder.recording()) + HDDRecorder.recordbuffer(outl,outr); + dump.inctick(); + }; + +//--------------------------------------------------------- +// GetAudioOutSamples +//--------------------------------------------------------- + +void Master::GetAudioOutSamples(int nsamples, REALTYPE* outl, REALTYPE* outr) + { + int dstOffset = 0; + while (nsamples) { + if (ksoundbuffersamples <= 0) { + AudioOut(audiooutl, audiooutr); + ksoundbuffersamples = SOUND_BUFFER_SIZE; + } + int n = nsamples > ksoundbuffersamples ? ksoundbuffersamples : nsamples; + int srcOffset = SOUND_BUFFER_SIZE - ksoundbuffersamples; + memcpy(outl + dstOffset, audiooutl + srcOffset, n * sizeof(REALTYPE)); + memcpy(outr + dstOffset, audiooutr + srcOffset, n * sizeof(REALTYPE)); + nsamples -= n; + dstOffset += n; + ksoundbuffersamples -= n; + } + } + +Master::~Master(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete (part[npart]); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete (insefx[nefx]); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete (sysefx[nefx]); + + delete [] audiooutl; + delete [] audiooutr; + delete [] tmpmixl; + delete [] tmpmixr; + delete (fft); + +}; + + +/* + * Parameter control + */ +void Master::setPvolume(char Pvolume_){ + Pvolume=Pvolume_; + volume=dB2rap((Pvolume-96.0)/96.0*40.0); +}; + +void Master::setPkeyshift(char Pkeyshift_){ + Pkeyshift=Pkeyshift_; + keyshift=(int)Pkeyshift-64; +}; + + +void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol){ + Psysefxvol[Pefx][Ppart]=Pvol; + sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + +void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol){ + Psysefxsend[Pefxfrom][Pefxto]=Pvol; + sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + + +/* + * Panic! (Clean up all parts and effects) + */ +void Master::ShutUp(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + part[npart]->cleanup(); + fakepeakpart[npart]=0; + }; + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup(); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup(); + vuresetpeaks(); + shutup=0; +}; + + +/* + * Reset peaks and clear the "cliped" flag (for VU-meter) + */ +void Master::vuresetpeaks(){ + vuoutpeakl=1e-9;vuoutpeakr=1e-9;vumaxoutpeakl=1e-9;vumaxoutpeakr=1e-9; + vuclipped=0; +}; + + + +void Master::applyparameters(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + part[npart]->applyparameters(); + }; +}; + +void Master::add2XML(XMLwrapper *xml){ + xml->addpar("volume",Pvolume); + xml->addpar("key_shift",Pkeyshift); + xml->addparbool("nrpn_receive",ctl.NRPN.receive); + + xml->beginbranch("MICROTONAL"); + microtonal.add2XML(xml); + xml->endbranch(); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + xml->beginbranch("PART",npart); + part[npart]->add2XML(xml); + xml->endbranch(); + }; + + xml->beginbranch("SYSTEM_EFFECTS"); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){ + xml->beginbranch("SYSTEM_EFFECT",nefx); + xml->beginbranch("EFFECT"); + sysefx[nefx]->add2XML(xml); + xml->endbranch(); + + for (int pefx=0;pefx<NUM_MIDI_PARTS;pefx++){ + xml->beginbranch("VOLUME",pefx); + xml->addpar("vol",Psysefxvol[nefx][pefx]); + xml->endbranch(); + }; + + for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){ + xml->beginbranch("SENDTO",tonefx); + xml->addpar("send_vol",Psysefxsend[nefx][tonefx]); + xml->endbranch(); + }; + + + xml->endbranch(); + }; + xml->endbranch(); + + xml->beginbranch("INSERTION_EFFECTS"); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + xml->beginbranch("INSERTION_EFFECT",nefx); + xml->addpar("part",Pinsparts[nefx]); + + xml->beginbranch("EFFECT"); + insefx[nefx]->add2XML(xml); + xml->endbranch(); + xml->endbranch(); + }; + + xml->endbranch(); + +}; + + +int Master::getalldata(char **data){ + XMLwrapper *xml=new XMLwrapper(); + + xml->beginbranch("MASTER"); + + busy = true; + add2XML(xml); + busy = false; + + xml->endbranch(); + + *data=xml->getXMLdata(); + delete (xml); + return(strlen(*data)+1); +}; + +void Master::putalldata(char *data,int size){ + XMLwrapper *xml=new XMLwrapper(); + if (!xml->putXMLdata(data)) { + delete(xml); + return; + }; + + if (xml->enterbranch("MASTER")==0) return; + + busy = true; + getfromXML(xml); + busy = false; + + xml->exitbranch(); + + delete(xml); +}; + +int Master::saveXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + + xml->beginbranch("MASTER"); + add2XML(xml); + xml->endbranch(); + + int result=xml->saveXMLfile(filename); + delete (xml); + return(result); +}; + + + +int Master::loadXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + if (xml->loadXMLfile(filename)<0) { + delete(xml); + return(-1); + }; + + if (xml->enterbranch("MASTER")==0) return(-10); + getfromXML(xml); + xml->exitbranch(); + + delete(xml); + return(0); +}; + +void Master::getfromXML(XMLwrapper *xml){ + setPvolume(xml->getpar127("volume",Pvolume)); + setPkeyshift(xml->getpar127("key_shift",Pkeyshift)); + ctl.NRPN.receive=xml->getparbool("nrpn_receive",ctl.NRPN.receive); + + + part[0]->Penabled=0; + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (xml->enterbranch("PART",npart)==0) continue; + part[npart]->getfromXML(xml); + xml->exitbranch(); + }; + + if (xml->enterbranch("MICROTONAL")){ + microtonal.getfromXML(xml); + xml->exitbranch(); + }; + + sysefx[0]->changeeffect(0); + if (xml->enterbranch("SYSTEM_EFFECTS")){ + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){ + if (xml->enterbranch("SYSTEM_EFFECT",nefx)==0) continue; + if (xml->enterbranch("EFFECT")){ + sysefx[nefx]->getfromXML(xml); + xml->exitbranch(); + }; + + for (int partefx=0;partefx<NUM_MIDI_PARTS;partefx++){ + if (xml->enterbranch("VOLUME",partefx)==0) continue; + setPsysefxvol(partefx,nefx,xml->getpar127("vol",Psysefxvol[partefx][nefx])); + xml->exitbranch(); + }; + + for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){ + if (xml->enterbranch("SENDTO",tonefx)==0) continue; + setPsysefxsend(nefx,tonefx,xml->getpar127("send_vol",Psysefxsend[nefx][tonefx])); + xml->exitbranch(); + }; + xml->exitbranch(); + }; + xml->exitbranch(); + }; + + + if (xml->enterbranch("INSERTION_EFFECTS")){ + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + + if (xml->enterbranch("INSERTION_EFFECT",nefx)==0) continue; + Pinsparts[nefx]=xml->getpar("part",Pinsparts[nefx],-2,NUM_MIDI_PARTS); + if (xml->enterbranch("EFFECT")){ + insefx[nefx]->getfromXML(xml); + xml->exitbranch(); + }; + xml->exitbranch(); + + }; + + xml->exitbranch(); + }; + +}; + + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.h new file mode 100644 index 00000000..51feabdd --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.h @@ -0,0 +1,167 @@ +/* + ZynAddSubFX - a software synthesizer + + Master.h - It sends Midi Messages to Parts, receives samples from parts, + process them with system/insertion effects and mix them + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef MASTER_H +#define MASTER_H + +#include "../globals.h" +#include "../Effects/EffectMgr.h" +#include "Part.h" +#include "../Output/Recorder.h" +#include "Microtonal.h" + +#include "Bank.h" +#include "Dump.h" +#include "../Seq/Sequencer.h" +#include "XMLwrapper.h" + +extern Dump dump; +class Master{ + public: + Master(); + ~Master(); + + //saves all settings to a XML file + //returns 0 for ok or <0 if there is an error + int saveXML(char *filename); + + //this adds the parameters to the XML data + void add2XML(XMLwrapper *xml); + + void defaults(); + + + //loads all settings from a XML file + //returns 0 for ok or -1 if there is an error + int loadXML(char *filename); + void applyparameters(); + + void getfromXML(XMLwrapper *xml); + + //get all data to a newly allocated array (used for VST) + //returns the datasize + int getalldata(char **data); + //put all data from the *data array to zynaddsubfx parameters (used for VST) + void putalldata(char *data,int size); + + + + //Midi IN + void NoteOn(unsigned char chan,unsigned char note,unsigned char velocity); + void NoteOff(unsigned char chan,unsigned char note); + void SetController(unsigned char chan,unsigned int type,int par); + //void NRPN... + + + void ShutUp(); + int shutup; + + //Audio Output + void AudioOut(REALTYPE *outl,REALTYPE *outr); + //Audio Output (for callback mode). This allows the program to be controled by an external program + void GetAudioOutSamples(int nsamples, REALTYPE *outl,REALTYPE *outr); + + + void partonoff(int npart,int what); + + //parts + Part *part[NUM_MIDI_PARTS]; + + //parameters + unsigned char Pvolume; + unsigned char Pkeyshift; + unsigned char Psysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; + unsigned char Psysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; + + //parameters control + void setPvolume(char Pvolume_); + void setPkeyshift(char Pkeyshift_); + void setPsysefxvol(int Ppart,int Pefx,char Pvol); + void setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol); + + //effects + EffectMgr *sysefx[NUM_SYS_EFX];//system + EffectMgr *insefx[NUM_INS_EFX];//insertion +// void swapcopyeffects(int what,int type,int neff1,int neff2); + + //HDD recorder + Recorder HDDRecorder; + + //part that's apply the insertion effect; -1 to disable + short int Pinsparts[NUM_INS_EFX]; + + //peaks for VU-meter + void vuresetpeaks(); + REALTYPE vuoutpeakl,vuoutpeakr,vumaxoutpeakl,vumaxoutpeakr,vurmspeakl,vurmspeakr; + int vuclipped; + + //peaks for part VU-meters + REALTYPE vuoutpeakpart[NUM_MIDI_PARTS]; + unsigned char fakepeakpart[NUM_MIDI_PARTS];//this is used to compute the "peak" when the part is disabled + + Controller ctl; + int swaplr;//1 if L and R are swapped + + //Sequencer + Sequencer seq; + + //other objects + Microtonal microtonal; + Bank bank; + + FFTwrapper *fft; + volatile bool busy; // if true, is busy and cannot accept + // events or deliver data + void lock() { busy = true; } + void unlock() { busy = false; } + + private: + REALTYPE volume; + REALTYPE sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; + REALTYPE sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; + + //Temporary mixing samples for part samples which is sent to system effect + REALTYPE *tmpmixl; + REALTYPE *tmpmixr; + + + int keyshift; + + //Audio Output samples (if it used GetAudioOutSamples - eg. for Jack output; elsewhere is unused) + REALTYPE *audiooutl; + REALTYPE *audiooutr; + + int ksoundbuffersamples; // number of valid samples in audiooutr/l + REALTYPE ksoundbuffersamplelow;//this is used for resampling (eg. if Jack samplerate!= SAMPLE_RATE) + REALTYPE oldsamplel,oldsampler;//this is used for resampling + + //Theese are called by the NoteOn, NoteOff,SetController (which are from external sources like MIDI, Virtual Keyboard) + //and are called by internal parts of the program (like sequencer) + void noteon(unsigned char chan,unsigned char note,unsigned char velocity); + void noteoff(unsigned char chan,unsigned char note); + void setcontroller(unsigned char chan,unsigned int type,int par); +}; + + +#endif + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C new file mode 100644 index 00000000..30a3a71e --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C @@ -0,0 +1,514 @@ +/* + ZynAddSubFX - a software synthesizer + + Microtonal.C - Tuning settings and microtonal capabilities + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 <math.h> +#include <string.h> +#include "Microtonal.h" + +#define MAX_LINE_SIZE 80 + +Microtonal::Microtonal(){ + Pname=new unsigned char[MICROTONAL_MAX_NAME_LEN]; + Pcomment=new unsigned char[MICROTONAL_MAX_NAME_LEN]; + defaults(); +}; + +void Microtonal::defaults(){ + Pinvertupdown=0; + Pinvertupdowncenter=60; + octavesize=12; + Penabled=0; + PAnote=69; + PAfreq=440.0; + Pscaleshift=64; + + Pfirstkey=0;Plastkey=127; + Pmiddlenote=60;Pmapsize=12; + Pmappingenabled=0; + + for (int i=0;i<128;i++) Pmapping[i]=i; + + for (int i=0;i<MAX_OCTAVE_SIZE;i++){ + octave[i].tuning=tmpoctave[i].tuning=pow(2,(i%octavesize+1)/12.0); + octave[i].type=tmpoctave[i].type=1; + octave[i].x1=tmpoctave[i].x1=(i%octavesize+1)*100; + octave[i].x2=tmpoctave[i].x2=0; + }; + octave[11].type=2;octave[11].x1=2;octave[11].x2=1; + for (int i=0;i<MICROTONAL_MAX_NAME_LEN;i++){ + Pname[i]='\0'; + Pcomment[i]='\0'; + }; + snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"12tET"); + snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"Equal Temperament 12 notes per octave"); + Pglobalfinedetune=64; +}; + +Microtonal::~Microtonal(){ + delete (Pname); + delete (Pcomment); +}; + +/* + * Get the size of the octave + */ +unsigned char Microtonal::getoctavesize(){ + if (Penabled!=0) return(octavesize); + else return(12); +}; + +/* + * Get the frequency according the note number + */ +REALTYPE Microtonal::getnotefreq(int note,int keyshift){ + // in this function will appears many times things like this: + // var=(a+b*100)%b + // I had written this way because if I use var=a%b gives unwanted results when a<0 + // This is the same with divisions. + + if ((Pinvertupdown!=0)&&((Pmappingenabled==0)||(Penabled==0))) note=(int) Pinvertupdowncenter*2-note; + + //compute global fine detune + REALTYPE globalfinedetunerap=pow(2.0,(Pglobalfinedetune-64.0)/1200.0);//-64.0 .. 63.0 cents + + if (Penabled==0) return(pow(2.0,(note-PAnote+keyshift)/12.0)*PAfreq*globalfinedetunerap);//12tET + + int scaleshift=((int)Pscaleshift-64+(int) octavesize*100)%octavesize; + + //compute the keyshift + REALTYPE rap_keyshift=1.0; + if (keyshift!=0){ + int kskey=(keyshift+(int)octavesize*100)%octavesize; + int ksoct=(keyshift+(int)octavesize*100)/octavesize-100; + rap_keyshift=(kskey==0) ? (1.0):(octave[kskey-1].tuning); + rap_keyshift*=pow(octave[octavesize-1].tuning,ksoct); + }; + + //if the mapping is enabled + if (Pmappingenabled!=0){ + if ((note<Pfirstkey)||(note>Plastkey)) return (-1.0); + //Compute how many mapped keys are from middle note to reference note + //and find out the proportion between the freq. of middle note and "A" note + int tmp=PAnote-Pmiddlenote,minus=0; + if (tmp<0) { tmp=-tmp; minus=1; }; + int deltanote=0; + for (int i=0;i<tmp;i++) if (Pmapping[i%Pmapsize]>=0) deltanote++; + REALTYPE rap_anote_middlenote=(deltanote==0) ? (1.0) : (octave[(deltanote-1)%octavesize].tuning); + if (deltanote!=0) rap_anote_middlenote*=pow(octave[octavesize-1].tuning,(deltanote-1)/octavesize); + if (minus!=0) rap_anote_middlenote=1.0/rap_anote_middlenote; + + //Convert from note (midi) to degree (note from the tunning) + int degoct=(note-(int)Pmiddlenote+(int) Pmapsize*200)/(int)Pmapsize-200; + int degkey=(note-Pmiddlenote+(int)Pmapsize*100)%Pmapsize; + degkey=Pmapping[degkey]; + if (degkey<0) return(-1.0);//this key is not mapped + + //invert the keyboard upside-down if it is asked for + //TODO: do the right way by using Pinvertupdowncenter + if (Pinvertupdown!=0){ + degkey=octavesize-degkey-1; + degoct=-degoct; + }; + //compute the frequency of the note + degkey=degkey+scaleshift; + degoct+=degkey/octavesize; + degkey%=octavesize; + + REALTYPE freq=(degkey==0) ? (1.0):octave[degkey-1].tuning; + freq*=pow(octave[octavesize-1].tuning,degoct); + freq*=PAfreq/rap_anote_middlenote; + freq*=globalfinedetunerap; + if (scaleshift!=0) freq/=octave[scaleshift-1].tuning; + return(freq*rap_keyshift); + } else {//if the mapping is disabled + int nt=note-PAnote+scaleshift; + int ntkey=(nt+(int)octavesize*100)%octavesize; + int ntoct=(nt-ntkey)/octavesize; + + REALTYPE oct=octave[octavesize-1].tuning; + REALTYPE freq=octave[(ntkey+octavesize-1)%octavesize].tuning*pow(oct,ntoct)*PAfreq; + if (ntkey==0) freq/=oct; + if (scaleshift!=0) freq/=octave[scaleshift-1].tuning; +// fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(log(freq/PAfreq)/log(2.0)*1200.0+0.5)); + freq*=globalfinedetunerap; + return(freq*rap_keyshift); + }; +}; + + +/* + * Convert a line to tunings; returns -1 if it ok + */ +int Microtonal::linetotunings(unsigned int nline,const char *line){ + int x1=-1,x2=-1,type=-1; + REALTYPE x=-1.0,tmp,tuning=1.0; + if (strstr(line,"/")==NULL){ + if (strstr(line,".")==NULL){// M case (M=M/1) + sscanf(line,"%d",&x1); + x2=1; + type=2;//division + } else {// float number case + sscanf(line,"%f",&x); + if (x<0.000001) return(1); + type=1;//float type(cents) + }; + } else {// M/N case + sscanf(line,"%d/%d",&x1,&x2); + if ((x1<0)||(x2<0)) return(1); + if (x2==0) x2=1; + type=2;//division + }; + + if (x1<=0) x1=1;//not allow zero frequency sounds (consider 0 as 1) + + //convert to float if the number are too big + if ((type==2)&&((x1>(128*128*128-1))||(x2>(128*128*128-1)))){ + type=1; + x=((REALTYPE) x1)/x2; + }; + switch (type){ + case 1: x1=(int) floor(x); + tmp=fmod(x,1.0); + x2=(int) (floor (tmp*1e6)); + tuning=pow(2.0,x/1200.0); + break; + case 2: x=((REALTYPE)x1)/x2; + tuning=x; + break; + }; + + tmpoctave[nline].tuning=tuning; + tmpoctave[nline].type=type; + tmpoctave[nline].x1=x1; + tmpoctave[nline].x2=x2; + + return(-1);//ok +}; + +/* + * Convert the text to tunnings + */ +int Microtonal::texttotunings(const char *text){ + unsigned int i,k=0,nl=0; + char *lin; + lin=new char[MAX_LINE_SIZE+1]; + while (k<strlen(text)){ + for (i=0;i<MAX_LINE_SIZE;i++){ + lin[i]=text[k++]; + if (lin[i]<0x20) break; + }; + lin[i]='\0'; + if (strlen(lin)==0) continue; + int err=linetotunings(nl,lin); + if (err!=-1) { + delete [] lin; + return(nl);//Parse error + }; + nl++; + }; + delete [] lin; + if (nl>MAX_OCTAVE_SIZE) nl=MAX_OCTAVE_SIZE; + if (nl==0) return(-2);//the input is empty + octavesize=nl; + for (i=0;i<octavesize;i++){ + octave[i].tuning=tmpoctave[i].tuning; + octave[i].type=tmpoctave[i].type; + octave[i].x1=tmpoctave[i].x1; + octave[i].x2=tmpoctave[i].x2; + }; + return(-1);//ok +}; + +/* + * Convert the text to mapping + */ +void Microtonal::texttomapping(const char *text){ + unsigned int i,k=0; + char *lin; + lin=new char[MAX_LINE_SIZE+1]; + for (i=0;i<128;i++) Pmapping[i]=-1; + int tx=0; + while (k<strlen(text)){ + for (i=0;i<MAX_LINE_SIZE;i++){ + lin[i]=text[k++]; + if (lin[i]<0x20) break; + }; + lin[i]='\0'; + if (strlen(lin)==0) continue; + + int tmp=0; + if (sscanf(lin,"%d",&tmp)==0) tmp=-1; + if (tmp<-1) tmp=-1; + Pmapping[tx]=tmp; + + if ((tx++)>127) break; + }; + delete [] lin; + + if (tx==0) tx=1; + Pmapsize=tx; +}; + +/* + * Convert tunning to text line + */ +void Microtonal::tuningtoline(int n,char *line,int maxn){ + if ((n>octavesize) || (n>MAX_OCTAVE_SIZE)) { + line[0]='\0'; + return; + }; + if (octave[n].type==1) snprintf(line,maxn,"%d.%d",octave[n].x1,octave[n].x2); + if (octave[n].type==2) snprintf(line,maxn,"%d/%d",octave[n].x1,octave[n].x2); +}; + + +int Microtonal::loadline(FILE *file,char *line){ + do { + if (fgets(line,500,file)==0) return(1); + } while (line[0]=='!'); + return(0); +}; +/* + * Loads the tunnings from a scl file + */ +int Microtonal::loadscl(const char *filename){ + FILE *file=fopen(filename, "r"); + char tmp[500]; + fseek(file,0,SEEK_SET); + //loads the short description + if (loadline(file,&tmp[0])!=0) return(2); + for (int i=0;i<500;i++) if (tmp[i]<32) tmp[i]=0; + snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"%s",tmp); + snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"%s",tmp); + //loads the number of the notes + if (loadline(file,&tmp[0])!=0) return(2); + int nnotes=MAX_OCTAVE_SIZE; + sscanf(&tmp[0],"%d",&nnotes); + if (nnotes>MAX_OCTAVE_SIZE) return (2); + //load the tunnings + for (int nline=0;nline<nnotes;nline++){ + if (loadline(file,&tmp[0])!=0) return(2); + linetotunings(nline,&tmp[0]); + }; + fclose(file); + + octavesize=nnotes; + for (int i=0;i<octavesize;i++){ + octave[i].tuning=tmpoctave[i].tuning; + octave[i].type=tmpoctave[i].type; + octave[i].x1=tmpoctave[i].x1; + octave[i].x2=tmpoctave[i].x2; + }; + + return(0); +}; + +/* + * Loads the mapping from a kbm file + */ +int Microtonal::loadkbm(const char *filename){ + FILE *file=fopen(filename, "r"); + int x; + char tmp[500]; + + fseek(file,0,SEEK_SET); + //loads the mapsize + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pmapsize=x; + //loads first MIDI note to retune + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pfirstkey=x; + //loads last MIDI note to retune + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Plastkey=x; + //loads last the middle note where scale fro scale degree=0 + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pmiddlenote=x; + //loads the reference note + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + PAnote=x; + //loads the reference freq. + if (loadline(file,&tmp[0])!=0) return(2); + REALTYPE tmpPAfreq=440.0; + if (sscanf(&tmp[0],"%f",&tmpPAfreq)==0) return(2); + PAfreq=tmpPAfreq; + + //the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method + if (loadline(file,&tmp[0])!=0) return(2); + + //load the mappings + if (Pmapsize!=0){ + for (int nline=0;nline<Pmapsize;nline++){ + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) x=-1; + Pmapping[nline]=x; + }; + Pmappingenabled=1; + } else { + Pmappingenabled=0; + Pmapping[0]=0; + Pmapsize=1; + }; + fclose(file); + + return(0); +}; + + + +void Microtonal::add2XML(XMLwrapper *xml){ + xml->addparstr("name",(char *) Pname); + xml->addparstr("comment",(char *) Pcomment); + + xml->addparbool("invert_up_down",Pinvertupdown); + xml->addparbool("invert_up_down_center",Pinvertupdowncenter); + + xml->addparbool("enabled",Penabled); + xml->addpar("global_fine_detune",Pglobalfinedetune); + + xml->addpar("a_note",PAnote); + xml->addparreal("a_freq",PAfreq); + + if ((Penabled==0)&&(xml->minimal)) return; + + xml->beginbranch("SCALE"); + xml->addpar("scale_shift",Pscaleshift); + xml->addpar("first_key",Pfirstkey); + xml->addpar("last_key",Plastkey); + xml->addpar("middle_note",Pmiddlenote); + + xml->beginbranch("OCTAVE"); + xml->addpar("octave_size",octavesize); + for (int i=0;i<octavesize;i++){ + xml->beginbranch("DEGREE",i); + if (octave[i].type==1){ + xml->addparreal("cents",octave[i].tuning); + }; + if (octave[i].type==2){ + xml->addpar("numerator",octave[i].x1); + xml->addpar("denominator",octave[i].x2); + }; + xml->endbranch(); + }; + xml->endbranch(); + + xml->beginbranch("KEYBOARD_MAPPING"); + xml->addpar("map_size",Pmapsize); + xml->addpar("mapping_enabled",Pmappingenabled); + for (int i=0;i<Pmapsize;i++){ + xml->beginbranch("KEYMAP",i); + xml->addpar("degree",Pmapping[i]); + xml->endbranch(); + }; + xml->endbranch(); + xml->endbranch(); +}; + +void Microtonal::getfromXML(XMLwrapper *xml){ + xml->getparstr("name",(char *) Pname,MICROTONAL_MAX_NAME_LEN); + xml->getparstr("comment",(char *) Pcomment,MICROTONAL_MAX_NAME_LEN); + + Pinvertupdown=xml->getparbool("invert_up_down",Pinvertupdown); + Pinvertupdowncenter=xml->getparbool("invert_up_down_center",Pinvertupdowncenter); + + Penabled=xml->getparbool("enabled",Penabled); + Pglobalfinedetune=xml->getpar127("global_fine_detune",Pglobalfinedetune); + + PAnote=xml->getpar127("a_note",PAnote); + PAfreq=xml->getparreal("a_freq",PAfreq,1.0,10000.0); + + if (xml->enterbranch("SCALE")){ + Pscaleshift=xml->getpar127("scale_shift",Pscaleshift); + Pfirstkey=xml->getpar127("first_key",Pfirstkey); + Plastkey=xml->getpar127("last_key",Plastkey); + Pmiddlenote=xml->getpar127("middle_note",Pmiddlenote); + + if (xml->enterbranch("OCTAVE")){ + octavesize=xml->getpar127("octave_size",octavesize); + for (int i=0;i<octavesize;i++){ + if (xml->enterbranch("DEGREE",i)==0) continue; + octave[i].x2=0; + octave[i].tuning=xml->getparreal("cents",octave[i].tuning); + octave[i].x1=xml->getpar127("numerator",octave[i].x1); + octave[i].x2=xml->getpar127("denominator",octave[i].x2); + + if (octave[i].x2!=0) octave[i].type=2; + else octave[i].type=1; + + xml->exitbranch(); + }; + xml->exitbranch(); + }; + + if (xml->enterbranch("KEYBOARD_MAPPING")){ + Pmapsize=xml->getpar127("map_size",Pmapsize); + Pmappingenabled=xml->getpar127("mapping_enabled",Pmappingenabled); + for (int i=0;i<Pmapsize;i++){ + if (xml->enterbranch("KEYMAP",i)==0) continue; + Pmapping[i]=xml->getpar127("degree",Pmapping[i]); + xml->exitbranch(); + }; + xml->exitbranch(); + }; + xml->exitbranch(); + }; +}; + + +int Microtonal::saveXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + + xml->beginbranch("MICROTONAL"); + add2XML(xml); + xml->endbranch(); + + int result=xml->saveXMLfile(filename); + delete (xml); + return(result); +}; + +int Microtonal::loadXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + if (xml->loadXMLfile(filename)<0) { + delete(xml); + return(-1); + }; + + if (xml->enterbranch("MICROTONAL")==0) return(-10); + getfromXML(xml); + xml->exitbranch(); + + delete(xml); + return(0); +}; + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.h new file mode 100644 index 00000000..60ffc4cf --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.h @@ -0,0 +1,111 @@ +/* + ZynAddSubFX - a software synthesizer + + Microtonal.h - Tuning settings and microtonal capabilities + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef MICROTONAL_H +#define MICROTONAL_H + +#include "../globals.h" +#include "XMLwrapper.h" + +#define MAX_OCTAVE_SIZE 128 +#define MICROTONAL_MAX_NAME_LEN 120 + +#include <stdio.h> + +class Microtonal{ + public: + Microtonal(); + ~Microtonal(); + void defaults(); + REALTYPE getnotefreq(int note,int keyshift); + + + //Parameters + //if the keys are inversed (the pitch is lower to keys from the right direction) + unsigned char Pinvertupdown; + + //the central key of the inversion + unsigned char Pinvertupdowncenter; + + //0 for 12 key temperate scale, 1 for microtonal + unsigned char Penabled; + + //the note of "A" key + unsigned char PAnote; + + //the frequency of the "A" note + REALTYPE PAfreq; + + //if the scale is "tuned" to a note, you can tune to other note + unsigned char Pscaleshift; + + //first and last key (to retune) + unsigned char Pfirstkey; + unsigned char Plastkey; + + //The middle note where scale degree 0 is mapped to + unsigned char Pmiddlenote; + + //Map size + unsigned char Pmapsize; + + //Mapping ON/OFF + unsigned char Pmappingenabled; + //Mapping (keys) + short int Pmapping[128]; + + unsigned char Pglobalfinedetune; + + // Functions + unsigned char getoctavesize(); + void tuningtoline(int n,char *line,int maxn); + int loadscl(const char *filename);//load the tunnings from a .scl file + int loadkbm(const char *filename);//load the mapping from .kbm file + int texttotunings(const char *text); + void texttomapping(const char *text); + unsigned char *Pname; + unsigned char *Pcomment; + + void add2XML(XMLwrapper *xml); + void getfromXML(XMLwrapper *xml); + int saveXML(char *filename); + int loadXML(char *filename); + + private: + int linetotunings(unsigned int nline,const char *line); + int loadline(FILE *file,char *line);//loads a line from the text file, while ignoring the lines beggining with "!" + unsigned char octavesize; + struct { + unsigned char type;//1 for cents or 2 for division + + // the real tuning (eg. +1.05946 for one halftone) + // or 2.0 for one octave + REALTYPE tuning; + + //the real tunning is x1/x2 + unsigned int x1,x2; + + } octave[MAX_OCTAVE_SIZE],tmpoctave[MAX_OCTAVE_SIZE]; + +}; + +#endif diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.C new file mode 100644 index 00000000..ceeeb7b6 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.C @@ -0,0 +1,881 @@ +/* + ZynAddSubFX - a software synthesizer + + Part.C - Part implementation + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 "Master.h" +#include "Part.h" +#include "Microtonal.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +Part::Part(Microtonal *microtonal_,FFTwrapper *fft_, Master* master_){ + microtonal=microtonal_; + fft=fft_; + master=master_; + partoutl=new REALTYPE [SOUND_BUFFER_SIZE]; + partoutr=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpoutl=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpoutr=new REALTYPE [SOUND_BUFFER_SIZE]; + + for (int n=0;n<NUM_KIT_ITEMS;n++){ + kit[n].Pname=new unsigned char [PART_MAX_NAME_LEN]; + kit[n].adpars=NULL;kit[n].subpars=NULL;kit[n].padpars=NULL; + }; + + kit[0].adpars=new ADnoteParameters(fft); + kit[0].subpars=new SUBnoteParameters(); + kit[0].padpars=new PADnoteParameters(fft,master); +// ADPartParameters=kit[0].adpars; +// SUBPartParameters=kit[0].subpars; + + //Part's Insertion Effects init + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) + partefx[nefx]=new EffectMgr(1,master); + + for (int n=0;n<NUM_PART_EFX+1;n++) { + partfxinputl[n]=new REALTYPE [SOUND_BUFFER_SIZE]; + partfxinputr[n]=new REALTYPE [SOUND_BUFFER_SIZE]; + Pefxbypass[n]=false; + }; + + killallnotes=0; + oldfreq=-1.0; + + int i,j; + for (i=0;i<POLIPHONY;i++){ + partnote[i].status=KEY_OFF; + partnote[i].note=-1; + partnote[i].itemsplaying=0; + for (j=0;j<NUM_KIT_ITEMS;j++){ + partnote[i].kititem[j].adnote=NULL; + partnote[i].kititem[j].subnote=NULL; + partnote[i].kititem[j].padnote=NULL; + }; + partnote[i].time=0; + }; + cleanup(); + + Pname=new unsigned char [PART_MAX_NAME_LEN]; + + oldvolumel=oldvolumer=0.5; + lastnote=-1; + + + defaults(); +}; + +void Part::defaults(){ + Penabled=0; + Pminkey=0; + Pmaxkey=127; + Pnoteon=1; + Ppolymode=1; + setPvolume(96); + Pkeyshift=64; + Prcvchn=0; + setPpanning(64); + Pvelsns=64; + Pveloffs=64; + Pkeylimit=15; + defaultsinstrument(); + ctl.defaults(); +}; + +void Part::defaultsinstrument(){ + ZERO(Pname,PART_MAX_NAME_LEN); + + info.Ptype=0; + ZERO(info.Pauthor,MAX_INFO_TEXT_SIZE+1); + ZERO(info.Pcomments,MAX_INFO_TEXT_SIZE+1); + + Pkitmode=0; + Pdrummode=0; + + for (int n=0;n<NUM_KIT_ITEMS;n++){ + kit[n].Penabled=0;kit[n].Pmuted=0; + kit[n].Pminkey=0;kit[n].Pmaxkey=127; + kit[n].Padenabled=0;kit[n].Psubenabled=0;kit[n].Ppadenabled=0; + ZERO(kit[n].Pname,PART_MAX_NAME_LEN); + kit[n].Psendtoparteffect=0; + if (n!=0) setkititemstatus(n,0); + }; + kit[0].Penabled=1; + kit[0].Padenabled=1; + kit[0].adpars->defaults(); + kit[0].subpars->defaults(); + kit[0].padpars->defaults(); + + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + partefx[nefx]->defaults(); + Pefxroute[nefx]=0;//route to next effect + }; + +}; + + + +/* + * Cleanup the part + */ +void Part::cleanup(){ + for (int k=0;k<POLIPHONY;k++) KillNotePos(k); + + memcpy(partoutl, denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memcpy(partoutr, denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + ctl.resetall(); + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) partefx[nefx]->cleanup(); + for (int n=0;n<NUM_PART_EFX+1;n++) { + memcpy(partfxinputl[n], denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memcpy(partfxinputr[n], denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + }; +}; + +Part::~Part(){ + cleanup(); + for (int n=0;n<NUM_KIT_ITEMS;n++){ + if (kit[n].adpars!=NULL) delete (kit[n].adpars); + if (kit[n].subpars!=NULL) delete (kit[n].subpars); + if (kit[n].padpars!=NULL) delete (kit[n].padpars); + kit[n].adpars=NULL;kit[n].subpars=NULL;kit[n].padpars=NULL; + delete(kit[n].Pname); + }; + + delete (Pname); + delete (partoutl); + delete (partoutr); + delete (tmpoutl); + delete (tmpoutr); + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) + delete (partefx[nefx]); + for (int n=0;n<NUM_PART_EFX+1;n++) { + delete (partfxinputl[n]); + delete (partfxinputr[n]); + }; +}; + +/* + * Note On Messages + */ +void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){ + int i,pos; + + lastnote=note; + if ((note<Pminkey)||(note>Pmaxkey)) return; + + pos=-1; + for (i=0;i<POLIPHONY;i++){ + if (partnote[i].status==KEY_OFF){ + pos=i; + break; + }; + }; + + if (Ppolymode==0){//if the mode is 'mono' turn off all other notes + for (i=0;i<POLIPHONY;i++) + if (partnote[i].status==KEY_PLAYING) NoteOff(partnote[i].note); + RelaseSustainedKeys(); + }; + + 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; + + //this computes the velocity sensing of the part + REALTYPE vel=VelF(velocity/127.0,Pvelsns); + + //compute the velocity offset + vel+=(Pveloffs-64.0)/64.0; + if (vel<0.0) vel=0.0; else if (vel>1.0) vel=1.0; + + //compute the keyshift + int partkeyshift=(int)Pkeyshift-64; + int keyshift=masterkeyshift+partkeyshift; + + //initialise note frequency + REALTYPE notebasefreq; + if (Pdrummode==0){ + notebasefreq=microtonal->getnotefreq(note,keyshift); + if (notebasefreq<0.0) return;//the key is no mapped + } else { + notebasefreq=440.0*pow(2.0,(note-69.0)/12.0); + }; + + //Portamento + if (oldfreq<1.0) oldfreq=notebasefreq;//this is only the first note is played + + int portamento=ctl.initportamento(oldfreq,notebasefreq); + + if (portamento!=0) ctl.portamento.noteusing=pos; + oldfreq=notebasefreq; + + partnote[pos].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)||(kit[0].Psubenabled!=0)||(kit[0].Ppadenabled!=0)) partnote[pos].itemsplaying++; + + } else {//init the notes for the "kit mode" + for (int item=0;item<NUM_KIT_ITEMS;item++){ + if (kit[item].Pmuted!=0) continue; + if ((note<kit[item].Pminkey)||(note>kit[item].Pmaxkey)) continue; + + int ci=partnote[pos].itemsplaying;//ci=current item + + partnote[pos].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[pos].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note); + + if ((kit[item].subpars!=NULL)&&(kit[item].Psubenabled)!=0) + partnote[pos].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note); + + if ((kit[item].padpars!=NULL)&&(kit[item].Ppadenabled)!=0) + partnote[pos].kititem[ci].padnote=new PADnote(kit[item].padpars,&ctl,notebasefreq,vel,portamento,note); + + if ((kit[item].adpars!=NULL)|| (kit[item].subpars!=NULL)) { + partnote[pos].itemsplaying++; + if ( ((kit[item].Padenabled!=0)||(kit[item].Psubenabled!=0)||(kit[item].Ppadenabled!=0)) + && (Pkitmode==2) ) break; + }; + }; + }; + }; + }; + + //this only relase the keys if there is maximum number of keys allowed + setkeylimit(Pkeylimit); +}; + +/* + * Note Off Messages + */ +void Part::NoteOff(unsigned char note){//relase the key + int i; + for (i=POLIPHONY-1;i>=0;i--){ //first note in, is first out if there are same note multiple times + if ((partnote[i].status==KEY_PLAYING)&&(partnote[i].note==note)) { + if (ctl.sustain.sustain==0){ //the sustain pedal is not pushed + RelaseNotePos(i); + break; + } else {//the sustain pedal is pushed + partnote[i].status=KEY_RELASED_AND_SUSTAINED; + }; + }; + }; +}; + +/* + * Controllers + */ +void Part::SetController(unsigned int type,int par){ + switch (type){ + case C_pitchwheel:ctl.setpitchwheel(par); + break; + case C_expression:ctl.setexpression(par); + setPvolume(Pvolume);//update the volume + break; + case C_portamento:ctl.setportamento(par); + break; + case C_panning:ctl.setpanning(par); + setPpanning(Ppanning);//update the panning + break; + case C_filtercutoff:ctl.setfiltercutoff(par); + break; + case C_filterq:ctl.setfilterq(par); + break; + case C_bandwidth:ctl.setbandwidth(par); + break; + case C_modwheel:ctl.setmodwheel(par); + break; + case C_fmamp:ctl.setfmamp(par); + break; + case C_volume:ctl.setvolume(par); + if (ctl.volume.receive!=0) volume=ctl.volume.volume; + else setPvolume(Pvolume); + break; + case C_sustain:ctl.setsustain(par); + if (ctl.sustain.sustain==0) RelaseSustainedKeys(); + break; + case C_allsoundsoff:AllNotesOff();//Panic + break; + case C_resetallcontrollers: + ctl.resetall(); + RelaseSustainedKeys(); + if (ctl.volume.receive!=0) volume=ctl.volume.volume; + else setPvolume(Pvolume); + setPvolume(Pvolume);//update the volume + setPpanning(Ppanning);//update the panning + + for (int item=0;item<NUM_KIT_ITEMS;item++){ + if (kit[item].adpars==NULL) continue; + kit[item].adpars->GlobalPar.Reson-> + sendcontroller(C_resonance_center,1.0); + + kit[item].adpars->GlobalPar.Reson-> + sendcontroller(C_resonance_bandwidth,1.0); + }; + //more update to add here if I add controllers + break; + case C_allnotesoff:RelaseAllKeys(); + break; + case C_resonance_center: + ctl.setresonancecenter(par); + for (int item=0;item<NUM_KIT_ITEMS;item++){ + if (kit[item].adpars==NULL) continue; + kit[item].adpars->GlobalPar.Reson-> + sendcontroller(C_resonance_center,ctl.resonancecenter.relcenter); + }; + break; + case C_resonance_bandwidth: + ctl.setresonancebw(par); + kit[0].adpars->GlobalPar.Reson-> + sendcontroller(C_resonance_bandwidth,ctl.resonancebandwidth.relbw); + break; + }; +}; +/* + * Relase the sustained keys + */ + +void Part::RelaseSustainedKeys(){ + for (int i=0;i<POLIPHONY;i++) + if (partnote[i].status==KEY_RELASED_AND_SUSTAINED) RelaseNotePos(i); +}; + +/* + * Relase all keys + */ + +void Part::RelaseAllKeys(){ + for (int i=0;i<POLIPHONY;i++){ + if ((partnote[i].status!=KEY_RELASED)&& + (partnote[i].status!=KEY_OFF)) //thanks to Frank Neumann + RelaseNotePos(i); + }; +}; + +/* + * Release note at position + */ +void Part::RelaseNotePos(int pos){ + + for (int j=0;j<NUM_KIT_ITEMS;j++){ + + if (partnote[pos].kititem[j].adnote!=NULL) + if (partnote[pos].kititem[j].adnote) + partnote[pos].kititem[j].adnote->relasekey(); + + if (partnote[pos].kititem[j].subnote!=NULL) + if (partnote[pos].kititem[j].subnote!=NULL) + partnote[pos].kititem[j].subnote->relasekey(); + + if (partnote[pos].kititem[j].padnote!=NULL) + if (partnote[pos].kititem[j].padnote) + partnote[pos].kititem[j].padnote->relasekey(); + }; + partnote[pos].status=KEY_RELASED; +}; + + +/* + * Kill note at position + */ +void Part::KillNotePos(int pos){ + partnote[pos].status=KEY_OFF; + partnote[pos].note=-1; + partnote[pos].time=0; + partnote[pos].itemsplaying=0; + + for (int j=0;j<NUM_KIT_ITEMS;j++){ + if (partnote[pos].kititem[j].adnote!=NULL) { + delete(partnote[pos].kititem[j].adnote); + partnote[pos].kititem[j].adnote=NULL; + }; + if (partnote[pos].kititem[j].subnote!=NULL) { + delete(partnote[pos].kititem[j].subnote); + partnote[pos].kititem[j].subnote=NULL; + }; + if (partnote[pos].kititem[j].padnote!=NULL) { + delete(partnote[pos].kititem[j].padnote); + partnote[pos].kititem[j].padnote=NULL; + }; + }; + if (pos==ctl.portamento.noteusing) { + ctl.portamento.noteusing=-1; + ctl.portamento.used=0; + }; +}; + + +/* + * Set Part's key limit + */ +void Part::setkeylimit(unsigned char Pkeylimit){ + this->Pkeylimit=Pkeylimit; + int keylimit=Pkeylimit; + if (keylimit==0) keylimit=POLIPHONY-5; + + //release old keys if the number of notes>keylimit + if (Ppolymode!=0){ + int notecount=0; + for (int i=0;i<POLIPHONY;i++){ + if ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) + notecount++; + }; + int oldestnotepos=-1,maxtime=0; + if (notecount>keylimit){//find out the oldest note + for (int i=0;i<POLIPHONY;i++){ + if ( ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) + && (partnote[i].time>maxtime)){ + maxtime=partnote[i].time; + oldestnotepos=i; + }; + }; + }; + if (oldestnotepos!=-1) RelaseNotePos(oldestnotepos); + }; +}; + + +/* + * Prepare all notes to be turned off + */ +void Part::AllNotesOff(){ + killallnotes=1; +}; + + +/* + * Compute Part samples and store them in the partoutl[] and partoutr[] + */ +void Part::ComputePartSmps(){ + int i, k; + int noteplay;//0 if there is nothing activated + for (int nefx=0;nefx<NUM_PART_EFX+1;nefx++){ + memset(partfxinputl[nefx], 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(partfxinputr[nefx], 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + }; + + for (k=0;k<POLIPHONY;k++){ + if (partnote[k].status==KEY_OFF) continue; + noteplay=0; + partnote[k].time++; + //get the sampledata of the note and kill it if it's finished + + for (int item=0;item<partnote[k].itemsplaying;item++){ + + int sendcurrenttofx=partnote[k].kititem[item].sendtoparteffect; + + ADnote *adnote=partnote[k].kititem[item].adnote; + SUBnote *subnote=partnote[k].kititem[item].subnote; + PADnote *padnote=partnote[k].kititem[item].padnote; + //get from the ADnote + if (adnote!=NULL) { + noteplay++; + if (adnote->ready!=0) adnote->noteout(&tmpoutl[0],&tmpoutr[0]); + else { + memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + } + if (adnote->finished()!=0){ + delete (adnote); + partnote[k].kititem[item].adnote=NULL; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the ADnote to part(mix) + partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; + partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; + }; + }; + //get from the SUBnote + if (subnote!=NULL) { + noteplay++; + if (subnote->ready!=0) subnote->noteout(&tmpoutl[0],&tmpoutr[0]); + else { + memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + } + + for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the SUBnote to part(mix) + partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; + partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; + }; + if (subnote->finished()!=0){ + delete (subnote); + partnote[k].kititem[item].subnote=NULL; + }; + }; + //get from the PADnote + if (padnote!=NULL) { + noteplay++; + if (padnote->ready!=0) padnote->noteout(&tmpoutl[0],&tmpoutr[0]); + else { + memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + } + if (padnote->finished()!=0){ + delete (padnote); + partnote[k].kititem[item].padnote=NULL; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the PADnote to part(mix) + partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; + partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; + }; + }; + + }; + //Kill note if there is no synth on that note + if (noteplay==0) KillNotePos(k); + }; + + + //Apply part's effects and mix them + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + if (!Pefxbypass[nefx]) { + partefx[nefx]->out(partfxinputl[nefx],partfxinputr[nefx]); + if (Pefxroute[nefx]==2){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partfxinputl[nefx+1][i]+=partefx[nefx]->efxoutl[i]; + partfxinputr[nefx+1][i]+=partefx[nefx]->efxoutr[i]; + }; + }; + }; + int routeto=((Pefxroute[nefx]==0) ? nefx+1 : NUM_PART_EFX); + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partfxinputl[routeto][i]+=partfxinputl[nefx][i]; + partfxinputr[routeto][i]+=partfxinputr[nefx][i]; + }; + + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partoutl[i]=partfxinputl[NUM_PART_EFX][i]; + partoutr[i]=partfxinputr[NUM_PART_EFX][i]; + }; + + //Kill All Notes if killallnotes!=0 + if (killallnotes!=0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; + partoutl[i]*=tmp; + partoutr[i]*=tmp; + tmpoutl[i]=0.0; + tmpoutr[i]=0.0; + }; + for (int k=0;k<POLIPHONY;k++) KillNotePos(k); + killallnotes=0; + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + partefx[nefx]->cleanup(); + }; + }; + ctl.updateportamento(); +}; + +/* + * Parameter control + */ +void Part::setPvolume(char Pvolume_){ + Pvolume=Pvolume_; + volume=dB2rap((Pvolume-96.0)/96.0*40.0)*ctl.expression.relvolume; +}; + +void Part::setPpanning(char Ppanning_){ + Ppanning=Ppanning_; + panning=Ppanning/127.0+ctl.panning.pan; + if (panning<0.0) panning=0.0;else if (panning>1.0) panning=1.0; + +}; + +/* + * Enable or disable a kit item + */ +void Part::setkititemstatus(int kititem,int Penabled_){ + if ((kititem==0)&&(kititem>=NUM_KIT_ITEMS)) return;//nonexistent kit item and the first kit item is always enabled + kit[kititem].Penabled=Penabled_; + + bool resetallnotes=false; + if (Penabled_==0){ + if (kit[kititem].adpars!=NULL) delete (kit[kititem].adpars); + if (kit[kititem].subpars!=NULL) delete (kit[kititem].subpars); + if (kit[kititem].padpars!=NULL) { + delete (kit[kititem].padpars); + resetallnotes=true; + }; + kit[kititem].adpars=NULL;kit[kititem].subpars=NULL;kit[kititem].padpars=NULL; + kit[kititem].Pname[0]='\0'; + } else { + if (kit[kititem].adpars==NULL) kit[kititem].adpars=new ADnoteParameters(fft); + if (kit[kititem].subpars==NULL) kit[kititem].subpars=new SUBnoteParameters(); + if (kit[kititem].padpars==NULL) kit[kititem].padpars=new PADnoteParameters(fft,master); + }; + + if (resetallnotes) for (int k=0;k<POLIPHONY;k++) KillNotePos(k); +}; + + + +void Part::add2XMLinstrument(XMLwrapper *xml){ + xml->beginbranch("INFO"); + xml->addparstr("name",(char *)Pname); + xml->addparstr("author",(char *)info.Pauthor); + xml->addparstr("comments",(char *)info.Pcomments); + xml->addpar("type",info.Ptype); + xml->endbranch(); + + + xml->beginbranch("INSTRUMENT_KIT"); + xml->addpar("kit_mode",Pkitmode); + xml->addparbool("drum_mode",Pdrummode); + + for (int i=0;i<NUM_KIT_ITEMS;i++){ + xml->beginbranch("INSTRUMENT_KIT_ITEM",i); + xml->addparbool("enabled",kit[i].Penabled); + if (kit[i].Penabled!=0) { + xml->addparstr("name",(char *)kit[i].Pname); + + xml->addparbool("muted",kit[i].Pmuted); + xml->addpar("min_key",kit[i].Pminkey); + xml->addpar("max_key",kit[i].Pmaxkey); + + xml->addpar("send_to_instrument_effect",kit[i].Psendtoparteffect); + + xml->addparbool("add_enabled",kit[i].Padenabled); + if ((kit[i].Padenabled!=0)&&(kit[i].adpars!=NULL)){ + xml->beginbranch("ADD_SYNTH_PARAMETERS"); + kit[i].adpars->add2XML(xml); + xml->endbranch(); + }; + + xml->addparbool("sub_enabled",kit[i].Psubenabled); + if ((kit[i].Psubenabled!=0)&&(kit[i].subpars!=NULL)){ + xml->beginbranch("SUB_SYNTH_PARAMETERS"); + kit[i].subpars->add2XML(xml); + xml->endbranch(); + }; + + xml->addparbool("pad_enabled",kit[i].Ppadenabled); + if ((kit[i].Ppadenabled!=0)&&(kit[i].padpars!=NULL)){ + xml->beginbranch("PAD_SYNTH_PARAMETERS"); + kit[i].padpars->add2XML(xml); + xml->endbranch(); + }; + + }; + xml->endbranch(); + }; + xml->endbranch(); + + xml->beginbranch("INSTRUMENT_EFFECTS"); + for (int nefx=0;nefx<NUM_PART_EFX;nefx++){ + xml->beginbranch("INSTRUMENT_EFFECT",nefx); + xml->beginbranch("EFFECT"); + partefx[nefx]->add2XML(xml); + xml->endbranch(); + + xml->addpar("route",Pefxroute[nefx]); + partefx[nefx]->setdryonly(Pefxroute[nefx]==2); + xml->addparbool("bypass",Pefxbypass[nefx]); + xml->endbranch(); + }; + xml->endbranch(); +}; + + +void Part::add2XML(XMLwrapper *xml){ + //parameters + xml->addparbool("enabled",Penabled); + if ((Penabled==0)&&(xml->minimal)) return; + + xml->addpar("volume",Pvolume); + xml->addpar("panning",Ppanning); + + xml->addpar("min_key",Pminkey); + xml->addpar("max_key",Pmaxkey); + xml->addpar("key_shift",Pkeyshift); + xml->addpar("rcv_chn",Prcvchn); + + xml->addpar("velocity_sensing",Pvelsns); + xml->addpar("velocity_offset",Pveloffs); + + xml->addparbool("note_on",Pnoteon); + xml->addparbool("poly_mode",Ppolymode); + xml->addpar("key_limit",Pkeylimit); + + xml->beginbranch("INSTRUMENT"); + add2XMLinstrument(xml); + xml->endbranch(); + + xml->beginbranch("CONTROLLER"); + ctl.add2XML(xml); + xml->endbranch(); +}; + +int Part::saveXML(char *filename){ + XMLwrapper *xml; + xml=new XMLwrapper(); + + xml->beginbranch("INSTRUMENT"); + add2XMLinstrument(xml); + xml->endbranch(); + + int result=xml->saveXMLfile(filename); + delete (xml); + return(result); +}; + +int Part::loadXMLinstrument(const char *filename){ + XMLwrapper *xml=new XMLwrapper(); + if (xml->loadXMLfile(filename)<0) { + delete(xml); + return(-1); + }; + + if (xml->enterbranch("INSTRUMENT")==0) return(-10); + getfromXMLinstrument(xml); + xml->exitbranch(); + + delete(xml); + return(0); +}; + + +void Part::applyparameters(){ + for (int n=0;n<NUM_KIT_ITEMS;n++){ + if ((kit[n].padpars!=NULL)&&(kit[n].Ppadenabled!=0)) kit[n].padpars->applyparameters(true); + }; +}; + +void Part::getfromXMLinstrument(XMLwrapper *xml){ + if (xml->enterbranch("INFO")){ + xml->getparstr("name",(char *)Pname,PART_MAX_NAME_LEN); + xml->getparstr("author",(char *)info.Pauthor,MAX_INFO_TEXT_SIZE); + xml->getparstr("comments",(char *)info.Pcomments,MAX_INFO_TEXT_SIZE); + info.Ptype=xml->getpar("type",info.Ptype,0,16); + + xml->exitbranch(); + }; + + if (xml->enterbranch("INSTRUMENT_KIT")){ + Pkitmode=xml->getpar127("kit_mode",Pkitmode); + Pdrummode=xml->getparbool("drum_mode",Pdrummode); + + setkititemstatus(0,0); + for (int i=0;i<NUM_KIT_ITEMS;i++){ + if (xml->enterbranch("INSTRUMENT_KIT_ITEM",i)==0) continue; + setkititemstatus(i,xml->getparbool("enabled",kit[i].Penabled)); + if (kit[i].Penabled==0) { + xml->exitbranch(); + continue; + }; + + xml->getparstr("name",(char *)kit[i].Pname,PART_MAX_NAME_LEN); + + kit[i].Pmuted=xml->getparbool("muted",kit[i].Pmuted); + kit[i].Pminkey=xml->getpar127("min_key",kit[i].Pminkey); + kit[i].Pmaxkey=xml->getpar127("max_key",kit[i].Pmaxkey); + + kit[i].Psendtoparteffect=xml->getpar127("send_to_instrument_effect",kit[i].Psendtoparteffect); + + kit[i].Padenabled=xml->getparbool("add_enabled",kit[i].Padenabled); + if (xml->enterbranch("ADD_SYNTH_PARAMETERS")){ + kit[i].adpars->getfromXML(xml); + xml->exitbranch(); + }; + + kit[i].Psubenabled=xml->getparbool("sub_enabled",kit[i].Psubenabled); + if (xml->enterbranch("SUB_SYNTH_PARAMETERS")){ + kit[i].subpars->getfromXML(xml); + xml->exitbranch(); + }; + + kit[i].Ppadenabled=xml->getparbool("pad_enabled",kit[i].Ppadenabled); + if (xml->enterbranch("PAD_SYNTH_PARAMETERS")){ + kit[i].padpars->getfromXML(xml); + xml->exitbranch(); + }; + + xml->exitbranch(); + }; + + xml->exitbranch(); + }; + + + if (xml->enterbranch("INSTRUMENT_EFFECTS")){ + for (int nefx=0;nefx<NUM_PART_EFX;nefx++){ + if (xml->enterbranch("INSTRUMENT_EFFECT",nefx)==0) continue; + if (xml->enterbranch("EFFECT")){ + partefx[nefx]->getfromXML(xml); + xml->exitbranch(); + }; + + Pefxroute[nefx]=xml->getpar("route",Pefxroute[nefx],0,NUM_PART_EFX); + partefx[nefx]->setdryonly(Pefxroute[nefx]==2); + Pefxbypass[nefx]=xml->getparbool("bypass",Pefxbypass[nefx]); + xml->exitbranch(); + }; + xml->exitbranch(); + }; + +}; + +void Part::getfromXML(XMLwrapper *xml){ + Penabled=xml->getparbool("enabled",Penabled); + + setPvolume(xml->getpar127("volume",Pvolume)); + setPpanning(xml->getpar127("panning",Ppanning)); + + Pminkey=xml->getpar127("min_key",Pminkey); + Pmaxkey=xml->getpar127("max_key",Pmaxkey); + Pkeyshift=xml->getpar127("key_shift",Pkeyshift); + Prcvchn=xml->getpar127("rcv_chn",Prcvchn); + + Pvelsns=xml->getpar127("velocity_sensing",Pvelsns); + Pveloffs=xml->getpar127("velocity_offset",Pveloffs); + + Pnoteon=xml->getparbool("note_on",Pnoteon); + Ppolymode=xml->getparbool("poly_mode",Ppolymode); + Pkeylimit=xml->getpar127("key_limit",Pkeylimit); + + + if (xml->enterbranch("INSTRUMENT")){ + getfromXMLinstrument(xml); + xml->exitbranch(); + }; + + if (xml->enterbranch("CONTROLLER")){ + ctl.getfromXML(xml); + xml->exitbranch(); + }; + +}; + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.h new file mode 100644 index 00000000..28ea9816 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Part.h @@ -0,0 +1,176 @@ +/* + ZynAddSubFX - a software synthesizer + + Part.h - Part implementation + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef PART_H +#define PART_H + +#define MAX_INFO_TEXT_SIZE 1000 + +#include "../globals.h" +#include "../Params/ADnoteParameters.h" +#include "../Params/SUBnoteParameters.h" +#include "../Params/PADnoteParameters.h" +#include "../Synth/ADnote.h" +#include "../Synth/SUBnote.h" +#include "../Synth/PADnote.h" +#include "../Params/Controller.h" +#include "../Misc/Microtonal.h" +#include "../DSP/FFTwrapper.h" +#include "../Effects/EffectMgr.h" +#include "XMLwrapper.h" + +class Master; + +class Part{ + + public: + Part(Microtonal *microtonal_,FFTwrapper *fft_, Master* master); + ~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 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 + + + Master* master; + + int lastnote; + + private: + void KillNotePos(int pos); + void RelaseNotePos(int pos); + 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; + }; + + 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/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.C new file mode 100644 index 00000000..74619731 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.C @@ -0,0 +1,112 @@ +/* + ZynAddSubFX - a software synthesizer + + Util.C - Miscellaneous functions + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 "Util.h" +#include <math.h> +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +int SAMPLE_RATE=44100; +int SOUND_BUFFER_SIZE=256; +int OSCIL_SIZE=512; + +Config config; +REALTYPE *denormalkillbuf; + + +/* + * Transform the velocity according the scaling parameter (velocity sensing) + */ +REALTYPE VelF(REALTYPE velocity,unsigned char scaling){ + REALTYPE x; + x=pow(VELOCITY_MAX_SCALE,(64.0-scaling)/64.0); + if ((scaling==127)||(velocity>0.99)) return(1.0); + else return(pow(velocity,x)); +}; + +/* + * Get the detune in cents + */ +REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune){ + REALTYPE det=0.0,octdet=0.0,cdet=0.0,findet=0.0; + //Get Octave + int octave=coarsedetune/1024; + if (octave>=8) octave-=16; + octdet=octave*1200.0; + + //Coarse and fine detune + int cdetune=coarsedetune%1024; + if (cdetune>512) cdetune-=1024; + + int fdetune=finedetune-8192; + + switch (type){ +// case 1: is used for the default (see below) + case 2: cdet=fabs(cdetune*10.0); + findet=fabs(fdetune/8192.0)*10.0; + break; + case 3: cdet=fabs(cdetune*100); + findet=pow(10,fabs(fdetune/8192.0)*3.0)/10.0-0.1; + break; + case 4: cdet=fabs(cdetune*701.95500087);//perfect fifth + findet=(pow(2,fabs(fdetune/8192.0)*12.0)-1.0)/4095*1200; + break; + //case ...: need to update N_DETUNE_TYPES, if you'll add more + default:cdet=fabs(cdetune*50.0); + findet=fabs(fdetune/8192.0)*35.0;//almost like "Paul's Sound Designer 2" + break; + }; + if (finedetune<8192) findet=-findet; + if (cdetune<0) cdet=-cdet; + + det=octdet+cdet+findet; + return(det); +}; + + +bool fileexists(char *filename){ + struct stat tmp; + int result=stat(filename,&tmp); + if (result>=0) return(true); + + return(false); +}; + +void newFFTFREQS(FFTFREQS *f,int size){ + f->c=new REALTYPE[size]; + f->s=new REALTYPE[size]; + for (int i=0;i<size;i++){ + f->c[i]=0.0;f->s[i]=0.0; + }; +}; +void deleteFFTFREQS(FFTFREQS *f){ + delete[] f->c; + delete[] f->s; + f->c=f->s=NULL; +}; + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.h new file mode 100644 index 00000000..c5b39476 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Util.h @@ -0,0 +1,45 @@ +/* + ZynAddSubFX - a software synthesizer + + Util.h - Miscellaneous functions + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 + +*/ + +#ifndef UTIL_H +#define UTIL_H + +#include <pthread.h> +#include "../globals.h" +#include "Microtonal.h" +#include "../DSP/FFTwrapper.h" +#include "Config.h" + +//Velocity Sensing function +extern REALTYPE VelF(REALTYPE velocity,unsigned char scaling); + +bool fileexists(char *filename); + +#define N_DETUNE_TYPES 4 //the number of detune types +extern REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune); + +extern REALTYPE *denormalkillbuf;//the buffer to add noise in order to avoid denormalisation + +extern Config config; + +#endif + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.C new file mode 100644 index 00000000..0f35faf2 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.C @@ -0,0 +1,533 @@ +/* + ZynAddSubFX - a software synthesizer + + XMLwrapper.C - XML wrapper + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 "XMLwrapper.h" +#include <stdio.h> +#include <stdlib.h> +#include <zlib.h> + +#include "../globals.h" +#include "Util.h" + +int xml_k=0; +char tabs[STACKSIZE+2]; + +const char *XMLwrapper_whitespace_callback(mxml_node_t *node,int where){ + const char *name=node->value.element.name; + + if ((where==MXML_WS_BEFORE_OPEN)&&(!strcmp(name,"?xml"))) return(NULL); + if ((where==MXML_WS_BEFORE_CLOSE)&&(!strcmp(name,"string"))) return(NULL); + + if ((where==MXML_WS_BEFORE_OPEN)||(where==MXML_WS_BEFORE_CLOSE)) { +/* const char *tmp=node->value.element.name; + if (tmp!=NULL) { + if ((strstr(tmp,"par")!=tmp)&&(strstr(tmp,"string")!=tmp)) { + printf("%s ",tmp); + if (where==MXML_WS_BEFORE_OPEN) xml_k++; + if (where==MXML_WS_BEFORE_CLOSE) xml_k--; + if (xml_k>=STACKSIZE) xml_k=STACKSIZE-1; + if (xml_k<0) xml_k=0; + printf("%d\n",xml_k); + printf("\n"); + }; + + }; + int i=0; + for (i=1;i<xml_k;i++) tabs[i]='\t'; + tabs[0]='\n';tabs[i+1]='\0'; + if (where==MXML_WS_BEFORE_OPEN) return(tabs); + else return("\n"); +*/ + return("\n"); + }; + + return(0); +}; + + +XMLwrapper::XMLwrapper(){ + ZERO(&parentstack,(int)sizeof(parentstack)); + ZERO(&values,(int)sizeof(values)); + + minimal=true; + stackpos=0; + + information.PADsynth_used=false; + + tree=mxmlNewElement(MXML_NO_PARENT,"?xml version=\"1.0\" encoding=\"UTF-8\"?"); +/* for mxml 2.1 (and older) + tree=mxmlNewElement(MXML_NO_PARENT,"?xml"); + mxmlElementSetAttr(tree,"version","1.0"); + mxmlElementSetAttr(tree,"encoding","UTF-8"); +*/ + + mxml_node_t *doctype=mxmlNewElement(tree,"!DOCTYPE"); + mxmlElementSetAttr(doctype,"ZynAddSubFX-data",NULL); + + node=root=mxmlNewElement(tree,"ZynAddSubFX-data"); + + mxmlElementSetAttr(root,"version-major","1"); + mxmlElementSetAttr(root,"version-minor","1"); + mxmlElementSetAttr(root,"ZynAddSubFX-author","Nasca Octavian Paul"); + + //make the empty branch that will contain the information parameters + info=addparams0("INFORMATION"); + + //save zynaddsubfx specifications + beginbranch("BASE_PARAMETERS"); + addpar("max_midi_parts",NUM_MIDI_PARTS); + addpar("max_kit_items_per_instrument",NUM_KIT_ITEMS); + + addpar("max_system_effects",NUM_SYS_EFX); + addpar("max_insertion_effects",NUM_INS_EFX); + addpar("max_instrument_effects",NUM_PART_EFX); + + addpar("max_addsynth_voices",NUM_VOICES); + endbranch(); + +}; + +XMLwrapper::~XMLwrapper(){ + if (tree!=NULL) mxmlDelete(tree); +}; + +bool XMLwrapper::checkfileinformation(char *filename){ + stackpos=0; + ZERO(&parentstack,(int)sizeof(parentstack)); + information.PADsynth_used=false; + + if (tree!=NULL) mxmlDelete(tree);tree=NULL; + char *xmldata=doloadfile(filename); + if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed + + + char *start=strstr(xmldata,"<INFORMATION>"); + char *end=strstr(xmldata,"</INFORMATION>"); + + if ((start==NULL)||(end==NULL)||(start>end)) { + delete(xmldata); + return(false); + }; + end+=strlen("</INFORMATION>"); + end[0]='\0'; + + tree=mxmlNewElement(MXML_NO_PARENT,"?xml"); + node=root=mxmlLoadString(tree,xmldata,MXML_OPAQUE_CALLBACK); + if (root==NULL) { + delete(xmldata); + mxmlDelete(tree); + node=root=tree=NULL; + return(false); + }; + + root=mxmlFindElement(tree,tree,"INFORMATION",NULL,NULL,MXML_DESCEND); + push(root); + + if (root==NULL){ + delete(xmldata); + mxmlDelete(tree); + node=root=tree=NULL; + return(false); + }; + + information.PADsynth_used=getparbool("PADsynth_used",false); + + exitbranch(); + if (tree!=NULL) mxmlDelete(tree); + delete(xmldata); + node=root=tree=NULL; + + return(true); +}; + + +/* SAVE XML members */ + +int XMLwrapper::saveXMLfile(char *filename){ + char *xmldata=getXMLdata(); + if (xmldata==NULL) return(-2); + + int compression=config.cfg.GzipCompression; + + int fnsize=strlen(filename)+100; + char *filenamenew=new char [fnsize]; + snprintf(filenamenew,fnsize,"%s",filename); + + int result=dosavefile(filenamenew,compression,xmldata); + + delete(filenamenew); + delete(xmldata); + return(result); +}; + +char *XMLwrapper::getXMLdata(){ + xml_k=0; + ZERO(tabs,STACKSIZE+2); + + mxml_node_t *oldnode=node; + + node=info; + //Info storing + addparbool("PADsynth_used",information.PADsynth_used); + + node=oldnode; + char *xmldata=mxmlSaveAllocString(tree,XMLwrapper_whitespace_callback); + + return(xmldata); +}; + + +int XMLwrapper::dosavefile(char *filename,int compression,char *xmldata){ + if (compression==0){ + FILE *file; + file=fopen(filename,"w"); + if (file==NULL) return(-1); + fputs(xmldata,file); + fclose(file); + } else { + if (compression>9) compression=9; + if (compression<1) compression=1; + char options[10]; + snprintf(options,10,"wb%d",compression); + + gzFile gzfile; + gzfile=gzopen(filename,options); + if (gzfile==NULL) return(-1); + gzputs(gzfile,xmldata); + gzclose(gzfile); + }; + + return(0); +}; + + + +void XMLwrapper::addpar(char *name,int val){ + addparams2("par","name",name,"value",int2str(val)); +}; + +void XMLwrapper::addparreal(char *name,REALTYPE val){ + addparams2("par_real","name",name,"value",real2str(val)); +}; + +void XMLwrapper::addparbool(char *name,int val){ + if (val!=0) addparams2("par_bool","name",name,"value","yes"); + else addparams2("par_bool","name",name,"value","no"); +}; + +void XMLwrapper::addparstr(char *name,char *val){ + mxml_node_t *element=mxmlNewElement(node,"string"); + mxmlElementSetAttr(element,"name",name); + mxmlNewText(element,0,val); +}; + + +void XMLwrapper::beginbranch(char *name){ + push(node); + node=addparams0(name); +}; + +void XMLwrapper::beginbranch(char *name,int id){ + push(node); + node=addparams1(name,"id",int2str(id)); +}; + +void XMLwrapper::endbranch(){ + node=pop(); +}; + + + +/* LOAD XML members */ + +int XMLwrapper::loadXMLfile(const char *filename){ + if (tree!=NULL) mxmlDelete(tree); + tree=NULL; + + ZERO(&parentstack,(int)sizeof(parentstack)); + ZERO(&values,(int)sizeof(values)); + + stackpos=0; + + char *xmldata=doloadfile(filename); + if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed + + root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK); + + delete(xmldata); + + if (tree==NULL) return(-2);//this is not XML + + + node=root=mxmlFindElement(tree,tree,"ZynAddSubFX-data",NULL,NULL,MXML_DESCEND); + if (root==NULL) return(-3);//the XML doesnt embbed zynaddsubfx data + push(root); + + values.xml_version.major=str2int(mxmlElementGetAttr(root,"version-major")); + values.xml_version.minor=str2int(mxmlElementGetAttr(root,"version-minor")); + + return(0); +}; + + +char *XMLwrapper::doloadfile(const char *filename){ + char *xmldata=NULL; + int filesize=-1; + + //try get filesize as gzip data (first) + gzFile gzfile=gzopen(filename,"rb"); + if (gzfile!=NULL){//this is a gzip file + // first check it's size + while(!gzeof(gzfile)) { + gzseek (gzfile,1024*1024,SEEK_CUR); + if (gztell(gzfile)>10000000) { + gzclose(gzfile); + goto notgzip;//the file is too big + }; + }; + filesize=gztell(gzfile); + + //rewind the file and load the data + xmldata=new char[filesize+1]; + ZERO(xmldata,filesize+1); + + gzrewind(gzfile); + gzread(gzfile,xmldata,filesize); + + gzclose(gzfile); + return (xmldata); + } else {//this is not a gzip file + notgzip: + FILE *file=fopen(filename,"rb"); + if (file==NULL) return(NULL); + fseek(file,0,SEEK_END); + filesize=ftell(file); + + xmldata=new char [filesize+1]; + ZERO(xmldata,filesize+1); + + rewind(file); + fread(xmldata,filesize,1,file); + + fclose(file); + return(xmldata); + }; +}; + +bool XMLwrapper::putXMLdata(char *xmldata){ + if (tree!=NULL) mxmlDelete(tree); + tree=NULL; + + ZERO(&parentstack,(int)sizeof(parentstack)); + ZERO(&values,(int)sizeof(values)); + + stackpos=0; + + if (xmldata==NULL) return (false); + + root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK); + + if (tree==NULL) return(false); + + node=root=mxmlFindElement(tree,tree,"ZynAddSubFX-data",NULL,NULL,MXML_DESCEND); + if (root==NULL) return (false);; + push(root); + + return(true); +}; + + + +int XMLwrapper::enterbranch(char *name){ + node=mxmlFindElement(peek(),peek(),name,NULL,NULL,MXML_DESCEND_FIRST); + if (node==NULL) return(0); + + push(node); + return(1); +}; + +int XMLwrapper::enterbranch(char *name,int id){ + snprintf(tmpstr,TMPSTR_SIZE,"%d",id); + node=mxmlFindElement(peek(),peek(),name,"id",tmpstr,MXML_DESCEND_FIRST); + if (node==NULL) return(0); + + push(node); + return(1); +}; + + +void XMLwrapper::exitbranch(){ + pop(); +}; + + +int XMLwrapper::getbranchid(int min, int max){ + int id=str2int(mxmlElementGetAttr(node,"id")); + if ((min==0)&&(max==0)) return(id); + + if (id<min) id=min; + else if (id>max) id=max; + + return(id); +}; + +int XMLwrapper::getpar(char *name,int defaultpar,int min,int max){ + node=mxmlFindElement(peek(),peek(),"par","name",name,MXML_DESCEND_FIRST); + if (node==NULL) return(defaultpar); + + const char *strval=mxmlElementGetAttr(node,"value"); + if (strval==NULL) return(defaultpar); + + int val=str2int(strval); + if (val<min) val=min; + else if (val>max) val=max; + + return(val); +}; + +int XMLwrapper::getpar127(char *name,int defaultpar){ + return(getpar(name,defaultpar,0,127)); +}; + +int XMLwrapper::getparbool(char *name,int defaultpar){ + node=mxmlFindElement(peek(),peek(),"par_bool","name",name,MXML_DESCEND_FIRST); + if (node==NULL) return(defaultpar); + + const char *strval=mxmlElementGetAttr(node,"value"); + if (strval==NULL) return(defaultpar); + + if ((strval[0]=='Y')||(strval[0]=='y')) return(1); + else return(0); +}; + +void XMLwrapper::getparstr(char *name,char *par,int maxstrlen){ + ZERO(par,maxstrlen); + node=mxmlFindElement(peek(),peek(),"string","name",name,MXML_DESCEND_FIRST); + + if (node==NULL) return; + if (node->child==NULL) return; + if (node->child->type!=MXML_OPAQUE) return; + + snprintf(par,maxstrlen,"%s",node->child->value.element.name); + +}; + +REALTYPE XMLwrapper::getparreal(char *name,REALTYPE defaultpar){ + node=mxmlFindElement(peek(),peek(),"par_real","name",name,MXML_DESCEND_FIRST); + if (node==NULL) return(defaultpar); + + const char *strval=mxmlElementGetAttr(node,"value"); + if (strval==NULL) return(defaultpar); + + return(str2real(strval)); +}; + +REALTYPE XMLwrapper::getparreal(char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max){ + REALTYPE result=getparreal(name,defaultpar); + + if (result<min) result=min; + else if (result>max) result=max; + return(result); +}; + + +/** Private members **/ + +char *XMLwrapper::int2str(int x){ + snprintf(tmpstr,TMPSTR_SIZE,"%d",x); + return(tmpstr); +}; + +char *XMLwrapper::real2str(REALTYPE x){ + snprintf(tmpstr,TMPSTR_SIZE,"%g",x); + return(tmpstr); +}; + +int XMLwrapper::str2int(const char *str){ + if (str==NULL) return(0); + int result=strtol(str,NULL,10); + return(result); +}; + +REALTYPE XMLwrapper::str2real(const char *str){ + if (str==NULL) return(0.0); + REALTYPE result=strtod(str,NULL); + return(result); +}; + + +mxml_node_t *XMLwrapper::addparams0(char *name){ + mxml_node_t *element=mxmlNewElement(node,name); + return(element); +}; + +mxml_node_t *XMLwrapper::addparams1(char *name,char *par1,char *val1){ + mxml_node_t *element=mxmlNewElement(node,name); + mxmlElementSetAttr(element,par1,val1); + return(element); +}; + +mxml_node_t *XMLwrapper::addparams2(char *name,char *par1,char *val1,char *par2, char *val2){ + mxml_node_t *element=mxmlNewElement(node,name); + mxmlElementSetAttr(element,par1,val1); + mxmlElementSetAttr(element,par2,val2); + return(element); +}; + + + + +void XMLwrapper::push(mxml_node_t *node){ + if (stackpos>=STACKSIZE-1) { + printf("BUG!: XMLwrapper::push() - full parentstack\n"); + return; + }; + stackpos++; + parentstack[stackpos]=node; + +// printf("push %d - %s\n",stackpos,node->value.element.name); + +}; +mxml_node_t *XMLwrapper::pop(){ + if (stackpos<=0) { + printf("BUG!: XMLwrapper::pop() - empty parentstack\n"); + return (root); + }; + mxml_node_t *node=parentstack[stackpos]; + parentstack[stackpos]=NULL; + +// printf("pop %d - %s\n",stackpos,node->value.element.name); + + stackpos--; + return(node); +}; + +mxml_node_t *XMLwrapper::peek(){ + if (stackpos<=0) { + printf("BUG!: XMLwrapper::peek() - empty parentstack\n"); + return (root); + }; + return(parentstack[stackpos]); +}; + + + diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.h b/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.h new file mode 100644 index 00000000..765622a2 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/XMLwrapper.h @@ -0,0 +1,175 @@ +/* + ZynAddSubFX - a software synthesizer + + XML.h - XML wrapper + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + 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) 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 <mxml.h> +#ifndef REALTYPE +#define REALTYPE float +#endif + +#ifndef XML_WRAPPER_H +#define XML_WRAPPER_H + +#define TMPSTR_SIZE 50 + +//the maxim tree depth +#define STACKSIZE 100 + +class XMLwrapper{ + public: + XMLwrapper(); + ~XMLwrapper(); + + /********************************/ + /* SAVE to XML */ + /********************************/ + + //returns 0 if ok or -1 if the file cannot be saved + int saveXMLfile(char *filename); + + //returns the new allocated string that contains the XML data (used for clipboard) + //the string is NULL terminated + char *getXMLdata(); + + //add simple parameter (name and value) + void addpar(char *name,int val); + void addparreal(char *name,REALTYPE val); + + //add boolean parameter (name and boolean value) + //if the value is 0 => "yes", else "no" + void addparbool(char *name,int val); + + //add string parameter (name and string) + void addparstr(char *name,char *val); + + //add a branch + void beginbranch(char *name); + void beginbranch(char *name, int id); + + //this must be called after each branch (nodes that contains child nodes) + void endbranch(); + + /********************************/ + /* LOAD from XML */ + /********************************/ + + //returns 0 if ok or -1 if the file cannot be loaded + int loadXMLfile(const char *filename); + + //used by the clipboard + bool putXMLdata(char *xmldata); + + //enter into the branch + //returns 1 if is ok, or 0 otherwise + int enterbranch(char *name); + + + //enter into the branch with id + //returns 1 if is ok, or 0 otherwise + int enterbranch(char *name, int id); + + //exits from a branch + void exitbranch(); + + //get the the branch_id and limits it between the min and max + //if min==max==0, it will not limit it + //if there isn't any id, will return min + //this must be called only imediately after enterbranch() + int getbranchid(int min, int max); + + //it returns the parameter and limits it between min and max + //if min==max==0, it will not limit it + //if no parameter will be here, the defaultpar will be returned + int getpar(char *name,int defaultpar,int min,int max); + + //the same as getpar, but the limits are 0 and 127 + int getpar127(char *name,int defaultpar); + + int getparbool(char *name,int defaultpar); + + void getparstr(char *name,char *par,int maxstrlen); + REALTYPE getparreal(char *name,REALTYPE defaultpar); + REALTYPE getparreal(char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max); + + bool minimal;//false if all parameters will be stored (used only for clipboard) + + struct { + bool PADsynth_used; + }information; + + //opens a file and parse only the "information" data on it + //returns "true" if all went ok or "false" on errors + bool checkfileinformation(char *filename); + + private: + + int dosavefile(char *filename,int compression,char *xmldata); + char *doloadfile(const char *filename); + + + mxml_node_t *tree;//all xml data + mxml_node_t *root;//xml data used by zynaddsubfx + mxml_node_t *node;//current node + mxml_node_t *info;//this node is used to store the information about the data + + //adds params like this: + // <name> + //returns the node + mxml_node_t *addparams0(char *name); + + //adds params like this: + // <name par1="val1"> + //returns the node + mxml_node_t *addparams1(char *name,char *par1,char *val1); + + //adds params like this: + // <name par1="val1" par2="val2"> + //returns the node + mxml_node_t *addparams2(char *name,char *par1,char *val1,char *par2, char *val2); + + char *int2str(int x); + char *real2str(REALTYPE x); + + int str2int(const char *str); + REALTYPE str2real(const char *str); + + char tmpstr[TMPSTR_SIZE]; + + + //this is used to store the parents + mxml_node_t *parentstack[STACKSIZE]; + int stackpos; + + + void push(mxml_node_t *node); + mxml_node_t *pop(); + mxml_node_t *peek(); + + //theese are used to store the values + struct{ + struct { + int major,minor; + }xml_version; + }values; + +}; + +#endif |