summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@thinkpad.(none)>2011-01-05 15:47:55 +0100
committerFlorian Jung <flo@thinkpad.(none)>2011-01-05 15:50:41 +0100
commit3d95a25600b5cab8a7e5245b7a581bd8c8939276 (patch)
treebe3c2d1b14dd309e48c4f541e67020fed47f5a6c
parent5e731c349b63a557b2e705ce3cd741f90c62c694 (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
-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;