diff --git a/source/native-plugins/zynaddsubfx-src.cpp b/source/native-plugins/zynaddsubfx-src.cpp index d76758378..07e21459f 100644 --- a/source/native-plugins/zynaddsubfx-src.cpp +++ b/source/native-plugins/zynaddsubfx-src.cpp @@ -402,6 +402,13 @@ extern "C" { #undef rChangeCb #define rChangeCb +#include "zynaddsubfx/Synth/ModFilter.cpp" +#undef rObject +#undef rStdString +#undef rStdStringCb +#undef rChangeCb +#define rChangeCb + #include "zynaddsubfx/Synth/OscilGen.cpp" #undef PC #undef DIFF diff --git a/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp b/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp index e493bfb7c..80f4d8ebd 100644 --- a/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp +++ b/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp @@ -279,7 +279,7 @@ void NotePool::enforceKeyLimit(int limit) void NotePool::releasePlayingNotes(void) { for(auto &d:activeDesc()) { - if(d.playing()) { + if(d.playing() || d.sustained()) { d.setStatus(KEY_RELEASED); for(auto s:activeNotes(d)) s.note->releasekey(); diff --git a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp index 23a5963c6..723839884 100644 --- a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp @@ -323,9 +323,11 @@ void AnalogFilter::setstages(int stages_) { if(stages_ >= MAX_FILTER_STAGES) stages_ = MAX_FILTER_STAGES - 1; - stages = stages_; - cleanup(); - computefiltercoefs(); + if(stages_ != stages) { + stages = stages_; + cleanup(); + computefiltercoefs(); + } } inline void AnalogBiquadFilterA(const float coeff[5], float &src, float work[4]) diff --git a/source/native-plugins/zynaddsubfx/DSP/Filter.cpp b/source/native-plugins/zynaddsubfx/DSP/Filter.cpp index 883cbfdd6..924972ae9 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Filter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/Filter.cpp @@ -39,7 +39,7 @@ Filter::Filter(unsigned int srate, int bufsize) alias(); } -Filter *Filter::generate(Allocator &memory, FilterParams *pars, +Filter *Filter::generate(Allocator &memory, const FilterParams *pars, unsigned int srate, int bufsize) { assert(srate != 0); diff --git a/source/native-plugins/zynaddsubfx/DSP/Filter.h b/source/native-plugins/zynaddsubfx/DSP/Filter.h index 848981f10..c668211d6 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Filter.h +++ b/source/native-plugins/zynaddsubfx/DSP/Filter.h @@ -29,7 +29,7 @@ class Filter { public: static float getrealfreq(float freqpitch); - static Filter *generate(class Allocator &memory, class FilterParams *pars, + static Filter *generate(Allocator &memory, const FilterParams *pars, unsigned int srate, int bufsize); Filter(unsigned int srate, int bufsize); diff --git a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp index 4773106e8..46bc3c6e9 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp @@ -28,8 +28,8 @@ #include "AnalogFilter.h" #include "../Params/FilterParams.h" -FormantFilter::FormantFilter(FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize) - : Filter(srate, bufsize), memory(*alloc) +FormantFilter::FormantFilter(const FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize) + :Filter(srate, bufsize), memory(*alloc) { numformants = pars->Pnumformants; for(int i = 0; i < numformants; ++i) diff --git a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h index ad8d6dd9e..261625bea 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h +++ b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h @@ -27,11 +27,10 @@ #include "Filter.h" -class Allocator; class FormantFilter:public Filter { public: - FormantFilter(class FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize); + FormantFilter(const FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize); ~FormantFilter(); void filterout(float *smp); void setfreq(float frequency); diff --git a/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp index cc78d378f..cabc633a2 100644 --- a/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp @@ -85,7 +85,7 @@ void SVFilter::setfreq(float frequency) bool nyquistthresh = (abovenq ^ oldabovenq); //if the frequency is changed fast, it needs interpolation - if((rap > 3.0f) || nyquistthresh) { //(now, filter and coeficients backup) + if((rap > 3.0f) || nyquistthresh) { //(now, filter and coefficients backup) if(!firsttime) needsinterpolation = true; ipar = par; diff --git a/source/native-plugins/zynaddsubfx/Misc/Bank.cpp b/source/native-plugins/zynaddsubfx/Misc/Bank.cpp index 969f79c89..c732a2413 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Bank.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Bank.cpp @@ -212,6 +212,7 @@ int Bank::loadfromslot(unsigned int ninstrument, Part *part) */ int Bank::loadbank(string bankdirname) { + normalizedirsuffix(bankdirname); DIR *dir = opendir(bankdirname.c_str()); clearbank(); @@ -285,9 +286,8 @@ int Bank::newbank(string newbankdirname) string bankdir; bankdir = config->cfg.bankRootDirList[0]; - if(((bankdir[bankdir.size() - 1]) != '/') - && ((bankdir[bankdir.size() - 1]) != '\\')) - bankdir += "/"; + expanddirname(bankdir); + normalizedirsuffix(bankdir); bankdir += newbankdirname; #ifdef _WIN32 @@ -404,6 +404,8 @@ void Bank::setLsb(uint8_t lsb) void Bank::scanrootdir(string rootdir) { + expanddirname(rootdir); + DIR *dir = opendir(rootdir.c_str()); if(dir == NULL) return; @@ -498,3 +500,23 @@ void Bank::deletefrombank(int pos) Bank::ins_t::ins_t() :name(""), filename("") {} + +void Bank::expanddirname(std::string &dirname) { + if (dirname.empty()) + return; + + // if the directory name starts with a ~ and the $HOME variable is + // defined in the environment, replace ~ by the content of $HOME + if (dirname.at(0) == '~') { + char *home_dirname = getenv("HOME"); + if (home_dirname != NULL) { + dirname = std::string(home_dirname) + dirname.substr(1); + } + } +} + +void Bank::normalizedirsuffix(string &dirname) const { + if(((dirname[dirname.size() - 1]) != '/') + && ((dirname[dirname.size() - 1]) != '\\')) + dirname += "/"; +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Bank.h b/source/native-plugins/zynaddsubfx/Misc/Bank.h index a41fea627..7d8f9d405 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Bank.h +++ b/source/native-plugins/zynaddsubfx/Misc/Bank.h @@ -100,7 +100,14 @@ class Bank std::string dirname; void scanrootdir(std::string rootdir); //scans a root dir for banks - + + /** Expends ~ prefix in dirname, if any */ + void expanddirname(std::string &dirname); + + /** Ensure that the directory name is suffixed by a + * directory separator */ + void normalizedirsuffix(std::string &dirname) const; + Config* const config; public: diff --git a/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp b/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp index 04035baec..3bc38908c 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,118 @@ const rtosc::Ports Microtonal::ports = { Microtonal &m = *(Microtonal*)d.obj; d.reply(d.loc, "i", m.getoctavesize()); }}, + {"mapping::s", rDoc("Get user editable tunings"), 0, [](const char *msg, RtData &d) + { + char buf[100*MAX_OCTAVE_SIZE] = {0}; + char tmpbuf[100] = {0}; + Microtonal &m = *(Microtonal*)d.obj; + if(rtosc_narguments(msg) == 1) { + m.texttomapping(rtosc_argument(msg,0).s); + } else { + for (int i=0;i=0) + d.reply("/alert", "s", + "Parse Error: The input may contain only numbers (like 232.59)\n" + "or divisions (like 121/64)."); + if (err==-2) + d.reply("/alert", "s", "Parse Error: The input is empty."); + } else { + for (int i=0;ix; + {"paste:b", rProp(internal) rDoc("Clone Input Microtonal Object"), 0, + [](const char *msg, RtData &d) + { + rtosc_blob_t b = rtosc_argument(msg, 0).b; + assert(b.len == sizeof(void*)); + Microtonal *other = *(Microtonal**)b.len; + Microtonal &self = *(Microtonal*)d.obj; + //oh how I wish there was some darn reflection for this... + + COPY(Pinvertupdown); + COPY(Pinvertupdowncenter); + COPY(Penabled); + COPY(PAnote); + COPY(PAfreq); + COPY(Pscaleshift); + COPY(Pfirstkey); + COPY(Plastkey); + COPY(Pmiddlenote); + COPY(Pmapsize); + COPY(Pmappingenabled); + for(int i=0; ioctave[i]; + COPY(Pglobalfinedetune); + + memcpy(self.Pname, other->Pname, sizeof(self.Pname)); + memcpy(self.Pcomment, other->Pcomment, sizeof(self.Pcomment)); + COPY(octavesize); + + for(int i=0; ioctave[i]; + d.reply("/free", "sb", "Microtonal", b.len, b.data); + }}, + {"paste_scl:b", rProp(internal) rDoc("Clone Input scl Object"), 0, + [](const char *msg, RtData &d) + { + rtosc_blob_t b = rtosc_argument(msg, 0).b; + assert(b.len == sizeof(void*)); + SclInfo *other = *(SclInfo**)b.data; + Microtonal &self = *(Microtonal*)d.obj; + memcpy(self.Pname, other->Pname, sizeof(self.Pname)); + memcpy(self.Pcomment, other->Pcomment, sizeof(self.Pcomment)); + COPY(octavesize); + + for(int i=0; ioctave[i]; + d.reply("/free", "sb", "SclInfo", b.len, b.data); + }}, + {"paste_kbm:b", rProp(internal) rDoc("Clone Input kbm Object"), 0, + [](const char *msg, RtData &d) + { + rtosc_blob_t b = rtosc_argument(msg, 0).b; + assert(b.len == sizeof(void*)); + KbmInfo *other = *(KbmInfo**)b.data; + Microtonal &self = *(Microtonal*)d.obj; + COPY(Pmapsize); + COPY(Pfirstkey); + COPY(Plastkey); + COPY(Pmiddlenote); + COPY(PAnote); + COPY(PAfreq); + COPY(Pmappingenabled); + + for(int i=0; i<128; ++i) + self.Pmapping[i] = other->Pmapping[i]; + d.reply("/free", "sb", "KbmInfo", b.len, b.data); + }}, +#undef COPY }; @@ -101,13 +214,10 @@ void Microtonal::defaults() Pmapping[i] = i; for(int i = 0; i < MAX_OCTAVE_SIZE; ++i) { - octave[i].tuning = tmpoctave[i].tuning = powf( - 2, - (i % octavesize - + 1) / 12.0f); - octave[i].type = tmpoctave[i].type = 1; - octave[i].x1 = tmpoctave[i].x1 = (i % octavesize + 1) * 100; - octave[i].x2 = tmpoctave[i].x2 = 0; + octave[i].tuning = powf(2, (i % octavesize + 1) / 12.0f); + octave[i].type = 1; + octave[i].x1 = (i % octavesize + 1) * 100; + octave[i].x2 = 0; } octave[11].type = 2; octave[11].x1 = 2; @@ -298,7 +408,7 @@ bool Microtonal::operator!=(const Microtonal µ) const /* * Convert a line to tunings; returns -1 if it ok */ -int Microtonal::linetotunings(unsigned int nline, const char *line) +int Microtonal::linetotunings(OctaveTuning &octave, const char *line) { int x1 = -1, x2 = -1, type = -1; float x = -1.0f, tmp, tuning = 1.0f; @@ -346,10 +456,10 @@ int Microtonal::linetotunings(unsigned int nline, const char *line) break; } - tmpoctave[nline].tuning = tuning; - tmpoctave[nline].type = type; - tmpoctave[nline].x1 = x1; - tmpoctave[nline].x2 = x2; + octave.tuning = tuning; + octave.type = type; + octave.x1 = x1; + octave.x2 = x2; return -1; //ok } @@ -359,10 +469,11 @@ int Microtonal::linetotunings(unsigned int nline, const char *line) */ int Microtonal::texttotunings(const char *text) { - unsigned int i, k = 0, nl = 0; - char *lin; - lin = new char[MAX_LINE_SIZE + 1]; + unsigned int k = 0, nl = 0; + char *lin = new char[MAX_LINE_SIZE + 1]; + OctaveTuning tmpoctave[MAX_OCTAVE_SIZE]; while(k < strlen(text)) { + int i; for(i = 0; i < MAX_LINE_SIZE; ++i) { lin[i] = text[k++]; if(lin[i] < 0x20) @@ -371,7 +482,7 @@ int Microtonal::texttotunings(const char *text) lin[i] = '\0'; if(strlen(lin) == 0) continue; - int err = linetotunings(nl, lin); + int err = linetotunings(tmpoctave[nl], lin); if(err != -1) { delete [] lin; return nl; //Parse error @@ -384,7 +495,7 @@ int Microtonal::texttotunings(const char *text) if(nl == 0) return -2; //the input is empty octavesize = nl; - for(i = 0; i < octavesize; ++i) { + for(int i = 0; i < octavesize; ++i) { octave[i].tuning = tmpoctave[i].tuning; octave[i].type = tmpoctave[i].type; octave[i].x1 = tmpoctave[i].x1; @@ -449,28 +560,37 @@ void Microtonal::tuningtoline(int n, char *line, int maxn) int Microtonal::loadline(FILE *file, char *line) { + memset(line, 0, 500); do { if(fgets(line, 500, file) == 0) return 1; } while(line[0] == '!'); return 0; } + + /* * Loads the tunnings from a scl file */ -int Microtonal::loadscl(const char *filename) +int Microtonal::loadscl(SclInfo &scl, const char *filename) { FILE *file = fopen(filename, "r"); char tmp[500]; + OctaveTuning tmpoctave[MAX_OCTAVE_SIZE]; + fseek(file, 0, SEEK_SET); + //loads the short description if(loadline(file, &tmp[0]) != 0) return 2; + for(int i = 0; i < 500; ++i) if(tmp[i] < 32) tmp[i] = 0; - snprintf((char *) Pname, MICROTONAL_MAX_NAME_LEN, "%s", tmp); - snprintf((char *) Pcomment, MICROTONAL_MAX_NAME_LEN, "%s", tmp); + + snprintf(scl.Pname, MICROTONAL_MAX_NAME_LEN, "%s", tmp); + snprintf(scl.Pcomment, MICROTONAL_MAX_NAME_LEN, "%s", tmp); + //loads the number of the notes if(loadline(file, &tmp[0]) != 0) return 2; @@ -478,29 +598,31 @@ int Microtonal::loadscl(const char *filename) sscanf(&tmp[0], "%d", &nnotes); if(nnotes > MAX_OCTAVE_SIZE) return 2; + //load the tunnings for(int nline = 0; nline < nnotes; ++nline) { if(loadline(file, &tmp[0]) != 0) return 2; - linetotunings(nline, &tmp[0]); + linetotunings(tmpoctave[nline], tmp); } fclose(file); - octavesize = nnotes; - for(int i = 0; i < octavesize; ++i) { - octave[i].tuning = tmpoctave[i].tuning; - octave[i].type = tmpoctave[i].type; - octave[i].x1 = tmpoctave[i].x1; - octave[i].x2 = tmpoctave[i].x2; + scl.octavesize = nnotes; + for(int i = 0; i < scl.octavesize; ++i) { + scl.octave[i].tuning = tmpoctave[i].tuning; + scl.octave[i].type = tmpoctave[i].type; + scl.octave[i].x1 = tmpoctave[i].x1; + scl.octave[i].x2 = tmpoctave[i].x2; } return 0; } + /* * Loads the mapping from a kbm file */ -int Microtonal::loadkbm(const char *filename) +int Microtonal::loadkbm(KbmInfo &kbm, const char *filename) { FILE *file = fopen(filename, "r"); int x; @@ -511,32 +633,32 @@ int Microtonal::loadkbm(const char *filename) //loads the mapsize if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) return 2; - Pmapsize = limit(x, 0, 127); + kbm.Pmapsize = limit(x, 0, 127); //loads first MIDI note to retune if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) return 2; - Pfirstkey = limit(x, 0, 127); + kbm.Pfirstkey = limit(x, 0, 127); //loads last MIDI note to retune if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) return 2; - Plastkey = limit(x, 0, 127); + kbm.Plastkey = limit(x, 0, 127); //loads last the middle note where scale fro scale degree=0 if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) return 2; - Pmiddlenote = limit(x, 0, 127); + kbm.Pmiddlenote = limit(x, 0, 127); //loads the reference note if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) return 2; - PAnote = limit(x,0,127); + kbm.PAnote = limit(x,0,127); //loads the reference freq. if(loadline(file, tmp) != 0 || sscanf(tmp, "%f", &tmpPAfreq) == 0) return 2; - PAfreq = tmpPAfreq; + kbm.PAfreq = tmpPAfreq; //the scale degree(which is the octave) is not loaded, //it is obtained by the tunnings with getoctavesize() method @@ -544,20 +666,20 @@ int Microtonal::loadkbm(const char *filename) return 2; //load the mappings - if(Pmapsize != 0) { - for(int nline = 0; nline < Pmapsize; ++nline) { + if(kbm.Pmapsize != 0) { + for(int nline = 0; nline < kbm.Pmapsize; ++nline) { if(loadline(file, tmp) != 0) return 2; if(sscanf(tmp, "%d", &x) == 0) x = -1; - Pmapping[nline] = x; + kbm.Pmapping[nline] = x; } - Pmappingenabled = 1; + kbm.Pmappingenabled = 1; } else { - Pmappingenabled = 0; - Pmapping[0] = 0; - Pmapsize = 1; + kbm.Pmappingenabled = 0; + kbm.Pmapping[0] = 0; + kbm.Pmapsize = 1; } fclose(file); diff --git a/source/native-plugins/zynaddsubfx/Misc/Microtonal.h b/source/native-plugins/zynaddsubfx/Misc/Microtonal.h index db5c9c924..5c6ed2cea 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Microtonal.h +++ b/source/native-plugins/zynaddsubfx/Misc/Microtonal.h @@ -24,12 +24,43 @@ #define MICROTONAL_H #include +#include #include "../globals.h" #define MAX_OCTAVE_SIZE 128 #define MICROTONAL_MAX_NAME_LEN 120 class XMLwrapper; +struct KbmInfo +{ + uint8_t Pmapsize; + uint8_t Pfirstkey; + uint8_t Plastkey; + uint8_t Pmiddlenote; + uint8_t PAnote; + float PAfreq; + uint8_t Pmappingenabled; + short int Pmapping[128]; +}; + +struct OctaveTuning { + unsigned char type; //1 for cents or 2 for division + + // the real tuning (eg. +1.05946f for one halftone) + // or 2.0f for one octave + float tuning; + + //the real tunning is x1/x2 + unsigned int x1, x2; +}; + +struct SclInfo +{ + char Pname[MICROTONAL_MAX_NAME_LEN]; + char Pcomment[MICROTONAL_MAX_NAME_LEN]; + unsigned char octavesize; + OctaveTuning octave[MAX_OCTAVE_SIZE]; +}; /**Tuning settings and microtonal capabilities*/ class Microtonal @@ -88,9 +119,9 @@ class Microtonal /**Convert tunning to string*/ void tuningtoline(int n, char *line, int maxn); /**load the tunnings from a .scl file*/ - int loadscl(const char *filename); + static int loadscl(SclInfo &scl, const char *filename); /**load the mapping from .kbm file*/ - int loadkbm(const char *filename); + static int loadkbm(KbmInfo &kbm, const char *filename); /**Load text into the internal tunings * *\todo better description*/ @@ -114,23 +145,19 @@ class Microtonal bool operator==(const Microtonal µ) const; bool operator!=(const Microtonal µ) const; + void clone(Microtonal &m); + static const rtosc::Ports ports; + + //only paste handler should access there (quasi-private) + unsigned char octavesize; + OctaveTuning octave[MAX_OCTAVE_SIZE]; private: - int linetotunings(unsigned int nline, const char *line); //loads a line from the text file, while ignoring the lines beggining with "!" - int loadline(FILE *file, char *line); + static int loadline(FILE *file, char *line); //Grab a 0..127 integer from the provided descriptor - unsigned char octavesize; - struct { - unsigned char type; //1 for cents or 2 for division - - // the real tuning (eg. +1.05946f for one halftone) - // or 2.0f for one octave - float tuning; - //the real tunning is x1/x2 - unsigned int x1, x2; - } octave[MAX_OCTAVE_SIZE], tmpoctave[MAX_OCTAVE_SIZE]; + static int linetotunings(struct OctaveTuning &tune, const char *line); const int& gzip_compression; }; diff --git a/source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp b/source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp index d1bc7417d..90ccf5b9c 100644 --- a/source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp @@ -157,6 +157,12 @@ void deallocate(const char *str, void *v) delete (Master*)v; else if(!strcmp(str, "fft_t")) delete[] (fft_t*)v; + else if(!strcmp(str, "KbmInfo")) + delete (KbmInfo*)v; + else if(!strcmp(str, "SclInfo")) + delete (SclInfo*)v; + else if(!strcmp(str, "Microtonal")) + delete (Microtonal*)v; else fprintf(stderr, "Unknown type '%s', leaking pointer %p!!\n", str, v); } @@ -556,6 +562,48 @@ public: parent->transmitMsg("/load-master", "b", sizeof(Master*), &m); } + void loadXsz(const char *filename, rtosc::RtData &d) + { + Microtonal *micro = new Microtonal(master->gzip_compression); + int err = micro->loadXML(filename); + if(err) { + d.reply("/alert", "s", "Error: Could not load the xsz file."); + delete micro; + } else + d.chain("/microtonal/paste", "b", sizeof(void*), µ); + } + + void saveXsz(const char *filename, rtosc::RtData &d) + { + int err = 0; + doReadOnlyOp([this,filename,&err](){ + err = master->microtonal.saveXML(filename);}); + if(err) + d.reply("/alert", "s", "Error: Could not save the xsz file."); + } + + void loadScl(const char *filename, rtosc::RtData &d) + { + SclInfo *scl = new SclInfo; + int err=Microtonal::loadscl(*scl, filename); + if(err) { + d.reply("/alert", "s", "Error: Could not load the scl file."); + delete scl; + } else + d.chain("/microtonal/paste_scl", "b", sizeof(void*), &scl); + } + + void loadKbm(const char *filename, rtosc::RtData &d) + { + KbmInfo *kbm = new KbmInfo; + int err=Microtonal::loadkbm(*kbm, filename); + if(err) { + d.reply("/alert", "s", "Error: Could not load the kbm file."); + delete kbm; + } else + d.chain("/microtonal/paste_kbm", "b", sizeof(void*), &kbm); + } + void updateResources(Master *m) { obj_store.clear(); @@ -861,6 +909,12 @@ rtosc::Ports bankPorts = { rBegin; impl.setLsb(rtosc_argument(msg, 0).i); rEnd}, + {"newbank:s", 0, 0, + rBegin; + int err = impl.newbank(rtosc_argument(msg, 0).s); + if(err) + d.reply("/alert", "s", "Error: Could not make a new bank (directory).."); + rEnd}, }; /****************************************************************************** @@ -959,6 +1013,27 @@ static rtosc::Ports middwareSnoopPorts = { xml.loadXMLfile(file); loadMidiLearn(xml, impl.midi_mapper); rEnd}, + //scale file stuff + {"load_xsz:s", 0, 0, + rBegin; + const char *file = rtosc_argument(msg, 0).s; + impl.loadXsz(file, d); + rEnd}, + {"save_xsz:s", 0, 0, + rBegin; + const char *file = rtosc_argument(msg, 0).s; + impl.saveXsz(file, d); + rEnd}, + {"load_scl:s", 0, 0, + rBegin; + const char *file = rtosc_argument(msg, 0).s; + impl.loadScl(file, d); + rEnd}, + {"load_kbm:s", 0, 0, + rBegin; + const char *file = rtosc_argument(msg, 0).s; + impl.loadKbm(file, d); + rEnd}, {"save_xmz:s", 0, 0, rBegin; const char *file = rtosc_argument(msg, 0).s; diff --git a/source/native-plugins/zynaddsubfx/Misc/Part.cpp b/source/native-plugins/zynaddsubfx/Misc/Part.cpp index bf79e08c2..6e7f4c29a 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Part.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Part.cpp @@ -312,7 +312,7 @@ void Part::defaultsinstrument() Pdrummode = 0; for(int n = 0; n < NUM_KIT_ITEMS; ++n) { - //kit[n].Penabled = false; + kit[n].Penabled = false; kit[n].Pmuted = false; kit[n].Pminkey = 0; kit[n].Pmaxkey = 127; @@ -847,9 +847,6 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_) delete kkit.adpars; delete kkit.subpars; delete kkit.padpars; - kkit.adpars = nullptr; - kkit.subpars = nullptr; - kkit.padpars = nullptr; kkit.Pname[0] = '\0'; notePool.killAllNotes(); diff --git a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp index 8ae71d5a6..aae5543a2 100644 --- a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp @@ -98,7 +98,7 @@ XMLwrapper::XMLwrapper() { version.Major = 2; version.Minor = 5; - version.Revision = 2; + version.Revision = 3; minimal = true; diff --git a/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp b/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp index be9f45ac3..e719228ce 100644 --- a/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp +++ b/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp @@ -237,21 +237,21 @@ void FilterParams::getfromFilterParams(FilterParams *pars) /* * Parameter control */ -float FilterParams::getfreq() +float FilterParams::getfreq() const { return (Pfreq / 64.0f - 1.0f) * 5.0f; } -float FilterParams::getq() +float FilterParams::getq() const { return expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; } -float FilterParams::getfreqtracking(float notefreq) +float FilterParams::getfreqtracking(float notefreq) const { return logf(notefreq / 440.0f) * (Pfreqtrack - 64.0f) / (64.0f * LOG_2); } -float FilterParams::getgain() +float FilterParams::getgain() const { return (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB } @@ -259,7 +259,7 @@ float FilterParams::getgain() /* * Get the center frequency of the formant's graph */ -float FilterParams::getcenterfreq() +float FilterParams::getcenterfreq() const { return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f); } @@ -267,7 +267,7 @@ float FilterParams::getcenterfreq() /* * Get the number of octave that the formant functions applies to */ -float FilterParams::getoctavesfreq() +float FilterParams::getoctavesfreq() const { return 0.25f + 10.0f * Poctavesfreq / 127.0f; } @@ -275,7 +275,7 @@ float FilterParams::getoctavesfreq() /* * Get the frequency from x, where x is [0..1] */ -float FilterParams::getfreqx(float x) +float FilterParams::getfreqx(float x) const { if(x > 1.0f) x = 1.0f; @@ -286,7 +286,7 @@ float FilterParams::getfreqx(float x) /* * Get the x coordinate from frequency (used by the UI) */ -float FilterParams::getfreqpos(float freq) +float FilterParams::getfreqpos(float freq) const { return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq(); } @@ -294,19 +294,19 @@ float FilterParams::getfreqpos(float freq) /* * Transforms a parameter to the real value */ -float FilterParams::getformantfreq(unsigned char freq) +float FilterParams::getformantfreq(unsigned char freq) const { float result = getfreqx(freq / 127.0f); return result; } -float FilterParams::getformantamp(unsigned char amp) +float FilterParams::getformantamp(unsigned char amp) const { float result = powf(0.1f, (1.0f - amp / 127.0f) * 4.0f); return result; } -float FilterParams::getformantq(unsigned char q) +float FilterParams::getformantq(unsigned char q) const { //temp float result = powf(25.0f, (q - 32.0f) / 64.0f); diff --git a/source/native-plugins/zynaddsubfx/Params/FilterParams.h b/source/native-plugins/zynaddsubfx/Params/FilterParams.h index a7c08fecb..a3fad0372 100644 --- a/source/native-plugins/zynaddsubfx/Params/FilterParams.h +++ b/source/native-plugins/zynaddsubfx/Params/FilterParams.h @@ -48,10 +48,10 @@ class FilterParams:public PresetsArray void getfromFilterParams(FilterParams *pars); - float getfreq(); - float getq(); - float getfreqtracking(float notefreq); - float getgain(); + float getfreq() const ; + float getq() const ; + float getfreqtracking(float notefreq) const ; + float getgain() const ; unsigned char Pcategory; //Filter category (Analog/Formant/StVar) unsigned char Ptype; // Filter type (for analog lpf,hpf,bpf..) @@ -80,14 +80,14 @@ class FilterParams:public PresetsArray unsigned char nvowel; //the vowel from the position } Psequence[FF_MAX_SEQUENCE]; - float getcenterfreq(); - float getoctavesfreq(); - float getfreqpos(float freq); - float getfreqx(float x); + float getcenterfreq() const ; + float getoctavesfreq() const ; + float getfreqpos(float freq) const ; + float getfreqx(float x) const ; - float getformantfreq(unsigned char freq); - float getformantamp(unsigned char amp); - float getformantq(unsigned char q); + float getformantfreq(unsigned char freq) const ; + float getformantamp(unsigned char amp) const ; + float getformantq(unsigned char q) const ; void defaults(int n); diff --git a/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp b/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp index d624077ed..2bf962779 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp @@ -29,9 +29,8 @@ #include "../globals.h" #include "../Misc/Util.h" #include "../Misc/Allocator.h" -#include "../DSP/Filter.h" #include "../Params/ADnoteParameters.h" -#include "../Params/FilterParams.h" +#include "ModFilter.h" #include "OscilGen.h" #include "ADnote.h" @@ -63,13 +62,6 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars) NoteGlobalPar.Panning = pars.GlobalPar.PPanning / 128.0f; - NoteGlobalPar.FilterCenterPitch = pars.GlobalPar.GlobalFilter->getfreq() //center freq - + pars.GlobalPar.PFilterVelocityScale - / 127.0f * 6.0f //velocity sensing - * (VelF(velocity, - pars.GlobalPar. - PFilterVelocityScaleFunction) - 1); - NoteGlobalPar.Fadein_adjustment = pars.GlobalPar.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE; NoteGlobalPar.Fadein_adjustment *= NoteGlobalPar.Fadein_adjustment; @@ -373,17 +365,10 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars) NoteVoicePar[nvoice].AmpLfo = NULL; NoteVoicePar[nvoice].AmpEnvelope = NULL; - NoteVoicePar[nvoice].VoiceFilterL = NULL; - NoteVoicePar[nvoice].VoiceFilterR = NULL; + NoteVoicePar[nvoice].Filter = NULL; NoteVoicePar[nvoice].FilterEnvelope = NULL; NoteVoicePar[nvoice].FilterLfo = NULL; - NoteVoicePar[nvoice].FilterCenterPitch = - pars.VoicePar[nvoice].VoiceFilter->getfreq() - + pars.VoicePar[nvoice].PFilterVelocityScale - / 127.0f * 6.0f //velocity sensing - * (VelF(velocity, - pars.VoicePar[nvoice].PFilterVelocityScaleFunction) - 1); NoteVoicePar[nvoice].filterbypass = pars.VoicePar[nvoice].Pfilterbypass; @@ -514,13 +499,9 @@ void ADnote::legatonote(LegatoParams lpars) else NoteGlobalPar.Panning = pars.GlobalPar.PPanning / 128.0f; - //center freq - NoteGlobalPar.FilterCenterPitch = pars.GlobalPar.GlobalFilter->getfreq() - + pars.GlobalPar.PFilterVelocityScale - / 127.0f * 6.0f //velocity sensing - * (VelF(velocity, - pars.GlobalPar. - PFilterVelocityScaleFunction) - 1); + NoteGlobalPar.Filter->updateSense(velocity, + pars.GlobalPar.PFilterVelocityScale, + pars.GlobalPar.PFilterVelocityScaleFunction); for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { @@ -580,13 +561,12 @@ void ADnote::legatonote(LegatoParams lpars) + i] = NoteVoicePar[nvoice].OscilSmp[i]; - - NoteVoicePar[nvoice].FilterCenterPitch = - pars.VoicePar[nvoice].VoiceFilter->getfreq() - + pars.VoicePar[nvoice].PFilterVelocityScale - / 127.0f * 6.0f //velocity sensing - * (VelF(velocity, - pars.VoicePar[nvoice].PFilterVelocityScaleFunction) - 1); + auto &voiceFilter = NoteVoicePar[nvoice].Filter; + if(voiceFilter) { + const auto &vce = pars.VoicePar[nvoice]; + voiceFilter->updateSense(velocity, vce.PFilterVelocityScale, + vce.PFilterVelocityScaleFunction); + } NoteVoicePar[nvoice].filterbypass = pars.VoicePar[nvoice].Pfilterbypass; @@ -653,9 +633,12 @@ void ADnote::legatonote(LegatoParams lpars) * NoteGlobalPar.AmpEnvelope->envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); - NoteGlobalPar.FilterQ = pars.GlobalPar.GlobalFilter->getq(); - NoteGlobalPar.FilterFreqTracking = - pars.GlobalPar.GlobalFilter->getfreqtracking(basefreq); + { + auto *filter = NoteGlobalPar.Filter; + filter->updateSense(velocity, pars.GlobalPar.PFilterVelocityScale, + pars.GlobalPar.PFilterVelocityScaleFunction); + filter->updateNoteFreq(basefreq); + } // Forbids the Modulation Voice to be greater or equal than voice for(int i = 0; i < NUM_VOICES; ++i) @@ -693,10 +676,12 @@ void ADnote::legatonote(LegatoParams lpars) if(pars.VoicePar[nvoice].PAmpLfoEnabled && NoteVoicePar[nvoice].AmpLfo) newamplitude[nvoice] *= NoteVoicePar[nvoice].AmpLfo->amplfoout(); - - - NoteVoicePar[nvoice].FilterFreqTracking = - pars.VoicePar[nvoice].VoiceFilter->getfreqtracking(basefreq); + auto *voiceFilter = NoteVoicePar[nvoice].Filter; + if(voiceFilter) { + voiceFilter->updateSense(velocity, pars.VoicePar[nvoice].PFilterVelocityScale, + pars.VoicePar[nvoice].PFilterVelocityScaleFunction); + voiceFilter->updateNoteFreq(basefreq); + } /* Voice Modulation Parameters Init */ if((NoteVoicePar[nvoice].FMEnabled != NONE) @@ -857,21 +842,24 @@ void ADnote::initparameters() vce.FreqLfo = memory.alloc(*param.FreqLfo, basefreq, time); /* Voice Filter Parameters Init */ - if(param.PFilterEnabled != 0) { - vce.VoiceFilterL = Filter::generate(memory, param.VoiceFilter, - synth.samplerate, synth.buffersize); - vce.VoiceFilterR = Filter::generate(memory, param.VoiceFilter, - synth.samplerate, synth.buffersize); - } + if(param.PFilterEnabled) { + vce.Filter = memory.alloc(*param.VoiceFilter, synth, time, memory, stereo, + basefreq); + vce.Filter->updateSense(velocity, param.PFilterVelocityScale, + param.PFilterVelocityScaleFunction); - if(param.PFilterEnvelopeEnabled) - vce.FilterEnvelope = memory.alloc(*param.FilterEnvelope, basefreq, synth.dt()); - if(param.PFilterLfoEnabled) - vce.FilterLfo = memory.alloc(*param.FilterLfo, basefreq, time); + if(param.PFilterEnvelopeEnabled) { + vce.FilterEnvelope = + memory.alloc(*param.FilterEnvelope, basefreq, synth.dt()); + vce.Filter->addMod(*vce.FilterEnvelope); + } - vce.FilterFreqTracking = - param.VoiceFilter->getfreqtracking(basefreq); + if(param.PFilterLfoEnabled) { + vce.FilterLfo = memory.alloc(*param.FilterLfo, basefreq, time); + vce.Filter->addMod(*vce.FilterLfo); + } + } /* Voice Modulation Parameters Init */ if((vce.FMEnabled != NONE) && (vce.FMVoice < 0)) { @@ -1050,8 +1038,8 @@ float ADnote::getFMvoicebasefreq(int nvoice) const void ADnote::computecurrentparameters() { int nvoice; - float voicefreq, voicepitch, filterpitch, filterfreq, FMfreq, - FMrelativepitch, globalpitch, globalfilterpitch; + float voicefreq, voicepitch, FMfreq, + FMrelativepitch, globalpitch; globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout() + NoteGlobalPar.FreqLfo->lfoout() * ctl.modwheel.relmod); @@ -1060,19 +1048,9 @@ void ADnote::computecurrentparameters() * NoteGlobalPar.AmpEnvelope->envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); - globalfilterpitch = NoteGlobalPar.FilterEnvelope->envout() - + NoteGlobalPar.FilterLfo->lfoout() - + NoteGlobalPar.FilterCenterPitch; - - float tmpfilterfreq = globalfilterpitch + ctl.filtercutoff.relfreq - + NoteGlobalPar.FilterFreqTracking; - - tmpfilterfreq = Filter::getrealfreq(tmpfilterfreq); + NoteGlobalPar.Filter->update(ctl.filtercutoff.relfreq, + ctl.filterq.relq); - float globalfilterq = NoteGlobalPar.FilterQ * ctl.filterq.relq; - NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq, globalfilterq); - if(stereo != 0) - NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq, globalfilterq); //compute the portamento, if it is used by this note float portamentofreqrap = 1.0f; @@ -1107,21 +1085,10 @@ void ADnote::computecurrentparameters() /****************/ /* Voice Filter */ /****************/ - if(NoteVoicePar[nvoice].VoiceFilterL) { - filterpitch = NoteVoicePar[nvoice].FilterCenterPitch; - - if(NoteVoicePar[nvoice].FilterEnvelope) - filterpitch += NoteVoicePar[nvoice].FilterEnvelope->envout(); - - if(NoteVoicePar[nvoice].FilterLfo) - filterpitch += NoteVoicePar[nvoice].FilterLfo->lfoout(); - - filterfreq = filterpitch + NoteVoicePar[nvoice].FilterFreqTracking; - filterfreq = Filter::getrealfreq(filterfreq); - - NoteVoicePar[nvoice].VoiceFilterL->setfreq(filterfreq); - if(stereo && NoteVoicePar[nvoice].VoiceFilterR) - NoteVoicePar[nvoice].VoiceFilterR->setfreq(filterfreq); + auto *voiceFilter = NoteVoicePar[nvoice].Filter; + if(voiceFilter) { + voiceFilter->update(ctl.filtercutoff.relfreq, + ctl.filterq.relq); } if(NoteVoicePar[nvoice].noisetype == 0) { //compute only if the voice isn't noise @@ -1702,12 +1669,13 @@ int ADnote::noteout(float *outl, float *outr) firsttick[nvoice] = 0; } - // Filter - if(NoteVoicePar[nvoice].VoiceFilterL) - NoteVoicePar[nvoice].VoiceFilterL->filterout(&tmpwavel[0]); - if(stereo && NoteVoicePar[nvoice].VoiceFilterR) - NoteVoicePar[nvoice].VoiceFilterR->filterout(&tmpwaver[0]); + if(NoteVoicePar[nvoice].Filter) { + if(stereo) + NoteVoicePar[nvoice].Filter->filter(tmpwavel, tmpwaver); + else + NoteVoicePar[nvoice].Filter->filter(tmpwavel, 0); + } //check if the amplitude envelope is finished, if yes, the voice will be fadeout if(NoteVoicePar[nvoice].AmpEnvelope) @@ -1767,14 +1735,13 @@ int ADnote::noteout(float *outl, float *outr) //Processing Global parameters - NoteGlobalPar.GlobalFilterL->filterout(&outl[0]); - - if(stereo == 0) { //set the right channel=left channel + if(stereo) { + NoteGlobalPar.Filter->filter(outl, outr); + } else { //set the right channel=left channel + NoteGlobalPar.Filter->filter(outl, 0); memcpy(outr, outl, synth.bufferbytes); memcpy(bypassr, bypassl, synth.bufferbytes); } - else - NoteGlobalPar.GlobalFilterR->filterout(&outr[0]); for(int i = 0; i < synth.buffersize; ++i) { outl[i] += bypassl[i]; @@ -1881,8 +1848,7 @@ void ADnote::Voice::kill(Allocator &memory, const SYNTH_T &synth) memory.dealloc(FreqLfo); memory.dealloc(AmpEnvelope); memory.dealloc(AmpLfo); - memory.dealloc(VoiceFilterL); - memory.dealloc(VoiceFilterR); + memory.dealloc(Filter); memory.dealloc(FilterEnvelope); memory.dealloc(FilterLfo); memory.dealloc(FMFreqEnvelope); @@ -1905,8 +1871,7 @@ void ADnote::Global::kill(Allocator &memory) memory.dealloc(FreqLfo); memory.dealloc(AmpEnvelope); memory.dealloc(AmpLfo); - memory.dealloc(GlobalFilterL); - memory.dealloc(GlobalFilterR); + memory.dealloc(Filter); memory.dealloc(FilterEnvelope); memory.dealloc(FilterLfo); } @@ -1927,16 +1892,17 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam ¶m, Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB * VelF(velocity, param.PAmpVelocityScaleFunction); //sensing - GlobalFilterL = Filter::generate(memory, param.GlobalFilter, - synth.samplerate, synth.buffersize); - if(stereo) - GlobalFilterR = Filter::generate(memory, param.GlobalFilter, - synth.samplerate, synth.buffersize); - else - GlobalFilterR = NULL; + Filter = memory.alloc(*param.GlobalFilter, synth, time, memory, + stereo, basefreq); FilterEnvelope = memory.alloc(*param.FilterEnvelope, basefreq, synth.dt()); FilterLfo = memory.alloc(*param.FilterLfo, basefreq, time); - FilterQ = param.GlobalFilter->getq(); - FilterFreqTracking = param.GlobalFilter->getfreqtracking(basefreq); + + Filter->addMod(*FilterEnvelope); + Filter->addMod(*FilterLfo); + + { + Filter->updateSense(velocity, param.PFilterVelocityScale, + param.PFilterVelocityScaleFunction); + } } diff --git a/source/native-plugins/zynaddsubfx/Synth/ADnote.h b/source/native-plugins/zynaddsubfx/Synth/ADnote.h index 1fb250664..7218f2fd8 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ADnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/ADnote.h @@ -154,15 +154,9 @@ class ADnote:public SynthNote /****************************************** * FILTER GLOBAL PARAMETERS * ******************************************/ - class Filter * GlobalFilterL, *GlobalFilterR; - - float FilterCenterPitch; //octaves - float FilterQ; - float FilterFreqTracking; - - Envelope *FilterEnvelope; - - LFO *FilterLfo; + ModFilter *Filter; + Envelope *FilterEnvelope; + LFO *FilterLfo; } NoteGlobalPar; @@ -226,15 +220,9 @@ class ADnote:public SynthNote /************************* * FILTER PARAMETERS * *************************/ - - class Filter * VoiceFilterL; - class Filter * VoiceFilterR; - - float FilterCenterPitch; /* Filter center Pitch*/ - float FilterFreqTracking; - - Envelope *FilterEnvelope; - LFO *FilterLfo; + ModFilter *Filter; + Envelope *FilterEnvelope; + LFO *FilterLfo; /**************************** diff --git a/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp b/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp new file mode 100644 index 000000000..98a3ad399 --- /dev/null +++ b/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp @@ -0,0 +1,149 @@ +#include "ModFilter.h" +#include "Envelope.h" +#include "LFO.h" +#include "../Misc/Util.h" +#include "../Misc/Allocator.h" +#include "../Params/FilterParams.h" +#include "../DSP/Filter.h" +#include "../DSP/SVFilter.h" +#include "../DSP/AnalogFilter.h" +#include "../DSP/FormantFilter.h" +#include + +ModFilter::ModFilter(const FilterParams &pars_, + const SYNTH_T &synth_, + const AbsTime &time_, + Allocator &alloc_, + bool stereo, + float notefreq) + :pars(pars_), synth(synth_), time(time_), alloc(alloc_), + baseQ(pars.getq()), baseFreq(pars.getfreq()), + noteFreq(notefreq), + left(nullptr), + right(nullptr), + env(nullptr), + lfo(nullptr) +{ + tracking = pars.getfreqtracking(notefreq); + baseQ = pars.getq(); + baseFreq = pars.getfreq(); + + left = Filter::generate(alloc, &pars, + synth.samplerate, synth.buffersize); + + if(stereo) + right = Filter::generate(alloc, &pars, + synth.samplerate, synth.buffersize); +} + +ModFilter::~ModFilter(void) +{ + alloc.dealloc(left); + alloc.dealloc(right); +} + +void ModFilter::addMod(LFO &lfo_) +{ + lfo = &lfo_; +} + +void ModFilter::addMod(Envelope &env_) +{ + env = &env_; +} + +//Recompute Filter Parameters +void ModFilter::update(float relfreq, float relq) +{ + if(pars.last_update_timestamp == time.time()) { + paramUpdate(left); + if(right) + paramUpdate(right); + + baseFreq = pars.getfreq(); + baseQ = pars.getq(); + tracking = pars.getfreqtracking(noteFreq); + } + + //Controller Free Center Frequency + const float Fc = baseFreq + + sense + + (env ? env->envout() : 0) + + (lfo ? lfo->lfoout() : 0); + + const float Fc_mod = Fc + relfreq + tracking; + + //Convert into Hz + const float Fc_Hz = Filter::getrealfreq(Fc_mod); + + const float q = baseQ * relq; + + left->setfreq_and_q(Fc_Hz, q); + if(right) + right->setfreq_and_q(Fc_Hz, q); +} + +void ModFilter::updateNoteFreq(float noteFreq_) +{ + noteFreq = noteFreq_; + tracking = pars.getfreqtracking(noteFreq); +} + +void ModFilter::updateSense(float velocity, uint8_t scale, + uint8_t func) +{ + const float velScale = scale / 127.0f; + sense = velScale * 6.0f * (VelF(velocity, func) - 1); +} + +void ModFilter::filter(float *l, float *r) +{ + if(left && l) + left->filterout(l); + if(right && r) + right->filterout(r); +} + +static int current_category(Filter *f) +{ + if(dynamic_cast(f)) + return 0; + else if(dynamic_cast(f)) + return 1; + else if(dynamic_cast(f)) + return 2; + + assert(false); +} + +void ModFilter::paramUpdate(Filter *&f) +{ + //Common parameters + baseQ = pars.getq(); + baseFreq = pars.getfreq(); + + if(current_category(f) != pars.Pcategory) { + alloc.dealloc(f); + f = Filter::generate(alloc, &pars, + synth.samplerate, synth.buffersize); + return; + } + + if(auto *sv = dynamic_cast(f)) + svParamUpdate(*sv); + else if(auto *an = dynamic_cast(f)) + anParamUpdate(*an); +} + +void ModFilter::svParamUpdate(SVFilter &sv) +{ + sv.settype(pars.Ptype); + sv.setstages(pars.Pstages); +} + +void ModFilter::anParamUpdate(AnalogFilter &an) +{ + an.settype(pars.Ptype); + an.setstages(pars.Pstages); + an.setgain(pars.getgain()); +} diff --git a/source/native-plugins/zynaddsubfx/Synth/ModFilter.h b/source/native-plugins/zynaddsubfx/Synth/ModFilter.h new file mode 100644 index 000000000..ad22c914c --- /dev/null +++ b/source/native-plugins/zynaddsubfx/Synth/ModFilter.h @@ -0,0 +1,55 @@ +#pragma once +#include "../globals.h" +#include "../Misc/Time.h" + +//Modulated instance of one of the filters in src/DSP/ +//Supports stereo modes +class ModFilter +{ + public: + ModFilter(const FilterParams &pars, + const SYNTH_T &synth, + const AbsTime &time, + Allocator &alloc, + bool stereo, + float notefreq_); + ~ModFilter(void); + + void addMod(LFO &lfo); + void addMod(Envelope &env); + + //normal per tick update + void update(float relfreq, float relq); + + //updates typically seen in note-init + void updateNoteFreq(float noteFreq_); + void updateSense(float velocity, + uint8_t scale, uint8_t func); + + //filter stereo/mono signal(s) in-place + void filter(float *l, float *r); + private: + void paramUpdate(Filter *&f); + void svParamUpdate(SVFilter &sv); + void anParamUpdate(AnalogFilter &an); + + + const FilterParams &pars; //Parameters to Pull Updates From + const SYNTH_T &synth; //Synthesizer Buffer Parameters + const AbsTime &time; //Time for RT Updates + Allocator &alloc; //RT Memory Pool + + + + float baseQ; //filter sharpness + float baseFreq; //base filter frequency + float noteFreq; //frequency note was initialized to + float tracking; //shift due to note frequency + float sense; //shift due to note velocity + + + Filter *left; //left channel filter + Filter *right;//right channel filter + Envelope *env; //center freq envelope + LFO *lfo; //center freq lfo +}; diff --git a/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp b/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp index 759c9bedb..23d39e148 100644 --- a/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp @@ -18,11 +18,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include "PADnote.h" +#include "ModFilter.h" #include "../Misc/Config.h" #include "../Misc/Allocator.h" -#include "../DSP/Filter.h" #include "../Params/PADnoteParameters.h" #include "../Params/Controller.h" #include "../Params/FilterParams.h" @@ -32,6 +33,10 @@ PADnote::PADnote(const PADnoteParameters *parameters, SynthParams pars, const int& interpolation) :SynthNote(pars), pars(*parameters), interpolation(interpolation) { + NoteGlobalPar.GlobalFilter = nullptr; + NoteGlobalPar.FilterEnvelope = nullptr; + NoteGlobalPar.FilterLfo = nullptr; + firsttime = true; setup(pars.frequency, pars.velocity, pars.portamento, pars.note); } @@ -112,13 +117,6 @@ void PADnote::setup(float freq, else NoteGlobalPar.Panning = pars.PPanning / 128.0f; - NoteGlobalPar.FilterCenterPitch = pars.GlobalFilter->getfreq() //center freq - + pars.PFilterVelocityScale / 127.0f - * 6.0f //velocity sensing - * (VelF(velocity, - pars. - PFilterVelocityScaleFunction) - 1); - if(!legato) { NoteGlobalPar.Fadein_adjustment = pars.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE; @@ -157,17 +155,25 @@ void PADnote::setup(float freq, * NoteGlobalPar.AmpLfo->amplfoout(); if(!legato) { - NoteGlobalPar.GlobalFilterL = Filter::generate(memory, pars.GlobalFilter, - synth.samplerate, synth.buffersize); - NoteGlobalPar.GlobalFilterR = Filter::generate(memory, pars.GlobalFilter, - synth.samplerate, synth.buffersize); + auto &flt = NoteGlobalPar.GlobalFilter; + auto &env = NoteGlobalPar.FilterEnvelope; + auto &lfo = NoteGlobalPar.FilterLfo; + assert(flt == nullptr); + flt = memory.alloc(*pars.GlobalFilter, synth, time, memory, true, basefreq); + + //setup mod + env = memory.alloc(*pars.FilterEnvelope, basefreq, synth.dt()); + lfo = memory.alloc(*pars.FilterLfo, basefreq, time); + flt->addMod(*env); + flt->addMod(*lfo); + } - NoteGlobalPar.FilterEnvelope = memory.alloc(*pars.FilterEnvelope, basefreq, synth.dt()); - NoteGlobalPar.FilterLfo = memory.alloc(*pars.FilterLfo, basefreq, time); + { + auto &flt = *NoteGlobalPar.GlobalFilter; + flt.updateSense(velocity, pars.PFilterVelocityScale, + pars.PFilterVelocityScaleFunction); + flt.updateNoteFreq(basefreq); } - NoteGlobalPar.FilterQ = pars.GlobalFilter->getq(); - NoteGlobalPar.FilterFreqTracking = pars.GlobalFilter->getfreqtracking( - basefreq); if(!pars.sample[nsample].smp) { finished_ = true; @@ -198,8 +204,7 @@ PADnote::~PADnote() memory.dealloc(NoteGlobalPar.FreqLfo); memory.dealloc(NoteGlobalPar.AmpEnvelope); memory.dealloc(NoteGlobalPar.AmpLfo); - memory.dealloc(NoteGlobalPar.GlobalFilterL); - memory.dealloc(NoteGlobalPar.GlobalFilterR); + memory.dealloc(NoteGlobalPar.GlobalFilter); memory.dealloc(NoteGlobalPar.FilterEnvelope); memory.dealloc(NoteGlobalPar.FilterLfo); } @@ -230,8 +235,7 @@ inline void PADnote::fadein(float *smps) void PADnote::computecurrentparameters() { - float globalpitch, globalfilterpitch; - globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout() + const float globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout() + NoteGlobalPar.FreqLfo->lfoout() * ctl.modwheel.relmod + NoteGlobalPar.Detune); globaloldamplitude = globalnewamplitude; @@ -239,18 +243,8 @@ void PADnote::computecurrentparameters() * NoteGlobalPar.AmpEnvelope->envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); - globalfilterpitch = NoteGlobalPar.FilterEnvelope->envout() - + NoteGlobalPar.FilterLfo->lfoout() - + NoteGlobalPar.FilterCenterPitch; - - float tmpfilterfreq = globalfilterpitch + ctl.filtercutoff.relfreq - + NoteGlobalPar.FilterFreqTracking; - - tmpfilterfreq = Filter::getrealfreq(tmpfilterfreq); - - float globalfilterq = NoteGlobalPar.FilterQ * ctl.filterq.relq; - NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq, globalfilterq); - NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq, globalfilterq); + NoteGlobalPar.GlobalFilter->update(ctl.filtercutoff.relfreq, + ctl.filterq.relq); //compute the portamento, if it is used by this note float portamentofreqrap = 1.0f; @@ -377,8 +371,7 @@ int PADnote::noteout(float *outl, float *outr) firsttime = false; } - NoteGlobalPar.GlobalFilterL->filterout(outl); - NoteGlobalPar.GlobalFilterR->filterout(outr); + NoteGlobalPar.GlobalFilter->filter(outl, outr); //Apply the punch if(NoteGlobalPar.Punch.Enabled != 0) diff --git a/source/native-plugins/zynaddsubfx/Synth/PADnote.h b/source/native-plugins/zynaddsubfx/Synth/PADnote.h index acfa26249..987f949c3 100644 --- a/source/native-plugins/zynaddsubfx/Synth/PADnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/PADnote.h @@ -98,15 +98,9 @@ class PADnote:public SynthNote /****************************************** * FILTER GLOBAL PARAMETERS * ******************************************/ - class Filter * GlobalFilterL, *GlobalFilterR; - - float FilterCenterPitch; //octaves - float FilterQ; - float FilterFreqTracking; - - Envelope *FilterEnvelope; - - LFO *FilterLfo; + ModFilter *GlobalFilter; + Envelope *FilterEnvelope; + LFO *FilterLfo; } NoteGlobalPar; diff --git a/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp b/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp index 31b0371c6..2c297e51b 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp @@ -28,16 +28,24 @@ #include "../globals.h" #include "SUBnote.h" #include "Envelope.h" +#include "ModFilter.h" #include "../Params/Controller.h" #include "../Params/SUBnoteParameters.h" #include "../Params/FilterParams.h" +#include "../Misc/Time.h" #include "../Misc/Util.h" #include "../Misc/Allocator.h" SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars) - :SynthNote(spars), pars(*parameters) + :SynthNote(spars), pars(*parameters), + AmpEnvelope(nullptr), + FreqEnvelope(nullptr), + BandWidthEnvelope(nullptr), + GlobalFilter(nullptr), + GlobalFilterEnvelope(nullptr), + NoteEnabled(ON), + lfilter(nullptr), rfilter(nullptr) { - NoteEnabled = ON; setup(spars.frequency, spars.velocity, spars.portamento, spars.note); } @@ -56,12 +64,14 @@ void SUBnote::setup(float freq, panning = pars.PPanning / 127.0f; else panning = RND; - if(!legato) { + + if(!legato) { //normal note numstages = pars.Pnumstages; stereo = pars.Pstereo; start = pars.Pstart; firsttick = 1; } + int pos[MAX_SUB_HARMONICS]; if(pars.Pfixedfreq == 0) @@ -91,20 +101,6 @@ void SUBnote::setup(float freq, basefreq *= powf(2.0f, detune / 1200.0f); //detune // basefreq*=ctl.pitchwheel.relfreq;//pitch wheel - //global filter - GlobalFilterCenterPitch = pars.GlobalFilter->getfreq() //center freq - + (pars.PGlobalFilterVelocityScale / 127.0f - * 6.0f) //velocity sensing - * (VelF(velocity, - pars.PGlobalFilterVelocityScaleFunction) - - 1); - - if(!legato) { - GlobalFilterL = NULL; - GlobalFilterR = NULL; - GlobalFilterEnvelope = NULL; - } - int harmonics = 0; //select only harmonics that desire to compute @@ -113,7 +109,7 @@ void SUBnote::setup(float freq, continue; pos[harmonics++] = n; } - if(!legato) + if(!legato) //normal note firstnumharmonics = numharmonics = harmonics; else { if(harmonics > firstnumharmonics) @@ -129,7 +125,7 @@ void SUBnote::setup(float freq, } - if(!legato) { + if(!legato) { //normal note lfilter = memory.valloc(numstages * numharmonics); if(stereo) rfilter = memory.valloc(numstages * numharmonics); @@ -199,7 +195,7 @@ void SUBnote::setup(float freq, oldpitchwheel = 0; oldbandwidth = 64; - if(!legato) { + if(!legato) { //normal note if(pars.Pfixedfreq == 0) initparameters(basefreq); else @@ -211,13 +207,14 @@ void SUBnote::setup(float freq, else freq *= basefreq / 440.0f; - if(pars.PGlobalFilterEnabled) { - globalfiltercenterq = pars.GlobalFilter->getq(); - GlobalFilterFreqTracking = pars.GlobalFilter->getfreqtracking( - basefreq); - } + if(GlobalFilter) + GlobalFilter->updateNoteFreq(basefreq); } + if(GlobalFilter) + GlobalFilter->updateSense(velocity, pars.PGlobalFilterVelocityScale, + pars.PGlobalFilterVelocityScaleFunction); + oldamplitude = newamplitude; } @@ -260,8 +257,7 @@ void SUBnote::KillNote() memory.dealloc(AmpEnvelope); memory.dealloc(FreqEnvelope); memory.dealloc(BandWidthEnvelope); - memory.dealloc(GlobalFilterL); - memory.dealloc(GlobalFilterR); + memory.dealloc(GlobalFilter); memory.dealloc(GlobalFilterEnvelope); NoteEnabled = OFF; } @@ -383,23 +379,19 @@ void SUBnote::filter(bpfilter &filter, float *smps) void SUBnote::initparameters(float freq) { AmpEnvelope = memory.alloc(*pars.AmpEnvelope, freq, synth.dt()); + if(pars.PFreqEnvelopeEnabled) FreqEnvelope = memory.alloc(*pars.FreqEnvelope, freq, synth.dt()); - else - FreqEnvelope = NULL; + if(pars.PBandWidthEnvelopeEnabled) BandWidthEnvelope = memory.alloc(*pars.BandWidthEnvelope, freq, synth.dt()); - else - BandWidthEnvelope = NULL; + if(pars.PGlobalFilterEnabled) { - globalfiltercenterq = pars.GlobalFilter->getq(); - GlobalFilterL = Filter::generate(memory, pars.GlobalFilter, - synth.samplerate, synth.buffersize); - if(stereo) - GlobalFilterR = Filter::generate(memory, pars.GlobalFilter, - synth.samplerate, synth.buffersize); GlobalFilterEnvelope = memory.alloc(*pars.GlobalFilterEnvelope, freq, synth.dt()); - GlobalFilterFreqTracking = pars.GlobalFilter->getfreqtracking(basefreq); + + GlobalFilter = memory.alloc(*pars.GlobalFilter, synth, time, memory, stereo, freq); + + GlobalFilter->addMod(*GlobalFilterEnvelope); } computecurrentparameters(); } @@ -492,21 +484,9 @@ void SUBnote::computecurrentparameters() newamplitude = volume * AmpEnvelope->envout_dB() * 2.0f; //Filter - if(GlobalFilterL != NULL) { - float globalfilterpitch = GlobalFilterCenterPitch - + GlobalFilterEnvelope->envout(); - float filterfreq = globalfilterpitch + ctl.filtercutoff.relfreq - + GlobalFilterFreqTracking; - filterfreq = Filter::getrealfreq(filterfreq); - - GlobalFilterL->setfreq_and_q(filterfreq, - globalfiltercenterq * ctl.filterq.relq); - if(GlobalFilterR != NULL) - GlobalFilterR->setfreq_and_q( - filterfreq, - globalfiltercenterq - * ctl.filterq.relq); - } + if(GlobalFilter) + GlobalFilter->update(ctl.filtercutoff.relfreq, + ctl.filterq.relq); } /* @@ -534,8 +514,6 @@ int SUBnote::noteout(float *outl, float *outr) outl[i] += tmpsmp[i] * rolloff; } - if(GlobalFilterL != NULL) - GlobalFilterL->filterout(&outl[0]); //right channel if(stereo) { @@ -549,11 +527,15 @@ int SUBnote::noteout(float *outl, float *outr) for(int i = 0; i < synth.buffersize; ++i) outr[i] += tmpsmp[i] * rolloff; } - if(GlobalFilterR != NULL) - GlobalFilterR->filterout(&outr[0]); - } - else + if(GlobalFilter) + GlobalFilter->filter(outl, outr); + + } else { + if(GlobalFilter) + GlobalFilter->filter(outl, 0); + memcpy(outr, outl, synth.bufferbytes); + } if(firsttick != 0) { int n = 10; diff --git a/source/native-plugins/zynaddsubfx/Synth/SUBnote.h b/source/native-plugins/zynaddsubfx/Synth/SUBnote.h index b57b7bd1d..b33a29846 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SUBnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/SUBnote.h @@ -25,7 +25,6 @@ #include "SynthNote.h" #include "../globals.h" -#include "../DSP/Filter.h" class SUBnote:public SynthNote { @@ -48,6 +47,10 @@ class SUBnote:public SynthNote int midinote, bool legato = false); void computecurrentparameters(); + /* + * Initialize envelopes and global filter + * calls computercurrentparameters() + */ void initparameters(float freq); void KillNote(); @@ -67,18 +70,14 @@ class SUBnote:public SynthNote Envelope *FreqEnvelope; Envelope *BandWidthEnvelope; - Filter *GlobalFilterL, *GlobalFilterR; - - Envelope *GlobalFilterEnvelope; + ModFilter *GlobalFilter; + Envelope *GlobalFilterEnvelope; //internal values ONOFFTYPE NoteEnabled; int firsttick, portamento; float volume, oldamplitude, newamplitude; - float GlobalFilterCenterPitch; //octaves - float GlobalFilterFreqTracking; - struct bpfilter { float freq, bw, amp; //filter parameters float a1, a2, b0, b2; //filter coefs. b1=0 diff --git a/source/native-plugins/zynaddsubfx/UI/BankUI.fl b/source/native-plugins/zynaddsubfx/UI/BankUI.fl index f98b61b81..099aa75da 100644 --- a/source/native-plugins/zynaddsubfx/UI/BankUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/BankUI.fl @@ -72,10 +72,7 @@ class BankUI {open dirname=fl_input("New empty Bank:"); if (dirname==NULL) return; - -osc->write("/newbank", "s", dirname); -/*if (result!=0) fl_alert("Error: Could not make a new bank (directory)..");*/ - +osc->write("/bank/newbank", "s", dirname); refreshmainwindow();} xywh {685 5 93 25} labelfont 1 labelsize 11 align 128 } diff --git a/source/native-plugins/zynaddsubfx/UI/MasterUI.fl b/source/native-plugins/zynaddsubfx/UI/MasterUI.fl index 91aaa0591..4c278766d 100644 --- a/source/native-plugins/zynaddsubfx/UI/MasterUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/MasterUI.fl @@ -336,9 +336,7 @@ filename=fl_file_chooser("Open:","({*.xsz})",NULL,0); if (filename==NULL) return; osc->write("/load_xsz", "s", filename); -/* -if (result==-10) fl_alert("Error: Could not load the file\\nbecause it is not a scale file."); - else if (result<0) fl_alert("Error: Could not load the file.");*/} +} xywh {40 40 100 20} } MenuItem {} { @@ -358,9 +356,7 @@ if (result) { }; -osc->write("/save_xsz", "s", filename); - -/*if (result<0) fl_alert("Error: Could not save the file.");*/} +osc->write("/save_xsz", "s", filename); } xywh {30 30 100 20} } MenuItem {} { diff --git a/source/native-plugins/zynaddsubfx/UI/MicrotonalUI.fl b/source/native-plugins/zynaddsubfx/UI/MicrotonalUI.fl index 6ca5676b8..f8fb4e564 100644 --- a/source/native-plugins/zynaddsubfx/UI/MicrotonalUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/MicrotonalUI.fl @@ -96,7 +96,8 @@ class MicrotonalUI {} { Fl_Input tuningsinput { label {Tunings:} xywh {8 144 182 264} type Multiline labelfont 1 labelsize 11 align 5 when 2 - code0 {updateTuningsInput();} + code0 {o->init("tunings");} + class Fl_Osc_Input } Fl_Input commentinput { label {Comment:} @@ -113,23 +114,18 @@ class MicrotonalUI {} { } Fl_Button {} { label {Import .SCL file} - callback {/*const char *filename; + callback {const char *filename; filename=fl_file_chooser("Open:","(*.scl)",NULL,0); if (filename==NULL) return; -int result=microtonal->loadscl(filename); -if (result==0) { +osc->write("/load_scl", "s", filename); +if (true) { updateTuningsInput(); - nameinput->cut(0,nameinput->maximum_size()); - nameinput->insert((char *)microtonal->Pname); - nameinput->position(0); - commentinput->cut(0,commentinput->maximum_size()); - commentinput->insert((char *)microtonal->Pname); - commentinput->position(0); + nameinput->update(); + commentinput->update(); tuningsinput->position(0); - octavesizeoutput->do_callback(); - } else { - fl_alert("Error: Could not load the file."); - };*/} + octavesizeoutput->update(); + } + } tooltip {Inport Scala .scl file (tunnings)} xywh {243 411 84 15} box THIN_UP_BOX labelfont 1 labelsize 10 } Fl_Group keymappinggroup { @@ -138,7 +134,8 @@ if (result==0) { } { Fl_Input mappinginput { xywh {250 147 146 258} type Multiline labelfont 1 labelsize 11 align 5 when 2 - code0 {updateMappingInput();} + code0 {o->init("mapping");} + class Fl_Osc_Input } Fl_Counter firstnotecounter { label {First note} @@ -177,12 +174,11 @@ o->show();} Fl_Button {} { label {Import .kbm file} callback { - //TODO Disabled until this can be moved into middleware - /*const char *filename; + const char *filename; filename=fl_file_chooser("Open:","(*.kbm)",NULL,0); if (filename==NULL) return; -int result=microtonal->loadkbm(filename); -if (result==0) { +osc->write("/load_kbm", "s", filename); +if (true) { updateMappingInput(); mappinginput->position(0); mapsizeoutput->update(); @@ -192,9 +188,7 @@ if (result==0) { mappingenabledbutton->update(); afreqinput->update(); anotecounter->update(); - } else { - fl_alert("Error: Could not load the file."); - };*/} + }} tooltip {Inport Scala .kbm file (keyboard mapping)} xywh {243 428 84 16} box THIN_UP_BOX labelfont 1 labelsize 10 } } @@ -236,39 +230,13 @@ o->redraw();} } } Function {updateTuningsInput()} {} { - code {char *tmpbuf=new char[100]; - -/* -tuningsinput->cut(0,tuningsinput->maximum_size()); - -for (int i=0;igetoctavesize();i++){ - if (i!=0) tuningsinput->insert("\\n"); - microtonal->tuningtoline(i,tmpbuf,100); - tuningsinput->insert(tmpbuf); -}; -*/ - -delete []tmpbuf;} {} + code {tuningsinput->update();} {} } Function {updateMappingInput()} {} { - code {char *tmpbuf=new char[100]; - -/* -mappinginput->cut(0,tuningsinput->maximum_size()); - -for (int i=0;iPmapsize;i++){ - if (i!=0) mappinginput->insert("\\n"); - if ((microtonal->Pmapping[i])==-1) - snprintf(tmpbuf,100,"x"); - else snprintf(tmpbuf,100,"%d",microtonal->Pmapping[i]); - mappinginput->insert(tmpbuf); -}; -*/ - -delete []tmpbuf;} {} + code { mappinginput->update(); } {} } - Function {MicrotonalUI(Fl_Osc_Interface *osc, std::string base)} {} { - code {make_window(osc, base);} {} + Function {MicrotonalUI(Fl_Osc_Interface *osc_, std::string base)} {} { + code {osc=osc_;make_window(osc, base);} {} } Function {~MicrotonalUI()} {} { code {microtonaluiwindow->hide(); @@ -278,15 +246,14 @@ delete(microtonaluiwindow);} {} code {microtonaluiwindow->show();} {} } Function {apply()} {} { - code {/*int err=microtonal->texttotunings(tuningsinput->value()); -if (err>=0) fl_alert("Parse Error: The input may contain only numbers (like 232.59)\\n or divisions (like 121/64)."); -if (err==-2) fl_alert("Parse Error: The input is empty."); -octavesizeoutput->do_callback(); - -microtonal->texttomapping(mappinginput->value()); -mapsizeoutput->do_callback(); -anotecounter->do_callback(); -*/ -//applybutton->color(FL_GRAY);} {} + code { + osc->write("/microtonal/tunings", "s", tuningsinput->value()); + osc->write("/microtonal/mapping", "s", mappinginput->value()); + octavesizeoutput->update(); + mapsizeoutput->update(); + anotecounter->update(); + } {} + } + decl {Fl_Osc_Interface *osc;} {private local } } diff --git a/source/native-plugins/zynaddsubfx/globals.h b/source/native-plugins/zynaddsubfx/globals.h index cf8f639b3..215e2073e 100644 --- a/source/native-plugins/zynaddsubfx/globals.h +++ b/source/native-plugins/zynaddsubfx/globals.h @@ -62,6 +62,12 @@ class Controller; class Master; class Part; +class Filter; +class AnalogFilter; +class SVFilter; +class FormantFilter; +class ModFilter; + #if defined(__APPLE__) || defined(__FreeBSD__) #include #else diff --git a/source/native-plugins/zynaddsubfx/main.cpp b/source/native-plugins/zynaddsubfx/main.cpp index b8fb80452..07116f805 100644 --- a/source/native-plugins/zynaddsubfx/main.cpp +++ b/source/native-plugins/zynaddsubfx/main.cpp @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) << "\nZynAddSubFX - Copyright (c) 2002-2013 Nasca Octavian Paul and others" << endl; cerr - << " Copyright (c) 2009-2015 Mark McCurry [active maintainer]" + << " Copyright (c) 2009-2016 Mark McCurry [active maintainer]" << endl; cerr << "Compiled: " << __DATE__ << " " << __TIME__ << endl; cerr << "This program is free software (GNU GPL v2 or later) and \n";