summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@thinkpad.(none)>2011-01-09 19:09:05 +0100
committerFlorian Jung <flo@thinkpad.(none)>2011-01-09 19:09:05 +0100
commitdf97e0ebb7f6591c50f3a588cb2a74901d38ac4a (patch)
treeaa68ab5a73388d57636a4e5c9058b9dcc0f21e90
parentaa1c06213e695be1dcb5980b638d8ce81efb4f51 (diff)
Merged branch for compiled notes
The synthesizer is now able to load and use compiled, optimized shared objects of programs. There's also a note-compiler which creates the code for such objects. TODO: - let the note-compiler automatically compile OR rename it to code-emitter
-rw-r--r--.depend25
-rw-r--r--TODO25
-rw-r--r--TODO.done12
-rw-r--r--note_compiler/.depend4
-rw-r--r--note_compiler/.gitignore1
-rw-r--r--note_compiler/IDEE30
-rw-r--r--note_compiler/Makefile34
-rw-r--r--note_compiler/howtocompile.txt4
-rw-r--r--note_compiler/main.cpp779
-rw-r--r--note_compiler/parser.cpp504
-rw-r--r--note_compiler/parser.h16
-rw-r--r--note_compiler/plugin_factory/Makefile34
l---------note_compiler/plugin_factory/channel.cpp1
l---------note_compiler/plugin_factory/channel.h1
l---------note_compiler/plugin_factory/cli.cpp1
l---------note_compiler/plugin_factory/cli.h1
l---------note_compiler/plugin_factory/defines.cpp1
l---------note_compiler/plugin_factory/defines.h1
l---------note_compiler/plugin_factory/envelope.cpp1
l---------note_compiler/plugin_factory/envelope.h1
l---------note_compiler/plugin_factory/filter.cpp1
l---------note_compiler/plugin_factory/filter.h1
l---------note_compiler/plugin_factory/fixed.h1
l---------note_compiler/plugin_factory/globals.cpp1
l---------note_compiler/plugin_factory/globals.h1
-rw-r--r--note_compiler/plugin_factory/infile.cpp392
l---------note_compiler/plugin_factory/jack.cpp1
l---------note_compiler/plugin_factory/jack.h1
l---------note_compiler/plugin_factory/load.cpp1
l---------note_compiler/plugin_factory/load.h1
l---------note_compiler/plugin_factory/main.cpp1
l---------note_compiler/plugin_factory/note.cpp1
l---------note_compiler/plugin_factory/note.h1
l---------note_compiler/plugin_factory/note_funcs.h1
l---------note_compiler/plugin_factory/note_loader.cpp1
l---------note_compiler/plugin_factory/note_loader.h1
l---------note_compiler/plugin_factory/note_skel.cpp1
l---------note_compiler/plugin_factory/note_skel.h1
l---------note_compiler/plugin_factory/parser.cpp1
l---------note_compiler/plugin_factory/parser.h1
l---------note_compiler/plugin_factory/programs.cpp1
l---------note_compiler/plugin_factory/programs.h1
l---------note_compiler/plugin_factory/readwave.cpp1
l---------note_compiler/plugin_factory/readwave.h1
l---------note_compiler/plugin_factory/util.cpp1
l---------note_compiler/plugin_factory/util.h1
-rw-r--r--note_compiler/programs.h121
-rw-r--r--note_compiler/templates/ctor.foot11
-rw-r--r--note_compiler/templates/get_sample.123
-rw-r--r--note_compiler/templates/head.148
-rw-r--r--note_compiler/templates/head.211
-rw-r--r--note_compiler/templates/interface.119
-rw-r--r--note_compiler/templates/set_param.127
-rw-r--r--note_compiler/templates/set_param.filter7
-rw-r--r--note_compiler/templates/set_param.filterenv34
-rw-r--r--note_compiler/templates/set_param.nofilter13
-rw-r--r--note_compiler/templates/set_param.nofilterenv7
-rw-r--r--note_compiler/util.cpp208
-rw-r--r--note_compiler/util.h31
-rw-r--r--synth/.depend50
-rw-r--r--synth/Makefile4
-rw-r--r--synth/channel.cpp75
-rw-r--r--synth/channel.h4
-rw-r--r--synth/globals.cpp2
-rw-r--r--synth/globals.h2
-rw-r--r--synth/jack.cpp46
-rw-r--r--synth/main.cpp25
-rw-r--r--synth/note.cpp87
-rw-r--r--synth/note.h32
-rw-r--r--synth/note_funcs.h20
-rw-r--r--synth/note_loader.cpp54
-rw-r--r--synth/note_loader.h13
-rw-r--r--synth/note_skel.cpp74
-rw-r--r--synth/note_skel.h56
-rw-r--r--synth/parser.cpp4
-rw-r--r--synth/programs.cpp7
-rw-r--r--synth/programs.h6
-rw-r--r--synth/util.cpp2
78 files changed, 2826 insertions, 190 deletions
diff --git a/.depend b/.depend
deleted file mode 100644
index 3a0b0ed..0000000
--- a/.depend
+++ /dev/null
@@ -1,25 +0,0 @@
-channel.o: channel.cpp channel.h fixed.h programs.h note.h envelope.h \
- filter.h defines.h util.h globals.h
-cli.o: cli.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h load.h
-defines.o: defines.cpp defines.h
-envelope.o: envelope.cpp envelope.h programs.h fixed.h
-filter.o: filter.cpp filter.h fixed.h defines.h globals.h programs.h \
- channel.h note.h envelope.h util.h
-globals.o: globals.cpp globals.h programs.h fixed.h channel.h note.h \
- envelope.h filter.h defines.h util.h
-jack.o: jack.cpp defines.h globals.h programs.h fixed.h channel.h note.h \
- envelope.h filter.h util.h jack.h
-load.o: load.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h
-main.o: main.cpp jack.h load.h cli.h parser.h fixed.h programs.h \
- channel.h note.h envelope.h filter.h defines.h util.h globals.h
-note.o: note.cpp note.h programs.h fixed.h envelope.h filter.h globals.h \
- channel.h defines.h util.h
-parser.o: parser.cpp parser.h fixed.h programs.h defines.h globals.h \
- channel.h note.h envelope.h filter.h util.h readwave.h
-programs.o: programs.cpp programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h util.h
-readwave.o: readwave.cpp readwave.h programs.h fixed.h util.h
-util.o: util.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h
diff --git a/TODO b/TODO
index a3a70eb..a77ac04 100644
--- a/TODO
+++ b/TODO
@@ -1,23 +1,28 @@
TODO für den synth
+ o bei envelopes: releasephase abschalten (bei sustain bleiben)
+ o soft-pedal
+
+ o programme on-the-fly (um)laden
+ o RAM aufräumen?
+
+ o beide parser: envelopes von oscs mit out=0 standardmäßig deaktivieren
+ o envelope, filter, ggf. auch alles aus program.o im hauptprogramm
+ lassen? d.h. via init funktionspointer übergeben oder virtuelle
+ interfaceklassen benutzen (für envelope/filter z.B.)
+
o KSL mit powf und floats statt mit double umschreiben
o statt lfo-nummer direkten zugriff auf curr_lfo angeben?
o bei tremolo (und vibrato?): eventuell nicht prüfen, obs aktiviert
ist, sondern zur not einfach *1 rechnen?
+ o beim default_program vielleicht auch ein optimiertes objekt benutzen?
- o programme on-the-fly (um)laden
-
- o bei envelopes: releasephase abschalten (bei sustain bleiben)
-
- o soft-pedal
-
- o RAM aufräumen?
-
o jedes programm eigene LFOs?
o andere wellenformen bei LFOs?
o mehr wellen für wave[]
o parser: sehr redundante funktionen zusammenführen
o parser: direkt in result schreiben?
+ o parser: lässt sich sicher noch viel besser lösen, siehe auch oben
o attack und release ggf. auf niedrigen wert (<=0.01) initen, um
knackser zu vermeiden?
@@ -29,11 +34,9 @@ TODO für den synth
o max_pitchbend per controller setzen?
o nur auf bestimmte channels reagieren
- (o)programs on-the-fly ändern (n_osc ändern)
- (o)lfo-maxima getrennt regeln. nää
(o)bei filter-envelopes: ksr/ksl? nää.
(o)resonanz-tremolo bei tiefpass? nää.
TODO fürs CLI
- x envelope_update_frames per CLI setzen
+ x ...
diff --git a/TODO.done b/TODO.done
index 9bf20da..c03e853 100644
--- a/TODO.done
+++ b/TODO.done
@@ -52,6 +52,7 @@ TODO für den synth
x BUG: bei Note::set_param sollte statt dem eigentlichen param
der orig gesetzt werden und dann neu berechnet werden!
x BUG: bei release und reattack: BEIDE male die filter-envelope beachten!
+ x wave auf int*[] mit wave[i]=new int[] umbauen
x oscval-nullen kann in get_sample() weggelassen werden
x in get_sample(), beim aufaddieren zum out (und vmtl auch fm-)wert:
erst nach dem addieren scalen, statt für jeden faktor einzeln
@@ -77,5 +78,16 @@ TODO fürs CLI
in parser: throw!, sonst: meckern und nächste zeile parsen
x automatisch an alle midi-outs hängen
x interface div-by-zero-sicher machen
+ x envelope_update_frames per CLI setzen
+ x .so unloaden!
+ * lfo-maxima getrennt regeln. [abgelehnt]
+TODO für den compiler
+ x wenn vel_influence für foo, aber foo ist konstant null, bleibt
+ foo trotzdem konstant.
+ x vel_influence ist IMMER gegeben für output, außer wenn anders
+ angegeben
+ x *1 bzw /2 optimierungen klappen nicht?
+ x pfactor nicht wegoptimieren, sondern immer verwenden
+ x wenn sync global aus ist, kann auch osc.sync genullt werden
diff --git a/note_compiler/.depend b/note_compiler/.depend
new file mode 100644
index 0000000..30001ec
--- /dev/null
+++ b/note_compiler/.depend
@@ -0,0 +1,4 @@
+main.o: main.cpp parser.h ../synth/fixed.h programs.h util.h
+parser.o: parser.cpp parser.h ../synth/fixed.h programs.h util.h \
+ ../synth/defines.h
+util.o: util.cpp util.h programs.h ../synth/fixed.h
diff --git a/note_compiler/.gitignore b/note_compiler/.gitignore
new file mode 100644
index 0000000..86a7c8e
--- /dev/null
+++ b/note_compiler/.gitignore
@@ -0,0 +1 @@
+compiler
diff --git a/note_compiler/IDEE b/note_compiler/IDEE
new file mode 100644
index 0000000..01fb251
--- /dev/null
+++ b/note_compiler/IDEE
@@ -0,0 +1,30 @@
+Die Programmdatei wird geparst. Der Parser achtet hierbei auf folgendes:
+ - Initialwert der Parameter
+ - werden die Parameter jemals geändert?
+
+Parameter, die nie geändert werden, werden hardgecodet.
+Parameter, die geändert werden können, nicht.
+
+Wann können Parameter verändert werden?
+ - per controller (set_param)
+ - per velocity (pfactor, apply_pfactor etc.)
+ - wenn vom user angegeben ("variable:")
+
+get_sample (und letztendlich auch alle anderen funktionen) folgender-
+maßen durchgehen:
+
+z.B. bei if (sync_factor): wenn sync-factor variabel ist, codestelle
+so übernehmen. sonst entweder das if rauslassen und nur den nutzteil
+übernehmen, oder den ganzen teil rauslassen.
+
+
+bei for (i=0;i<n_oscillators;i++) jeden osc einzeln eincodieren.
+jeweils relevante teile übernehmen, rest rauslassen
+
+bei konstanten werte diese hardcoden
+
+envelopes können ggf. weggelassen werden, wenn folgendes gilt:
+attack=0, decay=egal, sustain=1.0, release>9999
+
+arrays werden als viele pointer realisiert.
+also nicht oscillator[0], osc[1] etc sondern osc0, osc1 etc
diff --git a/note_compiler/Makefile b/note_compiler/Makefile
new file mode 100644
index 0000000..6a08b81
--- /dev/null
+++ b/note_compiler/Makefile
@@ -0,0 +1,34 @@
+CXX=g++
+CFLAGS=-Wall -g
+CXXFLAGS=$(CFLAGS)
+LDFLAGS=-lm `pkg-config --cflags --libs jack`
+
+OBJ=main.o parser.o util.o
+BIN=compiler
+
+DEPENDFILE = .depend
+
+
+SRC = $(OBJ:%.o=%.cpp)
+
+all: $(BIN)
+
+
+$(BIN): $(OBJ)
+ $(CXX) $(CXXFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS)
+
+
+depend dep: $(SRC)
+ $(CC) -MM $(SRC) > $(DEPENDFILE)
+
+-include $(DEPENDFILE)
+
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c $<
+
+.PHONY: clean dep depend
+
+clean:
+ rm -f $(OBJ) $(BIN)
+
diff --git a/note_compiler/howtocompile.txt b/note_compiler/howtocompile.txt
new file mode 100644
index 0000000..3bb6cd8
--- /dev/null
+++ b/note_compiler/howtocompile.txt
@@ -0,0 +1,4 @@
+gcc -fPIC -g -c -Wall a.c
+gcc -fPIC -g -c -Wall b.c
+gcc -shared -fPIC -Wl,-soname,libmystuff.so.1 \
+ -o libmystuff.so.1.0.1 a.o b.o -lc
diff --git a/note_compiler/main.cpp b/note_compiler/main.cpp
new file mode 100644
index 0000000..47ed685
--- /dev/null
+++ b/note_compiler/main.cpp
@@ -0,0 +1,779 @@
+//TODO: auf unbenutzte envelopes achten!
+
+#include <iostream>
+#include <fstream>
+
+#include "parser.h"
+#include "programs.h"
+#include "util.h"
+#include "../synth/fixed.h"
+
+using namespace std;
+
+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()
+{
+ 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";
+}
+
+
+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"
+ "\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"
+ "\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";
+
+ out << "\tdelete pfactor.fm["<<i<<"];\n";
+
+ out << "\t\n";
+ }
+
+ out << "\t\n"
+ "\tdelete [] oscval;\n"
+ "\tdelete [] old_oscval;\n"
+ "\t\n"
+ "\tdelete [] pfactor.out;\n"
+ "\tdelete [] pfactor.fm;\n"
+ "}\n";
+}
+
+
+void write_recalc_factors()
+{
+ out << "void Note::recalc_factors()\n"
+ "{\n";
+
+ 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";
+}
+
+void write_apply_pfactor()
+{
+ out << "void Note::apply_pfactor()\n"
+ "{\n";
+
+ 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++)
+ {
+ 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_set_param()
+{
+ out << "void Note::set_param(const parameter_t &p, fixed_t v)\n"
+ "{\n"
+ "\toscillator_t* sel_osc=NULL;\n"
+ "\toscillator_t* sel_orig_osc=NULL;\n"
+ "\tEnvelope* sel_env=NULL;\n"
+ "\t\n"
+ "\tswitch (p.osc)\n"
+ "\t{\n";
+
+ for (int i=0;i<prog.n_osc;i++)
+ {
+ out << "\t\tcase "<<i<<": sel_osc=&osc"<<i<<"; sel_orig_osc=&orig.osc"<<i<<"; ";
+
+ if (prog.env[i].enabled)
+ out << "sel_env=env"<<i<<"; ";
+ else
+ comment << "/* envelope"<<i<<" is disabled */ ";
+
+ out << "break;\n";
+ }
+
+ out << "\t\t\n"
+ "\t\tdefault: output_note(\"NOTE: trying to change the nonexistent oscillator\"+IntToStr(p.osc));\n"
+ "\t}\n"
+ "\t\n";
+
+ include_file("set_param.1");
+
+
+ if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false))
+ {
+ include_file("set_param.filter");
+ if (prog.filter.env_settings.enabled)
+ include_file("set_param.filterenv");
+ else
+ include_file("set_param.nofilterenv");
+ }
+ else
+ include_file("set_param.nofilter");
+
+ if ((prog.sync_factor!=0) || (prog.sync_factor_const==false))
+ out << "\t\t\n"
+ "\t\tcase SYNC_FACTOR: sync_factor=v; break;\n";
+ else
+ out << "\t\t\n"
+ "\t\tcase SYNC_FACTOR: output_note(\"NOTE: trying to set sync_factor, but it's disabled\"); break;\n";
+
+ out << "\t\t\n"
+ "\t\tdefault: throw string(\"trying to set an unknown parameter\");\n"
+ "\t}\n"
+ "}\n";
+}
+
+void write_create_note()
+{
+ out << "extern \"C\" NoteSkel* create_note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)\n"
+ "{\n"
+ "\treturn new Note(n,v,prg,pf,pb,prg_no);\n"
+ "}\n";
+}
+
+void write_destroy()
+{
+ out << "void Note::destroy()\n"
+ "{\n"
+ "\tdelete this;\n"
+ "}\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_destroy();
+ 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();
+ write_empty_line();
+
+ write_set_param();
+
+ write_empty_line();
+ write_empty_line();
+ write_empty_line();
+
+ //implementation of create_note and init_vars
+ include_file("interface.1");
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ cerr << "parsing '"<<argv[1]<<"'..." << endl;
+ prog=parse(argv[1]);
+
+ generate_source();
+ }
+ catch(string err)
+ {
+ cerr << "FATAL: "<<err<<endl;
+ }
+
+ return 0;
+}
diff --git a/note_compiler/parser.cpp b/note_compiler/parser.cpp
new file mode 100644
index 0000000..c89ddd9
--- /dev/null
+++ b/note_compiler/parser.cpp
@@ -0,0 +1,504 @@
+#include <cstdlib>
+#include <fstream>
+
+#include "parser.h"
+#include "programs.h"
+#include "util.h"
+#include "../synth/defines.h"
+#include "../synth/fixed.h"
+
+
+void init_oscs(int n_osc, oscillator_t *osc)
+{
+ for (int i=0;i<n_osc;i++)
+ {
+ osc[i].n_osc=n_osc;
+
+ osc[i].fm_strength=new fixed_t[n_osc];
+ osc[i].fm_strength_const=new bool[n_osc];
+ for (int j=0;j<n_osc;j++)
+ {
+ osc[i].fm_strength[j]=0;
+ osc[i].fm_strength_const[j]=true;
+ }
+
+ osc[i].output=0;
+ osc[i].output_const=true;
+ osc[i].output_no_pfactor=false;
+ osc[i].waveform=0;
+ osc[i].waveform_const=true;
+ osc[i].factor=ONE;
+ osc[i].factor_const=true;
+ osc[i].tremolo_depth=0;
+ osc[i].tremolo_depth_const=true;
+ osc[i].tremolo_lfo=0;
+ osc[i].tremolo_lfo_const=true;
+ osc[i].vibrato_depth=0;
+ osc[i].vibrato_depth_const=true;
+ 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;
+ osc[i].ksr_const=true;
+ osc[i].ksl_const=true;
+ }
+}
+
+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=1.0;
+ env[i].sustain_const=true;
+ env[i].release=0;
+ env[i].release_const=true;
+ env[i].hold=true;
+ env[i].hold_const=true;
+ }
+}
+
+void init_filter(filter_params_t &filter)
+{
+ filter.enabled=false;
+ filter.enabled_const=true;
+ filter.env_amount=0;
+ filter.env_amount_const=true;
+ filter.env_settings.attack=0;
+ filter.env_settings.attack_const=true;
+ filter.env_settings.decay=0;
+ filter.env_settings.decay_const=true;
+ filter.env_settings.release=0;
+ filter.env_settings.release_const=true;
+ filter.env_settings.sustain=0;
+ filter.env_settings.sustain_const=true;
+ filter.env_settings.hold=true;
+ filter.env_settings.hold_const=true;
+
+ filter.freqfactor_offset=0;
+ filter.freqfactor_offset_const=true;
+ filter.resonance=0;
+ filter.resonance_const=true;
+ filter.trem_strength=0;
+ filter.trem_strength_const=true;
+ filter.trem_lfo=0;
+ filter.trem_lfo_const=true;
+}
+
+
+string extract_array_name(string s)
+{
+ size_t p;
+ p=s.find('[');
+ if (p!=string::npos)
+ return s.substr(0,p);
+ else
+ return s;
+}
+
+int extract_array_index(string s, int dim)
+{
+ size_t p=-1,p2;
+ for (int i=0;i<dim;i++)
+ {
+ p=s.find('[',p+1);
+ if (p==string::npos) return -1;
+ }
+
+ p2=s.find(']',p+1);
+ if (p2==string::npos) return -1;
+
+ return atoi(s.substr(p+1,p2-p-1).c_str());
+}
+
+
+
+program_t parse(string fn)
+{
+ int n_osc=0;
+ oscillator_t *osc=NULL;
+ env_settings_t *env=NULL;
+ filter_params_t filter;
+ fixed_t sync_factor=0;
+ bool sync_factor_const=true;
+
+ char buf[2000];
+ string line;
+ string var;
+ string array;
+ string strval;
+ float val;
+
+ parameter_enum p;
+
+ int ind,ind2=0;
+
+ int state;
+
+ program_t result;
+
+
+ ifstream f;
+ f.open(fn.c_str());
+ if (f.good())
+ {
+ state=0;
+ while (!f.eof())
+ {
+ f.getline(buf,sizeof(buf)/sizeof(*buf)-1);
+ line=buf;
+ line=remove_all_spaces(buf);
+ if ((line!="") && (line[0]!='#')) //ignore comments and empty lines
+ {
+ if (line=="controllers:")
+ {
+ state=2;
+ continue;
+ }
+ else if (line=="defaults:")
+ {
+ state=3;
+ continue;
+ }
+ else if (line=="velocity:")
+ {
+ state=4;
+ continue;
+ }
+ else if (line=="variable:")
+ {
+ state=5;
+ continue;
+ }
+
+ var=extract_var(line);
+ array=extract_array_name(var);
+ strval=extract_val(line);
+ val=atof(strval.c_str());
+
+ switch (state)
+ {
+ case 0: //expect and read number of oscillators
+ if (var!="oscillators")
+ throw string("need to know number of oscillators");
+ else
+ n_osc=val;
+
+ if (n_osc<=0) throw string("invalid number of oscillators");
+
+ //init stuff
+ env=new env_settings_t[n_osc];
+ osc=new oscillator_t[n_osc];
+ init_oscs(n_osc, osc);
+ init_envs(n_osc, env);
+ init_filter(filter);
+
+ state=1;
+ break;
+
+ case 1: //read and set information about oscillator settings
+ p=param_to_enum(array);
+
+ ind=extract_array_index(var,1);
+ if ( param_needs_index(p) && (!((ind>=0) && (ind<n_osc))) )
+ throw string("out of array bounds");
+
+
+ switch (p)
+ {
+ case MODULATION:
+ ind2=extract_array_index(var,2);
+ if (!((ind2>=0) && (ind2<n_osc)))
+ throw string("out of array bounds");
+
+ osc[ind].fm_strength[ind2]=val*ONE;
+ break;
+ case OUTPUT:
+ osc[ind].output=val*ONE;
+ break;
+ case WAVEFORM:
+ if (isfloat(strval))
+ {
+ osc[ind].waveform=int(val);
+ }
+ else
+ {
+ osc[ind].have_custom_wave=true;
+ }
+ break;
+ case FACTOR:
+ osc[ind].factor=val*ONE;
+ break;
+ case TREMOLO:
+ osc[ind].tremolo_depth=int(val);
+ break;
+ case TREM_LFO:
+ if (strval=="snh")
+ osc[ind].tremolo_lfo=SNH_LFO;
+ else
+ {
+ osc[ind].tremolo_lfo= int(val);
+ if ((val<0) || (val>=N_LFOS))
+ throw string("invalid value for tremolo_lfo");
+ }
+ break;
+ case VIBRATO:
+ osc[ind].vibrato_depth=val;
+ break;
+ case VIB_LFO:
+ if (strval=="snh")
+ osc[ind].vibrato_lfo= SNH_LFO;
+ else
+ {
+ osc[ind].vibrato_lfo= int(val);
+ if ((val<0) || (val>=N_LFOS))
+ throw string("invalid value for vibrato_lfo");
+ }
+ break;
+ case ATTACK:
+ env[ind].attack=val;
+ break;
+ case DECAY:
+ env[ind].decay=val;
+ break;
+ case SUSTAIN:
+ env[ind].sustain=val;
+ break;
+ case RELEASE:
+ env[ind].release=val;
+ break;
+ case HOLD:
+ env[ind].hold=(val!=0);
+ break;
+ case KSR:
+ osc[ind].ksr=val;
+ break;
+ case KSL:
+ osc[ind].ksl=val;
+ break;
+ case SYNC:
+ osc[ind].sync=(val!=0);
+ break;
+ case FILTER_ENABLED:
+ filter.enabled=(val!=0);
+ break;
+ case FILTER_ENV_AMOUNT:
+ filter.env_amount=val;
+ break;
+ case FILTER_ATTACK:
+ filter.env_settings.attack=val;
+ break;
+ case FILTER_DECAY:
+ filter.env_settings.decay=val;
+ break;
+ case FILTER_SUSTAIN:
+ filter.env_settings.sustain=val;
+ break;
+ case FILTER_RELEASE:
+ filter.env_settings.release=val;
+ break;
+ case FILTER_HOLD:
+ filter.env_settings.hold=(val!=0);
+ break;
+ case FILTER_OFFSET:
+ filter.freqfactor_offset=val;
+ break;
+ case FILTER_RESONANCE:
+ filter.resonance=val;
+ break;
+ case FILTER_TREMOLO:
+ filter.trem_strength=int(val);
+ break;
+ case FILTER_TREM_LFO:
+ if (strval=="snh")
+ filter.trem_lfo=SNH_LFO;
+ else
+ {
+ filter.trem_lfo=int(val);
+ if ((val<0) || (val>=N_LFOS))
+ throw string("invalid value for filter_trem_lfo");
+ }
+ break;
+ case SYNC_FACTOR:
+ sync_factor=val*ONE;
+ break;
+ default:
+ throw string("unknown variable ('"+array+"')");
+ }
+ break;
+
+ case 5: //read which params shall be variable, even if
+ //there are currently no controllers which change them
+ case 4: //read velocity-influence over certain params
+ case 2: //read how controllers influence parameters
+ p=param_to_enum(array);
+
+ ind=extract_array_index(var,1);
+ if ( param_needs_index(p) && (!((ind>=0) && (ind<n_osc))) )
+ throw string("out of array bounds");
+
+ if (state==4) //velocity-influence
+ {
+ switch (p)
+ {
+ case MODULATION:
+ case OUTPUT:
+ case FILTER_ENV_AMOUNT:
+ case FILTER_RESONANCE:
+ case FILTER_OFFSET:
+ // everything ok, do nothing
+ break;
+
+ default: // other params than the above may not be influenced!
+ throw string("velocity cannot influence parameter '"+array+"'");
+ }
+ }
+
+
+ switch (p)
+ {
+ case MODULATION:
+ ind2=extract_array_index(var,2);
+ if (!((ind2>=0) && (ind2<n_osc)))
+ throw string("out of array bounds");
+
+ osc[ind].fm_strength_const[ind2]=false;
+ break;
+ case OUTPUT:
+ if (state==4) // vel.-influence
+ {
+ if (isfloat(strval)) //is it a plain number, not a formula?
+ osc[ind].output_no_pfactor=true;
+ }
+ else
+ osc[ind].output_const=false; break;
+ case WAVEFORM:
+ osc[ind].waveform_const=false; break;
+ case FACTOR:
+ osc[ind].factor_const=false; break;
+ case TREMOLO:
+ osc[ind].tremolo_depth_const=false; break;
+ case TREM_LFO:
+ osc[ind].tremolo_lfo_const=false; break;
+ case VIBRATO:
+ osc[ind].vibrato_depth_const=false; break;
+ case VIB_LFO:
+ osc[ind].vibrato_lfo_const=false; break;
+ case ATTACK:
+ env[ind].attack_const=false; break;
+ case DECAY:
+ env[ind].decay_const=false; break;
+ case SUSTAIN:
+ env[ind].sustain_const=false; break;
+ case RELEASE:
+ env[ind].release_const=false; break;
+ case HOLD:
+ env[ind].hold_const=false; break;
+ case KSR:
+ osc[ind].ksr_const=false; break;
+ case KSL:
+ osc[ind].ksl_const=false; break;
+ case SYNC:
+ osc[ind].sync_const=false; break;
+ case FILTER_ENABLED:
+ filter.enabled_const=false; break;
+ case FILTER_ENV_AMOUNT:
+ filter.env_amount_const=false; break;
+ case FILTER_ATTACK:
+ filter.env_settings.attack_const=false; break;
+ case FILTER_DECAY:
+ filter.env_settings.decay_const=false; break;
+ case FILTER_SUSTAIN:
+ filter.env_settings.sustain_const=false; break;
+ case FILTER_RELEASE:
+ filter.env_settings.release_const=false; break;
+ case FILTER_HOLD:
+ filter.env_settings.hold_const=false; break;
+ case FILTER_OFFSET:
+ filter.freqfactor_offset_const=false; break;
+ case FILTER_RESONANCE:
+ filter.resonance_const=false; break;
+ case FILTER_TREMOLO:
+ filter.trem_strength_const=false; break;
+ case FILTER_TREM_LFO:
+ filter.trem_lfo_const=false; break;
+ case SYNC_FACTOR:
+ sync_factor_const=false; break;
+ default:
+ throw string("unknown variable ('"+array+"')");
+ }
+
+
+
+ break;
+
+ case 3: //read controller default values
+ //ignored
+ break;
+ }
+ }
+ }
+
+
+ //some optimizations and checks
+
+ 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;
+ }
+
+ if ((sync_factor==0) && (sync_factor_const==true))
+ for (int i=0;i<n_osc;i++)
+ {
+ osc[i].sync=false;
+ osc[i].sync_const=true;
+ }
+
+
+
+ for (int i=0;i<n_osc;i++)
+ if ( (osc[i].output_no_pfactor==false) && !((osc[i].output==0) && (osc[i].output_const=true)) )
+ osc[i].output_const=false;
+
+ //end optimizations and checks
+
+ 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;
+ }
+ else
+ throw string ("could not open '"+fn+"'");
+
+ return result;
+ //no uninit / free of osc and env here, as it must be done by the caller
+}
+
+
+
diff --git a/note_compiler/parser.h b/note_compiler/parser.h
new file mode 100644
index 0000000..71e7545
--- /dev/null
+++ b/note_compiler/parser.h
@@ -0,0 +1,16 @@
+#ifndef __PARSER_H__
+#define __PARSET_H__
+
+
+#include <set>
+#include <map>
+#include <list>
+#include <string>
+
+#include "programs.h"
+
+using namespace std;
+
+program_t parse(string fn);
+
+#endif
diff --git a/note_compiler/plugin_factory/Makefile b/note_compiler/plugin_factory/Makefile
new file mode 100644
index 0000000..c99645d
--- /dev/null
+++ b/note_compiler/plugin_factory/Makefile
@@ -0,0 +1,34 @@
+CXX=g++
+CFLAGS=-Wall -fpic -O2 -pg
+CXXFLAGS=$(CFLAGS)
+LDFLAGS=-shared -fpic -Wl,-soname,libmystuff.so.1 -lc
+
+OBJ=envelope.o filter.o note_skel.o infile.o programs.o
+LIB=result.so
+
+DEPENDFILE = .depend
+
+
+SRC = $(OBJ:%.o=%.cpp)
+
+all: $(LIB)
+
+
+$(LIB): $(OBJ)
+ $(CXX) $(CXXFLAGS) -o $(LIB) $(OBJ) $(LDFLAGS)
+
+
+depend dep: $(SRC)
+ $(CC) -MM $(SRC) > $(DEPENDFILE)
+
+-include $(DEPENDFILE)
+
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c $<
+
+.PHONY: clean dep depend
+
+clean:
+ rm -f $(OBJ) $(LIB)
+
diff --git a/note_compiler/plugin_factory/channel.cpp b/note_compiler/plugin_factory/channel.cpp
new file mode 120000
index 0000000..792f620
--- /dev/null
+++ b/note_compiler/plugin_factory/channel.cpp
@@ -0,0 +1 @@
+../../synth/channel.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/channel.h b/note_compiler/plugin_factory/channel.h
new file mode 120000
index 0000000..6c30b75
--- /dev/null
+++ b/note_compiler/plugin_factory/channel.h
@@ -0,0 +1 @@
+../../synth/channel.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/cli.cpp b/note_compiler/plugin_factory/cli.cpp
new file mode 120000
index 0000000..93de14b
--- /dev/null
+++ b/note_compiler/plugin_factory/cli.cpp
@@ -0,0 +1 @@
+../../synth/cli.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/cli.h b/note_compiler/plugin_factory/cli.h
new file mode 120000
index 0000000..5a26149
--- /dev/null
+++ b/note_compiler/plugin_factory/cli.h
@@ -0,0 +1 @@
+../../synth/cli.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/defines.cpp b/note_compiler/plugin_factory/defines.cpp
new file mode 120000
index 0000000..dc04029
--- /dev/null
+++ b/note_compiler/plugin_factory/defines.cpp
@@ -0,0 +1 @@
+../../synth/defines.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/defines.h b/note_compiler/plugin_factory/defines.h
new file mode 120000
index 0000000..89519f4
--- /dev/null
+++ b/note_compiler/plugin_factory/defines.h
@@ -0,0 +1 @@
+../../synth/defines.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/envelope.cpp b/note_compiler/plugin_factory/envelope.cpp
new file mode 120000
index 0000000..3acf96b
--- /dev/null
+++ b/note_compiler/plugin_factory/envelope.cpp
@@ -0,0 +1 @@
+../../synth/envelope.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/envelope.h b/note_compiler/plugin_factory/envelope.h
new file mode 120000
index 0000000..76975f0
--- /dev/null
+++ b/note_compiler/plugin_factory/envelope.h
@@ -0,0 +1 @@
+../../synth/envelope.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/filter.cpp b/note_compiler/plugin_factory/filter.cpp
new file mode 120000
index 0000000..04ac153
--- /dev/null
+++ b/note_compiler/plugin_factory/filter.cpp
@@ -0,0 +1 @@
+../../synth/filter.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/filter.h b/note_compiler/plugin_factory/filter.h
new file mode 120000
index 0000000..406f7e6
--- /dev/null
+++ b/note_compiler/plugin_factory/filter.h
@@ -0,0 +1 @@
+../../synth/filter.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/fixed.h b/note_compiler/plugin_factory/fixed.h
new file mode 120000
index 0000000..e6e1fb0
--- /dev/null
+++ b/note_compiler/plugin_factory/fixed.h
@@ -0,0 +1 @@
+../../synth/fixed.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/globals.cpp b/note_compiler/plugin_factory/globals.cpp
new file mode 120000
index 0000000..b38aed3
--- /dev/null
+++ b/note_compiler/plugin_factory/globals.cpp
@@ -0,0 +1 @@
+../../synth/globals.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/globals.h b/note_compiler/plugin_factory/globals.h
new file mode 120000
index 0000000..0e3a295
--- /dev/null
+++ b/note_compiler/plugin_factory/globals.h
@@ -0,0 +1 @@
+../../synth/globals.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/infile.cpp b/note_compiler/plugin_factory/infile.cpp
new file mode 100644
index 0000000..3523fd8
--- /dev/null
+++ b/note_compiler/plugin_factory/infile.cpp
@@ -0,0 +1,392 @@
+#include <jack/jack.h>
+
+#include <cmath>
+#include <string>
+
+#include "defines.h"
+#include "programs.h"
+#include "envelope.h"
+#include "fixed.h"
+#include "filter.h"
+#include "note_skel.h"
+
+using namespace std;
+
+int filter_update_frames=0;
+int samp_rate=0;
+fixed_t** wave=NULL;
+fixed_t** curr_lfo=NULL;
+
+typedef void output_note_func_t(string s);
+typedef string IntToStr_func_t(int i);
+
+output_note_func_t* output_note=NULL;
+IntToStr_func_t* IntToStr=NULL;
+
+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);
+
+ void destroy();
+
+ private:
+ void do_ksl();
+ void do_ksr();
+
+ void recalc_factors();
+ void apply_pfactor();
+
+// member variables begin here
+
+ Envelope *env0;
+ Envelope *env1;
+
+ fixed_t *oscval;
+ fixed_t *old_oscval;
+
+ oscillator_t osc0;
+ oscillator_t osc1;
+
+ //sync is disabled
+
+ LowPassFilter filter;
+ filter_params_t filter_params;
+ int filter_update_counter;
+ Envelope *filter_envelope;
+
+ pfactor_value_t pfactor;
+ struct
+ {
+ oscillator_t osc0;
+ oscillator_t osc1;
+ filter_params_t filter_params;
+ } orig;
+// 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);
+}
+
+
+Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)
+{
+ curr_prg=&prg;
+
+ oscval=new fixed_t[2];
+ old_oscval=new fixed_t[2];
+ for (int i=0;i<2;i++)
+ oscval[i]=old_oscval[i]=0;
+
+ pfactor.out=new fixed_t [2];
+ pfactor.fm=new fixed_t* [2];
+ for (int i=0;i<2;i++)
+ pfactor.fm[i]=new fixed_t [2];
+
+ env0=new Envelope (prg.env_settings[0]);
+ env1=new Envelope (prg.env_settings[1]);
+
+ osc0=prg.osc_settings[0];
+ orig.osc0=prg.osc_settings[0];
+ osc1=prg.osc_settings[1];
+ orig.osc1=prg.osc_settings[1];
+
+ //initalize oscillator.phase to multiples of their wave resolution
+ osc0.phase=ONE * PHASE_INIT;
+ osc1.phase=init_custom_osc_phase(osc1.custom_wave->wave_len, osc1.custom_wave->samp_rate);
+
+ do_ksl();
+
+
+ filter_params=prg.filter_settings;
+ orig.filter_params=prg.filter_settings;
+ filter_envelope=new Envelope(filter_params.env_settings);
+ filter_update_counter=filter_update_frames;
+
+
+ portamento_frames=0;
+ set_portamento_frames(pf);
+
+ set_note(n);
+ freq=dest_freq;
+ set_vel(v);
+
+ pitchbend=pb;
+
+ program=prg_no;
+}
+
+Note::~Note()
+{
+ delete [] osc0.fm_strength;
+ delete env0;
+ delete pfactor.fm[0];
+
+ delete [] osc1.fm_strength;
+ delete env1;
+ delete pfactor.fm[1];
+
+
+ delete [] oscval;
+ delete [] old_oscval;
+
+ delete [] pfactor.out;
+ delete [] pfactor.fm;
+}
+void Note::destroy()
+{
+ delete this;
+}
+
+void Note::recalc_factors()
+{
+ pfactor.filter_env=calc_pfactor(curr_prg->pfactor.filter_env, vel);
+ pfactor.filter_res=calc_pfactor(curr_prg->pfactor.filter_res, vel);
+ pfactor.filter_offset=calc_pfactor(curr_prg->pfactor.filter_offset, vel);
+
+ for (int i=0;i<2;i++)
+ {
+ pfactor.out[i]=calc_pfactor(curr_prg->pfactor.out[i], vel);
+
+ for (int j=0;j<2;j++)
+ pfactor.fm[i][j]=calc_pfactor(curr_prg->pfactor.fm[i][j], vel);
+ }
+}
+void Note::apply_pfactor()
+{
+ filter_params.env_amount=orig.filter_params.env_amount*pfactor.filter_env /ONE;
+ filter_params.freqfactor_offset=orig.filter_params.freqfactor_offset*pfactor.filter_offset /ONE;
+ filter_params.resonance=orig.filter_params.resonance*pfactor.filter_res /ONE;
+
+ osc0.output=orig.osc0.output*pfactor.out[0] >>SCALE;
+ for (int i=0;i<2;i++)
+ osc0.fm_strength[i]=orig.osc0.fm_strength[i]*pfactor.fm[0][i] >>SCALE;
+ osc1.output=orig.osc1.output*pfactor.out[1] >>SCALE;
+ for (int i=0;i<2;i++)
+ osc1.fm_strength[i]=orig.osc1.fm_strength[i]*pfactor.fm[1][i] >>SCALE;
+}
+
+bool Note::still_active()
+{
+ if ( ((osc0.output>0) && (env0->still_active()))
+ || ((osc1.output>0) && (env1->still_active())) )
+ return true;
+ else
+ return false;
+}
+void Note::release()
+{
+ env0->release_key();
+ env1->release_key();
+
+ filter_envelope->release_key();
+}
+void Note::release_quickly(jack_nframes_t maxt)
+{
+ if (env0->get_release() > maxt)
+ env0->set_release(maxt);
+ env0->release_key();
+
+ if (env1->get_release() > maxt)
+ env1->set_release(maxt);
+ env1->release_key();
+
+}
+void Note::reattack()
+{
+ env0->reattack();
+ env1->reattack();
+
+ filter_envelope->reattack();
+}
+
+void Note::do_ksr()
+{
+ env0->set_ratefactor(1.0 / pow(freq>>SCALE, osc0.ksr));
+ env1->set_ratefactor(1.0 / pow(freq>>SCALE, osc1.ksr));
+}
+void Note::do_ksl()
+{
+}
+
+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;
+
+
+ //sync is disabled
+
+
+ osc0.phase+= (actual_freq*osc0.factor/samp_rate)>>SCALE;
+ oscval[0] = wave[0][ ( ( osc0.phase + ( + (old_oscval[1] * osc0.fm_strength[1]) >>SCALE ) ) * WAVE_RES >>SCALE ) % WAVE_RES ] * env0->get_level() >>SCALE;
+ //oscillator0 has no tremolo
+
+ osc1.phase+= (actual_freq*osc1.factor/samp_rate)>>SCALE;
+ oscval[1] = osc1.custom_wave->wave[ ( osc1.phase * osc1.custom_wave->samp_rate >>(2*SCALE) ) % osc1.custom_wave->wave_len ] * env1->get_level() >>SCALE;
+ //oscillator1 has no tremolo
+
+ fixed_t out = ( + osc0.output*oscval[0] + osc1.output*oscval[1] >>SCALE );
+
+
+ filter_update_counter++;
+ if (filter_update_counter>=filter_update_frames)
+ {
+ filter_update_counter=0;
+
+ float cutoff= float(actual_freq)/ONE *
+ float(curr_lfo[filter_params.trem_lfo][filter_params.trem_strength])/ONE *
+ ( filter_params.freqfactor_offset + filter_envelope->get_level() * filter_params.env_amount / float(ONE) );
+ filter.set_params( cutoff, filter_params.resonance );
+ }
+
+ filter.process_sample(&out);
+
+ return out;
+}
+
+void Note::set_param(const parameter_t &p, fixed_t v)
+{
+ oscillator_t* sel_osc=NULL;
+ oscillator_t* sel_orig_osc=NULL;
+ Envelope* sel_env=NULL;
+
+ switch (p.osc)
+ {
+ case 0: sel_osc=&osc0; sel_orig_osc=&orig.osc0; sel_env=env0; break;
+ case 1: sel_osc=&osc1; sel_orig_osc=&orig.osc1; sel_env=env1; break;
+
+ default: output_note("NOTE: trying to change the nonexistent oscillator"+IntToStr(p.osc));
+ }
+
+ if ( ((p.par==ATTACK) || (p.par==DECAY) || (p.par==SUSTAIN) ||
+ (p.par==RELEASE) || (p.par==HOLD)) && sel_env==NULL )
+ {
+ output_note("NOTE: cannot change parameter for envelope"+IntToStr(p.osc)+" because it's disabled");
+ return;
+ }
+
+ switch(p.par)
+ {
+ case ATTACK: sel_env->set_attack(v*samp_rate >>SCALE); break;
+ case DECAY: sel_env->set_decay(v*samp_rate >>SCALE); break;
+ case SUSTAIN: sel_env->set_sustain(v); break;
+ case RELEASE: sel_env->set_release(v*samp_rate >>SCALE); break;
+ case HOLD: sel_env->set_hold(v!=0); break;
+
+ case KSR: sel_osc->ksr=float(v)/ONE; break;
+ case KSL: sel_osc->ksl=float(v)/ONE; break;
+
+ case FACTOR: sel_osc->factor=v; break;
+ case TREMOLO: sel_osc->tremolo_depth=v; break;
+ case TREM_LFO: sel_osc->tremolo_lfo=v; break;
+ case VIBRATO: sel_osc->vibrato_depth=v; break;
+ case VIB_LFO: sel_osc->vibrato_lfo=v; break;
+ case WAVEFORM: sel_osc->waveform=v; break;
+ case SYNC: sel_osc->sync=(v!=0); break;
+ case MODULATION: sel_orig_osc->fm_strength[p.index]=v; apply_pfactor(); break;
+ case OUTPUT: sel_orig_osc->output=v; apply_pfactor(); break;
+
+
+ case FILTER_ENABLED: output_note("NOTE: cannot enable filter in playing notes"); break;
+ case FILTER_ENV_AMOUNT: orig.filter_params.env_amount=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_OFFSET: orig.filter_params.freqfactor_offset=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_RESONANCE: orig.filter_params.resonance=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_TREMOLO: filter_params.trem_strength=v; break;
+ case FILTER_TREM_LFO: filter_params.trem_lfo=v; 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 SYNC_FACTOR: output_note("NOTE: trying to set sync_factor, but it's disabled"); break;
+
+ default: throw string("trying to set an unknown parameter");
+ }
+}
+
+
+
+extern "C" NoteSkel* create_note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)
+{
+ if (wave==NULL)
+ throw string("FATAL: trying to create a new note from a shared object without initalizing\n"
+ " the object first! this should /never/ happen, please contact the developer");
+
+ return new Note(n,v,prg,pf,pb,prg_no);
+}
+
+extern "C" void init_vars(int sr, int fupfr, fixed_t **w, fixed_t **clfo, output_note_func_t* out_n, IntToStr_func_t* its)
+{
+ samp_rate=sr;
+ filter_update_frames=fupfr;
+ wave=w;
+ curr_lfo=clfo;
+ IntToStr=its;
+ output_note=out_n;
+}
+
+
diff --git a/note_compiler/plugin_factory/jack.cpp b/note_compiler/plugin_factory/jack.cpp
new file mode 120000
index 0000000..83a42b1
--- /dev/null
+++ b/note_compiler/plugin_factory/jack.cpp
@@ -0,0 +1 @@
+../../synth/jack.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/jack.h b/note_compiler/plugin_factory/jack.h
new file mode 120000
index 0000000..5c4c8cf
--- /dev/null
+++ b/note_compiler/plugin_factory/jack.h
@@ -0,0 +1 @@
+../../synth/jack.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/load.cpp b/note_compiler/plugin_factory/load.cpp
new file mode 120000
index 0000000..c08bf33
--- /dev/null
+++ b/note_compiler/plugin_factory/load.cpp
@@ -0,0 +1 @@
+../../synth/load.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/load.h b/note_compiler/plugin_factory/load.h
new file mode 120000
index 0000000..3f30401
--- /dev/null
+++ b/note_compiler/plugin_factory/load.h
@@ -0,0 +1 @@
+../../synth/load.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/main.cpp b/note_compiler/plugin_factory/main.cpp
new file mode 120000
index 0000000..b9733e2
--- /dev/null
+++ b/note_compiler/plugin_factory/main.cpp
@@ -0,0 +1 @@
+../../synth/main.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note.cpp b/note_compiler/plugin_factory/note.cpp
new file mode 120000
index 0000000..2b806ab
--- /dev/null
+++ b/note_compiler/plugin_factory/note.cpp
@@ -0,0 +1 @@
+../../synth/note.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note.h b/note_compiler/plugin_factory/note.h
new file mode 120000
index 0000000..200f314
--- /dev/null
+++ b/note_compiler/plugin_factory/note.h
@@ -0,0 +1 @@
+../../synth/note.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note_funcs.h b/note_compiler/plugin_factory/note_funcs.h
new file mode 120000
index 0000000..685d295
--- /dev/null
+++ b/note_compiler/plugin_factory/note_funcs.h
@@ -0,0 +1 @@
+../../synth/note_funcs.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note_loader.cpp b/note_compiler/plugin_factory/note_loader.cpp
new file mode 120000
index 0000000..e5cca64
--- /dev/null
+++ b/note_compiler/plugin_factory/note_loader.cpp
@@ -0,0 +1 @@
+../../synth/note_loader.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note_loader.h b/note_compiler/plugin_factory/note_loader.h
new file mode 120000
index 0000000..9155410
--- /dev/null
+++ b/note_compiler/plugin_factory/note_loader.h
@@ -0,0 +1 @@
+../../synth/note_loader.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note_skel.cpp b/note_compiler/plugin_factory/note_skel.cpp
new file mode 120000
index 0000000..e85be17
--- /dev/null
+++ b/note_compiler/plugin_factory/note_skel.cpp
@@ -0,0 +1 @@
+../../synth/note_skel.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/note_skel.h b/note_compiler/plugin_factory/note_skel.h
new file mode 120000
index 0000000..780165e
--- /dev/null
+++ b/note_compiler/plugin_factory/note_skel.h
@@ -0,0 +1 @@
+../../synth/note_skel.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/parser.cpp b/note_compiler/plugin_factory/parser.cpp
new file mode 120000
index 0000000..b849baf
--- /dev/null
+++ b/note_compiler/plugin_factory/parser.cpp
@@ -0,0 +1 @@
+../../synth/parser.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/parser.h b/note_compiler/plugin_factory/parser.h
new file mode 120000
index 0000000..c303d77
--- /dev/null
+++ b/note_compiler/plugin_factory/parser.h
@@ -0,0 +1 @@
+../../synth/parser.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/programs.cpp b/note_compiler/plugin_factory/programs.cpp
new file mode 120000
index 0000000..4a5fa05
--- /dev/null
+++ b/note_compiler/plugin_factory/programs.cpp
@@ -0,0 +1 @@
+../../synth/programs.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/programs.h b/note_compiler/plugin_factory/programs.h
new file mode 120000
index 0000000..77c6b54
--- /dev/null
+++ b/note_compiler/plugin_factory/programs.h
@@ -0,0 +1 @@
+../../synth/programs.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/readwave.cpp b/note_compiler/plugin_factory/readwave.cpp
new file mode 120000
index 0000000..d422f94
--- /dev/null
+++ b/note_compiler/plugin_factory/readwave.cpp
@@ -0,0 +1 @@
+../../synth/readwave.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/readwave.h b/note_compiler/plugin_factory/readwave.h
new file mode 120000
index 0000000..74f5e95
--- /dev/null
+++ b/note_compiler/plugin_factory/readwave.h
@@ -0,0 +1 @@
+../../synth/readwave.h \ No newline at end of file
diff --git a/note_compiler/plugin_factory/util.cpp b/note_compiler/plugin_factory/util.cpp
new file mode 120000
index 0000000..452cd9e
--- /dev/null
+++ b/note_compiler/plugin_factory/util.cpp
@@ -0,0 +1 @@
+../../synth/util.cpp \ No newline at end of file
diff --git a/note_compiler/plugin_factory/util.h b/note_compiler/plugin_factory/util.h
new file mode 120000
index 0000000..56353d9
--- /dev/null
+++ b/note_compiler/plugin_factory/util.h
@@ -0,0 +1 @@
+../../synth/util.h \ No newline at end of file
diff --git a/note_compiler/programs.h b/note_compiler/programs.h
new file mode 100644
index 0000000..9025ba1
--- /dev/null
+++ b/note_compiler/programs.h
@@ -0,0 +1,121 @@
+#ifndef __PROGRAMS_H__
+#define __PROGRAMS_H__
+
+
+#include "../synth/fixed.h"
+
+enum parameter_enum
+{
+ MODULATION=0,
+ OUTPUT,
+ WAVEFORM,
+ FACTOR,
+ TREMOLO,
+ TREM_LFO,
+ VIBRATO,
+ VIB_LFO,
+ ATTACK,
+ DECAY,
+ SUSTAIN,
+ RELEASE,
+ HOLD,
+ KSR,
+ KSL,
+ SYNC,
+ FILTER_ENABLED,
+ FILTER_ENV_AMOUNT,
+ FILTER_ATTACK,
+ FILTER_DECAY,
+ FILTER_SUSTAIN,
+ FILTER_RELEASE,
+ FILTER_HOLD,
+ FILTER_OFFSET,
+ FILTER_RESONANCE,
+ FILTER_TREMOLO,
+ FILTER_TREM_LFO,
+ SYNC_FACTOR,
+
+
+ PARAMETER_N_ENTRIES,
+ UNKNOWN=-1
+};
+
+
+struct oscillator_t
+{
+ fixed_t *fm_strength;
+ bool *fm_strength_const;
+ fixed_t output;
+ bool output_const;
+ bool output_no_pfactor;
+ int waveform;
+ bool waveform_const;
+ fixed_t factor;
+ bool factor_const;
+
+ fixed_t tremolo_depth;
+ bool tremolo_depth_const;
+ int tremolo_lfo;
+ bool tremolo_lfo_const;
+ fixed_t vibrato_depth;
+ bool vibrato_depth_const;
+ int vibrato_lfo;
+ bool vibrato_lfo_const;
+
+ bool have_custom_wave;
+
+ int n_osc;
+
+ float ksl;
+ bool ksl_const;
+ float ksr;
+ bool ksr_const;
+
+ bool sync;
+ bool sync_const;
+};
+
+struct env_settings_t
+{
+ bool enabled;
+ float attack;
+ bool attack_const;
+ float decay;
+ bool decay_const;
+ float sustain;
+ bool sustain_const;
+ float release;
+ bool release_const;
+ bool hold;
+ bool hold_const;
+};
+
+struct filter_params_t
+{
+ bool enabled;
+ bool enabled_const;
+ float resonance;
+ bool resonance_const;
+ float freqfactor_offset;
+ bool freqfactor_offset_const;
+ float env_amount;
+ bool env_amount_const;
+ int trem_strength;
+ bool trem_strength_const;
+ int trem_lfo;
+ bool trem_lfo_const;
+ env_settings_t env_settings;
+};
+
+struct program_t
+{
+ int n_osc;
+ oscillator_t *osc;
+ env_settings_t *env;
+ filter_params_t filter;
+
+ fixed_t sync_factor;
+ bool sync_factor_const;
+};
+
+#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..6759f56
--- /dev/null
+++ b/note_compiler/templates/head.1
@@ -0,0 +1,48 @@
+#include <jack/jack.h>
+
+#include <cmath>
+#include <string>
+
+#include "defines.h"
+#include "programs.h"
+#include "envelope.h"
+#include "fixed.h"
+#include "filter.h"
+#include "note_skel.h"
+
+using namespace std;
+
+int filter_update_frames=0;
+int samp_rate=0;
+fixed_t** wave=NULL;
+fixed_t** curr_lfo=NULL;
+
+typedef void output_note_func_t(string s);
+typedef string IntToStr_func_t(int i);
+
+output_note_func_t* output_note=NULL;
+IntToStr_func_t* IntToStr=NULL;
+
+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);
+
+ void destroy();
+
+ 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/note_compiler/templates/interface.1 b/note_compiler/templates/interface.1
new file mode 100644
index 0000000..cacc175
--- /dev/null
+++ b/note_compiler/templates/interface.1
@@ -0,0 +1,19 @@
+extern "C" NoteSkel* create_note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)
+{
+ if (wave==NULL)
+ throw string("FATAL: trying to create a new note from a shared object without initalizing\n"
+ " the object first! this should /never/ happen, please contact the developer");
+
+ return new Note(n,v,prg,pf,pb,prg_no);
+}
+
+extern "C" void init_vars(int sr, int fupfr, fixed_t **w, fixed_t **clfo, output_note_func_t* out_n, IntToStr_func_t* its)
+{
+ samp_rate=sr;
+ filter_update_frames=fupfr;
+ wave=w;
+ curr_lfo=clfo;
+ IntToStr=its;
+ output_note=out_n;
+}
+
diff --git a/note_compiler/templates/set_param.1 b/note_compiler/templates/set_param.1
new file mode 100644
index 0000000..21fc983
--- /dev/null
+++ b/note_compiler/templates/set_param.1
@@ -0,0 +1,27 @@
+ if ( ((p.par==ATTACK) || (p.par==DECAY) || (p.par==SUSTAIN) ||
+ (p.par==RELEASE) || (p.par==HOLD)) && sel_env==NULL )
+ {
+ output_note("NOTE: cannot change parameter for envelope"+IntToStr(p.osc)+" because it's disabled");
+ return;
+ }
+
+ switch(p.par)
+ {
+ case ATTACK: sel_env->set_attack(v*samp_rate >>SCALE); break;
+ case DECAY: sel_env->set_decay(v*samp_rate >>SCALE); break;
+ case SUSTAIN: sel_env->set_sustain(v); break;
+ case RELEASE: sel_env->set_release(v*samp_rate >>SCALE); break;
+ case HOLD: sel_env->set_hold(v!=0); break;
+
+ case KSR: sel_osc->ksr=float(v)/ONE; break;
+ case KSL: sel_osc->ksl=float(v)/ONE; break;
+
+ case FACTOR: sel_osc->factor=v; break;
+ case TREMOLO: sel_osc->tremolo_depth=v; break;
+ case TREM_LFO: sel_osc->tremolo_lfo=v; break;
+ case VIBRATO: sel_osc->vibrato_depth=v; break;
+ case VIB_LFO: sel_osc->vibrato_lfo=v; break;
+ case WAVEFORM: sel_osc->waveform=v; break;
+ case SYNC: sel_osc->sync=(v!=0); break;
+ case MODULATION: sel_orig_osc->fm_strength[p.index]=v; apply_pfactor(); break;
+ case OUTPUT: sel_orig_osc->output=v; apply_pfactor(); break;
diff --git a/note_compiler/templates/set_param.filter b/note_compiler/templates/set_param.filter
new file mode 100644
index 0000000..797d30b
--- /dev/null
+++ b/note_compiler/templates/set_param.filter
@@ -0,0 +1,7 @@
+
+ case FILTER_ENABLED: output_note("NOTE: cannot enable filter in playing notes"); break;
+ case FILTER_ENV_AMOUNT: orig.filter_params.env_amount=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_OFFSET: orig.filter_params.freqfactor_offset=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_RESONANCE: orig.filter_params.resonance=float(v)/ONE; apply_pfactor(); break;
+ case FILTER_TREMOLO: filter_params.trem_strength=v; break;
+ case FILTER_TREM_LFO: filter_params.trem_lfo=v; break;
diff --git a/note_compiler/templates/set_param.filterenv b/note_compiler/templates/set_param.filterenv
new file mode 100644
index 0000000..aaa21b4
--- /dev/null
+++ b/note_compiler/templates/set_param.filterenv
@@ -0,0 +1,34 @@
+ 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;
diff --git a/note_compiler/templates/set_param.nofilter b/note_compiler/templates/set_param.nofilter
new file mode 100644
index 0000000..e9ee336
--- /dev/null
+++ b/note_compiler/templates/set_param.nofilter
@@ -0,0 +1,13 @@
+ case FILTER_ENABLED:
+ case FILTER_ENV_AMOUNT:
+ case FILTER_ATTACK:
+ case FILTER_DECAY:
+ case FILTER_SUSTAIN:
+ case FILTER_RELEASE:
+ case FILTER_HOLD:
+ case FILTER_OFFSET:
+ case FILTER_RESONANCE:
+ case FILTER_TREMOLO:
+ case FILTER_TREM_LFO:
+ output_note("NOTE: trying to set some filter-param, but filter is disabled");
+ break;
diff --git a/note_compiler/templates/set_param.nofilterenv b/note_compiler/templates/set_param.nofilterenv
new file mode 100644
index 0000000..23ad36d
--- /dev/null
+++ b/note_compiler/templates/set_param.nofilterenv
@@ -0,0 +1,7 @@
+ case FILTER_ATTACK:
+ case FILTER_DECAY:
+ case FILTER_SUSTAIN:
+ case FILTER_RELEASE:
+ case FILTER_HOLD:
+ output_note("NOTE: trying to change filter envelope, but that envelope is disabled");
+ break;
diff --git a/note_compiler/util.cpp b/note_compiler/util.cpp
new file mode 100644
index 0000000..f73b8bb
--- /dev/null
+++ b/note_compiler/util.cpp
@@ -0,0 +1,208 @@
+#include <iostream>
+#include <sstream>
+
+#include "util.h"
+
+string IntToStr(int i)
+{
+ ostringstream s;
+ s<<i;
+ return s.str();
+}
+
+string IntToStrHex(int i)
+{
+ ostringstream s;
+ s<<std::hex << i;
+ return s.str();
+}
+
+bool isnum(string s)
+{
+ for (size_t i=0;i<s.length();i++)
+ if (!isdigit(s[i]))
+ return false;
+
+ return true;
+}
+
+bool isfloat(string s)
+{
+ return (s.find_first_not_of("0123456789.")==string::npos);
+}
+
+
+string remove_all_spaces(string s)
+{
+ string result;
+
+ for (size_t i=0; i<s.length(); i++)
+ if ((s[i]!=' ') && (s[i]!='\t'))
+ result+=s[i];
+
+ return result;
+}
+
+string trim_spaces(string s)
+{
+ string result;
+ int i;
+
+ for (i=0;i<s.length();i++)
+ if ((s[i]!=' ') && (s[i]!='\t'))
+ break;
+
+ if (i!=s.length())
+ {
+ result=s.substr(i);
+ for (i=result.length()-1;i>=0;i--)
+ if ((result[i]!=' ') && (result[i]!='\t'))
+ break;
+
+ if (i>=0)
+ return result.substr(0,i+1);
+ else
+ return "";
+ }
+ else
+ {
+ return "";
+ }
+}
+
+/*
+void output_warning(string s)
+{
+ cout << s << endl;
+ if (fatal_warnings) throw string(s);
+}
+
+void output_note(string s)
+{
+ if (!quiet) cout << s << endl;
+}
+
+void output_verbose(string s)
+{
+ if (verbose) cout << s << endl;
+}
+*/
+
+
+bool param_needs_index(parameter_enum p)
+{
+ switch (p)
+ {
+ case FILTER_ENABLED:
+
+ case FILTER_ATTACK:
+ case FILTER_DECAY:
+ case FILTER_SUSTAIN:
+ case FILTER_RELEASE:
+ case FILTER_HOLD:
+ case FILTER_ENV_AMOUNT:
+
+ case FILTER_OFFSET:
+ case FILTER_RESONANCE:
+
+ case FILTER_TREMOLO:
+ case FILTER_TREM_LFO:
+
+ case SYNC_FACTOR:
+ return false;
+
+ default: return true;
+ }
+}
+
+parameter_enum param_to_enum(string param)
+{
+ if (param=="mod")
+ return MODULATION;
+ else if (param=="out")
+ return OUTPUT;
+ else if (param=="waveform")
+ return WAVEFORM;
+ else if (param=="sync")
+ return SYNC;
+ else if (param=="factor")
+ return FACTOR;
+ else if (param=="trem")
+ return TREMOLO;
+ else if (param=="trem_lfo")
+ return TREM_LFO;
+ else if (param=="vib")
+ return VIBRATO;
+ else if (param=="vib_lfo")
+ return VIB_LFO;
+ else if (param=="attack")
+ return ATTACK;
+ else if (param=="decay")
+ return DECAY;
+ else if (param=="sustain")
+ return SUSTAIN;
+ else if (param=="release")
+ return RELEASE;
+ else if (param=="hold")
+ return HOLD;
+ else if (param=="ksl")
+ return KSL;
+ else if (param=="ksr")
+ return KSR;
+ else if (param=="filter.enabled")
+ return FILTER_ENABLED;
+ else if (param=="filter.env_amount")
+ return FILTER_ENV_AMOUNT;
+ else if (param=="filter.attack")
+ return FILTER_ATTACK;
+ else if (param=="filter.decay")
+ return FILTER_DECAY;
+ else if (param=="filter.sustain")
+ return FILTER_SUSTAIN;
+ else if (param=="filter.release")
+ return FILTER_RELEASE;
+ else if (param=="filter.hold")
+ return FILTER_HOLD;
+ else if (param=="filter.offset")
+ return FILTER_OFFSET;
+ else if (param=="filter.resonance")
+ return FILTER_RESONANCE;
+ else if (param=="filter.trem")
+ return FILTER_TREMOLO;
+ else if (param=="filter.trem_lfo")
+ return FILTER_TREM_LFO;
+ else if (param=="sync_factor")
+ return SYNC_FACTOR;
+ else
+ return UNKNOWN;
+}
+
+string extract_var(string s)
+{
+ size_t p;
+ p=s.find('=');
+ if (p!=string::npos)
+ return s.substr(0,p);
+ else
+ return "";
+}
+
+string extract_val(string s)
+{
+ size_t p;
+ p=s.find('=');
+ if (p!=string::npos)
+ return s.substr(p+1);
+ else
+ return s;
+}
+
+string fileext(string f)
+{
+ size_t pos;
+ pos=f.rfind('.');
+ if (pos!=string::npos)
+ return f.substr(pos+1);
+ else
+ return "";
+}
diff --git a/note_compiler/util.h b/note_compiler/util.h
new file mode 100644
index 0000000..e571c7d
--- /dev/null
+++ b/note_compiler/util.h
@@ -0,0 +1,31 @@
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <string>
+#include "programs.h"
+
+using namespace std;
+
+string IntToStr(int i);
+string IntToStrHex(int i);
+
+bool isnum(string s);
+bool isfloat(string s);
+
+string remove_all_spaces(string s);
+string trim_spaces(string s);
+
+void output_warning(string s);
+void output_note(string s);
+void output_verbose(string s);
+
+bool param_needs_index(parameter_enum p);
+parameter_enum param_to_enum(string param);
+
+string extract_var(string s);
+string extract_val(string s);
+
+string fileext(string f);
+
+
+#endif
diff --git a/synth/.depend b/synth/.depend
index 3a0b0ed..fb0d8aa 100644
--- a/synth/.depend
+++ b/synth/.depend
@@ -1,25 +1,31 @@
-channel.o: channel.cpp channel.h fixed.h programs.h note.h envelope.h \
- filter.h defines.h util.h globals.h
-cli.o: cli.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h load.h
+channel.o: channel.cpp channel.h fixed.h programs.h note_funcs.h \
+ note_skel.h defines.h util.h globals.h note.h envelope.h filter.h
+cli.o: cli.cpp util.h programs.h fixed.h note_funcs.h globals.h channel.h \
+ note_skel.h defines.h load.h
defines.o: defines.cpp defines.h
-envelope.o: envelope.cpp envelope.h programs.h fixed.h
+envelope.o: envelope.cpp envelope.h programs.h fixed.h note_funcs.h
filter.o: filter.cpp filter.h fixed.h defines.h globals.h programs.h \
- channel.h note.h envelope.h util.h
-globals.o: globals.cpp globals.h programs.h fixed.h channel.h note.h \
- envelope.h filter.h defines.h util.h
-jack.o: jack.cpp defines.h globals.h programs.h fixed.h channel.h note.h \
- envelope.h filter.h util.h jack.h
-load.o: load.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h
+ note_funcs.h channel.h note_skel.h util.h
+globals.o: globals.cpp globals.h programs.h fixed.h note_funcs.h \
+ channel.h note_skel.h defines.h util.h
+jack.o: jack.cpp defines.h globals.h programs.h fixed.h note_funcs.h \
+ channel.h note_skel.h util.h jack.h
+load.o: load.cpp util.h programs.h fixed.h note_funcs.h globals.h \
+ channel.h note_skel.h defines.h
main.o: main.cpp jack.h load.h cli.h parser.h fixed.h programs.h \
- channel.h note.h envelope.h filter.h defines.h util.h globals.h
-note.o: note.cpp note.h programs.h fixed.h envelope.h filter.h globals.h \
- channel.h defines.h util.h
-parser.o: parser.cpp parser.h fixed.h programs.h defines.h globals.h \
- channel.h note.h envelope.h filter.h util.h readwave.h
-programs.o: programs.cpp programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h util.h
-readwave.o: readwave.cpp readwave.h programs.h fixed.h util.h
-util.o: util.cpp util.h programs.h fixed.h globals.h channel.h note.h \
- envelope.h filter.h defines.h
+ note_funcs.h channel.h note_skel.h defines.h util.h globals.h \
+ note_loader.h
+note.o: note.cpp note.h programs.h fixed.h note_funcs.h envelope.h \
+ filter.h note_skel.h globals.h channel.h defines.h util.h
+note_skel.o: note_skel.cpp note_skel.h programs.h fixed.h note_funcs.h \
+ globals.h channel.h defines.h util.h
+parser.o: parser.cpp parser.h fixed.h programs.h note_funcs.h defines.h \
+ globals.h channel.h note_skel.h util.h readwave.h
+programs.o: programs.cpp programs.h fixed.h note_funcs.h globals.h \
+ channel.h note_skel.h defines.h util.h
+readwave.o: readwave.cpp readwave.h programs.h fixed.h note_funcs.h \
+ util.h
+util.o: util.cpp util.h programs.h fixed.h note_funcs.h globals.h \
+ channel.h note_skel.h defines.h
+note_loader.o: note_loader.cpp note_loader.h programs.h fixed.h \
+ note_funcs.h globals.h channel.h note_skel.h defines.h util.h
diff --git a/synth/Makefile b/synth/Makefile
index f84441c..c1d6dab 100644
--- a/synth/Makefile
+++ b/synth/Makefile
@@ -1,9 +1,9 @@
CXX=g++
-CFLAGS=-Wall -g
+CFLAGS=-Wall -O2
CXXFLAGS=$(CFLAGS)
LDFLAGS=-lm `pkg-config --cflags --libs jack`
-OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o
+OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o note_loader.o
BIN=synth
DEPENDFILE = .depend
diff --git a/synth/channel.cpp b/synth/channel.cpp
index 6446b0f..0042162 100644
--- a/synth/channel.cpp
+++ b/synth/channel.cpp
@@ -3,6 +3,11 @@
#include "math.h"
#include "globals.h"
+#include "note.h"
+
+#include "note_funcs.h"
+
+
Channel::Channel()
{
volume=ONE;
@@ -32,11 +37,11 @@ Channel::~Channel()
void Channel::cleanup()
{
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
for (it=notes.begin(); it!=notes.end(); it++)
if ((*it)->still_active()==false)
{
- delete *it;
+ (*it)->destroy();
it=notes.erase(it);
}
}
@@ -45,7 +50,7 @@ fixed_t Channel::get_sample()
{
fixed_t sum=0;
- for (list<Note*>::iterator it=notes.begin(); it!=notes.end(); it++)
+ for (list<NoteSkel*>::iterator it=notes.begin(); it!=notes.end(); it++)
sum+=(*it)->get_sample();
return sum*volume >>SCALE;
@@ -82,14 +87,14 @@ void Channel::note_off(int note)
void Channel::really_do_note_off(int note)
{
- for (list<Note*>::iterator it=notes.begin(); it!=notes.end(); it++)
+ for (list<NoteSkel*>::iterator it=notes.begin(); it!=notes.end(); it++)
if ((*it)->get_note()==note)
(*it)->release();
}
void Channel::note_on(int note, int vel)
{
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
if (vel>0) //note on
{
pressed_keys.insert(note);
@@ -97,22 +102,29 @@ void Channel::note_on(int note, int vel)
if ( (n_voices==1) && (!notes.empty()) ) //we're in monomode
{
//no need to create a new note; reuse the existing
- Note *n; //i'm lazy
+ NoteSkel *n; //i'm lazy
n= *(notes.begin());
if (n->get_program() != program)
{
//if the program has changed, kill the previous note and
//create a new one
- delete n;
+ n->destroy();
notes.clear();
- notes.push_back( new Note(note,(float)vel/128.0,
- curr_prg,
- portamento_frames,
- pitchbend,
- program) );
-
+ NoteSkel *newnote=NULL;
+ if (curr_prg.create_func==NULL)
+ newnote = new Note(note,(float)vel/128.0,
+ curr_prg,
+ portamento_frames, pitchbend,
+ program);
+ else
+ newnote = curr_prg.create_func(note,(float)vel/128.0,
+ curr_prg,
+ portamento_frames, pitchbend,
+ program);
+
+ notes.push_back(newnote);
}
else //program did not change
{
@@ -139,11 +151,22 @@ void Channel::note_on(int note, int vel)
}
if (neednewnote)
- notes.push_back( new Note(note,(float)vel/128.0,
- curr_prg,
- portamento_frames,
- pitchbend,
- program) );
+ {
+ NoteSkel *newnote=NULL;
+ if (curr_prg.create_func==NULL)
+ newnote = new Note(note,(float)vel/128.0,
+ curr_prg,
+ portamento_frames, pitchbend,
+ program);
+ else
+ newnote = curr_prg.create_func(note,(float)vel/128.0,
+ curr_prg,
+ portamento_frames, pitchbend,
+ program);
+
+ notes.push_back(newnote);
+ }
+
apply_voice_limit();
}
}
@@ -171,7 +194,7 @@ void Channel::apply_voice_limit()
int diff=notes.size()-n_voices;
if (diff>0)
{
- list<Note*>::iterator it=notes.begin();
+ list<NoteSkel*>::iterator it=notes.begin();
if (quick_release)
for (int i=0;i<diff;i++)
@@ -182,7 +205,7 @@ void Channel::apply_voice_limit()
else
for (int i=0;i<diff;i++)
{
- delete (*it);
+ (*it)->destroy();
it=notes.erase(it);
}
}
@@ -259,7 +282,7 @@ void Channel::recalc_param(const parameter_t &par, program_t &prg)
// waveform etc it's in int (i.e., val/ONE is very small, while
// val is what we want)
- for (list<Note*>::iterator it=notes.begin(); it!=notes.end(); it++)
+ for (list<NoteSkel*>::iterator it=notes.begin(); it!=notes.end(); it++)
(*it)->set_param(par, val);
curr_prg.set_param(par, val);
@@ -320,7 +343,7 @@ void Channel::set_real_portamento_frames()
else
portamento_frames=0;
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
for (it=notes.begin(); it!=notes.end(); it++)
(*it)->set_portamento_frames(portamento_frames);
}
@@ -374,17 +397,17 @@ void Channel::set_legato_pedal(bool newstate)
void Channel::panic()
{
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
for (it=notes.begin(); it!=notes.end();)
{
- delete *it;
+ (*it)->destroy();
it=notes.erase(it);
}
}
void Channel::release_all()
{
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
for (it=notes.begin(); it!=notes.end(); it++)
(*it)->release();
}
@@ -399,7 +422,7 @@ void Channel::set_pitch_bend(float val)
{
pitchbend=pow(2.0,val/12.0)*ONE;
- list<Note*>::iterator it;
+ list<NoteSkel*>::iterator it;
for (it=notes.begin(); it!=notes.end(); it++)
(*it)->set_pitchbend(pitchbend);
}
diff --git a/synth/channel.h b/synth/channel.h
index f673294..b0a855a 100644
--- a/synth/channel.h
+++ b/synth/channel.h
@@ -7,7 +7,7 @@
#include "fixed.h"
#include "programs.h"
-#include "note.h"
+#include "note_skel.h"
#include "defines.h"
#include "util.h"
@@ -55,7 +55,7 @@ class Channel
fixed_t pitchbend;
float max_pitchbend;
- std::list<Note*> notes;
+ std::list<NoteSkel*> notes;
bool do_portamento;
diff --git a/synth/globals.cpp b/synth/globals.cpp
index e932fcb..6a84353 100644
--- a/synth/globals.cpp
+++ b/synth/globals.cpp
@@ -3,7 +3,7 @@
fixed_t **lfo[N_LFOS];
fixed_t *curr_lfo[N_LFOS+1];
-fixed_t wave[N_WAVEFORMS][WAVE_RES];
+fixed_t* wave[N_WAVEFORMS];
fixed_t sample_and_hold[N_LFO_LEVELS];
diff --git a/synth/globals.h b/synth/globals.h
index efbbe72..ffc1de5 100644
--- a/synth/globals.h
+++ b/synth/globals.h
@@ -14,7 +14,7 @@ using namespace std;
extern fixed_t **lfo[N_LFOS];
extern fixed_t *curr_lfo[N_LFOS+1];
-extern fixed_t wave[N_WAVEFORMS][WAVE_RES];
+extern fixed_t* wave[N_WAVEFORMS];
extern fixed_t sample_and_hold[N_LFO_LEVELS];
diff --git a/synth/jack.cpp b/synth/jack.cpp
index 093e9b5..3949722 100644
--- a/synth/jack.cpp
+++ b/synth/jack.cpp
@@ -12,7 +12,7 @@
using namespace std;
-//#define DO_DEBUGGING_EVENTS
+#define DO_DEBUGGING_EVENTS
jack_port_t *midi_in;
jack_port_t *out_port[N_CHANNELS];
@@ -317,7 +317,7 @@ int process_callback(jack_nframes_t nframes, void *notused)
}
else if (tmp2==0)
{
- if (lastframe>tmp+44100*2)
+ if (lastframe>tmp+44100*1)
{
tmp2=1;
cout << "BÄÄM" << endl;
@@ -326,17 +326,53 @@ int process_callback(jack_nframes_t nframes, void *notused)
}
else if (tmp2==1)
{
- if (lastframe>tmp+44100*4)
+ if (lastframe>tmp+44100*2)
{
tmp2=2;
channel[0]->event(0x90,87,5);
- channel[0]->set_controller(57, 127);
+ channel[0]->set_controller(58, 0);
+ cout << "BÄÄM2" << endl;
+ }
+ }
+ else if (tmp2==2)
+ {
+ if (lastframe>tmp+44100*3)
+ {
+ tmp2=3;
+ channel[0]->event(0x90,90,127);
+ cout << "BÄÄM2" << endl;
+ }
+ }
+ else if (tmp2==3)
+ {
+ if (lastframe>tmp+44100*4)
+ {
+ tmp2=4;
+ channel[0]->event(0x90,60,96);
+ cout << "BÄÄM2" << endl;
+ }
+ }
+ else if (tmp2==4)
+ {
+ if (lastframe>tmp+44100*5)
+ {
+ tmp2=5;
+ channel[0]->event(0x90,63,32);
+ cout << "BÄÄM2" << endl;
+ }
+ }
+ else if (tmp2==5)
+ {
+ if (lastframe>tmp+44100*6)
+ {
+ tmp2=6;
+ channel[0]->event(0x90,66,60);
cout << "BÄÄM2" << endl;
}
}
else
{
- if (lastframe>tmp+44100*10)
+ if (lastframe>tmp+44100*8)
{
cout << "finished" << endl;
exit(0);
diff --git a/synth/main.cpp b/synth/main.cpp
index 95444cb..1c8dd4c 100644
--- a/synth/main.cpp
+++ b/synth/main.cpp
@@ -12,6 +12,7 @@
#include "programs.h"
#include "defines.h"
#include "globals.h"
+#include "note_loader.h"
using namespace std;
@@ -106,6 +107,23 @@ int main(int argc, char** argv)
try
{
program_settings[i]=parse(programfile[i]);
+
+ // try to load the appropriate .so file
+ if (access( (programfile[i]+".so").c_str(), R_OK ) == 0)
+ {
+ try
+ {
+ load_note_from_so(programfile[i]+".so", program_settings[i]);
+ output_verbose("NOTE: loaded shared object for program '"+programfile[i]+"'");
+ }
+ catch (string err)
+ {
+ output_note("NOTE: could not load shared object '"+programfile[i]+".so"+"':\n"
+ " "+err+"\n"
+ " this is not fatal, the note has been loaded properly, but generic\n"
+ " unoptimized (slow) code will be used.");
+ }
+ }
}
catch (string err)
{
@@ -121,7 +139,9 @@ int main(int argc, char** argv)
}
}
-
+ for (i=0;i<N_WAVEFORMS;i++)
+ wave[i]=new fixed_t[WAVE_RES];
+
for (i=0;i<WAVE_RES;i++)
{
wave[0][i]=sin(i*2.0*3.141592654/WAVE_RES)*ONE;
@@ -165,6 +185,9 @@ void cleanup()
channel[i]=NULL;
}
+ for (int i=0;i<128;i++)
+ maybe_unload_note(program_settings[i]);
+
delete [] program_settings;
}
diff --git a/synth/note.cpp b/synth/note.cpp
index a9a5a42..b6bfa22 100644
--- a/synth/note.cpp
+++ b/synth/note.cpp
@@ -1,4 +1,3 @@
-#include <string>
#include <cmath>
#include "note.h"
@@ -17,8 +16,12 @@ inline fixed_t init_custom_osc_phase(int len, fixed_t sr)
Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no)
{
+
curr_prg=&prg;
+
+
+
n_oscillators=prg.n_osc;
@@ -62,17 +65,8 @@ Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int pr
}
- portamento_frames=0;
- set_portamento_frames(pf);
-
- set_note(n);
- freq=dest_freq;
- set_vel(v);
do_ksl();
- pitchbend=pb;
-
- program=prg_no;
filter_params=prg.filter_settings;
orig.filter_params=prg.filter_settings;
@@ -88,6 +82,22 @@ Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int pr
sync_factor=prg.sync_factor;
sync_phase=0;
+
+
+
+
+ portamento_frames=0;
+ set_portamento_frames(pf);
+
+ set_note(n);
+ freq=dest_freq;
+ set_vel(v);
+
+ pitchbend=pb;
+
+ program=prg_no;
+
+
}
Note::~Note()
@@ -262,52 +272,6 @@ void Note::reattack()
filter_envelope->reattack();
}
-void Note::set_pitchbend(fixed_t pb)
-{
- pitchbend=pb;
-}
-
-void Note::set_freq(float f)
-{
- old_freq=freq;
- dest_freq=f*ONE;
- portamento_t=0;
-
- do_ksr();
-}
-
-void Note::set_freq(float f, bool do_port)
-{
- set_freq(f);
-
- if (!do_port)
- old_freq=dest_freq;
-}
-
-void Note::set_note(int n)
-{
- note=n;
- set_freq(440.0*pow(2.0,(float)(n-69)/12.0));
-}
-
-void Note::set_note(int n, bool do_port)
-{
- note=n;
- set_freq(440.0*pow(2.0,(float)(n-69)/12.0), do_port);
-}
-
-int Note::get_note()
-{
- return note;
-}
-
-void Note::set_vel(float v)
-{
- vel=v*ONE;
-
- recalc_factors();
- apply_pfactor();
-}
void Note::do_ksl()
{ //osc.ksl is in Bel/octave (i.e. dB/10)
@@ -328,12 +292,6 @@ void Note::do_ksr()
envelope[i]->set_ratefactor(1.0 / pow(freq>>SCALE, oscillator[i].ksr));
}
-void Note::set_portamento_frames(jack_nframes_t t)
-{
- portamento_frames=t;
- portamento_t=0;
-}
-
fixed_t Note::get_sample()
{
if (freq!=dest_freq)
@@ -450,3 +408,8 @@ fixed_t Note::get_sample()
return out;
}
}
+
+void Note::destroy()
+{
+ delete this;
+}
diff --git a/synth/note.h b/synth/note.h
index 26ce379..03a7180 100644
--- a/synth/note.h
+++ b/synth/note.h
@@ -7,27 +7,22 @@
#include "envelope.h"
#include "fixed.h"
#include "filter.h"
+#include "note_skel.h"
-class Note
+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();
- int get_note();
- void set_note(int n);
- void set_note(int n, bool do_port);
- void set_freq(float f);
- void set_freq(float f, bool do_port);
- void set_pitchbend(fixed_t pb);
- void set_vel(float v);
- void set_portamento_frames(jack_nframes_t f);
+
void release_quickly(jack_nframes_t maxt);
void release();
void reattack();
bool still_active();
void set_param(const parameter_t &p, fixed_t v);
- int get_program(){return program;}
+
+ void destroy();
private:
void do_ksl();
@@ -37,10 +32,6 @@ class Note
void apply_pfactor();
Envelope **envelope;
-
- fixed_t freq, dest_freq, old_freq;
- fixed_t vel;
- jack_nframes_t portamento_t, portamento_frames;
int env_frame_counter;
@@ -55,12 +46,6 @@ class Note
pfactor_value_t pfactor;
- int note;
- int program;
- program_t *curr_prg;
-
- fixed_t pitchbend;
-
LowPassFilter filter;
Envelope *filter_envelope;
filter_params_t filter_params;
@@ -71,13 +56,6 @@ class Note
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/note_funcs.h b/synth/note_funcs.h
new file mode 100644
index 0000000..2a9d3c0
--- /dev/null
+++ b/synth/note_funcs.h
@@ -0,0 +1,20 @@
+#ifndef __NOTE_FUNCS_H
+#define __NOTE_FUNCS_H
+
+#include <jack/jack.h>
+
+#include "fixed.h"
+#include <string>
+
+using namespace std;
+
+class NoteSkel;
+struct program_t;
+
+typedef void output_note_func_t(string s);
+typedef string IntToStr_func_t(int i);
+
+typedef NoteSkel* create_func_t (int, float, program_t&, jack_nframes_t, fixed_t, int);
+typedef void init_func_t(int sr, int fupfr, fixed_t **w, fixed_t **clfo, output_note_func_t* out_n, IntToStr_func_t* its);
+
+#endif
diff --git a/synth/note_loader.cpp b/synth/note_loader.cpp
new file mode 100644
index 0000000..28613b9
--- /dev/null
+++ b/synth/note_loader.cpp
@@ -0,0 +1,54 @@
+
+#include <iostream>
+#include <dlfcn.h>
+
+#include "note_loader.h"
+#include "programs.h"
+#include "note_funcs.h"
+#include "globals.h"
+
+using namespace std;
+
+void load_note_from_so(string file, program_t &prog)
+{
+ void *handle;
+
+ handle = dlopen(file.c_str(), RTLD_LAZY);
+
+ if (handle==NULL)
+ throw string("could not open shared object (")+string(dlerror())+string(")");
+
+ try
+ {
+ prog.create_func=(create_func_t*) dlsym(handle,"create_note");
+ if (prog.create_func==NULL)
+ throw string("could not find symbol create_note in shared object (")+dlerror()+")";
+
+ init_func_t* initfunc=(init_func_t*) dlsym(handle,"init_vars");
+ if (initfunc==NULL)
+ throw string("could not find symbol init_vars in shared object (")+dlerror()+")";
+
+ initfunc(samp_rate, filter_update_frames, wave, curr_lfo, &output_note, &IntToStr);
+
+
+
+ prog.dl_handle=handle;
+ }
+ catch (string err)
+ {
+ prog.create_func=NULL;
+ prog.dl_handle=NULL;
+ dlclose(handle);
+ throw err;
+ }
+}
+
+void maybe_unload_note(program_t &prog)
+{
+ if (prog.dl_handle)
+ {
+ dlclose(prog.dl_handle);
+ prog.dl_handle=NULL;
+ prog.create_func=NULL;
+ }
+}
diff --git a/synth/note_loader.h b/synth/note_loader.h
new file mode 100644
index 0000000..6731da1
--- /dev/null
+++ b/synth/note_loader.h
@@ -0,0 +1,13 @@
+#ifndef __NOTE_LOADER_H__
+#define __NOTE_LOADER_H__
+
+#include <string>
+#include <jack/jack.h>
+
+#include "programs.h"
+
+using namespace std;
+
+void load_note_from_so(string file, program_t &prog); //throws string
+void maybe_unload_note(program_t &prog);
+#endif
diff --git a/synth/note_skel.cpp b/synth/note_skel.cpp
new file mode 100644
index 0000000..b028ca4
--- /dev/null
+++ b/synth/note_skel.cpp
@@ -0,0 +1,74 @@
+#include <cmath>
+
+#include "note_skel.h"
+#include "globals.h"
+#include "defines.h"
+
+using namespace std;
+
+NoteSkel::NoteSkel()
+{
+}
+
+NoteSkel::~NoteSkel()
+{
+
+}
+
+void NoteSkel::set_pitchbend(fixed_t pb)
+{
+ pitchbend=pb;
+}
+
+void NoteSkel::set_freq(float f)
+{
+ old_freq=freq;
+ dest_freq=f*ONE;
+ portamento_t=0;
+
+ do_ksr();
+}
+
+void NoteSkel::set_freq(float f, bool do_port)
+{
+ set_freq(f);
+
+ if (!do_port)
+ old_freq=dest_freq;
+}
+
+void NoteSkel::set_note(int n)
+{
+ note=n;
+ set_freq(440.0*pow(2.0,(float)(n-69)/12.0));
+}
+
+void NoteSkel::set_note(int n, bool do_port)
+{
+ note=n;
+ set_freq(440.0*pow(2.0,(float)(n-69)/12.0), do_port);
+}
+
+int NoteSkel::get_note()
+{
+ return note;
+}
+
+void NoteSkel::set_vel(float v)
+{
+ vel=v*ONE;
+
+ recalc_factors();
+ apply_pfactor();
+}
+
+void NoteSkel::set_portamento_frames(jack_nframes_t t)
+{
+ portamento_frames=t;
+ portamento_t=0;
+}
+
+int NoteSkel::get_program()
+{
+ return program;
+}
diff --git a/synth/note_skel.h b/synth/note_skel.h
new file mode 100644
index 0000000..6aebb8b
--- /dev/null
+++ b/synth/note_skel.h
@@ -0,0 +1,56 @@
+#ifndef __NOTE_SKEL_H__
+#define __NOTE_SKEL_H__
+
+#include <jack/jack.h>
+
+#include "programs.h"
+#include "fixed.h"
+
+class NoteSkel
+{
+ public:
+ NoteSkel();
+ virtual ~NoteSkel();
+ virtual fixed_t get_sample()=0;
+
+ int get_program();
+ int get_note();
+ void set_note(int n);
+ void set_note(int n, bool do_port);
+ void set_freq(float f);
+ void set_freq(float f, bool do_port);
+ void set_pitchbend(fixed_t pb);
+ void set_vel(float v);
+ void set_portamento_frames(jack_nframes_t f);
+
+ virtual void release_quickly(jack_nframes_t maxt)=0;
+ virtual void release()=0;
+ virtual void reattack()=0;
+ virtual bool still_active()=0;
+
+ virtual void set_param(const parameter_t &p, fixed_t v)=0;
+
+ virtual void destroy()=0;
+
+ protected:
+ virtual void do_ksl()=0;
+ virtual void do_ksr()=0;
+
+ virtual void recalc_factors()=0;
+ virtual void apply_pfactor()=0;
+
+ fixed_t freq, dest_freq, old_freq;
+ fixed_t vel;
+ jack_nframes_t portamento_t, portamento_frames;
+
+ pfactor_value_t pfactor;
+
+ int note;
+ int program;
+ program_t *curr_prg;
+
+ fixed_t pitchbend;
+};
+
+
+#endif
diff --git a/synth/parser.cpp b/synth/parser.cpp
index 96648d6..5da2175 100644
--- a/synth/parser.cpp
+++ b/synth/parser.cpp
@@ -1,5 +1,3 @@
-//uniniten
-
#include <cstdlib>
#include <fstream>
@@ -286,7 +284,7 @@ program_t parse(string fn)
pfactor_formula_t pfactor;
- fixed_t sync_factor;
+ fixed_t sync_factor=0;
diff --git a/synth/programs.cpp b/synth/programs.cpp
index be82fed..094f209 100644
--- a/synth/programs.cpp
+++ b/synth/programs.cpp
@@ -49,6 +49,9 @@ program_t::program_t()
pfactor.fm=NULL;
pfactor.out=NULL;
+
+ create_func=NULL;
+ dl_handle=NULL;
}
program_t::~program_t()
@@ -115,6 +118,10 @@ program_t& program_t::operator=(const program_t &that)
memcpy(this->pfactor.fm[i], that.pfactor.fm[i], sizeof(param_factor_t)*n_osc);
}
+
+ this->create_func=that.create_func;
+ this->dl_handle=that.dl_handle;
+
return *this;
}
else
diff --git a/synth/programs.h b/synth/programs.h
index e0b409c..9d8d8cc 100644
--- a/synth/programs.h
+++ b/synth/programs.h
@@ -7,6 +7,7 @@
#include <list>
#include "fixed.h"
+#include "note_funcs.h"
#include <jack/jack.h>
using namespace std;
@@ -173,7 +174,10 @@ struct program_t
pfactor_formula_t pfactor;
-
+
+ void *dl_handle;
+ create_func_t *create_func;
+
program_t();
~program_t();
diff --git a/synth/util.cpp b/synth/util.cpp
index ca213fd..51e6fda 100644
--- a/synth/util.cpp
+++ b/synth/util.cpp
@@ -192,7 +192,7 @@ string extract_val(string s)
if (p!=string::npos)
return s.substr(p+1);
else
- return "";
+ return s;
}
string fileext(string f)