diff options
author | Florian Jung <flo@thinkpad.(none)> | 2011-01-05 15:47:55 +0100 |
---|---|---|
committer | Florian Jung <flo@thinkpad.(none)> | 2011-01-05 15:50:41 +0100 |
commit | 3d95a25600b5cab8a7e5245b7a581bd8c8939276 (patch) | |
tree | be3c2d1b14dd309e48c4f541e67020fed47f5a6c /note_compiler | |
parent | 5e731c349b63a557b2e705ce3cd741f90c62c694 (diff) |
Note-compiler is _mostly_ complete; plus some tiny bugfixes
The note-compiler can read a program-definition and emits a cpp-file
which implements that definition. This implementation is optimized.
HOWEVER, the compiler still does not emit a set_param() function. this
will lead to a linker error because the function is not implemented
(but defined). After adding an empty implementation by hand the emitted
compiles well, and also seems to work when used in the synth.
TODO:
- implement set_param()
- compiler must emit a loader-function (which returns a new Note)
- use that loader function in the synth
Diffstat (limited to 'note_compiler')
-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 |
8 files changed, 894 insertions, 9 deletions
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); +} + |