commit 6baafe64de55619ce701034da5937a17eb41a742
parent f186c492a5085101c30d78d02eb86169fd4d202b
Author: fundamental <[email protected]>
Date: Fri, 15 Feb 2013 09:58:51 -0500
PADnoteParameters: Updates to samples via rtosc
As a warning to the squimish, this is a messy commit with plenty left to do
- PADnoteParameters and some related synthesis code has been refactored to make
it more readable
- Samples are generated WITHOUT a lock and are delivered over a rtosc link
- Memory leaks when old samples are discarded
- This introduces a possible future race condition with values of
PADnoteParameters changing while this non-rt synthesis is being done.
- A very hacky build setup was needed to get this to link properly (for some
unknown reason) [see MiddleWare.h]
Now for the good:
- Ports are introduced to Part, Kit, and Padnote
- Existing loading is the same as it was previously
- The UI has the concept of OSC addresses introduced to it
- The scope of the horrid mutex has been further reduced
- OscilGen data (for at least the PADnote case) has been defined to be a
non-realtime structure and as such it can be treated as such (though it will
need to be migrated to the middleware layer)
- PadNoteTest now has looser boundries as it seems particularly sensitive to
optimization issues (though this could indicate some lurking undefined
behavior)
Diffstat:
19 files changed, 533 insertions(+), 339 deletions(-)
diff --git a/src/Misc/CMakeLists.txt b/src/Misc/CMakeLists.txt
@@ -11,6 +11,7 @@ set(zynaddsubfx_misc_SRCS
Misc/XMLwrapper.cpp
Misc/Recorder.cpp
Misc/WavFile.cpp
+ Misc/MiddleWare.cpp
Misc/WaveShapeSmps.cpp
)
diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp
@@ -44,21 +44,6 @@ using namespace std;
using rtosc::Ports;
using rtosc::RtData;
-template<class T>
-T lim(T min, T max, T val)
-{
- return val<max?(val>min?val:min):max;
-}
-//floating point parameter - with lookup code
-#define PARAMF(type, var, name, scale, _min, _max, desc) \
-{#name"::f", #scale "," # _min "," #_max ":'parameter':" desc, 0, \
- [](const char *m, RtData d) { \
- if(rtosc_narguments(m)==0) {\
- bToU->write("/display", "sf", d.loc, ((type*)d.obj)->var); \
- } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='f') {\
- ((type*)d.obj)->var = lim<float>(_min,_max,rtosc_argument(m,0).f); \
- bToU->write(d.loc, "f", ((type*)d.obj)->var);}}}
-
static Ports localports = {
{"echo", ":'hidden':Hidden port to echo messages", 0, [](const char *m, RtData) {
bToU->raw_write(m-1);}},
@@ -69,6 +54,7 @@ static Ports localports = {
Master *m = (Master*)d.obj;
m->vuresetpeaks();}},
PARAMF(Master, volume, volume, log, 0.01, 4.42, "Master Volume"),
+ RECURSP(Master, Part, part, part, 16, "Part"),//NUM_MIDI_PARTS
};
Ports &Master::ports = localports;
@@ -627,10 +613,10 @@ void Master::vuresetpeaks()
vu.clipped = 0;
}
-void Master::applyparameters(bool lockmutex)
+void Master::applyparameters(void)
{
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
- part[npart]->applyparameters(lockmutex);
+ part[npart]->applyparameters();
}
void Master::add2XML(XMLwrapper *xml)
diff --git a/src/Misc/Master.h b/src/Misc/Master.h
@@ -73,7 +73,10 @@ class Master
/**loads all settings from a XML file
* @return 0 for ok or -1 if there is an error*/
int loadXML(const char *filename);
- void applyparameters(bool lockmutex = true);
+
+ /**Regenerate PADsynth and other non-RT parameters
+ * It is NOT SAFE to call this from a RT context*/
+ void applyparameters(void);
void getfromXML(XMLwrapper *xml);
diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp
@@ -0,0 +1,31 @@
+#include "../Params/PADnoteParameters.h"
+#include <cstring>
+#include <cstdio>
+
+#include <rtosc/thread-link.h>
+
+extern rtosc::ThreadLink *uToB;
+namespace MiddleWare {
+void preparePadSynth(const char *path, PADnoteParameters *p)
+{
+ char path_buffer[1024];
+ strncpy(path_buffer, path, 1024);
+ if(char *old_end = rindex(path_buffer, '/')) {
+ unsigned max = 0;
+ p->sampleGenerator([&max,&old_end,&path_buffer]
+ (unsigned N, PADnoteParameters::Sample &s)
+ {
+ max = max<N ? N : max;
+ sprintf(old_end, "/sample%d", N);
+ uToB->write(path_buffer, "ifb",
+ s.size, s.basefreq, sizeof(float*), &s.smp);
+ });
+ //clear out unused samples
+ for(unsigned i = max+1; i < PAD_MAX_SAMPLES; ++i) {
+ sprintf(old_end, "/sample%d", i);
+ uToB->write(path_buffer, "ifb",
+ 0, 440.0f, sizeof(float*), NULL);
+ }
+ }
+}
+}
diff --git a/src/Misc/MiddleWare.h b/src/Misc/MiddleWare.h
@@ -0,0 +1,10 @@
+#pragma once
+class PADnoteParameters;
+//Link between realtime and non-realtime layers
+namespace MiddleWare
+{
+static void preparePadSynth(const char *path, PADnoteParameters *p);
+};
+
+//XXX Odd Odd compiler behavior has made this hack necessary (darn you linker)
+#include "MiddleWare.cpp"
diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp
@@ -36,6 +36,22 @@
#include <stdio.h>
#include <string.h>
+#include <rtosc/ports.h>
+
+using rtosc::Ports;
+using rtosc::RtData;
+
+static Ports partPorts = {
+ RECURS(Part, Part::Kit, kit, kit, 16, "Kit"),//NUM_KIT_ITEMS
+};
+
+static Ports kitPorts = {
+ RECURP(Part::Kit, PADnoteParameters, padpars, padpars, "Padnote parameters"),
+};
+
+Ports &Part::Kit::ports = kitPorts;
+Ports &Part::ports = partPorts;
+
Part::Part(Microtonal *microtonal_, FFTwrapper *fft_, pthread_mutex_t *mutex_)
{
microtonal = microtonal_;
@@ -54,7 +70,7 @@ Part::Part(Microtonal *microtonal_, FFTwrapper *fft_, pthread_mutex_t *mutex_)
kit[0].adpars = new ADnoteParameters(fft);
kit[0].subpars = new SUBnoteParameters();
- kit[0].padpars = new PADnoteParameters(fft, mutex);
+ kit[0].padpars = new PADnoteParameters(fft);
//Part's Insertion Effects init
for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) {
@@ -1079,7 +1095,7 @@ void Part::setkititemstatus(int kititem, int Penabled_)
if(kit[kititem].subpars == NULL)
kit[kititem].subpars = new SUBnoteParameters();
if(kit[kititem].padpars == NULL)
- kit[kititem].padpars = new PADnoteParameters(fft, mutex);
+ kit[kititem].padpars = new PADnoteParameters(fft);
}
if(resetallnotes)
@@ -1199,7 +1215,7 @@ int Part::saveXML(const char *filename)
return result;
}
-int Part::loadXMLinstrument(const char *filename) /*{*/
+int Part::loadXMLinstrument(const char *filename)
{
XMLwrapper *xml = new XMLwrapper();
if(xml->loadXMLfile(filename) < 0) {
@@ -1214,14 +1230,14 @@ int Part::loadXMLinstrument(const char *filename) /*{*/
delete (xml);
return 0;
-} /*}*/
+}
-void Part::applyparameters(bool lockmutex) /*{*/
+void Part::applyparameters(void)
{
for(int n = 0; n < NUM_KIT_ITEMS; ++n)
- if((kit[n].padpars != NULL) && (kit[n].Ppadenabled != 0))
- kit[n].padpars->applyparameters(lockmutex);
-} /*}*/
+ if(kit[n].Ppadenabled && kit[n].padpars)
+ kit[n].padpars->applyparameters();
+}
void Part::getfromXMLinstrument(XMLwrapper *xml)
{
diff --git a/src/Misc/Part.h b/src/Misc/Part.h
@@ -30,6 +30,7 @@
#include "../Misc/Microtonal.h"
#include <list> // For the monomemnotes list.
+#include <pthread.h>
class EffectMgr;
class ADnoteParameters;
@@ -81,7 +82,7 @@ class Part
void defaults();
void defaultsinstrument();
- void applyparameters(bool lockmutex = true);
+ void applyparameters(void);
void getfromXML(XMLwrapper *xml);
void getfromXMLinstrument(XMLwrapper *xml);
@@ -89,7 +90,7 @@ class Part
void cleanup(bool final = false);
//the part's kit
- struct {
+ struct Kit {
unsigned char Penabled, Pmuted, Pminkey, Pmaxkey;
unsigned char *Pname;
unsigned char Padenabled, Psubenabled, Ppadenabled;
@@ -97,6 +98,8 @@ class Part
ADnoteParameters *adpars;
SUBnoteParameters *subpars;
PADnoteParameters *padpars;
+
+ static rtosc::Ports &ports;
} kit[NUM_KIT_ITEMS];
@@ -152,10 +155,12 @@ class Part
pthread_mutex_t *mutex;
- pthread_mutex_t load_mutex;
+ pthread_mutex_t load_mutex;
int lastnote;
+ static rtosc::Ports &ports;
+
private:
void RunNote(unsigned k);
void KillNotePos(int pos);
diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp
@@ -220,3 +220,9 @@ 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);
}
+
+const char *message_snip(const char *m)
+{
+ while(*m && *m!='/')++m;
+ return *m?m+1:m;
+}
diff --git a/src/Misc/Util.h b/src/Misc/Util.h
@@ -87,6 +87,17 @@ T limit(T val, T min, T max)
return val < min ? min : (val > max ? max : val);
}
+template<class T>
+T array_max(const T *data, size_t len)
+{
+ T max = 0;
+
+ for(unsigned i = 0; i < len; ++i)
+ if(max < data[i])
+ max = data[i];
+ return max;
+}
+
//Random number generator
typedef uint32_t prng_t;
@@ -120,4 +131,51 @@ float interpolate(const float *data, size_t len, float pos);
//Linear circular interpolation
float cinterpolate(const float *data, size_t len, float pos);
+/**
+ * Port macros - these produce easy and regular port definitions for common
+ * types
+ */
+
+///trims a path in recursions
+const char *message_snip(const char *m);
+
+///floating point parameter - with lookup code
+#define PARAMF(type, var, name, scale, _min, _max, desc) \
+{#name"::f", #scale "," # _min "," #_max ":'parameter':" desc, 0, \
+ [](const char *m, RtData d) { \
+ if(rtosc_narguments(m)==0) {\
+ bToU->write("/display", "sf", d.loc, ((type*)d.obj)->var); \
+ } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='f') {\
+ ((type*)d.obj)->var = limit<float>(_min,_max,rtosc_argument(m,0).f); \
+ bToU->write(d.loc, "f", ((type*)d.obj)->var);}}}
+
+///Recur - perform a simple recursion
+#define RECUR(type, cast, name, var, desc) \
+{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){\
+ cast::ports.dispatch(d.loc, d.loc_size, message_snip(m),\
+ &(((type*)d.obj)->var));}}
+
+///Recurs - perform a ranged recursion
+#define RECURS(type, cast, name, var, length, desc) \
+{#name "#" #length "/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){ \
+ const char *mm = m; \
+ while(!isdigit(*mm))++mm; \
+ cast::ports.dispatch(d.loc, d.loc_size, message_snip(m), \
+ &(((type*)d.obj)->var)[atoi(mm)]);}}
+
+///Recur - perform a simple recursion (on pointer member)
+#define RECURP(type, cast, name, var, desc) \
+{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){\
+ cast::ports.dispatch(d.loc, d.loc_size, message_snip(m),\
+ (((type*)d.obj)->var));}}
+
+///Recurs - perform a ranged recursion (on pointer array member)
+#define RECURSP(type, cast, name, var, length, desc) \
+{#name "#" #length "/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){ \
+ const char *mm = m; \
+ while(!isdigit(*mm))++mm; \
+ cast::ports.dispatch(d.loc, d.loc_size, message_snip(m), \
+ (((type*)d.obj)->var)[atoi(mm)]);}}
+
+
#endif
diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp
@@ -19,17 +19,37 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <math.h>
+#include <cmath>
#include "PADnoteParameters.h"
#include "../Misc/WavFile.h"
+#include <cstdio>
-PADnoteParameters::PADnoteParameters(FFTwrapper *fft_,
- pthread_mutex_t *mutex_):Presets()
+#include <rtosc/ports.h>
+
+static rtosc::Ports localPorts =
+{
+ {"sample#64:ifb", "::Nothing to see here", 0,
+ [](const char *m, rtosc::RtData d)
+ {
+ PADnoteParameters *p = (PADnoteParameters*)d.obj;
+ const char *mm = m;
+ while(!isdigit(*mm))++mm;
+ unsigned n = atoi(mm);
+ p->sample[n].size = rtosc_argument(m,0).i;
+ p->sample[n].basefreq = rtosc_argument(m,1).f;
+ p->sample[n].smp = *(float**)rtosc_argument(m,2).b.data;
+
+ //XXX TODO memory managment (deallocation of smp buffer)
+ }},
+};
+
+rtosc::Ports &PADnoteParameters::ports = localPorts;
+
+PADnoteParameters::PADnoteParameters(FFTwrapper *fft_):Presets()
{
setpresettype("Ppadsyth");
fft = fft_;
- mutex = mutex_;
resonance = new Resonance();
oscilgen = new OscilGen(fft_, resonance);
@@ -50,7 +70,6 @@ PADnoteParameters::PADnoteParameters(FFTwrapper *fft_,
for(int i = 0; i < PAD_MAX_SAMPLES; ++i)
sample[i].smp = NULL;
- newsample.smp = NULL;
defaults();
}
@@ -137,10 +156,9 @@ void PADnoteParameters::deletesample(int n)
{
if((n < 0) || (n >= PAD_MAX_SAMPLES))
return;
- if(sample[n].smp != NULL) {
- delete[] sample[n].smp;
- sample[n].smp = NULL;
- }
+
+ delete[] sample[n].smp;
+ sample[n].smp = NULL;
sample[n].size = 0;
sample[n].basefreq = 440.0f;
}
@@ -323,10 +341,10 @@ float PADnoteParameters::setPbandwidth(int Pbandwidth)
float PADnoteParameters::getNhr(int n)
{
float result = 1.0f;
- float par1 = powf(10.0f, -(1.0f - Phrpos.par1 / 255.0f) * 3.0f);
- float par2 = Phrpos.par2 / 255.0f;
+ const float par1 = powf(10.0f, -(1.0f - Phrpos.par1 / 255.0f) * 3.0f);
+ const float par2 = Phrpos.par2 / 255.0f;
- float n0 = n - 1.0f;
+ const float n0 = n - 1.0f;
float tmp = 0.0f;
int thresh = 0;
switch(Phrpos.type) {
@@ -369,19 +387,51 @@ float PADnoteParameters::getNhr(int n)
break;
}
- float par3 = Phrpos.par3 / 255.0f;
+ const float par3 = Phrpos.par3 / 255.0f;
- float iresult = floor(result + 0.5f);
- float dresult = result - iresult;
+ const float iresult = floor(result + 0.5f);
+ const float dresult = result - iresult;
- result = iresult + (1.0f - par3) * dresult;
+ return iresult + (1.0f - par3) * dresult;
+}
- return result;
+//Transform non zero positive signals into ones with a max of one
+static void normalize_max(float *f, size_t len)
+{
+ float max = 0.0f;
+ for(unsigned i = 0; i < len; ++i)
+ if(f[i] > i)
+ max = f[i];
+ if(max > 0.000001f)
+ for(unsigned i = 0; i < len; ++i)
+ f[i] /= max;
+}
+
+//Translate Bandwidth scale integer into floating point value
+static float Pbwscale_translate(char Pbwscale)
+{
+ switch(Pbwscale) {
+ case 0: return 1.0f;
+ case 1: return 0.0f;
+ case 2: return 0.25f;
+ case 3: return 0.5f;
+ case 4: return 0.75f;
+ case 5: return 1.5f;
+ case 6: return 2.0f;
+ case 7: return -0.5f;
+ default: return 1.0;
+ }
}
/*
* Generates the long spectrum for Bandwidth mode (only amplitudes are generated; phases will be random)
*/
+
+//Requires
+// - bandwidth scaling power
+// - bandwidth
+// - oscilator harmonics at various frequences (oodles of data)
+// - sampled resonance
void PADnoteParameters::generatespectrum_bandwidthMode(float *spectrum,
int size,
float basefreq,
@@ -389,27 +439,22 @@ void PADnoteParameters::generatespectrum_bandwidthMode(float *spectrum,
int profilesize,
float bwadjust)
{
- for(int i = 0; i < size; ++i)
- spectrum[i] = 0.0f;
-
float harmonics[synth->oscilsize / 2];
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- harmonics[i] = 0.0f;
+ memset(spectrum, 0, sizeof(float) * size);
+ memset(harmonics, 0, sizeof(float) * (synth->oscilsize / 2));
+
//get the harmonic structure from the oscillator (I am using the frequency amplitudes, only)
oscilgen->get(harmonics, basefreq, false);
//normalize
- float max = 0.0f;
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- if(harmonics[i] > max)
- max = harmonics[i];
- if(max < 0.000001f)
- max = 1;
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- harmonics[i] /= max;
+ normalize_max(harmonics, synth->oscilsize / 2);
+
+ //Constants across harmonics
+ const float power = Pbwscale_translate(Pbwscale);
+ const float bandwidthcents = setPbandwidth(Pbandwidth);
for(int nh = 1; nh < synth->oscilsize / 2; ++nh) { //for each harmonic
- float realfreq = getNhr(nh) * basefreq;
+ const float realfreq = getNhr(nh) * basefreq;
if(realfreq > synth->samplerate_f * 0.49999f)
break;
if(realfreq < 20.0f)
@@ -418,51 +463,23 @@ void PADnoteParameters::generatespectrum_bandwidthMode(float *spectrum,
continue;
//compute the bandwidth of each harmonic
- float bandwidthcents = setPbandwidth(Pbandwidth);
- float bw =
- (powf(2.0f, bandwidthcents / 1200.0f) - 1.0f) * basefreq / bwadjust;
- float power = 1.0f;
- switch(Pbwscale) {
- case 0:
- power = 1.0f;
- break;
- case 1:
- power = 0.0f;
- break;
- case 2:
- power = 0.25f;
- break;
- case 3:
- power = 0.5f;
- break;
- case 4:
- power = 0.75f;
- break;
- case 5:
- power = 1.5f;
- break;
- case 6:
- power = 2.0f;
- break;
- case 7:
- power = -0.5f;
- break;
- }
- bw = bw * powf(realfreq / basefreq, power);
- int ibw = (int)((bw / (synth->samplerate_f * 0.5f) * size)) + 1;
+ const float bw =
+ ((powf(2.0f, bandwidthcents / 1200.0f) - 1.0f) * basefreq / bwadjust)
+ * powf(realfreq / basefreq, power);
+ const int ibw = (int)((bw / (synth->samplerate_f * 0.5f) * size)) + 1;
float amp = harmonics[nh - 1];
if(resonance->Penabled)
amp *= resonance->getfreqresponse(realfreq);
if(ibw > profilesize) { //if the bandwidth is larger than the profilesize
- float rap = sqrt((float)profilesize / (float)ibw);
- int cfreq =
+ const float rap = sqrt((float)profilesize / (float)ibw);
+ const int cfreq =
(int) (realfreq
/ (synth->samplerate_f * 0.5f) * size) - ibw / 2;
for(int i = 0; i < ibw; ++i) {
- int src = (int)(i * rap * rap);
- int spfreq = i + cfreq;
+ const int src = i * rap * rap;
+ const int spfreq = i + cfreq;
if(spfreq < 0)
continue;
if(spfreq >= size)
@@ -471,13 +488,12 @@ void PADnoteParameters::generatespectrum_bandwidthMode(float *spectrum,
}
}
else { //if the bandwidth is smaller than the profilesize
- float rap = sqrt((float)ibw / (float)profilesize);
- float ibasefreq = realfreq / (synth->samplerate_f * 0.5f) * size;
+ const float rap = sqrt((float)ibw / (float)profilesize);
+ const float ibasefreq = realfreq / (synth->samplerate_f * 0.5f) * size;
for(int i = 0; i < profilesize; ++i) {
- float idfreq = i / (float)profilesize - 0.5f;
- idfreq *= ibw;
- int spfreq = (int) (idfreq + ibasefreq);
- float fspfreq = fmodf((float)idfreq + ibasefreq, 1.0f);
+ const float idfreq = (i / (float)profilesize - 0.5f) * ibw;
+ const int spfreq = (int) (idfreq + ibasefreq);
+ const float fspfreq = fmodf((float)idfreq + ibasefreq, 1.0f);
if(spfreq <= 0)
continue;
if(spfreq >= size - 1)
@@ -497,55 +513,46 @@ void PADnoteParameters::generatespectrum_otherModes(float *spectrum,
int size,
float basefreq)
{
- for(int i = 0; i < size; ++i)
- spectrum[i] = 0.0f;
-
float harmonics[synth->oscilsize / 2];
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- harmonics[i] = 0.0f;
+ memset(spectrum, 0, sizeof(float) * size);
+ memset(harmonics, 0, sizeof(float) * (synth->oscilsize / 2));
+
//get the harmonic structure from the oscillator (I am using the frequency amplitudes, only)
oscilgen->get(harmonics, basefreq, false);
//normalize
- float max = 0.0f;
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- if(harmonics[i] > max)
- max = harmonics[i];
- if(max < 0.000001f)
- max = 1;
- for(int i = 0; i < synth->oscilsize / 2; ++i)
- harmonics[i] /= max;
+ normalize_max(harmonics, synth->oscilsize / 2);
for(int nh = 1; nh < synth->oscilsize / 2; ++nh) { //for each harmonic
- float realfreq = getNhr(nh) * basefreq;
-
- ///sa fac aici interpolarea si sa am grija daca frecv descresc
+ const float realfreq = getNhr(nh) * basefreq;
+ //take care of interpolation if frequency decreases
if(realfreq > synth->samplerate_f * 0.49999f)
break;
if(realfreq < 20.0f)
break;
-// if (harmonics[nh-1]<1e-4) continue;
float amp = harmonics[nh - 1];
if(resonance->Penabled)
amp *= resonance->getfreqresponse(realfreq);
- int cfreq = (int) (realfreq / (synth->samplerate_f * 0.5f) * size);
+ const int cfreq = realfreq / (synth->samplerate_f * 0.5f) * size;
spectrum[cfreq] = amp + 1e-9;
}
- if(Pmode != 1) {
+ //In continous mode the spectrum gets additional interpolation between the
+ //spectral peaks
+ if(Pmode != 1) { //continous mode
int old = 0;
for(int k = 1; k < size; ++k)
if((spectrum[k] > 1e-10) || (k == (size - 1))) {
- int delta = k - old;
- float val1 = spectrum[old];
- float val2 = spectrum[k];
- float idelta = 1.0f / delta;
+ const int delta = k - old;
+ const float val1 = spectrum[old];
+ const float val2 = spectrum[k];
+ const float idelta = 1.0f / delta;
for(int i = 0; i < delta; ++i) {
- float x = idelta * i;
+ const float x = idelta * i;
spectrum[old + i] = val1 * (1.0f - x) + val2 * x;
}
old = k;
@@ -556,17 +563,37 @@ void PADnoteParameters::generatespectrum_otherModes(float *spectrum,
/*
* Applies the parameters (i.e. computes all the samples, based on parameters);
*/
-void PADnoteParameters::applyparameters(bool lockmutex)
+void PADnoteParameters::applyparameters(void)
+{
+ unsigned max = 0;
+ sampleGenerator([&max,this]
+ (unsigned N, PADnoteParameters::Sample &smp) {
+ delete[] sample[N].smp;
+ sample[N] = smp;
+ max = max < N ? N : max;
+ });
+
+ //Delete remaining unused samples
+ for(unsigned i = max; i < PAD_MAX_SAMPLES; ++i)
+ deletesample(i);
+}
+
+//Requires
+// - Pquality.samplesize
+// - Pquality.basenote
+// - Pquality.oct
+// - Pquality.smpoct
+// - spectrum at various frequencies (oodles of data)
+void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb)
{
const int samplesize = (((int) 1) << (Pquality.samplesize + 14));
- int spectrumsize = samplesize / 2;
+ const int spectrumsize = samplesize / 2;
float spectrum[spectrumsize];
- int profilesize = 512;
+ const int profilesize = 512;
float profile[profilesize];
- float bwadjust = getprofile(profile, profilesize);
-// for (int i=0;i<profilesize;i++) profile[i]*=profile[i];
+ const float bwadjust = getprofile(profile, profilesize);
float basefreq = 65.406f * powf(2.0f, Pquality.basenote / 2);
if(Pquality.basenote % 2 == 1)
basefreq *= 1.5f;
@@ -584,16 +611,17 @@ void PADnoteParameters::applyparameters(bool lockmutex)
if(samplemax == 0)
samplemax = 1;
- //prepare a BIG FFT stuff
+ //prepare a BIG FFT
FFTwrapper *fft = new FFTwrapper(samplesize);
fft_t *fftfreqs = new fft_t[samplesize / 2];
- float adj[samplemax]; //this is used to compute frequency relation to the base frequency
+ //this is used to compute frequency relation to the base frequency
+ float adj[samplemax];
for(int nsample = 0; nsample < samplemax; ++nsample)
adj[nsample] = (Pquality.oct + 1.0f) * (float)nsample / samplemax;
for(int nsample = 0; nsample < samplemax; ++nsample) {
- float tmp = adj[nsample] - adj[samplemax - 1] * 0.5f;
- float basefreqadjust = powf(2.0f, tmp);
+ const float basefreqadjust =
+ powf(2.0f, adj[nsample] - adj[samplemax - 1] * 0.5f);
if(Pmode == 0)
generatespectrum_bandwidthMode(spectrum,
@@ -606,13 +634,18 @@ void PADnoteParameters::applyparameters(bool lockmutex)
generatespectrum_otherModes(spectrum, spectrumsize,
basefreq * basefreqadjust);
- const int extra_samples = 5; //the last samples contains the first samples (used for linear/cubic interpolation)
+ //the last samples contains the first samples
+ //(used for linear/cubic interpolation)
+ const int extra_samples = 5;
+ PADnoteParameters::Sample newsample;
newsample.smp = new float[samplesize + extra_samples];
newsample.smp[0] = 0.0f;
for(int i = 1; i < spectrumsize; ++i) //randomize the phases
- fftfreqs[i] = std::polar(spectrum[i], (float)RND * 6.29f);
- fft->freqs2smps(fftfreqs, newsample.smp); //that's all; here is the only ifft for the whole sample; no windows are used ;-)
+ fftfreqs[i] = std::polar(spectrum[i], (float)RND * 2 * PI);
+ //that's all; here is the only ifft for the whole sample;
+ //no windows are used ;-)
+ fft->freqs2smps(fftfreqs, newsample.smp);
//normalize(rms)
@@ -622,7 +655,7 @@ void PADnoteParameters::applyparameters(bool lockmutex)
rms = sqrt(rms);
if(rms < 0.000001f)
rms = 1.0f;
- rms *= sqrt(262144.0f / samplesize);
+ rms *= sqrt(262144.0f / samplesize);//262144=2^18
for(int i = 0; i < samplesize; ++i)
newsample.smp[i] *= 1.0f / rms * 50.0f;
@@ -630,42 +663,20 @@ void PADnoteParameters::applyparameters(bool lockmutex)
for(int i = 0; i < extra_samples; ++i)
newsample.smp[i + samplesize] = newsample.smp[i];
- //replace the current sample with the new computed sample
- if(lockmutex) {
- pthread_mutex_lock(mutex);
- deletesample(nsample);
- sample[nsample].smp = newsample.smp;
- sample[nsample].size = samplesize;
- sample[nsample].basefreq = basefreq * basefreqadjust;
- pthread_mutex_unlock(mutex);
- }
- else {
- deletesample(nsample);
- sample[nsample].smp = newsample.smp;
- sample[nsample].size = samplesize;
- sample[nsample].basefreq = basefreq * basefreqadjust;
- }
- newsample.smp = NULL;
+ //yield new sample
+ newsample.size = samplesize;
+ newsample.basefreq = basefreq * basefreqadjust;
+ cb(nsample, newsample);
}
+
+ //Cleanup
delete (fft);
delete[] fftfreqs;
-
- //delete the additional samples that might exists and are not useful
- if(lockmutex) {
- pthread_mutex_lock(mutex);
- for(int i = samplemax; i < PAD_MAX_SAMPLES; ++i)
- deletesample(i);
- pthread_mutex_unlock(mutex);
- }
- else
- for(int i = samplemax; i < PAD_MAX_SAMPLES; ++i)
- deletesample(i);
- ;
}
void PADnoteParameters::export2wav(std::string basefilename)
{
- applyparameters(true);
+ applyparameters();
basefilename += "_PADsynth_";
for(int k = 0; k < PAD_MAX_SAMPLES; ++k) {
if(sample[k].smp == NULL)
diff --git a/src/Params/PADnoteParameters.h b/src/Params/PADnoteParameters.h
@@ -35,12 +35,22 @@
#include "FilterParams.h"
#include "Presets.h"
#include <string>
-#include <pthread.h>
-
+#include <functional>
+
+/**
+ * Parameters for PAD synthesis
+ *
+ * Note - unlike most other parameter objects significant portions of this
+ * object are `owned' by the non-realtime context. The realtime context only
+ * needs the samples generated by the PADsynth algorithm and modulators (ie
+ * envelopes/filters/LFOs) for amplitude, frequency, and filters.
+ * The ownership will be unclear for the time being, but it should be made more
+ * explicit with time.
+ */
class PADnoteParameters:public Presets
{
public:
- PADnoteParameters(FFTwrapper *fft_, pthread_mutex_t *mutex_);
+ PADnoteParameters(FFTwrapper *fft_);
~PADnoteParameters();
void defaults();
@@ -145,17 +155,23 @@ class PADnoteParameters:public Presets
float setPbandwidth(int Pbandwidth); //returns the BandWidth in cents
float getNhr(int n); //gets the n-th overtone position relatively to N harmonic
- void applyparameters(bool lockmutex);
+ void applyparameters(void);
void export2wav(std::string basefilename);
OscilGen *oscilgen;
Resonance *resonance;
- struct {
+ //RT sample data
+ struct Sample {
int size;
float basefreq;
float *smp;
- } sample[PAD_MAX_SAMPLES], newsample;
+ } sample[PAD_MAX_SAMPLES];
+
+ typedef std::function<void(int,PADnoteParameters::Sample&)> callback;
+ void sampleGenerator(PADnoteParameters::callback cb);
+
+ static rtosc::Ports &ports;
private:
void generatespectrum_bandwidthMode(float *spectrum,
@@ -171,7 +187,6 @@ class PADnoteParameters:public Presets
void deletesample(int n);
FFTwrapper *fft;
- pthread_mutex_t *mutex;
};
diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp
@@ -904,6 +904,31 @@ short int OscilGen::get(float *smps, float freqHz, int resonance)
return 0;
}
+///*
+// * Get the oscillator function's harmonics
+// */
+//void OscilGen::getPad(float *smps, float freqHz)
+//{
+// if(needPrepare())
+// prepare();
+//
+// clearAll(outoscilFFTfreqs);
+//
+// const int nyquist = (synth->oscilsize / 2);
+//
+// //Process harmonics
+// for(int i = 1; i < nyquist - 1; ++i)
+// outoscilFFTfreqs[i] = oscilFFTfreqs[i];
+//
+// adaptiveharmonic(outoscilFFTfreqs, freqHz);
+// adaptiveharmonicpostprocess(&outoscilFFTfreqs[1], nyquist - 1);
+//
+// rmsNormalize(outoscilFFTfreqs);
+//
+// for(int i = 1; i < nyquist; ++i)
+// smps[i - 1] = abs(outoscilFFTfreqs, i);
+//}
+//
/*
* Get the spectrum of the oscillator for the UI
diff --git a/src/Synth/Resonance.cpp b/src/Synth/Resonance.cpp
@@ -19,9 +19,10 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <math.h>
-#include <stdlib.h>
+#include <cmath>
+#include <cstdlib>
#include "Resonance.h"
+#include "../Misc/Util.h"
Resonance::Resonance():Presets()
{
@@ -29,11 +30,11 @@ Resonance::Resonance():Presets()
defaults();
}
-Resonance::~Resonance()
+Resonance::~Resonance(void)
{}
-void Resonance::defaults()
+void Resonance::defaults(void)
{
Penabled = 0;
PmaxdB = 20;
@@ -59,37 +60,27 @@ void Resonance::setpoint(int n, unsigned char p)
/*
* Apply the resonance to FFT data
*/
-void Resonance::applyres(int n, fft_t *fftdata, float freq)
+void Resonance::applyres(int n, fft_t *fftdata, float freq) const
{
if(Penabled == 0)
return; //if the resonance is disabled
- float sum = 0.0f,
- l1 = logf(getfreqx(0.0f) * ctlcenter),
- l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
- for(int i = 0; i < N_RES_POINTS; ++i)
- if(sum < Prespoints[i])
- sum = Prespoints[i];
- if(sum < 1.0f)
- sum = 1.0f;
+ const float l1 = logf(getfreqx(0.0f) * ctlcenter),
+ l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
+
+ //Provide an upper bound for resonance
+ const float upper =
+ limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, INFINITY);
for(int i = 1; i < n; ++i) {
- float x = (logf(freq * i) - l1) / l2; //compute where the n-th hamonics fits to the graph
- if(x < 0.0f)
- x = 0.0f;
-
- x *= N_RES_POINTS;
- float dx = x - floor(x);
- x = floor(x);
- int kx1 = (int)x;
- if(kx1 >= N_RES_POINTS)
- kx1 = N_RES_POINTS - 1;
- int kx2 = kx1 + 1;
- if(kx2 >= N_RES_POINTS)
- kx2 = N_RES_POINTS - 1;
+ //compute where the n-th hamonics fits to the graph
+ const float x = limit((logf(freq) - l1) / l2, 0.0f, INFINITY) * N_RES_POINTS;
+ const float dx = x - floor(x);
+ const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
+ const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
float y =
- (Prespoints[kx1]
- * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 127.0f;
+ ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx)
+ - upper) / 127.0f;
y = powf(10.0f, y * PmaxdB / 20.0f);
@@ -103,35 +94,28 @@ void Resonance::applyres(int n, fft_t *fftdata, float freq)
/*
* Gets the response at the frequency "freq"
*/
-
-float Resonance::getfreqresponse(float freq)
+//Requires
+// - resonance data
+// - max resonance
+// - mapping from resonance data to frequency
+float Resonance::getfreqresponse(float freq) const
{
- float l1 = logf(getfreqx(0.0f) * ctlcenter),
- l2 = logf(2.0f) * getoctavesfreq() * ctlbw, sum = 0.0f;
-
- for(int i = 0; i < N_RES_POINTS; ++i)
- if(sum < Prespoints[i])
- sum = Prespoints[i];
- if(sum < 1.0f)
- sum = 1.0f;
-
- float x = (logf(freq) - l1) / l2; //compute where the n-th hamonics fits to the graph
- if(x < 0.0f)
- x = 0.0f;
- x *= N_RES_POINTS;
- float dx = x - floor(x);
- x = floor(x);
- int kx1 = (int)x;
- if(kx1 >= N_RES_POINTS)
- kx1 = N_RES_POINTS - 1;
- int kx2 = kx1 + 1;
- if(kx2 >= N_RES_POINTS)
- kx2 = N_RES_POINTS - 1;
- float result =
- (Prespoints[kx1]
- * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 127.0f;
- result = powf(10.0f, result * PmaxdB / 20.0f);
- return result;
+ const float l1 = logf(getfreqx(0.0f) * ctlcenter),
+ l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
+
+ //Provide an upper bound for resonance
+ const float upper =
+ limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, INFINITY);
+
+ //compute where the n-th hamonics fits to the graph
+ const float x = limit((logf(freq) - l1) / l2, 0.0f, INFINITY) * N_RES_POINTS;
+ const float dx = x - floor(x);
+ const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
+ const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
+ //Interpolate
+ const float result =
+ ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) - upper) / 127.0f;
+ return powf(10.0f, result * PmaxdB / 20.0f);
}
@@ -195,18 +179,16 @@ void Resonance::interpolatepeaks(int type)
/*
* Get the frequency from x, where x is [0..1]; x is the x coordinate
*/
-float Resonance::getfreqx(float x)
+float Resonance::getfreqx(float x) const
{
- if(x > 1.0f)
- x = 1.0f;
- float octf = powf(2.0f, getoctavesfreq());
- return getcenterfreq() / sqrt(octf) * powf(octf, x);
+ const float octf = powf(2.0f, getoctavesfreq());
+ return getcenterfreq() / sqrt(octf) * powf(octf, limit(x, 0.0f, 1.0f));
}
/*
* Get the x coordinate from frequency (used by the UI)
*/
-float Resonance::getfreqpos(float freq)
+float Resonance::getfreqpos(float freq) const
{
return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
}
@@ -214,7 +196,7 @@ float Resonance::getfreqpos(float freq)
/*
* Get the center frequency of the resonance graph
*/
-float Resonance::getcenterfreq()
+float Resonance::getcenterfreq() const
{
return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
}
@@ -222,7 +204,7 @@ float Resonance::getcenterfreq()
/*
* Get the number of octave that the resonance functions applies to
*/
-float Resonance::getoctavesfreq()
+float Resonance::getoctavesfreq() const
{
return 0.25f + 10.0f * Poctavesfreq / 127.0f;
}
@@ -235,9 +217,6 @@ void Resonance::sendcontroller(MidiControllers ctl, float par)
ctlbw = par;
}
-
-
-
void Resonance::add2XML(XMLwrapper *xml)
{
xml->addparbool("enabled", Penabled);
diff --git a/src/Synth/Resonance.h b/src/Synth/Resonance.h
@@ -33,24 +33,24 @@
class Resonance:public Presets
{
public:
- Resonance();
- ~Resonance();
+ Resonance(void);
+ ~Resonance(void);
void setpoint(int n, unsigned char p);
- void applyres(int n, fft_t *fftdata, float freq);
- void smooth();
+ void applyres(int n, fft_t *fftdata, float freq) const;
+ void smooth(void);
void interpolatepeaks(int type);
void randomize(int type);
void add2XML(XMLwrapper *xml);
- void defaults();
+ void defaults(void);
void getfromXML(XMLwrapper *xml);
- float getfreqpos(float freq);
- float getfreqx(float x);
- float getfreqresponse(float freq);
- float getcenterfreq();
- float getoctavesfreq();
+ float getfreqpos(float freq) const;
+ float getfreqx(float x) const;
+ float getfreqresponse(float freq) const;
+ float getcenterfreq(void) const;
+ float getoctavesfreq(void) const;
void sendcontroller(MidiControllers ctl, float par);
//parameters
diff --git a/src/Tests/PadNoteTest.h b/src/Tests/PadNoteTest.h
@@ -71,7 +71,7 @@ class PadNoteTest:public CxxTest::TestSuite
fft = new FFTwrapper(synth->oscilsize);
//prepare the default settings
- PADnoteParameters *defaultPreset = new PADnoteParameters(fft,NULL);
+ PADnoteParameters *defaultPreset = new PADnoteParameters(fft);
//Assert defaults
@@ -92,7 +92,7 @@ class PadNoteTest:public CxxTest::TestSuite
//defaultPreset->defaults();
- defaultPreset->applyparameters(false);
+ defaultPreset->applyparameters();
//verify xml was loaded
///TS_ASSERT(defaultPreset->VoicePar[1].Enabled);
@@ -151,7 +151,7 @@ class PadNoteTest:public CxxTest::TestSuite
#endif
sampleCount += synth->buffersize;
- TS_ASSERT_DELTA(outL[255], 0.0660f, 0.0001f);
+ TS_ASSERT_DELTA(outL[255], 0.0660f, 0.0005f);
note->relasekey();
@@ -159,11 +159,11 @@ class PadNoteTest:public CxxTest::TestSuite
note->noteout(outL, outR);
sampleCount += synth->buffersize;
- TS_ASSERT_DELTA(outL[255], -0.0729f, 0.0001f);
+ TS_ASSERT_DELTA(outL[255], -0.0729f, 0.0005f);
note->noteout(outL, outR);
sampleCount += synth->buffersize;
- TS_ASSERT_DELTA(outL[255], 0.0613f, 0.0001f);
+ TS_ASSERT_DELTA(outL[255], 0.0613f, 0.0005f);
note->noteout(outL, outR);
sampleCount += synth->buffersize;
@@ -171,7 +171,7 @@ class PadNoteTest:public CxxTest::TestSuite
note->noteout(outL, outR);
sampleCount += synth->buffersize;
- TS_ASSERT_DELTA(outL[255], -0.0070f, 0.0001f);
+ TS_ASSERT_DELTA(outL[255], -0.0070f, 0.0005f);
while(!note->finished()) {
note->noteout(outL, outR);
diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl
@@ -530,7 +530,7 @@ pthread_mutex_unlock(&master->mutex);}
} {
Fl_Group partui {open
xywh {0 310 383 175}
- code0 {o->init(master->part[0],master,0,bankui);}
+ code0 {o->init(master->part[0],"/part0/", master,0,bankui);}
code1 {o->show();}
class PartUI
} {}
@@ -806,7 +806,9 @@ partuigroup->remove(partui);
delete partui;
partui=new PartUI(0,0,765,525);
partuigroup->add(partui);
-partui->init(master->part[nval],master,nval,bankui);
+char buffer[1024];
+snprintf(buffer, 1024, "/part%d/", nval);
+partui->init(master->part[nval], buffer, master, nval, bankui);
partui->redraw();
o->redraw();
npart=nval;
@@ -1586,7 +1588,7 @@ simplesyseffsend->value(master->Psysefxvol[nsyseff][npart]);} {}
//load the data
int result=master->loadXML(filename);
- master->applyparameters(false);
+ master->applyparameters();
pthread_mutex_unlock(&master->mutex);
npartcounter->value(1);
diff --git a/src/UI/PADnoteUI.fl b/src/UI/PADnoteUI.fl
@@ -1,52 +1,62 @@
# data file for the Fltk User Interface Designer (fluid)
-version 1.0110
+version 1.0300
header_name {.h}
code_name {.cc}
-decl {\#include "../Params/PADnoteParameters.h"} {public
+decl {\#include "../Params/PADnoteParameters.h"} {public local
}
-decl {\#include "../Misc/Util.h"} {public
+decl {\#include "../Misc/Util.h"} {public local
}
-decl {\#include "../Misc/Master.h"} {public
+decl {\#include "../Misc/Master.h"} {public local
}
-decl {\#include "ResonanceUI.h"} {public
+decl {\#include "../Misc/MiddleWare.h"} {public local
}
-decl {\#include <FL/Fl_Box.H>} {public
+decl {\#include "ResonanceUI.h"} {public local
}
-decl {\#include <FL/Fl_Group.H>} {public
+decl {\#include <FL/Fl_Box.H>} {public local
}
-decl {\#include <FL/Fl_File_Chooser.H>} {public
+decl {\#include <FL/Fl_Group.H>} {public local
}
-decl {\#include <math.h>} {}
+decl {\#include <FL/Fl_File_Chooser.H>} {public local
+}
+
+decl {\#include <math.h>} {private local
+}
-decl {\#include <stdio.h>} {}
+decl {\#include <stdio.h>} {private local
+}
-decl {\#include <stdlib.h>} {}
+decl {\#include <stdlib.h>} {private local
+}
-decl {\#include <string.h>} {}
+decl {\#include <string.h>} {private local
+}
-decl {\#include "WidgetPDial.h"} {public
+decl {\#include <string>} {selected public local
}
-decl {\#include "EnvelopeUI.h"} {public
+decl {\#include "WidgetPDial.h"} {public local
}
-decl {\#include "LFOUI.h"} {public
+decl {\#include "EnvelopeUI.h"} {public local
}
-decl {\#include "FilterUI.h"} {public
+decl {\#include "LFOUI.h"} {public local
}
-decl {\#include "OscilGenUI.h"} {public
+decl {\#include "FilterUI.h"} {public local
}
-decl {\#include "PresetsUI.h"} {public
+decl {\#include "OscilGenUI.h"} {public local
+}
+
+decl {\#include "PresetsUI.h"} {public local
}
class PADnoteHarmonicProfile {: {public Fl_Box}
@@ -128,8 +138,9 @@ fl_line(ox+lx/2+rbw,oy,ox+lx/2+rbw,oy+ly-1);
fl_line_style(0);} {}
}
- decl {Master *master;} {}
- decl {PADnoteParameters *pars;} {public
+ decl {Master *master;} {private local
+ }
+ decl {PADnoteParameters *pars;} {public local
}
}
@@ -223,16 +234,18 @@ for (int i=0;i<lx;i++){
};} {}
}
- decl {Master *master;} {}
- decl {PADnoteParameters *pars;} {public
+ decl {Master *master;} {private local
+ }
+ decl {PADnoteParameters *pars;} {public local
}
}
class PADnoteUI {open : {public PresetsUI_}
} {
- Function {PADnoteUI(PADnoteParameters *parameters,Master *master_)} {open
+ Function {PADnoteUI(PADnoteParameters *parameters, std::string location_, Master *master_)} {open
} {
- code {pars=parameters;
+ code {location=location_;
+pars=parameters;
master=master_;
oscui=NULL;
resui=new ResonanceUI(pars->resonance);
@@ -242,7 +255,7 @@ make_window();} {}
} {
Fl_Window padnotewindow {
label {PAD synth Parameters} open
- xywh {294 392 535 435} type Double visible
+ xywh {297 415 535 435} type Double visible
} {
Fl_Tabs {} {
callback {if (o->value()!=harmonicstructuregroup) applybutton->hide();
@@ -250,7 +263,7 @@ make_window();} {}
xywh {0 0 535 395} box UP_FRAME
} {
Fl_Group harmonicstructuregroup {
- label {Harmonic Structure} open selected
+ label {Harmonic Structure} open
xywh {0 20 535 375} box UP_FRAME
} {
Fl_Group bwprofilegroup {
@@ -961,7 +974,7 @@ hprofile->redraw();}
}
Fl_Button applybutton {
label {Apply Changes}
- callback {pars->applyparameters(true);
+ callback {MiddleWare::preparePadSynth(location.c_str(), pars);
o->color(FL_GRAY);
if (oscui!=NULL) {
oscui->applybutton->color(FL_GRAY);
@@ -1092,7 +1105,7 @@ hprofile->redraw();
overtonepos->redraw();
osc->redraw();
-pars->applyparameters(true);
+MiddleWare::preparePadSynth(location.c_str(), pars);
applybutton->color(FL_GRAY);
applybutton->parent()->redraw();} {}
}
@@ -1103,14 +1116,16 @@ delete(resui);
padnotewindow->hide();
delete(padnotewindow);} {}
}
- decl {PADnoteParameters *pars;} {public
+ decl {PADnoteParameters *pars;} {public local
+ }
+ decl {Master *master;} {public local
}
- decl {Master *master;} {public
+ decl {OscilEditor *oscui;} {public local
}
- decl {OscilEditor *oscui;} {public
+ decl {Oscilloscope *osc;} {public local
}
- decl {Oscilloscope *osc;} {public
+ decl {ResonanceUI *resui;} {public local
}
- decl {ResonanceUI *resui;} {public
+ decl {std::string location;} {private local
}
}
diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl
@@ -1,45 +1,50 @@
# data file for the Fltk User Interface Designer (fluid)
-version 1.0110
+version 1.0300
header_name {.h}
code_name {.cc}
-decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {}
+decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {private local
+}
+
+decl {//License: GNU GPL version 2 or later} {private local
+}
-decl {//License: GNU GPL version 2 or later} {}
+decl {\#include <stdlib.h>} {public local
+}
-decl {\#include <stdlib.h>} {public
+decl {\#include <stdio.h>} {public local
}
-decl {\#include <stdio.h>} {public
+decl {\#include <string.h>} {public local
}
-decl {\#include <string.h>} {public
+decl {\#include <string>} {selected public local
}
-decl {\#include "WidgetPDial.h"} {public
+decl {\#include "WidgetPDial.h"} {public local
}
-decl {\#include "EffUI.h"} {public
+decl {\#include "EffUI.h"} {public local
}
-decl {\#include "BankUI.h"} {public
+decl {\#include "BankUI.h"} {public local
}
-decl {\#include "ADnoteUI.h"} {public
+decl {\#include "ADnoteUI.h"} {public local
}
-decl {\#include "SUBnoteUI.h"} {public
+decl {\#include "SUBnoteUI.h"} {public local
}
-decl {\#include "PADnoteUI.h"} {public
+decl {\#include "PADnoteUI.h"} {public local
}
-decl {\#include "../Misc/Config.h"} {public
+decl {\#include "../Misc/Config.h"} {public local
}
-decl {\#include "../Misc/Master.h"} {public
+decl {\#include "../Misc/Master.h"} {public local
}
-decl {\#include "../Misc/Part.h"} {public
+decl {\#include "../Misc/Part.h"} {public local
}
class PartSysEffSend {open : {public Fl_Group}
@@ -47,7 +52,7 @@ class PartSysEffSend {open : {public Fl_Group}
Function {make_window()} {open private
} {
Fl_Window syseffsend {
- private xywh {589 129 100 100} type Double box NO_BOX
+ private xywh {592 152 100 100} type Double box NO_BOX
class Fl_Group visible
} {
Fl_Dial {} {
@@ -78,9 +83,12 @@ end();} {}
code {syseffsend->hide();
//delete(syseffsend);} {}
}
- decl {Master *master;} {}
- decl {int neff;} {}
- decl {int npart;} {}
+ decl {Master *master;} {private local
+ }
+ decl {int neff;} {private local
+ }
+ decl {int npart;} {private local
+ }
}
class PartKitItem {open : {public Fl_Group}
@@ -88,7 +96,7 @@ class PartKitItem {open : {public Fl_Group}
Function {make_window()} {open private
} {
Fl_Window partkititem {
- private xywh {473 406 670 100} type Double box NO_BOX
+ private xywh {476 429 670 100} type Double box NO_BOX
class Fl_Group visible
} {
Fl_Group partkititemgroup {
@@ -262,11 +270,16 @@ end();} {}
code {partkititem->hide();
//delete(partkititem);} {}
}
- decl {Part *part;} {}
- decl {int n;} {}
- decl {Master *master;} {}
- decl {char label[10];} {}
- decl {class PartUI *partui;} {}
+ decl {Part *part;} {private local
+ }
+ decl {int n;} {private local
+ }
+ decl {Master *master;} {private local
+ }
+ decl {char label[10];} {private local
+ }
+ decl {class PartUI *partui;} {private local
+ }
}
class PartUI {open : {public Fl_Group}
@@ -274,7 +287,7 @@ class PartUI {open : {public Fl_Group}
Function {make_window()} {open private
} {
Fl_Window partgroup {open
- private xywh {688 264 385 180} type Double box NO_BOX
+ private xywh {691 287 385 180} type Double box NO_BOX
class Fl_Group visible
} {
Fl_Group partgroupui {open
@@ -452,7 +465,7 @@ if (part->Penabled==0) partgroupui->deactivate();
}
Fl_Window ctlwindow {
label Controllers open
- private xywh {777 261 500 130} type Double box NO_BOX visible
+ private xywh {777 284 500 130} type Double box NO_BOX visible
} {
Fl_Check_Button {} {
label Expr
@@ -634,8 +647,8 @@ else {propta->deactivate();proptb->deactivate();}}
}
}
Fl_Window partfx {
- label {Part's Insert Effects} selected
- private xywh {554 660 390 145} type Double box NO_BOX visible
+ label {Part's Insert Effects}
+ private xywh {557 683 390 145} type Double box NO_BOX visible
} {
Fl_Counter inseffnocounter {
label {FX No.}
@@ -756,7 +769,7 @@ pthread_mutex_unlock(&master->mutex);}
}
Fl_Window instrumentkitlist {
label {Instrument Kit} open
- xywh {586 566 670 370} type Double box NO_BOX visible
+ xywh {589 589 670 370} type Double box NO_BOX visible
} {
Fl_Button {} {
label {Close Window}
@@ -837,7 +850,7 @@ if (part->Pkitmode==0) {
}
Fl_Window instrumenteditwindow {
label {Instrument Edit} open
- xywh {247 621 395 360} type Double box NO_BOX visible
+ xywh {250 621 395 360} type Double box NO_BOX visible
} {
Fl_Group {} {
xywh {0 220 395 110} box UP_FRAME
@@ -1020,8 +1033,9 @@ subnoteui=NULL;
padnoteui=NULL;
lastkititem=-1;} {}
}
- Function {init(Part *part_,Master *master_,int npart_,BankUI *bankui_)} {} {
+ Function {init(Part *part_, std::string part_path_, Master *master_,int npart_,BankUI *bankui_)} {} {
code {bankui=bankui_;
+ part_path = part_path_;
part=part_;
npart=npart_;
master=master_;
@@ -1075,8 +1089,11 @@ if (kititem!=lastkititem){
if (part->kit[kititem].subpars!=NULL)
subnoteui=new SUBnoteUI(part->kit[kititem].subpars);
- if (part->kit[kititem].padpars!=NULL)
- padnoteui=new PADnoteUI(part->kit[kititem].padpars,master);
+ if (part->kit[kititem].padpars!=NULL) {
+ char buffer[1024];
+ snprintf(buffer, 1024, "%skit%d/padpars/", part_path.c_str(), kititem);
+ padnoteui=new PADnoteUI(part->kit[kititem].padpars, buffer, master);
+ }
};
@@ -1106,15 +1123,28 @@ delete(instrumentkitlist);
instrumenteditwindow->hide();
delete(instrumenteditwindow);} {}
}
- decl {Part *part;} {}
- decl {Master *master;} {}
- decl {BankUI *bankui;} {}
- decl {ADnoteUI *adnoteui;} {}
- decl {SUBnoteUI *subnoteui;} {}
- decl {PADnoteUI *padnoteui;} {}
- decl {PartSysEffSend *psyef[NUM_SYS_EFX];} {}
- decl {int npart;} {}
- decl {int ninseff;} {}
- decl {int lastkititem;} {}
- decl {PartKitItem *partkititem[NUM_KIT_ITEMS];} {}
+ decl {Part *part;} {private local
+ }
+ decl {Master *master;} {private local
+ }
+ decl {BankUI *bankui;} {private local
+ }
+ decl {ADnoteUI *adnoteui;} {private local
+ }
+ decl {SUBnoteUI *subnoteui;} {private local
+ }
+ decl {PADnoteUI *padnoteui;} {private local
+ }
+ decl {PartSysEffSend *psyef[NUM_SYS_EFX];} {private local
+ }
+ decl {int npart;} {private local
+ }
+ decl {int ninseff;} {private local
+ }
+ decl {int lastkititem;} {private local
+ }
+ decl {PartKitItem *partkititem[NUM_KIT_ITEMS];} {private local
+ }
+ decl {std::string part_path;} {private local
+ }
}
diff --git a/src/main.cpp b/src/main.cpp
@@ -35,6 +35,7 @@
#include <lo/lo.h>
#include <rtosc/ports.h>
#include <rtosc/thread-link.h>
+#include "Params/PADnoteParameters.h"
#include "DSP/FFTwrapper.h"
#include "Misc/Master.h"