From 3d95a25600b5cab8a7e5245b7a581bd8c8939276 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 5 Jan 2011 15:47:55 +0100 Subject: 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 --- note_compiler/main.cpp | 707 ++++++++++++++++++++++++++++++++++- note_compiler/note.cpp.todo | 72 ++++ note_compiler/parser.cpp | 41 +- note_compiler/programs.h | 3 + note_compiler/templates/ctor.foot | 11 + note_compiler/templates/get_sample.1 | 23 ++ note_compiler/templates/head.1 | 35 ++ note_compiler/templates/head.2 | 11 + 8 files changed, 894 insertions(+), 9 deletions(-) create mode 100644 note_compiler/note.cpp.todo create mode 100644 note_compiler/templates/ctor.foot create mode 100644 note_compiler/templates/get_sample.1 create mode 100644 note_compiler/templates/head.1 create mode 100644 note_compiler/templates/head.2 (limited to 'note_compiler') 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 +#include #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;iwave_len, osc"<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;ipfactor.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<"<pfactor.out[i], vel);\n" + "\t\t\n" + "\t\tfor (int j=0;j<"<pfactor.fm[i][j], vel);\n" + "\t}\n"; + } + + out << "}\n"; +} - cout << "n_osc="<>SCALE;\n" + "\tfor (int i=0;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;i0) && (env"<still_active()))"; + else + out << "\n\t /* envelope"<release_key();\n"; + else + comment << "\t//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;iget_release() > maxt)\n" + "\t\tenv"<set_release(maxt);\n" + "\tenv"<release_key();\n" + "\t\n"; + else + comment << "\t//envelope"<reattack();\n"; + else + comment << "\t//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;iset_ratefactor(1.0 / pow(freq>>SCALE, osc"<> SCALE );\n" + "\t\n"; + + for (int i=0;iset_max( "<> 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;iwave_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"<>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"<>SCALE fehlt noch! + for (int j=0;j>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["<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"<>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"<>SCALE;\n"; + else if (prog.osc[i].tremolo_depth!=0) + out << "\toscval["<>SCALE;\n"; + else + comment << "\t//oscillator"<>SCALE )"; + if (outstring_nonscaled!="") + outstring+=" "+outstring_nonscaled; + + if (outstring=="") + throw string ("this instrument has no output at all!"); + + out << "\tfixed_t out = "<=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;i100)) //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=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 + +#include + +#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); +} + -- cgit v1.2.3