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:
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;