summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO12
-rw-r--r--note_compiler/main.cpp707
-rw-r--r--note_compiler/note.cpp.todo72
-rw-r--r--note_compiler/parser.cpp41
-rw-r--r--note_compiler/programs.h3
-rw-r--r--note_compiler/templates/ctor.foot11
-rw-r--r--note_compiler/templates/get_sample.123
-rw-r--r--note_compiler/templates/head.135
-rw-r--r--note_compiler/templates/head.211
-rw-r--r--synth/note.cpp1
-rw-r--r--synth/note.h7
-rw-r--r--synth/parser.cpp2
12 files changed, 907 insertions, 18 deletions
diff --git a/TODO b/TODO
index 97475fb..e9ee05b 100644
--- a/TODO
+++ b/TODO
@@ -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;