summaryrefslogtreecommitdiff
path: root/note_compiler/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'note_compiler/parser.cpp')
-rw-r--r--note_compiler/parser.cpp504
1 files changed, 504 insertions, 0 deletions
diff --git a/note_compiler/parser.cpp b/note_compiler/parser.cpp
new file mode 100644
index 0000000..c89ddd9
--- /dev/null
+++ b/note_compiler/parser.cpp
@@ -0,0 +1,504 @@
+#include <cstdlib>
+#include <fstream>
+
+#include "parser.h"
+#include "programs.h"
+#include "util.h"
+#include "../synth/defines.h"
+#include "../synth/fixed.h"
+
+
+void init_oscs(int n_osc, oscillator_t *osc)
+{
+ for (int i=0;i<n_osc;i++)
+ {
+ osc[i].n_osc=n_osc;
+
+ osc[i].fm_strength=new fixed_t[n_osc];
+ osc[i].fm_strength_const=new bool[n_osc];
+ for (int j=0;j<n_osc;j++)
+ {
+ osc[i].fm_strength[j]=0;
+ osc[i].fm_strength_const[j]=true;
+ }
+
+ osc[i].output=0;
+ osc[i].output_const=true;
+ osc[i].output_no_pfactor=false;
+ osc[i].waveform=0;
+ osc[i].waveform_const=true;
+ osc[i].factor=ONE;
+ osc[i].factor_const=true;
+ osc[i].tremolo_depth=0;
+ osc[i].tremolo_depth_const=true;
+ osc[i].tremolo_lfo=0;
+ osc[i].tremolo_lfo_const=true;
+ osc[i].vibrato_depth=0;
+ osc[i].vibrato_depth_const=true;
+ osc[i].vibrato_lfo=0;
+ osc[i].vibrato_lfo_const=true;
+ osc[i].have_custom_wave=false;
+ osc[i].sync=false;
+ osc[i].sync_const=true;
+ osc[i].ksr_const=true;
+ osc[i].ksl_const=true;
+ }
+}
+
+void init_envs(int n_osc, env_settings_t *env)
+{
+ for (int i=0;i<n_osc;i++)
+ {
+ env[i].enabled=true;
+ env[i].attack=0;
+ env[i].attack_const=true;
+ env[i].decay=0;
+ env[i].decay_const=true;
+ env[i].sustain=1.0;
+ env[i].sustain_const=true;
+ env[i].release=0;
+ env[i].release_const=true;
+ env[i].hold=true;
+ env[i].hold_const=true;
+ }
+}
+
+void init_filter(filter_params_t &filter)
+{
+ filter.enabled=false;
+ filter.enabled_const=true;
+ filter.env_amount=0;
+ filter.env_amount_const=true;
+ filter.env_settings.attack=0;
+ filter.env_settings.attack_const=true;
+ filter.env_settings.decay=0;
+ filter.env_settings.decay_const=true;
+ filter.env_settings.release=0;
+ filter.env_settings.release_const=true;
+ filter.env_settings.sustain=0;
+ filter.env_settings.sustain_const=true;
+ filter.env_settings.hold=true;
+ filter.env_settings.hold_const=true;
+
+ filter.freqfactor_offset=0;
+ filter.freqfactor_offset_const=true;
+ filter.resonance=0;
+ filter.resonance_const=true;
+ filter.trem_strength=0;
+ filter.trem_strength_const=true;
+ filter.trem_lfo=0;
+ filter.trem_lfo_const=true;
+}
+
+
+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<dim;i++)
+ {
+ p=s.find('[',p+1);
+ if (p==string::npos) return -1;
+ }
+
+ p2=s.find(']',p+1);
+ if (p2==string::npos) return -1;
+
+ return atoi(s.substr(p+1,p2-p-1).c_str());
+}
+
+
+
+program_t parse(string fn)
+{
+ int n_osc=0;
+ oscillator_t *osc=NULL;
+ env_settings_t *env=NULL;
+ filter_params_t filter;
+ fixed_t sync_factor=0;
+ bool sync_factor_const=true;
+
+ char buf[2000];
+ string line;
+ string var;
+ string array;
+ string strval;
+ float val;
+
+ parameter_enum p;
+
+ int ind,ind2=0;
+
+ int state;
+
+ program_t result;
+
+
+ ifstream f;
+ f.open(fn.c_str());
+ if (f.good())
+ {
+ 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;
+ }
+ else if (line=="variable:")
+ {
+ state=5;
+ 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);
+
+ 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<n_osc))) )
+ throw string("out of array bounds");
+
+
+ switch (p)
+ {
+ case MODULATION:
+ ind2=extract_array_index(var,2);
+ if (!((ind2>=0) && (ind2<n_osc)))
+ throw string("out of array bounds");
+
+ osc[ind].fm_strength[ind2]=val*ONE;
+ break;
+ case OUTPUT:
+ osc[ind].output=val*ONE;
+ break;
+ case WAVEFORM:
+ if (isfloat(strval))
+ {
+ osc[ind].waveform=int(val);
+ }
+ else
+ {
+ osc[ind].have_custom_wave=true;
+ }
+ break;
+ case FACTOR:
+ osc[ind].factor=val*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;
+ break;
+ case DECAY:
+ env[ind].decay=val;
+ break;
+ case SUSTAIN:
+ env[ind].sustain=val;
+ break;
+ case RELEASE:
+ env[ind].release=val;
+ 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;
+ break;
+ case FILTER_DECAY:
+ filter.env_settings.decay=val;
+ break;
+ case FILTER_SUSTAIN:
+ filter.env_settings.sustain=val;
+ break;
+ case FILTER_RELEASE:
+ filter.env_settings.release=val;
+ 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;
+ default:
+ throw string("unknown variable ('"+array+"')");
+ }
+ break;
+
+ case 5: //read which params shall be variable, even if
+ //there are currently no controllers which change them
+ case 4: //read velocity-influence over certain params
+ 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<n_osc))) )
+ throw string("out of array bounds");
+
+ if (state==4) //velocity-influence
+ {
+ switch (p)
+ {
+ case MODULATION:
+ case OUTPUT:
+ case FILTER_ENV_AMOUNT:
+ case FILTER_RESONANCE:
+ case FILTER_OFFSET:
+ // everything ok, do nothing
+ break;
+
+ default: // other params than the above may not be influenced!
+ throw string("velocity cannot influence parameter '"+array+"'");
+ }
+ }
+
+
+ switch (p)
+ {
+ case MODULATION:
+ ind2=extract_array_index(var,2);
+ if (!((ind2>=0) && (ind2<n_osc)))
+ throw string("out of array bounds");
+
+ osc[ind].fm_strength_const[ind2]=false;
+ break;
+ case OUTPUT:
+ if (state==4) // vel.-influence
+ {
+ if (isfloat(strval)) //is it a plain number, not a formula?
+ osc[ind].output_no_pfactor=true;
+ }
+ else
+ osc[ind].output_const=false; break;
+ case WAVEFORM:
+ osc[ind].waveform_const=false; break;
+ case FACTOR:
+ osc[ind].factor_const=false; break;
+ case TREMOLO:
+ osc[ind].tremolo_depth_const=false; break;
+ case TREM_LFO:
+ osc[ind].tremolo_lfo_const=false; break;
+ case VIBRATO:
+ osc[ind].vibrato_depth_const=false; break;
+ case VIB_LFO:
+ osc[ind].vibrato_lfo_const=false; break;
+ case ATTACK:
+ env[ind].attack_const=false; break;
+ case DECAY:
+ env[ind].decay_const=false; break;
+ case SUSTAIN:
+ env[ind].sustain_const=false; break;
+ case RELEASE:
+ env[ind].release_const=false; break;
+ case HOLD:
+ env[ind].hold_const=false; break;
+ case KSR:
+ osc[ind].ksr_const=false; break;
+ case KSL:
+ osc[ind].ksl_const=false; break;
+ case SYNC:
+ osc[ind].sync_const=false; break;
+ case FILTER_ENABLED:
+ filter.enabled_const=false; break;
+ case FILTER_ENV_AMOUNT:
+ filter.env_amount_const=false; break;
+ case FILTER_ATTACK:
+ filter.env_settings.attack_const=false; break;
+ case FILTER_DECAY:
+ filter.env_settings.decay_const=false; break;
+ case FILTER_SUSTAIN:
+ filter.env_settings.sustain_const=false; break;
+ case FILTER_RELEASE:
+ filter.env_settings.release_const=false; break;
+ case FILTER_HOLD:
+ filter.env_settings.hold_const=false; break;
+ case FILTER_OFFSET:
+ filter.freqfactor_offset_const=false; break;
+ case FILTER_RESONANCE:
+ filter.resonance_const=false; break;
+ case FILTER_TREMOLO:
+ filter.trem_strength_const=false; break;
+ case FILTER_TREM_LFO:
+ filter.trem_lfo_const=false; break;
+ case SYNC_FACTOR:
+ sync_factor_const=false; break;
+ default:
+ throw string("unknown variable ('"+array+"')");
+ }
+
+
+
+ break;
+
+ case 3: //read controller default values
+ //ignored
+ break;
+ }
+ }
+ }
+
+
+ //some optimizations and checks
+
+ for (int i=0;i<n_osc;i++)
+ if ((env[i].attack==0) && (env[i].sustain==1.0)
+ && (env[i].release>100)) //TODO FINDMICH besseres kriterium?
+ env[i].enabled=false;
+
+ if ( ((filter.env_settings.attack==0) && (filter.env_settings.sustain==1.0)
+ && (filter.env_settings.release>100)) //TODO FINDMICH siehe oben
+ || ((filter.env_amount==0) && (filter.env_amount_const==true)) )
+ filter.env_settings.enabled=false;
+
+ bool use_sync=false;
+ for (int i=0;i<n_osc;i++)
+ if ((osc[i].sync==true) || (osc[i].sync_const==false))
+ {
+ use_sync=true;
+ break;
+ }
+
+ if (!use_sync)
+ {
+ sync_factor=0;
+ sync_factor_const=true;
+ }
+
+ if ((sync_factor==0) && (sync_factor_const==true))
+ for (int i=0;i<n_osc;i++)
+ {
+ osc[i].sync=false;
+ osc[i].sync_const=true;
+ }
+
+
+
+ for (int i=0;i<n_osc;i++)
+ if ( (osc[i].output_no_pfactor==false) && !((osc[i].output==0) && (osc[i].output_const=true)) )
+ osc[i].output_const=false;
+
+ //end optimizations and checks
+
+ result.n_osc=n_osc;
+ result.osc=osc;
+ result.env=env;
+ result.filter=filter;
+ result.sync_factor=sync_factor;
+ result.sync_factor_const=sync_factor_const;
+ }
+ else
+ throw string ("could not open '"+fn+"'");
+
+ return result;
+ //no uninit / free of osc and env here, as it must be done by the caller
+}
+
+
+