zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 0d5230fa8635975ce071ba87a31d7d7bafe341f4
parent ffca051ad9d7bfef49192de413a96e7f0c04605e
Author: Johannes Lorenz <johannes89@ist-einmalig.de>
Date:   Mon, 18 Sep 2017 22:27:32 +0200

Merge

Diffstat:
Msrc/CMakeLists.txt | 6++++--
Msrc/Effects/Alienwah.cpp | 29+++++++++++++++++++----------
Msrc/Effects/Chorus.cpp | 2+-
Msrc/Effects/Distorsion.cpp | 32++++++++++++++++++++------------
Msrc/Effects/DynamicFilter.cpp | 28++++++++++++++++++----------
Msrc/Effects/Echo.cpp | 23+++++++++++++++++------
Msrc/Effects/Effect.h | 29+++++++++++++++++++++++++++--
Msrc/Effects/EffectMgr.cpp | 26++++++++++----------------
Msrc/Effects/Phaser.cpp | 64+++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/Effects/Reverb.cpp | 42+++++++++++++++++++++++++++++++-----------
Msrc/Misc/Config.cpp | 26++++++++++++++------------
Msrc/Misc/Master.cpp | 2+-
Msrc/Misc/Master.h | 17+++++++++++++++--
Msrc/Misc/Microtonal.cpp | 2+-
Msrc/Misc/MiddleWare.cpp | 228++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/Misc/Part.cpp | 5++---
Msrc/Misc/Part.h | 4+++-
Msrc/Misc/Schema.cpp | 12+++++++++++-
Msrc/Misc/Util.h | 7++-----
Msrc/Misc/XMLwrapper.cpp | 2+-
Msrc/Output/DSSIaudiooutput.cpp | 5+++--
Msrc/Params/ADnoteParameters.cpp | 3+--
Msrc/Params/ADnoteParameters.h | 8++++----
Msrc/Params/Controller.cpp | 75++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/Params/EnvelopeParams.cpp | 94+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/Params/EnvelopeParams.h | 42++++++++++++++++++++++++++++++++----------
Msrc/Params/FilterParams.cpp | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/Params/FilterParams.h | 19++++++++++++-------
Msrc/Params/LFOParams.cpp | 7+++++--
Msrc/Params/PADnoteParameters.cpp | 102+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/Params/SUBnoteParameters.cpp | 64++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/Plugin/ZynAddSubFX/DistrhoPluginInfo.h | 16++++++++++++++++
Msrc/Plugin/ZynAddSubFX/ZynAddSubFX.cpp | 35++++++++++++++++++++++++++++++-----
Msrc/Synth/OscilGen.cpp | 58+++++++++++++++++++++++++++++++++++-----------------------
Msrc/Synth/Resonance.cpp | 17+++++++++++------
Msrc/Tests/CMakeLists.txt | 9++++++---
Msrc/Tests/MessageTest.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Tests/PluginTest.h | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Tests/SaveOSC.cpp | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Tests/guitar-adnote.xmz | 32++++++++++++++++----------------
Msrc/UI/MasterUI.fl | 2+-
Msrc/main.cpp | 3+--
42 files changed, 1103 insertions(+), 465 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -515,9 +515,11 @@ if (DssiEnable) Output/DSSIControlDescription.h) target_link_libraries(zynaddsubfx_dssi - zynaddsubfx_core + zynaddsubfx_core ${OS_LIBRARIES} - ${LIBLO_LIBRARIES} + ${LIBLO_LIBRARIES} + ${PLATFORM_LIBRARIES} + -Wl,--no-undefined ) install(TARGETS zynaddsubfx_dssi LIBRARY DESTINATION ${PluginLibDir}/dssi/) endif() diff --git a/src/Effects/Alienwah.cpp b/src/Effects/Alienwah.cpp @@ -36,17 +36,26 @@ rtosc::Ports Alienwah::ports = { else d.reply(d.loc, "i", o->Ppreset); rEnd}, - //Pvolume/Ppanning are common - rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), - rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), + rEffParVol(rDefault(127), rPresetsAt(3, 93)), + rEffParPan(), + rEffPar(Pfreq, 2, rShort("freq") rPresets(70, 73, 63, 25), + "Effect Frequency"), + rEffPar(Pfreqrnd, 3, rShort("rand"), rPreset(1, 106) rDefault(0), + "Frequency Randomness"), rEffPar(PLFOtype, 4, rShort("shape"), - rOptions(sine, triangle), "LFO Shape"), - rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"), - rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"), - rEffPar(Pfeedback, 7, rShort("fb"), "Feedback"), - rEffPar(Pdelay, 8, rLinear(1,100), rShort("delay"), "Delay"), - rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"), - rEffPar(Pphase, 10, rShort("phase"), "Phase"), + rOptions(sine, triangle), rPresets(sine, sine, triangle, triangle), + "LFO Shape"), + rEffPar(PStereo, 5, rShort("stereo"), rPresets(62, 101, 100, 66), + "Stereo Mode"), + rEffPar(Pdepth, 6, rShort("depth"), rPresets(60, 60, 112, 101), + "LFO Depth"), + rEffPar(Pfeedback, 7, rShort("fb"), rPreset(3, 11), rDefault(105), + "Feedback"), + rEffPar(Pdelay, 8, rLinear(1,100), rPresets(25, 17, 31, 47), + rShort("delay"), "Delay"), + rEffPar(Plrcross, 9, rShort("l/r"), rDefault(0), "Left/Right Crossover"), + rEffPar(Pphase, 10, rShort("phase"), rDefault(64), rPreset(2, 42), + rPreset(3, 86), "Phase"), }; #undef rBegin #undef rEnd diff --git a/src/Effects/Chorus.cpp b/src/Effects/Chorus.cpp @@ -49,7 +49,7 @@ rtosc::Ports Chorus::ports = { rDefault(0), "Frequency Randomness"), rEffPar(PLFOtype, 4, rShort("shape"), rOptions(sine, tri), - rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine), + rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine) "LFO Shape"), rEffPar(PStereo, 5, rShort("stereo"), rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62), "Stereo Mode"), diff --git a/src/Effects/Distorsion.cpp b/src/Effects/Distorsion.cpp @@ -37,21 +37,29 @@ rtosc::Ports Distorsion::ports = { else d.reply(d.loc, "i", o->Ppreset); rEnd}, - //Pvolume/Ppanning are common - rEffPar(Plrcross, 2, rShort("l/r"), "Left/Right Crossover"), - rEffPar(Pdrive, 3, rShort("drive"), "Input amplification"), - rEffPar(Plevel, 4, rShort("output"), "Output amplification"), + rEffParVol(rDefault(127), rPresetsAt(2, 64, 64)), + rEffParPan(), + rEffPar(Plrcross, 2, rShort("l/r"), rDefault(35), "Left/Right Crossover"), + rEffPar(Pdrive, 3, rShort("drive"), rPresets(56, 29, 75, 85, 63, 88), + "Input amplification"), + rEffPar(Plevel, 4, rShort("output"), rPresets(70, 75, 80, 62, 75, 75), + "Output amplification"), rEffPar(Ptype, 5, rShort("type"), rOptions(Arctangent, Asymmetric, Pow, Sine, Quantisize, - Zigzag, Limiter, Upper Limiter, Lower Limiter, - Inverse Limiter, Clip, Asym2, Pow2, sigmoid), + Zigzag, Limiter, Upper Limiter, Lower Limiter, + Inverse Limiter, Clip, Asym2, Pow2, sigmoid), + rPresets(Arctangent, Asymmetric, Zigzag, + Asymmetric, Pow, Quantisize), "Distortion Shape"), - rEffParTF(Pnegate, 6, rShort("neg"), "Negate Signal"), - rEffPar(Plpf, 7, rShort("lpf"), "Low Pass Cutoff"), - rEffPar(Phpf, 8, rShort("hpf"), "High Pass Cutoff"), - rEffParTF(Pstereo, 9, rShort("stereo"), "Stereo"), - rEffParTF(Pprefiltering, 10, rShort("p.filt"), - "Filtering before/after non-linearity"), + rEffParTF(Pnegate, 6, rShort("neg"), rDefault(false), "Negate Signal"), + rEffPar(Plpf, 7, rShort("lpf"), + rPreset(0, 96), rPreset(4, 55), rDefault(127), "Low Pass Cutoff"), + rEffPar(Phpf, 8, rShort("hpf"), + rPreset(2, 105), rPreset(3, 118), rDefault(0), "High Pass Cutoff"), + rEffParTF(Pstereo, 9, rShort("stereo"), + rPresets(false, false, true, true, false, true), "Stereo"), + rEffParTF(Pprefiltering, 10, rShort("p.filt"), rDefault(false), + "Filtering before/after non-linearity"), {"waveform:", 0, 0, [](const char *, rtosc::RtData &d) { Distorsion &dd = *(Distorsion*)d.obj; diff --git a/src/Effects/DynamicFilter.cpp b/src/Effects/DynamicFilter.cpp @@ -36,16 +36,24 @@ rtosc::Ports DynamicFilter::ports = { else d.reply(d.loc, "i", o->Ppreset); rEnd}, - //Pvolume/Ppanning are common - rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), - rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), - rEffPar(PLFOtype, 4, rShort("shape"), - rOptions(sin, tri), "LFO Shape"), - rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"), - rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"), - rEffPar(Pampsns, 7, rShort("sense"), "how the filter varies according to the input amplitude"), - rEffPar(Pampsnsinv, 8, rShort("sns.inv"), "Sense Inversion"), - rEffPar(Pampsmooth, 9, rShort("smooth"), "how smooth the input amplitude changes the filter"), + rEffParVol(rDefault(110), rPreset(2, 110), rPreset(4, 127)), + rEffParPan(), + rEffPar(Pfreq, 2, rShort("freq"), rPresets(80, 70, 30, 80, 50), + "Effect Frequency"), + rEffPar(Pfreqrnd, 3, rShort("rand"), rDefault(0), + "Frequency Randomness"), + rEffPar(PLFOtype, 4, rShort("shape"), rOptions(sin, tri), rDefault(sin), + "LFO Shape"), + rEffPar(PStereo, 5, rShort("stereo"), rPresets(64, 80, 50, 64, 96), + "Stereo Mode"), + rEffPar(Pdepth, 6, rShort("depth"), rPresets(0, 70, 80, 0, 64), + "LFO Depth"), + rEffPar(Pampsns, 7, rShort("sense"), + rPreset(0, 90) rPreset(3, 64) rDefault(0), + "how the filter varies according to the input amplitude"), + rEffPar(Pampsnsinv, 8, rShort("sns.inv"), rDefault(0), "Sense Inversion"), + rEffPar(Pampsmooth, 9, rShort("smooth"), rDefault(60), + "how smooth the input amplitude changes the filter"), }; #undef rBegin #undef rEnd diff --git a/src/Effects/Echo.cpp b/src/Effects/Echo.cpp @@ -39,12 +39,23 @@ rtosc::Ports Echo::ports = { else d.reply(d.loc, "i", o->Ppreset); rEnd}, - //Pvolume/Ppanning are common - rEffPar(Pdelay, 2, rShort("delay"), "Length of Echo"), - rEffPar(Plrdelay, 3, rShort("lr delay"), "Difference In Left/Right Delay"), - rEffPar(Plrcross, 4, rShort("cross"), "Left/Right Crossover"), - rEffPar(Pfb, 5, rShort("feedback"), "Echo Feedback"), - rEffPar(Phidamp, 6, rShort("damp"), "Dampen High Frequencies"), + rEffParVol(rDefault(67), rPresetsAt(6, 81, 81, 62)), + rEffParPan(rPresetsAt(2, 75, 60, 60, 64, 60, 60, 64)), + rEffPar(Pdelay, 2, rShort("delay"), + rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28), + "Length of Echo"), + rEffPar(Plrdelay, 3, rShort("lr delay"), + rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64), + "Difference In Left/Right Delay"), + rEffPar(Plrcross, 4, rShort("cross"), + rPresetsAt(5, 0, 100, 127, 100), rDefault(30), + "Left/Right Crossover"), + rEffPar(Pfb, 5, rShort("feedback"), + rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90), + "Echo Feedback"), + rEffPar(Phidamp, 6, rShort("damp"), + rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55), + "Dampen High Frequencies"), }; #undef rBegin #undef rEnd diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h @@ -19,11 +19,15 @@ #include "../Params/FilterParams.h" #include "../Misc/Stereo.h" +// bug: the effect parameters can currently be set, but such values +// will not be saved into XML files #ifndef rEffPar #define rEffPar(name, idx, ...) \ - {STRINGIFY(name) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParCb(idx)} + {STRINGIFY(name) "::i", rProp(parameter) rDefaultDepends(preset) \ + DOC(__VA_ARGS__), NULL, rEffParCb(idx)} #define rEffParTF(name, idx, ...) \ - {STRINGIFY(name) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)} + {STRINGIFY(name) "::T:F", rProp(parameter) rDefaultDepends(preset) \ + DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)} #define rEffParCb(idx) \ [](const char *msg, rtosc::RtData &d) {\ rObject &obj = *(rObject*)d.obj; \ @@ -40,6 +44,27 @@ d.reply(d.loc, obj.getpar(idx)?"T":"F");} #endif +#define rEffParCommon(pname, rshort, rdoc, idx, ...) \ +{STRINGIFY(pname) ":", rProp(parameter) rLinear(0,127) \ + rShort(rshort) rDoc(rdoc), \ + 0, \ + [](const char *msg, rtosc::RtData &d) \ + { \ + rObject& eff = *(rObject*)d.obj; \ + if(!rtosc_narguments(msg)) \ + d.reply(d.loc, "i", eff.getpar(idx)); \ + else { \ + eff.changepar(0, rtosc_argument(msg, 0).i); \ + d.broadcast(d.loc, "i", eff.getpar(idx)); \ + } \ + }} + +#define rEffParVol(...) rEffParCommon(Pvolume, "amt", "amount of effect", 0, \ + __VA_ARGS__) +#define rEffParPan(...) rEffParCommon(Ppanning, "pan", "panning", 1, \ + __VA_ARGS__) + + namespace zyn { class FilterParams; diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -38,15 +38,16 @@ namespace zyn { {STRINGIFY(name)"/", NULL, &name::ports,\ [](const char *msg, rtosc::RtData &data){\ rObject &o = *(rObject*)data.obj; \ - data.obj = o.efx; \ - if(!dynamic_cast<name*>(o.efx)) \ + data.obj = dynamic_cast<name*>(o.efx); \ + if(!data.obj) \ return; \ SNIP \ name::ports.dispatch(msg, data); \ }} static const rtosc::Ports local_ports = { - rSelf(EffectMgr), + rSelf(EffectMgr, rEnabledByCondition(self-enabled)), rPaste, + rEnabledCondition(self-enabled, obj->geteffect()), rRecurp(filterpars, "Filter Parameter for Dynamic Filter"), {"Pvolume::i", rProp(parameter) rLinear(0,127) rShort("amt") rDoc("amount of effect"), 0, @@ -93,7 +94,8 @@ static const rtosc::Ports local_ports = { d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm))); } }}, - {"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector"), NULL, + {"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector") + rDefault(0), NULL, [](const char *msg, rtosc::RtData &d) { char loc[1024]; @@ -129,18 +131,10 @@ static const rtosc::Ports local_ports = { eq->getFilter(a,b); d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b); }}, - {"efftype::i", rOptions(Disabled, Reverb, Echo, Chorus, - Phaser, Alienwah, Distortion, EQ, DynFilter) - rProp(parameter) rDoc("Get Effect Type"), NULL, - [](const char *m, rtosc::RtData &d) - { - EffectMgr *eff = (EffectMgr*)d.obj; - if(rtosc_narguments(m)) { - eff->changeeffectrt(rtosc_argument(m,0).i); - d.broadcast(d.loc, "i", eff->nefx); - } else - d.reply(d.loc, "i", eff->nefx); - }}, + {"efftype::i:c:S", rOptions(Disabled, Reverb, Echo, Chorus, + Phaser, Alienwah, Distortion, EQ, DynFilter) rDefault(Disabled) + rProp(parameter) rDoc("Get Effect Type"), NULL, + rCOptionCb(obj->nefx, obj->changeeffectrt(var))}, {"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL, [](const char *msg, rtosc::RtData &d) { diff --git a/src/Effects/Phaser.cpp b/src/Effects/Phaser.cpp @@ -37,7 +37,8 @@ namespace zyn { d.reply(d.loc, "i", p.P##pname); \ rEnd #define rParamPhaser(name, ...) \ - {STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, ucharParamCb(name)} + {STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) \ + rDefaultDepends(preset) DOC(__VA_ARGS__), NULL, ucharParamCb(name)} rtosc::Ports Phaser::ports = { {"preset::i", rProp(parameter) @@ -53,23 +54,52 @@ rtosc::Ports Phaser::ports = { else d.reply(d.loc, "i", o->Ppreset); rEnd}, - //Pvolume/Ppanning are common - rEffPar(lfo.Pfreq, 2, rShort("freq"), "LFO frequency"), - rEffPar(lfo.Prandomness, 3, rShort("rnd."), "LFO randomness"), + rEffParVol(rDefault(64), rPreset(3, 39), rPreset(10, 25)), + rEffParPan(), + rEffPar(lfo.Pfreq, 2, rShort("freq"), + rPresets(36, 35, 31, 22, 20, 53, 14, 14, 9, 14, 127, 1), + "LFO frequency"), + rEffPar(lfo.Prandomness, 3, rShort("rnd."), + rPreset(5, 100), rPreset(7, 5), rPresetsAt(9, 10, 10, 10), + rDefault(0), "LFO randomness"), rEffPar(lfo.PLFOtype, 4, rShort("type"), - rOptions(sine, tri), "lfo shape"), - rEffPar(lfo.Pstereo, 5, rShort("stereo"), "Left/right channel phase shift"), - rEffPar(Pdepth, 6, rShort("depth"), "LFP depth"), - rEffPar(Pfb, 7, rShort("fb"), "Feedback"), - rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), ""), - rParamPhaser(lrcross, rShort("cross"), "Channel routing"), - rParamPhaser(offset, rShort("off"), "Offset"), - rEffParTF(Poutsub, 10, rShort("sub"), "Invert output"), - rParamPhaser(phase, rShort("phase"), ""), - rParamPhaser(width, rShort("width"), ""), - rEffParTF(Phyper, 12, rShort("hyp."), "Square the LFO"), - rEffPar(Pdistortion, 13, rShort("distort"), "Distortion"), - rEffParTF(Panalog, 14, rShort("analog"), "Use analog phaser"), + rPreset(4, tri), rPresetsAt(6, tri, tri), rPreset(11, tri), + rDefault(sine), + rOptions(sine, tri), "lfo shape"), + rEffPar(lfo.Pstereo, 5, rShort("stereo"), + rPresetsAt(1, 88, 66, 66, 110, 58), rDefault(64), + "Left/right channel phase shift"), + rEffPar(Pdepth, 6, rShort("depth"), + rPresets(110, 40, 68, 67, 67, 37, 64, 70, 60, 45, 25, 70), + "LFP depth"), + rEffPar(Pfb, 7, rShort("fb"), + rPresets(64, 64, 107, 10, 78, 78, 40, 40, 40, 80, 16, 40), + "Feedback"), + rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), + rPresets(1, 3, 2, 5, 10, 3, 4, 6, 8, 7, 8, 12), + ""), + rParamPhaser(lrcross, rShort("cross"), + rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), + "Channel routing"), + rParamPhaser(offset, rShort("off"), + rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), + "Offset"), + rEffParTF(Poutsub, 10, rShort("sub"), + rPreset(3, true), rPreset(9, true), rDefault(false), + "Invert output"), + rParamPhaser(phase, rShort("phase"), + rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), + rParamPhaser(width, rShort("width"), + rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), + rEffParTF(Phyper, 12, rShort("hyp."), + rPresetsAt(6, true, true, false, true, false, true), + rDefault(false), "Square the LFO"), + rEffPar(Pdistortion, 13, rShort("distort"), + rPresetsAt(6, 20, 20, 20, 20, 20, 20), rDefault(0), + "Distortion"), + rEffParTF(Panalog, 14, rShort("analog"), + rPresetsAt(6, true, true, true, true, true, true), rDefault(false), + "Use analog phaser"), }; #undef rBegin #undef rEnd diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp @@ -39,18 +39,38 @@ rtosc::Ports Reverb::ports = { else d.reply(d.loc, "i", o->Ppreset); 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("hpf"), "High pass filter"), - rEffPar(Plohidamp,9, rShort("damp"), "Dampening"), + rEffParVol(rDefault(90), rPresets(80, 80, 80), + rPresetsAt(5, 100, 100, 110, 85, 95)), + rEffParPan(rPreset(8, 80)), + rEffPar(Ptime, 2, rShort("time"), + rPresets(63, 69, 69, 51, 53, 33, 21, 14, 84, 26, 40, 93, 111), + "Length of Reverb"), + rEffPar(Pidelay, 3, rShort("i.time"), + rPresets(24, 35, 24, 10, 20, 0, 26, 0, 20, 60, 88, 15, 30), + "Delay for first impulse"), + rEffPar(Pidelayfb,4, rShort("i.fb"), rPresetsAt(8, 42, 71, 71), rDefault(0), + "Feedback for first impulse"), + rEffPar(Plpf, 7, rShort("lpf"), + rPreset(1, 85), rPresetsAt(62, 127, 51, 114, 114, 114), + rDefault(127), "Low pass filter"), + rEffPar(Phpf, 8, rShort("hpf"), + rPresets(5), rPresetsAt(2, 75, 21, 75), rPreset(7, 50), + rPreset(12, 90), rDefault(0), "High pass filter"), + rEffPar(Plohidamp,9, rShort("damp"), rDefault(0), + rPresets(83, 71, 78, 78, 71, 106, 77, 71, 78, 64, 88, 77, 74) + "Dampening"), //Todo make this a selector - rEffPar(Ptype, 10,rShort("type"), - rOptions(Random, Freeverb, Bandwidth), "Type"), - rEffPar(Proomsize,11,rShort("size"), "Room Size"), - rEffPar(Pbandwidth,12,rShort("bw"), "Bandwidth"), + rEffPar(Ptype, 10, rShort("type"), + rOptions(Random, Freeverb, Bandwidth), + rPresets(Freeverb, Random, Freeverb, Freeverb, Freeverb, Random, + Freeverb, Random, Freeverb, Freeverb, Freeverb, Random, + Freeverb) + rDefault(Random), "Type"), + rEffPar(Proomsize,11,rShort("size"), + rPreset(2, 85), rPresetsAt(5, 30, 45, 25, 105), + rPresetsAt(11, 95, 80), rDefault(64), + "Room Size"), + rEffPar(Pbandwidth,12,rShort("bw"), rDefault(20), "Bandwidth"), }; #undef rBegin #undef rEnd diff --git a/src/Misc/Config.cpp b/src/Misc/Config.cpp @@ -43,13 +43,13 @@ namespace zyn { static const rtosc::Ports ports = { //rString(cfg.LinuxOSSWaveOutDev), //rString(cfg.LinuxOSSSeqInDev), - rParamI(cfg.SampleRate, rDefault(44100), "samples of audio per second"), - rParamI(cfg.SoundBufferSize, rDefault(256), "Size of processed audio buffer"), - rParamI(cfg.OscilSize, rDefault(1024), "Size Of Oscillator Wavetable"), - rToggle(cfg.SwapStereo, rDefault(false), "Swap Left And Right Channels"), - rToggle(cfg.BankUIAutoClose, rDefault(false), "Automatic Closing of BackUI After Patch Selection"), - rParamI(cfg.GzipCompression, rDefault(3), "Level of Gzip Compression For Save Files"), - rParamI(cfg.Interpolation, rDefault(0), "Level of Interpolation, Linear/Cubic"), + rParamI(cfg.SampleRate, "samples of audio per second"), + rParamI(cfg.SoundBufferSize, "Size of processed audio buffer"), + rParamI(cfg.OscilSize, "Size Of Oscillator Wavetable"), + rToggle(cfg.SwapStereo, "Swap Left And Right Channels"), + rToggle(cfg.BankUIAutoClose, "Automatic Closing of BackUI After Patch Selection"), + rParamI(cfg.GzipCompression, "Level of Gzip Compression For Save Files"), + rParamI(cfg.Interpolation, "Level of Interpolation, Linear/Cubic"), {"cfg.presetsDirList", rDoc("list of preset search directories"), 0, [](const char *msg, rtosc::RtData &d) { @@ -120,10 +120,10 @@ static const rtosc::Ports ports = { //rArrayS(cfg.bankRootDirList,MAX_BANK_ROOT_DIRS), //rString(cfg.currentBankDir), //rArrayS(cfg.presetsDirList,MAX_BANK_ROOT_DIRS), - rToggle(cfg.CheckPADsynth, rDefault(true), "Old Check For PADsynth functionality within a patch"), - rToggle(cfg.IgnoreProgramChange, rDefault(false), "Ignore MIDI Program Change Events"), - rParamI(cfg.UserInterfaceMode, rDefault(0), "Beginner/Advanced Mode Select"), - rParamI(cfg.VirKeybLayout, rDefault(1), "Keyboard Layout For Virtual Piano Keyboard"), + rToggle(cfg.CheckPADsynth, "Old Check For PADsynth functionality within a patch"), + rToggle(cfg.IgnoreProgramChange, "Ignore MIDI Program Change Events"), + rParamI(cfg.UserInterfaceMode, "Beginner/Advanced Mode Select"), + rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"), //rParamS(cfg.LinuxALSAaudioDev), //rParamS(cfg.nameTag) {"cfg.OscilPower::i", rProp(parameter) rDoc("Size Of Oscillator Wavetable"), 0, @@ -174,7 +174,9 @@ const rtosc::Ports &Config::ports = zyn::ports; #endif Config::Config() -{} +{ + init(); +} void Config::init() { diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -332,7 +332,7 @@ static const Ports master_ports = { rArrayOption(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off), rOptions(Part1, Part2, Part3, Part4, Part5, Part6, Part7, Part8, Part9, Part10, Part11, Part12, - Part13, Part14, Part15, Part16) rDefault([Off...]), + Part13, Part14, Part15, Part16) rDefault(Off), "Part to insert part onto"), {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDefault(64) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -16,7 +16,7 @@ #define MASTER_H #include "../globals.h" #include "Microtonal.h" -#include <rtosc/miditable.h> +#include <rtosc/automations.h> #include <rtosc/ports.h> #include "Time.h" @@ -65,6 +65,14 @@ class Master * @return 0 for ok or -1 if there is an error*/ int loadXML(const char *filename); + /**Save all settings to an OSC file (as specified by RT OSC) + * @param filename File to save to or NULL (useful for testing) + * @return 0 for ok or <0 if there is an error*/ + int saveOSC(const char *filename); + /**loads all settings from an OSC file (as specified by RT OSC) + * @return 0 for ok or <0 if there is an error*/ + int loadOSC(const char *filename); + /**Regenerate PADsynth and other non-RT parameters * It is NOT SAFE to call this from a RT context*/ void applyparameters(void) NONREALTIME; @@ -171,7 +179,7 @@ class Master WatchManager watcher; //Midi Learn - rtosc::MidiMapperRT midi; + rtosc::AutomationMgr automate; bool frozenState;//read-only parameters for threadsafe actions Allocator *memory; @@ -199,6 +207,11 @@ class Master //Callback When Master changes void(*mastercb)(void*,Master*); void* mastercb_ptr; + + //Return XML data as string. Must be freed. + char* getXMLData(); + //Used by loadOSC and saveOSC + int loadOSCFromStr(const char *filename); }; } diff --git a/src/Misc/Microtonal.cpp b/src/Misc/Microtonal.cpp @@ -65,7 +65,7 @@ const rtosc::Ports Microtonal::ports = { rParamZyn(Pmapsize, rDefault(12), "Size of key map"), rToggle(Pmappingenabled, rDefault(false), "Mapping Enable"), - rParams(Pmapping, 128, /*rDefault([1 1 2 ...]),*/ "Mapping of keys"), + rParams(Pmapping, 128, rDefaultMissing, "Mapping of keys"), rParamZyn(Pglobalfinedetune, rShort("fine"), rDefault(64), "Fine detune for all notes"), diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -227,50 +227,50 @@ void preparePadSynth(string path, PADnoteParameters *p, rtosc::RtData &d) * MIDI Serialization * * * ******************************************************************************/ -void saveMidiLearn(XMLwrapper &xml, const rtosc::MidiMappernRT &midi) -{ - xml.beginbranch("midi-learn"); - for(auto value:midi.inv_map) { - XmlNode binding("midi-binding"); - auto biject = std::get<3>(value.second); - binding["osc-path"] = value.first; - binding["coarse-CC"] = to_s(std::get<1>(value.second)); - binding["fine-CC"] = to_s(std::get<2>(value.second)); - binding["type"] = "i"; - binding["minimum"] = to_s(biject.min); - binding["maximum"] = to_s(biject.max); - xml.add(binding); - } - xml.endbranch(); -} - -void loadMidiLearn(XMLwrapper &xml, rtosc::MidiMappernRT &midi) -{ - using rtosc::Port; - if(xml.enterbranch("midi-learn")) { - auto nodes = xml.getBranch(); - - //TODO clear mapper - - for(auto node:nodes) { - if(node.name != "midi-binding" || - !node.has("osc-path") || - !node.has("coarse-CC")) - continue; - const string path = node["osc-path"]; - const int CC = atoi(node["coarse-CC"].c_str()); - const Port *p = Master::ports.apropos(path.c_str()); - if(p) { - printf("loading midi port...\n"); - midi.addNewMapper(CC, *p, path); - } else { - printf("unknown midi bindable <%s>\n", path.c_str()); - } - } - xml.exitbranch(); - } else - printf("cannot find 'midi-learn' branch...\n"); -} +//void saveMidiLearn(XMLwrapper &xml, const rtosc::MidiMappernRT &midi) +//{ +// xml.beginbranch("midi-learn"); +// for(auto value:midi.inv_map) { +// XmlNode binding("midi-binding"); +// auto biject = std::get<3>(value.second); +// binding["osc-path"] = value.first; +// binding["coarse-CC"] = to_s(std::get<1>(value.second)); +// binding["fine-CC"] = to_s(std::get<2>(value.second)); +// binding["type"] = "i"; +// binding["minimum"] = to_s(biject.min); +// binding["maximum"] = to_s(biject.max); +// xml.add(binding); +// } +// xml.endbranch(); +//} +// +//void loadMidiLearn(XMLwrapper &xml, rtosc::MidiMappernRT &midi) +//{ +// using rtosc::Port; +// if(xml.enterbranch("midi-learn")) { +// auto nodes = xml.getBranch(); +// +// //TODO clear mapper +// +// for(auto node:nodes) { +// if(node.name != "midi-binding" || +// !node.has("osc-path") || +// !node.has("coarse-CC")) +// continue; +// const string path = node["osc-path"]; +// const int CC = atoi(node["coarse-CC"].c_str()); +// const Port *p = Master::ports.apropos(path.c_str()); +// if(p) { +// printf("loading midi port...\n"); +// midi.addNewMapper(CC, *p, path); +// } else { +// printf("unknown midi bindable <%s>\n", path.c_str()); +// } +// } +// xml.exitbranch(); +// } else +// printf("cannot find 'midi-learn' branch...\n"); +//} /****************************************************************************** * Non-RealTime Object Store * @@ -747,7 +747,7 @@ public: rtosc::UndoHistory undo; //MIDI Learn - rtosc::MidiMappernRT midi_mapper; + //rtosc::MidiMappernRT midi_mapper; //Link To the Realtime rtosc::ThreadLink *bToU; @@ -1202,24 +1202,24 @@ static rtosc::Ports middwareSnoopPorts = { impl.kitEnable(msg); d.forward(); rEnd}, - {"save_xlz:s", 0, 0, - rBegin; - const char *file = rtosc_argument(msg, 0).s; - XMLwrapper xml; - saveMidiLearn(xml, impl.midi_mapper); - xml.saveXMLfile(file, impl.master->gzip_compression); - rEnd}, - {"load_xlz:s", 0, 0, - rBegin; - const char *file = rtosc_argument(msg, 0).s; - XMLwrapper xml; - xml.loadXMLfile(file); - loadMidiLearn(xml, impl.midi_mapper); - rEnd}, - {"clear_xlz:", 0, 0, - rBegin; - impl.midi_mapper.clear(); - rEnd}, + //{"save_xlz:s", 0, 0, + // rBegin; + // const char *file = rtosc_argument(msg, 0).s; + // XMLwrapper xml; + // saveMidiLearn(xml, impl.midi_mapper); + // xml.saveXMLfile(file, impl.master->gzip_compression); + // rEnd}, + //{"load_xlz:s", 0, 0, + // rBegin; + // const char *file = rtosc_argument(msg, 0).s; + // XMLwrapper xml; + // xml.loadXMLfile(file); + // loadMidiLearn(xml, impl.midi_mapper); + // rEnd}, + //{"clear_xlz:", 0, 0, + // rBegin; + // impl.midi_mapper.clear(); + // rEnd}, //scale file stuff {"load_xsz:s", 0, 0, rBegin; @@ -1391,51 +1391,51 @@ static rtosc::Ports middwareSnoopPorts = { impl.undo.seekHistory(+1); rEnd}, //port to observe the midi mappings - {"midi-learn-values:", 0, 0, - rBegin; - auto &midi = impl.midi_mapper; - auto key = keys(midi.inv_map); - //cc-id, path, min, max -#define MAX_MIDI 32 - rtosc_arg_t args[MAX_MIDI*4]; - char argt[MAX_MIDI*4+1] = {0}; - int j=0; - for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) { - auto val = midi.inv_map[key[i]]; - if(std::get<1>(val) == -1) - continue; - argt[4*j+0] = 'i'; - args[4*j+0].i = std::get<1>(val); - argt[4*j+1] = 's'; - args[4*j+1].s = key[i].c_str(); - argt[4*j+2] = 'i'; - args[4*j+2].i = 0; - argt[4*j+3] = 'i'; - args[4*j+3].i = 127; - j++; - - } - d.replyArray(d.loc, argt, args); -#undef MAX_MIDI - rEnd}, - {"learn:s", 0, 0, - rBegin; - string addr = rtosc_argument(msg, 0).s; - auto &midi = impl.midi_mapper; - auto map = midi.getMidiMappingStrings(); - if(map.find(addr) != map.end()) - midi.map(addr.c_str(), false); - else - midi.map(addr.c_str(), true); - rEnd}, - {"unlearn:s", 0, 0, - rBegin; - string addr = rtosc_argument(msg, 0).s; - auto &midi = impl.midi_mapper; - auto map = midi.getMidiMappingStrings(); - midi.unMap(addr.c_str(), false); - midi.unMap(addr.c_str(), true); - rEnd}, + //{"midi-learn-values:", 0, 0, + // rBegin; + // auto &midi = impl.midi_mapper; + // auto key = keys(midi.inv_map); + // //cc-id, path, min, max +//#define MAX_MIDI 32 + // rtosc_arg_t args[MAX_MIDI*4]; + // char argt[MAX_MIDI*4+1] = {0}; + // int j=0; + // for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) { + // auto val = midi.inv_map[key[i]]; + // if(std::get<1>(val) == -1) + // continue; + // argt[4*j+0] = 'i'; + // args[4*j+0].i = std::get<1>(val); + // argt[4*j+1] = 's'; + // args[4*j+1].s = key[i].c_str(); + // argt[4*j+2] = 'i'; + // args[4*j+2].i = 0; + // argt[4*j+3] = 'i'; + // args[4*j+3].i = 127; + // j++; + + // } + // d.replyArray(d.loc, argt, args); +//#undef MAX_MIDI + // rEnd}, + //{"learn:s", 0, 0, + // rBegin; + // string addr = rtosc_argument(msg, 0).s; + // auto &midi = impl.midi_mapper; + // auto map = midi.getMidiMappingStrings(); + // if(map.find(addr) != map.end()) + // midi.map(addr.c_str(), false); + // else + // midi.map(addr.c_str(), true); + // rEnd}, + //{"unlearn:s", 0, 0, + // rBegin; + // string addr = rtosc_argument(msg, 0).s; + // auto &midi = impl.midi_mapper; + // auto map = midi.getMidiMappingStrings(); + // midi.unMap(addr.c_str(), false); + // midi.unMap(addr.c_str(), true); + // rEnd}, //drop this message into the abyss {"ui/title:", 0, 0, [](const char *msg, RtData &d) {}}, {"quit:", 0, 0, [](const char *, RtData&) {Pexitprogram = 1;}}, @@ -1482,10 +1482,10 @@ static rtosc::Ports middlewareReplyPorts = { if(impl.recording_undo) impl.undo.recordEvent(msg); rEnd}, - {"midi-use-CC:i", 0, 0, - rBegin; - impl.midi_mapper.useFreeID(rtosc_argument(msg, 0).i); - rEnd}, + //{"midi-use-CC:i", 0, 0, + // rBegin; + // impl.midi_mapper.useFreeID(rtosc_argument(msg, 0).i); + // rEnd}, {"broadcast:", 0, 0, rBegin; impl.broadcast = true; rEnd}, {"forward:", 0, 0, rBegin; impl.forward = true; rEnd}, }; @@ -1510,8 +1510,8 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, { bToU = new rtosc::ThreadLink(4096*2*16,1024/16); uToB = new rtosc::ThreadLink(4096*2*16,1024/16); - midi_mapper.base_ports = &Master::ports; - midi_mapper.rt_cb = [this](const char *msg){handleMsg(msg);}; + //midi_mapper.base_ports = &Master::ports; + //midi_mapper.rt_cb = [this](const char *msg){handleMsg(msg);}; if(preferrred_port != -1) server = lo_server_new_with_proto(to_s(preferrred_port).c_str(), LO_UDP, liblo_error_cb); diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -88,10 +88,9 @@ static const Ports partPorts = { "Instrument comments"), rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "User specified label"), rArrayI(Pefxroute, NUM_PART_EFX, - rOptions(Next Effect,Part Out,Dry Out), - ":default\0=[\"Next Effect\"S ...]\0", + rOptions(Next Effect,Part Out,Dry Out), rDefaultId(Next Effect), "Effect Routing"), - rArrayT(Pefxbypass, NUM_PART_EFX, rDefault([false...]), + rArrayT(Pefxbypass, NUM_PART_EFX, rDefault(false), "If an effect is bypassed"), {"captureMin:", rDoc("Capture minimum valid note"), NULL, [](const char *, RtData &r) diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -85,6 +85,7 @@ class Part struct Kit { Kit(void); Part *parent; + bool firstkit; bool Penabled, Pmuted; unsigned char Pminkey, Pmaxkey; char *Pname; @@ -106,13 +107,14 @@ class Part void setkeylimit(unsigned char Pkeylimit); void setkititemstatus(unsigned kititem, bool Penabled_); + unsigned char partno; /**<if it's the Master's first part*/ bool Penabled; /**<if the part is enabled*/ unsigned char Pvolume; /**<part volume*/ unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/ unsigned char Pmaxkey; //the maximum key that the part receives noteon messages void setPvolume(char Pvolume); unsigned char Pkeyshift; //Part keyshift - unsigned char Prcvchn; //from what midi channel it receive commnads + unsigned char Prcvchn; //from what midi channel it receives commands unsigned char Ppanning; //part panning void setPpanning(char Ppanning); unsigned char Pvelsns; //velocity sensing (amplitude velocity scale) diff --git a/src/Misc/Schema.cpp b/src/Misc/Schema.cpp @@ -21,6 +21,8 @@ namespace zyn { * - 'shortname' : string [OPTIONAL] * - 'tooltip' : string [OPTIONAL] * - 'type' : type + * - 'units' : unit-type + * - 'scale' : scale-type * - 'domain' : range [OPTIONAL] * - 'options' : [option...] [OPTIONAL] * type : {'int', 'float', 'boolean'} @@ -105,7 +107,8 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta) * - 'domain' : range [OPTIONAL] */ static bool first = true; -void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) +void dump_param_cb(const rtosc::Port *p, const char *full_name, const char*, + const Ports&,void *v, void*) { typedef std::vector<std::pair<int,string>> opts; std::ostream &o = *(std::ostream*)v; @@ -114,6 +117,9 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) auto mparameter = meta.find("parameter"); auto mdoc = meta.find("documentation"); auto msname = meta.find("shortname"); + auto units = meta.find("unit"); + auto scale = meta.find("scale"); + opts options; string doc; string name = p->name;; @@ -189,6 +195,10 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) o << " \"shortname\": \"" << msname.value << "\",\n"; o << " \"name\" : \"" << name << "\",\n"; o << " \"tooltip\" : \"" << doc << "\",\n"; + if(units != meta.end()) + o << " \"units\" : \"" << units.value << "\",\n"; + if(scale != meta.end()) + o << " \"scale\" : \"" << scale.value << "\",\n"; o << " \"type\" : \"" << type << "\""; if(min && max) o << ",\n \"range\" : [" << min << "," << max << "]"; diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -153,11 +153,6 @@ char *rtosc_splat(const char *path, std::set<std::string>); #define rParamZyn(name, ...) \ {STRINGIFY(name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, rParamICb(name)} -#define rSelf(type) \ -{"self:", rProp(internal) rMap(class, type) rDoc("port metadata"), 0, \ - [](const char *, rtosc::RtData &d){ \ - d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\ - #define rPresetType \ {"preset-type:", rProp(internal) rDoc("clipboard type of object"), 0, \ [](const char *, rtosc::RtData &d){ \ @@ -184,4 +179,6 @@ rPresetType, \ } +#define rUnit(x) rMap(unit, x) + #endif diff --git a/src/Misc/XMLwrapper.cpp b/src/Misc/XMLwrapper.cpp @@ -253,7 +253,7 @@ void XMLwrapper::addparreal(const string &name, float val) union { float in; uint32_t out; } convert; char buf[11]; convert.in = val; - sprintf(buf, "0x%8X", convert.out); + sprintf(buf, "0x%0.8X", convert.out); addparams("par_real", 3, "name", name.c_str(), "value", stringFrom<float>(val).c_str(), "exact_value", buf); } diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -30,6 +30,8 @@ using std::vector; //Dummy variables and functions for linking purposes const char *instance_name = 0; + +namespace zyn { class WavFile; namespace Nio { bool start(void){return 1;}; @@ -46,6 +48,7 @@ namespace Nio { string getSource(void){return "";} string getSink(void){return "";} } +} // namespace zyn // // Static stubs for LADSPA member functions @@ -622,8 +625,6 @@ DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) : dssi_control{dssi_c this->sampleRate = sampleRate; this->banksInited = false; - config.init(); - zyn::sprng(time(NULL)); synth.alias(); diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -370,8 +370,7 @@ static const Ports adPorts = {//XXX 16 should not be hard coded rArrayPaste, rRecurs(VoicePar, NUM_VOICES), {"VoicePar#" STRINGIFY(NUM_VOICES) "/Enabled::T:F", - rProp(parameter) rShort("enable") rDoc("Voice Enable") - rDefault([true false false ...]), + rProp(parameter) rShort("enable") rDoc("Voice Enable"), NULL, rArrayTCbMember(VoicePar, Enabled)}, rRecur(GlobalPar, "Adnote Parameters"), }; diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -330,14 +330,14 @@ class ADnoteParameters:public PresetsArray void defaults(int n); //n is the nvoice void add2XMLsection(XMLwrapper& xml, int n); void getfromXMLsection(XMLwrapper& xml, int n); - private: + const AbsTime *time; + int64_t last_update_timestamp; + + private: void EnableVoice(const SYNTH_T &synth, int nvoice, const AbsTime* time); void KillVoice(int nvoice); FFTwrapper *fft; - - const AbsTime *time; - int64_t last_update_timestamp; }; } diff --git a/src/Params/Controller.cpp b/src/Params/Controller.cpp @@ -29,32 +29,57 @@ namespace zyn { #undef rChangeCb #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } const rtosc::Ports Controller::ports = { - rParamZyn(panning.depth, rShort("pan.d"), rDefault(64), "Depth of Panning MIDI Control"), - rParamZyn(filtercutoff.depth, rShort("fc.d"), rDefault(64), "Depth of Filter Cutoff MIDI Control"), - rParamZyn(filterq.depth, rShort("fq.d"), rDefault(64), "Depth of Filter Q MIDI Control"), - rParamZyn(bandwidth.depth, rShort("bw.d"), rDefault(64), "Depth of Bandwidth MIDI Control"), - rToggle(bandwidth.exponential, rShort("bw.exp"), rDefault(false), "Bandwidth Exponential Mode"), - rParamZyn(modwheel.depth, rShort("mdw.d"), rDefault(80), "Depth of Modwheel MIDI Control"), - rToggle(modwheel.exponential, rShort("mdw.exp"), rDefault(false), "Modwheel Exponential Mode"), - rToggle(pitchwheel.is_split, rDefault(false), rDefault(false), "If PitchWheel Has unified bendrange or not"), - rParamI(pitchwheel.bendrange, rShort("pch.d"), rDefault(200), "Range of MIDI Pitch Wheel"), - rParamI(pitchwheel.bendrange_down, rDefault(0), "Lower Range of MIDI Pitch Wheel"), - rToggle(expression.receive, rShort("exp.rcv"), rDefault(true), "Expression MIDI Receive"), - rToggle(fmamp.receive, rShort("fma.rcv"), rDefault(true), "FM amplitude MIDI Receive"), - rToggle(volume.receive, rShort("vol.rcv"), rDefault(true), "Volume MIDI Receive"), - rToggle(sustain.receive, rShort("sus.rcv"), rDefault(true), "Sustain MIDI Receive"), - rToggle(portamento.receive, rShort("prt.rcv"), rDefault(true), "Portamento MIDI Receive"), - rToggle(portamento.portamento, rDefault(false), "Portamento Enable"), - rParamZyn(portamento.time, rShort("time"), rDefault(64), "Portamento Length"), - rToggle(portamento.proportional, rShort("propt."), rDefault(false), "Whether the portamento time is proportional" + rParamZyn(panning.depth, rShort("pan.d"), rDefault(64), + "Depth of Panning MIDI Control"), + rParamZyn(filtercutoff.depth, rShort("fc.d"), rDefault(64), + "Depth of Filter Cutoff MIDI Control"), + rParamZyn(filterq.depth, rShort("fq.d"), rDefault(64), + "Depth of Filter Q MIDI Control"), + rParamZyn(bandwidth.depth, rShort("bw.d"), rDefault(64), + "Depth of Bandwidth MIDI Control"), + rToggle(bandwidth.exponential, rShort("bw.exp"), rDefault(false), + "Bandwidth Exponential Mode"), + rParamZyn(modwheel.depth, rShort("mdw.d"), rDefault(80), + "Depth of Modwheel MIDI Control"), + rToggle(modwheel.exponential, rShort("mdw.exp"), rDefault(false), + "Modwheel Exponential Mode"), + rToggle(pitchwheel.is_split, rDefault(false), + "If PitchWheel Has unified bendrange or not"), + rParamI(pitchwheel.bendrange, rShort("pch.d"), rDefault(200), + "Range of MIDI Pitch Wheel"), + rParamI(pitchwheel.bendrange_down, rDefault(0), + "Lower Range of MIDI Pitch Wheel"), + rToggle(expression.receive, rShort("exp.rcv"), rDefault(true), + "Expression MIDI Receive"), + rToggle(fmamp.receive, rShort("fma.rcv"), rDefault(true), + "FM amplitude MIDI Receive"), + rToggle(volume.receive, rShort("vol.rcv"), rDefault(true), + "Volume MIDI Receive"), + rToggle(sustain.receive, rShort("sus.rcv"), rDefault(true), + "Sustain MIDI Receive"), + rToggle(portamento.receive, rShort("prt.rcv"), rDefault(true), + "Portamento MIDI Receive"), + rToggle(portamento.portamento, rDefault(false), + "Portamento Enable"), + rParamZyn(portamento.time, rShort("time"), rDefault(64), + "Portamento Length"), + rToggle(portamento.proportional, rShort("propt."), rDefault(false), + "Whether the portamento time is proportional" "to the size of the interval between two notes."), - rParamZyn(portamento.propRate, rShort("scale"), rDefault(80), "Portamento proportional scale"), - rParamZyn(portamento.propDepth, rShort("depth"), rDefault(90), "Portamento proportional depth"), - rParamZyn(portamento.pitchthresh, rShort("thresh"), rDefault(3), "Threshold for portamento"), - rToggle(portamento.pitchthreshtype, rShort("tr.type"), rDefault(1), "Type of threshold"), - rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), rDefault(64), "Relative length of glide up vs glide down"), - rParamZyn(resonancecenter.depth, rShort("rfc.d"), rDefault(64), "Resonance Center MIDI Depth"), - rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), rDefault(64), "Resonance Bandwidth MIDI Depth"), + rParamZyn(portamento.propRate, rShort("scale"), rDefault(80), + "Portamento proportional scale"), + rParamZyn(portamento.propDepth, rShort("depth"), rDefault(90), + "Portamento proportional depth"), + rParamZyn(portamento.pitchthresh, rShort("thresh"), rDefault(3), + "Threshold for portamento"), + rToggle(portamento.pitchthreshtype, rShort("tr.type"), rDefault(true), + "Type of threshold"), + rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), rDefault(64), + "Relative length of glide up vs glide down"), + rParamZyn(resonancecenter.depth, rShort("rfc.d"), rDefault(64), + "Resonance Center MIDI Depth"), + rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), rDefault(64), + "Resonance Bandwidth MIDI Depth"), rToggle(NRPN.receive, rDefault(true), "NRPN MIDI Enable"), rAction(defaults), }; diff --git a/src/Params/EnvelopeParams.cpp b/src/Params/EnvelopeParams.cpp @@ -41,24 +41,50 @@ static const rtosc::Ports localPorts = { #undef rChangeCb #define rChangeCb if(!obj->Pfreemode) obj->converttofree(); \ if(obj->time) { obj->last_update_timestamp = obj->time->time(); } - rParamZyn(Penvpoints, rProp(internal), "Number of points in complex definition"), - rParamZyn(Penvsustain, "Location of the sustain point"), + rOption(envelope_type, rProp(internal), + rOptions(ad_global_amp, ad_global_freq, ad_global_filter, + ad_voice_amp, ad_voice_freq, ad_voice_filter, + ad_voice_fm_freq, ad_voice_fm_amp, + sub_freq_env, sub_bandwidth_env), "function of the envelope"), + rParamZyn(Penvpoints, rProp(internal), rDefaultDepends(envelope_type), + rPresets(4, 3, 4, 4, 3, 4, 3, 4, 3, 3), + "Number of points in complex definition"), + rParamZyn(Penvsustain, rDefaultDepends(envelope_type), + rPresets(2, 1, 2, 2, 1, 2, 1, 2, 1, 1), + "Location of the sustain point"), rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"), rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"), - rParamZyn(Penvstretch, rShort("stretch"), + rParamZyn(Penvstretch, rShort("stretch"), rDefaultDepends(envelope_type), + rPresets(64, 0, 0, 64, 0, 0, 0, 64, 64, 64), "Stretch with respect to frequency"), - rToggle(Pforcedrelease, rShort("frcr"), + rToggle(Pforcedrelease, rShort("frcr"), rDefaultDepends(envelope_type), + rPresets(true, false, true, true, false, + false, false, true, false, false), "Force Envelope to fully evaluate"), - rToggle(Plinearenvelope, rShort("lin/log"), + rToggle(Plinearenvelope, rShort("lin/log"), rDefault(false), "Linear or Logarithmic Envelopes"), - rParamZyn(PA_dt, rShort("a.dt"), - rDefaultDepends(Envmode), rMap(default 1, 0 /*TODO*/) "Attack Time"), - rParamZyn(PA_val, rShort("a.val"), rDefaultDepends(Envmode), "Attack Value"), - rParamZyn(PD_dt, rShort("d.dt"), rDefaultDepends(Envmode), "Decay Time"), - rParamZyn(PD_val, rShort("d.val"), rDefaultDepends(Envmode), "Decay Value"), - rParamZyn(PS_val, rShort("s.val"), rDefaultDepends(Envmode), "Sustain Value"), - rParamZyn(PR_dt, rShort("r.dt"), rDefaultDepends(Envmode), "Release Time"), - rParamZyn(PR_val, rShort("r.val"), "Release Value"), + rParamZyn(PA_dt, rShort("a.dt"), rDefaultDepends(envelope_type), + rPresets(0, 50, 40, 0, 40, 70, 90, 80, 50, 70), + "Attack Time"), + rParamZyn(PA_val, rShort("a.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(4, 30, 90, 20, 64, 30, 100), + "Attack Value"), + rParamZyn(PD_dt, rShort("d.dt"), rDefaultDepends(envelope_type), + rDefault(10), rPresets(40, 10, 70, 100, 10, 70, 10, 90), + "Decay Time"), + rParamZyn(PD_val, rShort("d.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(5, 40), + "Decay Value"), + rParamZyn(PS_val, rShort("s.val"), rDefaultDepends(envelope_type), + rDefault(64), + rPresets(127), rPresetsAt(3, 127), rPresetsAt(7, 127), + "Sustain Value"), + rParamZyn(PR_dt, rShort("r.dt"), rDefaultDepends(envelope_type), + rPresets(25, 60, 60, 100, 60, 10, 80, 100, 60, 60), + "Release Time"), + rParamZyn(PR_val, rShort("r.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(5, 40, 40), + "Release Value"), {"Envmode:", rDoc("Envelope variant type"), NULL, rBegin; @@ -203,6 +229,26 @@ void EnvelopeParams::paste(const EnvelopeParams &ep) } #undef COPY +void EnvelopeParams::init(EnvelopeParams::envelope_type_t etype) +{ + switch(etype) + { + case ad_global_amp_env: ADSRinit_dB(0, 40, 127, 25); break; + case ad_global_freq_env: ASRinit(64, 50, 64, 60); break; + case ad_global_filter_env: ADSRinit_filter(64, 40, 64, 70, 60, 64); + break; + case ad_voice_amp_env: ADSRinit_dB(0, 100, 127, 100); break; + case ad_voice_freq_env: ASRinit(30, 40, 64, 60); break; + case ad_voice_filter_env: ADSRinit_filter(90, 70, 40, 70, 10, 40); + break; + case ad_voice_fm_freq_env: ASRinit(20, 90, 40, 80); break; + case ad_voice_fm_amp_env: ADSRinit(80, 90, 127, 100); break; + case sub_freq_env: ASRinit(30, 50, 64, 60); break; + case sub_bandwidth_env: ASRinit_bw(100, 70, 64, 60); break; + }; + envelope_type = etype; +} + float EnvelopeParams::getdt(char i) const { return EnvelopeParams::dt(Penvdt[(int)i]); @@ -305,16 +351,6 @@ void EnvelopeParams::converttofree() { switch(Envmode) { case 1: - Penvpoints = 4; - Penvsustain = 2; - Penvval[0] = 0; - Penvdt[1] = PA_dt; - Penvval[1] = 127; - Penvdt[2] = PD_dt; - Penvval[2] = PS_val; - Penvdt[3] = PR_dt; - Penvval[3] = 0; - break; case 2: Penvpoints = 4; Penvsustain = 2; @@ -327,6 +363,7 @@ void EnvelopeParams::converttofree() Penvval[3] = 0; break; case 3: + case 5: Penvpoints = 3; Penvsustain = 1; Penvval[0] = PA_val; @@ -346,15 +383,6 @@ void EnvelopeParams::converttofree() Penvdt[3] = PR_dt; Penvval[3] = PR_val; break; - case 5: - Penvpoints = 3; - Penvsustain = 1; - Penvval[0] = PA_val; - Penvdt[1] = PA_dt; - Penvval[1] = 64; - Penvdt[2] = PR_dt; - Penvval[2] = PR_val; - break; } } @@ -414,7 +442,7 @@ public: // f^{-1} o (env_dB2rap^{-1}) o dB2rap o f // from the xml file. This results in the following formula: ? roundf(127.0f * (0.5f * - log10f( 0.01f + 0.99f * + log10f( 0.01f + 0.99f * powf(100, input/127.0f - 1)) + 1)) : input; diff --git a/src/Params/EnvelopeParams.h b/src/Params/EnvelopeParams.h @@ -23,21 +23,28 @@ namespace zyn { class EnvelopeParams:public Presets { public: + enum envelope_type_t + { + ad_global_amp_env, // ADSRinit_dB(0, 40, 127, 25); + ad_global_freq_env, // ASRinit(64, 50, 64, 60); + ad_global_filter_env, // ADSRinit_filter(64, 40, 64, 70, 60, 64) + + ad_voice_amp_env, // ADSRinit_dB(0, 100, 127, 100); + ad_voice_freq_env, // ASRinit(30, 40, 64, 60); + ad_voice_filter_env, // ADSRinit_filter(90, 70, 40, 70, 10, 40); + ad_voice_fm_freq_env, // ASRinit(20, 90, 40, 80); + ad_voice_fm_amp_env, // ADSRinit(80, 90, 127, 100) + sub_freq_env, // ASRinit(30, 50, 64, 60); + sub_bandwidth_env, // ASRinit_bw(100, 70, 64, 60) + }; + EnvelopeParams(unsigned char Penvstretch_=64, unsigned char Pforcedrelease_=0, const AbsTime *time_ = nullptr); ~EnvelopeParams(); void paste(const EnvelopeParams &ep); - void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt); - void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt); - void ASRinit(char A_val, char A_dt, char R_val, char R_dt); - void ADSRinit_filter(char A_val, - char A_dt, - char D_val, - char D_dt, - char R_dt, - char R_val); - void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt); + + void init(envelope_type_t etype); void converttofree(); void add2XML(XMLwrapper& xml); @@ -48,6 +55,10 @@ class EnvelopeParams:public Presets static float dt(char val); static char inv_dt(float val); + //! @brief defines where it is used and its default settings + //! corresponds to envelope_type_t + int envelope_type; + /* MIDI Parameters */ unsigned char Pfreemode; //1 for free mode, 0 otherwise unsigned char Penvpoints; @@ -78,6 +89,17 @@ class EnvelopeParams:public Presets static float env_dB2rap(float db); private: + void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt); + void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt); + void ASRinit(char A_val, char A_dt, char R_val, char R_dt); + void ADSRinit_filter(char A_val, + char A_dt, + char D_val, + char D_dt, + char R_dt, + char R_val); + void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt); + void store2defaults(); /* Default parameters */ diff --git a/src/Params/FilterParams.cpp b/src/Params/FilterParams.cpp @@ -3,7 +3,9 @@ FilterParams.cpp - Parameters for filter Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2017 Mark McCurry Author: Nasca Octavian Paul + Mark McCurry This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -66,14 +68,16 @@ const rtosc::Ports FilterParams::ports = { rOption(Ptype, rShort("type"), rOptions(LP1, HP1, LP2, HP2, BP, notch, peak, l.shelf, h.shelf), "Filter Type"), - rParamZyn(Pfreq, rShort("cutoff"), "Center Freq"), - rParamZyn(Pq, rShort("q"), - "Quality Factor (resonance/bandwidth)"), rParamI(Pstages, rShort("stages"), rLinear(0,5), "Filter Stages"), - rParamZyn(Pfreqtrack, rShort("f.track"), + rParamF(baseq, rShort("q"), rUnit(none), rLog(0.1, 1000), + "Quality Factor (resonance/bandwidth)"), + rParamF(basefreq, rShort("cutoff"), rUnit(Hz), rLog(31.25, 32000), + "Base cutoff frequency"), + rParamF(freqtracking, rShort("f.track"), rUnit(%), rLinear(-100, 100), "Frequency Tracking amount"), - rParamZyn(Pgain, rShort("gain"), "Output Gain"), + rParamF(gain, rShort("gain"), rUnit(dB), rLinear(-30, 30), + "Output Gain"), rParamI(Pnumformants, rShort("formants"), rLinear(1,12), "Number of formants to be used"), rParamZyn(Pformantslowness, rShort("slew"), @@ -97,8 +101,9 @@ const rtosc::Ports FilterParams::ports = { unsigned idx = atoi(mm); if(rtosc_narguments(msg)) { obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i; - } else d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel); + } else + d.reply(d.loc, "i", obj->Psequence[idx].nvowel); }}, {"type-svf::i", rProp(parameter) rShort("type") rOptions(low, high, band, notch) @@ -222,6 +227,65 @@ const rtosc::Ports FilterParams::ports = { } d.replyArray(d.loc, type, args); }}, + + //Old 0..127 parameter mappings + {"Pfreq::i", rLinear(0, 127) rShort("cutoff") rProp(deprecated) rDoc("Center Freq"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pfreq = rtosc_argument(msg, 0).i; + obj->basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + obj->basefreq = powf(2.0f, obj->basefreq + 9.96578428f); + rChangeCb; + d.broadcast(d.loc, "i", Pfreq); + } else { + float tmp = obj->basefreq; + tmp = log2f(tmp) - 9.96578428f; + tmp = (tmp / 5.0 + 1.0) * 64.0f; + int Pfreq = roundf(tmp); + d.reply(d.loc, "i", Pfreq); + } + }}, + {"Pfreqtrack::i", rLinear(0, 127) rShort("f.track") rProp(deprecated) rDoc("Frequency Tracking amount"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pfreqtracking = rtosc_argument(msg, 0).i; + obj->freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f); + rChangeCb; + d.broadcast(d.loc, "i", Pfreqtracking); + } else { + int Pfreqtracking = obj->freqtracking/100.0*64.0 + 64.0; + d.reply(d.loc, "i", Pfreqtracking); + } + }}, + {"Pgain::i", rLinear(0, 127) rShort("gain") rProp(deprecated) rDoc("Output Gain"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pgain = rtosc_argument(msg, 0).i; + obj->gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + rChangeCb; + d.broadcast(d.loc, "i", Pgain); + } else { + int Pgain = roundf((obj->gain/30.0f + 1.0f) * 64.0f); + d.reply(d.loc, "i", Pgain); + } + }}, + {"Pq::i", rLinear(0,127) rShort("q") rProp(deprecated) + rDoc("Quality Factor (resonance/bandwidth)"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pq = rtosc_argument(msg, 0).i; + obj->baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + rChangeCb; + d.broadcast(d.loc, "i", Pq); + } else { + int Pq = roundf(127.0f * sqrtf(logf(0.9f + obj->baseq)/logf(1000.0f))); + d.reply(d.loc, "i", Pq); + } + }}, }; #undef rChangeCb #define rChangeCb @@ -257,16 +321,21 @@ void FilterParams::defaults() Pfreq = Dfreq; Pq = Dq; - Pstages = 0; - Pfreqtrack = 64; - Pgain = 64; - Pcategory = 0; + Pstages = 0; + basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + basefreq = powf(2.0f, basefreq + 9.96578428f); + baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + + gain = 0.0f; + freqtracking = 0.0f; + + Pcategory = 0; Pnumformants = 3; Pformantslowness = 64; for(int j = 0; j < FF_MAX_VOWELS; ++j) defaults(j); - ; + Psequencesize = 3; for(int i = 0; i < FF_MAX_SEQUENCE; ++i) @@ -306,10 +375,10 @@ void FilterParams::getfromFilterParams(FilterParams *pars) Pfreq = pars->Pfreq; Pq = pars->Pq; - Pstages = pars->Pstages; - Pfreqtrack = pars->Pfreqtrack; - Pgain = pars->Pgain; - Pcategory = pars->Pcategory; + Pstages = pars->Pstages; + freqtracking = pars->freqtracking; + gain = pars->gain; + Pcategory = pars->Pcategory; Pnumformants = pars->Pnumformants; Pformantslowness = pars->Pformantslowness; @@ -337,21 +406,21 @@ void FilterParams::getfromFilterParams(FilterParams *pars) */ float FilterParams::getfreq() const { - return (Pfreq / 64.0f - 1.0f) * 5.0f; + return log2(basefreq) - log2f(1000.0f); } float FilterParams::getq() const { - return expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + return baseq; } float FilterParams::getfreqtracking(float notefreq) const { - return logf(notefreq / 440.0f) * (Pfreqtrack - 64.0f) / (64.0f * LOG_2); + return log2f(notefreq / 440.0f) * (freqtracking / 100.0); } float FilterParams::getgain() const { - return (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + return gain; } /* @@ -427,11 +496,11 @@ void FilterParams::add2XML(XMLwrapper& xml) //filter parameters xml.addpar("category", Pcategory); xml.addpar("type", Ptype); - xml.addpar("freq", Pfreq); - xml.addpar("q", Pq); + xml.addparreal("basefreq", basefreq); + xml.addparreal("baseq", baseq); xml.addpar("stages", Pstages); - xml.addpar("freq_track", Pfreqtrack); - xml.addpar("gain", Pgain); + xml.addparreal("freq_tracking", freqtracking); + xml.addparreal("gain", gain); //formant filter parameters if((Pcategory == 1) || (!xml.minimal)) { @@ -481,14 +550,28 @@ void FilterParams::getfromXMLsection(XMLwrapper& xml, int n) void FilterParams::getfromXML(XMLwrapper& xml) { + const bool upgrade_3_0_2 = (xml.fileversion() < version_type(3,0,2)) && (xml.getparreal("basefreq", -1) < 0); + //filter parameters - Pcategory = xml.getpar127("category", Pcategory); - Ptype = xml.getpar127("type", Ptype); - Pfreq = xml.getpar127("freq", Pfreq); - Pq = xml.getpar127("q", Pq); - Pstages = xml.getpar127("stages", Pstages); - Pfreqtrack = xml.getpar127("freq_track", Pfreqtrack); - Pgain = xml.getpar127("gain", Pgain); + Pcategory = xml.getpar127("category", Pcategory); + Ptype = xml.getpar127("type", Ptype); + Pstages = xml.getpar127("stages", Pstages); + if(upgrade_3_0_2) { + int Pfreq = xml.getpar127("freq", 0); + basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + basefreq = powf(2.0f, basefreq + 9.96578428f); + int Pq = xml.getpar127("q", 0); + baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + int Pgain = xml.getpar127("gain", 0); + gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + int Pfreqtracking = xml.getpar127("freq_track", 0); + freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f); + } else { + basefreq = xml.getparreal("basefreq", 1000); + baseq = xml.getparreal("baseq", 10); + gain = xml.getparreal("gain", 0); + freqtracking = xml.getparreal("freq_track", 0); + } //formant filter parameters if(xml.enterbranch("FORMANT_FILTER")) { @@ -526,11 +609,11 @@ void FilterParams::paste(FilterParams &x) { COPY(Pcategory); COPY(Ptype); - COPY(Pfreq); + COPY(basefreq); COPY(Pq); COPY(Pstages); - COPY(Pfreqtrack); - COPY(Pgain); + COPY(freqtracking); + COPY(gain); COPY(Pnumformants); COPY(Pformantslowness); @@ -565,7 +648,6 @@ void FilterParams::paste(FilterParams &x) void FilterParams::pasteArray(FilterParams &x, int nvowel) { - printf("FilterParameters::pasting-an-array<%d>\n", nvowel); for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) { auto &self = Pvowels[nvowel].formants[nformant]; auto &update = x.Pvowels[nvowel].formants[nformant]; diff --git a/src/Params/FilterParams.h b/src/Params/FilterParams.h @@ -46,13 +46,18 @@ class FilterParams:public PresetsArray 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..) - unsigned char Pfreq; // Frequency (64-central frequency) - unsigned char Pq; // Q parameters (resonance or bandwidth) - unsigned char Pstages; //filter stages+1 - unsigned char Pfreqtrack; //how the filter frequency is changing according the note frequency - unsigned char Pgain; //filter's output gain + unsigned Pcategory:2; //< Filter category (Analog/Formant/StVar) + unsigned Ptype:8; //< Filter type (for analog lpf,hpf,bpf..) + unsigned Pstages:8; //< filter stages+1 + float basefreq; //< Base cutoff frequency (Hz) + float baseq; //< Q parameters (resonance or bandwidth) + float freqtracking; //< Tracking of center frequency with note frequency (percentage) + float gain; //< filter's output gain (dB) + + int Pq; //dummy + int Pfreq; //dummy + int Pfreqtrack; //dummy + int Pgain; //dummy //Formant filter parameters unsigned char Pnumformants; //how many formants are used diff --git a/src/Params/LFOParams.cpp b/src/Params/LFOParams.cpp @@ -47,8 +47,10 @@ static const rtosc::Ports _ports = { rParamZyn(Pdelay, rShort("delay"), rSpecial(disable), "Delay before LFO start\n" "0..4 second delay"), rToggle(Pcontinous, rShort("c"), "Enable for global operation"), - rParamZyn(Pstretch, rShort("str"), rCentered, rDefault(64), "Note frequency stretch"), - + rParamZyn(Pstretch, rShort("str"), rCentered, rDefault(64), + "Note frequency stretch"), +// these are currently not yet implemented at must be hidden therefore +#ifdef DEAD_PORTS //Float valued aliases {"delay::f", rProp(parameter) rMap(units, ms) rLog(0,4000), 0, rBegin; @@ -58,6 +60,7 @@ static const rtosc::Ports _ports = { {"period::f", rProp(parameter) rMap(units, ms) rPseudoLog(0.10, 1500.0), 0, rBegin; rEnd}, +#endif }; #undef rPseudoLog #undef rBegin diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp @@ -44,26 +44,39 @@ static const rtosc::Ports realtime_ports = rToggle(PStereo, rShort("stereo"), rDefault(true), "Stereo/Mono Mode"), rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"), rParamZyn(PVolume, rShort("vol"), rDefault(90), "Synth Volume"), - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(64), "Amplitude Velocity Sensing function"), + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(64), + "Amplitude Velocity Sensing function"), - rParamZyn(Fadein_adjustment, rShort("a.pop."), rDefault(FADEIN_ADJUSTMENT_SCALE), "Adjustment for anti-pop strategy."), + rParamZyn(Fadein_adjustment, rShort("a.pop."), + rDefault(FADEIN_ADJUSTMENT_SCALE), "Adjustment for anti-pop strategy."), //Punch - rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), "Punch Strength"), - rParamZyn(PPunchTime, rShort("time"), rDefault(60), "Length of punch"), - rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), "How Punch changes with note frequency"), - rParamZyn(PPunchVelocitySensing, rShort("sense"), rDefault(72), "Punch Velocity control"), + rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), + "Punch Strength"), + rParamZyn(PPunchTime, rShort("time"), rDefault(60), + "Length of punch"), + rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), + "How Punch changes with note frequency"), + rParamZyn(PPunchVelocitySensing, rShort("sense"), rDefault(72), + "Punch Velocity control"), //Filter - rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), "Filter Velocity Function Shape"), + rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //Freq - rToggle(Pfixedfreq, rShort("fixed"), rDefault(false), "Base frequency fixed frequency enable"), - rParamZyn(PfixedfreqET, rShort("f.ET"), rDefault(0), "Equal temeperate control for fixed frequency operation"), - rParamZyn(PBendAdjust, rDefault(88), "Pitch bend adjustment"), - rParamZyn(POffsetHz, rShort("offset"), rDefault(64), "Voice constant offset"), - rParamI(PDetune, rShort("fine"), rLinear(0, 16383), rDefault(8192), "Fine Detune"), + rToggle(Pfixedfreq, rShort("fixed"), rDefault(false), + "Base frequency fixed frequency enable"), + rParamZyn(PfixedfreqET, rShort("f.ET"), rDefault(0), + "Equal temeperate control for fixed frequency operation"), + rParamZyn(PBendAdjust, rDefault(88), + "Pitch bend adjustment"), + rParamZyn(POffsetHz, rShort("offset"), rDefault(64), + "Voice constant offset"), + rParamI(PDetune, rShort("fine"), rLinear(0, 16383), rDefault(8192), + "Fine Detune"), rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"), rParamZyn(PDetuneType, rShort("type"), rOptions(L35cents, L10cents, E100cents, E1200cents), @@ -142,26 +155,36 @@ static const rtosc::Ports non_realtime_ports = rRecurp(resonance, "Resonance"), //Harmonic Shape - rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), rOptions(bandwidth,discrete,continious), + rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), + rOptions(bandwidth,discrete,continious), rDefault(bandwidth), - "Harmonic Distribution Model"), - rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), rShort("shape"), - rDefault(Gaussian), + "Harmonic Distribution Model"), + rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), + rShort("shape"), rDefault(Gaussian), "Harmonic profile shape"), - rParamZyn(Php.base.par1, rShort("warp"), rDefault(80), "Harmonic shape distribution parameter"), - rParamZyn(Php.freqmult, rShort("clone"), rDefault(0), "Frequency multiplier on distribution"), - rParamZyn(Php.modulator.par1, rShort("p1"), rDefault(0), "Distribution modulator parameter"), - rParamZyn(Php.modulator.freq, rShort("freq"), rDefault(30), "Frequency of modulator parameter"), - rParamZyn(Php.width, rShort("bandwidth"), rDefault(127), "Width of base harmonic"), - rOption(Php.amp.mode, rShort("mode"), rOptions(Sum, Mult, Div1, Div2), - rDefault(0), "Amplitude harmonic multiplier type"), + rParamZyn(Php.base.par1, rShort("warp"), rDefault(80), + "Harmonic shape distribution parameter"), + rParamZyn(Php.freqmult, rShort("clone"), rDefault(0), + "Frequency multiplier on distribution"), + rParamZyn(Php.modulator.par1, rShort("p1"), rDefault(0), + "Distribution modulator parameter"), + rParamZyn(Php.modulator.freq, rShort("freq"), rDefault(30), + "Frequency of modulator parameter"), + rParamZyn(Php.width, rShort("bandwidth"), rDefault(127), + "Width of base harmonic"), + rOption(Php.amp.mode, rShort("mode"), + rOptions(Sum, Mult, Div1, Div2), rDefault(Sum), + "Amplitude harmonic multiplier type"), //Harmonic Modulation rOption(Php.amp.type, rShort("mult"), rOptions(Off, Gauss, Sine, Flat), - rDefault(0), "Type of amplitude multipler"), - rParamZyn(Php.amp.par1, rShort("p1"), rDefault(80), "Amplitude multiplier parameter"), - rParamZyn(Php.amp.par2, rShort("p2"), rDefault(60), "Amplitude multiplier parameter"), - rToggle(Php.autoscale, rShort("auto"), rDefault(true), "Autoscaling Harmonics"), + rDefault(Off), "Type of amplitude multipler"), + rParamZyn(Php.amp.par1, rShort("p1"), rDefault(80), + "Amplitude multiplier parameter"), + rParamZyn(Php.amp.par2, rShort("p2"), rDefault(60), + "Amplitude multiplier parameter"), + rToggle(Php.autoscale, rShort("auto"), rDefault(true), + "Autoscaling Harmonics"), rOption(Php.onehalf, rShort("side"), rOptions(Full, Upper Half, Lower Half), rDefault(Full) "Harmonic cutoff model"), @@ -172,7 +195,7 @@ static const rtosc::Ports non_realtime_ports = EqualHz, Quater, Half, 75%, 150%, Double, Inv. Half), - rDefault(Normal), + rDefault(Normal), "Bandwidth scaling"), //Harmonic Position Modulation @@ -181,24 +204,27 @@ static const rtosc::Ports non_realtime_ports = Power, Shift), rDefault(Harmonic) "Harmonic Overtone shifting mode"), - rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), rDefault(0), "Harmonic position parameter"), - rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), rDefault(0), "Harmonic position parameter"), - rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), rDefault(0), "Harmonic position parameter"), + rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), + rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), + rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), //Quality rOption(Pquality.samplesize, rShort("quality"), rOptions(16k (Tiny), 32k, 64k (Small), 128k, 256k (Normal), 512k, 1M (Big)), - rDefault(128k), + rDefaultId(128k), "Size of each wavetable element"), rOption(Pquality.basenote, rShort("basenote"), rOptions(C-2, G-2, C-3, G-3, C-4, G-4, C-5, G-5, G-6,), - rDefault(C-4), + rDefaultId(C-4), "Base note for wavetable"), rOption(Pquality.smpoct, rShort("smp/oct"), rOptions(0.5, 1, 2, 3, 4, 6, 12), - rDefault(2), + rDefault(2), "Samples per octave"), rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7), rDefault(3), "Number of octaves to sample (above the first sample"), @@ -285,16 +311,16 @@ PADnoteParameters::PADnoteParameters(const SYNTH_T &synth_, FFTwrapper *fft_, oscilgen->ADvsPAD = true; FreqEnvelope = new EnvelopeParams(0, 0, time_); - FreqEnvelope->ASRinit(64, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_global_freq_env); FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_); GlobalFilter = new FilterParams(2, 94, 40, time_); FilterEnvelope = new EnvelopeParams(0, 1, time_); - FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + FilterEnvelope->init(EnvelopeParams::ad_global_filter_env); FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_); for(int i = 0; i < PAD_MAX_SAMPLES; ++i) diff --git a/src/Params/SUBnoteParameters.cpp b/src/Params/SUBnoteParameters.cpp @@ -40,32 +40,44 @@ static const rtosc::Ports SUBnotePorts = { rToggle(Pstereo, rShort("stereo"), rDefault(true), "Stereo Enable"), rParamZyn(PVolume, rShort("volume"), rDefault(96), "Volume"), rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"), - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(90), "Amplitude Velocity Sensing function"), - rParamI(PDetune, rShort("detune"), rLinear(0, 16383), rDefault(8192), "Detune in detune type units"), + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(90), + "Amplitude Velocity Sensing function"), + rParamI(PDetune, rShort("detune"), rLinear(0, 16383), rDefault(8192), + "Detune in detune type units"), rParamI(PCoarseDetune, rShort("cdetune"), rDefault(0), "Coarse Detune"), //Real values needed rOption(PDetuneType, rShort("det. scl."), - rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), rDefault(L10 cents), "Detune Scale"), - rToggle(PFreqEnvelopeEnabled, rShort("enable"), rDefault(false), "Enable for Frequency Envelope"), - rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), rDefault(false), "Enable for Bandwidth Envelope"), - rToggle(PGlobalFilterEnabled, rShort("enable"), rDefault(false), "Enable for Global Filter"), - rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), rDefault(64), "Filter Velocity Magnitude"), - rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), rDefault(64), "Filter Velocity Function Shape"), + rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), + rDefaultId(L10 cents), "Detune Scale"), + rToggle(PFreqEnvelopeEnabled, rShort("enable"), rDefault(false), + "Enable for Frequency Envelope"), + rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), rDefault(false), + "Enable for Bandwidth Envelope"), + rToggle(PGlobalFilterEnabled, rShort("enable"), + rDefault(false), "Enable for Global Filter"), + rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //rRecur(FreqEnvelope, EnvelopeParams), //rToggle(),//continue - rToggle(Pfixedfreq, rShort("fixed freq"), rDefault(false), "Base frequency fixed frequency enable"), - rParamZyn(PfixedfreqET, rShort("fixed ET"), rDefault(0), "Equal temeperate control for fixed frequency operation"), - rParamZyn(PBendAdjust, rShort("bend"), rDefault(88), "Pitch bend adjustment"), - rParamZyn(POffsetHz, rShort("+ Hz"), rDefault(64), "Voice constant offset"), + rToggle(Pfixedfreq, rShort("fixed freq"), rDefault(false), + "Base frequency fixed frequency enable"), + rParamZyn(PfixedfreqET, rShort("fixed ET"), rDefault(0), + "Equal temeperate control for fixed frequency operation"), + rParamZyn(PBendAdjust, rShort("bend"), rDefault(88), + "Pitch bend adjustment"), + rParamZyn(POffsetHz, rShort("+ Hz"), rDefault(64), + "Voice constant offset"), #undef rChangeCb #define rChangeCb obj->updateFrequencyMultipliers(); if (obj->time) { \ obj->last_update_timestamp = obj->time->time(); } rParamI(POvertoneSpread.type, rMap(min, 0), rMap(max, 7), rShort("spread type") rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, Power, Shift), - rDefault(Harmonic) + rDefault(Harmonic) "Spread of harmonic frequencies"), rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), rShort("p1"), - rDefault(0), "Overtone Parameter"), + rDefault(0), "Overtone Parameter"), rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"), rDefault(0), "Overtone Parameter"), rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("forceH"), @@ -74,20 +86,24 @@ static const rtosc::Ports SUBnotePorts = { #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), rDefault(2), "Number of filter stages"), - rParamZyn(Pbandwidth, rShort("bandwidth"), rDefault(40), "Bandwidth of filters"), - rParamZyn(Phmagtype, rShort("mag. type"), rOptions(linear, -40dB, -60dB, -80dB, -100dB), + rParamZyn(Pbandwidth, rShort("bandwidth"), rDefault(40), + "Bandwidth of filters"), + rParamZyn(Phmagtype, rShort("mag. type"), + rOptions(linear, -40dB, -60dB, -80dB, -100dB), rDefault(linear), "Magnitude scale"), - rArray(Phmag, MAX_SUB_HARMONICS, rDefault(0), + rArray(Phmag, MAX_SUB_HARMONICS, rDefaultMissing, "Harmonic magnitudes"), - rArray(Phrelbw, MAX_SUB_HARMONICS, rDefault(64), + rArray(Phrelbw, MAX_SUB_HARMONICS, rDefaultMissing, "Relative bandwidth"), - rParamZyn(Pbwscale, rShort("stretch"), rDefault(64), "Bandwidth scaling with frequency"), + rParamZyn(Pbwscale, rShort("stretch"), rDefault(64), + "Bandwidth scaling with frequency"), rRecurp(AmpEnvelope, "Amplitude envelope"), rRecurp(FreqEnvelope, "Frequency Envelope"), rRecurp(BandWidthEnvelope, "Bandwidth Envelope"), rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"), rRecurp(GlobalFilter, "Post Filter"), - rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), rDefault(random), + rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), + rDefault(random), "How harmonics are initialized"), {"clear:", rDoc("Reset all harmonics to equal bandwidth/zero amplitude"), NULL, @@ -185,15 +201,15 @@ SUBnoteParameters::SUBnoteParameters(const AbsTime *time_) { setpresettype("Psubsynth"); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); FreqEnvelope = new EnvelopeParams(64, 0, time_); - FreqEnvelope->ASRinit(30, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::sub_freq_env); BandWidthEnvelope = new EnvelopeParams(64, 0, time_); - BandWidthEnvelope->ASRinit_bw(100, 70, 64, 60); + BandWidthEnvelope->init(EnvelopeParams::sub_bandwidth_env); GlobalFilter = new FilterParams(2, 80, 40, time_); GlobalFilterEnvelope = new EnvelopeParams(0, 1, time_); - GlobalFilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + GlobalFilterEnvelope->init(EnvelopeParams::ad_global_filter_env); defaults(); } diff --git a/src/Plugin/ZynAddSubFX/DistrhoPluginInfo.h b/src/Plugin/ZynAddSubFX/DistrhoPluginInfo.h @@ -41,6 +41,22 @@ #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 enum Parameters { + kParamSlot1, + kParamSlot2, + kParamSlot3, + kParamSlot4, + kParamSlot5, + kParamSlot6, + kParamSlot7, + kParamSlot8, + kParamSlot9, + kParamSlot10, + kParamSlot11, + kParamSlot12, + kParamSlot13, + kParamSlot14, + kParamSlot15, + kParamSlot16, kParamOscPort, kParamCount }; diff --git a/src/Plugin/ZynAddSubFX/ZynAddSubFX.cpp b/src/Plugin/ZynAddSubFX/ZynAddSubFX.cpp @@ -115,8 +115,6 @@ public: oscPort(0), middlewareThread(new MiddleWareThread()) { - config.init(); - synth.buffersize = static_cast<int>(getBufferSize()); synth.samplerate = static_cast<uint>(getSampleRate()); @@ -226,6 +224,15 @@ protected: parameter.ranges.def = 0.0f; break; } + if(kParamSlot1 <= index && index <= kParamSlot16) { + parameter.hints = kParameterIsAutomable; + parameter.name = ("Slot " + zyn::to_s(index-kParamSlot1 + 1)).c_str(); + parameter.symbol = ("slot" + zyn::to_s(index-kParamSlot1 + 1)).c_str(); + parameter.unit = ""; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + parameter.ranges.def = 0.5f; + } } /** @@ -238,9 +245,11 @@ protected: { case kParamOscPort: return oscPort; - default: - return 0.0f; } + if(kParamSlot1 <= index && index <= kParamSlot16) { + return master->automate.getSlot(index - kParamSlot1); + } + return 0.0f; } /** @@ -249,9 +258,12 @@ protected: When a parameter is marked as automable, you must ensure no non-realtime operations are performed. @note This function will only be called for parameter inputs. */ - void setParameterValue(uint32_t /*index*/, float /*value*/) noexcept override + void setParameterValue(uint32_t index, float value) noexcept override { // only an output port for now + if(kParamSlot1 <= index && index <= kParamSlot16) { + master->automate.setSlot(index - kParamSlot1, value); + } } /* -------------------------------------------------------------------------------------------------------- @@ -395,6 +407,17 @@ protected: master->setController(channel, control, value); } break; + case 0xC0: { + const int program = midiEvent.data[1]; + + for(int i=0; i < NUM_MIDI_PARTS; ++i) { + //set the program of the parts assigned to the midi channel + if(master->part[i]->Prcvchn == channel) { + middleware->pendingSetProgram(i, program); + } + } + } break; + case 0xE0: { const uint8_t lsb = midiEvent.data[1]; const uint8_t msb = midiEvent.data[2]; @@ -570,6 +593,7 @@ END_NAMESPACE_DISTRHO /* ------------------------------------------------------------------------------------------------------------ * Dummy variables and functions for linking purposes */ +namespace zyn { class WavFile; namespace Nio { void masterSwap(zyn::Master*){} @@ -583,3 +607,4 @@ namespace Nio { void waveStart(){} void waveStop(){} } +} diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -38,27 +38,30 @@ const rtosc::Ports OscilGen::non_realtime_ports = { rOptions(linear,dB scale (-40), dB scale (-60), dB scale (-80), dB scale (-100)), + rDefault(linear), "Type of magnitude for harmonics"), rOption(Pcurrentbasefunc, rShort("base"), rOptions(sine, triangle, pulse, saw, power, gauss, diode, abssine, pulsesine, stretchsine, chirp, absstretchsine, chebyshev, sqr, spike, circle), rOpt(127,use-as-base waveform), + rDefault(sine), "Base Waveform for harmonics"), - rParamZyn(Pbasefuncpar, rShort("shape"), + rParamZyn(Pbasefuncpar, rShort("shape"), rDefault(64), "Morph between possible base function shapes " "(e.g. rising sawtooth vs a falling sawtooth)"), rOption(Pbasefuncmodulation, rShort("mod"), - rOptions(None, Rev, Sine, Power, Chop), + rOptions(None, Rev, Sine, Power, Chop), rDefault(None), "Modulation applied to Base function spectra"), - rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), + rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), rDefault(64), "Base function modulation parameter"), - rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), + rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), rDefault(64), "Base function modulation parameter"), - rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), + rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), rDefault(32), "Base function modulation parameter"), - rParamZyn(Pwaveshaping, rShort("amount"), "Degree Of Waveshaping"), - rOption(Pwaveshapingfunction, rShort("distort"), + rParamZyn(Pwaveshaping, rShort("amount"), rDefault(64), + "Degree Of Waveshaping"), + rOption(Pwaveshapingfunction, rShort("distort"), rDefault(Undistorted), rOptions(Undistorted, Arctangent, Asymmetric, Pow, Sine, Quantisize, Zigzag, Limiter, Upper Limiter, Lower Limiter, @@ -66,22 +69,29 @@ const rtosc::Ports OscilGen::non_realtime_ports = { "Shape of distortion to be applied"), rOption(Pfiltertype, rShort("filter"), rOptions(No Filter, lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2, - cos, sin, low_shelf, s), "Harmonic Filter"), - rParamZyn(Pfilterpar1, rShort("p1"), "Filter parameter"), - rParamZyn(Pfilterpar2, rShort("p2"), "Filter parameter"), - rToggle(Pfilterbeforews, rShort("pre/post"), "Filter before waveshaping spectra;" + cos, sin, low_shelf, s), rDefaultId(No Filter), "Harmonic Filter"), + rParamZyn(Pfilterpar1, rShort("p1"), rDefault(64), "Filter parameter"), + rParamZyn(Pfilterpar2, rShort("p2"), rDefault(64), "Filter parameter"), + rToggle(Pfilterbeforews, rShort("pre/post"), rDefault(false), + "Filter before waveshaping spectra;" "When enabled oscilfilter(freqs); then waveshape(freqs);, " "otherwise waveshape(freqs); then oscilfilter(freqs);"), rOption(Psatype, rShort("spec. adj."), rOptions(None, Pow, ThrsD, ThrsU), - "Spectral Adjustment Type"), - rParamZyn(Psapar, rShort("p1"), "Spectral Adjustment Parameter"), - rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), "Amount of shift on harmonics"), - rToggle(Pharmonicshiftfirst, rShort("pre/post"), "If harmonics are shifted before waveshaping/filtering"), + rDefault(None), "Spectral Adjustment Type"), + rParamZyn(Psapar, rShort("p1"), rDefault(64), + "Spectral Adjustment Parameter"), + rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), rDefault(0), + "Amount of shift on harmonics"), + rToggle(Pharmonicshiftfirst, rShort("pre/post"), rDefault(false), + "If harmonics are shifted before waveshaping/filtering"), rOption(Pmodulation, rShort("FM"), rOptions(None, Rev, Sine, Power), - "Frequency Modulation To Combined Spectra"), - rParamZyn(Pmodulationpar1, rShort("p1"), "modulation parameter"), - rParamZyn(Pmodulationpar2, rShort("p2"), "modulation parameter"), - rParamZyn(Pmodulationpar3, rShort("p3"), "modulation parameter"), + rDefault(None), "Frequency Modulation To Combined Spectra"), + rParamZyn(Pmodulationpar1, rShort("p1"), rDefault(64), + "modulation parameter"), + rParamZyn(Pmodulationpar2, rShort("p2"), rDefault(64), + "modulation parameter"), + rParamZyn(Pmodulationpar3, rShort("p3"), rDefault(32), + "modulation parameter"), //TODO update to rArray and test @@ -193,19 +203,21 @@ const rtosc::Ports OscilGen::realtime_ports{ rPresetType, rParamZyn(Prand, rLinear(-64, 63), rShort("phase rnd"), "Oscillator Phase Randomness: smaller than 0 is \"" "group\", larger than 0 is for each harmonic"), - rParamZyn(Pamprandpower, rShort("variance"), + rParamZyn(Pamprandpower, rShort("variance"), rDefault(64), "Variance of harmonic randomness"), rOption(Pamprandtype, rShort("distribution"), rOptions(None, Pow, Sin), + rDefault(None), "Harmonic random distribution to select from"), rOption(Padaptiveharmonics, rShort("adapt") rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd), + rDefault(OFF), "Adaptive Harmonics Mode"), rParamI(Padaptiveharmonicsbasefreq, rShort("c. freq"), rLinear(0,255), - "Base frequency of adaptive harmonic (30..3000Hz)"), + rDefault(128), "Base frequency of adaptive harmonic (30..3000Hz)"), rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200), - "Adaptive Harmonic Strength"), + rDefault(100), "Adaptive Harmonic Strength"), rParamI(Padaptiveharmonicspar, rShort("power"), rLinear(0,100), - "Adaptive Harmonics Postprocessing Power"), + rDefault(50), "Adaptive Harmonics Postprocessing Power"), {"waveform:", rDoc("Returns waveform points"), NULL, [](const char *, rtosc::RtData &d) { OscilGen &o = *((OscilGen*)d.obj); diff --git a/src/Synth/Resonance.cpp b/src/Synth/Resonance.cpp @@ -29,12 +29,17 @@ namespace zyn { const rtosc::Ports Resonance::ports = { rSelf(Resonance), rPaste, - rToggle(Penabled, rShort("enable"), "resonance enable"), - rToggle(Pprotectthefundamental, rShort("p.fund."), "Disable resonance filter on first harmonic"), - rParams(Prespoints, N_RES_POINTS, "Resonance data points"), - rParamZyn(PmaxdB, rShort("max"), "how many dB the signal may be amplified"), - rParamZyn(Pcenterfreq, rShort("c.freq"), "Center frequency"), - rParamZyn(Poctavesfreq, rShort("oct"), "The number of octaves..."), + rToggle(Penabled, rShort("enable"), rDefault(false), + "resonance enable"), + rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false), + "Disable resonance filter on first harmonic"), + rParams(Prespoints, N_RES_POINTS, rDefaultMissing, + "Resonance data points"), + rParamZyn(PmaxdB, rShort("max"), rDefault(20), + "how many dB the signal may be amplified"), + rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"), + rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64), + "The number of octaves..."), rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"), rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"), rAction(smooth, "Smooth out frequency response"), diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -42,7 +42,7 @@ target_link_libraries(XMLwrapperTest ${test_lib}) target_link_libraries(RandTest ${test_lib}) target_link_libraries(PADnoteTest ${test_lib}) target_link_libraries(MqTest ${test_lib}) -target_link_libraries(WatchTest ${test_lib}) +target_link_libraries(WatchTest ${test_lib}) target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio zynaddsubfx_gui_bridge ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) @@ -63,8 +63,11 @@ target_link_libraries(EffectTest ${test_lib}) add_executable(ins-test InstrumentStats.cpp) target_link_libraries(ins-test ${test_lib} rt) -# add_executable(load_omz load_omz.cpp) -# target_link_libraries(load-omz ${test_lib}) +add_executable(save-osc SaveOSC.cpp) +target_link_libraries(save-osc + zynaddsubfx_core zynaddsubfx_nio + zynaddsubfx_gui_bridge + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) #message(STATUS "Plugin Test ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}") diff --git a/src/Tests/MessageTest.h b/src/Tests/MessageTest.h @@ -243,6 +243,53 @@ class MessageTest:public CxxTest::TestSuite TS_ASSERT_EQUALS(field2, 35); } + void testFilterDepricated(void) + { + vector<string> v = {"Pfreq", "Pfreqtrack", "Pgain", "Pq"}; + for(int i=0; i<v.size(); ++i) { + string path = "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v[i]; + for(int j=0; j<128; ++j) { + mw->transmitMsg(path.c_str(), "i", j); //Set + mw->transmitMsg(path.c_str(), ""); //Get + } + + } + while(ms->uToB->hasNext()) { + const char *msg = ms->uToB->read(); + //printf("RT: handling <%s>\n", msg); + ms->applyOscEvent(msg); + } + + int id = 0; + int state = 0; + int value = 0; + // 0 - broadcast + // 1 - true value (set) + // 2 - expected value (get) + while(ms->bToU->hasNext()) { + const char *msg = ms->bToU->read(); + if(state == 0) { + TS_ASSERT_EQUALS(rtosc_narguments(msg), 0); + state = 1; + } else if(state == 1) { + TS_ASSERT_EQUALS(rtosc_narguments(msg), 1); + value = rtosc_argument(msg, 0).i; + state = 2; + } else if(state == 2) { + int val = rtosc_argument(msg, 0).i; + if(value != val) { + printf("%s - %d should equal %d\n", msg, value, val); + TS_ASSERT(0); + } + state = 0; + } + + //printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg)); + //if(rtosc_narguments(msg)) + // printf(" %d\n", rtosc_argument(msg, 0).i); + } + } + private: SYNTH_T *synth; diff --git a/src/Tests/PluginTest.h b/src/Tests/PluginTest.h @@ -33,6 +33,95 @@ NSM_Client *nsm = 0; char *instance_name=(char*)""; MiddleWare *middleware; +void fill_vec_with_lines(std::vector<string> &v, string s) +{ + std::istringstream stream(s); + std::string line; + while(std::getline(stream, line)) + v.push_back(line); +} +void print_string_differences(string orig, string next) +{ + std::vector<string> a, b; + fill_vec_with_lines(a, orig); + fill_vec_with_lines(b, next); + int N = a.size(); + int M = b.size(); + printf("%d vs %d\n", N, M); + + //Original String by New String + //Each step is either an insertion, deletion, or match + //Match is 0 cost and moves +1 State (if symbols are the same) + //Replace is 3 cost and moves +1 State (if symbols are different) + //Insertion is 2 cost and moves +2 State (+2 if symbols are different) + //Deletion is 1 cost and moves +0 State (+2 if symbols are different) + char *transition = new char[N*M]; + int *cost = new int[N*M]; + + const int match = 1; + const int insert = 2; + const int del = 3; + for(int i=0; i<N; ++i) { + for(int j=0; j<M; ++j) { + transition[i*M + j] = 0; + cost[i*M + j] = 0xffff; + } + } + + //Just assume the -1 line is the same + cost[0*M + 0] = (a[0] == b[0])*3; + cost[0*M + 1] = (a[1] == b[0])*2 + 2; + for(int i=1; i<N; ++i) { + for(int j=0; j<M; ++j) { + int cost_match = 0xffffff; + int cost_ins = 0xffffff; + int cost_del = 0xffffff; + cost_del = cost[(i-1)*M + j] + 2 + (a[i] != b[j])*2; + if(j > 1) + cost_ins = cost[(i-1)*M + (j-2)] + 1 + 2*(a[i] != b[j]); + if(j > 0) + cost_match = cost[(i-1)*M + (j-1)] + 2*(a[i] != b[j]); + + if(cost_match >= 0xffff && cost_ins >= 0xffff && cost_del >= 0xffff) { + ; + } else if(cost_match < cost_ins && cost_match < cost_del) { + cost[i*M+j] = cost_match; + transition[i*M+j] = match; + } else if(cost_ins < cost_del) { + cost[i*M+j] = cost_ins; + transition[i*M+j] = insert; + } else { + cost[i*M+j] = cost_del; + transition[i*M+j] = del; + } + } + } + + int total_cost = cost[(N-1)*M + (M-1)]; + if(total_cost < 500) { + printf("total cost = %d\n", cost[(N-1)*M + (M-1)]); + + //int b_pos = b.size()-1; + int a_pos = a.size()-1; + for(int i=(M-1); i >= 0; --i) { + if(a[a_pos] != b[i]) { + printf("- %s\n", a[a_pos].c_str()); + printf("+ %s\n", b[i].c_str()); + } + if(transition[i*M+a_pos] == match) { + //printf("R"); + a_pos -= 1; + } else if(transition[i*M+a_pos] == del) { + //printf("D"); + } else if(transition[i*M+a_pos] == insert) { + //printf("I"); + a_pos -= 2; + } + } + //printf("%d vs %d\n", N, M); + } +} + class PluginTest:public CxxTest::TestSuite { public: @@ -104,6 +193,8 @@ class PluginTest:public CxxTest::TestSuite TS_ASSERT_EQUALS((int)(fdata.length()+1), res); TS_ASSERT(fdata == result); + if(fdata != result) + print_string_differences(fdata, result); } diff --git a/src/Tests/SaveOSC.cpp b/src/Tests/SaveOSC.cpp @@ -0,0 +1,103 @@ +#include <cassert> +#include <thread> +#include <iostream> +#include <unistd.h> + +#include <cxxtest/TestSuite.h> + +#include "../Misc/Master.h" +#include "../Misc/MiddleWare.h" +#include "../UI/NSM.H" + +// for linking purposes only: +NSM_Client *nsm = 0; +zyn::MiddleWare *middleware = 0; + +char *instance_name=(char*)""; + +// Middleware is not required, since all ports requiring MiddleWare use the +// rNoWalk macro. If you still want to enable it, uncomment this: +// #define RUN_MIDDLEWARE + +class SaveOSCTest +{ + void setUp() { + synth = new zyn::SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + synth->alias(); + + mw = new zyn::MiddleWare(std::move(*synth), &config); + master = mw->spawnMaster(); + realtime = nullptr; + } + + void tearDown() { + delete mw; + delete synth; + } + + public: + SaveOSCTest() { setUp(); } + ~SaveOSCTest() { tearDown(); } + + int run(int argc, char** argv) + { + assert(argc == 2); + const char *filename = argv[1]; + + int tmp = master->loadXML(filename); + if(tmp < 0) { + std::cerr << "ERROR: Could not load master file " << filename + << "." << std::endl; + exit(1); + } + + assert(master); + return (master->saveOSC(NULL) == 0) ? 0 : 1; + } + + + void start_realtime(void) + { + do_exit = false; +#ifdef RUN_MIDDLEWARE + realtime = new std::thread([this](){ + while(!do_exit) + { + /*while(bToU->hasNext()) { + const char *rtmsg = bToU->read(); + bToUhandle(rtmsg); + }*/ + mw->tick(); + usleep(500); + }}); +#endif + } + void stop_realtime(void) + { + do_exit = true; +#ifdef RUN_MIDDLEWARE + realtime->join(); + delete realtime; + realtime = NULL; +#endif + } + + private: + zyn::Config config; + zyn::SYNTH_T* synth; + zyn::MiddleWare* mw; + zyn::Master* master; + std::thread* realtime; + bool do_exit; +}; + +int main(int argc, char** argv) +{ + SaveOSCTest test; + test.start_realtime(); + int res = test.run(argc, argv); + test.stop_realtime(); + return res; +} diff --git a/src/Tests/guitar-adnote.xmz b/src/Tests/guitar-adnote.xmz @@ -137,11 +137,11 @@ version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul"> <FILTER> <par name="category" value="0" /> <par name="type" value="2" /> -<par name="freq" value="70" /> -<par name="q" value="40" /> +<par_real name="basefreq" value="1383.91" exact_value="0x44ACFD1C" /> +<par_real name="baseq" value="1.08427" exact_value="0x3F8AC956" /> <par name="stages" value="0" /> -<par name="freq_track" value="64" /> -<par name="gain" value="64" /> +<par_real name="freq_tracking" value="0" exact_value="0x00000000" /> +<par_real name="gain" value="0" exact_value="0x00000000" /> </FILTER> <FILTER_ENVELOPE> <par_bool name="free_mode" value="no" /> @@ -309,11 +309,11 @@ version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul"> <FILTER> <par name="category" value="0" /> <par name="type" value="2" /> -<par name="freq" value="65" /> -<par name="q" value="68" /> +<par_real name="basefreq" value="1055.65" exact_value="0x4483F4A4" /> +<par_real name="baseq" value="6.34546" exact_value="0x40CB0DF9" /> <par name="stages" value="0" /> -<par name="freq_track" value="64" /> -<par name="gain" value="64" /> +<par_real name="freq_tracking" value="0" exact_value="0x00000000" /> +<par_real name="gain" value="0" exact_value="0x00000000" /> </FILTER> <par_bool name="filter_envelope_enabled" value="yes" /> <FILTER_ENVELOPE> @@ -1060,11 +1060,11 @@ version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul"> <FILTER> <par name="category" value="0" /> <par name="type" value="4" /> -<par name="freq" value="80" /> -<par name="q" value="40" /> +<par_real name="basefreq" value="2378.41" exact_value="0x4514A69F" /> +<par_real name="baseq" value="1.08427" exact_value="0x3F8AC956" /> <par name="stages" value="0" /> -<par name="freq_track" value="64" /> -<par name="gain" value="64" /> +<par_real name="freq_tracking" value="0" exact_value="0x00000000" /> +<par_real name="gain" value="0" exact_value="0x00000000" /> </FILTER> <par name="filter_velocity_sensing" value="64" /> <par name="filter_velocity_sensing_amplitude" value="64" /> @@ -3411,11 +3411,11 @@ version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul"> <FILTER> <par name="category" value="0" /> <par name="type" value="2" /> -<par name="freq" value="111" /> -<par name="q" value="95" /> +<par_real name="basefreq" value="12745.1" exact_value="0x4647248B" /> +<par_real name="baseq" value="46.8148" exact_value="0x423B4262" /> <par name="stages" value="0" /> -<par name="freq_track" value="64" /> -<par name="gain" value="64" /> +<par_real name="freq_tracking" value="0" exact_value="0x00000000" /> +<par_real name="gain" value="0" exact_value="0x00000000" /> </FILTER> <FILTER_ENVELOPE> <par_bool name="free_mode" value="no" /> diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -2,7 +2,7 @@ version 1.0302 header_name {.h} code_name {.cc} -decl {//Copyright (c) 2002-2009 Nasca Octavian Paul - (c) 2009-2016 Mark McCurry} {private local +decl {//Copyright (c) 2002-2009 Nasca Octavian Paul - (c) 2009-2017 Mark McCurry} {private local } decl {//License: GNU GPL version 2 or later} {private local diff --git a/src/main.cpp b/src/main.cpp @@ -215,13 +215,12 @@ int main(int argc, char *argv[]) { SYNTH_T synth; Config config; - config.init(); int noui = 0; cerr << "\nZynAddSubFX - Copyright (c) 2002-2013 Nasca Octavian Paul and others" << endl; cerr - << " Copyright (c) 2009-2016 Mark McCurry [active maintainer]" + << " Copyright (c) 2009-2017 Mark McCurry [active maintainer]" << endl; cerr << "Compiled: " << __DATE__ << " " << __TIME__ << endl; cerr << "This program is free software (GNU GPL v2 or later) and \n";