/* Copyright (C) 2010-2012 Florian Jung This file is part of flo's FM synth. flo's FM synth is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. flo's FM synth 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 for more details. You should have received a copy of the GNU General Public License along with flo's FM synth. If not, see . */ #include #include #include #include "parser.h" #include "defines.h" #include "programs.h" #include "globals.h" #include "util.h" #include "readwave.h" string extract_array_name(string s) { size_t p; p=s.find('['); if (p!=string::npos) return s.substr(0,p); else return s; } int extract_array_index(string s, int dim) { size_t p=-1,p2; for (int i=0;i extract_terms(string s) { list result; size_t p=-1,p2; s="+"+s+"+"; p=0; p2=s.find_first_of("+-",p+1); while(p2!=string::npos) { result.push_back(s.substr(p,p2-p)); p=p2; p2=s.find_first_of("+-",p+1); } return result; } list extract_factors(string s) { list result; size_t p=-1,p2; s="*"+s+"*"; p=0; p2=s.find_first_of("*/",p+1); while(p2!=string::npos) { result.push_back(s.substr(p,p2-p)); p=p2; p2=s.find_first_of("*/",p+1); } return result; } list extract_formula(string s) { list result; term_t tmp; list terms=extract_terms(s); for (list::iterator term=terms.begin(); term!=terms.end(); ++term) { list factors=extract_factors(term->substr(1)); double fac= ((*term)[0]=='+') ? 1.0 : -1.0; string cont=""; for (list::iterator factor=factors.begin(); factor!=factors.end(); ++factor) { if (factor->find_first_not_of("0123456789.*/+-")==string::npos) { if ((*factor)[0]=='*') fac*=atof((*factor).substr(1).c_str()); else { if (atof((*factor).substr(1).c_str())==0) throw string("dividing by zero is not allowed"); fac/=atof((*factor).substr(1).c_str()); } } else { if (cont!="") throw string("multiplicating controllers is not allowed"); if ((*factor)[0]!='*') throw string("dividing through a controller is not allowed"); cont=(*factor).substr(1); } } if (cont=="") tmp.c=NO_CONT; else { if (extract_array_name(cont)!="cont") throw string("expected 'cont', found '"+extract_array_name(cont)+"'"); tmp.c=extract_array_index(cont,1); if ((tmp.c<0) || (tmp.c>127)) throw string("invalid controller specified"); } tmp.f=fac*ONE; result.push_back(tmp); } return result; } param_factor_t parse_pfactor(string s) //TODO fast dasselbe wie oben. mergen? { //TODO cont müsste vel heißen FINDMICH ---> ^ ^ ^ param_factor_t result; result.offset=0; result.vel_amount=0; list terms=extract_terms(s); for (list::iterator term=terms.begin(); term!=terms.end(); ++term) { list factors=extract_factors(term->substr(1)); double fac= ((*term)[0]=='+') ? 1.0 : -1.0; string cont=""; for (list::iterator factor=factors.begin(); factor!=factors.end(); ++factor) { if (factor->find_first_not_of("0123456789.*/+-")==string::npos) { if ((*factor)[0]=='*') fac*=atof((*factor).substr(1).c_str()); else { if (atof((*factor).substr(1).c_str())==0) throw string("dividing by zero is not allowed"); fac/=atof((*factor).substr(1).c_str()); } } else { if (cont!="") throw string("multiplicating velocity is not allowed"); if ((*factor)[0]!='*') throw string("dividing through velocity is not allowed"); cont=(*factor).substr(1); } } if (cont=="") { result.offset+= fac*ONE; } else { if (cont!="vel") throw string("expected 'vel', found '"+cont+"'"); result.vel_amount+= fac*ONE; } } return result; } void init_oscs(int n_osc, oscillator_t *osc) { for (int i=0;i affect[128]; map< parameter_t, list > formula; int controller_default[128]; for (int i=0;i<128;++i) controller_default[i]=0; filter_params_t filter; pfactor_formula_t pfactor; fixed_t sync_factor=0; char buf[2000]; list terms; string line; string var; string array; string strval; float val; parameter_enum p; int ind,ind2=0; int state; ifstream f; f.open(fn.c_str()); if (!f.good()) throw string ("could not open '"+fn+"'"); //else state=0; while (!f.eof()) { f.getline(buf,sizeof(buf)/sizeof(*buf)-1); line=buf; line=remove_all_spaces(buf); if ((line!="") && (line[0]!='#')) //ignore comments and empty lines { if (line=="controllers:") { state=2; continue; } else if (line=="defaults:") { state=3; continue; } else if (line=="velocity:") { state=4; continue; } var=extract_var(line); array=extract_array_name(var); strval=extract_val(line); val=atof(strval.c_str()); switch (state) { case 0: //expect and read number of oscillators if (var!="oscillators") throw string("need to know number of oscillators"); else n_osc=val; if (n_osc<=0) throw string("invalid number of oscillators"); //init stuff env=new env_settings_t[n_osc]; osc=new oscillator_t[n_osc]; init_oscs(n_osc,osc); init_envs(n_osc,env); init_filter(filter); init_pfactors(n_osc,pfactor); state=1; break; case 1: //read and set information about oscillator settings p=param_to_enum(array); ind=extract_array_index(var,1); if ( param_needs_index(p) && (!((ind>=0) && (ind=0) && (ind2samp_rate/=given_freq; } break; case FACTOR: osc[ind].factor=pow(2.0,val/12.0) *ONE; break; case TREMOLO: osc[ind].tremolo_depth=int(val); break; case TREM_LFO: if (strval=="snh") osc[ind].tremolo_lfo=SNH_LFO; else { osc[ind].tremolo_lfo= int(val); if ((val<0) || (val>=N_LFOS)) throw string("invalid value for tremolo_lfo"); } break; case VIBRATO: osc[ind].vibrato_depth=val; break; case VIB_LFO: if (strval=="snh") osc[ind].vibrato_lfo= SNH_LFO; else { osc[ind].vibrato_lfo= int(val); if ((val<0) || (val>=N_LFOS)) throw string("invalid value for vibrato_lfo"); } break; case ATTACK: env[ind].attack=val*samp_rate; break; case DECAY: env[ind].decay=val*samp_rate; break; case SUSTAIN: env[ind].sustain=val*ONE; break; case RELEASE: env[ind].release=val*samp_rate; break; case HOLD: env[ind].hold=(val!=0); break; case KSR: osc[ind].ksr=val; break; case KSL: osc[ind].ksl=val; break; case SYNC: osc[ind].sync=(val!=0); break; case FILTER_ENABLED: filter.enabled=(val!=0); break; case FILTER_ENV_AMOUNT: filter.env_amount=val; break; case FILTER_ATTACK: filter.env_settings.attack=val*samp_rate/filter_update_frames; break; case FILTER_DECAY: filter.env_settings.decay=val*samp_rate/filter_update_frames; break; case FILTER_SUSTAIN: filter.env_settings.sustain=val*ONE; break; case FILTER_RELEASE: filter.env_settings.release=val*samp_rate/filter_update_frames; break; case FILTER_HOLD: filter.env_settings.hold=(val!=0); break; case FILTER_OFFSET: filter.freqfactor_offset=val; break; case FILTER_RESONANCE: filter.resonance=val; break; case FILTER_TREMOLO: filter.trem_strength=int(val); break; case FILTER_TREM_LFO: if (strval=="snh") filter.trem_lfo=SNH_LFO; else { filter.trem_lfo=int(val); if ((val<0) || (val>=N_LFOS)) throw string("invalid value for filter_trem_lfo"); } break; case SYNC_FACTOR: sync_factor=val*ONE; break; case FREQ_ATTACK: osc[ind].freq_env.attack=val*samp_rate; break; case FREQ_DECAY: osc[ind].freq_env.decay=val*samp_rate; break; case FREQ_SUSTAIN: osc[ind].freq_env.sustain=val*ONE; break; case FREQ_RELEASE: osc[ind].freq_env.release=val*samp_rate; break; case FREQ_HOLD: osc[ind].freq_env.hold=(val!=0); break; case FREQ_ENV_AMOUNT: osc[ind].freq_env_amount=val; break; default: throw string("unknown variable ('"+array+"')"); } break; case 2: //read how controllers influence parameters p=param_to_enum(array); ind=extract_array_index(var,1); if ( param_needs_index(p) && (!((ind>=0) && (ind=0) && (ind2::iterator it=terms.begin(); it!=terms.end(); ++it) if (it->c!=NO_CONT) affect[it->c].insert(par); formula[par]=terms; break; case 3: //read controller default values if (array=="cont") { ind=extract_array_index(var,1); if ((ind<0) || (ind>127)) throw string("out of array bounds"); if ((val<0) || (val>127)) throw string("value out of range"); controller_default[ind]=val; } else throw string("expected cont, found '"+array+"'"); break; case 4: //read velocity-influence over certain params p=param_to_enum(array); ind=extract_array_index(var,1); if ( param_needs_index(p) && (!((ind>=0) && (ind=0) && (ind2 >::iterator it=formula.begin(); it!=formula.end(); ++it) if ((it->first.par==OUTPUT) && (env[it->first.osc].release<0)) neverending_tone=true; for (int i=0;i