/*
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