zynaddsubfx

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

commit 9f5648d27750c27b9227e336dc3e5537ed51c7cf
parent 86373594d9bc02daff32316e45cc1c5f0802153a
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sun, 15 Jun 2014 15:34:55 -0400

Add Fast Abort To Instrument Loading

If a part has another pending load the current load will be aborted.
This should allow for easy exploring through banks even if the midi controller
insists on sending requests for all of the intermediate patches.

Diffstat:
Msrc/Misc/MiddleWare.cpp | 42++++++++++++++++++++++++++++++++----------
Msrc/Misc/MiddleWare.h | 1+
Msrc/Misc/Part.cpp | 7++++++-
Msrc/Misc/Part.h | 2++
Msrc/Nio/InMgr.cpp | 13+++++++++++--
Msrc/Params/PADnoteParameters.cpp | 18+++++++++++++++---
Msrc/Params/PADnoteParameters.h | 4+++-
7 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -170,7 +170,7 @@ void preparePadSynth(string path, PADnoteParameters *p) printf("sending info to '%s'\n", (path+to_s(N)).c_str()); uToB->write((path+to_s(N)).c_str(), "ifb", s.size, s.basefreq, sizeof(float*), &s.smp); - }); + }, []{return false;}); //clear out unused samples for(unsigned i = max+1; i < PAD_MAX_SAMPLES; ++i) { uToB->write((path+to_s(i)).c_str(), "ifb", @@ -336,6 +336,12 @@ struct MiddleWareImpl } } } + + //Null out Load IDs + for(int i=0; i < NUM_MIDI_PARTS; ++i) { + pending_load[i] = 0; + actual_load[i] = 0; + } } ~MiddleWareImpl(void) @@ -431,12 +437,18 @@ struct MiddleWareImpl void loadPart(int npart, const char *filename, Master *master, Fl_Osc_Interface *osc) { printf("loading part...\n"); + actual_load[npart]++; + + if(actual_load[npart] != pending_load[npart]) + return; + assert(actual_load[npart] <= pending_load[npart]); + auto alloc = std::async(std::launch::async, - [master,filename](){Part *p = new Part(&master->microtonal, master->fft); + [master,filename,this,npart](){Part *p = new Part(&master->microtonal, master->fft); if(p->loadXMLinstrument(filename)) fprintf(stderr, "FAILED TO LOAD PART!!\n"); - p->applyparameters(); + p->applyparameters([this,npart]{printf("%d vs %d\n", (int)actual_load[npart], (int)pending_load[npart]);return actual_load[npart] != pending_load[npart];}); return p;}); //fprintf(stderr, "loading a part!!\n"); //Load the part @@ -671,10 +683,12 @@ struct MiddleWareImpl } else if(strstr(msg, "/load_xmz") && !strcmp(rtosc_argument_string(msg), "s")) { loadMaster(rtosc_argument(msg,0).s); } else if(!strcmp(msg, "/load_xiz") && !strcmp(rtosc_argument_string(msg), "is")) { + pending_load[rtosc_argument(msg,0).i]++; loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc); - } else if(strstr(msg, "load-part") && !strcmp(rtosc_argument_string(msg), "is")) + } else if(strstr(msg, "load-part") && !strcmp(rtosc_argument_string(msg), "is")) { + pending_load[rtosc_argument(msg,0).i]++; loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc); - else + } else uToB->raw_write(msg); } @@ -727,6 +741,9 @@ struct MiddleWareImpl void(*idle)(void); cb_t cb; void *ui; + + std::atomic_int pending_load[NUM_MIDI_PARTS]; + std::atomic_int actual_load[NUM_MIDI_PARTS]; }; /** @@ -839,14 +856,14 @@ class UI_Interface:public Fl_Osc_Interface //A very simplistic implementation of a UI agnostic refresh method virtual void damage(const char *path) { - printf("\n\nDamage(\"%s\")\n", path); + //printf("\n\nDamage(\"%s\")\n", path); for(auto pair:map) { if(strstr(pair.first.c_str(), path)) { auto *tmp = dynamic_cast<Fl_Widget*>(pair.second); - if(tmp) - printf("%x, %d %d [%s]\n", (int)pair.second, tmp->visible_r(), tmp->visible(), pair.first.c_str()); - else - printf("%x, (NULL)[%s]\n", (int)pair.second,pair.first.c_str()); + //if(tmp) + // printf("%x, %d %d [%s]\n", (int)pair.second, tmp->visible_r(), tmp->visible(), pair.first.c_str()); + //else + // printf("%x, (NULL)[%s]\n", (int)pair.second,pair.first.c_str()); if(!tmp || tmp->visible_r()) pair.second->update(); } @@ -952,6 +969,7 @@ void MiddleWare::tick(void) { impl->tick(); } + void MiddleWare::setUiCallback(void(*cb)(void*,const char *),void *ui) { impl->cb = cb; @@ -963,3 +981,7 @@ void MiddleWare::setIdleCallback(void(*cb)(void)) impl->idle = cb; } +void MiddleWare::pendingSetProgram(int part) +{ + impl->pending_load[part]++; +} diff --git a/src/Misc/MiddleWare.h b/src/Misc/MiddleWare.h @@ -12,6 +12,7 @@ class MiddleWare void setUiCallback(void(*cb)(void*,const char *),void *ui); void setIdleCallback(void(*cb)(void)); void tick(void); + void pendingSetProgram(int part); static void preparePadSynth(const char *, class PADnoteParameters *){}; private: diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -1337,9 +1337,14 @@ int Part::loadXMLinstrument(const char *filename) void Part::applyparameters(void) { + applyparameters([]{return false;}); +} + +void Part::applyparameters(std::function<bool()> do_abort) +{ for(int n = 0; n < NUM_KIT_ITEMS; ++n) if(kit[n].Ppadenabled && kit[n].padpars) - kit[n].padpars->applyparameters(); + kit[n].padpars->applyparameters(do_abort); } void Part::getfromXMLinstrument(XMLwrapper *xml) diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -29,6 +29,7 @@ #include "../Params/Controller.h" #include "../Misc/Microtonal.h" +#include <functional> #include <list> // For the monomemnotes list. class EffectMgr; @@ -82,6 +83,7 @@ class Part void defaultsinstrument(); void applyparameters(void); + void applyparameters(std::function<bool()> do_abort); void getfromXML(XMLwrapper *xml); void getfromXMLinstrument(XMLwrapper *xml); diff --git a/src/Nio/InMgr.cpp b/src/Nio/InMgr.cpp @@ -2,11 +2,15 @@ #include "MidiIn.h" #include "EngineMgr.h" #include "../Misc/Master.h" +#include "../Misc/Part.h" +#include "../Misc/MiddleWare.h" #include <rtosc/thread-link.h> #include <iostream> using namespace std; +extern MiddleWare *middleware; + ostream &operator<<(ostream &out, const MidiEvent &ev) { switch(ev.type) { @@ -85,8 +89,13 @@ void InMgr::flush() break; case M_PGMCHANGE: - //FIXME channel is only interpreted as part number here - bToU->write("/setprogram", "cc", ev.channel, ev.num); + 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 == ev.channel) { + bToU->write("/setprogram", "cc", i, ev.num); + middleware->pendingSetProgram(i); + } + } break; case M_PRESSURE: diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp @@ -703,15 +703,23 @@ void PADnoteParameters::generatespectrum_otherModes(float *spectrum, /* * Applies the parameters (i.e. computes all the samples, based on parameters); */ -void PADnoteParameters::applyparameters(void) +void PADnoteParameters::applyparameters() { + applyparameters([]{return false;}); +} + +void PADnoteParameters::applyparameters(std::function<bool()> do_abort) +{ + if(do_abort()) + return; unsigned max = 0; sampleGenerator([&max,this] (unsigned N, PADnoteParameters::Sample &smp) { delete[] sample[N].smp; sample[N] = smp; max = max < N ? N : max; - }); + }, + do_abort); //Delete remaining unused samples for(unsigned i = max; i < PAD_MAX_SAMPLES; ++i) @@ -724,7 +732,8 @@ void PADnoteParameters::applyparameters(void) // - Pquality.oct // - Pquality.smpoct // - spectrum at various frequencies (oodles of data) -void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb) +void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb, + std::function<bool()> do_abort) { const int samplesize = (((int) 1) << (Pquality.samplesize + 14)); const int spectrumsize = samplesize / 2; @@ -760,6 +769,8 @@ void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb) for(int nsample = 0; nsample < samplemax; ++nsample) adj[nsample] = (Pquality.oct + 1.0f) * (float)nsample / samplemax; for(int nsample = 0; nsample < samplemax; ++nsample) { + if(do_abort()) + goto exit; const float basefreqadjust = powf(2.0f, adj[nsample] - adj[samplemax - 1] * 0.5f); @@ -808,6 +819,7 @@ void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb) newsample.basefreq = basefreq * basefreqadjust; cb(nsample, newsample); } +exit: //Cleanup delete (fft); diff --git a/src/Params/PADnoteParameters.h b/src/Params/PADnoteParameters.h @@ -156,6 +156,7 @@ class PADnoteParameters:public Presets float getNhr(int n); //gets the n-th overtone position relatively to N harmonic void applyparameters(void); + void applyparameters(std::function<bool()> do_abort); void export2wav(std::string basefilename); OscilGen *oscilgen; @@ -169,7 +170,8 @@ class PADnoteParameters:public Presets } sample[PAD_MAX_SAMPLES]; typedef std::function<void(int,PADnoteParameters::Sample&)> callback; - void sampleGenerator(PADnoteParameters::callback cb); + void sampleGenerator(PADnoteParameters::callback cb, + std::function<bool()> do_abort); static rtosc::Ports &ports;