diff options
author | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
commit | b703eab295330e6f81564fbb39a10a1a2fdd2f54 (patch) | |
tree | e46b5c9a6bc22fd661c15d1d2123f5bf631cef80 /muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C | |
parent | 5d5fa0fdf913907edbc3d2d29a7548f0cb658c94 (diff) |
moved old qt4 branch
Diffstat (limited to 'muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C')
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C | 514 |
1 files changed, 514 insertions, 0 deletions
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); +}; + + |