| @@ -51,6 +51,51 @@ void SVFilter::cleanup() | |||||
| abovenq = false; | abovenq = false; | ||||
| } | } | ||||
| SVFilter::response::response(float b0, float b1, float b2, | |||||
| float a0, float a1 ,float a2) | |||||
| { | |||||
| a[0] = a0; | |||||
| a[1] = a1; | |||||
| a[2] = a2; | |||||
| b[0] = b0; | |||||
| b[1] = b1; | |||||
| b[2] = b2; | |||||
| } | |||||
| SVFilter::response SVFilter::computeResponse(int type, | |||||
| float freq, float pq, int stages, float gain, float fs) | |||||
| { | |||||
| typedef SVFilter::response res; | |||||
| float f = freq / fs * 4.0; | |||||
| if(f > 0.99999f) | |||||
| f = 0.99999f; | |||||
| float q = 1.0f - atanf(sqrtf(pq)) * 2.0f / PI; | |||||
| q = powf(q, 1.0f / (stages + 1)); | |||||
| float qrt = sqrtf(q); | |||||
| float g = powf(gain, 1.0 / (stages + 1)); | |||||
| if(type == 0) { //Low | |||||
| return res{0, g*f*f*qrt, 0, | |||||
| 1, (q*f+f*f-2), (1-q*f)}; | |||||
| } | |||||
| if(type == 1) {//High | |||||
| //g *= qrt/(1+f*q); | |||||
| g *= qrt; | |||||
| return res{g, -2*g, g, | |||||
| //1, (f*f-2*f*q-2)/(1+f*q), 1}; | |||||
| 1, (q*f+f*f-2), (1-q*f)}; | |||||
| } | |||||
| if(type == 2) {//Band | |||||
| g *= f*qrt; | |||||
| return res{g, -g, 0, | |||||
| 1, (q*f+f*f-2), (1-q*f)}; | |||||
| } | |||||
| if(type == 3 || true) {//Notch | |||||
| g *= qrt; | |||||
| return res{g, -2*g+g*f*f, g, | |||||
| 1, (q*f+f*f-2), (1-q*f)}; | |||||
| } | |||||
| } | |||||
| void SVFilter::computefiltercoefs(void) | void SVFilter::computefiltercoefs(void) | ||||
| { | { | ||||
| par.f = freq / samplerate_f * 4.0f; | par.f = freq / samplerate_f * 4.0f; | ||||
| @@ -136,7 +181,8 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) | |||||
| out = &x.notch; | out = &x.notch; | ||||
| break; | break; | ||||
| default: | default: | ||||
| errx(1, "Impossible SVFilter type encountered [%d]", type); | |||||
| out = &x.low; | |||||
| warnx("Impossible SVFilter type encountered [%d]", type); | |||||
| } | } | ||||
| for(int i = 0; i < buffersize; ++i) { | for(int i = 0; i < buffersize; ++i) { | ||||
| @@ -148,6 +194,17 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) | |||||
| } | } | ||||
| } | } | ||||
| // simplifying the responses | |||||
| // xl = xl*z(-1) + pf*xb*z(-1) | |||||
| // xh = pq1*x - xl - pq*xb*z(-1) | |||||
| // xb = pf*xh + xb*z(-1) | |||||
| // xn = xh + xl | |||||
| // | |||||
| // xl = pf*xb*z(-1)/(1-z(-1)) | |||||
| // xb = pf*xh/(1-z(-1)) | |||||
| // xl = pf*pfxh*z(-1)/(1-z(-1))^2 | |||||
| void SVFilter::filterout(float *smp) | void SVFilter::filterout(float *smp) | ||||
| { | { | ||||
| for(int i = 0; i < stages + 1; ++i) | for(int i = 0; i < stages + 1; ++i) | ||||
| @@ -36,6 +36,15 @@ class SVFilter:public Filter | |||||
| void setstages(int stages_); | void setstages(int stages_); | ||||
| void cleanup(); | void cleanup(); | ||||
| struct response { | |||||
| response(float b0, float b1, float b2, | |||||
| float a0, float a1 ,float a2); | |||||
| float a[3]; | |||||
| float b[3]; | |||||
| }; | |||||
| static response computeResponse(int type, | |||||
| float freq, float pq, int stages, float g, float fs); | |||||
| private: | private: | ||||
| struct fstage { | struct fstage { | ||||
| float low, high, band, notch; | float low, high, band, notch; | ||||
| @@ -131,9 +131,12 @@ static const rtosc::Ports local_ports = { | |||||
| //Return the old data for distruction | //Return the old data for distruction | ||||
| d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_); | d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_); | ||||
| }}, | }}, | ||||
| rSubtype(Echo), | |||||
| rSubtype(Alienwah), | rSubtype(Alienwah), | ||||
| rSubtype(Chorus), | |||||
| rSubtype(Distorsion), | rSubtype(Distorsion), | ||||
| rSubtype(Echo), | |||||
| rSubtype(Phaser), | |||||
| rSubtype(Reverb), | |||||
| }; | }; | ||||
| const rtosc::Ports &EffectMgr::ports = local_ports; | const rtosc::Ports &EffectMgr::ports = local_ports; | ||||
| @@ -34,21 +34,21 @@ rtosc::Ports Phaser::ports = { | |||||
| rBegin; | rBegin; | ||||
| rEnd}, | rEnd}, | ||||
| //Pvolume/Ppanning are common | //Pvolume/Ppanning are common | ||||
| rEffPar(lfo.Pfreq, 2, ""), | |||||
| rEffPar(lfo.Prandomness, 3, ""), | |||||
| rEffPar(lfo.PLFOtype, 4, ""), | |||||
| rEffPar(lfo.Pstereo, 5, ""), | |||||
| rEffPar(Pdepth, 6, ""), | |||||
| rEffPar(Pfb, 7, ""), | |||||
| rEffPar(Pstages, 8, ""), | |||||
| rEffPar(Plrcross, 9, ""), | |||||
| rEffPar(Poffset, 9, ""), | |||||
| rEffParTF(Poutsub, 10, ""), | |||||
| rEffPar(Pphase, 11, ""), | |||||
| rEffPar(Pwidth, 11, ""), | |||||
| rEffPar(Phyper, 12, ""), | |||||
| rEffPar(Pdistortion, 13, ""), | |||||
| rEffPar(Panalog, 14, ""), | |||||
| rEffPar(lfo.Pfreq, 2, rShort("freq"), ""), | |||||
| rEffPar(lfo.Prandomness, 3, rShort("rnd."), ""), | |||||
| rEffPar(lfo.PLFOtype, 4, rShort("type"), ""), | |||||
| rEffParTF(lfo.Pstereo, 5, rShort("stereo"), ""), | |||||
| rEffPar(Pdepth, 6, rShort("depth"), ""), | |||||
| rEffPar(Pfb, 7, rShort("fb"), ""), | |||||
| rEffPar(Pstages, 8, rShort("stages"), ""), | |||||
| rEffPar(Plrcross, 9, rShort("cross"), ""), | |||||
| rEffPar(Poffset, 9, rShort("off"), ""), | |||||
| rEffParTF(Poutsub, 10, rShort("sub") ""), | |||||
| rEffPar(Pphase, 11, rShort("phase"), ""), | |||||
| rEffPar(Pwidth, 11, rShort("width"), ""), | |||||
| rEffParTF(Phyper, 12, rShort("hyp."), ""), | |||||
| rEffPar(Pdistortion, 13, rShort("distort"), "Distortion"), | |||||
| rEffParTF(Panalog, 14, rShort("analog"), ""), | |||||
| }; | }; | ||||
| #undef rBegin | #undef rBegin | ||||
| #undef rEnd | #undef rEnd | ||||
| @@ -17,6 +17,36 @@ | |||||
| #include "../DSP/AnalogFilter.h" | #include "../DSP/AnalogFilter.h" | ||||
| #include "../DSP/Unison.h" | #include "../DSP/Unison.h" | ||||
| #include <cmath> | #include <cmath> | ||||
| #include <rtosc/ports.h> | |||||
| #include <rtosc/port-sugar.h> | |||||
| #define rObject Reverb | |||||
| #define rBegin [](const char *, rtosc::RtData &) { | |||||
| #define rEnd } | |||||
| rtosc::Ports Reverb::ports = { | |||||
| {"preset::i", rOptions(Cathedral1, Cathedral2, Cathedral3, | |||||
| Hall1, Hall2, Room1, Room2, Basement, | |||||
| Tunnel, Echoed1, Echoed2, VeryLong1, VeryLong2) | |||||
| rProp(parameter) | |||||
| rDoc("Instrument Presets"), 0, | |||||
| rBegin; | |||||
| rEnd}, | |||||
| //Pvolume/Ppanning are common | |||||
| rEffPar(Ptime, 2, rShort("time"), "Length of Reverb"), | |||||
| rEffPar(Pidelay, 3, rShort("i.time"), "Delay for first impulse"), | |||||
| rEffPar(Pidelayfb,4, rShort("i.fb"), "Feedback for first impulse"), | |||||
| rEffPar(Plpf, 7, rShort("lpf"), "Low pass filter"), | |||||
| rEffPar(Phpf, 8, rShort("lpf"), "High pass filter"), | |||||
| rEffPar(Plohidamp,9, rShort("damp"), "Dampening"), | |||||
| //Todo make this a selector | |||||
| rEffPar(Ptype, 10,rShort("type"), "Type"), | |||||
| rEffPar(Proomsize,11,rShort("size"), "Room Size"), | |||||
| rEffPar(Pbandwidth,12,rShort("bw"), "Bandwidth"), | |||||
| }; | |||||
| #undef rBegin | |||||
| #undef rEnd | |||||
| #undef rObject | |||||
| Reverb::Reverb(EffectParams pars) | Reverb::Reverb(EffectParams pars) | ||||
| :Effect(pars), | :Effect(pars), | ||||
| @@ -32,6 +32,7 @@ class Reverb:public Effect | |||||
| void changepar(int npar, unsigned char value); | void changepar(int npar, unsigned char value); | ||||
| unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
| static rtosc::Ports ports; | |||||
| private: | private: | ||||
| //Parametrii | //Parametrii | ||||
| unsigned char Pvolume; | unsigned char Pvolume; | ||||
| @@ -16,7 +16,7 @@ | |||||
| #include <mxml.h> | #include <mxml.h> | ||||
| #include <string> | #include <string> | ||||
| #include <vector> | #include <vector> | ||||
| #include "../version.h" | |||||
| #include "../zyn-version.h" | |||||
| #ifndef XML_WRAPPER_H | #ifndef XML_WRAPPER_H | ||||
| #define XML_WRAPPER_H | #define XML_WRAPPER_H | ||||
| @@ -15,6 +15,7 @@ | |||||
| #include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
| #include "../Misc/Time.h" | #include "../Misc/Time.h" | ||||
| #include "../DSP/AnalogFilter.h" | #include "../DSP/AnalogFilter.h" | ||||
| #include "../DSP/SVFilter.h" | |||||
| #include <cmath> | #include <cmath> | ||||
| #include <cstdio> | #include <cstdio> | ||||
| #include <cstdlib> | #include <cstdlib> | ||||
| @@ -89,6 +90,9 @@ const rtosc::Ports FilterParams::ports = { | |||||
| rToggle(Psequencereversed, "If the modulator input is inverted"), | rToggle(Psequencereversed, "If the modulator input is inverted"), | ||||
| //{"Psequence#" FF_MAX_SEQUENCE "/nvowel", "", NULL, [](){}}, | //{"Psequence#" FF_MAX_SEQUENCE "/nvowel", "", NULL, [](){}}, | ||||
| {"type-svf::i", rProp(parameter) rShort("type") | |||||
| rOptions(low, high, band, notch) | |||||
| rDoc("Filter Type"), 0, rOptionCb(Ptype)}, | |||||
| //UI reader | //UI reader | ||||
| {"Pvowels:", rDoc("Get Formant Vowels"), NULL, | {"Pvowels:", rDoc("Get Formant Vowels"), NULL, | ||||
| @@ -132,24 +136,37 @@ const rtosc::Ports FilterParams::ports = { | |||||
| rDoc("Get a frequency response"), | rDoc("Get a frequency response"), | ||||
| NULL, [](const char *, RtData &d) { | NULL, [](const char *, RtData &d) { | ||||
| FilterParams *obj = (FilterParams *) d.obj; | FilterParams *obj = (FilterParams *) d.obj; | ||||
| int order = 0; | |||||
| float gain = dB2rap(obj->getgain()); | |||||
| if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) | |||||
| gain = 1.0; | |||||
| auto cf = AnalogFilter::computeCoeff(obj->Ptype, | |||||
| Filter::getrealfreq(obj->getfreq()), | |||||
| obj->getq(), obj->Pstages, | |||||
| gain, 48000, order); | |||||
| if(order == 2) { | |||||
| if(obj->Pcategory == 0) { | |||||
| int order = 0; | |||||
| float gain = dB2rap(obj->getgain()); | |||||
| if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) | |||||
| gain = 1.0; | |||||
| auto cf = AnalogFilter::computeCoeff(obj->Ptype, | |||||
| Filter::getrealfreq(obj->getfreq()), | |||||
| obj->getq(), obj->Pstages, | |||||
| gain, 48000, order); | |||||
| if(order == 2) { | |||||
| d.reply(d.loc, "fffffff", | |||||
| (float)obj->Pstages, | |||||
| cf.c[0], cf.c[1], cf.c[2], | |||||
| 0.0, cf.d[1], cf.d[2]); | |||||
| } else if(order == 1) { | |||||
| d.reply(d.loc, "fffff", | |||||
| (float)obj->Pstages, | |||||
| cf.c[0], cf.c[1], | |||||
| 0.0, cf.d[1]); | |||||
| } | |||||
| } else if(obj->Pcategory == 2) { | |||||
| int order = 0; | |||||
| float gain = dB2rap(obj->getgain()); | |||||
| auto cf = SVFilter::computeResponse(obj->Ptype, | |||||
| Filter::getrealfreq(obj->getfreq()), | |||||
| obj->getq(), obj->Pstages, | |||||
| gain, 48000); | |||||
| d.reply(d.loc, "fffffff", | d.reply(d.loc, "fffffff", | ||||
| (float)obj->Pstages, | (float)obj->Pstages, | ||||
| cf.c[0], cf.c[1], cf.c[2], | |||||
| 0.0, cf.d[1], cf.d[2]); | |||||
| } else if(order == 1) { | |||||
| d.reply(d.loc, "fffff", | |||||
| (float)obj->Pstages, | |||||
| cf.c[0], cf.c[1], | |||||
| 0.0, cf.d[1]); | |||||
| cf.b[0], cf.b[1], cf.b[2], | |||||
| 0.0, -cf.a[1], -cf.a[2]); | |||||
| } | } | ||||
| }}, | }}, | ||||
| // "", NULL, [](){}},"/freq" | // "", NULL, [](){}},"/freq" | ||||
| @@ -35,7 +35,7 @@ | |||||
| #include "Misc/Master.h" | #include "Misc/Master.h" | ||||
| #include "Misc/Part.h" | #include "Misc/Part.h" | ||||
| #include "Misc/Util.h" | #include "Misc/Util.h" | ||||
| #include "version.h" | |||||
| #include "zyn-version.h" | |||||
| //Nio System | //Nio System | ||||
| #include "Nio/Nio.h" | #include "Nio/Nio.h" | ||||
| @@ -27,6 +27,7 @@ | |||||
| //Hack to workaround old incomplete decltype implementations | //Hack to workaround old incomplete decltype implementations | ||||
| #ifdef __GNUC__ | #ifdef __GNUC__ | ||||
| #ifndef __clang__ | |||||
| #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 7) | #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 7) | ||||
| template<typename T> | template<typename T> | ||||
| struct rtosc_hack_decltype_t | struct rtosc_hack_decltype_t | ||||
| @@ -37,6 +38,7 @@ struct rtosc_hack_decltype_t | |||||
| #define decltype(expr) rtosc_hack_decltype_t<decltype(expr)>::type | #define decltype(expr) rtosc_hack_decltype_t<decltype(expr)>::type | ||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| #endif | |||||
| //General macro utilities | //General macro utilities | ||||
| #define STRINGIFY2(a) #a | #define STRINGIFY2(a) #a | ||||
| @@ -13,7 +13,7 @@ | |||||
| #include <iostream> | #include <iostream> | ||||
| #include "version.h" | |||||
| #include "zyn-version.h" | |||||
| constexpr int version_type::v_strcmp(const version_type& v2, int i) const | constexpr int version_type::v_strcmp(const version_type& v2, int i) const | ||||
| { | { | ||||
| @@ -33,7 +33,7 @@ public: | |||||
| //! constructs the current zynaddsubfx version | //! constructs the current zynaddsubfx version | ||||
| constexpr version_type() : | constexpr version_type() : | ||||
| version_type(2, 5, 4) | |||||
| version_type(2, 4, 4) | |||||
| { | { | ||||
| } | } | ||||