zynaddsubfx

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

commit 2a655e26a6eb8a2685cbc41edfebdf9dbab4347a
parent 6a1b57fc8af7d5f20275730ed1677b0611f0c22a
Author: Johannes Lorenz <johannes89@ist-einmalig.de>
Date:   Fri, 10 Jul 2015 20:07:50 +0200

Merge from Master (Release 2.5.1).

Diffstat:
MCMakeLists.txt | 2+-
MHISTORY.txt | 4++--
Msrc/Effects/EffectMgr.cpp | 37++++++++++++++++++++++++-------------
Msrc/Effects/EffectMgr.h | 4++--
Msrc/Misc/MiddleWare.cpp | 115++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/Misc/Util.cpp | 20++++++++++++++++++++
Msrc/Misc/Util.h | 3+++
Msrc/Misc/XMLwrapper.cpp | 2+-
Msrc/Output/DSSIaudiooutput.cpp | 7+++++++
Msrc/Params/EnvelopeParams.cpp | 4++++
Msrc/Tests/guitar-adnote.xmz | 2+-
Msrc/UI/ADnoteUI.fl | 14+++++++-------
Msrc/UI/BankView.cpp | 2+-
Msrc/UI/CMakeLists.txt | 1+
Msrc/UI/ConfigUI.fl | 28++++++++++++++++++++++------
Msrc/UI/EnvelopeFreeEdit.cpp | 9++++++---
Msrc/UI/EnvelopeUI.fl | 112++++++++++++++++++++++++++++++++++++++++---------------------------------------
Asrc/UI/Fl_Osc_Numeric_Input.H | 17+++++++++++++++++
Asrc/UI/Fl_Osc_Numeric_Input.cpp | 36++++++++++++++++++++++++++++++++++++
Msrc/UI/Fl_Osc_Output.H | 3+--
Msrc/UI/Fl_Osc_Output.cpp | 6+++---
Msrc/UI/Fl_Oscilloscope.h | 3+++
Msrc/UI/MasterUI.fl | 10++++++----
Msrc/UI/NioUI.cpp | 128++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/UI/NioUI.h | 8+++++---
Msrc/UI/Osc_DataModel.h | 4++--
Asrc/UI/Osc_IntModel.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/UI/OscilGenUI.fl | 8+++++++-
Msrc/UI/SUBnoteUI.fl | 31+++++++++++++++++++++++--------
Msrc/UI/guimain.cpp | 4+++-
Msrc/main.cpp | 18++++++++++++++++++
31 files changed, 510 insertions(+), 177 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") project(zynaddsubfx) -set(VERSION "2.5.0") +set(VERSION "2.5.1") #Include RTOSC diff --git a/HISTORY.txt b/HISTORY.txt @@ -1,10 +1,10 @@ -2.5.1 (25 May 2015) +2.5.1 (4 July 2015) - Add Colorized CMake Configuration - Add PID option for jack - Add OSC port option - Add MIDI unlearn - Add External UI Compilation - - Add Split Pitchblend + - Add Split Pitchbend - Fix No Install NTK Build - Fix Linker Issues - Fix Presets/Copy/Paste diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -45,7 +45,7 @@ static const rtosc::Ports local_ports = { rSelf(EffectMgr), rPaste, rRecurp(filterpars, "Filter Parameter for Dynamic Filter"), - {"parameter#64::i", rProp(alias) rDoc("Parameter Accessor"), NULL, + {"parameter#128::i", rProp(alias) rDoc("Parameter Accessor"), NULL, [](const char *msg, rtosc::RtData &d) { EffectMgr *eff = (EffectMgr*)d.obj; @@ -54,8 +54,10 @@ static const rtosc::Ports local_ports = { if(!rtosc_narguments(msg)) d.reply(d.loc, "i", eff->geteffectparrt(atoi(mm))); - else + else { eff->seteffectparrt(atoi(mm), rtosc_argument(msg, 0).i); + d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm))); + } }}, {"preset::i", rProp(alias) rDoc("Effect Preset Selector"), NULL, [](const char *msg, rtosc::RtData &d) @@ -63,8 +65,10 @@ static const rtosc::Ports local_ports = { EffectMgr *eff = (EffectMgr*)d.obj; if(!rtosc_narguments(msg)) d.reply(d.loc, "i", eff->getpreset()); - else + else { eff->changepresetrt(rtosc_argument(msg, 0).i); + d.broadcast(d.loc, "i", eff->getpreset()); + } }}, {"eq-coeffs:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL, [](const char *, rtosc::RtData &d) @@ -83,9 +87,10 @@ static const rtosc::Ports local_ports = { {"efftype::i", rDoc("Get Effect Type"), NULL, [](const char *m, rtosc::RtData &d) { EffectMgr *eff = (EffectMgr*)d.obj; - if(rtosc_narguments(m)) + if(rtosc_narguments(m)) { eff->changeeffectrt(rtosc_argument(m,0).i); - else + d.broadcast(d.loc, "i", eff->nefx); + } else d.reply(d.loc, "i", eff->nefx); }}, {"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL, @@ -143,7 +148,7 @@ void EffectMgr::defaults(void) } //Change the effect -void EffectMgr::changeeffectrt(int _nefx) +void EffectMgr::changeeffectrt(int _nefx, bool avoidSmash) { cleanup(); if(nefx == _nefx && efx != NULL) @@ -187,6 +192,10 @@ void EffectMgr::changeeffectrt(int _nefx) if(efx) filterpars = efx->filterpars; + + if(!avoidSmash) + for(int i=0; i<128; ++i) + settings[i] = geteffectparrt(i); } void EffectMgr::changeeffect(int _nefx) @@ -205,8 +214,8 @@ int EffectMgr::geteffect(void) // Initialize An Effect in RT context void EffectMgr::init(void) { - changeeffectrt(nefx); - changepresetrt(preset); + changeeffectrt(nefx, true); + changepresetrt(preset, true); for(int i=0; i<128; ++i) seteffectparrt(i, settings[i]); } @@ -242,11 +251,14 @@ void EffectMgr::changepreset(unsigned char npreset) } // Change the preset of the current effect -void EffectMgr::changepresetrt(unsigned char npreset) +void EffectMgr::changepresetrt(unsigned char npreset, bool avoidSmash) { preset = npreset; if(efx) efx->setpreset(npreset); + if(!avoidSmash) + for(int i=0; i<128; ++i) + settings[i] = geteffectparrt(i); } //Change a parameter of the current effect @@ -370,11 +382,10 @@ void EffectMgr::setdryonly(bool value) void EffectMgr::paste(EffectMgr &e) { - changeeffectrt(e.nefx); - changepresetrt(e.preset); - for(int i=0;i<128;++i){ + changeeffectrt(e.nefx, true); + changepresetrt(e.preset, true); + for(int i=0;i<128;++i) seteffectparrt(e.settings[i], i); - } } void EffectMgr::add2XML(XMLwrapper *xml) diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -55,11 +55,11 @@ class EffectMgr:public Presets void kill(void) REALTIME; void cleanup(void) REALTIME; - void changeeffectrt(int nefx_) REALTIME; + void changeeffectrt(int nefx_, bool avoidSmash=false) REALTIME; void changeeffect(int nefx_) NONREALTIME; int geteffect(void); void changepreset(unsigned char npreset) NONREALTIME; - void changepresetrt(unsigned char npreset) REALTIME; + void changepresetrt(unsigned char npreset, bool avoidSmash=false) REALTIME; unsigned char getpreset(void); void seteffectpar(int npar, unsigned char value) NONREALTIME; void seteffectparrt(int npar, unsigned char value) REALTIME; diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -8,6 +8,7 @@ #include <rtosc/undo-history.h> #include <rtosc/thread-link.h> #include <rtosc/ports.h> +#include <rtosc/typed-message.h> #include <lo/lo.h> #include <unistd.h> @@ -28,6 +29,7 @@ #include "../Params/PADnoteParameters.h" #include "../DSP/FFTwrapper.h" #include "../Synth/OscilGen.h" +#include "../Nio/Nio.h" #include <string> #include <future> @@ -196,7 +198,7 @@ void preparePadSynth(string path, PADnoteParameters *p, rtosc::ThreadLink *uToB) * - Load Bank * * - Refresh List of Banks * *****************************************************************************/ -void refreshBankView(const Bank &bank, unsigned loc, Fl_Osc_Interface *osc) +void refreshBankView(const Bank &bank, unsigned loc, std::function<void(const char*)> cb) { if(loc >= BANK_SIZE) return; @@ -208,15 +210,12 @@ void refreshBankView(const Bank &bank, unsigned loc, Fl_Osc_Interface *osc) errx(1, "Failure to handle bank update properly..."); - if (osc) - osc->tryLink(response); + if(cb) + cb(response); } -void bankList(Bank &bank, Fl_Osc_Interface *osc) +void bankList(Bank &bank, std::function<void(const char*)> cb) { - if (! osc) - return; - char response[2048]; int i = 0; @@ -224,35 +223,35 @@ void bankList(Bank &bank, Fl_Osc_Interface *osc) if(!rtosc_message(response, 2048, "/bank-list", "iss", i++, elm.name.c_str(), elm.dir.c_str())) errx(1, "Failure to handle bank update properly..."); - if (osc) - osc->tryLink(response); + if(cb) + cb(response); } } -void rescanForBanks(Bank &bank, Fl_Osc_Interface *osc) +void rescanForBanks(Bank &bank, std::function<void(const char*)> cb) { bank.rescanforbanks(); - bankList(bank, osc); + bankList(bank, cb); } -void loadBank(Bank &bank, int pos, Fl_Osc_Interface *osc) +void loadBank(Bank &bank, int pos, std::function<void(const char*)> cb) { if(bank.bankpos != pos) { bank.bankpos = pos; bank.loadbank(bank.banks[pos].dir); for(int i=0; i<BANK_SIZE; ++i) - refreshBankView(bank, i, osc); + refreshBankView(bank, i, cb); } } -void bankPos(Bank &bank, Fl_Osc_Interface *osc) +void bankPos(Bank &bank, std::function<void(const char *)> cb) { char response[2048]; if(!rtosc_message(response, 2048, "/loadbank", "i", bank.bankpos)) errx(1, "Failure to handle bank update properly..."); - if(osc) - osc->tryLink(response); + if(cb) + cb(response); } /***************************************************************************** @@ -348,14 +347,14 @@ struct NonRtObjStore { std::string base = "/part"+to_s(i)+"/kit"+to_s(j)+"/"; for(int k=0; k<NUM_VOICES; ++k) { - std::string nbase = base+"adpars/voice"+to_s(k)+"/"; + std::string nbase = base+"adpars/VoicePar"+to_s(k)+"/"; if(adpars) { auto &nobj = adpars->VoicePar[k]; - objmap[nbase+"oscil/"] = nobj.OscilSmp; - objmap[nbase+"mod-oscil/"] = nobj.FMSmp; + objmap[nbase+"OscilSmp/"] = nobj.OscilSmp; + objmap[nbase+"FMSmp/"] = nobj.FMSmp; } else { - objmap[nbase+"oscil/"] = nullptr; - objmap[nbase+"mod-oscil/"] = nullptr; + objmap[nbase+"OscilSmp/"] = nullptr; + objmap[nbase+"FMSmp/"] = nullptr; } } } @@ -366,10 +365,10 @@ struct NonRtObjStore for(int k=0; k<NUM_VOICES; ++k) { if(padpars) { objmap[base+"padpars/"] = padpars; - objmap[base+"padpars/oscil/"] = padpars->oscilgen; + objmap[base+"padpars/oscilgen/"] = padpars->oscilgen; } else { objmap[base+"padpars/"] = nullptr; - objmap[base+"padpars/oscil/"] = nullptr; + objmap[base+"padpars/oscilgen/"] = nullptr; } } } @@ -427,6 +426,38 @@ struct ParamStore PADnoteParameters *pad[NUM_MIDI_PARTS][NUM_KIT_ITEMS]; }; +//XXX perhaps move this to Nio +//(there needs to be some standard Nio stub file for this sort of stuff) +namespace Nio +{ + using std::get; + using rtosc::rtMsg; + rtosc::Ports ports = { + {"sink-list:", 0, 0, [](const char *msg, rtosc::RtData &d) { + auto list = Nio::getSinks(); + char *ret = rtosc_splat(d.loc, list); + d.reply(ret); + delete [] ret; + }}, + {"source-list:", 0, 0, [](const char *msg, rtosc::RtData &d) { + auto list = Nio::getSources(); + char *ret = rtosc_splat(d.loc, list); + d.reply(ret); + delete [] ret; + }}, + {"source::s", 0, 0, [](const char *msg, rtosc::RtData &d) { + if(rtosc_narguments(msg) == 0) + d.reply(d.loc, "s", Nio::getSource().c_str()); + else if(rtMsg<const char*> m{msg}) + Nio::setSource(get<0>(m));}}, + {"sink::s", 0, 0, [](const char *msg, rtosc::RtData &d) { + if(rtosc_narguments(msg) == 0) + d.reply(d.loc, "s", Nio::getSink().c_str()); + else if(rtMsg<const char*> m{msg}) + Nio::setSink(get<0>(m));}}, + }; +} + /* Implementation */ class MiddleWareImpl { @@ -787,6 +818,22 @@ public: } } + void handleIo(const char *msg) + { + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + DummyDataObj d(buffer, 1024, (void*)&config, this, uToB); + strcpy(buffer, "/io/"); + + Nio::ports.dispatch(msg+4, d); + if(!d.matches) { + fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); + fprintf(stderr, "Unknown location '%s'<%s>\n", + msg, rtosc_argument_string(msg)); + fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); + } + } + void handleConfig(const char *msg) { char buffer[1024]; @@ -1181,8 +1228,8 @@ void MiddleWareImpl::kitEnable(int part, int kit, int type) */ void MiddleWareImpl::handleMsg(const char *msg) { - assert(!strstr(msg,"free")); assert(msg && *msg && rindex(msg, '/')[1]); + assert(strstr(msg,"free") == NULL || strstr(rtosc_argument_string(msg), "b") == NULL); assert(strcmp(msg, "/part0/Psysefxvol")); assert(strcmp(msg, "/Penabled")); assert(strcmp(msg, "part0/part0/Ppanning")); @@ -1203,16 +1250,22 @@ void MiddleWareImpl::handleMsg(const char *msg) int npart = -1; char testchr = 0; + std::function<void(const char*)> bank_cb; + if(last_url == "GUI") + bank_cb = [this](const char *msg){if(osc)osc->tryLink(msg);}; + else + bank_cb = [this](const char *msg){this->bToUhandle(msg, 1);}; + if(!strcmp(msg, "/refresh_bank") && !strcmp(rtosc_argument_string(msg), "i")) { - refreshBankView(master->bank, rtosc_argument(msg,0).i, osc); + refreshBankView(master->bank, rtosc_argument(msg,0).i, bank_cb); } else if(!strcmp(msg, "/bank-list") && !strcmp(rtosc_argument_string(msg), "")) { - bankList(master->bank, osc); + bankList(master->bank, bank_cb); } else if(!strcmp(msg, "/rescanforbanks") && !strcmp(rtosc_argument_string(msg), "")) { - rescanForBanks(master->bank, osc); + rescanForBanks(master->bank, bank_cb); } else if(!strcmp(msg, "/loadbank") && !strcmp(rtosc_argument_string(msg), "i")) { - loadBank(master->bank, rtosc_argument(msg, 0).i, osc); + loadBank(master->bank, rtosc_argument(msg, 0).i, bank_cb); } else if(!strcmp(msg, "/loadbank") && !strcmp(rtosc_argument_string(msg), "")) { - bankPos(master->bank, osc); + bankPos(master->bank, bank_cb); } else if(obj_store.has(obj_rl)) { //try some over simplified pattern matching if(strstr(msg, "oscilgen/") || strstr(msg, "FMSmp/") || strstr(msg, "OscilSmp/")) { @@ -1257,6 +1310,8 @@ void MiddleWareImpl::handleMsg(const char *msg) handleConfig(msg); } else if(strstr(msg, "/presets/")) { handlePresets(msg); + } else if(strstr(msg, "/io/")) { + handleIo(msg); } else if(strstr(msg, "Padenabled") || strstr(msg, "Ppadenabled") || strstr(msg, "Psubenabled")) { kitEnable(msg); uToB->raw_write(msg); @@ -1382,7 +1437,7 @@ void MiddleWare::activeUrl(std::string u) { impl->last_url = u; } - + const SYNTH_T &MiddleWare::getSynth(void) const { return impl->synth; diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp @@ -42,6 +42,8 @@ #include <err.h> #endif +#include <rtosc/rtosc.h> + prng_t prng_state = 0x1234; /* @@ -210,3 +212,21 @@ float cinterpolate(const float *data, size_t len, float pos) const float leftness = pos - l_pos; return data[l_pos] * leftness + data[r_pos] * (1.0f - leftness); } + +char *rtosc_splat(const char *path, std::set<std::string> v) +{ + char argT[v.size()+1]; + rtosc_arg_t arg[v.size()]; + unsigned i=0; + for(auto vv : v) { + argT[i] = 's'; + arg[i].s = vv.c_str(); + i++; + } + argT[v.size()] = 0; + + size_t len = rtosc_amessage(0, 0, path, argT, arg); + char *buf = new char[len]; + rtosc_amessage(buf, len, path, argT, arg); + return buf; +} diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -27,6 +27,7 @@ #include <sstream> #include <stdint.h> #include <algorithm> +#include <set> using std::min; using std::max; @@ -146,6 +147,8 @@ static inline void nullify(T &t) {delete t; t = NULL; } template<class T> static inline void arrayNullify(T &t) {delete [] t; t = NULL; } +char *rtosc_splat(const char *path, std::set<std::string>); + /** * Port macros - these produce easy and regular port definitions for common * types diff --git a/src/Misc/XMLwrapper.cpp b/src/Misc/XMLwrapper.cpp @@ -98,7 +98,7 @@ XMLwrapper::XMLwrapper() { version.Major = 2; version.Minor = 5; - version.Revision = 0; + version.Revision = 1; minimal = true; diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -37,6 +37,7 @@ #include <string.h> #include <limits.h> +using std::set; using std::string; using std::vector; @@ -51,6 +52,12 @@ namespace Nio { void waveStart(void){} void waveStop(void){} void waveEnd(void){} + bool setSource(string){return true;} + bool setSink(string){return true;} + set<string> getSources(void){return set<string>();} + set<string> getSinks(void){return set<string>();} + string getSource(void){return "";} + string getSink(void){return "";} } // diff --git a/src/Params/EnvelopeParams.cpp b/src/Params/EnvelopeParams.cpp @@ -34,7 +34,11 @@ using namespace rtosc; static const rtosc::Ports localPorts = { rSelf(EnvelopeParams), rPaste, +#undef rChangeCb +#define rChangeCb if(!obj->Pfreemode) obj->converttofree(); rToggle(Pfreemode, "Complex Envelope Definitions"), +#undef rChangeCb +#define rChangeCb rParamZyn(Penvpoints, rProp(internal), "Number of points in complex definition"), rParamZyn(Penvsustain, rProp(internal), "Location of the sustain point"), rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"), diff --git a/src/Tests/guitar-adnote.xmz b/src/Tests/guitar-adnote.xmz @@ -2,7 +2,7 @@ <?xml version="1.0f" encoding="UTF-8"?> <!DOCTYPE ZynAddSubFX-data> <ZynAddSubFX-data version-major="2" version-minor="5" -version-revision="0" ZynAddSubFX-author="Nasca Octavian Paul"> +version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul"> <INFORMATION> <par_bool name="PADsynth_used" value="yes" /> </INFORMATION> diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.fl @@ -119,7 +119,7 @@ class ADvoicelistitem {open : {public Fl_Osc_Group} class Fl_Osc_Output } Fl_Slider voicedetune { - callback {//detunevalueoutput->do_callback();} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {315 5 185 20} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune",'i');} class Fl_Osc_Slider @@ -253,7 +253,7 @@ o->redraw();} class Fl_Osc_Counter } Fl_Slider {} { - callback {o->oscWrite("detunevalue");} + callback {fmdetunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {590 245 155 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PFMDetune", 'i');} class Fl_Osc_Slider @@ -266,7 +266,7 @@ o->redraw();} } Fl_Choice {} { label {Detune Type} - callback {fmdetunevalueoutput->do_callback();} open + callback {fmdetunevalueoutput->update();} open xywh {540 280 75 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("Default");o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->init("PFMDetuneType");} @@ -466,7 +466,7 @@ o->redraw();} class Fl_Osc_Counter } Fl_Slider {} { - callback {detunevalueoutput->do_callback();} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {58 287 392 13} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune", 'i');} class Fl_Osc_Slider @@ -493,7 +493,7 @@ o->redraw();} } Fl_Choice {} { label {Detune Type} - callback {detunevalueoutput->do_callback();} open + callback {detunevalueoutput->update();} open xywh {455 320 70 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("Default");o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->init("PDetuneType");} @@ -866,7 +866,7 @@ class ADnoteUI {open : {public PresetsUI_} class LFOUI } {} Fl_Slider detune { - callback {o->oscWrite("detunevalue");} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {60 300 385 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune", 'i');} class Fl_Osc_Slider @@ -879,7 +879,7 @@ class ADnoteUI {open : {public PresetsUI_} } Fl_Choice detunetype { label {Detune Type} - callback {o->oscWrite("detunevalue");} open + callback {detunevalueoutput->update();} open xywh {455 340 75 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->init("PDetuneType",1);} diff --git a/src/UI/BankView.cpp b/src/UI/BankView.cpp @@ -15,8 +15,8 @@ BankList::BankList(int x,int y, int w, int h, const char *label) void BankList::init(std::string path) { ext = path; + oscRegister("bank-list"); oscRegister(path.c_str()); - osc->createLink("/bank-list", this); } void BankList::OSC_raw(const char *msg) diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt @@ -67,6 +67,7 @@ add_library(zynaddsubfx_gui STATIC Fl_Osc_Output.cpp Fl_Osc_Counter.cpp Fl_Osc_Input.cpp + Fl_Osc_Numeric_Input.cpp Fl_Osc_Value.cpp Fl_Osc_ListView.cpp Fl_Resonance_Graph.cpp diff --git a/src/UI/ConfigUI.fl b/src/UI/ConfigUI.fl @@ -29,12 +29,18 @@ decl {\#include "Fl_Osc_Counter.H"} {public local decl {\#include "Fl_Osc_Choice.H"} {public local } +decl {\#include "Osc_IntModel.h"} {public local +} + decl {\#include "Fl_Osc_Check.H"} {public local } decl {\#include "Fl_Osc_Input.H"} {public local } +decl {\#include "Fl_Osc_Numeric_Input.H"} {public local +} + decl {\#include "Fl_Osc_ListView.H"} {public local } @@ -71,14 +77,14 @@ class ConfigUI {} { Fl_Input samplerateinput { xywh {115 50 60 20} type Int textfont 1 code0 {o->init("cfg.SampleRate");} - class Fl_Osc_Input + class Fl_Osc_Numeric_Input } } Fl_Input {} { label {Buffer Size} tooltip {Internal Sound Buffer Size (samples)} xywh {190 45 60 20} type Int labelsize 11 align 129 textfont 1 code0 {o->init("cfg.SoundBufferSize");} - class Fl_Osc_Input + class Fl_Osc_Numeric_Input } Fl_Check_Button {} { label {Swap Stereo } @@ -86,11 +92,12 @@ class ConfigUI {} { code0 {o->init("cfg.SwapStereo");} class Fl_Osc_Check } - Fl_Choice {} { + Fl_Choice oscilsize_widget { label OscilSize + callback{ + oscilsize->updateVal((int)(o->value()+7)); + } tooltip {ADSynth Oscillator Size (samples)} xywh {175 80 75 20} down_box BORDER_BOX labelfont 1 labelsize 11 textsize 10 - code0 {o->init("cfg.OscilPower");} - class Fl_Osc_Choice } { MenuItem {} { label 128 @@ -279,7 +286,14 @@ activatebutton_presetdir(true);} Function {ConfigUI(Fl_Osc_Interface *osc_)} {} { code { osc = osc_; - make_window();} {} + make_window(); + oscilsize = new Osc_IntModel(osc); + oscilsize->callback = [this](int i){ + oscilsize_widget->value(i-7); + }; + oscilsize->update("/config/cfg.OscilPower"); + + } {} } Function {activatebutton_rootdir(bool active)} {} { code {if (active) { @@ -308,4 +322,6 @@ activatebutton_presetdir(true);} } decl {class Fl_Osc_Interface *osc;} {public local } + decl {class Osc_IntModel *oscilsize;} {public local + } } diff --git a/src/UI/EnvelopeFreeEdit.cpp b/src/UI/EnvelopeFreeEdit.cpp @@ -26,7 +26,7 @@ void EnvelopeFreeEdit::init(void) void EnvelopeFreeEdit::OSC_raw(const char *msg) { const char *args = rtosc_argument_string(msg); - if(strstr(msg,"Penvpoints") && !strcmp(args, "c")) { + if(strstr(msg,"Penvpoints") && !strcmp(args, "i")) { Penvpoints = rtosc_argument(msg, 0).i; } else if(strstr(msg,"Penvdt") && !strcmp(args, "b")) { rtosc_blob_t b = rtosc_argument(msg, 0).b; @@ -36,7 +36,7 @@ void EnvelopeFreeEdit::OSC_raw(const char *msg) rtosc_blob_t b = rtosc_argument(msg, 0).b; assert(b.len == MAX_ENVELOPE_POINTS); memcpy(Penvval, b.data, MAX_ENVELOPE_POINTS); - } else if(strstr(msg,"Penvsustain") && !strcmp(args, "c")) { + } else if(strstr(msg,"Penvsustain") && !strcmp(args, "i")) { Penvsustain = rtosc_argument(msg, 0).i; } redraw(); @@ -202,7 +202,10 @@ int EnvelopeFreeEdit::handle(int event) else Penvdt[currentpoint]=0; - oscWrite(to_s("Penvdt")+to_s(currentpoint), "c", newdt); + oscWrite(to_s("Penvval")+to_s(currentpoint), "c", ny); + oscWrite(to_s("Penvdt")+to_s(currentpoint), "c", newdt); + oscWrite("Penvdt",""); + oscWrite("Penvval",""); redraw(); if(pair) diff --git a/src/UI/EnvelopeUI.fl b/src/UI/EnvelopeUI.fl @@ -126,11 +126,15 @@ sustaincounter->update(); } Fl_Check_Button freemodebutton { label FreeMode - callback {reinit(); + callback { + o->oscWrite("Pfreemode", o->value() ? "T" : "F"); + reinit(o->value()); freeedit->lastpoint=-1; freeedit->redraw();} tooltip {Enable or disable the freemode} xywh {10 155 95 20} labelsize 11 + code0{o->init("Pfreemode");} + class Fl_Osc_Check } Fl_Check_Button forcedreleasecheck { label frcR @@ -503,7 +507,6 @@ envfree->redraw();} base = base_; ext = ext_; Envmode = env_type; - Pfreemode = false; Penvsustain = false; Penvpoints = 3; Penvstretch = 0; @@ -537,59 +540,60 @@ refresh();} {} code {Fl_Osc_Group::rebase(new_base); freemodeeditwindow->rebase(new_base+ext);} {} } - Function {reinit()} {open + Function {reinit(bool Pfreemode)} {open } { - code {if(Pfreemode){ - int answer=fl_choice("Disable the free mode of the Envelope?","No","Yes",NULL); - freemodebutton->value(Pfreemode); - if (answer==0) - return; -}; - -Pfreemode = !Pfreemode; - -hide(); -const int winx=freemodeeditwindow->x(); -const int winy=freemodeeditwindow->y(); - -freemodeeditwindow->hide(); - -envwindow->hide(); -Fl_Group *par=envwindow->parent(); -par->hide(); - - -refresh(); -envwindow->show(); -par->redraw(); - -par->show(); -show(); -freemodeeditwindow->position(winx,winy); -freemodeeditwindow->show(); - -if (Pfreemode) { - freemodebutton->value(1); - addpoint->show(); - deletepoint->show(); - forcedreleasecheck->show(); - sustaincounter->show(); - envstretchdial->show(); -} else{ - freemodebutton->value(0); - addpoint->hide(); - deletepoint->hide(); - forcedreleasecheck->hide(); - sustaincounter->hide(); - envstretchdial->hide(); -}; + code { + //if(!Pfreemode){ + // int answer=fl_choice("Disable the free mode of the Envelope?","No","Yes",NULL); + // freemodebutton->value(Pfreemode); + // if (answer==0) + // return; + //}; + freeedit->update(); + + hide(); + const int winx=freemodeeditwindow->x(); + const int winy=freemodeeditwindow->y(); + + bool reshow = freemodeeditwindow->visible(); + freemodeeditwindow->hide(); + + envwindow->hide(); + Fl_Group *par=envwindow->parent(); + par->hide(); + + + refresh(); + envwindow->show(); + par->redraw(); + + par->show(); + show(); + freemodeeditwindow->position(winx,winy); + if(reshow) + freemodeeditwindow->show(); + + if (Pfreemode) { + freemodebutton->value(1); + addpoint->show(); + deletepoint->show(); + forcedreleasecheck->show(); + sustaincounter->show(); + envstretchdial->show(); + } else{ + freemodebutton->value(0); + addpoint->hide(); + deletepoint->hide(); + forcedreleasecheck->hide(); + sustaincounter->hide(); + envstretchdial->hide(); + }; } {selected } } Function {refresh()} {open } { - code {freemodebutton->value(Pfreemode); - + code { sustaincounter->value(Penvsustain); sustaincounter->maximum(Penvpoints-2); @@ -598,7 +602,7 @@ if (Pfreemode) { linearenvelopecheck->value(Plinearenvelope); //Conditionally display widgets - if(Pfreemode) { + if(freemodebutton->value()) { freemodebutton->value(1); addpoint->show(); deletepoint->show(); @@ -614,14 +618,14 @@ linearenvelopecheck->value(Plinearenvelope); envstretchdial->hide(); } - if(Pfreemode || Envmode>2) + if(freemodebutton->value() || Envmode>2) linearenvelopecheck->hide(); else linearenvelopecheck->show(); forcedreleasecheck->value(Pforcedrelease); -if (Pfreemode==0){ +if (freemodebutton->value()==0){ addpoint->hide(); deletepoint->hide(); } else { @@ -635,7 +639,7 @@ envADSRfilter->hide(); envASRbw->hide(); envfree->hide(); -if (Pfreemode==0){ +if (freemodebutton->value()==0){ switch(Envmode){ case 1: case 2: @@ -664,8 +668,6 @@ envwindow->show();} {} } decl {int Envmode;} {private local } - decl {int Pfreemode;} {private local - } decl {int Penvsustain;} {private local } decl {int Penvpoints;} {private local diff --git a/src/UI/Fl_Osc_Numeric_Input.H b/src/UI/Fl_Osc_Numeric_Input.H @@ -0,0 +1,17 @@ +#pragma once +#include <FL/Fl_Input.H> +#include "Fl_Osc_Widget.H" + +class Fl_Osc_Numeric_Input: public Fl_Input, public Fl_Osc_Widget +{ + public: + Fl_Osc_Numeric_Input(int X, int Y, int W, int H, const char *label = NULL); + virtual ~Fl_Osc_Numeric_Input(void); + + //Normal Initialization + void init(const char *path); + + virtual void OSC_value(int i) override; + virtual void OSC_value(float f) override; + static void numeric_callback(Fl_Widget *w); +}; diff --git a/src/UI/Fl_Osc_Numeric_Input.cpp b/src/UI/Fl_Osc_Numeric_Input.cpp @@ -0,0 +1,36 @@ +#include "Fl_Osc_Numeric_Input.H" + +Fl_Osc_Numeric_Input::Fl_Osc_Numeric_Input(int X, int Y, int W, int H, const char *label) + :Fl_Input(X,Y,W,H, label), Fl_Osc_Widget(this) +{ + callback(numeric_callback); +} + +Fl_Osc_Numeric_Input::~Fl_Osc_Numeric_Input(void) +{} + +void Fl_Osc_Numeric_Input::init(const char *path) +{ + ext = path; + oscRegister(path); +} + +void Fl_Osc_Numeric_Input::OSC_value(float f) +{ + OSC_value((int)f); +} + +void Fl_Osc_Numeric_Input::OSC_value(int i) +{ + char buf[128]; + snprintf(buf, 128, "%d", i); + value(buf); +} + +void Fl_Osc_Numeric_Input::numeric_callback(Fl_Widget *w) +{ + auto &ww = *(Fl_Osc_Numeric_Input *)w; + int x = atoi(ww.value()); + if(x) + ww.oscWrite(ww.ext, "i", x); +} diff --git a/src/UI/Fl_Osc_Output.H b/src/UI/Fl_Osc_Output.H @@ -2,7 +2,7 @@ #include <FL/Fl_Value_Output.H> #include "Fl_Osc_Widget.H" -class Fl_Osc_Output:public Fl_Value_Output, Fl_Osc_Widget +class Fl_Osc_Output:public Fl_Value_Output, public Fl_Osc_Widget { public: Fl_Osc_Output(int x, int y, int w, int h, const char *label = NULL); @@ -19,6 +19,5 @@ class Fl_Osc_Output:public Fl_Value_Output, Fl_Osc_Widget void cb(void); private: float newvalue_; - std::string name; std::pair<Fl_Callback*, void*> cb_data; }; diff --git a/src/UI/Fl_Osc_Output.cpp b/src/UI/Fl_Osc_Output.cpp @@ -19,7 +19,7 @@ Fl_Osc_Output::Fl_Osc_Output(int X, int Y, int W, int H, const char *label) void Fl_Osc_Output::init(const char *path) { - name = path; + ext = path; oscRegister(path); }; @@ -51,7 +51,7 @@ void Fl_Osc_Output::OSC_value(float v) void Fl_Osc_Output::update(void) { - oscWrite(name); + oscWrite(ext); } float Fl_Osc_Output::newvalue(void) const @@ -61,5 +61,5 @@ float Fl_Osc_Output::newvalue(void) const void Fl_Osc_Output::cb(void) { - oscWrite(name); + oscWrite(ext); } diff --git a/src/UI/Fl_Oscilloscope.h b/src/UI/Fl_Oscilloscope.h @@ -54,6 +54,9 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget virtual void OSC_value(unsigned N, void *data) override { + if(oscilsize == 0) + OSC_value((int)N/4); + assert(N==(unsigned)(oscilsize*4)); memcpy(smps, data, N); diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -17,7 +17,9 @@ decl {\#include <stdio.h>} {public local decl {\#include <string.h>} {public local } -decl {\#include "zynaddsubfx.xpm"} {private local +decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) +\#include "zynaddsubfx.xpm" +\#endif} {public local } decl {\#include "WidgetPDial.h"} {public local @@ -74,7 +76,7 @@ extern NSM_Client *nsm; \#endif} {public local } -decl {\#if __linux__ +decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) \#include <X11/xpm.h> \#endif} {public local } @@ -1480,7 +1482,7 @@ masterwindowlabel[99]='\\0'; masterwindow->label(&masterwindowlabel[0]); simplemasterwindow->label(&masterwindowlabel[0]);} {} } - Function {MasterUI(int *exitprogram_, class Fl_Osc_Interface *osc_)} {open + Function {MasterUI(int *exitprogram_, class Fl_Osc_Interface *osc_):nioui(osc_)} {open } { code {exitprogram=exitprogram_; osc=osc_; @@ -1500,7 +1502,7 @@ configui=new ConfigUI(osc); make_window(); fl_open_display(); -\#ifdef __linux__ +\#if defined(__linux__) && ! defined(PLUGINVERSION) Pixmap p, mask; XCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), (char**)zynaddsubfx_xpm, &p, &mask, NULL); diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp @@ -10,49 +10,110 @@ #include <FL/Fl_Tabs.H> #include <FL/Fl_Group.H> #include <FL/Fl_Text_Display.H> +#include "Osc_SimpleListModel.h" using namespace std; -NioUI::NioUI() +static void callback_fn_choice_nio(Fl_Widget *w, void *); +class Fl_Osc_StrChoice:public Fl_Choice, public Fl_Osc_Widget +{ + public: + Fl_Osc_StrChoice(int X, int Y, int W, int H, const char *label = NULL) + :Fl_Choice(X,Y,W,H, label), Fl_Osc_Widget(this), cb_data(NULL, NULL) + { + Fl_Choice::callback(callback_fn_choice_nio, NULL); + } + + virtual ~Fl_Osc_StrChoice(void) {}; + void init(std::string path_) + { + ext = path_; + Fl_Osc_Pane *pane = fetch_osc_pane(this); + assert(pane); + assert(pane->osc); + osc = pane->osc; + oscRegister(path_.c_str()); + }; + + + void OSC_value(const char *S) override + { + for(int i=0; i<size()-1; ++i) { + printf("size = %d, i=%d, text='%s'\n", size(), i, text(i)); + if(!strcmp(S, text(i))) + value(i); + } + } + + //Refetch parameter information + void update(void) + { + assert(osc); + oscWrite(ext); + } + void callback(Fl_Callback *cb, void *p = NULL) + { + cb_data.first = cb; + cb_data.second = p; + } + + void cb(void) + { + assert(osc); + if(text(value())) + oscWrite(ext, "s", text(value())); + if(cb_data.first) + cb_data.first(this, cb_data.second); + } + private: + int min; + std::pair<Fl_Callback*, void*> cb_data; +}; +static void callback_fn_choice_nio(Fl_Widget *w, void *) +{ + ((Fl_Osc_StrChoice*)w)->cb(); +} + +NioUI::NioUI(Fl_Osc_Interface *osc) :Fl_Window(200, 100, 400, 400, "New IO Controls") { //hm, I appear to be leaking memory - Fl_Group *settings = new Fl_Group(0, 20, 400, 400 - 35, "Settings"); + Fl_Osc_Group *settings = new Fl_Osc_Group(0, 20, 400, 400 - 35, "Settings"); { - audio = new Fl_Choice(60, 80, 100, 25, "Audio"); - audio->callback(audioCallback); - midi = new Fl_Choice(60, 100, 100, 25, "Midi"); - midi->callback(midiCallback); + settings->osc = osc; + audio = new Fl_Osc_StrChoice(60, 80, 100, 25, "Audio"); + //audio->callback(audioCallback); + audio->init("/io/sink"); + midi = new Fl_Osc_StrChoice(60, 100, 100, 25, "Midi"); + //midi->callback(midiCallback); + midi->init("/io/source"); } settings->end(); + //Get options + midi_opt = new Osc_SimpleListModel(osc); + audio_opt = new Osc_SimpleListModel(osc); + + using list_t = Osc_SimpleListModel::list_t; + //initialize midi list - { - //set<string> midiList = Nio::getSources(); - //string source = Nio::getSource(); - //int midival = 0; - //for(set<string>::iterator itr = midiList.begin(); - // itr != midiList.end(); ++itr) { - // midi->add(itr->c_str()); - // if(*itr == source) - // midival = midi->size() - 2; - //} - //midi->value(midival); - } + midi_opt->callback = [this](list_t list) { + printf("midi list updating...\n"); + midi->clear(); + for(auto io:list) + midi->add(io.c_str()); + }; //initialize audio list - { - //set<string> audioList = Nio::getSinks(); - //string sink = Nio::getSink(); - //int audioval = 0; - //for(set<string>::iterator itr = audioList.begin(); - // itr != audioList.end(); ++itr) { - // audio->add(itr->c_str()); - // if(*itr == sink) - // audioval = audio->size() - 2; - //} - //audio->value(audioval); - } + audio_opt->callback = [this](list_t list) { + audio->clear(); + for(auto io:list) + audio->add(io.c_str()); + }; + + midi_opt->update("/io/source-list"); + audio_opt->update("/io/sink-list"); + resizable(this); size_range(400, 300); } @@ -61,7 +122,12 @@ NioUI::~NioUI() {} void NioUI::refresh() -{} +{ + midi_opt->update("/io/source-list"); + audio_opt->update("/io/sink-list"); + midi->update(); + audio->update(); +} void NioUI::midiCallback(Fl_Widget *c) { diff --git a/src/UI/NioUI.h b/src/UI/NioUI.h @@ -7,12 +7,14 @@ class NioUI:public Fl_Window { public: - NioUI(); + NioUI(class Fl_Osc_Interface*); ~NioUI(); void refresh(); private: - class Fl_Choice * midi; - class Fl_Choice * audio; + class Fl_Osc_StrChoice * midi; + class Fl_Osc_StrChoice * audio; + class Osc_SimpleListModel * midi_opt; + class Osc_SimpleListModel * audio_opt; static void midiCallback(Fl_Widget *c); static void audioCallback(Fl_Widget *c); }; diff --git a/src/UI/Osc_DataModel.h b/src/UI/Osc_DataModel.h @@ -1,3 +1,4 @@ +#pragma once #include "Fl_Osc_Widget.H" #include <functional> #include <vector> @@ -7,7 +8,7 @@ class Osc_DataModel:public Fl_Osc_Widget { public: Osc_DataModel(Fl_Osc_Interface *osc_) - :Fl_Osc_Widget("", osc_), list_size(0) + :Fl_Osc_Widget("", osc_) { assert(osc); } @@ -15,7 +16,6 @@ class Osc_DataModel:public Fl_Osc_Widget typedef std::string value_t; value_t value; std::function<void(value_t)> callback; - unsigned list_size; void update(std::string url) { diff --git a/src/UI/Osc_IntModel.h b/src/UI/Osc_IntModel.h @@ -0,0 +1,45 @@ +#pragma once +#include "Fl_Osc_Widget.H" +#include <functional> +#include <vector> +#include <rtosc/rtosc.h> + +class Osc_IntModel:public Fl_Osc_Widget +{ + public: + Osc_IntModel(Fl_Osc_Interface *osc_) + :Fl_Osc_Widget("", osc_), value(0) + { + assert(osc); + } + + typedef int value_t; + value_t value; + std::function<void(value_t)> callback; + + void updateVal(value_t v) + { + value = v; + oscWrite(ext, "i", v); + } + + void update(std::string url) + { + if(!ext.empty()) + osc->removeLink(this); + ext = url; + + oscRegister(ext.c_str()); + } + + //Raw messages + virtual void OSC_raw(const char *msg) + { + std::string args = rtosc_argument_string(msg); + if(args == "i") { + value = rtosc_argument(msg, 0).i; + if(callback) + callback(value); + } + } +}; diff --git a/src/UI/OscilGenUI.fl b/src/UI/OscilGenUI.fl @@ -119,7 +119,7 @@ class Oscilharmonic {: {public Fl_Group} Fl_Slider mag { callback {int x=64; if (Fl::event_button3()) o->value(x); - else x=127-(int)o->value(); + else x=128-(int)o->value(); if (x==64) o->selection_color(0); else o->selection_color(222); @@ -496,12 +496,15 @@ redrawoscil();} if (autoclearbutton->value()){ for (int i=0;i<MAX_AD_HARMONICS;i++){ h[i]->mag->value(64); + h[i]->mag->do_callback(); h[i]->phase->value(64); + h[i]->phase->do_callback(); }; harmonicshiftcounter->value(0); h[0]->mag->value(0); + h[0]->mag->do_callback(); wshbutton->value(0); wshbutton->do_callback(); fltbutton->value(0); @@ -527,9 +530,12 @@ redrawoscil();} for (int i=0;i<MAX_AD_HARMONICS;i++){ h[i]->mag->value(64); + h[i]->mag->do_callback(); h[i]->phase->value(64); + h[i]->phase->do_callback(); }; h[0]->mag->value(0); +h[0]->mag->do_callback(); //for (int i=0;i<MAX_AD_HARMONICS;i++){ // if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0); diff --git a/src/UI/SUBnoteUI.fl b/src/UI/SUBnoteUI.fl @@ -52,6 +52,20 @@ class PPSlider {: {public Fl_Slider, public Fl_Osc_Widget} } { code {int X=x(),Y=y(),W=w(),H=h(); +// catch any (un)learn event first +{ + bool middle_mouse = (event == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift()); + bool ctl_click = (event == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl()); + bool shift_middle = (event == FL_PUSH && Fl::event_state(FL_BUTTON2) && Fl::event_shift()); + if(middle_mouse || ctl_click) { + osc->write("/learn", "s", (loc+ext).c_str()); + return 1; + } else if(shift_middle) { + osc->write("/unlearn", "s", (loc+ext).c_str()); + return 1; + } +} + if ((!Fl::event_buttons())|| (event==0)||(Fl::event_shift()==0)) return(Fl_Slider::handle(event)); if (!Fl::event_inside(X,Y,W,H)) { @@ -100,7 +114,7 @@ class SUBnoteharmonic {: {public Fl_Osc_Group} int x=0; if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); else o->value(127-x); - o->osc->writeValue(o->loc + "Phmag" + to_s(n), (char) x); + o->osc->writeValue(o->loc + o->ext, (char) x); if (x==0) o->selection_color(0); else o->selection_color(222);} tooltip {harmonic's magnitude} xywh {0 15 10 135} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 127 @@ -110,7 +124,7 @@ if (x==0) o->selection_color(0); callback {int x=64; if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); else o->value(x); - o->osc->writeValue(o->loc+"Phrelbw"+to_s(n), (char) x);} + o->osc->writeValue(o->loc + o->ext, (char) x)}; tooltip {harmonic's bandwidth} xywh {0 157 10 130} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 class PPSlider } @@ -137,17 +151,18 @@ if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); code {n=n_; make_window(); harmonic->show(); - -osc->createLink(base+"Phmag"+to_s(n), mag); -osc->createLink(base+"Phrelbw"+to_s(n), bw); -osc->requestValue(base+"Phmag"+to_s(n)); +mag->ext = "Phmag" + to_s(n); +mag->oscRegister(mag->ext.c_str()); +bw->ext = "Phrelbw" + to_s(n); +bw->oscRegister(bw->ext.c_str()); osc->requestValue(base+"Phrelbw"+to_s(n)); end();} {} } Function {refresh()} {} { - code {osc->requestValue(base+"Phmag"+to_s(n)); -osc->requestValue(base+"Phrelbw"+to_s(n));} {} + code {// request values for the widgets +mag->oscWrite(mag->ext); +bw->oscWrite(bw->ext);} {} } Function {~SUBnoteharmonic()} {} { code {harmonic->hide(); diff --git a/src/UI/guimain.cpp b/src/UI/guimain.cpp @@ -328,13 +328,15 @@ class UI_Interface:public Fl_Osc_Interface void write(string s, const char *args, ...) override { + char buffer[4096]; va_list va; va_start(va, args); + rtosc_vmessage(buffer, sizeof(buffer), s.c_str(), args, va); //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40); ////fprintf(stderr, "."); //fprintf(stderr, "write(%s:%s)\n", s.c_str(), args); //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); - transmitMsg(s.c_str(), args, va); + transmitMsg(buffer); va_end(va); } diff --git a/src/main.cpp b/src/main.cpp @@ -424,11 +424,29 @@ int main(int argc, char *argv[]) gui = NULL; + + //Capture Startup Responses + typedef std::vector<const char *> wait_t; + wait_t msg_waitlist; + middleware->setUiCallback([](void*v,const char*msg) { + wait_t &wait = *(wait_t*)v; + size_t len = rtosc_message_length(msg, -1); + char *copy = new char[len]; + memcpy(copy, msg, len); + wait.push_back(copy); + }, &msg_waitlist); + if(!noui) gui = GUI::createUi(middleware->spawnUiApi(), &Pexitprogram); middleware->setUiCallback(GUI::raiseUi, gui); middleware->setIdleCallback([](void*){GUI::tickUi(gui);}, NULL); + //Replay Startup Responses + for(auto msg:msg_waitlist) { + GUI::raiseUi(gui, msg); + delete [] msg; + } + if(!noui) { GUI::raiseUi(gui, "/show", "i", config.cfg.UserInterfaceMode);