diff options
| author | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 | 
|---|---|---|
| committer | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 | 
| commit | e40fc849149dd97c248866a4a1d026dda5e57b62 (patch) | |
| tree | b12b358f3b3a0608001d30403358f8443118ec5f /attic/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C | |
| parent | 1bd4f2e8d9745cabb667b043171cad22c8577768 (diff) | |
clean3
Diffstat (limited to 'attic/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C')
| -rw-r--r-- | attic/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C | 514 | 
1 files changed, 514 insertions, 0 deletions
| diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Misc/Microtonal.C new file mode 100644 index 00000000..30a3a71e --- /dev/null +++ b/attic/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); +}; + + | 
