diff options
-rw-r--r-- | TODO | 12 | ||||
-rw-r--r-- | note_compiler/main.cpp | 707 | ||||
-rw-r--r-- | note_compiler/note.cpp.todo | 72 | ||||
-rw-r--r-- | note_compiler/parser.cpp | 41 | ||||
-rw-r--r-- | note_compiler/programs.h | 3 | ||||
-rw-r--r-- | note_compiler/templates/ctor.foot | 11 | ||||
-rw-r--r-- | note_compiler/templates/get_sample.1 | 23 | ||||
-rw-r--r-- | note_compiler/templates/head.1 | 35 | ||||
-rw-r--r-- | note_compiler/templates/head.2 | 11 | ||||
-rw-r--r-- | synth/note.cpp | 1 | ||||
-rw-r--r-- | synth/note.h | 7 | ||||
-rw-r--r-- | synth/parser.cpp | 2 |
12 files changed, 907 insertions, 18 deletions
@@ -1,4 +1,16 @@ TODO für den synth +!!!o BUG: bei Note::set_param sollte statt dem eigentlichen param + der orig gesetzt werden und dann neu berechnet werden! +!!!o BUG: bei release und reattack: BEIDE male die filter-envelope beachten! + o KSL mit powf und floats statt mit double umschreiben + o statt lfo-nummer direkten zugriff auf curr_lfo angeben? + o oscval-nullen kann in get_sample() weggelassen werden + o bei tremolo (und vibrato?): eventuell nicht prüfen, obs aktiviert + ist, sondern zur not einfach *1 rechnen? + o in get_sample(), beim aufaddieren zum out (und vmtl auf fm-)wert: + erst nach dem addieren scalen, statt für jeden faktor einzeln + + o filter_envelope könnte mit anderem ctor geinitet werden (weniger schreibarbeit) o notes compilieren und als .so-datei laden o programme on-the-fly (um)laden diff --git a/note_compiler/main.cpp b/note_compiler/main.cpp index cd83eee..7f48c0b 100644 --- a/note_compiler/main.cpp +++ b/note_compiler/main.cpp @@ -1,4 +1,7 @@ +//TODO: auf unbenutzte envelopes achten! + #include <iostream> +#include <fstream> #include "parser.h" #include "programs.h" @@ -7,18 +10,710 @@ using namespace std; -int main(int argc, char** argv) +ostream &out=cout; +ostream &comment=cout; +program_t prog; + +void write_empty_line() +{ + out << "\n"; +} + +void include_file(string file) +{ + file="templates/"+file; + + ifstream in; + in.open(file.c_str()); + if (!in.good()) + throw string ("include: could not open '"+file+"'"); + + char tempbuf[2000]; + while (!in.eof()) + { + in.getline(tempbuf, sizeof(tempbuf)); + out << tempbuf << "\n"; + } +} + +void write_env_decs() +{ + for (int i=0;i<prog.n_osc;i++) + if (prog.env[i].enabled) + out << "\t\tEnvelope *env"<<i<<";\n"; + else + { + comment << "\t\t//envelope"<<i<<" is unused\n"; + if ( (prog.osc[i].ksl!=0) || (prog.osc[i].ksl_const==false) ) + out << "\t\tfixed_t kslval"<<i<<";\n"; + } +} +void write_oscval_decs() +{ + out << "\t\tfixed_t *oscval;\n" + "\t\tfixed_t *old_oscval;\n"; +} +void write_osc_decs() +{ + for (int i=0;i<prog.n_osc;i++) + out << "\t\toscillator_t osc"<<i<<";\n"; +} +void write_osc_decs2() +{ + for (int i=0;i<prog.n_osc;i++) + out << "\t\t\toscillator_t osc"<<i<<";\n"; +} + +void write_sync_decs() +{ + if ((prog.sync_factor!=0) || (prog.sync_factor_const==false)) + out << "\t\tfixed_t sync_factor;\n" + "\t\tfixed_t sync_phase;\n"; + else + comment << "\t\t//sync is disabled\n"; +} + +void write_filter_decs() +{ + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + { + out << "\t\tLowPassFilter filter;\n" + "\t\tfilter_params_t filter_params;\n" + "\t\tint filter_update_counter;\n"; + if (prog.filter.env_settings.enabled==true) + out << "\t\tEnvelope *filter_envelope;\n"; + else + comment << "\t\t//filter envelope is disabled\n"; + + } + else + comment << "\t\t//filter is disabled\n"; +} + +void write_pfactor_decs() +{ + if (prog.use_pfactor) + { + out << "\t\tpfactor_value_t pfactor;\n" + "\t\tstruct\n" + "\t\t{\n"; + write_osc_decs2(); + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + out << "\t\t\tfilter_params_t filter_params;\n"; + else + comment << "\t\t\t//filter is disabled\n"; + out << "\t\t} orig;\n"; + } + else + comment << "\t\t//pfactors/velocity influence are disabled\n"; +} + + +void write_ctor() +{ + int i; + string tabtmp=""; + + out << "Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)\n" + "{\n" + "\tcurr_prg=&prg;\n" + "\t\n" + "\toscval=new fixed_t["<< prog.n_osc <<"];\n" + "\told_oscval=new fixed_t["<< prog.n_osc <<"];\n" + "\tfor (int i=0;i<"<<prog.n_osc<<";i++)\n" + "\t\toscval[i]=old_oscval[i]=0;\n" + "\t\n" + "\tpfactor.out=new fixed_t ["<<prog.n_osc<<"];\n" + "\tpfactor.fm=new fixed_t* ["<<prog.n_osc<<"];\n" + "\tfor (int i=0;i<"<<prog.n_osc<<";i++)\n" + "\t\tpfactor.fm[i]=new fixed_t ["<<prog.n_osc<<"];\n" + "\t\n"; + + for (i=0;i<prog.n_osc;i++) + if (prog.env[i].enabled) + out << "\tenv"<<i<<"=new Envelope (prg.env_settings["<<i<<"]);\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n"; + + out << "\t\n"; + + for (i=0;i<prog.n_osc;i++) + { + out << "\tosc"<<i<<"=prg.osc_settings["<<i<<"];\n"; + if (prog.use_pfactor) + out << "\torig.osc"<<i<<"=prg.osc_settings["<<i<<"];\n"; + } + + out << "\t\n"; + + out << "\t//initalize oscillator.phase to multiples of their wave resolution\n"; + for (i=0;i<prog.n_osc;i++) + { + out << "\tosc"<<i<<".phase="; + if (prog.osc[i].have_custom_wave) + out << "init_custom_osc_phase(osc"<<i<<".custom_wave->wave_len, osc"<<i<<".custom_wave->samp_rate);\n"; + else + out << "ONE * PHASE_INIT;\n"; + } + + out << "\t\n" + "\tdo_ksl();\n" + "\t\n" + "\t\n"; + + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + { + //a filter_params and orig.filter_params member exist + out << "\tfilter_params=prg.filter_settings;\n"; + if (prog.use_pfactor) + out << "\torig.filter_params=prg.filter_settings;\n"; + + if (prog.filter.enabled_const==false) + { + out << "\tif (filter_params.enabled)\n" + "\t{\n"; + tabtmp="\t"; + } + out << tabtmp << "\tfilter_envelope=new Envelope(filter_params.env_settings);\n" << + tabtmp << "\tfilter_update_counter=filter_update_frames;\n"; + if (prog.filter.enabled_const==false) + out << "\t}\n"; + tabtmp=""; + + out << "\t\n" + "\t\n"; + } + + + if ((prog.sync_factor!=0) || (prog.sync_factor_const==false)) + out << "\tsync_factor=prg.sync_factor;\n" + "\tsync_phase=0;\n" + "\t\n" + "\t\n"; + + + include_file("ctor.foot"); +} + +void write_dtor() +{ + int i; + + out << "Note::~Note()\n" + "{\n"; + + for (i=0;i<prog.n_osc;i++) + { + out << "\tdelete [] osc"<<i<<".fm_strength;\n"; + + if (prog.env[i].enabled) + out << "\tdelete env"<<i<<";\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n"; + + if (prog.use_pfactor) + out << "\tdelete pfactor.fm["<<i<<"];\n"; + + out << "\t\n"; + } + + out << "\t\n" + "\tdelete [] oscval;\n" + "\tdelete [] old_oscval;\n"; + + if (prog.use_pfactor) + { + out << "\t\n" + "\tdelete [] pfactor.out;\n" + "\tdelete [] pfactor.fm;\n"; + } + out << "}\n"; +} + + +void write_recalc_factors() { - program_t p=parse("../../velotest.prog"); + out << "void Note::recalc_factors()\n" + "{\n"; + + if (prog.use_pfactor) + { + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + { + out << "\tpfactor.filter_env=calc_pfactor(curr_prg->pfactor.filter_env, vel);\n" + "\tpfactor.filter_res=calc_pfactor(curr_prg->pfactor.filter_res, vel);\n" + "\tpfactor.filter_offset=calc_pfactor(curr_prg->pfactor.filter_offset, vel);\n" + "\t\n"; + } + + out << "\tfor (int i=0;i<"<<prog.n_osc<<";i++)\n" + "\t{\n" + "\t\tpfactor.out[i]=calc_pfactor(curr_prg->pfactor.out[i], vel);\n" + "\t\t\n" + "\t\tfor (int j=0;j<"<<prog.n_osc<<";j++)\n" + "\t\t\tpfactor.fm[i][j]=calc_pfactor(curr_prg->pfactor.fm[i][j], vel);\n" + "\t}\n"; + } + + out << "}\n"; +} - cout << "n_osc="<<p.n_osc<<endl; - for (int i=0;i<p.n_osc;i++) +void write_apply_pfactor() +{ + out << "void Note::apply_pfactor()\n" + "{\n"; + + if (prog.use_pfactor) { - for (int j=0;j<p.n_osc;j++) + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + out << "\tfilter_params.env_amount=orig.filter_params.env_amount*pfactor.filter_env /ONE;\n" + "\tfilter_params.freqfactor_offset=orig.filter_params.freqfactor_offset*pfactor.filter_offset /ONE;\n" + "\tfilter_params.resonance=orig.filter_params.resonance*pfactor.filter_res /ONE;\n" + "\t\n"; + + for (int i=0;i<prog.n_osc;i++) { - cout << " "<<i<<" gets modulated by "<<j<<": strength="<<p.osc[i].fm_strength[j]<<", const="<<p.osc[i].fm_strength_const[j]<<endl; + out << "\tosc"<<i<<".output=orig.osc"<<i<<".output*pfactor.out["<<i<<"] >>SCALE;\n" + "\tfor (int i=0;i<"<<prog.n_osc<<";i++)\n" + "\t\tosc"<<i<<".fm_strength[i]=orig.osc"<<i<<".fm_strength[i]*pfactor.fm["<<i<<"][i] >>SCALE;\n"; } } + + out << "}\n"; +} + +void write_still_active() +{ + out << "bool Note::still_active()\n" + "{\n"; + + out << "\tif ( "; + if (prog.env[0].enabled) + out << " ((osc"<<0<<".output>0) && (env"<<0<<"->still_active()))"; + else + out << " // envelope"<<0<<" is disabled"; + + for (int i=1;i<prog.n_osc;i++) + { + if (prog.env[i].enabled) + out << "\n\t || ((osc"<<i<<".output>0) && (env"<<i<<"->still_active()))"; + else + out << "\n\t /* envelope"<<i<<" is disabled */"; + } + + out << " )\n" + "\t\treturn true;\n" + "\telse\n" + "\t\treturn false;\n"; + + + out << "}\n"; +} + +void write_release() +{ + out << "void Note::release()\n" + "{\n"; + + for (int i=0;i<prog.n_osc;i++) + { + if (prog.env[i].enabled) + out << "\tenv"<<i<<"->release_key();\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n"; + } + + + if (prog.filter.enabled && prog.filter.enabled_const) + out << "\n\tfilter_envelope->release_key();\n"; + else if (prog.filter.enabled_const==false) + out << "\n\tif (filter_params.enabled)\n" + "\t\tfilter_envelope->release_key();\n"; + + out << "}\n"; +} + +void write_release_quickly() +{ + out << "void Note::release_quickly(jack_nframes_t maxt)\n" + "{\n"; + + for (int i=0;i<prog.n_osc;i++) + { + if (prog.env[i].enabled) + out << "\tif (env"<<i<<"->get_release() > maxt)\n" + "\t\tenv"<<i<<"->set_release(maxt);\n" + "\tenv"<<i<<"->release_key();\n" + "\t\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n" + "\t\n"; + } + + out << "}\n"; +} + +void write_reattack() +{ + out << "void Note::reattack()\n" + "{\n"; + + for (int i=0;i<prog.n_osc;i++) + { + if (prog.env[i].enabled) + out << "\tenv"<<i<<"->reattack();\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n"; + } + + + if (prog.filter.enabled && prog.filter.enabled_const) + out << "\n\tfilter_envelope->reattack();\n"; + else if (prog.filter.enabled_const==false) + out << "\n\tif (filter_params.enabled)\n" + "\t\tfilter_envelope->reattack();\n"; + + out << "}\n"; +} + +void write_do_ksr() +{ + out << "void Note::do_ksr()\n" + "{\n"; + + for (int i=0;i<prog.n_osc;i++) + { + if (prog.env[i].enabled) + out << "\tenv"<<i<<"->set_ratefactor(1.0 / pow(freq>>SCALE, osc"<<i<<".ksr));\n"; + else + comment << "\t//envelope"<<i<<" is disabled\n"; + } + + out << "}\n"; +} + +void write_do_ksl() +{ + bool need_ksl=false; + + out << "void Note::do_ksl()\n" + "{\n"; + + + for (int i=0;i<prog.n_osc;i++) + if ( (prog.osc[i].ksl!=0) || (prog.osc[i].ksl_const==false) ) + { + need_ksl=true; + break; + } + + if (need_ksl) + { + out << "\tdouble tempfreq=double ( freq >> SCALE );\n" + "\t\n"; + + for (int i=0;i<prog.n_osc;i++) + { + if ( (prog.osc[i].ksl==0) && (prog.osc[i].ksl_const) ) + comment << "\t//ksl is disabled for oscillator"<<i<<"\n"; + else + { + string kslstring = "( (osc"+IntToStr(i)+".ksl==0) ? ONE : ( fixed_t(double(ONE) / pow(tempfreq, osc"+IntToStr(i)+".ksl)) ) )"; + + if (prog.env[i].enabled) + out << "\tenv"<<i<<"->set_max( "<<kslstring<<" );\n"; + else + out << "\tkslval"<<i<<"="<<kslstring<<";\n"; + } + } + } + out << "}\n"; +} + +void write_get_sample() +{ + string tabtemp=""; + + include_file("get_sample.1"); + + { //SYNC TODO + if (prog.sync_factor_const==false) + { + out << "\tif (sync_factor)\n" + "\t{\n"; + + tabtemp="\t"; + } + + if ( (prog.sync_factor_const==false) || (prog.sync_factor!=0) ) + { + string temp; + if (prog.sync_factor_const) + temp=IntToStr(prog.sync_factor); + else + temp="sync_factor"; + + out << tabtemp << "\tsync_phase+=(actual_freq*"<<temp<<"/samp_rate) >> SCALE;\n" + << tabtemp << "\t\n" + << tabtemp << "\tif (sync_phase >= ONE)\n" + << tabtemp << "\t{\n" + << tabtemp << "\t\tsync_phase-=ONE;\n" + << tabtemp << "\t\t\n"; + + for (int i=0;i<prog.n_osc;i++) + { + string initstring; + if (prog.osc[i].have_custom_wave) + initstring="init_custom_osc_phase(osc"+IntToStr(i)+".custom_wave->wave_len, osc"+IntToStr(i)+".custom_wave->samp_rate)"; + else + initstring="ONE * PHASE_INIT"; + + string full_command="osc"+IntToStr(i)+".phase="+initstring+";\n"; + + if ( prog.osc[i].sync_const && prog.osc[i].sync ) + out << tabtemp << "\t\t" << full_command; + else if ( prog.osc[i].sync_const && (prog.osc[i].sync==false) ) + comment << tabtemp << "\t\t//sync is disabled for osc"<<i<<"\n"; + else //if (prog.osc[i].sync_const==false) + out << tabtemp << "\t\tif (osc"<<i<<".sync) " <<full_command; + } + + out << tabtemp << "\t}\n"; + + } + else //if ( (prog.sync_factor_const==true) && (prog.sync_factor==0) ) + comment << "\t//sync is disabled\n"; + + if (prog.sync_factor_const==false) + { + out << "\t}\n"; + + tabtemp=""; + } + out << "\t\n\t\n"; + } //SYNC TODO + + { //OSCS TODO + string outstring_scaled="", outstring_nonscaled=""; + + for (int i=0;i<prog.n_osc;i++) + { + // increment phase + string phase_inc_lfo = "( (curr_lfo[osc"+IntToStr(i)+".vibrato_lfo][osc"+IntToStr(i)+".vibrato_depth]*actual_freq >>SCALE)*osc"+IntToStr(i)+".factor/samp_rate)>>SCALE"; + string phase_inc = "(actual_freq*osc"+IntToStr(i)+".factor/samp_rate)>>SCALE"; + if (prog.osc[i].vibrato_depth_const == false) + out << "\tosc"<<i<<".phase+= ( (osc"<<i<<".vibrato_depth==0) ? ("<<phase_inc<<") : ("<<phase_inc_lfo<<") );\n"; + else if (prog.osc[i].vibrato_depth == 0) + out << "\tosc"<<i<<".phase+= "<<phase_inc<<";\n"; + else + out << "\tosc"<<i<<".phase+= "<<phase_inc_lfo<<";\n"; + + // calculate phase modulation + string fm=""; //TODO FINDMICH: das >>SCALE fehlt noch! + for (int j=0;j<prog.n_osc;j++) + { + if (prog.osc[i].fm_strength_const[j] == false) + fm+="+ (old_oscval["+IntToStr(j)+"] * osc"+IntToStr(i)+".fm_strength["+IntToStr(j)+"]) "; + else if (prog.osc[i].fm_strength[j]!=0) + fm+="+ (old_oscval["+IntToStr(j)+"] * "+IntToStr(prog.osc[i].fm_strength[j])+") "; + } + + // generate string for modulated phase + string phase; + if (fm!="") + phase="( osc"+IntToStr(i)+".phase + ( "+fm+">>SCALE ) )"; + else + phase="osc"+IntToStr(i)+".phase"; + + // generate string for wave + string wavetemp; + if (prog.osc[i].have_custom_wave) + { + string cw="osc"+IntToStr(i)+".custom_wave"; + wavetemp=cw+"->wave[ ( "+phase+" * "+cw+"->samp_rate >>(2*SCALE) ) % "+cw+"->wave_len ]"; + } + else + { + string waveformtemp; + if (prog.osc[i].waveform_const) + waveformtemp=IntToStr(prog.osc[i].waveform); + else + waveformtemp="osc"+IntToStr(i)+".waveform"; + + wavetemp="wave["+waveformtemp+"][ ( "+phase+" * WAVE_RES >>SCALE ) % WAVE_RES ]"; + } + + // finally write "oscval[n]=..." + out << "\toscval["<<i<<"] = "<<wavetemp; + // figure out whether we need to multiply with the env, with ksl or not at all + if (prog.env[i].enabled) + out<<" * env"<<i<<"->get_level() >>SCALE;\n"; + else if ( (prog.osc[i].ksl!=0) || (prog.osc[i].ksl_const==false) ) + // i.e.: if osc[i] has a kslval variable + out<<" * kslval"<<i<<" >>SCALE;\n"; + else //no envelope, no kslval + out<<";\n"; + + + // maybe do tremolo + string tremlfo; + if (prog.osc[i].tremolo_lfo_const==false) + tremlfo="osc"+IntToStr(i)+".tremolo_lfo"; + else + tremlfo=IntToStr(prog.osc[i].tremolo_lfo); + + if (prog.osc[i].tremolo_depth_const==false) + out << "\tif (osc"<<i<<".tremolo_depth)\n" + "\t\toscval["<<i<<"] = oscval["<<i<<"] * curr_lfo["<<tremlfo<<"][osc"<<i<<".tremolo_depth] >>SCALE;\n"; + else if (prog.osc[i].tremolo_depth!=0) + out << "\toscval["<<i<<"] = oscval["<<i<<"] * curr_lfo["<<tremlfo<<"]["<<prog.osc[i].tremolo_depth<<"] >>SCALE;\n"; + else + comment << "\t//oscillator"<<i<<" has no tremolo\n"; + + // maybe add this osc to the output + if (prog.osc[i].output_const==false) + outstring_scaled+="+ osc"+IntToStr(i)+".output*oscval["+IntToStr(i)+"] "; + else if (prog.osc[i].output==ONE) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"] "; + else if (prog.osc[i].output==ONE/2) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/2 "; + else if (prog.osc[i].output==ONE/3) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/3 "; + else if (prog.osc[i].output==ONE/4) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/4 "; + else if (prog.osc[i].output==ONE/5) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/5 "; + else if (prog.osc[i].output==ONE/6) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/6 "; + else if (prog.osc[i].output==ONE/7) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/7 "; + else if (prog.osc[i].output==ONE/8) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/8 "; + else if (prog.osc[i].output==ONE/9) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/9 "; + else if (prog.osc[i].output==ONE/10) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]/10 "; + else if (prog.osc[i].output==ONE*2) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]*2 "; + else if (prog.osc[i].output==ONE*3) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]*3 "; + else if (prog.osc[i].output==ONE*4) + outstring_nonscaled+="+ oscval["+IntToStr(i)+"]*4 "; + else if (prog.osc[i].output!=0) + outstring_scaled+="+ "+IntToStr(prog.osc[i].output)+"*oscval["+IntToStr(i)+"] "; + //else: output is 0, ignore it + + out << "\t\n"; + } + + // generate, check and write the final outstring + string outstring=""; + if (outstring_scaled!="") + outstring+="( "+outstring_scaled+" >>SCALE )"; + if (outstring_nonscaled!="") + outstring+=" "+outstring_nonscaled; + + if (outstring=="") + throw string ("this instrument has no output at all!"); + + out << "\tfixed_t out = "<<outstring<<";\n" + "\t\n" + "\t\n"; + } //OSCS TODO + + { //FILTER TODO + tabtemp=""; + + if (prog.filter.enabled_const==false) + { + out << "\tif (filter_params.enabled)\n" + "\t{\n"; + tabtemp="\t"; + } + + if ((prog.filter.enabled_const==false) || (prog.filter.enabled==true)) + out << tabtemp << "\tfilter_update_counter++;\n" + << tabtemp << "\tif (filter_update_counter>=filter_update_frames)\n" + << tabtemp << "\t{\n" + << tabtemp << "\t\tfilter_update_counter=0;\n" + << tabtemp << "\t\t\n" + << tabtemp << "\t\tfloat cutoff= float(actual_freq)/ONE * \n" + << tabtemp << "\t\t\tfloat(curr_lfo[filter_params.trem_lfo][filter_params.trem_strength])/ONE *\n" + << tabtemp << "\t\t\t( filter_params.freqfactor_offset + filter_envelope->get_level() * filter_params.env_amount / float(ONE) );\n" + << tabtemp << "\t\tfilter.set_params( cutoff, filter_params.resonance );\n" + << tabtemp << "\t}\n" + << tabtemp << "\t\n" + << tabtemp << "\tfilter.process_sample(&out);\n"; + + if (prog.filter.enabled_const==false) + { + out << "\t}\n"; + tabtemp=""; + } + out << "\t\n"; + } + + out << "\treturn out;\n"; + out << "}\n"; +} + +void write_foo() +{ + out << "void Note::foo()\n" + "{\n"; + + out << "}\n"; +} + +void generate_source() +{ + //#includes and definition of class Note + include_file("head.1"); + write_env_decs(); + write_empty_line(); + write_oscval_decs(); + write_empty_line(); + write_osc_decs(); + write_empty_line(); + write_sync_decs(); + write_empty_line(); + write_filter_decs(); + write_empty_line(); + write_pfactor_decs(); + include_file("head.2"); + + + //implementation of Note's functions + write_ctor(); + write_dtor(); + write_empty_line(); + + write_recalc_factors(); + write_apply_pfactor(); + write_empty_line(); + + write_still_active(); + write_release(); + write_release_quickly(); + write_reattack(); + write_empty_line(); + + write_do_ksr(); + write_do_ksl(); + write_empty_line(); + + write_get_sample(); +} + +int main(int argc, char** argv) +{ + prog=parse("../../filtertest.prog"); + + prog.env[1].enabled=false; + + + generate_source(); + return 0; } diff --git a/note_compiler/note.cpp.todo b/note_compiler/note.cpp.todo new file mode 100644 index 0000000..a256525 --- /dev/null +++ b/note_compiler/note.cpp.todo @@ -0,0 +1,72 @@ +void Note::set_param(const parameter_t &p, fixed_t v) //ACHTUNG: +{ + //wenn das verändert wird, muss auch program_t::set_param verändert werden! + switch(p.par) + { + case ATTACK: envelope[p.osc]->set_attack(v*samp_rate >>SCALE); break; + case DECAY: envelope[p.osc]->set_decay(v*samp_rate >>SCALE); break; + case SUSTAIN: envelope[p.osc]->set_sustain(v); break; + case RELEASE: envelope[p.osc]->set_release(v*samp_rate >>SCALE); break; + case HOLD: envelope[p.osc]->set_hold(v!=0); break; + + case KSR: oscillator[p.osc].ksr=float(v)/ONE; break; + case KSL: oscillator[p.osc].ksl=float(v)/ONE; break; + + case FACTOR: oscillator[p.osc].factor=v; break; + case MODULATION: oscillator[p.osc].fm_strength[p.index]=v*pfactor.fm[p.osc][p.index] >>SCALE; break; + case OUTPUT: oscillator[p.osc].output=v*pfactor.out[p.osc] >>SCALE; break; + case TREMOLO: oscillator[p.osc].tremolo_depth=v; break; + case TREM_LFO: oscillator[p.osc].tremolo_lfo=v; break; + case VIBRATO: oscillator[p.osc].vibrato_depth=v; break; + case VIB_LFO: oscillator[p.osc].vibrato_lfo=v; break; + case WAVEFORM: oscillator[p.osc].waveform=v; break; + case SYNC: oscillator[p.osc].sync=(v!=0); break; + + case FILTER_ENABLED: output_note("NOTE: cannot enable filter in playing notes"); break; + case FILTER_ENV_AMOUNT: filter_params.env_amount=float(v*pfactor.filter_env)/ONE/ONE; break; + + case FILTER_ATTACK: + if (filter_params.enabled) + filter_envelope->set_attack(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-attack when filter is disabled"); + break; + + case FILTER_DECAY: + if (filter_params.enabled) + filter_envelope->set_decay(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-decay when filter is disabled"); + break; + + case FILTER_SUSTAIN: + if (filter_params.enabled) + filter_envelope->set_sustain(v); + else + output_note("NOTE: cannot set filter-sustain when filter is disabled"); + break; + + case FILTER_RELEASE: + if (filter_params.enabled) + filter_envelope->set_release(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-release when filter is disabled"); + break; + + case FILTER_HOLD: + if (filter_params.enabled) + filter_envelope->set_hold(v!=0); + else + output_note("NOTE: cannot set filter-hold when filter is disabled"); + break; + + case FILTER_OFFSET: filter_params.freqfactor_offset=float(v*pfactor.filter_offset)/ONE/ONE; break; + case FILTER_RESONANCE: filter_params.resonance=float(v*pfactor.filter_res)/ONE/ONE; break; + case FILTER_TREMOLO: filter_params.trem_strength=v; break; + case FILTER_TREM_LFO: filter_params.trem_lfo=v; break; + + case SYNC_FACTOR: sync_factor=v; break; + default: throw string("trying to set an unknown parameter"); + + } +} diff --git a/note_compiler/parser.cpp b/note_compiler/parser.cpp index 98c65ac..3f142bd 100644 --- a/note_compiler/parser.cpp +++ b/note_compiler/parser.cpp @@ -37,6 +37,8 @@ void init_oscs(int n_osc, oscillator_t *osc) 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; } } @@ -44,11 +46,12 @@ 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=ONE; + env[i].sustain=1.0; env[i].sustain_const=true; env[i].release=0; env[i].release_const=true; @@ -118,9 +121,11 @@ program_t parse(string fn) oscillator_t *osc=NULL; env_settings_t *env=NULL; filter_params_t filter; - fixed_t sync_factor; + fixed_t sync_factor=0; bool sync_factor_const=true; + bool use_pfactor=false; + char buf[2000]; string line; string var; @@ -351,6 +356,7 @@ program_t parse(string fn) default: // other params than the above may not be influenced! throw string("velocity cannot influence parameter '"+array+"'"); } + use_pfactor=true; } @@ -432,13 +438,42 @@ program_t parse(string fn) } } + + //some optimizations + + 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; + } + + //end optimizations + 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; - + result.use_pfactor=use_pfactor; } else throw string ("could not open '"+fn+"'"); diff --git a/note_compiler/programs.h b/note_compiler/programs.h index daf238f..f290e35 100644 --- a/note_compiler/programs.h +++ b/note_compiler/programs.h @@ -76,6 +76,7 @@ struct oscillator_t struct env_settings_t { + bool enabled; float attack; bool attack_const; float decay; @@ -114,6 +115,8 @@ struct program_t fixed_t sync_factor; bool sync_factor_const; + + bool use_pfactor; }; #endif diff --git a/note_compiler/templates/ctor.foot b/note_compiler/templates/ctor.foot new file mode 100644 index 0000000..05d4421 --- /dev/null +++ b/note_compiler/templates/ctor.foot @@ -0,0 +1,11 @@ + portamento_frames=0; + set_portamento_frames(pf); + + set_note(n); + freq=dest_freq; + set_vel(v); + + pitchbend=pb; + + program=prg_no; +} diff --git a/note_compiler/templates/get_sample.1 b/note_compiler/templates/get_sample.1 new file mode 100644 index 0000000..3d73052 --- /dev/null +++ b/note_compiler/templates/get_sample.1 @@ -0,0 +1,23 @@ +fixed_t Note::get_sample() +{ + if (freq!=dest_freq) + { + // the div.by.zero if p_frames=0 is avoided because then the + // if-condition below is always true + if (portamento_t>=portamento_frames) + freq=dest_freq; + else //will only happen if p_t < p_frames -> p_frames is always > 0 -> div. ok + freq = old_freq + (dest_freq-old_freq)*portamento_t/portamento_frames; + + do_ksl(); + + portamento_t++; + } + + fixed_t actual_freq=freq*pitchbend >>SCALE; + + fixed_t *temp; + temp=old_oscval; //swap the current and old oscval-pointers + old_oscval=oscval; + oscval=temp; + diff --git a/note_compiler/templates/head.1 b/note_compiler/templates/head.1 new file mode 100644 index 0000000..3d9e903 --- /dev/null +++ b/note_compiler/templates/head.1 @@ -0,0 +1,35 @@ +#include <jack/jack.h> + +#include <cmath> + +#include "globals.h" +#include "defines.h" +#include "programs.h" +#include "envelope.h" +#include "fixed.h" +#include "filter.h" +#include "note_skel.h" + +using namespace std; + +class Note : public NoteSkel +{ + public: + Note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no); + ~Note(); + fixed_t get_sample(); + + void release_quickly(jack_nframes_t maxt); + void release(); + void reattack(); + bool still_active(); + void set_param(const parameter_t &p, fixed_t v); + + private: + void do_ksl(); + void do_ksr(); + + void recalc_factors(); + void apply_pfactor(); + +// member variables begin here diff --git a/note_compiler/templates/head.2 b/note_compiler/templates/head.2 new file mode 100644 index 0000000..917030c --- /dev/null +++ b/note_compiler/templates/head.2 @@ -0,0 +1,11 @@ +// member variables end here +}; + +//this function returns the smallest phase_init possible for a +//given custom_wave which is greater or equal than PHASE_INIT +#define PHASE_INIT 100 +inline fixed_t init_custom_osc_phase(int len, fixed_t sr) +{ + return ( (fixed_t(ceil( float(PHASE_INIT) * sr / len / ONE )) *len << (2*SCALE)) / sr); +} + diff --git a/synth/note.cpp b/synth/note.cpp index 8ab0546..2f192f2 100644 --- a/synth/note.cpp +++ b/synth/note.cpp @@ -1,4 +1,3 @@ -#include <string> #include <cmath> #include "note.h" diff --git a/synth/note.h b/synth/note.h index 0e76505..aab471c 100644 --- a/synth/note.h +++ b/synth/note.h @@ -51,13 +51,6 @@ class Note : public NoteSkel oscillator_t *oscillator; filter_params_t filter_params; } orig; - -/* *einstellungen: oszillatoren, deren lautstärke etc. - * note - * lautstärke - * *pitchbend - * *portamento time - */ }; diff --git a/synth/parser.cpp b/synth/parser.cpp index 96648d6..a2ab747 100644 --- a/synth/parser.cpp +++ b/synth/parser.cpp @@ -286,7 +286,7 @@ program_t parse(string fn) pfactor_formula_t pfactor; - fixed_t sync_factor; + fixed_t sync_factor=0; |