From ae8c1183ac4f9a3e3c54ac7fb57fe7d1631d1740 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 1 Jan 2011 17:12:35 +0100 Subject: Replace class Parser with function parse() --- synth/TODO | 32 --- synth/TODO.done | 71 ------ synth/main.cpp | 4 +- synth/parser.cpp | 673 ++++++++++++++++++++++++++++--------------------------- synth/parser.h | 32 +-- 5 files changed, 350 insertions(+), 462 deletions(-) delete mode 100644 synth/TODO delete mode 100644 synth/TODO.done diff --git a/synth/TODO b/synth/TODO deleted file mode 100644 index d507df0..0000000 --- a/synth/TODO +++ /dev/null @@ -1,32 +0,0 @@ -TODO für den synth - o notes compilieren und als .so-datei laden - - o RAM aufräumen? - - o jedes programm eigene LFOs? - o andere wellenformen bei LFOs? - o mehr wellen für wave[] - - o parser: sehr redundante funktionen zusammenführen - o parser: direkt in result schreiben? - - o attack und release ggf. auf niedrigen wert (<=0.01) initen, um - knackser zu vermeiden? - - o chorus, reverb etc. - - o konnte-nicht-verbinden-warnung weniger schlimm machen - - o max_pitchbend per controller setzen? - o nur auf bestimmte channels reagieren - - o diverse pedale (soft, sostenuto, halte, legato (?)) - - (o)programs on-the-fly ändern (n_osc ändern) - (o)lfo-maxima getrennt regeln. nää - (o)bei filter-envelopes: ksr/ksl? nää. - (o)resonanz-tremolo bei tiefpass? nää. - - -TODO fürs CLI - x ... diff --git a/synth/TODO.done b/synth/TODO.done deleted file mode 100644 index 0cd6d16..0000000 --- a/synth/TODO.done +++ /dev/null @@ -1,71 +0,0 @@ -TODO für den synth - x knistern bei aktivem frameskip - x tremolo und vibrato: phase nurnoch ++ - x rettack im monomode abschalten (sondern einfach nur freq ändern) - x bei freqänderung: aufpassen, ob nicht das programm auch geändert - wurde. wenn ja: delete && new - x note-limit - x stereo: pan/balance - x envelopes on-the-fly ändern - x programs laden - x beim note-limit: statt abzuschneiden ausblenden - x einstellmöglichkeiten via MIDI-controller - x grund-controller bearbeiten - x ein port pro channel - x controllern einen defaultwert pro programm mitgeben - x monophoner modus - x reattack - x alwaysreattack setzen können - x portamento testen - x memcheck-clean! - x memcpy durch copy() plus operator= ersetzen? - x pitch-bend - x controller-reset - x key scale level, key scale rate - x akkurates note-on - x frameskip - x globale config-datei, oder alle programs in einem verz. einlesen etc. - x auf dateifehler reagieren! - x sampler-"oscs", d.h. laden von wav-dateien, die sich sonst - wie oscs verhalten (fm möglich usw.) - x analoge synthese auf den output jeder note anwenden - x tiefpass via def.datei setzen: trem, env, res - x tiefpass via controller setzen - x osc-sync - x bei genügend xruns noten töten - x filter knackst - x bei self-mod mit faktor 1 (auch ohne filter): segfault - x bei starken vibratos: segfault, weil fm zu extrem wird - x bei bug.prog: auch ohne filter: knacksen bei den meisten noten (z.B. C) - x per velocity statt lautstärke andere params steuern - x frameskip so implementieren, dass bufsize irrelevant ist - x lfo_update_frames einstellbar machen - sollte durch frameskip dividiert werden - x tremolo- und vibrato-arrays sind mit mehreren MB zu groß! - ein wert pro sample ist unnötig. könnte auch rechenzeit in - calc_foo sparen, da seltener aufgerufen - x sample-and-hold -> fm_strength, -> freq, -> VCF - * bei osc-envelopes ggf. auch nur alle n frames neu setzen? [verschoben] - * filter optimieren? (arbeiten momentan mit floats) [verschoben] - verstehen, optimieren und dann profilen - x stimmt die stereo-implementierung? [ja] - - -TODO fürs CLI - x filter_update_frames, lfo_update_frames in config, in sec (auch im CLI) - x max_port_time einstellen - x manuelle program -> datei - mappings - x automatische mappings ( xxxIGNORIERT.prg, xxx ist die programmnummer), - alle dateien eines verzeichnisses einlesen. bei nichtexistenz - auf normalen sinus zurückfallen - x konfigdateien lesen (inhalt wie CLI-optionen) - x vibrato- und tremolo-frequenzen einstellen - x cleanup-intervall setzen - x space-sicher machen - x fehlerbehandlung: - syntaxfehler sollten übergangen werden, sofern möglich - in parser: throw!, sonst: meckern und nächste zeile parsen - x automatisch an alle midi-outs hängen - x interface div-by-zero-sicher machen - - diff --git a/synth/main.cpp b/synth/main.cpp index deebf06..ae2e0d8 100644 --- a/synth/main.cpp +++ b/synth/main.cpp @@ -95,7 +95,6 @@ int main(int argc, char** argv) lfo[i][j][k]= (1.0 + temp*(float(LFO_MAX)*k/N_LFO_LEVELS)) * ONE; } - Parser parser; program_settings=new program_t[128]; for (i=0;i<128;i++) @@ -104,8 +103,7 @@ int main(int argc, char** argv) { try { - parser.parse(programfile[i]); - program_settings[i]=parser.get_results(); + program_settings[i]=parse(programfile[i]); } catch (string err) { diff --git a/synth/parser.cpp b/synth/parser.cpp index 52717a5..96648d6 100644 --- a/synth/parser.cpp +++ b/synth/parser.cpp @@ -1,3 +1,5 @@ +//uniniten + #include #include @@ -9,21 +11,32 @@ #include "readwave.h" -Parser::Parser() +string extract_array_name(string s) { - n_osc=0; - osc=NULL; - env=NULL; - for (int i=0;i<128;i++) - controller_default[i]=0; + size_t p; + p=s.find('['); + if (p!=string::npos) + return s.substr(0,p); + else + return s; } -Parser::~Parser() +int extract_array_index(string s, int dim) { - uninit_stuff(); + size_t p=-1,p2; + for (int i=0;i Parser::extract_terms(string s) +list extract_terms(string s) { list result; @@ -43,7 +56,7 @@ list Parser::extract_terms(string s) return result; } -list Parser::extract_factors(string s) +list extract_factors(string s) { list result; @@ -63,7 +76,7 @@ list Parser::extract_factors(string s) return result; } -list Parser::extract_formula(string s) +list extract_formula(string s) { list result; term_t tmp; @@ -116,7 +129,7 @@ list Parser::extract_formula(string s) return result; } -param_factor_t Parser::parse_pfactor(string s) //TODO fast dasselbe wie oben. mergen? +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; @@ -169,10 +182,8 @@ param_factor_t Parser::parse_pfactor(string s) //TODO fast dasselbe wie oben. me return result; } -void Parser::init_stuff() +void init_oscs(int n_osc, oscillator_t *osc) { - env=new env_settings_t[n_osc]; - osc=new oscillator_t[n_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; + + + + char buf[2000]; list terms; string line; @@ -299,298 +305,299 @@ void Parser::parse(string fn) int state; - uninit_stuff(); - ifstream f; f.open(fn.c_str()); - if (f.good()) + if (!f.good()) + throw string ("could not open '"+fn+"'"); + //else + + state=0; + while (!f.eof()) { - 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 { - 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:") { - if (line=="controllers:") - { - state=2; - continue; - } - else if (line=="defaults:") - { - state=3; - continue; - } - else if (line=="velocity:") - { - state=4; - continue; - } + 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()); + 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; - 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(); - - 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) && (ind2=0) && (indsamp_rate/=given_freq; + } + 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*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; + 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"); - switch (p) - { - case MODULATION: - ind2=extract_array_index(var,2); - if (!((ind2>=0) && (ind2127)) + throw string("value out of range"); - 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 - { - size_t pos=strval.find(':'); - if (pos==string::npos) - throw string("expected 'freq:file.wav', found no ':'"); - - float given_freq=atof(strval.substr(0,pos).c_str()); - string wavefile=strval.substr(pos+1); - - if (given_freq<=0) - throw string("illegal freq specified for custom wave '"+wavefile+"'"); - - osc[ind].custom_wave=new custom_wave_t; - read_wave(wavefile.c_str(), osc[ind].custom_wave); - osc[ind].custom_wave->samp_rate/=given_freq; - } - 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*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; - 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) && (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); + pfactor.fm[ind][ind2]=parse_pfactor(strval); + break; - if ((ind<0) || (ind>127)) - throw string("out of array bounds"); + case OUTPUT: + pfactor.out[ind]=parse_pfactor(strval); + break; - 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 extract_terms(string s); - static list extract_factors(string s); - static list extract_formula(string s); - static param_factor_t parse_pfactor(string s); - static int extract_array_index(string s, int dim); - - int n_osc; - oscillator_t *osc; - env_settings_t *env; - set affect[128]; - map< parameter_t, list > formula; - int controller_default[128]; - filter_params_t filter; - - pfactor_formula_t pfactor; - - fixed_t sync_factor; -}; - +program_t parse(string fn); #endif -- cgit v1.2.1