zynaddsubfx

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

commit 229a227cbf2a8ac4c243c2c10a5dfdc00ce70bb9
parent 51591b3286dd2cb492979829c7f376e674763220
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Fri, 20 May 2016 11:09:11 -0400

Get Watchpoints Practically Working

Diffstat:
Msrc/Misc/Master.cpp | 29++++++++++++++++++++++-------
Msrc/Misc/Part.cpp | 4++--
Msrc/Params/LFOParams.cpp | 15+++++++++++++++
Msrc/Synth/ADnote.cpp | 6+++---
Msrc/Synth/LFO.cpp | 7+++----
Msrc/Synth/LFO.h | 3+--
Msrc/Synth/WatchPoint.cpp | 49++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/Synth/WatchPoint.h | 44++++++++++++++++++++++----------------------
Msrc/UI/Connection.cpp | 2+-
9 files changed, 113 insertions(+), 46 deletions(-)

diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -75,7 +75,7 @@ static const Ports sysefxPort = static const Ports sysefsendto = { - {"to#" STRINGIFY(NUM_SYS_EFX) "::i", + {"to#" STRINGIFY(NUM_SYS_EFX) "::i", rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d) { //same ugly workaround as before @@ -98,6 +98,16 @@ static const Ports sysefsendto = }} }; +#define rBegin [](const char *msg, RtData &d) { Master *m = (Master*)d.obj +#define rEnd } + +static const Ports watchPorts = { + {"add:s", rDoc("Add synthesis state to watch"), 0, + rBegin; + m->watcher.add_watch(rtosc_argument(msg,0).s); + rEnd}, +}; + static const Ports master_ports = { rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."), rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS @@ -241,11 +251,16 @@ static const Ports master_ports = { {"HDDRecorder/pause:", rDoc("Pause recording"), 0, [](const char *, RtData &d) { Master *m = (Master*)d.obj; m->HDDRecorder.pause();}}, - {"watch/add:s", rDoc("Add synthesis state to watch"), 0, [](const char *msg, RtData &d) { - Master *m = (Master*)d.obj; - m->watcher.add_watch(rtosc_argument(msg,0).s);}}, - + {"watch/", rDoc("Interface to grab out live synthesis state"), &watchPorts, + rBOIL_BEGIN; + SNIP; + watchPorts.dispatch(msg, data); + rBOIL_END}, }; + +#undef rBegin +#undef rEnd + const Ports &Master::ports = master_ports; class DataObj:public rtosc::RtData @@ -364,7 +379,7 @@ void Master::applyOscEvent(const char *msg) DataObj d{loc_buf, 1024, this, bToU}; memset(loc_buf, 0, sizeof(loc_buf)); d.matches = 0; - + if(strcmp(msg, "/get-vu") && false) { fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40); fprintf(stdout, "backend[*]: '%s'<%s>\n", msg, @@ -690,7 +705,7 @@ bool Master::AudioOut(float *outr, float *outl) } if(events>1 && false) fprintf(stderr, "backend: %d events per cycle\n",events); - + //Swaps the Left channel with Right Channel if(swaplr) diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -502,14 +502,14 @@ bool Part::NoteOn(unsigned char note, if(item.Padenabled) notePool.insertNote(note, sendto, {memory.alloc<ADnote>(kit[i].adpars, pars, - wm, (pre+"kit"+i+"/add/").c_str), 0, i}); + wm, (pre+"kit"+i+"/adpars/").c_str), 0, i}); if(item.Psubenabled) notePool.insertNote(note, sendto, {memory.alloc<SUBnote>(kit[i].subpars, pars), 1, i}); if(item.Ppadenabled) notePool.insertNote(note, sendto, {memory.alloc<PADnote>(kit[i].padpars, pars, interpolation, wm, - (pre+"kit"+i+"/pad/").c_str), 2, i}); + (pre+"kit"+i+"/padpars/").c_str), 2, i}); } catch (std::bad_alloc & ba) { std::cerr << "dropped new note: " << ba.what() << std::endl; } diff --git a/src/Params/LFOParams.cpp b/src/Params/LFOParams.cpp @@ -27,6 +27,8 @@ using namespace rtosc; #define rObject LFOParams #undef rChangeCb #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } +#define rBegin [](const char *msg, rtosc::RtData &d) { +#define rEnd } static const rtosc::Ports _ports = { rSelf(LFOParams), rPaste, @@ -45,7 +47,20 @@ static const rtosc::Ports _ports = { "0..4 second delay"), rToggle(Pcontinous, rShort("c"), "Enable for global operation"), rParamZyn(Pstretch, rShort("str"), rCentered, "Note frequency stretch"), + + //Float valued aliases + {"delay::f", rProp(parameter) rMap(units, ms) rLog(0,4000), 0, + rBegin; + + rEnd}, +#define rPseudoLog(a,b) rLog(a,b) + {"period::f", rProp(parameter) rMap(units, ms) rPseudoLog(0.10, 1500.0), 0, + rBegin; + rEnd}, }; +#undef rPseudoLog +#undef rBegin +#undef rEnd #undef rChangeCb const rtosc::Ports &LFOParams::ports = _ports; diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -1886,11 +1886,11 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam &param, ScratchString pre = prefix; FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, synth.dt()); FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time, wm, - (pre+"FreqLfo/").c_str); + (pre+"GlobalPar/FreqLfo/").c_str); AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, synth.dt()); AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time, wm, - (pre+"AmpLfo/").c_str); + (pre+"GlobalPar/AmpLfo/").c_str); Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB * VelF(velocity, param.PAmpVelocityScaleFunction); //sensing @@ -1900,7 +1900,7 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam &param, FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, synth.dt()); FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time, wm, - (pre+"FilterLfo/").c_str); + (pre+"GlobalPar/FilterLfo/").c_str); Filter->addMod(*FilterEnvelope); Filter->addMod(*FilterLfo); diff --git a/src/Synth/LFO.cpp b/src/Synth/LFO.cpp @@ -27,8 +27,7 @@ LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManage deterministic(!lfopars.Pfreqrand), dt_(t.dt()), lfopars_(lfopars), basefreq_(basefreq), - watchPhase(m, watch_prefix, "phase"), - watchMag(m, watch_prefix, "magnitude") + watchOut(m, watch_prefix, "out") { int stretch = lfopars.Pstretch; if(stretch == 0) @@ -170,8 +169,8 @@ float LFO::lfoout() computeNextFreqRnd(); } - watchPhase(phase); - watchMag(out); + float watch_data[2] = {phase, out}; + watchOut(watch_data, 2); return out; } diff --git a/src/Synth/LFO.h b/src/Synth/LFO.h @@ -65,8 +65,7 @@ class LFO const LFOParams &lfopars_; const float basefreq_; - FloatWatchPoint watchPhase; - FloatWatchPoint watchMag; + VecWatchPoint watchOut; void computeNextFreqRnd(void); }; diff --git a/src/Synth/WatchPoint.cpp b/src/Synth/WatchPoint.cpp @@ -32,7 +32,6 @@ WatchPoint::WatchPoint(WatchManager *ref, const char *prefix, const char *id) strncpy(identity, prefix, 128); if(id) strncat(identity, id, 128); - //printf("new watchpoint ={%s:%s} <%s>\n", prefix, id, identity); } bool WatchPoint::is_active(void) @@ -44,7 +43,7 @@ bool WatchPoint::is_active(void) if(reference && reference->active(identity)) { active = true; - samples_left = reference->samples(identity); + samples_left = 1; return true; } @@ -54,12 +53,17 @@ bool WatchPoint::is_active(void) FloatWatchPoint::FloatWatchPoint(WatchManager *ref, const char *prefix, const char *id) :WatchPoint(ref, prefix, id) {} + +VecWatchPoint::VecWatchPoint(WatchManager *ref, const char *prefix, const char *id) + :WatchPoint(ref, prefix, id) +{} WatchManager::WatchManager(thrlnk *link) :write_back(link), new_active(false) { memset(active_list, 0, sizeof(active_list)); memset(sample_list, 0, sizeof(sample_list)); + memset(data_list, 0, sizeof(data_list)); memset(deactivate, 0, sizeof(deactivate)); } @@ -70,6 +74,7 @@ void WatchManager::add_watch(const char *id) if(!active_list[i][0]) { strncpy(active_list[i], id, 128); new_active = true; + sample_list[i] = 0; break; } } @@ -85,19 +90,39 @@ void WatchManager::del_watch(const char *id) void WatchManager::tick(void) { + //Try to send out any vector stuff + for(int i=0; i<MAX_WATCH; ++i) { + if(sample_list[i]) { + char arg_types[MAX_SAMPLE+1] = {0}; + rtosc_arg_t arg_val[MAX_SAMPLE]; + for(int j=0; j<sample_list[i]; ++j) { + arg_types[j] = 'f'; + arg_val[j].f = data_list[i][j]; + } + + write_back->writeArray(active_list[i], arg_types, arg_val); + deactivate[i] = true; + } + } + + //Cleanup internal data new_active = false; //Clear deleted slots - for(int i=0; i<MAX_WATCH; ++i) - if(deactivate[i]) + for(int i=0; i<MAX_WATCH; ++i) { + if(deactivate[i]) { memset(active_list[i], 0, 128); + sample_list[i] = 0; + } + } + } bool WatchManager::active(const char *id) const { assert(this); assert(id); - if(new_active) + if(new_active || true) for(int i=0; i<MAX_WATCH; ++i) if(!strcmp(active_list[i], id)) return true; @@ -121,3 +146,17 @@ void WatchManager::satisfy(const char *id, float f) del_watch(id); } +void WatchManager::satisfy(const char *id, float *f, int n) +{ + int selected = -1; + for(int i=0; i<MAX_WATCH; ++i) + if(!strcmp(active_list[i], id)) + selected = i; + + if(selected == -1) + return; + + //FIXME buffer overflow + for(int i=0; i<n; ++i) + data_list[selected][sample_list[selected]++] = f[i]; +} diff --git a/src/Synth/WatchPoint.h b/src/Synth/WatchPoint.h @@ -3,20 +3,12 @@ WatchPoint.h - Synthesis State Watcher Copyright (C) 2015-2015 Mark McCurry + Author: Mark McCurry - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License (version 2 or later) for more details. - - You should have received a copy of the GNU General Public License (version 2) - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. */ #pragma once @@ -36,12 +28,15 @@ struct WatchPoint }; #define MAX_WATCH 16 +#define MAX_WATCH_PATH 128 +#define MAX_SAMPLE 128 struct WatchManager { typedef rtosc::ThreadLink thrlnk; thrlnk *write_back; bool new_active; - char active_list[128][MAX_WATCH]; + char active_list[MAX_WATCH][MAX_WATCH_PATH]; + float data_list[MAX_SAMPLE][MAX_WATCH]; int sample_list[MAX_WATCH]; bool deactivate[MAX_WATCH]; @@ -57,6 +52,7 @@ struct WatchManager //Watch Point Response API void satisfy(const char *, float); + void satisfy(const char *, float*, int); }; struct FloatWatchPoint:public WatchPoint @@ -71,11 +67,15 @@ struct FloatWatchPoint:public WatchPoint } }; -//struct VecWatchPoint:public WatchPoint -//{ -// inline void operator()(float *f, int n) -// { -// if(!is_active()) { -// } -// } -//}; +//basically the same as the float watch point, only it consumes tuples +struct VecWatchPoint : public WatchPoint +{ + VecWatchPoint(WatchManager *ref, const char *prefix, const char *id); + inline void operator()(float *f, int n) + { + if(is_active() && reference) { + reference->satisfy(identity, f, n); + active = false; + } + } +}; diff --git a/src/UI/Connection.cpp b/src/UI/Connection.cpp @@ -407,7 +407,7 @@ class UI_Interface:public Fl_Osc_Interface virtual void damage(const char *path) override { #ifndef NO_UI - printf("\n\nDamage(\"%s\")\n", path); + //printf("\n\nDamage(\"%s\")\n", path); std::set<Fl_Osc_Widget*> to_update; for(auto pair:map) { if(strstr(pair.first.c_str(), path)) {