Browse Source

Update zynaddsubfx

tags/1.9.7
falkTX 9 years ago
parent
commit
48f4cd1ecf
68 changed files with 1534 additions and 422 deletions
  1. +8
    -3
      data/copy-zynaddsubfx
  2. +5
    -1
      source/native-plugins/zynaddsubfx-fx.cpp
  3. +0
    -10
      source/native-plugins/zynaddsubfx-src.cpp
  4. +0
    -7
      source/native-plugins/zynaddsubfx-ui.cpp
  5. +2
    -0
      source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp
  6. +2
    -0
      source/native-plugins/zynaddsubfx/DSP/Unison.cpp
  7. +13
    -6
      source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp
  8. +13
    -4
      source/native-plugins/zynaddsubfx/Effects/Chorus.cpp
  9. +34
    -4
      source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp
  10. +46
    -58
      source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp
  11. +3
    -1
      source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h
  12. +78
    -0
      source/native-plugins/zynaddsubfx/Effects/EQ.cpp
  13. +3
    -1
      source/native-plugins/zynaddsubfx/Effects/EQ.h
  14. +8
    -2
      source/native-plugins/zynaddsubfx/Effects/Echo.cpp
  15. +4
    -2
      source/native-plugins/zynaddsubfx/Effects/Effect.cpp
  16. +3
    -1
      source/native-plugins/zynaddsubfx/Effects/Effect.h
  17. +49
    -12
      source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp
  18. +38
    -18
      source/native-plugins/zynaddsubfx/Effects/Phaser.cpp
  19. +9
    -3
      source/native-plugins/zynaddsubfx/Effects/Reverb.cpp
  20. +17
    -1
      source/native-plugins/zynaddsubfx/Misc/Bank.cpp
  21. +1
    -0
      source/native-plugins/zynaddsubfx/Misc/Bank.h
  22. +128
    -6
      source/native-plugins/zynaddsubfx/Misc/BankDb.cpp
  23. +8
    -3
      source/native-plugins/zynaddsubfx/Misc/BankDb.h
  24. +46
    -1
      source/native-plugins/zynaddsubfx/Misc/Config.cpp
  25. +1
    -0
      source/native-plugins/zynaddsubfx/Misc/Config.h
  26. +63
    -31
      source/native-plugins/zynaddsubfx/Misc/Master.cpp
  27. +8
    -0
      source/native-plugins/zynaddsubfx/Misc/Master.h
  28. +45
    -12
      source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp
  29. +1
    -0
      source/native-plugins/zynaddsubfx/Misc/Microtonal.h
  30. +322
    -14
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
  31. +7
    -6
      source/native-plugins/zynaddsubfx/Misc/Part.cpp
  32. +1
    -1
      source/native-plugins/zynaddsubfx/Misc/Schema.cpp
  33. +1
    -0
      source/native-plugins/zynaddsubfx/Misc/Util.cpp
  34. +3
    -0
      source/native-plugins/zynaddsubfx/Misc/Util.h
  35. +21
    -14
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp
  36. +12
    -3
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h
  37. +32
    -11
      source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp
  38. +1
    -0
      source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h
  39. +2
    -1
      source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp
  40. +31
    -16
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp
  41. +6
    -5
      source/native-plugins/zynaddsubfx/Params/Controller.cpp
  42. +83
    -21
      source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp
  43. +5
    -0
      source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h
  44. +22
    -13
      source/native-plugins/zynaddsubfx/Params/FilterParams.cpp
  45. +23
    -19
      source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp
  46. +11
    -8
      source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp
  47. +17
    -1
      source/native-plugins/zynaddsubfx/Synth/ADnote.cpp
  48. +1
    -0
      source/native-plugins/zynaddsubfx/Synth/ADnote.h
  49. +4
    -12
      source/native-plugins/zynaddsubfx/Synth/Envelope.cpp
  50. +0
    -2
      source/native-plugins/zynaddsubfx/Synth/Envelope.h
  51. +24
    -8
      source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp
  52. +4
    -0
      source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp
  53. +5
    -0
      source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp
  54. +1
    -1
      source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp
  55. +2
    -2
      source/native-plugins/zynaddsubfx/UI/EffUI.fl
  56. +3
    -1
      source/native-plugins/zynaddsubfx/UI/FilterUI.fl
  57. +3
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Value.H
  58. +21
    -2
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Value.cpp
  59. +2
    -2
      source/native-plugins/zynaddsubfx/UI/MasterUI.fl
  60. +16
    -21
      source/native-plugins/zynaddsubfx/UI/NSM.C
  61. +3
    -1
      source/native-plugins/zynaddsubfx/UI/NSM.H
  62. +1
    -1
      source/native-plugins/zynaddsubfx/UI/guimain.cpp
  63. +146
    -18
      source/native-plugins/zynaddsubfx/main.cpp
  64. +34
    -1
      source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp
  65. +1
    -1
      source/native-plugins/zynaddsubfx/rtosc/port-sugar.h
  66. +5
    -5
      source/native-plugins/zynaddsubfx/rtosc/ports.h
  67. +3
    -17
      source/native-plugins/zynaddsubfx/version.cpp
  68. +19
    -7
      source/native-plugins/zynaddsubfx/zyn-version.h

+ 8
- 3
data/copy-zynaddsubfx View File

@@ -2,8 +2,8 @@

set -e

ORIG_ZYN_DIR="/home/falktx/Projects/FOSS/GIT-mine/zynaddsubfx-code"
CARLA_ZYN_DIR="/home/falktx/Projects/FOSS/GIT-mine/Carla/source/native-plugins/zynaddsubfx"
ORIG_ZYN_DIR="/home/falktx/FOSS/GIT-mine/falkTX/zynaddsubfx"
CARLA_ZYN_DIR="/home/falktx/FOSS/GIT-mine/falkTX/Carla/source/native-plugins/zynaddsubfx"

rm -f $CARLA_ZYN_DIR/*.cpp
rm -f $CARLA_ZYN_DIR/*.h
@@ -36,7 +36,12 @@ cp $ORIG_ZYN_DIR/tlsf/*.c $CARLA_ZYN_DIR/tlsf/
rm $CARLA_ZYN_DIR/*/CMakeLists.txt
rm $CARLA_ZYN_DIR/UI/zynaddsubfx.xpm

sed -i "s|emplace_uint32(|emplace_uint32_cpp(|" $CARLA_ZYN_DIR/rtosc/cpp/subtree-serialize.cpp
cp $ORIG_ZYN_DIR/src/zyn-version.h.in $CARLA_ZYN_DIR/zyn-version.h
sed -i 's|${VERSION_MAJOR}|3|' $CARLA_ZYN_DIR/zyn-version.h
sed -i 's|${VERSION_MINOR}|0|' $CARLA_ZYN_DIR/zyn-version.h
sed -i 's|${VERSION_REVISION}|1|' $CARLA_ZYN_DIR/zyn-version.h

sed -i "s|emplace_uint32(|emplace_uint32_cpp(|" $CARLA_ZYN_DIR/rtosc/cpp/subtree-serialize.cpp
sed -i "s|../../include/rtosc/|../|" $CARLA_ZYN_DIR/rtosc/cpp/*.cpp
sed -i "s|../../tlsf/tlsf.h|tlsf/tlsf.h|" $CARLA_ZYN_DIR/Misc/Allocator.cpp
sed -i "s|../src/globals.h|globals.h|" $CARLA_ZYN_DIR/Misc/Config.cpp


+ 5
- 1
source/native-plugins/zynaddsubfx-fx.cpp View File

@@ -45,6 +45,7 @@ protected:
fProgramCount(programCount),
fBufferSize(getBufferSize()),
fSampleRate(getSampleRate()),
fFilterParams(nullptr),
fEffect(nullptr),
efxoutl(nullptr),
efxoutr(nullptr)
@@ -191,7 +192,9 @@ protected:
delete fEffect;
}

EffectParams pars(fAllocator.getObject(), false, efxoutl, efxoutr, 0, static_cast<uint>(fSampleRate), static_cast<int>(fBufferSize));
EffectParams pars(fAllocator.getObject(), false, efxoutl, efxoutr, 0,
static_cast<uint>(fSampleRate), static_cast<int>(fBufferSize), &fFilterParams);

fEffect = new ZynFX(pars);

if (firstInit)
@@ -217,6 +220,7 @@ protected:
uint32_t fBufferSize;
double fSampleRate;

FilterParams fFilterParams;
Effect* fEffect;
float* efxoutl;
float* efxoutr;


+ 0
- 10
source/native-plugins/zynaddsubfx-src.cpp View File

@@ -17,16 +17,6 @@

#include "CarlaDefines.h"

#ifdef CARLA_OS_WIN
# include <cmath>
# define errx(...) {}
# define warnx(...) {}
# define index strchr
# define rindex strrchr
#else
# include <err.h>
#endif

#define PLUGINVERSION
#define SOURCE_DIR "/usr/share/zynaddsubfx/examples"
#undef override


+ 0
- 7
source/native-plugins/zynaddsubfx-ui.cpp View File

@@ -17,13 +17,6 @@

#include "CarlaPipeUtils.cpp"

#ifdef CARLA_OS_WIN
# define errx(...)
# define warnx(...)
#else
# include <err.h>
#endif

#define PLUGINVERSION
#define SOURCE_DIR "/usr/share/zynaddsubfx"
#undef override


+ 2
- 0
source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp View File

@@ -18,6 +18,8 @@
#include "../Misc/Util.h"
#include "SVFilter.h"

#define errx(...) {}
#define warnx(...) {}
#ifndef errx
#include <err.h>
#endif


+ 2
- 0
source/native-plugins/zynaddsubfx/DSP/Unison.cpp View File

@@ -18,6 +18,8 @@
#include "Unison.h"
#include "globals.h"

#define errx(...) {}
#define warnx(...) {}
#ifndef errx
#include <err.h>
#endif


+ 13
- 6
source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp View File

@@ -20,22 +20,29 @@
using std::complex;

#define rObject Alienwah
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports Alienwah::ports = {
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4)
{"preset::i", rProp(parameter)
rOptions(wah 1, wah 2, wah 3, wah 4)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
rEffPar(PLFOtype, 4, rShort("shape"), "LFO Shape"),
rEffParTF(PStereo, 5, rShort("stereo"), "Stereo/Mono Mode"),
rEffPar(PLFOtype, 4, rShort("shape"),
rOptions(sine, triangle), "LFO Shape"),
rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
rEffPar(Pfeedback, 7, rShort("fb"), "Feedback"),
rEffPar(Pdelay, 8, rShort("delay"), "Delay"),
rEffPar(Pdelay, 8, rLinear(1,100), rShort("delay"), "Delay"),
rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"),
rEffPar(Pphase, 10, rShort("phase"), "Phase"),
};
@@ -159,7 +166,7 @@ void Alienwah::setdelay(unsigned char _Pdelay)
{
memory.devalloc(oldl);
memory.devalloc(oldr);
Pdelay = (_Pdelay >= MAX_ALIENWAH_DELAY) ? MAX_ALIENWAH_DELAY : _Pdelay;
Pdelay = limit<int>(_Pdelay, 1, MAX_ALIENWAH_DELAY);
oldl = memory.valloc<complex<float>>(Pdelay);
oldr = memory.valloc<complex<float>>(Pdelay);
cleanup();


+ 13
- 4
source/native-plugins/zynaddsubfx/Effects/Chorus.cpp View File

@@ -21,19 +21,28 @@
using namespace std;

#define rObject Chorus
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports Chorus::ports = {
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4)
{"preset::i", rProp(parameter)
rOptions(Chorus1, Chorus2, Chorus3, Celeste1, Celeste2,
Flange1, Flange2, Flange3, Flange4, Flange5)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);

rEnd},
//Pvolume/Ppanning are common
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
rEffPar(PLFOtype, 4, rShort("shape"), "LFO Shape"),
rEffParTF(PStereo,5, rShort("stereo"), "Stereo/Mono Mode"),
rEffPar(PLFOtype, 4, rShort("shape"),
rOptions(sine, tri), "LFO Shape"),
rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
rEffPar(Pdelay, 7, rShort("delay"), "Delay"),
rEffPar(Pfeedback,8, rShort("fb"), "Feedback"),


+ 34
- 4
source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp View File

@@ -20,25 +20,55 @@
#include <rtosc/port-sugar.h>

#define rObject Distorsion
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports Distorsion::ports = {
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4)
{"preset::i", rProp(parameter)
rOptions(Overdrive 1, Overdrive 2, A. Exciter 1, A. Exciter 2, Guitar Amp,
Quantisize)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
rEffPar(Plrcross, 2, rShort("l/r") "Left/Right Crossover"),
rEffPar(Plrcross, 2, rShort("l/r"), "Left/Right Crossover"),
rEffPar(Pdrive, 3, rShort("drive"), "Input amplification"),
rEffPar(Plevel, 4, rShort("output"), "Output amplification"),
rEffPar(Ptype, 5, rShort("type"), "Distortion Shape"),
rEffPar(Ptype, 5, rShort("type"),
rOptions(Arctangent, Asymmetric, Pow, Sine, Quantisize,
Zigzag, Limiter, Upper Limiter, Lower Limiter,
Inverse Limiter, Clip, Asym2, Pow2, sigmoid),
"Distortion Shape"),
rEffParTF(Pnegate, 6, rShort("neg"), "Negate Signal"),
rEffPar(Plpf, 7, rShort("lpf"), "Low Pass Cutoff"),
rEffPar(Phpf, 8, rShort("hpf"), "High Pass Cutoff"),
rEffParTF(Pstereo, 9, rShort("stereo"), "Stereo"),
rEffParTF(Pprefiltering, 10, rShort("p.filt"),
"Filtering before/after non-linearity"),
{"waveform:", 0, 0, [](const char *, rtosc::RtData &d)
{
Distorsion &dd = *(Distorsion*)d.obj;
float buffer[128];
rtosc_arg_t args[128];
char arg_str[128+1] = {0};

for(int i=0; i<128; ++i)
buffer[i] = 2*(i/128.0)-1;

waveShapeSmps(sizeof(buffer), buffer, dd.Ptype + 1, dd.Pdrive);

for(int i=0; i<128; ++i) {
arg_str[i] = 'f';
args[i].f = buffer[i];
}

d.replyArray(d.loc, arg_str, args);
}},
};
#undef rBegin
#undef rEnd


+ 46
- 58
source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp View File

@@ -11,6 +11,7 @@
of the License, or (at your option) any later version.
*/

#include <cassert>
#include <cmath>
#include <iostream>
#include "DynamicFilter.h"
@@ -20,47 +21,29 @@
#include <rtosc/port-sugar.h>

#define rObject DynamicFilter
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports DynamicFilter::ports = {
{"preset::i", rOptions(WahWah, AutoWah, Sweep, VocalMorph1, VocalMorph1)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
{"Pfreq::i", rShort("freq")
rDoc("Effect Frequency"), 0,
rBegin;
rEnd},
{"Pfreqrnd::i", rShort("rand")
rDoc("Frequency Randomness"), 0,
rBegin;
rEnd},
{"PLFOtype::i", rShort("shape")
rDoc("LFO Shape"), 0,
rBegin;
rEnd},
{"PStereo::T:F", rShort("stereo")
rDoc("Stereo/Mono Mode"), 0,
rBegin;
rEnd},
{"Pdepth::i", rShort("depth")
rDoc("LFO Depth"), 0,
rBegin;
rEnd},
{"Pampsns::i", rShort("sense")
rDoc("how the filter varies according to the input amplitude"), 0,
rBegin;
rEnd},
{"Pampsnsinv::T:F", rShort("sns.inv")
rDoc("Sense Inversion"), 0,
rBegin;
rEnd},
{"Pampsmooth::i", rShort("smooth")
rDoc("how smooth the input amplitude changes the filter"), 0,
rBegin;
rEnd},
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
rEffPar(PLFOtype, 4, rShort("shape"),
rOptions(sin, tri), "LFO Shape"),
rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
rEffPar(Pampsns, 7, rShort("sense"), "how the filter varies according to the input amplitude"),
rEffPar(Pampsnsinv, 8, rShort("sns.inv"), "Sense Inversion"),
rEffPar(Pampsmooth, 9, rShort("smooth"), "how smooth the input amplitude changes the filter"),
};
#undef rBegin
#undef rEnd
@@ -77,14 +60,13 @@ DynamicFilter::DynamicFilter(EffectParams pars, const AbsTime *time)
filterl(NULL),
filterr(NULL)
{
filterpars = memory.alloc<FilterParams>(0,0,0,time);
setpreset(Ppreset);
filterpars = pars.filterpars;
setpreset(Ppreset, pars.filterprotect);
cleanup();
}

DynamicFilter::~DynamicFilter()
{
memory.dealloc(filterpars);
memory.dealloc(filterl);
memory.dealloc(filterr);
}
@@ -188,28 +170,8 @@ void DynamicFilter::reinitfilter(void)
}
}

void DynamicFilter::setpreset(unsigned char npreset)
void DynamicFilter::setfilterpreset(unsigned char npreset)
{
const int PRESET_SIZE = 10;
const int NUM_PRESETS = 5;
unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
//WahWah
{110, 64, 80, 0, 0, 64, 0, 90, 0, 60},
//AutoWah
{110, 64, 70, 0, 0, 80, 70, 0, 0, 60},
//Sweep
{100, 64, 30, 0, 0, 50, 80, 0, 0, 60},
//VocalMorph1
{110, 64, 80, 0, 0, 64, 0, 64, 0, 60},
//VocalMorph1
{127, 64, 50, 0, 0, 96, 64, 0, 0, 60}
};

if(npreset >= NUM_PRESETS)
npreset = NUM_PRESETS - 1;
for(int n = 0; n < PRESET_SIZE; ++n)
changepar(n, presets[npreset][n]);

filterpars->defaults();

switch(npreset) {
@@ -298,10 +260,36 @@ void DynamicFilter::setpreset(unsigned char npreset)
// for (int i=0;i<5;i++){
// printf("freq=%d amp=%d q=%d\n",filterpars->Pvowels[0].formants[i].freq,filterpars->Pvowels[0].formants[i].amp,filterpars->Pvowels[0].formants[i].q);
// };
reinitfilter();
}

void DynamicFilter::setpreset(unsigned char npreset, bool protect)
{
const int PRESET_SIZE = 10;
const int NUM_PRESETS = 5;
unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
//WahWah
{110, 64, 80, 0, 0, 64, 0, 90, 0, 60},
//AutoWah
{110, 64, 70, 0, 0, 80, 70, 0, 0, 60},
//Sweep
{100, 64, 30, 0, 0, 50, 80, 0, 0, 60},
//VocalMorph1
{110, 64, 80, 0, 0, 64, 0, 64, 0, 60},
//VocalMorph1
{127, 64, 50, 0, 0, 96, 64, 0, 0, 60}
};

if(npreset >= NUM_PRESETS)
npreset = NUM_PRESETS - 1;
for(int n = 0; n < PRESET_SIZE; ++n)
changepar(n, presets[npreset][n]);

if(insertion == 0) //lower the volume if this is system effect
changepar(0, presets[npreset][0] * 0.5f);
Ppreset = npreset;
reinitfilter();
if(!protect)
setfilterpreset(npreset);
}




+ 3
- 1
source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h View File

@@ -25,7 +25,8 @@ class DynamicFilter:public Effect
~DynamicFilter();
void out(const Stereo<float *> &smp);

void setpreset(unsigned char npreset);
void setpreset(unsigned char npreset) { setpreset(npreset, false); };
void setpreset(unsigned char npreset, bool protect);
void changepar(int npar, unsigned char value);
unsigned char getpar(int npar) const;
void cleanup(void);
@@ -45,6 +46,7 @@ class DynamicFilter:public Effect
void setdepth(unsigned char _Pdepth);
void setampsns(unsigned char _Pampsns);

void setfilterpreset(unsigned char npreset);
void reinitfilter(void);

//Internal Values


+ 78
- 0
source/native-plugins/zynaddsubfx/Effects/EQ.cpp View File

@@ -12,10 +12,88 @@
*/

#include <cmath>
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>
#include "EQ.h"
#include "../DSP/AnalogFilter.h"
#include "../Misc/Allocator.h"

using rtosc::RtData;
#define rObject EQ
#define rBegin [](const char *msg, RtData &d) {\
rObject *obj = (rObject*)d.obj;
#define rEQ(offset) \
int nfilt = atoi(msg-2); \
int id = 10+nfilt*5+offset; \
if(rtosc_narguments(msg)) \
obj->changepar(id, rtosc_argument(msg,0).i);\
else \
d.reply(d.loc, "i", obj->getpar(id))

#define rEnd }

static rtosc::Ports filterports {
{"Ptype::i", rProp(parameter) rOptions(Off, LP1, HP1, LP2,
HP2, BP, notch, peak, l.shelf, h.shelf)
rShort("type") rDoc("Filter Type"), 0,
rBegin;
rEQ(0);
rEnd},
{"Pfreq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
rShort("freq"), 0,
rBegin;
rEQ(1);
rEnd},
{"Pgain::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
rShort("gain"), 0,
rBegin;
rEQ(2);
rEnd},
{"Pq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
rShort("q") rDoc("Resonance/Bandwidth"), 0,
rBegin;
rEQ(3);
rEnd},
{"Pstages::i", rProp(parameter) rMap(min, 0) rMap(max, 4)
rShort("stages") rDoc("Additional filter stages"), 0,
rBegin;
rEQ(4);
rEnd},
};

rtosc::Ports EQ::ports = {
{"filter#8/", 0, &filterports,
rBegin;
(void)obj;
SNIP;
filterports.dispatch(msg, d);
rEnd},
{"coeff:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL,
[](const char *, rtosc::RtData &d)
{
EQ *eq = (EQ*)d.obj;
float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
eq->getFilter(a,b);

char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {0};
rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {0};
for(int i=0; i<MAX_EQ_BANDS*MAX_FILTER_STAGES*3; ++i) {
int stride = MAX_EQ_BANDS*MAX_FILTER_STAGES*3;
type[i] = type[i+stride] = 'f';
val[i].f = b[i];
val[i+stride].f = a[i];
}
d.replyArray(d.loc, type, val);
}},
};

#undef rObject
#undef rBegin
#undef rEnd

EQ::EQ(EffectParams pars)
:Effect(pars)
{


+ 3
- 1
source/native-plugins/zynaddsubfx/Effects/EQ.h View File

@@ -31,6 +31,8 @@ class EQ:public Effect

void getFilter(float *a/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/,
float *b/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/) const;

static rtosc::Ports ports;
private:
//Parameters
unsigned char Pvolume;
@@ -41,7 +43,7 @@ class EQ:public Effect
//parameters
unsigned char Ptype, Pfreq, Pgain, Pq, Pstages;
//internal values
/* TODO
* The analog filters here really ought to be dumbed down some as
* you are just looking to do a batch convolution in the end


+ 8
- 2
source/native-plugins/zynaddsubfx/Effects/Echo.cpp View File

@@ -22,14 +22,20 @@
#define MAX_DELAY 2

#define rObject Echo
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports Echo::ports = {
{"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1, Panning Echo 2, Panning Echo 3, Feedback Echo)
{"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1,
Panning Echo 2, Panning Echo 3, Feedback Echo)
rProp(parameter)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
rEffPar(Pdelay, 2, rShort("delay"), "Length of Echo"),


+ 4
- 2
source/native-plugins/zynaddsubfx/Effects/Effect.cpp View File

@@ -18,9 +18,11 @@
#include <cmath>

EffectParams::EffectParams(Allocator &alloc_, bool insertion_, float *efxoutl_, float *efxoutr_,
unsigned char Ppreset_, unsigned int srate_, int bufsize_, FilterParams *filterpars_)
unsigned char Ppreset_, unsigned int srate_, int bufsize_, FilterParams *filterpars_,
bool filterprotect_)
:alloc(alloc_), insertion(insertion_), efxoutl(efxoutl_), efxoutr(efxoutr_),
Ppreset(Ppreset_), srate(srate_), bufsize(bufsize_), filterpars(filterpars_)
Ppreset(Ppreset_), srate(srate_), bufsize(bufsize_), filterpars(filterpars_),
filterprotect(filterprotect_)
{}
Effect::Effect(EffectParams pars)
:Ppreset(pars.Ppreset),


+ 3
- 1
source/native-plugins/zynaddsubfx/Effects/Effect.h View File

@@ -55,7 +55,8 @@ struct EffectParams
* @param Ppreset_ chosen preset
* @return Initialized Effect Parameter object*/
EffectParams(Allocator &alloc_, bool insertion_, float *efxoutl_, float *efxoutr_,
unsigned char Ppreset_, unsigned int srate, int bufsize, FilterParams *filterpars_=0);
unsigned char Ppreset_, unsigned int srate, int bufsize, FilterParams *filterpars_,
bool filterprotect=false);


Allocator &alloc;
@@ -66,6 +67,7 @@ struct EffectParams
unsigned int srate;
int bufsize;
FilterParams *filterpars;
bool filterprotect;
};

/**this class is inherited by the all effects(Reverb, Echo, ..)*/


+ 49
- 12
source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp View File

@@ -14,6 +14,7 @@
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>
#include <iostream>
#include <cassert>


#include "EffectMgr.h"
@@ -38,6 +39,8 @@
[](const char *msg, rtosc::RtData &data){\
rObject &o = *(rObject*)data.obj; \
data.obj = o.efx; \
if(!dynamic_cast<name*>(o.efx)) \
return; \
SNIP \
name::ports.dispatch(msg, data); \
}}
@@ -45,6 +48,30 @@ static const rtosc::Ports local_ports = {
rSelf(EffectMgr),
rPaste,
rRecurp(filterpars, "Filter Parameter for Dynamic Filter"),
{"Pvolume::i", rProp(parameter) rLinear(0,127) rShort("amt") rDoc("amount of effect"),
0,
[](const char *msg, rtosc::RtData &d)
{
EffectMgr *eff = (EffectMgr*)d.obj;
if(!rtosc_narguments(msg))
d.reply(d.loc, "i", eff->geteffectparrt(0));
else if(rtosc_type(msg, 0) == 'i'){
eff->seteffectparrt(0, rtosc_argument(msg, 0).i);
d.broadcast(d.loc, "i", eff->geteffectparrt(0));
}
}},
{"Ppanning::i", rProp(parameter) rLinear(0,127) rShort("pan") rDoc("panning"),
0,
[](const char *msg, rtosc::RtData &d)
{
EffectMgr *eff = (EffectMgr*)d.obj;
if(!rtosc_narguments(msg))
d.reply(d.loc, "i", eff->geteffectparrt(1));
else if(rtosc_type(msg, 0) == 'i'){
eff->seteffectparrt(1, rtosc_argument(msg, 0).i);
d.broadcast(d.loc, "i", eff->geteffectparrt(1));
}
}},
{"parameter#128::i:T:F", rProp(parameter) rProp(alias) rLinear(0,127) rDoc("Parameter Accessor"),
NULL,
[](const char *msg, rtosc::RtData &d)
@@ -103,7 +130,7 @@ static const rtosc::Ports local_ports = {
d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b);
}},
{"efftype::i", rOptions(Disabled, Reverb, Echo, Chorus,
Phaser, Alienwah, Distorsion, EQ, DynamicFilter)
Phaser, Alienwah, Distorsion, EQ, DynFilter)
rProp(parameter) rDoc("Get Effect Type"), NULL,
[](const char *m, rtosc::RtData &d)
{
@@ -134,7 +161,9 @@ static const rtosc::Ports local_ports = {
rSubtype(Alienwah),
rSubtype(Chorus),
rSubtype(Distorsion),
rSubtype(DynamicFilter),
rSubtype(Echo),
rSubtype(EQ),
rSubtype(Phaser),
rSubtype(Reverb),
};
@@ -146,7 +175,7 @@ EffectMgr::EffectMgr(Allocator &alloc, const SYNTH_T &synth_,
:insertion(insertion_),
efxoutl(new float[synth_.buffersize]),
efxoutr(new float[synth_.buffersize]),
filterpars(NULL),
filterpars(new FilterParams(time_)),
nefx(0),
efx(NULL),
time(time_),
@@ -165,6 +194,7 @@ EffectMgr::EffectMgr(Allocator &alloc, const SYNTH_T &synth_,
EffectMgr::~EffectMgr()
{
memory.dealloc(efx);
delete filterpars;
delete [] efxoutl;
delete [] efxoutr;
}
@@ -186,7 +216,7 @@ void EffectMgr::changeeffectrt(int _nefx, bool avoidSmash)
memset(efxoutr, 0, synth.bufferbytes);
memory.dealloc(efx);
EffectParams pars(memory, insertion, efxoutl, efxoutr, 0,
synth.samplerate, synth.buffersize);
synth.samplerate, synth.buffersize, filterpars, avoidSmash);
try {
switch (nefx) {
case 1:
@@ -223,9 +253,6 @@ void EffectMgr::changeeffectrt(int _nefx, bool avoidSmash)
return;
}

if(efx)
filterpars = efx->filterpars;

if(!avoidSmash)
for(int i=0; i<128; ++i)
settings[i] = geteffectparrt(i);
@@ -288,6 +315,10 @@ void EffectMgr::changepreset(unsigned char npreset)
void EffectMgr::changepresetrt(unsigned char npreset, bool avoidSmash)
{
preset = npreset;
if(avoidSmash && dynamic_cast<DynamicFilter*>(efx)) {
efx->Ppreset = npreset;
return;
}
if(efx)
efx->setpreset(npreset);
if(!avoidSmash)
@@ -424,6 +455,11 @@ void EffectMgr::paste(EffectMgr &e)
changepresetrt(e.preset, true);
for(int i=0;i<128;++i)
seteffectparrt(i, e.settings[i]);
if(dynamic_cast<DynamicFilter*>(efx)) {
std::swap(filterpars, e.filterpars);
efx->filterpars = filterpars;
}
cleanup(); // cleanup the effect and recompute its parameters
}

void EffectMgr::add2XML(XMLwrapper& xml)
@@ -443,7 +479,8 @@ void EffectMgr::add2XML(XMLwrapper& xml)
xml.addpar("par", par);
xml.endbranch();
}
if(filterpars) {
assert(filterpars);
if(nefx == 8) {
xml.beginbranch("FILTER");
filterpars->add2XML(xml);
xml.endbranch();
@@ -469,11 +506,11 @@ void EffectMgr::getfromXML(XMLwrapper& xml)
seteffectpar(n, xml.getpar127("par", par));
xml.exitbranch();
}
if(filterpars)
if(xml.enterbranch("FILTER")) {
filterpars->getfromXML(xml);
xml.exitbranch();
}
assert(filterpars);
if(xml.enterbranch("FILTER")) {
filterpars->getfromXML(xml);
xml.exitbranch();
}
xml.exitbranch();
}
cleanup();


+ 38
- 18
source/native-plugins/zynaddsubfx/Effects/Phaser.cpp View File

@@ -25,30 +25,50 @@
using namespace std;

#define rObject Phaser
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

#define ucharParamCb(pname) rBegin \
rObject &p = *(rObject*)d.obj; \
if(rtosc_narguments(msg)) \
p.set##pname(rtosc_argument(msg, 0).i); \
else \
d.reply(d.loc, "i", p.P##pname); \
rEnd
#define rParamPhaser(name, ...) \
{STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, ucharParamCb(name)}

rtosc::Ports Phaser::ports = {
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4)
{"preset::i", rProp(parameter)
rOptions(Phaser 1, Phaser 2, Phaser 3, Phaser 4,
Phaser 5, Phaser 6,
APhaser 1, APhaser 2, APhaser 3, APhaser 4,
APhaser 5, APhaser 6)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
rEffPar(lfo.Pfreq, 2, rShort("freq"), ""),
rEffPar(lfo.Prandomness, 3, rShort("rnd."), ""),
rEffPar(lfo.PLFOtype, 4, rShort("type"), ""),
rEffParTF(lfo.Pstereo, 5, rShort("stereo"), ""),
rEffPar(Pdepth, 6, rShort("depth"), ""),
rEffPar(Pfb, 7, rShort("fb"), ""),
rEffPar(Pstages, 8, rShort("stages"), ""),
rEffPar(Plrcross, 9, rShort("cross"), ""),
rEffPar(Poffset, 9, rShort("off"), ""),
rEffParTF(Poutsub, 10, rShort("sub") ""),
rEffPar(Pphase, 11, rShort("phase"), ""),
rEffPar(Pwidth, 11, rShort("width"), ""),
rEffParTF(Phyper, 12, rShort("hyp."), ""),
rEffPar(lfo.Pfreq, 2, rShort("freq"), "LFO frequency"),
rEffPar(lfo.Prandomness, 3, rShort("rnd."), "LFO randomness"),
rEffPar(lfo.PLFOtype, 4, rShort("type"),
rOptions(sine, tri), "lfo shape"),
rEffPar(lfo.Pstereo, 5, rShort("stereo"), "Left/right channel phase shift"),
rEffPar(Pdepth, 6, rShort("depth"), "LFP depth"),
rEffPar(Pfb, 7, rShort("fb"), "Feedback"),
rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), ""),
rParamPhaser(lrcross, rShort("cross"), "Channel routing"),
rParamPhaser(offset, rShort("off"), "Offset"),
rEffParTF(Poutsub, 10, rShort("sub"), "Invert output"),
rParamPhaser(phase, rShort("phase"), ""),
rParamPhaser(width, rShort("width"), ""),
rEffParTF(Phyper, 12, rShort("hyp."), "Square the LFO"),
rEffPar(Pdistortion, 13, rShort("distort"), "Distortion"),
rEffParTF(Panalog, 14, rShort("analog"), ""),
rEffParTF(Panalog, 14, rShort("analog"), "Use analog phaser"),
};
#undef rBegin
#undef rEnd
@@ -316,7 +336,7 @@ void Phaser::setoffset(unsigned char Poffset)
offsetpct = (float)Poffset / 127.0f;
}

void Phaser::setstages(unsigned char Pstages)
void Phaser::setstages(unsigned char Pstages_)
{
memory.devalloc(old.l);
memory.devalloc(old.r);
@@ -325,7 +345,7 @@ void Phaser::setstages(unsigned char Pstages)
memory.devalloc(yn1.l);
memory.devalloc(yn1.r);

this->Pstages = min(MAX_PHASER_STAGES, (int)Pstages);
Pstages = limit<int>(Pstages_, 1, MAX_PHASER_STAGES);

old = Stereo<float *>(memory.valloc<float>(Pstages * 2),
memory.valloc<float>(Pstages * 2));


+ 9
- 3
source/native-plugins/zynaddsubfx/Effects/Reverb.cpp View File

@@ -21,7 +21,7 @@
#include <rtosc/port-sugar.h>

#define rObject Reverb
#define rBegin [](const char *, rtosc::RtData &) {
#define rBegin [](const char *msg, rtosc::RtData &d) {
#define rEnd }

rtosc::Ports Reverb::ports = {
@@ -31,16 +31,22 @@ rtosc::Ports Reverb::ports = {
rProp(parameter)
rDoc("Instrument Presets"), 0,
rBegin;
rObject *o = (rObject*)d.obj;
if(rtosc_narguments(msg))
o->setpreset(rtosc_argument(msg, 0).i);
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
//Pvolume/Ppanning are common
rEffPar(Ptime, 2, rShort("time"), "Length of Reverb"),
rEffPar(Pidelay, 3, rShort("i.time"), "Delay for first impulse"),
rEffPar(Pidelayfb,4, rShort("i.fb"), "Feedback for first impulse"),
rEffPar(Plpf, 7, rShort("lpf"), "Low pass filter"),
rEffPar(Phpf, 8, rShort("lpf"), "High pass filter"),
rEffPar(Phpf, 8, rShort("hpf"), "High pass filter"),
rEffPar(Plohidamp,9, rShort("damp"), "Dampening"),
//Todo make this a selector
rEffPar(Ptype, 10,rShort("type"), "Type"),
rEffPar(Ptype, 10,rShort("type"),
rOptions(Random, Freeverb, Bandwidth), "Type"),
rEffPar(Proomsize,11,rShort("size"), "Room Size"),
rEffPar(Pbandwidth,12,rShort("bw"), "Bandwidth"),
};


+ 17
- 1
source/native-plugins/zynaddsubfx/Misc/Bank.cpp View File

@@ -364,9 +364,11 @@ void Bank::rescanforbanks()
//sort the banks
sort(banks.begin(), banks.end());

for(int i = 0; i < (int) banks.size(); ++i)
db->addBankDir(banks[i].dir);

//remove duplicate bank names
for(int j = 0; j < (int) banks.size() - 1; ++j) {
db->addBankDir(banks[j].dir);
int dupl = 0;
for(int i = j + 1; i < (int) banks.size(); ++i) {
if(banks[i].name == banks[j].name) {
@@ -469,6 +471,20 @@ std::vector<std::string> Bank::search(std::string s) const
}
return out;
}
std::vector<std::string> Bank::blist(std::string s)
{
std::vector<std::string> out;
int result = loadbank(s);
for(int i=0; i<128; ++i) {
if(ins[i].filename.empty())
out.push_back("Empty Preset");
else
out.push_back(ins[i].name);
out.push_back(to_s(i));
}
return out;
}

int Bank::addtobank(int pos, string filename, string name)
{


+ 1
- 0
source/native-plugins/zynaddsubfx/Misc/Bank.h View File

@@ -77,6 +77,7 @@ class Bank
} ins[BANK_SIZE];

std::vector<std::string> search(std::string) const;
std::vector<std::string> blist(std::string);

private:



+ 128
- 6
source/native-plugins/zynaddsubfx/Misc/BankDb.cpp View File

@@ -1,8 +1,10 @@
#include "BankDb.h"
#include "XMLwrapper.h"
#include "Util.h"
#include "../globals.h"
#include <cstring>
#include <dirent.h>
#include <sys/stat.h>

#define INSTRUMENT_EXTENSION ".xiz"

@@ -11,12 +13,34 @@ typedef BankDb::svec svec;
typedef BankDb::bvec bvec;

BankEntry::BankEntry(void)
:id(0), add(false), pad(false), sub(false)
:id(0), add(false), pad(false), sub(false), time(0)
{}

bool platform_strcasestr(const char *hay, const char *needle)
{
int n = strlen(hay);
int m = strlen(needle);
for(int i=0; i<n; i++) {
int good = 1;
for(int j=0; j<m; ++j) {
if(toupper(hay[i+j]) != toupper(needle[j])) {
good = 0;
break;
}

}
if(good)
return 1;
}
return 0;

}

bool sfind(std::string hay, std::string needle)
{
return strcasestr(hay.c_str(), needle.c_str());
//return strcasestr(hay.c_str(), needle.c_str());
return platform_strcasestr(hay.c_str(), needle.c_str());
return false;
}

bool BankEntry::match(string s) const
@@ -31,6 +55,11 @@ bool BankEntry::match(string s) const
sfind(type, s) || sfind(comments,s) || sfind(author,s);
}

bool BankEntry::operator<(const BankEntry &b) const
{
return this->file < b.file;
}

static svec split(string s)
{
svec vec;
@@ -73,6 +102,8 @@ bvec BankDb::search(std::string ss) const
vec.push_back(field);
}

std::sort(vec.begin(), vec.end());

return vec;
}

@@ -92,9 +123,77 @@ void BankDb::clear(void)
fields.clear();
}

static std::string getCacheName(void)
{
char name[512] = {0};
snprintf(name, sizeof(name), "%s%s", getenv("HOME"),
"/.zynaddsubfx-bank-cache.xml");
return name;
}

static bvec loadCache(void)
{
bvec cache;
XMLwrapper xml;
xml.loadXMLfile(getCacheName());
if(xml.enterbranch("bank-cache")) {
auto nodes = xml.getBranch();

for(auto node:nodes) {
BankEntry be;
#define bind(x,y) if(node.has(#x)) {be.x = y(node[#x].c_str());}
bind(file, string);
bind(bank, string);
bind(name, string);
bind(comments, string);
bind(author, string);
bind(type, atoi);
bind(id, atoi);
bind(add, atoi);
bind(pad, atoi);
bind(sub, atoi);
bind(time, atoi);
#undef bind
cache.push_back(be);
}
}
return cache;
}

static void saveCache(bvec vec)
{
XMLwrapper xml;
xml.beginbranch("bank-cache");
for(auto value:vec) {
XmlNode binding("instrument-entry");
#define bind(x) binding[#x] = to_s(value.x);
bind(file);
bind(bank);
bind(name);
bind(comments);
bind(author);
bind(type);
bind(id);
bind(add);
bind(pad);
bind(sub);
bind(time);
#undef bind
xml.add(binding);
}
xml.endbranch();
xml.saveXMLfile(getCacheName(), 0);
}

void BankDb::scanBanks(void)
{
fields.clear();
bvec cache = loadCache();
bmap cc;
for(auto c:cache)
cc[c.bank + c.file] = c;

bvec ncache;
for(auto bank:banks)
{
DIR *dir = opendir(bank.c_str());
@@ -102,6 +201,7 @@ void BankDb::scanBanks(void)
if(!dir)
continue;


struct dirent *fn;

while((fn = readdir(dir))) {
@@ -111,16 +211,36 @@ void BankDb::scanBanks(void)
if(!strstr(filename, INSTRUMENT_EXTENSION))
continue;

auto xiz = processXiz(filename, bank);
auto xiz = processXiz(filename, bank, cc);
fields.push_back(xiz);
ncache.push_back(xiz);
}

closedir(dir);

}
saveCache(ncache);
}

BankEntry BankDb::processXiz(std::string filename, std::string bank) const
BankEntry BankDb::processXiz(std::string filename,
std::string bank, bmap &cache) const
{
string fname = bank+filename;

//Grab a timestamp
struct stat st;
int ret = lstat(fname.c_str(), &st);
int time = 0;
if(ret != -1)
time = st.st_mtim.tv_sec;

//quickly check if the file exists in the cache and if it is up-to-date
if(cache.find(fname) != cache.end() &&
cache[fname].time == time)
return cache[fname];



//verify if the name is like this NNNN-name (where N is a digit)
int no = 0;
unsigned int startname = 0;
@@ -153,6 +273,7 @@ BankEntry BankDb::processXiz(std::string filename, std::string bank) const
entry.file = filename;
entry.bank = bank;
entry.id = no;
entry.time = time;

if(no != 0) //the instrument position in the bank is found
entry.name = name.substr(startname);
@@ -179,10 +300,10 @@ BankEntry BankDb::processXiz(std::string filename, std::string bank) const
"Sound Effects",
};


//Try to obtain other metadata (expensive)
XMLwrapper xml;
string fname = bank+filename;
int ret = xml.loadXMLfile(fname);
ret = xml.loadXMLfile(fname);
if(xml.enterbranch("INSTRUMENT")) {
if(xml.enterbranch("INFO")) {
char author[1024];
@@ -213,6 +334,7 @@ BankEntry BankDb::processXiz(std::string filename, std::string bank) const
//printf("Bank Entry:\n");
//printf("\tname - %s\n", entry.name.c_str());
//printf("\tauthor - %s\n", line(entry.author).c_str());
//printf("\tbank - %s\n", entry.bank.c_str());
//printf("\tadd/pad/sub - %d/%d/%d\n", entry.add, entry.pad, entry.sub);

return entry;


+ 8
- 3
source/native-plugins/zynaddsubfx/Misc/BankDb.h View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <vector>
#include <map>

struct BankEntry
{
@@ -15,16 +16,20 @@ struct BankEntry
bool add;
bool pad;
bool sub;
int time;//last update
typedef std::vector<std::string> svec;
svec tags(void) const;
bool match(std::string) const;
bool operator<(const BankEntry &b) const;
};


class BankDb
{
public:
typedef std::vector<std::string> svec;
typedef std::vector<BankEntry> bvec;
typedef std::vector<std::string> svec;
typedef std::vector<BankEntry> bvec;
typedef std::map<std::string,BankEntry> bmap;

//search for banks
//uses a space separated list of keywords and
@@ -44,7 +49,7 @@ class BankDb
void scanBanks(void);

private:
BankEntry processXiz(std::string, std::string) const;
BankEntry processXiz(std::string, std::string, bmap&) const;
bvec fields;
svec banks;
};

+ 46
- 1
source/native-plugins/zynaddsubfx/Misc/Config.cpp View File

@@ -19,7 +19,7 @@
#include <rtosc/port-sugar.h>

#include "Config.h"
#include "globals.h"
#include "../globals.h"
#include "XMLwrapper.h"

#define rStdString(name, len, ...) \
@@ -136,6 +136,37 @@ static const rtosc::Ports ports = {
c.cfg.OscilSize = val;
d.broadcast(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0)));
}},
{"add-favorite:s", rDoc("Add favorite directory"), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
for(int i=0; i<MAX_BANK_ROOT_DIRS; ++i) {
if(c.cfg.favoriteList[i].empty()) {
c.cfg.favoriteList[i] = rtosc_argument(msg, 0).s;
return;
}
}

}},
{"favorites:", rProp(parameter), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
char *argt = new char[MAX_BANK_ROOT_DIRS+1];
rtosc_arg_t *args = new rtosc_arg_t[MAX_BANK_ROOT_DIRS];
memset(argt, 0, MAX_BANK_ROOT_DIRS+1);
int j = 0;
for(int i=0; i<MAX_BANK_ROOT_DIRS; ++i) {
if(!c.cfg.favoriteList[i].empty()) {
argt[j] = 's';
args[j].s = c.cfg.favoriteList[i].c_str();
j++;
}
}
d.replyArray(d.loc, argt, args);
delete [] argt;
delete [] args;
}},
};
const rtosc::Ports &Config::ports = ::ports;
#endif
@@ -319,6 +350,13 @@ void Config::readConfig(const char *filename)
cfg.presetsDirList[i] = xmlcfg.getparstr("presets_root", "");
xmlcfg.exitbranch();
}
//Get favs
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i)
if(xmlcfg.enterbranch("FAVSROOT", i)) {
cfg.favoriteList[i] = xmlcfg.getparstr("favoirtes_root", "");
xmlcfg.exitbranch();
}

//linux stuff
xmlcfg.getparstr("linux_oss_wave_out_dev",
@@ -380,6 +418,13 @@ void Config::saveConfig(const char *filename) const
xmlcfg->addparstr("presets_root", cfg.presetsDirList[i]);
xmlcfg->endbranch();
}
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i)
if(!cfg.favoriteList[i].empty()) {
xmlcfg->beginbranch("FAVSROOT", i);
xmlcfg->addparstr("favoirtes_root", cfg.favoriteList[i]);
xmlcfg->endbranch();
}

xmlcfg->addpar("interpolation", cfg.Interpolation);



+ 1
- 0
source/native-plugins/zynaddsubfx/Misc/Config.h View File

@@ -46,6 +46,7 @@ class Config
int Interpolation;
std::string bankRootDirList[MAX_BANK_ROOT_DIRS], currentBankDir;
std::string presetsDirList[MAX_BANK_ROOT_DIRS];
std::string favoriteList[MAX_BANK_ROOT_DIRS];
int CheckPADsynth;
int IgnoreProgramChange;
int UserInterfaceMode;


+ 63
- 31
source/native-plugins/zynaddsubfx/Misc/Master.cpp View File

@@ -116,7 +116,7 @@ static const Ports master_ports = {
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX
rRecur(microtonal, "Micrtonal Mapping Functionality"),
rRecur(ctl, "Controller"),
rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-1, Master),
rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off)
rOptions(Part1, Part2, Part3, Part4, Part5, Part6,
Part7, Part8, Part9, Part10, Part11, Part12,
Part13, Part14, Part15, Part16),
@@ -682,27 +682,8 @@ void dump_msg(const char* ptr, std::ostream& os = std::cerr)
#endif
int msg_id=0;

/*
* Master audio out (the final sound)
*/
bool Master::AudioOut(float *outr, float *outl)
bool Master::runOSC(float *outl, float *outr, bool offline)
{
//Danger Limits
if(memory->lowMemory(2,1024*1024))
printf("QUITE LOW MEMORY IN THE RT POOL BE PREPARED FOR WEIRD BEHAVIOR!!\n");
//Normal Limits
if(!pendingMemory && memory->lowMemory(4,1024*1024)) {
printf("Requesting more memory\n");
bToU->write("/request-memory", "");
pendingMemory = true;
}


//Handle watch points
if(bToU)
watcher.write_back = bToU;
watcher.tick();

//Handle user events TODO move me to a proper location
char loc_buf[1024];
DataObj d{loc_buf, 1024, this, bToU};
@@ -714,7 +695,8 @@ bool Master::AudioOut(float *outr, float *outl)
if(!strcmp(msg, "/load-master")) {
Master *this_master = this;
Master *new_master = *(Master**)rtosc_argument(msg, 0).b.data;
new_master->AudioOut(outl, outr);
if(!offline)
new_master->AudioOut(outl, outr);
Nio::masterSwap(new_master);
if (mastercb)
mastercb(mastercb_ptr, new_master);
@@ -731,23 +713,55 @@ bool Master::AudioOut(float *outr, float *outl)
}
ports.dispatch(msg, d, true);
events++;
if(!d.matches) {
//workaround for requesting voice status
int a=0, b=0, c=0;
char e=0;
if(4 == sscanf(msg, "/part%d/kit%d/adpars/VoicePar%d/Enable%c", &a, &b, &c, &e)) {
d.reply(msg, "F");
d.matches++;
}
}
if(!d.matches) {// && !ports.apropos(msg)) {
fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);
fprintf(stderr, "Unknown address<BACKEND> '%s:%s'\n", uToB->peak(), rtosc_argument_string(uToB->peak()));
#if 0
if(strstr(msg, "PFMVelocity"))
dump_msg(msg);
if(ports.apropos(msg))
fprintf(stderr, " -> best match: '%s'\n", ports.apropos(msg)->name);
if(ports.apropos(msg+1))
fprintf(stderr, " -> best match: '%s'\n", ports.apropos(msg+1)->name);
#endif
fprintf(stderr, "Unknown address<BACKEND:%s> '%s:%s'\n",
offline ? "offline" : "online",
uToB->peak(),
rtosc_argument_string(uToB->peak()));
fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
}
}
if(events>1 && false)
fprintf(stderr, "backend: %d events per cycle\n",events);

return true;
}

/*
* Master audio out (the final sound)
*/
bool Master::AudioOut(float *outr, float *outl)
{
//Danger Limits
if(memory->lowMemory(2,1024*1024))
printf("QUITE LOW MEMORY IN THE RT POOL BE PREPARED FOR WEIRD BEHAVIOR!!\n");
//Normal Limits
if(!pendingMemory && memory->lowMemory(4,1024*1024)) {
printf("Requesting more memory\n");
bToU->write("/request-memory", "");
pendingMemory = true;
}

//work through events
if(!runOSC(outl, outr, false))
return false;


//Handle watch points
if(bToU)
watcher.write_back = bToU;
watcher.tick();


//Swaps the Left channel with Right Channel
if(swaplr)
@@ -896,6 +910,22 @@ bool Master::AudioOut(float *outr, float *outl)
//update the global frame timer
time++;

#ifdef DEMO_VERSION
double seconds = time.time()*synth.buffersize_f/synth.samplerate_f;
if(seconds > 10*60) {//10 minute trial
shutup = true;
for(int i = 0; i < synth.buffersize; ++i) {
float tmp = (synth.buffersize_f - i) / synth.buffersize_f;
outl[i] *= 0.0f;
outr[i] *= 0.0f;
}
}
#endif

//Update pulse
last_ack = last_beat;


return true;
}

@@ -998,6 +1028,8 @@ void Master::ShutUp()
insefx[nefx]->cleanup();
for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
sysefx[nefx]->cleanup();
for(int i = 0; i < int(sizeof(activeNotes)/sizeof(activeNotes[0])); ++i)
activeNotes[i] = 0;
vuresetpeaks();
shutup = 0;
}


+ 8
- 0
source/native-plugins/zynaddsubfx/Misc/Master.h View File

@@ -91,6 +91,9 @@ class Master

void vuUpdate(const float *outl, const float *outr);

//Process a set of OSC events in the bToU buffer
bool runOSC(float *outl, float *outr, bool offline=false);

/**Audio Output*/
bool AudioOut(float *outl, float *outr) REALTIME;
/**Audio Output (for callback mode).
@@ -175,6 +178,11 @@ class Master
bool pendingMemory;
const SYNTH_T &synth;
const int& gzip_compression; //!< value from config

//Heartbeat for identifying plugin offline modes
//in units of 10 ms (done s.t. overflow is in 497 days)
uint32_t last_beat;
uint32_t last_ack;
private:
float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];
float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX];


+ 45
- 12
source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp View File

@@ -3,6 +3,7 @@

Microtonal.cpp - Tuning settings and microtonal capabilities
Copyright (C) 2002-2005 Nasca Octavian Paul
Copyright (C) 2016 Mark McCurry
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or
@@ -39,25 +40,25 @@ using namespace rtosc;
* A good lookup table should be a good finalization of this
*/
const rtosc::Ports Microtonal::ports = {
rToggle(Pinvertupdown, "key mapping inverse"),
rParamZyn(Pinvertupdowncenter, "center of the inversion"),
rToggle(Penabled, "Enable for microtonal mode"),
rParamZyn(PAnote, "The note for 'A'"),
rParamF(PAfreq, "Frequency of the 'A' note"),
rParamZyn(Pscaleshift, "UNDOCUMENTED"),
rParamZyn(Pfirstkey, "First key to retune"),
rParamZyn(Plastkey, "Last key to retune"),
rParamZyn(Pmiddlenote, "Scale degree 0 note"),
rToggle(Pinvertupdown, rShort("inv."), "key mapping inverse"),
rParamZyn(Pinvertupdowncenter, rShort("center"), "center of the inversion"),
rToggle(Penabled, rShort("enable"), "Enable for microtonal mode"),
rParamZyn(PAnote, rShort("A note"), "The note for 'A'"),
rParamF(PAfreq, rShort("A freq"), "Frequency of the 'A' note"),
rParamZyn(Pscaleshift, rShort("shift"), "UNDOCUMENTED"),
rParamZyn(Pfirstkey, rShort("first key"), "First key to retune"),
rParamZyn(Plastkey, rShort("last key"), "Last key to retune"),
rParamZyn(Pmiddlenote, rShort("middle"), "Scale degree 0 note"),

//TODO check to see if this should be exposed
rParamZyn(Pmapsize, "Size of key map"),
rToggle(Pmappingenabled, "Mapping Enable"),

rParams(Pmapping, 128, "Mapping of keys"),
rParamZyn(Pglobalfinedetune, "Fine detune for all notes"),
rParamZyn(Pglobalfinedetune, rShort("fine"), "Fine detune for all notes"),

rString(Pname, MICROTONAL_MAX_NAME_LEN, "Microtonal Name"),
rString(Pcomment, MICROTONAL_MAX_NAME_LEN, "Microtonal Name"),
rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), "Microtonal Name"),
rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), "Microtonal comments"),

{"octavesize:", rDoc("Get octave size"), 0, [](const char*, RtData &d)
{
@@ -790,6 +791,7 @@ void Microtonal::getfromXML(XMLwrapper& xml)
}
xml.exitbranch();
}
apply();
}


@@ -819,3 +821,34 @@ int Microtonal::loadXML(const char *filename)

return 0;
}

//roundabout function, but it works
void Microtonal::apply(void)
{
{
char buf[100*MAX_OCTAVE_SIZE] = {0};
char tmpbuf[100] = {0};
for (int i=0;i<Pmapsize;i++) {
if (i!=0)
strncat(buf, "\n", sizeof(buf)-1);
if (Pmapping[i]==-1)
snprintf(tmpbuf,100,"x");
else
snprintf(tmpbuf,100,"%d",Pmapping[i]);
strncat(buf, tmpbuf, sizeof(buf)-1);
}
texttomapping(buf);
}

{
char buf[100*MAX_OCTAVE_SIZE] = {0};
char tmpbuf[100] = {0};
for (int i=0;i<getoctavesize();i++){
if (i!=0)
strncat(buf, "\n", sizeof(buf)-1);
tuningtoline(i,tmpbuf,100);
strncat(buf, tmpbuf, sizeof(buf)-1);
}
int err = texttotunings(buf);
}
}

+ 1
- 0
source/native-plugins/zynaddsubfx/Misc/Microtonal.h View File

@@ -149,6 +149,7 @@ class Microtonal
//Grab a 0..127 integer from the provided descriptor

static int linetotunings(struct OctaveTuning &tune, const char *line);
void apply(void);

const int& gzip_compression;
};


+ 322
- 14
source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp View File

@@ -17,6 +17,7 @@
#include <fstream>
#include <iostream>
#include <dirent.h>
#include <sys/stat.h>

#include <rtosc/undo-history.h>
#include <rtosc/thread-link.h>
@@ -49,11 +50,14 @@
#include <atomic>
#include <list>

#define errx(...) {}
#define warnx(...) {}
#ifndef errx
#include <err.h>
#endif

using std::string;
int Pexitprogram = 0;

/******************************************************************************
* LIBLO And Reflection Code *
@@ -459,8 +463,16 @@ public:
int preferred_port);
~MiddleWareImpl(void);

//Check offline vs online mode in plugins
void heartBeat(Master *m);
int64_t start_time_sec;
int64_t start_time_nsec;
bool offline;

//Apply function while parameters are write locked
void doReadOnlyOp(std::function<void()> read_only_fn);
void doReadOnlyOpPlugin(std::function<void()> read_only_fn);
bool doReadOnlyOpNormal(std::function<void()> read_only_fn, bool canfail=false);

void savePart(int npart, const char *filename)
{
@@ -489,7 +501,7 @@ public:
assert(actual_load[npart] <= pending_load[npart]);

//load part in async fashion when possible
#if HAVE_ASYNC
#ifndef WIN32
auto alloc = std::async(std::launch::async,
[master,filename,this,npart](){
Part *p = new Part(*master->memory, synth,
@@ -663,6 +675,13 @@ public:
}

autoSave.tick();

heartBeat(master);

//XXX This might have problems with a master swap operation
if(offline)
master->runOSC(0,0,true);

}


@@ -838,6 +857,47 @@ class MwDataObj:public rtosc::RtData
MiddleWareImpl *mwi;
};

static std::vector<std::string> getFiles(const char *folder, bool finddir)
{
DIR *dir = opendir(folder);

if(dir == NULL) {
return {};
}

struct dirent *fn;
std::vector<string> files;

while((fn = readdir(dir))) {
#ifndef WIN32
bool is_dir = fn->d_type & DT_DIR;
//it could still be a symbolic link
if(!is_dir) {
string path = string(folder) + "/" + fn->d_name;
struct stat buf;
memset((void*)&buf, 0, sizeof(buf));
int err = stat(path.c_str(), &buf);
if(err)
printf("[Zyn:Error] stat cannot handle <%s>:%d\n", path.c_str(), err);
if(S_ISDIR(buf.st_mode)) {
is_dir = true;
}
}
#else
std::string darn_windows = folder + std::string("/") + std::string(fn->d_name);
printf("attr on <%s> => %x\n", darn_windows.c_str(), GetFileAttributes(darn_windows.c_str()));
printf("desired mask = %x\n", mask);
printf("error = %x\n", INVALID_FILE_ATTRIBUTES);
bool is_dir = GetFileAttributes(darn_windows.c_str()) & FILE_ATTRIBUTE_DIRECTORY;
#endif
if(finddir == is_dir)
files.push_back(fn->d_name);
}

closedir(dir);
std::sort(begin(files), end(files));
return files;
}



@@ -926,6 +986,25 @@ const rtosc::Ports bankPorts = {
}
d.replyArray("/bank/types", t, args);
rEnd},
{"tags:", 0, 0,
rBegin;
const char *types[8];
types[ 0] = "fast";
types[ 1] = "slow";
types[ 2] = "saw";
types[ 3] = "bell";
types[ 4] = "lead";
types[ 5] = "ambient";
types[ 6] = "horn";
types[ 7] = "alarm";
char t[8+1]={0};
rtosc_arg_t args[8];
for(int i=0; i<8; ++i) {
t[i] = 's';
args[i].s = types[i];
}
d.replyArray(d.loc, t, args);
rEnd},
{"slot#1024:", 0, 0,
rBegin;
const int loc = extractInt(msg);
@@ -1010,7 +1089,20 @@ const rtosc::Ports bankPorts = {
{"search:s", 0, 0,
rBegin;
auto res = impl.search(rtosc_argument(msg, 0).s);
#define MAX_SEARCH 128
#define MAX_SEARCH 300
char res_type[MAX_SEARCH+1] = {0};
rtosc_arg_t res_dat[MAX_SEARCH] = {0};
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) {
res_type[i] = 's';
res_dat[i].s = res[i].c_str();
}
d.replyArray("/bank/search_results", res_type, res_dat);
#undef MAX_SEARCH
rEnd},
{"blist:s", 0, 0,
rBegin;
auto res = impl.blist(rtosc_argument(msg, 0).s);
#define MAX_SEARCH 300
char res_type[MAX_SEARCH+1] = {0};
rtosc_arg_t res_dat[MAX_SEARCH] = {0};
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) {
@@ -1020,6 +1112,10 @@ const rtosc::Ports bankPorts = {
d.replyArray("/bank/search_results", res_type, res_dat);
#undef MAX_SEARCH
rEnd},
{"search_results:", 0, 0,
rBegin;
d.reply("/bank/search_results", "");
rEnd},
};

/******************************************************************************
@@ -1157,6 +1253,63 @@ static rtosc::Ports middwareSnoopPorts = {
const char *file = rtosc_argument(msg,1).s;
impl.savePart(part_id, file);
rEnd},
{"file_home_dir:", 0, 0,
rBegin;
const char *home = getenv("PWD");
if(!home)
home = getenv("HOME");
if(!home)
home = getenv("USERPROFILE");
if(!home)
home = getenv("HOMEPATH");
if(!home)
home = "/";

string home_ = home;
#ifndef WIN32
if(home_[home_.length()-1] != '/')
home_ += '/';
#endif
d.reply(d.loc, "s", home_.c_str());
rEnd},
{"file_list_files:s", 0, 0,
rBegin;
const char *folder = rtosc_argument(msg, 0).s;

auto files = getFiles(folder, false);

const int N = files.size();
rtosc_arg_t *args = new rtosc_arg_t[N];
char *types = new char[N+1];
types[N] = 0;
for(int i=0; i<N; ++i) {
args[i].s = files[i].c_str();
types[i] = 's';
}

d.replyArray(d.loc, types, args);
delete [] types;
delete [] args;
rEnd},
{"file_list_dirs:s", 0, 0,
rBegin;
const char *folder = rtosc_argument(msg, 0).s;

auto files = getFiles(folder, true);

const int N = files.size();
rtosc_arg_t *args = new rtosc_arg_t[N];
char *types = new char[N+1];
types[N] = 0;
for(int i=0; i<N; ++i) {
args[i].s = files[i].c_str();
types[i] = 's';
}

d.replyArray(d.loc, types, args);
delete [] types;
delete [] args;
rEnd},
{"reload_auto_save:i", 0, 0,
rBegin
const int save_id = rtosc_argument(msg,0).i;
@@ -1180,10 +1333,12 @@ static rtosc::Ports middwareSnoopPorts = {
rBegin;
const char *file = rtosc_argument(msg, 0).s;
impl.loadMaster(file);
d.reply("/damage", "s", "/");
rEnd},
{"reset_master:", 0, 0,
rBegin;
impl.loadMaster(NULL);
d.reply("/damage", "s", "/");
rEnd},
{"load_xiz:is", 0, 0,
rBegin;
@@ -1221,7 +1376,9 @@ static rtosc::Ports middwareSnoopPorts = {
rEnd},
{"part#16/clear:", 0, 0,
rBegin;
impl.loadClearPart(extractInt(msg));
int id = extractInt(msg);
impl.loadClearPart(id);
d.reply("/damage", "s", ("/part"+to_s(id)).c_str());
rEnd},
{"undo:", 0, 0,
rBegin;
@@ -1240,16 +1397,20 @@ static rtosc::Ports middwareSnoopPorts = {
#define MAX_MIDI 32
rtosc_arg_t args[MAX_MIDI*4];
char argt[MAX_MIDI*4+1] = {0};
int j=0;
for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) {
auto val = midi.inv_map[key[i]];
argt[4*i+0] = 'i';
args[4*i+0].i = std::get<1>(val);
argt[4*i+1] = 's';
args[4*i+1].s = key[i].c_str();
argt[4*i+2] = 'i';
args[4*i+2].i = 0;
argt[4*i+3] = 'i';
args[4*i+3].i = 127;
if(std::get<1>(val) == -1)
continue;
argt[4*j+0] = 'i';
args[4*j+0].i = std::get<1>(val);
argt[4*j+1] = 's';
args[4*j+1].s = key[i].c_str();
argt[4*j+2] = 'i';
args[4*j+2].i = 0;
argt[4*j+3] = 'i';
args[4*j+3].i = 127;
j++;

}
d.replyArray(d.loc, argt, args);
@@ -1274,7 +1435,8 @@ static rtosc::Ports middwareSnoopPorts = {
midi.unMap(addr.c_str(), true);
rEnd},
//drop this message into the abyss
{"ui/title:", 0, 0, [](const char *msg, RtData &d) {}}
{"ui/title:", 0, 0, [](const char *msg, RtData &d) {}},
{"quit:", 0, 0, [](const char *, RtData&) {Pexitprogram = 1;}},
};

static rtosc::Ports middlewareReplyPorts = {
@@ -1344,8 +1506,8 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_,
int res = master->saveXML(save_file.c_str());
(void)res;});})
{
bToU = new rtosc::ThreadLink(4096*2,1024);
uToB = new rtosc::ThreadLink(4096*2,1024);
bToU = new rtosc::ThreadLink(4096*2*16,1024/16);
uToB = new rtosc::ThreadLink(4096*2*16,1024/16);
midi_mapper.base_ports = &Master::ports;
midi_mapper.rt_cb = [this](const char *msg){handleMsg(msg);};
if(preferrred_port != -1)
@@ -1390,6 +1552,14 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_,
rtosc_message(buf, 1024, "/undo_resume","");
handleMsg(buf);
});

//Setup starting time
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
start_time_sec = time.tv_sec;
start_time_nsec = time.tv_nsec;

offline = false;
}

MiddleWareImpl::~MiddleWareImpl(void)
@@ -1464,6 +1634,130 @@ void MiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn)
}
}

//Offline detection code:
// - Assume that the audio callback should be run at least once every 50ms
// - Atomically provide the number of ms since start to Master
// - Every time middleware ticks provide a heart beat
// - If when the heart beat is provided the backend is more than 200ms behind
// the last heartbeat then it must be offline
// - When marked offline the backend doesn't receive another heartbeat until it
// registers the current beat that it's behind on
void MiddleWareImpl::heartBeat(Master *master)
{
//Current time
//Last provided beat
//Last acknowledged beat
//Current offline status
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
uint32_t now = (time.tv_sec-start_time_sec)*100 +
(time.tv_nsec-start_time_nsec)*1e-9*100;
int32_t last_ack = master->last_ack;
int32_t last_beat = master->last_beat;

//everything is considered online for the first second
if(now < 100)
return;

if(offline) {
if(last_beat == last_ack) {
//XXX INSERT MESSAGE HERE ABOUT TRANSITION TO ONLINE
offline = false;

//Send new heart beat
master->last_beat = now;
}
} else {
//it's unquestionably alive
if(last_beat == last_ack) {

//Send new heart beat
master->last_beat = now;
return;
}

//it's pretty likely dead
if(last_beat-last_ack > 0 && now-last_beat > 20) {
//The backend has had 200 ms to acquire a new beat
//The backend instead has an older beat
//XXX INSERT MESSAGE HERE ABOUT TRANSITION TO OFFLINE
offline = true;
return;
}

//who knows if it's alive or not here, give it a few ms to acquire or
//not
}

}

void MiddleWareImpl::doReadOnlyOpPlugin(std::function<void()> read_only_fn)
{
assert(uToB);
int offline = 0;
if(offline) {
std::atomic_thread_fence(std::memory_order_acquire);

//Now it is safe to do any read only operation
read_only_fn();
} else if(!doReadOnlyOpNormal(read_only_fn, true)) {
//check if we just transitioned to offline mode

std::atomic_thread_fence(std::memory_order_acquire);

//Now it is safe to do any read only operation
read_only_fn();
}
}

bool MiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, bool canfail)
{
assert(uToB);
uToB->write("/freeze_state","");

std::list<const char *> fico;
int tries = 0;
while(tries++ < 2000) {
if(!bToU->hasNext()) {
usleep(500);
continue;
}
const char *msg = bToU->read();
if(!strcmp("/state_frozen", msg))
break;
size_t bytes = rtosc_message_length(msg, bToU->buffer_size());
char *save_buf = new char[bytes];
memcpy(save_buf, msg, bytes);
fico.push_back(save_buf);
}

if(canfail) {
//Now to resume normal operations
uToB->write("/thaw_state","");
for(auto x:fico) {
uToB->raw_write(x);
delete [] x;
}
return false;
}

assert(tries < 10000);//if this happens, the backend must be dead

std::atomic_thread_fence(std::memory_order_acquire);

//Now it is safe to do any read only operation
read_only_fn();

//Now to resume normal operations
uToB->write("/thaw_state","");
for(auto x:fico) {
uToB->raw_write(x);
delete [] x;
}
return true;
}

void MiddleWareImpl::broadcastToRemote(const char *rtmsg)
{
//Always send to the local UI
@@ -1479,6 +1773,11 @@ void MiddleWareImpl::broadcastToRemote(const char *rtmsg)

void MiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest)
{
if(!rtmsg || rtmsg[0] != '/' || !rtosc_message_length(rtmsg, -1)) {
printf("[Warning] Invalid message in sendToRemote <%s>...\n", rtmsg);
return;
}

//printf("sendToRemote(%s:%s,%s)\n", rtmsg, rtosc_argument_string(rtmsg),
// dest.c_str());
if(dest == "GUI") {
@@ -1486,6 +1785,10 @@ void MiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest)
} else if(!dest.empty()) {
lo_message msg = lo_message_deserialise((void*)rtmsg,
rtosc_message_length(rtmsg, bToU->buffer_size()), NULL);
if(!msg) {
printf("[ERROR] OSC to <%s> Failed To Parse In Liblo\n", rtmsg);
return;
}

//Send to known url
lo_address addr = lo_address_new_from_url(dest.c_str());
@@ -1522,6 +1825,11 @@ void MiddleWareImpl::bToUhandle(const char *rtmsg)
MwDataObj d(this);
middlewareReplyPorts.dispatch(rtmsg, d, true);

if(!rtmsg) {
fprintf(stderr, "[ERROR] Unexpected Null OSC In Zyn\n");
return;
}

in_order = true;
//Normal message not captured by the ports
if(d.matches == 0) {


+ 7
- 6
source/native-plugins/zynaddsubfx/Misc/Part.cpp View File

@@ -51,10 +51,10 @@ static const Ports partPorts = {
rParamZyn(Pvolume, rShort("Vol"), "Part Volume"),
#undef rChangeCb
#define rChangeCb obj->setPpanning(obj->Ppanning);
rParamZyn(Ppanning, "Set Panning"),
rParamZyn(Ppanning, rShort("pan"), "Set Panning"),
#undef rChangeCb
#define rChangeCb obj->setkeylimit(obj->Pkeylimit);
rParamI(Pkeylimit, rProp(parameter), rMap(min,0), rMap(max, POLYPHONY), "Key limit per part"),
rParamI(Pkeylimit, rShort("limit"), rProp(parameter), rMap(min,0), rMap(max, POLYPHONY), "Key limit per part"),
#undef rChangeCb
#define rChangeCb
rParamZyn(Pminkey, rShort("min"), "Min Used Key"),
@@ -62,8 +62,8 @@ static const Ports partPorts = {
rParamZyn(Pkeyshift, rShort("shift"), "Part keyshift"),
rParamZyn(Prcvchn, rOptions(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16),
"Active MIDI channel"),
rParamZyn(Pvelsns, "Velocity sensing"),
rParamZyn(Pveloffs, "Velocity offset"),
rParamZyn(Pvelsns, rShort("sense"), "Velocity sensing"),
rParamZyn(Pveloffs, rShort("offset"), "Velocity offset"),
rToggle(Pnoteon, "If the channel accepts note on events"),
rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), "Kit mode/enable\n"
"Off - Only the first kit is ever utilized\n"
@@ -77,7 +77,8 @@ static const Ports partPorts = {
rString(info.Pauthor, MAX_INFO_TEXT_SIZE, "Instrument author"),
rString(info.Pcomments, MAX_INFO_TEXT_SIZE, "Instrument comments"),
rString(Pname, PART_MAX_NAME_LEN, "User specified label"),
rArrayI(Pefxroute, NUM_PART_EFX, "Effect Routing"),
rArrayI(Pefxroute, NUM_PART_EFX,
rOptions(Next Effect,Part Out,Dry Out), "Effect Routing"),
rArrayT(Pefxbypass, NUM_PART_EFX, "If an effect is bypassed"),
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
@@ -100,7 +101,7 @@ static const Ports partPorts = {
int res = 0;
if(!p->Ppolymode)
res = p->Plegatomode ? 2 : 1;
d.reply(d.loc, "c", res);
d.reply(d.loc, "i", res);
return;
}



+ 1
- 1
source/native-plugins/zynaddsubfx/Misc/Schema.cpp View File

@@ -168,7 +168,7 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v)
const char *max = meta["max"];

for(auto m:meta) {
if(strlen(m.title) >= 5 && !bcmp(m.title, "map ", 4)) {
if(strlen(m.title) >= 5 && !memcmp(m.title, "map ", 4)) {
int id = atoi(m.title+4);
std::string val = m.value;
options.push_back(std::make_pair(id, val));


+ 1
- 0
source/native-plugins/zynaddsubfx/Misc/Util.cpp View File

@@ -29,6 +29,7 @@
#include <sched.h>
#endif

#define errx(...) {}
#ifndef errx
#include <err.h>
#endif


+ 3
- 0
source/native-plugins/zynaddsubfx/Misc/Util.h View File

@@ -20,6 +20,9 @@
#include <algorithm>
#include <set>

#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>

using std::min;
using std::max;



+ 21
- 14
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp View File

@@ -102,11 +102,11 @@ XMLwrapper::XMLwrapper()

node = root = addparams("ZynAddSubFX-data", 4,
"version-major", stringFrom<int>(
version.major()).c_str(),
version.get_major()).c_str(),
"version-minor", stringFrom<int>(
version.minor()).c_str(),
version.get_minor()).c_str(),
"version-revision",
stringFrom<int>(version.revision()).c_str(),
stringFrom<int>(version.get_revision()).c_str(),
"ZynAddSubFX-author", "Nasca Octavian Paul");

//make the empty branch that will contain the information parameters
@@ -125,10 +125,21 @@ XMLwrapper::XMLwrapper()
endbranch();
}

XMLwrapper::~XMLwrapper()
void
XMLwrapper::cleanup(void)
{
if(tree)
mxmlDelete(tree);

/* make sure freed memory is not referenced */
tree = 0;
node = 0;
root = 0;
}

XMLwrapper::~XMLwrapper()
{
cleanup();
}

void XMLwrapper::setPadSynth(bool enabled)
@@ -297,9 +308,7 @@ const char *trimLeadingWhite(const char *c)

int XMLwrapper::loadXMLfile(const string &filename)
{
if(tree != NULL)
mxmlDelete(tree);
tree = NULL;
cleanup();

const char *xmldata = doloadfile(filename);
if(xmldata == NULL)
@@ -323,13 +332,13 @@ int XMLwrapper::loadXMLfile(const string &filename)
return -3; //the XML doesnt embbed zynaddsubfx data

//fetch version information
fileversion.set_major(stringTo<int>(mxmlElementGetAttr(root, "version-major")));
fileversion.set_minor(stringTo<int>(mxmlElementGetAttr(root, "version-minor")));
fileversion.set_revision(
_fileversion.set_major(stringTo<int>(mxmlElementGetAttr(root, "version-major")));
_fileversion.set_minor(stringTo<int>(mxmlElementGetAttr(root, "version-minor")));
_fileversion.set_revision(
stringTo<int>(mxmlElementGetAttr(root, "version-revision")));

if(verbose)
cout << "loadXMLfile() version: " << fileversion << endl;
cout << "loadXMLfile() version: " << _fileversion << endl;

return 0;
}
@@ -367,10 +376,8 @@ char *XMLwrapper::doloadfile(const string &filename) const

bool XMLwrapper::putXMLdata(const char *xmldata)
{
if(tree != NULL)
mxmlDelete(tree);
cleanup();

tree = NULL;
if(xmldata == NULL)
return false;



+ 12
- 3
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h View File

@@ -16,7 +16,7 @@
#include <mxml.h>
#include <string>
#include <vector>
#include "../zyn-version.h"
#include "zyn-version.h"

#ifndef XML_WRAPPER_H
#define XML_WRAPPER_H
@@ -233,6 +233,10 @@ class XMLwrapper

std::vector<XmlNode> getBranch(void) const;

const version_type& fileversion() const {
return _fileversion;
}

private:

/**
@@ -254,6 +258,11 @@ class XMLwrapper
*/
char *doloadfile(const std::string &filename) const;

/**
* Cleanup XML tree before loading new one.
*/
void cleanup(void);

mxml_node_t *tree; /**<all xml data*/
mxml_node_t *root; /**<xml data used by zynaddsubfx*/
mxml_node_t *node; /**<current subtree in parsing or writing */
@@ -272,8 +281,8 @@ class XMLwrapper
*/
mxml_node_t *addparams(const char *name, unsigned int params,
...) const;
version_type fileversion;
public:
version_type _fileversion;
};

#endif

+ 32
- 11
source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp View File

@@ -105,7 +105,15 @@ void *AlsaEngine::MidiThread(void)
snd_seq_event_t *event;
MidiEvent ev;
set_realtime();
while(snd_seq_event_input(midi.handle, &event) > 0) {
while(1) {
if(midi.exiting)
break;
if(snd_seq_event_input_pending(midi.handle, 1) <= 0) {
usleep(10);
continue;
}
if(snd_seq_event_input(midi.handle, &event) < 0)
break;
//ensure ev is empty
ev.channel = 0;
ev.num = 0;
@@ -225,6 +233,7 @@ bool AlsaEngine::openMidi()
if(alsaport < 0)
return false;

midi.exiting = false;
pthread_attr_t attr;

pthread_attr_init(&attr);
@@ -239,8 +248,10 @@ void AlsaEngine::stopMidi()
return;

snd_seq_t *handle = midi.handle;
if((NULL != midi.handle) && midi.pThread)
pthread_cancel(midi.pThread);
if((NULL != midi.handle) && midi.pThread) {
midi.exiting = true;
pthread_join(midi.pThread, 0);
}
midi.handle = NULL;
if(handle)
snd_seq_close(handle);
@@ -319,6 +330,18 @@ bool AlsaEngine::openAudio()
snd_pcm_hw_params_set_periods_near(audio.handle,
audio.params, &audio.periods, NULL);

/* Set buffer size (in frames). The resulting latency is given by */
/* latency = periodsize * periods / (rate * bytes_per_frame) */
snd_pcm_uframes_t alsa_buffersize = synth.buffersize;
rc = snd_pcm_hw_params_set_buffer_size_near(audio.handle,
audio.params,
&alsa_buffersize);

/* At this place, ALSA's and zyn's buffer sizes may differ. */
/* This should not be a problem. */
if((int)alsa_buffersize != synth.buffersize)
cerr << "ALSA buffer size: " << alsa_buffersize << endl;

/* Write the parameters to the driver */
rc = snd_pcm_hw_params(audio.handle, audio.params);
if(rc < 0) {
@@ -328,12 +351,6 @@ bool AlsaEngine::openAudio()
return false;
}

/* Set buffer size (in frames). The resulting latency is given by */
/* latency = periodsize * periods / (rate * bytes_per_frame) */
snd_pcm_hw_params_set_buffer_size(audio.handle,
audio.params,
synth.buffersize);

//snd_pcm_hw_params_get_period_size(audio.params, &audio.frames, NULL);
//snd_pcm_hw_params_get_period_time(audio.params, &val, NULL);

@@ -371,8 +388,12 @@ void *AlsaEngine::processAudio()
snd_pcm_prepare(handle);
}
else
if(rc < 0)
cerr << "error from writei: " << snd_strerror(rc) << endl;
if(rc < 0) {
cerr << "AlsaEngine: Recovering connection..." << endl;
rc = snd_pcm_recover(handle, rc, 0);
if(rc < 0)
throw "Could not recover ALSA connection";
}
}
return NULL;
}

+ 1
- 0
source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h View File

@@ -56,6 +56,7 @@ class AlsaEngine:public AudioOut, MidiIn
std::string device;
snd_seq_t *handle;
int alsaId;
bool exiting;
pthread_t pThread;
} midi;



+ 2
- 1
source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp View File

@@ -119,7 +119,8 @@ void *WavEngine::AudioThread()
-32768,
32767);
}
file->writeStereoSamples(synth.buffersize, recordbuf_16bit);
if(file)
file->writeStereoSamples(synth.buffersize, recordbuf_16bit);
}

delete[] recordbuf_16bit;


+ 31
- 16
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp View File

@@ -78,25 +78,29 @@ static const Ports voicePorts = {
"Subvoice vibratto speed"),
rOption(Unison_invert_phase, rShort("inv."),
rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"),
rOption(Type, rShort("type"), rOptions(Sound,White,Pink), "Type of Sound"),
rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), "Type of Sound"),
rParamZyn(PDelay, rShort("delay"), "Voice Startup Delay"),
rToggle(Presonance, rShort("enable"), "Resonance Enable"),
rParamI(Pextoscil, rShort("ext."),
rMap(min, -1), rMap(max, 16), "External Oscilator Selection"),
rMap(min, -1), rMap(max, 16), "External Oscillator Selection"),
rParamI(PextFMoscil, rShort("ext."),
rMap(min, -1), rMap(max, 16), "External FM Oscilator Selection"),
rMap(min, -1), rMap(max, 16), "External FM Oscillator Selection"),
rParamZyn(Poscilphase, rShort("phase"), "Oscillator Phase"),
rParamZyn(PFMoscilphase, rShort("phase"), "FM Oscillator Phase"),
rToggle(Pfilterbypass, rShort("bypass"), "Filter Bypass"),

//Freq Stuff
rToggle(Pfixedfreq, rShort("fixed"), "If frequency is fixed"),
rParamZyn(PfixedfreqET, rShort("e.t."), "Equal Tempermant Parameter"),
rParamZyn(PfixedfreqET, rShort("e.t."), "Equal Temperament Parameter"),
rParamZyn(PBendAdjust, rShort("bend"), "Pitch bend adjustment"),
rParamZyn(POffsetHz, rShort("offset"), "Voice constant offset"),
rParamI(PDetune, rShort("fine"), "Fine Detune"),
//nominally -8192..8191
rParamI(PDetune, rShort("fine"),
rLinear(0, 16383), "Fine Detune"),
rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"),
rParamZyn(PDetuneType, rShort("type"), "Magnitude of Detune"),
rParamZyn(PDetuneType, rShort("type"),
rOptions(L35cents, L10cents, E100cents, E1200cents),
"Magnitude of Detune"),
rToggle(PFreqEnvelopeEnabled, rShort("enable"), "Frequency Envelope Enable"),
rToggle(PFreqLfoEnabled, rShort("enable"), "Frequency LFO Enable"),

@@ -118,14 +122,18 @@ static const Ports voicePorts = {

//Modulator Stuff
rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase,
frequency, pitch), "Modulator mode"),
frequency, pulse), "Modulator mode"),
rParamI(PFMVoice, rShort("voice"), "Modulator Oscillator Selection"),
rParamZyn(PFMVolume, rShort("vol."), "Modulator Magnitude"),
rParamZyn(PFMVolumeDamp, rShort("damp."), "Modulator HF dampening"),
rParamZyn(PFMVelocityScaleFunction, rShort("sense"), "Modulator Velocity Function"),
rParamI(PFMDetune, rShort("fine"), "Modulator Fine Detune"),
//nominally -8192..8191
rParamI(PFMDetune, rShort("fine"),
rLinear(0, 16383), "Modulator Fine Detune"),
rParamI(PFMCoarseDetune, rShort("coarse"), "Modulator Coarse Detune"),
rParamZyn(PFMDetuneType, rShort("type"), "Modulator Detune Magnitude"),
rParamZyn(PFMDetuneType, rShort("type"),
rOptions(L35cents, L10cents, E100cents, E1200cents),
"Modulator Detune Magnitude"),
rToggle(PFMFixedFreq, rShort("fixed"), "Modulator Frequency Fixed"),
rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), "Modulator Frequency Envelope"),
rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), "Modulator Amplitude Envelope"),
@@ -143,7 +151,8 @@ static const Ports voicePorts = {
//TODO do the same for the other engines
d.reply(d.loc, "f", getdetune(detuneType, 0, obj->PDetune));
}},
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
{"octave::c:i", rProp(parameter) rShort("octave") rLinear(-8, 7) rDoc("Octave note offset"),
NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
@@ -157,7 +166,8 @@ static const Ports voicePorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
{"coarsedetune::c:i", rProp(parameter) rShort("coarse") rLinear(-64,63)
rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
@@ -183,7 +193,7 @@ static const Ports voicePorts = {
//TODO do the same for the other engines
d.reply(d.loc, "f", getdetune(detuneType, 0, obj->PFMDetune));
}},
{"FMoctave::c:i", rProp(parameter) rDoc("Octave note offset for modulator"), NULL,
{"FMoctave::c:i", rProp(parameter) rShort("octave") rLinear(-8,7) rDoc("Octave note offset for modulator"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
@@ -197,7 +207,8 @@ static const Ports voicePorts = {
obj->PFMCoarseDetune = k*1024 + obj->PFMCoarseDetune%1024;
}
}},
{"FMcoarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune for modulator"),
{"FMcoarsedetune::c:i", rProp(parameter) rShort("coarse") rLinear(-64,63)
rDoc("Coarse note detune for modulator"),
NULL, [](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
@@ -239,7 +250,9 @@ static const Ports globalPorts = {
rToggle(PStereo, rShort("stereo"), "Mono/Stereo Enable"),

//Frequency
rParamI(PDetune, rShort("fine"), "Fine Detune"),
//nominally -8192..8191
rParamI(PDetune, rShort("fine"),
rLinear(0, 16383), "Fine Detune"),
rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"),
rParamZyn(PDetuneType, rShort("type"),
rOptions(L35cents, L10cents, E100cents, E1200cents),
@@ -272,7 +285,8 @@ static const Ports globalPorts = {
rObject *obj = (rObject *)d.obj;
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
}},
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
{"octave::c:i", rProp(parameter) rShort("octave") rLinear(-8,7)
rDoc("Octave note offset"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
@@ -286,7 +300,8 @@ static const Ports globalPorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
{"coarsedetune::c:i", rProp(parameter) rShort("coarse") rLinear(-64, 63)
rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;


+ 6
- 5
source/native-plugins/zynaddsubfx/Params/Controller.cpp View File

@@ -35,21 +35,22 @@ const rtosc::Ports Controller::ports = {
rParamZyn(modwheel.depth, rShort("mdw.d"), "Depth of Modwheel MIDI Control"),
rToggle(modwheel.exponential, rShort("mdw.exp"), "Modwheel Exponential Mode"),
rToggle(pitchwheel.is_split, "If PitchWheel Has unified bendrange or not"),
rParamI(pitchwheel.bendrange, "Range of MIDI Pitch Wheel"),
rParamI(pitchwheel.bendrange, rShort("pch.d"), "Range of MIDI Pitch Wheel"),
rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"),
rToggle(expression.receive, rShort("exp.rcv"), "Expression MIDI Receive"),
rToggle(fmamp.receive, rShort("fma.rcv"), "FM amplitude MIDI Receive"),
rToggle(volume.receive, rShort("vol.rcv"), "Volume MIDI Receive"),
rToggle(sustain.receive, rShort("sus.rcv"), "Sustain MIDI Receive"),
rToggle(portamento.receive, rShort("prt.rcv"), "Portamento MIDI Receive"),
rToggle(portamento.portamento, "UNDOCUMENTED"),
rToggle(portamento.portamento, "Portamento Enable"),
rParamZyn(portamento.time, rShort("time"), "Portamento Length"),
rToggle(portamento.proportional, rShort("propt."), "If all portamentos are proportional to the distance they span"),
rParamZyn(portamento.propRate, rShort("rate"), "Portamento proportional rate"),
rToggle(portamento.proportional, rShort("propt."), "Whether the portamento time is proportional"
"to the size of the interval between two notes."),
rParamZyn(portamento.propRate, rShort("scale"), "Portamento proportional scale"),
rParamZyn(portamento.propDepth, rShort("depth"), "Portamento proportional depth"),
rParamZyn(portamento.pitchthresh, rShort("thresh"), "Threshold for portamento"),
rToggle(portamento.pitchthreshtype, rShort("tr.type"), "Type of threshold"),
rParamZyn(portamento.updowntimestretch, "UNDOCUMENTED"),
rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), "Relative length of glide up vs glide down"),
rParamZyn(resonancecenter.depth, rShort("rfc.d"), "Resonance Center MIDI Depth"),
rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), "Resonance Bandwidth MIDI Depth"),
rToggle(NRPN.receive, "NRPN MIDI Enable"),


+ 83
- 21
source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp View File

@@ -17,6 +17,7 @@
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>

#include "zyn-version.h"
#include "EnvelopeParams.h"
#include "../Misc/Util.h"
#include "../Misc/Time.h"
@@ -38,7 +39,7 @@ static const rtosc::Ports localPorts = {
#define rChangeCb if(!obj->Pfreemode) obj->converttofree(); \
if(obj->time) { obj->last_update_timestamp = obj->time->time(); }
rParamZyn(Penvpoints, rProp(internal), "Number of points in complex definition"),
rParamZyn(Penvsustain, rProp(internal), "Location of the sustain point"),
rParamZyn(Penvsustain, "Location of the sustain point"),
rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"),
rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"),
rParamZyn(Penvstretch, rShort("stretch"),
@@ -54,28 +55,46 @@ static const rtosc::Ports localPorts = {
rParamZyn(PS_val, rShort("s.val"), "Sustain Value"),
rParamZyn(PR_dt, rShort("r.dt"), "Release Time"),
rParamZyn(PR_val, rShort("r.val"), "Release Value"),
{"envdt:", rDoc("Envelope Delay Times"), NULL,

{"Envmode:", rDoc("Envelope variant type"), NULL,
rBegin;
d.reply(d.loc, "i", env->Envmode);
rEnd},

{"envdt", rDoc("Envelope Delay Times"), NULL,
rBegin;
const int N = MAX_ENVELOPE_POINTS;
rtosc_arg_t args[N];
char arg_types[N+1] = {0};
for(int i=0; i<N; ++i) {
args[i].f = env->getdt(i);
arg_types[i] = 'f';
const int M = rtosc_narguments(msg);
if(M == 0) {
rtosc_arg_t args[N];
char arg_types[N+1] = {0};
for(int i=0; i<N; ++i) {
args[i].f = env->getdt(i);
arg_types[i] = 'f';
}
d.replyArray(d.loc, arg_types, args);
} else {
for(int i=0; i<N && i<M; ++i)
env->Penvdt[i] = env->inv_dt(rtosc_argument(msg, i).f);
}
d.replyArray(d.loc, arg_types, args);
rEnd},
{"envval:", rDoc("Envelope Delay Times"), NULL,
{"envval", rDoc("Envelope Delay Times"), NULL,
rBegin;
const int N = MAX_ENVELOPE_POINTS;
rtosc_arg_t args[N];
char arg_types[N+1] = {0};
for(int i=0; i<N; ++i) {
args[i].f = env->Penvval[i]/127.0f;
arg_types[i] = 'f';
const int M = rtosc_narguments(msg);
if(M == 0) {
rtosc_arg_t args[N];
char arg_types[N+1] = {0};
for(int i=0; i<N; ++i) {
args[i].f = env->Penvval[i]/127.0f;
arg_types[i] = 'f';
}
d.replyArray(d.loc, arg_types, args);
} else {
for(int i=0; i<N && i<M; ++i) {
env->Penvval[i] = limit(roundf(rtosc_argument(msg,i).f*127.0f), 0.0f, 127.0f);
}
}
d.replyArray(d.loc, arg_types, args);
rEnd},

{"addPoint:i", rProp(internal) rDoc("Add point to envelope"), NULL,
@@ -190,6 +209,12 @@ float EnvelopeParams::dt(char val)
return (powf(2.0f, val / 127.0f * 12.0f) - 1.0f) * 10.0f; //miliseconds
}

char EnvelopeParams::inv_dt(float val)
{
int ival = roundf(logf(val/10.0f + 1.0f)/logf(2.0f) * 127.0f/12.0f);
return limit(ival, 0, 127);
}


/*
* ADSR/ASR... initialisations
@@ -358,7 +383,42 @@ void EnvelopeParams::add2XML(XMLwrapper& xml)
}
}

float EnvelopeParams::env_dB2rap(float db) {
return (powf(10.0f, db / 20.0f) - 0.01)/.99f;
}

float EnvelopeParams::env_rap2dB(float rap) {
return 20.0f * log10f(rap * 0.99f + 0.01);
}

/**
since commit 5334d94283a513ae42e472aa020db571a3589fb9, i.e. between
versions 2.4.3 and 2.4.4, the amplitude envelope has been converted
differently from dB to rap for AmplitudeEnvelope (mode 2)
this converts the values read from an XML file once
*/
struct version_fixer_t
{
const bool mismatch;
public:
int operator()(int input) const
{
return (mismatch)
// The errors occured when calling env_dB2rap. Let f be the
// conversion function for mode 2 (see Envelope.cpp), then we
// load values with (let "o" be the function composition symbol):
// f^{-1} o (env_dB2rap^{-1}) o dB2rap o f
// from the xml file. This results in the following formula:
? roundf(127.0f * (0.5f *
log10f( 0.01f + 0.99f *
powf(100, input/127.0f - 1))
+ 1))
: input;
}
version_fixer_t(const version_type& fileversion, int env_mode) :
mismatch(fileversion < version_type(2,4,4) &&
(env_mode == 2)) {}
};

void EnvelopeParams::getfromXML(XMLwrapper& xml)
{
@@ -369,20 +429,22 @@ void EnvelopeParams::getfromXML(XMLwrapper& xml)
Pforcedrelease = xml.getparbool("forced_release", Pforcedrelease);
Plinearenvelope = xml.getparbool("linear_envelope", Plinearenvelope);

version_fixer_t version_fix(xml.fileversion(), Envmode);

PA_dt = xml.getpar127("A_dt", PA_dt);
PD_dt = xml.getpar127("D_dt", PD_dt);
PR_dt = xml.getpar127("R_dt", PR_dt);
PA_val = xml.getpar127("A_val", PA_val);
PD_val = xml.getpar127("D_val", PD_val);
PS_val = xml.getpar127("S_val", PS_val);
PR_val = xml.getpar127("R_val", PR_val);
PA_val = version_fix(xml.getpar127("A_val", PA_val));
PD_val = version_fix(xml.getpar127("D_val", PD_val));
PS_val = version_fix(xml.getpar127("S_val", PS_val));
PR_val = version_fix(xml.getpar127("R_val", PR_val));

for(int i = 0; i < Penvpoints; ++i) {
if(xml.enterbranch("POINT", i) == 0)
continue;
if(i != 0)
Penvdt[i] = xml.getpar127("dt", Penvdt[i]);
Penvval[i] = xml.getpar127("val", Penvval[i]);
Penvval[i] = version_fix(xml.getpar127("val", Penvval[i]));
xml.exitbranch();
}



+ 5
- 0
source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h View File

@@ -44,6 +44,7 @@ class EnvelopeParams:public Presets

float getdt(char i) const;
static float dt(char val);
static char inv_dt(float val);

/* MIDI Parameters */
unsigned char Pfreemode; //1 for free mode, 0 otherwise
@@ -70,6 +71,10 @@ class EnvelopeParams:public Presets
int64_t last_update_timestamp;

static const rtosc::Ports &ports;

static float env_rap2dB(float rap);
static float env_dB2rap(float db);

private:
void store2defaults();



+ 22
- 13
source/native-plugins/zynaddsubfx/Params/FilterParams.cpp View File

@@ -32,9 +32,9 @@ constexpr int sizeof_pvowels = sizeof(FilterParams::Pvowels);
#define rObject FilterParams::Pvowels_t::formants_t

static const rtosc::Ports subsubports = {
rParamZyn(freq, "Formant frequency"),
rParamZyn(amp, "Strength of formant"),
rParamZyn(q, "Quality Factor"),
rParamZyn(freq, rShort("f.freq"), "Formant frequency"),
rParamZyn(amp, rShort("f.str"), "Strength of formant"),
rParamZyn(q, rShort("f.q"), "The formant's quality factor, also known as resonance bandwidth or Q for short"),
};
#undef rObject

@@ -68,28 +68,37 @@ const rtosc::Ports FilterParams::ports = {
rParamZyn(Pfreq, rShort("cutoff"), "Center Freq"),
rParamZyn(Pq, rShort("q"),
"Quality Factor (resonance/bandwidth)"),
rOption(Pstages, rShort("stages"),
rOptions(1, 2, 3, 4, 5), "Filter Stages"),
rParamI(Pstages, rShort("stages"),
rLinear(0,5), "Filter Stages"),
rParamZyn(Pfreqtrack, rShort("f.track"),
"Frequency Tracking amount"),
rParamZyn(Pgain, rShort("gain"), "Output Gain"),
rParamZyn(Pnumformants, rShort("formants"),
"Number of formants to be used"),
rParamI(Pnumformants, rShort("formants"),
rLinear(1,12), "Number of formants to be used"),
rParamZyn(Pformantslowness, rShort("slew"),
"Rate that formants change"),
rParamZyn(Pvowelclearness, rShort("clarity"),
"Cost for mixing vowels"),
"How much each vowel is smudged with the next in sequence. A high clarity will avoid smudging."),
rParamZyn(Pcenterfreq, rShort("cutoff"),
"Center Freq (formant)"),
rParamZyn(Poctavesfreq, rShort("octaves"),
"Number of octaves for formant"),

//TODO check if FF_MAX_SEQUENCE is acutally expanded or not
rParamZyn(Psequencesize, rMap(max, FF_MAX_SEQUENCE), "Length of vowel sequence"),
rParamZyn(Psequencestretch, "How modulators stretch the sequence"),
rToggle(Psequencereversed, "If the modulator input is inverted"),
rParamI(Psequencesize, rShort("seq.size"), rLinear(0, FF_MAX_SEQUENCE), "Length of vowel sequence"),
rParamZyn(Psequencestretch, rShort("seq.str"), "How modulators stretch the sequence"),
rToggle(Psequencereversed, rShort("reverse"), "If the modulator input is inverted"),

//{"Psequence#" FF_MAX_SEQUENCE "/nvowel", "", NULL, [](){}},
{"vowel_seq#" STRINGIFY(FF_MAX_SEQUENCE) "::i", rShort("vowel") rDoc("Vowel number of this sequence position"), NULL,
[](const char *msg, RtData &d){
FilterParams *obj = (FilterParams *) d.obj;
const char *mm = msg;
while(*mm && !isdigit(*mm)) ++mm;
unsigned idx = atoi(mm);
if(rtosc_narguments(msg)) {
obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i;
} else
d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel);
}},
{"type-svf::i", rProp(parameter) rShort("type")
rOptions(low, high, band, notch)
rDoc("Filter Type"), 0, rOptionCb(Ptype)},


+ 23
- 19
source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp View File

@@ -40,31 +40,33 @@ static const rtosc::Ports realtime_ports =
rRecurp(GlobalFilter, "Post Filter"),

//Volume
rToggle(PStereo, "Stereo/Mono Mode"),
rParamZyn(PPanning, "Left Right Panning"),
rParamZyn(PVolume, "Synth Volume"),
rParamZyn(PAmpVelocityScaleFunction, "Amplitude Velocity Sensing function"),
rToggle(PStereo, rShort("stereo"), "Stereo/Mono Mode"),
rParamZyn(PPanning, rShort("panning"), "Left Right Panning"),
rParamZyn(PVolume, rShort("vol"), "Synth Volume"),
rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"),

rParamZyn(Fadein_adjustment, "Adjustment for anti-pop strategy."),
rParamZyn(Fadein_adjustment, rShort("a.pop."), "Adjustment for anti-pop strategy."),

//Punch
rParamZyn(PPunchStrength, "Punch Strength"),
rParamZyn(PPunchTime, "UNKNOWN"),
rParamZyn(PPunchStretch, "How Punch changes with note frequency"),
rParamZyn(PPunchVelocitySensing, "Punch Velocity control"),
rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"),
rParamZyn(PPunchTime, rShort("time"), "Length of punch"),
rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"),
rParamZyn(PPunchVelocitySensing, rShort("sense"), "Punch Velocity control"),

//Filter
rParamZyn(PFilterVelocityScale, "Filter Velocity Magnitude"),
rParamZyn(PFilterVelocityScaleFunction, "Filter Velocity Function Shape"),
rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"),
rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"),

//Freq
rToggle(Pfixedfreq, "Base frequency fixed frequency enable"),
rParamZyn(PfixedfreqET, "Equal temeperate control for fixed frequency operation"),
rToggle(Pfixedfreq, rShort("fixed"), "Base frequency fixed frequency enable"),
rParamZyn(PfixedfreqET, rShort("f.ET"), "Equal temeperate control for fixed frequency operation"),
rParamZyn(PBendAdjust, "Pitch bend adjustment"),
rParamZyn(POffsetHz, "Voice constant offset"),
rParamI(PDetune, "Fine Detune"),
rParamI(PCoarseDetune, "Coarse Detune"),
rParamZyn(PDetuneType, "Magnitude of Detune"),
rParamZyn(POffsetHz, rShort("offset"), "Voice constant offset"),
rParamI(PDetune, rShort("fine"), rLinear(0, 16383), "Fine Detune"),
rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"),
rParamZyn(PDetuneType, rShort("type"),
rOptions(L35cents, L10cents, E100cents, E1200cents),
"Magnitude of Detune"),

{"sample#64:ifb", rProp(internal) rDoc("Nothing to see here"), 0,
[](const char *m, rtosc::RtData &d)
@@ -86,7 +88,8 @@ static const rtosc::Ports realtime_ports =
PADnoteParameters *obj = (PADnoteParameters *)d.obj;
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
}},
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
{"octave::c:i", rProp(parameter) rShort("octave") rLinear(-8,7)
rDoc("Octave note offset"), NULL,
[](const char *msg, RtData &d)
{
PADnoteParameters *obj = (PADnoteParameters *)d.obj;
@@ -100,7 +103,8 @@ static const rtosc::Ports realtime_ports =
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
{"coarsedetune::c:i", rProp(parameter) rShort("coarse") rLinear(-64, 63)
rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
PADnoteParameters *obj = (PADnoteParameters *)d.obj;


+ 11
- 8
source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp View File

@@ -40,10 +40,11 @@ static const rtosc::Ports SUBnotePorts = {
rParamZyn(PVolume, rShort("volume"), "Volume"),
rParamZyn(PPanning, rShort("panning"), "Left Right Panning"),
rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"),
rParamI(PDetune, rShort("detune"), "Detune in detune type units"),
rParamI(PDetune, rShort("detune"), rLinear(0, 16383), "Detune in detune type units"),
rParamI(PCoarseDetune, rShort("cdetune"), "Coarse Detune"),
//Real values needed
rOption(PDetuneType, rShort("det. scl."), rOptions(100 cents, 200 cents, 500 cents), "Detune Scale"),
rOption(PDetuneType, rShort("det. scl."),
rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), "Detune Scale"),
rToggle(PFreqEnvelopeEnabled, rShort("enable"), "Enable for Frequency Envelope"),
rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), "Enable for Bandwidth Envelope"),
rToggle(PGlobalFilterEnabled, rShort("enable"), "Enable for Global Filter"),
@@ -65,13 +66,13 @@ static const rtosc::Ports SUBnotePorts = {
"Overtone Parameter"),
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"),
"Overtone Parameter"),
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("p3"),
"Overtone Parameter"),
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("forceH"),
"Force Overtones To Harmonics"),
#undef rChangeCb
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
rParamZyn(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), "Number of filter stages"),
rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), "Number of filter stages"),
rParamZyn(Pbandwidth, rShort("bandwidth"), "Bandwidth of filters"),
rParamZyn(Phmagtype, rShort("mag. type"),"How the magnitudes are computed (0=linear,1=-60dB,2=-60dB)"),
rParamZyn(Phmagtype, rShort("mag. type"), rOptions(linear, -40dB, -60dB, -80dB, -100dB), "Magnitude scale"),
rArray(Phmag, MAX_SUB_HARMONICS, "Harmonic magnitudes"),
rArray(Phrelbw, MAX_SUB_HARMONICS, "Relative bandwidth"),
rParamZyn(Pbwscale, rShort("stretch"), "Bandwidth scaling with frequency"),
@@ -95,7 +96,8 @@ static const rtosc::Ports SUBnotePorts = {
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
rEnd},
//weird stuff for PCoarseDetune
{"octave::c:i", rProp(parameter) rDoc("Note octave shift"), NULL,
{"octave::c:i", rProp(parameter) rShort("octave") rLinear(-8,7)
rDoc("Note octave shift"), NULL,
rBegin;
if(!rtosc_narguments(msg)) {
int k=obj->PCoarseDetune/1024;
@@ -107,7 +109,8 @@ static const rtosc::Ports SUBnotePorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
rEnd},
{"coarsedetune::c:i", rProp(parameter) rDoc("Note coarse detune"), NULL,
{"coarsedetune::c:i", rProp(parameter) rShort("coarse") rLinear(-64, 63)
rDoc("Note coarse detune"), NULL,
rBegin;
if(!rtosc_narguments(msg)) {
int k=obj->PCoarseDetune%1024;


+ 17
- 1
source/native-plugins/zynaddsubfx/Synth/ADnote.cpp View File

@@ -651,6 +651,8 @@ void ADnote::legatonote(LegatoParams lpars)
* (1.0f - pars.VoicePar[nvoice].PVolume / 127.0f)) // -60 dB .. 0 dB
* VelF(velocity,
pars.VoicePar[nvoice].PAmpVelocityScaleFunction); //velocity
if(pars.VoicePar[nvoice].PVolume == 0)
NoteVoicePar[nvoice].Volume = 0;

if(pars.VoicePar[nvoice].PVolumeminus != 0)
NoteVoicePar[nvoice].Volume = -NoteVoicePar[nvoice].Volume;
@@ -808,6 +810,8 @@ void ADnote::initparameters(WatchManager *wm, const char *prefix)
/* Voice Amplitude Parameters Init */
vce.Volume = powf(0.1f, 3.0f * (1.0f - param.PVolume / 127.0f)) // -60dB..0dB
* VelF(velocity, param.PAmpVelocityScaleFunction);
if(param.PVolume == 0)
vce.Volume = 0;

if(param.PVolumeminus)
vce.Volume = -vce.Volume;
@@ -1523,6 +1527,15 @@ inline void ADnote::ComputeVoicePinkNoise(int nvoice)
}
}

inline void ADnote::ComputeVoiceDC(int nvoice)
{
for(int k = 0; k < unison_size[nvoice]; ++k) {
float *tw = tmpwave_unison[k];
for(int i = 0; i < synth.buffersize; ++i)
tw[i] = 1.0f;
}
}



/*
@@ -1568,9 +1581,12 @@ int ADnote::noteout(float *outl, float *outr)
case 1:
ComputeVoiceWhiteNoise(nvoice);
break;
default:
case 2:
ComputeVoicePinkNoise(nvoice);
break;
default:
ComputeVoiceDC(nvoice);
break;
}
// Voice Processing



+ 1
- 0
source/native-plugins/zynaddsubfx/Synth/ADnote.h View File

@@ -95,6 +95,7 @@ class ADnote:public SynthNote
/**Generate Noise Samples for Voice*/
inline void ComputeVoiceWhiteNoise(int nvoice);
inline void ComputeVoicePinkNoise(int nvoice);
inline void ComputeVoiceDC(int nvoice);

/**Fadein in a way that removes clicks but keep sound "punchy"*/
inline void fadein(float *smps) const;


+ 4
- 12
source/native-plugins/zynaddsubfx/Synth/Envelope.cpp View File

@@ -173,14 +173,6 @@ float Envelope::envout(bool doWatch)
return out;
}

inline float Envelope::env_dB2rap(float db) {
return (powf(10.0f, db / 20.0f) - 0.01)/.99f;
}

inline float Envelope::env_rap2dB(float rap) {
return 20.0f * log10f(rap * 0.99f + 0.01);
}

/*
* Envelope Output (dB)
*/
@@ -191,8 +183,8 @@ float Envelope::envout_dB()
return envout(true);

if((currentpoint == 1) && (!keyreleased || !forcedrelease)) { //first point is always lineary interpolated
float v1 = env_dB2rap(envval[0]);
float v2 = env_dB2rap(envval[1]);
float v1 = EnvelopeParams::env_dB2rap(envval[0]);
float v2 = EnvelopeParams::env_dB2rap(envval[1]);
out = v1 + (v2 - v1) * t;

t += inct;
@@ -204,11 +196,11 @@ float Envelope::envout_dB()
}

if(out > 0.001f)
envoutval = env_rap2dB(out);
envoutval = EnvelopeParams::env_rap2dB(out);
else
envoutval = MIN_ENVELOPE_DB;
} else
out = env_dB2rap(envout(false));
out = EnvelopeParams::env_dB2rap(envout(false));

float pos[2] = {(float)currentpoint + t, out};
watchOut(pos, 2);


+ 0
- 2
source/native-plugins/zynaddsubfx/Synth/Envelope.h View File

@@ -36,8 +36,6 @@ class Envelope
* @return returns 1 if the envelope is finished*/
bool finished(void) const;
private:
float env_rap2dB(float rap);
float env_dB2rap(float db);
int envpoints;
int envsustain; //"-1" means disabled
float envdt[MAX_ENVELOPE_POINTS]; //millisecons


+ 24
- 8
source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp View File

@@ -27,8 +27,6 @@
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>

pthread_t main_thread;

#define rObject OscilGen
const rtosc::Ports OscilGen::non_realtime_ports = {
rSelf(OscilGen),
@@ -57,7 +55,7 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
"Base function modulation parameter"),
rParamZyn(Pbasefuncmodulationpar3, rShort("p3"),
"Base function modulation parameter"),
rParamZyn(Pwaveshaping, "Degree Of Waveshaping"),
rParamZyn(Pwaveshaping, rShort("amount"), "Degree Of Waveshaping"),
rOption(Pwaveshapingfunction, rShort("distort"),
rOptions(Undistorted,
Arctangent, Asymmetric, Pow, Sine, Quantisize,
@@ -75,7 +73,7 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
rOption(Psatype, rShort("spec. adj."), rOptions(None, Pow, ThrsD, ThrsU),
"Spectral Adjustment Type"),
rParamZyn(Psapar, rShort("p1"), "Spectral Adjustment Parameter"),
rParamI(Pharmonicshift, rShort("shift"), "Amount of shift on harmonics"),
rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), "Amount of shift on harmonics"),
rToggle(Pharmonicshiftfirst, rShort("pre/post"), "If harmonics are shifted before waveshaping/filtering"),
rOption(Pmodulation, rShort("FM"), rOptions(None, Rev, Sine, Power),
"Frequency Modulation To Combined Spectra"),
@@ -95,7 +93,8 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
else {
phase = rtosc_argument(m,0).i;
//XXX hack hack
char *repath = strdup(d.loc);
char repath[128];
strcpy(repath, d.loc);
char *edit = strrchr(repath, '/')+1;
strcpy(edit, "prepare");
OscilGen &o = *((OscilGen*)d.obj);
@@ -119,7 +118,8 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
mag = rtosc_argument(m,0).i;
//printf("setting magnitude\n\n");
//XXX hack hack
char *repath = strdup(d.loc);
char repath[128];
strcpy(repath, d.loc);
char *edit = strrchr(repath, '/')+1;
strcpy(edit, "prepare");
OscilGen &o = *((OscilGen*)d.obj);
@@ -163,10 +163,22 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
{"convert2sine:", rProp(non-realtime) rDoc("Translates waveform into FS"),
NULL, [](const char *, rtosc::RtData &d) {
((OscilGen*)d.obj)->convert2sine();
//XXX hack hack
char repath[128];
strcpy(repath, d.loc);
char *edit = strrchr(repath, '/')+1;
*edit = 0;
d.reply("/damage", "s", repath);
}},
{"use-as-base:", rProp(non-realtime) rDoc("Translates current waveform into base"),
NULL, [](const char *, rtosc::RtData &d) {
((OscilGen*)d.obj)->useasbase();
//XXX hack hack
char repath[128];
strcpy(repath, d.loc);
char *edit = strrchr(repath, '/')+1;
*edit = 0;
d.reply("/damage", "s", repath);
}}};

#define rForwardCb [](const char *msg, rtosc::RtData &d) {\
@@ -174,7 +186,7 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
const rtosc::Ports OscilGen::realtime_ports{
rSelf(OscilGen),
rPresetType,
rParamZyn(Prand, rShort("phase rnd"), "Oscilator Phase Randomness: smaller than 0 is \""
rParamZyn(Prand, rLinear(-64, 63), rShort("phase rnd"), "Oscillator Phase Randomness: smaller than 0 is \""
"group\", larger than 0 is for each harmonic"),
rParamZyn(Pamprandpower, rShort("variance"),
"Variance of harmonic randomness"),
@@ -187,7 +199,7 @@ const rtosc::Ports OscilGen::realtime_ports{
"Base frequency of adaptive harmonic (30..3000Hz)"),
rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200),
"Adaptive Harmonic Strength"),
rParamZyn(Padaptiveharmonicspar, rShort("par"),
rParamI(Padaptiveharmonicspar, rShort("power"), rLinear(0,100),
"Adaptive Harmonics Postprocessing Power"),
{"waveform:", rDoc("Returns waveform points"),
NULL, [](const char *, rtosc::RtData &d) {
@@ -228,6 +240,10 @@ const rtosc::MergePorts OscilGen::ports{
&OscilGen::non_realtime_ports
};

#ifndef M_PI_2
# define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif


//operations on FFTfreqs
inline void clearAll(fft_t *freqs, int oscilsize)


+ 4
- 0
source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp View File

@@ -28,6 +28,10 @@
#include "../Misc/Util.h"
#include "../Misc/Allocator.h"

#ifndef M_PI
# define M_PI 3.14159265358979323846 /* pi */
#endif

SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
:SynthNote(spars), pars(*parameters),
AmpEnvelope(nullptr),


+ 5
- 0
source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp View File

@@ -69,6 +69,11 @@ WatchManager::WatchManager(thrlnk *link)
void WatchManager::add_watch(const char *id)
{
//Don't add duplicate watchs
for(int i=0; i<MAX_WATCH; ++i)
if(!strcmp(active_list[i], id))
return;

//Apply to a free slot
for(int i=0; i<MAX_WATCH; ++i) {
if(!active_list[i][0]) {


+ 1
- 1
source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp View File

@@ -27,7 +27,7 @@ void raiseUi(ui_handle_t, const char *, const char *, ...)
}
void tickUi(ui_handle_t)
{
usleep(100000);
usleep(1000);
}
Fl_Osc_Interface *genOscInterface(MiddleWare*)
{


+ 2
- 2
source/native-plugins/zynaddsubfx/UI/EffUI.fl View File

@@ -445,7 +445,7 @@ if (filterwindow!=NULL){
class Fl_Osc_Check
}
Fl_Check_Button chorusp11 {
label Substract
label Subtract
tooltip {inverts the output} xywh {185 10 70 20} box THIN_UP_BOX down_box DOWN_BOX color 51 labelsize 10
code0 {o->init("parameter11");}
class Fl_Osc_Check
@@ -599,7 +599,7 @@ if (filterwindow!=NULL){
class Fl_Osc_Dial
}
Fl_Check_Button phaserp10 {
label Substract
label Subtract
tooltip {inverts output} xywh {200 10 74 20} box THIN_UP_BOX down_box DOWN_BOX color 51 labelfont 1 labelsize 10
code0 {o->init("parameter10");}
class Fl_Osc_Check


+ 3
- 1
source/native-plugins/zynaddsubfx/UI/FilterUI.fl View File

@@ -333,7 +333,7 @@ formantfiltergraph->redraw();}
}
Fl_Counter {} {
label {S.Pos.}
callback {nseqpos = o->value();update_formant_window();}
callback {nseqpos = o->value();update_formant_window();vowel_counter->oscMove("vowel_seq"+to_s(nseqpos));}
tooltip {Current position from the sequence} xywh {595 97 40 15} type Simple labelfont 1 labelsize 10 align 9 minimum 0 maximum 127 step 1 textsize 10
code0 {o->bounds(0,FF_MAX_SEQUENCE-2);}
code1 {o->value(nseqpos);}
@@ -343,6 +343,8 @@ formantfiltergraph->redraw();}
callback {(void)o;//pars->Psequence[nseqpos].nvowel=(int) o->value(); pars->changed=true;}
xywh {640 97 40 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textsize 10
code0 {o->bounds(0,FF_MAX_VOWELS-1);}
code1 {o->init("vowel_seq0");}
class Fl_Osc_Counter
}
Fl_Check_Button {} {
label {Neg.Input}


+ 3
- 0
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Value.H View File

@@ -21,4 +21,7 @@ class Fl_Osc_Value: public Fl_Value_Input, public Fl_Osc_Widget
//Normal Initialization
void init(const char *path);
void OSC_value(float v);

void cb();
};

+ 21
- 2
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Value.cpp View File

@@ -11,16 +11,35 @@
*/
#include "Fl_Osc_Value.H"

static void callback_fn_value(Fl_Widget *w, void *)
{
((Fl_Osc_Value*)w)->cb();
}

Fl_Osc_Value::Fl_Osc_Value(int X, int Y, int W, int H, const char *label)
:Fl_Value_Input(X,Y,W,H, label), Fl_Osc_Widget(this)
{
Fl_Value_Input::callback(callback_fn_value);
}

Fl_Osc_Value::~Fl_Osc_Value(void)
{}

void Fl_Osc_Value::init(const char *path)
void Fl_Osc_Value::init(const char *path_)
{
ext = path_;
oscRegister(path_);
}

void Fl_Osc_Value::OSC_value(float v)
{
(void)path;
//static char value[1024];
//snprintf(value, sizeof(value), "%f", v);
this->value(v);
}

void Fl_Osc_Value::cb(void)
{
assert(osc);
oscWrite(ext, "f", (float)(value()));
}

+ 2
- 2
source/native-plugins/zynaddsubfx/UI/MasterUI.fl View File

@@ -2,7 +2,7 @@
version 1.0302
header_name {.h}
code_name {.cc}
decl {//Copyright (c) 2002-2009 Nasca Octavian Paul} {private local
decl {//Copyright (c) 2002-2009 Nasca Octavian Paul - (c) 2009-2016 Mark McCurry} {private local
}

decl {//License: GNU GPL version 2 or later} {private local
@@ -869,7 +869,7 @@ panelwindow->show();}
xywh {411 344 365 280} type Double hide
} {
Fl_Box {} {
label {Copyright (c) 2002-2009 Nasca O. PAUL and others. Please read AUTHORS.txt}
label {Copyright (c) 2002-2009 Nasca O. PAUL, 2009-2016 Mark McCurry, and others. Please read AUTHORS.txt}
xywh {15 35 335 55} labeltype EMBOSSED_LABEL labelsize 15 align 208
}
Fl_Box {} {


+ 16
- 21
source/native-plugins/zynaddsubfx/UI/NSM.C View File

@@ -22,7 +22,7 @@

#include "../Nio/Nio.h"

#ifndef NO_UI
#if defined(FLTK_UI) || defined(NTK_UI)
#include <FL/Fl.H>
#endif
#include <cstdio>
@@ -30,9 +30,10 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

extern int Pexitprogram;
#ifndef NO_UI
#if defined(FLTK_UI) || defined(NTK_UI)
#include "MasterUI.h"
extern MasterUI *ui;
#endif
@@ -40,10 +41,11 @@ extern MasterUI *ui;
extern NSM_Client *nsm;
extern char *instance_name;

NSM_Client::NSM_Client()
NSM_Client::NSM_Client(MiddleWare *m)
:project_filename(0),
display_name(0),
middleware(m)
{
project_filename = 0;
display_name = 0;
}

int command_open(const char *name,
@@ -58,9 +60,7 @@ NSM_Client::command_save(char **out_msg)
(void) out_msg;
int r = ERR_OK;

#ifndef NO_UI
ui->do_save_master(project_filename);
#endif
middleware->transmitMsg("/save_xmz", "s", project_filename);

return r;
}
@@ -82,24 +82,19 @@ NSM_Client::command_open(const char *name,

char *new_filename;

//if you're on windows enjoy the undefined behavior...
#ifndef WIN32
asprintf(&new_filename, "%s.xmz", name);
#endif

struct stat st;

int r = ERR_OK;

#ifndef NO_UI
if(0 == stat(new_filename, &st)) {
if(ui->do_load_master_unconditional(new_filename, display_name) < 0) {
*out_msg = strdup("Failed to load for unknown reason");
r = ERR_GENERAL;

return r;
}
}
if(0 == stat(new_filename, &st))
middleware->transmitMsg("/load_xmz", "s", new_filename);
else
ui->do_new_master_unconditional();
#endif
middleware->transmitMsg("/reset_master", "");

if(project_filename)
free(project_filename);
@@ -114,7 +109,7 @@ NSM_Client::command_open(const char *name,
return r;
}

#ifndef NO_UI
#if defined(FLTK_UI) || defined(NTK_UI)
static void save_callback(Fl_Widget *, void *v)
{
MasterUI *ui = static_cast<MasterUI*>(v);
@@ -125,7 +120,7 @@ static void save_callback(Fl_Widget *, void *v)
void
NSM_Client::command_active(bool active)
{
#ifndef NO_UI
#if defined(FLTK_UI) || defined(NTK_UI)
if(active) {
Fl_Menu_Item *m;
//TODO see if there is a cleaner way of doing this without voiding


+ 3
- 1
source/native-plugins/zynaddsubfx/UI/NSM.H View File

@@ -21,6 +21,7 @@

#if USE_NSM
#include "NSM/Client.H"
#include "../Misc/MiddleWare.h"

class NSM_Client:public NSM::Client
{
@@ -28,8 +29,9 @@ class NSM_Client:public NSM::Client

char *project_filename;
char *display_name;
MiddleWare *middleware;

NSM_Client();
NSM_Client(MiddleWare *m);
~NSM_Client() { }

protected:


+ 1
- 1
source/native-plugins/zynaddsubfx/UI/guimain.cpp View File

@@ -46,7 +46,7 @@ bool fileexists(const char *filename)
return false;
}

int Pexitprogram = 0;
int Pexitprogram=0;


#include "Connection.h"


+ 146
- 18
source/native-plugins/zynaddsubfx/main.cpp View File

@@ -17,15 +17,17 @@
#include <map>
#include <cmath>
#include <cctype>
#include <ctime>
#include <algorithm>
#include <signal.h>

#include <err.h>
#include <unistd.h>
#include <pthread.h>

#include <getopt.h>

#include <lo/lo.h>
#include <rtosc/rtosc.h>
#include <rtosc/ports.h>
#include <rtosc/thread-link.h>
#include "Params/PADnoteParameters.h"
@@ -39,6 +41,7 @@

//Nio System
#include "Nio/Nio.h"
#include "Nio/InMgr.h"

//GUI System
#include "UI/Connection.h"
@@ -53,7 +56,7 @@ using namespace std;
Master *master;
int swaplr = 0; //1 for left-right swapping

int Pexitprogram = 0; //if the UI set this to 1, the program will exit
extern int Pexitprogram; //if the UI set this to 1, the program will exit

#if LASH
#include "Misc/LASHClient.h"
@@ -70,7 +73,6 @@ char *instance_name = 0;

void exitprogram(const Config &config);

extern pthread_t main_thread;

//cleanup on signaled exit
void sigterm_exit(int /*sig*/)
@@ -117,9 +119,88 @@ void exitprogram(const Config& config)
FFT_cleanup();
}

//Windows MIDI OH WHAT A HACK...
#ifdef WIN32
#include <windows.h>
#include <mmsystem.h>
extern InMgr *in;
HMIDIIN winmidiinhandle = 0;

void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,
DWORD dwParam1,DWORD dwParam2)
{
int midicommand=0;
if (wMsg==MIM_DATA) {
int cmd,par1,par2;
cmd=dwParam1&0xff;
if (cmd==0xfe) return;
par1=(dwParam1>>8)&0xff;
par2=dwParam1>>16;
int cmdchan=cmd&0x0f;
int cmdtype=(cmd>>4)&0x0f;

int tmp=0;
MidiEvent ev;
switch (cmdtype) {
case(0x8)://noteon
ev.type = 1;
ev.num = par1;
ev.channel = cmdchan;
ev.value = 0;
in->putEvent(ev);
break;
case(0x9)://noteoff
ev.type = 1;
ev.num = par1;
ev.channel = cmdchan;
ev.value = par2&0xff;
in->putEvent(ev);
break;
case(0xb)://controller
ev.type = 2;
ev.num = par1;
ev.channel = cmdchan;
ev.value = par2&0xff;
in->putEvent(ev);
break;
case(0xe)://pitch wheel
//tmp=(par1+par2*(long int) 128)-8192;
//winmaster->SetController(cmdchan,C_pitchwheel,tmp);
break;
default:
break;
};

};
};

void InitWinMidi(int midi)
{
(void)midi;
for(int i=0; i<10; ++i) {
long int res=midiInOpen(&winmidiinhandle,i,(DWORD_PTR)(void*)WinMidiInProc,0,CALLBACK_FUNCTION);
if(res == MMSYSERR_NOERROR) {
res=midiInStart(winmidiinhandle);
printf("[INFO] Starting Windows MIDI At %d with code %d(noerror=%d)\n", i, res, MMSYSERR_NOERROR);
if(res == 0)
return;
} else
printf("[INFO] No Windows MIDI Device At id %d\n", i);
}
};

//void StopWinMidi()
//{
// midiInStop(winmidiinhandle);
// midiInClose(winmidiinhandle);
//};
#else
void InitWinMidi(int) {}
#endif


int main(int argc, char *argv[])
{
main_thread = pthread_self();
SYNTH_T synth;
Config config;
config.init();
@@ -156,6 +237,9 @@ int main(int argc, char *argv[])
{
"load-instrument", 2, NULL, 'L'
},
{
"midi-learn", 2, NULL, 'M'
},
{
"sample-rate", 2, NULL, 'r'
},
@@ -210,9 +294,6 @@ int main(int argc, char *argv[])
{
"dump-json-schema", 2, NULL, 'D'
},
{
"ui-title", 1, NULL, 'u'
},
{
0, 0, 0, 0
}
@@ -221,8 +302,9 @@ int main(int argc, char *argv[])
int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
int prefered_port = -1;
int auto_save_interval = 60;
int wmidi = -1;

string loadfile, loadinstrument, execAfterInit, ui_title;
string loadfile, loadinstrument, execAfterInit, loadmidilearn;

while(1) {
int tmp = 0;
@@ -230,7 +312,7 @@ int main(int argc, char *argv[])
/**\todo check this process for a small memory leak*/
opt = getopt_long(argc,
argv,
"l:L:r:b:o:I:O:N:e:P:A:u:D:hvapSDUY",
"l:L:M:r:b:o:I:O:N:e:P:A:D:hvapSDUYZ",
opts,
&option_index);
char *optarguments = optarg;
@@ -267,6 +349,9 @@ int main(int argc, char *argv[])
case 'L':
GETOP(loadinstrument);
break;
case 'M':
GETOP(loadmidilearn);
break;
case 'r':
GETOPNUM(synth.samplerate);
if(synth.samplerate < 4000) {
@@ -351,9 +436,9 @@ int main(int argc, char *argv[])
dump_json(outfile, Master::ports);
}
break;
case 'u':
case 'Z':
if(optarguments)
ui_title = optarguments;
wmidi = atoi(optarguments);
break;
case '?':
cerr << "ERROR:Bad option or parameter.\n" << endl;
@@ -374,6 +459,7 @@ int main(int argc, char *argv[])
<< " -v , --version \t\t\t Display version and exit\n"
<< " -l file, --load=FILE\t\t\t Loads a .xmz file\n"
<< " -L file, --load-instrument=FILE\t Loads a .xiz file\n"
<< " -M file, --midi-learn=FILE\t\t Loads a .xlz file\n"
<< " -r SR, --sample-rate=SR\t\t Set the sample rate SR\n"
<<
" -b BS, --buffer-size=SR\t\t Set the buffer size (granularity)\n"
@@ -391,7 +477,6 @@ int main(int argc, char *argv[])
<< " -I , --input\t\t\t\t Set Input Engine\n"
<< " -e , --exec-after-init\t\t Run post-initialization script\n"
<< " -d , --dump-oscdoc=FILE\t\t Dump oscdoc xml to file\n"
<< " -u , --ui-title=TITLE\t\t Extend UI Window Titles\n"
<< endl;

return 0;
@@ -441,22 +526,34 @@ int main(int argc, char *argv[])
}
}

if(!loadmidilearn.empty()) {
char msg[1024];
rtosc_message(msg, sizeof(msg), "/load_xlz",
"s", loadmidilearn.c_str());
middleware->transmitMsg(msg);
}

if(altered_master)
middleware->updateResources(master);

//Run the Nio system
printf("[INFO] Nio::start()\n");
bool ioGood = Nio::start();

printf("[INFO] exec-after-init\n");
if(!execAfterInit.empty()) {
cout << "Executing user supplied command: " << execAfterInit << endl;
if(system(execAfterInit.c_str()) == -1)
cerr << "Command Failed..." << endl;
}

InitWinMidi(wmidi);


gui = NULL;

//Capture Startup Responses
printf("[INFO] startup OSC\n");
typedef std::vector<const char *> wait_t;
wait_t msg_waitlist;
middleware->setUiCallback([](void*v,const char*msg) {
@@ -467,21 +564,19 @@ int main(int argc, char *argv[])
wait.push_back(copy);
}, &msg_waitlist);

printf("[INFO] UI calbacks\n");
if(!noui)
gui = GUI::createUi(middleware->spawnUiApi(), &Pexitprogram);
middleware->setUiCallback(GUI::raiseUi, gui);
middleware->setIdleCallback([](void*){GUI::tickUi(gui);}, NULL);

//Replay Startup Responses
printf("[INFO] OSC replay\n");
for(auto msg:msg_waitlist) {
GUI::raiseUi(gui, msg);
delete [] msg;
}

//set titles
if(!ui_title.empty())
GUI::raiseUi(gui, "/ui/title", "s", ui_title.c_str());

if(!noui)
{
GUI::raiseUi(gui, "/show", "i", config.cfg.UserInterfaceMode);
@@ -490,18 +585,31 @@ int main(int argc, char *argv[])
"Default IO did not initialize.\nDefaulting to NULL backend.");
}

if(auto_save_interval > 0) {
printf("[INFO] auto_save setup\n");
if(auto_save_interval > 0 && false) {
int old_save = middleware->checkAutoSave();
if(old_save > 0)
GUI::raiseUi(gui, "/alert-reload", "i", old_save);
middleware->enableAutoSave(auto_save_interval);
}
printf("[INFO] NSM Stuff\n");

//TODO move this stuff into Cmake
#if USE_NSM && defined(WIN32)
#undef USE_NSM
#define USE_NSM 0
#endif

#if LASH && defined(WIN32)
#undef LASH
#define LASH 0
#endif

#if USE_NSM
char *nsm_url = getenv("NSM_URL");

if(nsm_url) {
nsm = new NSM_Client;
nsm = new NSM_Client(middleware);

if(!nsm->init(nsm_url))
nsm->announce("ZynAddSubFX", ":switch:", argv[0]);
@@ -512,6 +620,7 @@ int main(int argc, char *argv[])
}
#endif

printf("[INFO] LASH Stuff\n");
#if USE_NSM
if(!nsm)
#endif
@@ -522,7 +631,22 @@ int main(int argc, char *argv[])
#endif
}

#ifdef ZEST_GUI
if(!noui) {
printf("[INFO] Launching Zyn-Fusion...\n");
const char *addr = middleware->getServerAddress();
if(fork() == 0) {
execlp("zyn-fusion", "zyn-fusion", addr, "--builtin", "--no-hotload", 0);
execlp("./zyn-fusion", "zyn-fusion", addr, "--builtin", "--no-hotload", 0);

err(1,"Failed to launch Zyn-Fusion");
}
}
#endif

printf("[INFO] Main Loop...\n");
while(Pexitprogram == 0) {
#ifndef WIN32
#if USE_NSM
if(nsm) {
nsm->check();
@@ -553,7 +677,11 @@ int main(int argc, char *argv[])
done:
#endif
GUI::tickUi(gui);
#endif
middleware->tick();
#ifdef WIN32
Sleep(1);
#endif
}

exitprogram(config);


+ 34
- 1
source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp View File

@@ -19,6 +19,13 @@ RtData::RtData(void)
:loc(NULL), loc_size(0), obj(NULL), matches(0), message(NULL)
{}

void RtData::replyArray(const char *path, const char *args,
rtosc_arg_t *vals)
{
(void) path;
(void) args;
(void) vals;
}
void RtData::reply(const char *path, const char *args, ...)
{
va_list va;
@@ -30,6 +37,23 @@ void RtData::reply(const char *path, const char *args, ...)
};
void RtData::reply(const char *msg)
{(void)msg;};
void RtData::chain(const char *path, const char *args, ...)
{
(void) path;
(void) args;
}

void RtData::chain(const char *msg)
{
(void) msg;
};
void RtData::chainArray(const char *path, const char *args,
rtosc_arg_t *vals)
{
(void) path;
(void) args;
(void) vals;
};
void RtData::broadcast(const char *path, const char *args, ...)
{
va_list va;
@@ -41,9 +65,18 @@ void RtData::broadcast(const char *path, const char *args, ...)
}
void RtData::broadcast(const char *msg)
{reply(msg);};
void RtData::broadcastArray(const char *path, const char *args,
rtosc_arg_t *vals)
{
(void) path;
(void) args;
(void) vals;
}

void RtData::forward(const char *rational)
{}
{
(void) rational;
}

void metaiterator_advance(const char *&title, const char *&value)
{


+ 1
- 1
source/native-plugins/zynaddsubfx/rtosc/port-sugar.h View File

@@ -91,7 +91,7 @@ struct rtosc_hack_decltype_t
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)
#define OPTIONS_IMP13(a,b,c,d,e,f,g,h,i,j,k,l,m) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)
#define OPTIONS_IMP12(a,b,c,d,e,f,g,h,i,j,k,l) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)


+ 5
- 5
source/native-plugins/zynaddsubfx/rtosc/ports.h View File

@@ -55,17 +55,17 @@ struct RtData
const char *message;

virtual void replyArray(const char *path, const char *args,
rtosc_arg_t *vals){};
rtosc_arg_t *vals);
virtual void reply(const char *path, const char *args, ...);
virtual void reply(const char *msg);
virtual void chain(const char *path, const char *args, ...){};
virtual void chain(const char *msg){};
virtual void chain(const char *path, const char *args, ...);
virtual void chain(const char *msg);
virtual void chainArray(const char *path, const char *args,
rtosc_arg_t *vals){};
rtosc_arg_t *vals);
virtual void broadcast(const char *path, const char *args, ...);
virtual void broadcast(const char *msg);
virtual void broadcastArray(const char *path, const char *args,
rtosc_arg_t *vals){};
rtosc_arg_t *vals);

virtual void forward(const char *rational=NULL);
};


+ 3
- 17
source/native-plugins/zynaddsubfx/version.cpp View File

@@ -15,26 +15,12 @@

#include "zyn-version.h"

constexpr int version_type::v_strcmp(const version_type& v2, int i) const
{
return (i == sizeof(version))
? 0
: ((version[i] == v2.version[i])
? v_strcmp(v2, i+1)
: (version[i] - v2.version[i]));
}

constexpr bool version_type::operator<(const version_type& other) const
{
return v_strcmp(other, 0) < 0;
}

std::ostream& operator<< (std::ostream& os,
const version_type& v)
{
return os << v.major() << '.'
<< v.minor() << '.'
<< v.revision();
return os << v.get_major() << '.'
<< v.get_minor() << '.'
<< v.get_revision();
}

static_assert(!(version_type(3,1,1) < version_type(1,3,3)),


+ 19
- 7
source/native-plugins/zynaddsubfx/zyn-version.h View File

@@ -23,8 +23,15 @@ class version_type
char version[3];

// strcmp-like comparison against another version_type
constexpr int v_strcmp(const version_type& v2, int i) const;

constexpr int v_strcmp(const version_type& v2, int i) const
{
return (i == sizeof(version))
? 0
: ((version[i] == v2.version[i])
? v_strcmp(v2, i+1)
: (version[i] - v2.version[i]));
}
public:
constexpr version_type(char maj, char min, char rev) :
version{maj, min, rev}
@@ -33,7 +40,9 @@ public:

//! constructs the current zynaddsubfx version
constexpr version_type() :
version_type(2, 4, 4)
version_type(3,
0,
1)
{
}

@@ -41,11 +50,14 @@ public:
void set_minor(int min) { version[1] = min; }
void set_revision(int rev) { version[2] = rev; }

int major() const { return version[0]; }
int minor() const { return version[1]; }
int revision() const { return version[2]; }
int get_major() const { return version[0]; }
int get_minor() const { return version[1]; }
int get_revision() const { return version[2]; }

constexpr bool operator<(const version_type& other) const;
constexpr bool operator<(const version_type& other) const
{
return v_strcmp(other, 0) < 0;
}

//! prints version as <major>.<minor>.<revision>
friend std::ostream& operator<< (std::ostream& os,


Loading…
Cancel
Save