From df97e0ebb7f6591c50f3a588cb2a74901d38ac4a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 9 Jan 2011 19:09:05 +0100 Subject: 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 --- .depend | 25 - TODO | 25 +- TODO.done | 12 + note_compiler/.depend | 4 + note_compiler/.gitignore | 1 + note_compiler/IDEE | 30 + note_compiler/Makefile | 34 ++ note_compiler/howtocompile.txt | 4 + note_compiler/main.cpp | 779 ++++++++++++++++++++++++++ note_compiler/parser.cpp | 504 +++++++++++++++++ note_compiler/parser.h | 16 + note_compiler/plugin_factory/Makefile | 34 ++ note_compiler/plugin_factory/channel.cpp | 1 + note_compiler/plugin_factory/channel.h | 1 + note_compiler/plugin_factory/cli.cpp | 1 + note_compiler/plugin_factory/cli.h | 1 + note_compiler/plugin_factory/defines.cpp | 1 + note_compiler/plugin_factory/defines.h | 1 + note_compiler/plugin_factory/envelope.cpp | 1 + note_compiler/plugin_factory/envelope.h | 1 + note_compiler/plugin_factory/filter.cpp | 1 + note_compiler/plugin_factory/filter.h | 1 + note_compiler/plugin_factory/fixed.h | 1 + note_compiler/plugin_factory/globals.cpp | 1 + note_compiler/plugin_factory/globals.h | 1 + note_compiler/plugin_factory/infile.cpp | 392 +++++++++++++ note_compiler/plugin_factory/jack.cpp | 1 + note_compiler/plugin_factory/jack.h | 1 + note_compiler/plugin_factory/load.cpp | 1 + note_compiler/plugin_factory/load.h | 1 + note_compiler/plugin_factory/main.cpp | 1 + note_compiler/plugin_factory/note.cpp | 1 + note_compiler/plugin_factory/note.h | 1 + note_compiler/plugin_factory/note_funcs.h | 1 + note_compiler/plugin_factory/note_loader.cpp | 1 + note_compiler/plugin_factory/note_loader.h | 1 + note_compiler/plugin_factory/note_skel.cpp | 1 + note_compiler/plugin_factory/note_skel.h | 1 + note_compiler/plugin_factory/parser.cpp | 1 + note_compiler/plugin_factory/parser.h | 1 + note_compiler/plugin_factory/programs.cpp | 1 + note_compiler/plugin_factory/programs.h | 1 + note_compiler/plugin_factory/readwave.cpp | 1 + note_compiler/plugin_factory/readwave.h | 1 + note_compiler/plugin_factory/util.cpp | 1 + note_compiler/plugin_factory/util.h | 1 + note_compiler/programs.h | 121 ++++ note_compiler/templates/ctor.foot | 11 + note_compiler/templates/get_sample.1 | 23 + note_compiler/templates/head.1 | 48 ++ note_compiler/templates/head.2 | 11 + note_compiler/templates/interface.1 | 19 + note_compiler/templates/set_param.1 | 27 + note_compiler/templates/set_param.filter | 7 + note_compiler/templates/set_param.filterenv | 34 ++ note_compiler/templates/set_param.nofilter | 13 + note_compiler/templates/set_param.nofilterenv | 7 + note_compiler/util.cpp | 208 +++++++ note_compiler/util.h | 31 + synth/.depend | 50 +- synth/Makefile | 4 +- synth/channel.cpp | 75 ++- synth/channel.h | 4 +- synth/globals.cpp | 2 +- synth/globals.h | 2 +- synth/jack.cpp | 46 +- synth/main.cpp | 25 +- synth/note.cpp | 87 +-- synth/note.h | 32 +- synth/note_funcs.h | 20 + synth/note_loader.cpp | 54 ++ synth/note_loader.h | 13 + synth/note_skel.cpp | 74 +++ synth/note_skel.h | 56 ++ synth/parser.cpp | 4 +- synth/programs.cpp | 7 + synth/programs.h | 6 +- synth/util.cpp | 2 +- 78 files changed, 2826 insertions(+), 190 deletions(-) delete mode 100644 .depend create mode 100644 note_compiler/.depend create mode 100644 note_compiler/.gitignore create mode 100644 note_compiler/IDEE create mode 100644 note_compiler/Makefile create mode 100644 note_compiler/howtocompile.txt create mode 100644 note_compiler/main.cpp create mode 100644 note_compiler/parser.cpp create mode 100644 note_compiler/parser.h create mode 100644 note_compiler/plugin_factory/Makefile create mode 120000 note_compiler/plugin_factory/channel.cpp create mode 120000 note_compiler/plugin_factory/channel.h create mode 120000 note_compiler/plugin_factory/cli.cpp create mode 120000 note_compiler/plugin_factory/cli.h create mode 120000 note_compiler/plugin_factory/defines.cpp create mode 120000 note_compiler/plugin_factory/defines.h create mode 120000 note_compiler/plugin_factory/envelope.cpp create mode 120000 note_compiler/plugin_factory/envelope.h create mode 120000 note_compiler/plugin_factory/filter.cpp create mode 120000 note_compiler/plugin_factory/filter.h create mode 120000 note_compiler/plugin_factory/fixed.h create mode 120000 note_compiler/plugin_factory/globals.cpp create mode 120000 note_compiler/plugin_factory/globals.h create mode 100644 note_compiler/plugin_factory/infile.cpp create mode 120000 note_compiler/plugin_factory/jack.cpp create mode 120000 note_compiler/plugin_factory/jack.h create mode 120000 note_compiler/plugin_factory/load.cpp create mode 120000 note_compiler/plugin_factory/load.h create mode 120000 note_compiler/plugin_factory/main.cpp create mode 120000 note_compiler/plugin_factory/note.cpp create mode 120000 note_compiler/plugin_factory/note.h create mode 120000 note_compiler/plugin_factory/note_funcs.h create mode 120000 note_compiler/plugin_factory/note_loader.cpp create mode 120000 note_compiler/plugin_factory/note_loader.h create mode 120000 note_compiler/plugin_factory/note_skel.cpp create mode 120000 note_compiler/plugin_factory/note_skel.h create mode 120000 note_compiler/plugin_factory/parser.cpp create mode 120000 note_compiler/plugin_factory/parser.h create mode 120000 note_compiler/plugin_factory/programs.cpp create mode 120000 note_compiler/plugin_factory/programs.h create mode 120000 note_compiler/plugin_factory/readwave.cpp create mode 120000 note_compiler/plugin_factory/readwave.h create mode 120000 note_compiler/plugin_factory/util.cpp create mode 120000 note_compiler/plugin_factory/util.h create mode 100644 note_compiler/programs.h create mode 100644 note_compiler/templates/ctor.foot create mode 100644 note_compiler/templates/get_sample.1 create mode 100644 note_compiler/templates/head.1 create mode 100644 note_compiler/templates/head.2 create mode 100644 note_compiler/templates/interface.1 create mode 100644 note_compiler/templates/set_param.1 create mode 100644 note_compiler/templates/set_param.filter create mode 100644 note_compiler/templates/set_param.filterenv create mode 100644 note_compiler/templates/set_param.nofilter create mode 100644 note_compiler/templates/set_param.nofilterenv create mode 100644 note_compiler/util.cpp create mode 100644 note_compiler/util.h create mode 100644 synth/note_funcs.h create mode 100644 synth/note_loader.cpp create mode 100644 synth/note_loader.h create mode 100644 synth/note_skel.cpp create mode 100644 synth/note_skel.h 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;i9999 + +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 +#include + +#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;iwave_len, osc"<samp_rate);\n"; + else + out << "ONE * PHASE_INIT;\n"; + } + + out << "\t\n" + "\tdo_ksl();\n" + "\t\n" + "\t\n"; + + if ((prog.filter.enabled==true) || (prog.filter.enabled_const==false)) + { + //a filter_params and orig.filter_params member exist + out << "\tfilter_params=prg.filter_settings;\n" + "\torig.filter_params=prg.filter_settings;\n"; + + if (prog.filter.enabled_const==false) + { + out << "\tif (filter_params.enabled)\n" + "\t{\n"; + tabtmp="\t"; + } + out << tabtmp << "\tfilter_envelope=new Envelope(filter_params.env_settings);\n" << + tabtmp << "\tfilter_update_counter=filter_update_frames;\n"; + if (prog.filter.enabled_const==false) + out << "\t}\n"; + tabtmp=""; + + out << "\t\n" + "\t\n"; + } + + + if ((prog.sync_factor!=0) || (prog.sync_factor_const==false)) + out << "\tsync_factor=prg.sync_factor;\n" + "\tsync_phase=0;\n" + "\t\n" + "\t\n"; + + + include_file("ctor.foot"); +} + +void write_dtor() +{ + int i; + + out << "Note::~Note()\n" + "{\n"; + + for (i=0;ipfactor.filter_env, vel);\n" + "\tpfactor.filter_res=calc_pfactor(curr_prg->pfactor.filter_res, vel);\n" + "\tpfactor.filter_offset=calc_pfactor(curr_prg->pfactor.filter_offset, vel);\n" + "\t\n"; + } + + out << "\tfor (int i=0;i<"<pfactor.out[i], vel);\n" + "\t\t\n" + "\t\tfor (int j=0;j<"<pfactor.fm[i][j], vel);\n" + "\t}\n"; + + out << "}\n"; +} + +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>SCALE;\n" + "\tfor (int i=0;i<"<>SCALE;\n"; + } + + out << "}\n"; +} + +void write_still_active() +{ + out << "bool Note::still_active()\n" + "{\n"; + + out << "\tif ( "; + if (prog.env[0].enabled) + out << " ((osc"<<0<<".output>0) && (env"<<0<<"->still_active()))"; + else + out << " // envelope"<<0<<" is disabled"; + + for (int i=1;i0) && (env"<still_active()))"; + else + out << "\n\t /* envelope"<release_key();\n"; + else + comment << "\t//envelope"<release_key();\n"; + else if (prog.filter.enabled_const==false) + out << "\n\tif (filter_params.enabled)\n" + "\t\tfilter_envelope->release_key();\n"; + + out << "}\n"; +} + +void write_release_quickly() +{ + out << "void Note::release_quickly(jack_nframes_t maxt)\n" + "{\n"; + + for (int i=0;iget_release() > maxt)\n" + "\t\tenv"<set_release(maxt);\n" + "\tenv"<release_key();\n" + "\t\n"; + else + comment << "\t//envelope"<reattack();\n"; + else + comment << "\t//envelope"<reattack();\n"; + else if (prog.filter.enabled_const==false) + out << "\n\tif (filter_params.enabled)\n" + "\t\tfilter_envelope->reattack();\n"; + + out << "}\n"; +} + +void write_do_ksr() +{ + out << "void Note::do_ksr()\n" + "{\n"; + + for (int i=0;iset_ratefactor(1.0 / pow(freq>>SCALE, osc"<> SCALE );\n" + "\t\n"; + + for (int i=0;iset_max( "<> SCALE;\n" + << tabtemp << "\t\n" + << tabtemp << "\tif (sync_phase >= ONE)\n" + << tabtemp << "\t{\n" + << tabtemp << "\t\tsync_phase-=ONE;\n" + << tabtemp << "\t\t\n"; + + for (int i=0;iwave_len, osc"+IntToStr(i)+".custom_wave->samp_rate)"; + else + initstring="ONE * PHASE_INIT"; + + string full_command="osc"+IntToStr(i)+".phase="+initstring+";\n"; + + if ( prog.osc[i].sync_const && prog.osc[i].sync ) + out << tabtemp << "\t\t" << full_command; + else if ( prog.osc[i].sync_const && (prog.osc[i].sync==false) ) + comment << tabtemp << "\t\t//sync is disabled for osc"<>SCALE)*osc"+IntToStr(i)+".factor/samp_rate)>>SCALE"; + string phase_inc = "(actual_freq*osc"+IntToStr(i)+".factor/samp_rate)>>SCALE"; + if (prog.osc[i].vibrato_depth_const == false) + out << "\tosc"<>SCALE fehlt noch! + for (int j=0;j>SCALE ) )"; + else + phase="osc"+IntToStr(i)+".phase"; + + // generate string for wave + string wavetemp; + if (prog.osc[i].have_custom_wave) + { + string cw="osc"+IntToStr(i)+".custom_wave"; + wavetemp=cw+"->wave[ ( "+phase+" * "+cw+"->samp_rate >>(2*SCALE) ) % "+cw+"->wave_len ]"; + } + else + { + string waveformtemp; + if (prog.osc[i].waveform_const) + waveformtemp=IntToStr(prog.osc[i].waveform); + else + waveformtemp="osc"+IntToStr(i)+".waveform"; + + wavetemp="wave["+waveformtemp+"][ ( "+phase+" * WAVE_RES >>SCALE ) % WAVE_RES ]"; + } + + // finally write "oscval[n]=..." + out << "\toscval["<get_level() >>SCALE;\n"; + else if ( (prog.osc[i].ksl!=0) || (prog.osc[i].ksl_const==false) ) + // i.e.: if osc[i] has a kslval variable + out<<" * kslval"<>SCALE;\n"; + else //no envelope, no kslval + out<<";\n"; + + + // maybe do tremolo + string tremlfo; + if (prog.osc[i].tremolo_lfo_const==false) + tremlfo="osc"+IntToStr(i)+".tremolo_lfo"; + else + tremlfo=IntToStr(prog.osc[i].tremolo_lfo); + + if (prog.osc[i].tremolo_depth_const==false) + out << "\tif (osc"<>SCALE;\n"; + else if (prog.osc[i].tremolo_depth!=0) + out << "\toscval["<>SCALE;\n"; + else + comment << "\t//oscillator"<>SCALE )"; + if (outstring_nonscaled!="") + outstring+=" "+outstring_nonscaled; + + if (outstring=="") + throw string ("this instrument has no output at all!"); + + out << "\tfixed_t out = "<=filter_update_frames)\n" + << tabtemp << "\t{\n" + << tabtemp << "\t\tfilter_update_counter=0;\n" + << tabtemp << "\t\t\n" + << tabtemp << "\t\tfloat cutoff= float(actual_freq)/ONE * \n" + << tabtemp << "\t\t\tfloat(curr_lfo[filter_params.trem_lfo][filter_params.trem_strength])/ONE *\n" + << tabtemp << "\t\t\t( filter_params.freqfactor_offset + filter_envelope->get_level() * filter_params.env_amount / float(ONE) );\n" + << tabtemp << "\t\tfilter.set_params( cutoff, filter_params.resonance );\n" + << tabtemp << "\t}\n" + << tabtemp << "\t\n" + << tabtemp << "\tfilter.process_sample(&out);\n"; + + if (prog.filter.enabled_const==false) + { + out << "\t}\n"; + tabtemp=""; + } + out << "\t\n"; + } + + out << "\treturn out;\n"; + out << "}\n"; +} + +void write_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 +#include + +#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=0) && (ind=0) && (ind2=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=0) && (ind2100)) //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 +#include +#include +#include + +#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 + +#include +#include + +#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 + +#include +#include + +#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 +#include + +#include "util.h" + +string IntToStr(int i) +{ + ostringstream s; + s<=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 +#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::iterator it; + list::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::iterator it=notes.begin(); it!=notes.end(); it++) + for (list::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::iterator it=notes.begin(); it!=notes.end(); it++) + for (list::iterator it=notes.begin(); it!=notes.end(); it++) if ((*it)->get_note()==note) (*it)->release(); } void Channel::note_on(int note, int vel) { - list::iterator it; + list::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::iterator it=notes.begin(); + list::iterator it=notes.begin(); if (quick_release) for (int i=0;idestroy(); 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::iterator it=notes.begin(); it!=notes.end(); it++) + for (list::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::iterator it; + list::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::iterator it; + list::iterator it; for (it=notes.begin(); it!=notes.end();) { - delete *it; + (*it)->destroy(); it=notes.erase(it); } } void Channel::release_all() { - list::iterator it; + list::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::iterator it; + list::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 notes; + std::list 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 #include #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 + +#include "fixed.h" +#include + +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 +#include + +#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 +#include + +#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 + +#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 + +#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 #include @@ -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 #include "fixed.h" +#include "note_funcs.h" #include 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) -- cgit v1.2.1