@@ -144,6 +144,7 @@ bin/resources/*.py | |||
source/native-plugins/resources/*.py | |||
# zynaddsubfx | |||
source/native-plugins/zynaddsubfx/rtosc/version.c.in | |||
source/native-plugins/zynaddsubfx/Output/ | |||
source/native-plugins/zynaddsubfx/Tests/ | |||
source/native-plugins/zynaddsubfx/UI/ADnoteUI.cpp | |||
@@ -14,6 +14,7 @@ rm -f $CARLA_ZYN_DIR/Misc/* | |||
rm -f $CARLA_ZYN_DIR/Nio/* | |||
rm -f $CARLA_ZYN_DIR/Params/* | |||
rm -f $CARLA_ZYN_DIR/Synth/* | |||
rm -f $CARLA_ZYN_DIR/Tests/* | |||
rm -fr $CARLA_ZYN_DIR/UI/* | |||
rm -fr $CARLA_ZYN_DIR/rtosc/* | |||
rm -f $CARLA_ZYN_DIR/tlsf/* | |||
@@ -39,7 +40,13 @@ rm $CARLA_ZYN_DIR/UI/zynaddsubfx.xpm | |||
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|${VERSION_REVISION}|2|' $CARLA_ZYN_DIR/zyn-version.h | |||
find $CARLA_ZYN_DIR -name "*.h" -type f | xargs sed -i "s|namespace zyn|namespace zyncarla|g" | |||
find $CARLA_ZYN_DIR -name "*.fl" -type f | xargs sed -i "s|namespace zyn|namespace zyncarla|g" | |||
find $CARLA_ZYN_DIR -name "*.cpp" -type f | xargs sed -i "s|namespace zyn|namespace zyncarla|g" | |||
sed -i "s|zyn::|zyncarla::|g" $CARLA_ZYN_DIR/*/*.h | |||
sed -i "s|zyn::|zyncarla::|g" $CARLA_ZYN_DIR/*/*.cpp | |||
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 | |||
@@ -31,7 +31,7 @@ endif # EXPERIMENTAL_PLUGINS | |||
ifeq ($(HAVE_ZYN_DEPS),true) | |||
ZYN_CXX_FLAGS = $(BUILD_CXX_FLAGS) -Izynaddsubfx -Izynaddsubfx/rtosc | |||
ZYN_CXX_FLAGS += -Wno-misleading-indentation -Wno-shift-negative-value | |||
ZYN_CXX_FLAGS += -Wno-misleading-indentation -Wno-shift-negative-value -fpermissive | |||
ZYN_CXX_FLAGS += $(shell pkg-config --cflags fftw3 mxml zlib) | |||
ZYN_LD_FLAGS = $(LINK_FLAGS) | |||
ZYN_LD_FLAGS += $(shell pkg-config --libs liblo) | |||
@@ -34,6 +34,8 @@ using juce::roundToIntAccurate; | |||
using juce::FloatVectorOperations; | |||
using juce::SharedResourcePointer; | |||
using namespace zyncarla; | |||
// ----------------------------------------------------------------------- | |||
template<class ZynFX> | |||
@@ -241,7 +241,9 @@ extern "C" { | |||
#undef rChangeCb | |||
#define rChangeCb | |||
#define INSTRUMENT_EXTENSION INSTRUMENT_EXTENSION_DB | |||
#include "zynaddsubfx/Misc/BankDb.cpp" | |||
#undef INSTRUMENT_EXTENSION | |||
#undef rBegin | |||
#undef rObject | |||
#undef rStdString | |||
@@ -528,6 +530,7 @@ extern "C" { | |||
#include "zynaddsubfx/globals.cpp" | |||
// Dummy variables and functions for linking purposes | |||
namespace zyncarla { | |||
class WavFile; | |||
namespace Nio { | |||
void masterSwap(Master*){} | |||
@@ -541,3 +544,4 @@ namespace Nio { | |||
void waveStart(){} | |||
void waveStop(){} | |||
} | |||
} |
@@ -38,6 +38,8 @@ using juce::roundToIntAccurate; | |||
using juce::FloatVectorOperations; | |||
using juce::ScopedPointer; | |||
using namespace zyncarla; | |||
// #define ZYN_MSG_ANYWHERE | |||
// ----------------------------------------------------------------------- | |||
@@ -73,7 +75,7 @@ public: | |||
std::vector<const ProgramInfo*> programs; | |||
programs.push_back(new ProgramInfo(0, 0, "default", "")); | |||
CarlaConfig config; | |||
Config config; | |||
config.init(); | |||
SYNTH_T synth; | |||
@@ -834,7 +836,7 @@ private: | |||
MiddleWare* fMiddleWare; | |||
Master* fMaster; | |||
SYNTH_T fSynth; | |||
CarlaConfig fConfig; | |||
Config fConfig; | |||
char* fDefaultState; | |||
float fParameters[kParamCount]; | |||
@@ -15,6 +15,9 @@ | |||
#define INVALID ((int32_t)0xffffffff) | |||
#define MAX ((int32_t)0x7fffffff) | |||
namespace zyncarla { | |||
QueueListItem::QueueListItem(void) | |||
:memory(0), size(0) | |||
{ | |||
@@ -114,3 +117,5 @@ MultiQueue::~MultiQueue(void) | |||
delete [] pool[i].memory; | |||
delete [] pool; | |||
} | |||
} |
@@ -13,6 +13,8 @@ | |||
#include <atomic> | |||
#include <cassert> | |||
namespace zyncarla { | |||
//XXX rename this thing | |||
typedef struct QueueListItem qli_t; | |||
struct QueueListItem | |||
@@ -60,3 +62,5 @@ class MultiQueue | |||
void write(qli_t *q) { m_msgs.write(q); } | |||
qli_t *read(void) { return m_msgs.read(); } | |||
}; | |||
} |
@@ -19,6 +19,8 @@ | |||
#define SUSTAIN_BIT 0x04 | |||
#define NOTE_MASK 0x03 | |||
namespace zyncarla { | |||
enum NoteStatus { | |||
KEY_OFF = 0x00, | |||
KEY_PLAYING = 0x01, | |||
@@ -430,3 +432,5 @@ void NotePool::dump(void) | |||
} | |||
printf(">NotePool::dump\n"); | |||
} | |||
} |
@@ -17,6 +17,8 @@ | |||
//Expected upper bound of synths given that max polyphony is hit | |||
#define EXPECTED_USAGE 3 | |||
namespace zyncarla { | |||
struct LegatoParams; | |||
class NotePool | |||
{ | |||
@@ -145,3 +147,5 @@ class NotePool | |||
void dump(void); | |||
}; | |||
} |
@@ -2,6 +2,8 @@ | |||
#include <cstring> | |||
#include <cstdio> | |||
namespace zyncarla { | |||
ScratchString::ScratchString(void) | |||
{ | |||
memset(c_str, 0, sizeof(c_str)); | |||
@@ -37,3 +39,5 @@ ScratchString ScratchString::operator+(const ScratchString s) | |||
//{ | |||
// return c_str; | |||
//} | |||
} |
@@ -1,6 +1,8 @@ | |||
#pragma once | |||
#define SCRATCH_SIZE 128 | |||
namespace zyncarla { | |||
//Fixed Size String Substitute | |||
struct ScratchString | |||
{ | |||
@@ -15,3 +17,6 @@ struct ScratchString | |||
char c_str[SCRATCH_SIZE]; | |||
}; | |||
} | |||
@@ -20,6 +20,8 @@ | |||
#include "../Misc/Util.h" | |||
#include "AnalogFilter.h" | |||
namespace zyncarla { | |||
AnalogFilter::AnalogFilter(unsigned char Ftype, | |||
float Ffreq, | |||
float Fq, | |||
@@ -423,3 +425,5 @@ float AnalogFilter::H(float freq) | |||
h = h / (x * x + y * y); | |||
return powf(h, (stages + 1.0f) / 2.0f); | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
#include "../globals.h" | |||
#include "Filter.h" | |||
namespace zyncarla { | |||
/**Implementation of Several analog filters (lowpass, highpass...) | |||
* Implemented with IIR filters | |||
* Coefficients generated with "Cookbook formulae for audio EQ"*/ | |||
@@ -77,5 +79,6 @@ class AnalogFilter:public Filter | |||
//(used to see if it needs interpolation) | |||
}; | |||
} | |||
#endif |
@@ -17,6 +17,8 @@ | |||
#include <pthread.h> | |||
#include "FFTwrapper.h" | |||
namespace zyncarla { | |||
static pthread_mutex_t *mutex = NULL; | |||
FFTwrapper::FFTwrapper(int fftsize_) | |||
@@ -91,3 +93,5 @@ void FFT_cleanup() | |||
delete mutex; | |||
mutex = NULL; | |||
} | |||
} |
@@ -17,6 +17,8 @@ | |||
#include <complex> | |||
#include "../globals.h" | |||
namespace zyncarla { | |||
/**A wrapper for the FFTW library (Fast Fourier Transforms)*/ | |||
class FFTwrapper | |||
{ | |||
@@ -58,4 +60,7 @@ FFTpolar(const _Tp& __rho, const _Tp& __theta = _Tp(0)) | |||
} | |||
void FFT_cleanup(); | |||
} | |||
#endif |
@@ -22,6 +22,8 @@ | |||
#include "../Params/FilterParams.h" | |||
#include "../Misc/Allocator.h" | |||
namespace zyncarla { | |||
Filter::Filter(unsigned int srate, int bufsize) | |||
: outgain(1.0f), | |||
samplerate(srate), | |||
@@ -65,3 +67,5 @@ float Filter::getrealfreq(float freqpitch) | |||
{ | |||
return powf(2.0f, freqpitch + 9.96578428f); //log2(1000)=9.95748f | |||
} | |||
} |
@@ -16,6 +16,8 @@ | |||
#include "../globals.h" | |||
namespace zyncarla { | |||
class Filter | |||
{ | |||
public: | |||
@@ -53,4 +55,6 @@ class Filter | |||
} | |||
}; | |||
} | |||
#endif |
@@ -19,6 +19,8 @@ | |||
#include "AnalogFilter.h" | |||
#include "../Params/FilterParams.h" | |||
namespace zyncarla { | |||
FormantFilter::FormantFilter(const FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize) | |||
:Filter(srate, bufsize), memory(*alloc) | |||
{ | |||
@@ -215,3 +217,5 @@ void FormantFilter::filterout(float *smp) | |||
oldformantamp[j] = currentformants[j].amp; | |||
} | |||
} | |||
} |
@@ -17,6 +17,7 @@ | |||
#include "../globals.h" | |||
#include "Filter.h" | |||
namespace zyncarla { | |||
class FormantFilter:public Filter | |||
{ | |||
@@ -55,4 +56,6 @@ class FormantFilter:public Filter | |||
Allocator &memory; | |||
}; | |||
} | |||
#endif |
@@ -24,6 +24,8 @@ | |||
#include <err.h> | |||
#endif | |||
namespace zyncarla { | |||
SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq, | |||
unsigned char Fstages, unsigned int srate, int bufsize) | |||
:Filter(srate, bufsize), | |||
@@ -229,3 +231,5 @@ void SVFilter::filterout(float *smp) | |||
for(int i = 0; i < buffersize; ++i) | |||
smp[i] *= outgain; | |||
} | |||
} |
@@ -17,6 +17,8 @@ | |||
#include "../globals.h" | |||
#include "Filter.h" | |||
namespace zyncarla { | |||
class SVFilter:public Filter | |||
{ | |||
public: | |||
@@ -67,4 +69,6 @@ class SVFilter:public Filter | |||
bool needsinterpolation, firsttime; | |||
}; | |||
} | |||
#endif |
@@ -24,6 +24,8 @@ | |||
#include <err.h> | |||
#endif | |||
namespace zyncarla { | |||
Unison::Unison(Allocator *alloc_, int update_period_samples_, float max_delay_sec_, float srate_f) | |||
:unison_size(0), | |||
base_freq(1.0f), | |||
@@ -196,3 +198,5 @@ void Unison::updateUnisonData() | |||
} | |||
first_time = false; | |||
} | |||
} |
@@ -18,6 +18,9 @@ | |||
//how much the unison frequencies varies (always >= 1.0) | |||
#define UNISON_FREQ_SPAN 2.0f | |||
namespace zyncarla { | |||
class Allocator; | |||
class Unison | |||
@@ -67,4 +70,7 @@ class Unison | |||
float samplerate_f; | |||
Allocator &alloc; | |||
}; | |||
} | |||
#endif |
@@ -17,6 +17,8 @@ | |||
#include "../Misc/Allocator.h" | |||
#include "Alienwah.h" | |||
namespace zyncarla { | |||
using std::complex; | |||
#define rObject Alienwah | |||
@@ -34,17 +36,26 @@ rtosc::Ports Alienwah::ports = { | |||
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"), | |||
rEffParVol(rDefault(127), rPresetsAt(3, 93)), | |||
rEffParPan(), | |||
rEffPar(Pfreq, 2, rShort("freq") rPresets(70, 73, 63, 25), | |||
"Effect Frequency"), | |||
rEffPar(Pfreqrnd, 3, rShort("rand"), rPreset(1, 106) rDefault(0), | |||
"Frequency Randomness"), | |||
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, rLinear(1,100), rShort("delay"), "Delay"), | |||
rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"), | |||
rEffPar(Pphase, 10, rShort("phase"), "Phase"), | |||
rOptions(sine, triangle), rPresets(sine, sine, triangle, triangle), | |||
"LFO Shape"), | |||
rEffPar(PStereo, 5, rShort("stereo"), rPresets(62, 101, 100, 66), | |||
"Stereo Mode"), | |||
rEffPar(Pdepth, 6, rShort("depth"), rPresets(60, 60, 112, 101), | |||
"LFO Depth"), | |||
rEffPar(Pfeedback, 7, rShort("fb"), rPreset(3, 11), rDefault(105), | |||
"Feedback"), | |||
rEffPar(Pdelay, 8, rLinear(1,100), rPresets(25, 17, 31, 47), | |||
rShort("delay"), "Delay"), | |||
rEffPar(Plrcross, 9, rShort("l/r"), rDefault(0), "Left/Right Crossover"), | |||
rEffPar(Pphase, 10, rShort("phase"), rDefault(64), rPreset(2, 42), | |||
rPreset(3, 86), "Phase"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -257,3 +268,5 @@ unsigned char Alienwah::getpar(int npar) const | |||
default: return 0; | |||
} | |||
} | |||
} |
@@ -20,6 +20,8 @@ | |||
#define MAX_ALIENWAH_DELAY 100 | |||
namespace zyncarla { | |||
/**"AlienWah" Effect*/ | |||
class Alienwah:public Effect | |||
{ | |||
@@ -58,4 +60,6 @@ class Alienwah:public Effect | |||
int oldk; | |||
}; | |||
} | |||
#endif |
@@ -17,9 +17,10 @@ | |||
#include "../Misc/Allocator.h" | |||
#include "Chorus.h" | |||
#include <iostream> | |||
using namespace std; | |||
namespace zyncarla { | |||
#define rObject Chorus | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -38,17 +39,32 @@ rtosc::Ports Chorus::ports = { | |||
rEnd}, | |||
//Pvolume/Ppanning are common | |||
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), | |||
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), | |||
rEffParVol(rDefault(64)), | |||
rEffParPan(), | |||
rEffPar(Pfreq, 2, rShort("freq"), | |||
rPresets(50, 45, 29, 26, 29, 57, 33, 53, 40, 55), | |||
"Effect Frequency"), | |||
rEffPar(Pfreqrnd, 3, rShort("rand"), | |||
rPreset(4, 117) rPreset(6, 34) rPreset(7, 34) rPreset(9, 105) | |||
rDefault(0), "Frequency Randomness"), | |||
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"), | |||
rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"), | |||
rEffParTF(Pflangemode, 10, rShort("flange"), "Flange Mode"), | |||
rEffParTF(Poutsub, 11, rShort("sub"), "Output Subtraction"), | |||
rOptions(sine, tri), | |||
rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine) | |||
"LFO Shape"), | |||
rEffPar(PStereo, 5, rShort("stereo"), | |||
rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62), "Stereo Mode"), | |||
rEffPar(Pdepth, 6, rShort("depth"), | |||
rPresets(40, 56, 97, 115, 115, 23, 35, 35, 12), "LFO Depth"), | |||
rEffPar(Pdelay, 7, rShort("delay"), | |||
rPresets(85, 90, 95, 18, 9, 3, 3, 3, 19), "Delay"), | |||
rEffPar(Pfeedback,8, rShort("fb"), | |||
rPresets(64, 64, 90, 90, 31, 62, 109, 54, 97), "Feedback"), | |||
rEffPar(Plrcross, 9, rShort("l/r"), rPresets(119, 19, 127, 127, 127), | |||
rDefault(0), "Left/Right Crossover"), | |||
rEffParTF(Pflangemode, 10, rShort("flange"), rDefault(false), | |||
"Flange Mode"), | |||
rEffParTF(Poutsub, 11, rShort("sub"), rPreset(4, true), rPreset(7, true), | |||
rDefault(false), "Output Subtraction"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -294,3 +310,5 @@ unsigned char Chorus::getpar(int npar) const | |||
default: return 0; | |||
} | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
#define MAX_CHORUS_DELAY 250.0f //ms | |||
namespace zyncarla { | |||
/**Chorus and Flange effects*/ | |||
class Chorus:public Effect | |||
{ | |||
@@ -95,4 +97,6 @@ class Chorus:public Effect | |||
float getdelay(float xlfo); | |||
}; | |||
} | |||
#endif |
@@ -19,6 +19,8 @@ | |||
#include <rtosc/ports.h> | |||
#include <rtosc/port-sugar.h> | |||
namespace zyncarla { | |||
#define rObject Distorsion | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -35,21 +37,29 @@ rtosc::Ports Distorsion::ports = { | |||
else | |||
d.reply(d.loc, "i", o->Ppreset); | |||
rEnd}, | |||
//Pvolume/Ppanning are common | |||
rEffPar(Plrcross, 2, rShort("l/r"), "Left/Right Crossover"), | |||
rEffPar(Pdrive, 3, rShort("drive"), "Input amplification"), | |||
rEffPar(Plevel, 4, rShort("output"), "Output amplification"), | |||
rEffParVol(rDefault(127), rPresetsAt(2, 64, 64)), | |||
rEffParPan(), | |||
rEffPar(Plrcross, 2, rShort("l/r"), rDefault(35), "Left/Right Crossover"), | |||
rEffPar(Pdrive, 3, rShort("drive"), rPresets(56, 29, 75, 85, 63, 88), | |||
"Input amplification"), | |||
rEffPar(Plevel, 4, rShort("output"), rPresets(70, 75, 80, 62, 75, 75), | |||
"Output amplification"), | |||
rEffPar(Ptype, 5, rShort("type"), | |||
rOptions(Arctangent, Asymmetric, Pow, Sine, Quantisize, | |||
Zigzag, Limiter, Upper Limiter, Lower Limiter, | |||
Inverse Limiter, Clip, Asym2, Pow2, sigmoid), | |||
Zigzag, Limiter, Upper Limiter, Lower Limiter, | |||
Inverse Limiter, Clip, Asym2, Pow2, sigmoid), | |||
rPresets(Arctangent, Asymmetric, Zigzag, | |||
Asymmetric, Pow, Quantisize), | |||
"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"), | |||
rEffParTF(Pnegate, 6, rShort("neg"), rDefault(false), "Negate Signal"), | |||
rEffPar(Plpf, 7, rShort("lpf"), | |||
rPreset(0, 96), rPreset(4, 55), rDefault(127), "Low Pass Cutoff"), | |||
rEffPar(Phpf, 8, rShort("hpf"), | |||
rPreset(2, 105), rPreset(3, 118), rDefault(0), "High Pass Cutoff"), | |||
rEffParTF(Pstereo, 9, rShort("stereo"), | |||
rPresets(false, false, true, true, false, true), "Stereo"), | |||
rEffParTF(Pprefiltering, 10, rShort("p.filt"), rDefault(false), | |||
"Filtering before/after non-linearity"), | |||
{"waveform:", 0, 0, [](const char *, rtosc::RtData &d) | |||
{ | |||
Distorsion &dd = *(Distorsion*)d.obj; | |||
@@ -60,7 +70,8 @@ rtosc::Ports Distorsion::ports = { | |||
for(int i=0; i<128; ++i) | |||
buffer[i] = 2*(i/128.0)-1; | |||
waveShapeSmps(sizeof(buffer), buffer, dd.Ptype + 1, dd.Pdrive); | |||
waveShapeSmps(sizeof(buffer)/sizeof(buffer[0]), buffer, | |||
dd.Ptype + 1, dd.Pdrive); | |||
for(int i=0; i<128; ++i) { | |||
arg_str[i] = 'f'; | |||
@@ -292,3 +303,5 @@ unsigned char Distorsion::getpar(int npar) const | |||
default: return 0; //in case of bogus parameter number | |||
} | |||
} | |||
} |
@@ -16,6 +16,8 @@ | |||
#include "Effect.h" | |||
namespace zyncarla { | |||
/**Distortion Effect*/ | |||
class Distorsion:public Effect | |||
{ | |||
@@ -50,4 +52,6 @@ class Distorsion:public Effect | |||
class AnalogFilter * lpfl, *lpfr, *hpfl, *hpfr; | |||
}; | |||
} | |||
#endif |
@@ -20,6 +20,8 @@ | |||
#include <rtosc/ports.h> | |||
#include <rtosc/port-sugar.h> | |||
namespace zyncarla { | |||
#define rObject DynamicFilter | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -34,16 +36,24 @@ rtosc::Ports DynamicFilter::ports = { | |||
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"), | |||
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"), | |||
rEffParVol(rDefault(110), rPreset(2, 110), rPreset(4, 127)), | |||
rEffParPan(), | |||
rEffPar(Pfreq, 2, rShort("freq"), rPresets(80, 70, 30, 80, 50), | |||
"Effect Frequency"), | |||
rEffPar(Pfreqrnd, 3, rShort("rand"), rDefault(0), | |||
"Frequency Randomness"), | |||
rEffPar(PLFOtype, 4, rShort("shape"), rOptions(sin, tri), rDefault(sin), | |||
"LFO Shape"), | |||
rEffPar(PStereo, 5, rShort("stereo"), rPresets(64, 80, 50, 64, 96), | |||
"Stereo Mode"), | |||
rEffPar(Pdepth, 6, rShort("depth"), rPresets(0, 70, 80, 0, 64), | |||
"LFO Depth"), | |||
rEffPar(Pampsns, 7, rShort("sense"), | |||
rPreset(0, 90) rPreset(3, 64) rDefault(0), | |||
"how the filter varies according to the input amplitude"), | |||
rEffPar(Pampsnsinv, 8, rShort("sns.inv"), rDefault(0), "Sense Inversion"), | |||
rEffPar(Pampsmooth, 9, rShort("smooth"), rDefault(60), | |||
"how smooth the input amplitude changes the filter"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -351,3 +361,5 @@ unsigned char DynamicFilter::getpar(int npar) const | |||
default: return 0; | |||
} | |||
} | |||
} |
@@ -17,6 +17,8 @@ | |||
#include "Effect.h" | |||
#include "EffectLFO.h" | |||
namespace zyncarla { | |||
/**DynamicFilter Effect*/ | |||
class DynamicFilter:public Effect | |||
{ | |||
@@ -56,4 +58,6 @@ class DynamicFilter:public Effect | |||
float ms1, ms2, ms3, ms4; //mean squares | |||
}; | |||
} | |||
#endif |
@@ -18,6 +18,8 @@ | |||
#include "../DSP/AnalogFilter.h" | |||
#include "../Misc/Allocator.h" | |||
namespace zyncarla { | |||
using rtosc::RtData; | |||
#define rObject EQ | |||
#define rBegin [](const char *msg, RtData &d) {\ | |||
@@ -78,8 +80,8 @@ rtosc::Ports EQ::ports = { | |||
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}; | |||
char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {}; | |||
rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {}; | |||
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'; | |||
@@ -297,3 +299,5 @@ void EQ::getFilter(float *a, float *b) const | |||
} | |||
} | |||
} | |||
} |
@@ -16,6 +16,8 @@ | |||
#include "Effect.h" | |||
namespace zyncarla { | |||
/**EQ Effect*/ | |||
class EQ:public Effect | |||
{ | |||
@@ -53,4 +55,6 @@ class EQ:public Effect | |||
} filter[MAX_EQ_BANDS]; | |||
}; | |||
} | |||
#endif |
@@ -21,6 +21,8 @@ | |||
#define MAX_DELAY 2 | |||
namespace zyncarla { | |||
#define rObject Echo | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -37,12 +39,23 @@ rtosc::Ports Echo::ports = { | |||
else | |||
d.reply(d.loc, "i", o->Ppreset); | |||
rEnd}, | |||
//Pvolume/Ppanning are common | |||
rEffPar(Pdelay, 2, rShort("delay"), "Length of Echo"), | |||
rEffPar(Plrdelay, 3, rShort("lr delay"), "Difference In Left/Right Delay"), | |||
rEffPar(Plrcross, 4, rShort("cross"), "Left/Right Crossover"), | |||
rEffPar(Pfb, 5, rShort("feedback"), "Echo Feedback"), | |||
rEffPar(Phidamp, 6, rShort("damp"), "Dampen High Frequencies"), | |||
rEffParVol(rDefault(67), rPresetsAt(6, 81, 81, 62)), | |||
rEffParPan(rPresetsAt(2, 75, 60, 60, 64, 60, 60, 64)), | |||
rEffPar(Pdelay, 2, rShort("delay"), | |||
rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28), | |||
"Length of Echo"), | |||
rEffPar(Plrdelay, 3, rShort("lr delay"), | |||
rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64), | |||
"Difference In Left/Right Delay"), | |||
rEffPar(Plrcross, 4, rShort("cross"), | |||
rPresetsAt(5, 0, 100, 127, 100), rDefault(30), | |||
"Left/Right Crossover"), | |||
rEffPar(Pfb, 5, rShort("feedback"), | |||
rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90), | |||
"Echo Feedback"), | |||
rEffPar(Phidamp, 6, rShort("damp"), | |||
rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55), | |||
"Dampen High Frequencies"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -145,7 +158,11 @@ void Echo::setvolume(unsigned char _Pvolume) | |||
Pvolume = _Pvolume; | |||
if(insertion == 0) { | |||
outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
if (Pvolume == 0) { | |||
outvolume = 0.0f; | |||
} else { | |||
outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
} | |||
volume = 1.0f; | |||
} | |||
else | |||
@@ -251,3 +268,5 @@ unsigned char Echo::getpar(int npar) const | |||
default: return 0; // in case of bogus parameter number | |||
} | |||
} | |||
} |
@@ -17,6 +17,8 @@ | |||
#include "Effect.h" | |||
#include "../Misc/Stereo.h" | |||
namespace zyncarla { | |||
/**Echo Effect*/ | |||
class Echo:public Effect | |||
{ | |||
@@ -94,4 +96,6 @@ class Echo:public Effect | |||
Stereo<int> ndelta; | |||
}; | |||
} | |||
#endif |
@@ -17,6 +17,8 @@ | |||
#include "../Params/FilterParams.h" | |||
#include <cmath> | |||
namespace zyncarla { | |||
EffectParams::EffectParams(Allocator &alloc_, bool insertion_, float *efxoutl_, float *efxoutr_, | |||
unsigned char Ppreset_, unsigned int srate_, int bufsize_, FilterParams *filterpars_, | |||
bool filterprotect_) | |||
@@ -63,3 +65,5 @@ void Effect::setlrcross(char Plrcross_) | |||
Plrcross = Plrcross_; | |||
lrcross = (float)Plrcross / 127.0f; | |||
} | |||
} |
@@ -19,14 +19,15 @@ | |||
#include "../Params/FilterParams.h" | |||
#include "../Misc/Stereo.h" | |||
class FilterParams; | |||
class Allocator; | |||
// bug: the effect parameters can currently be set, but such values | |||
// will not be saved into XML files | |||
#ifndef rEffPar | |||
#define rEffPar(name, idx, ...) \ | |||
{STRINGIFY(name) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParCb(idx)} | |||
{STRINGIFY(name) "::i", rProp(parameter) rDefaultDepends(preset) \ | |||
DOC(__VA_ARGS__), NULL, rEffParCb(idx)} | |||
#define rEffParTF(name, idx, ...) \ | |||
{STRINGIFY(name) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)} | |||
{STRINGIFY(name) "::T:F", rProp(parameter) rDefaultDepends(preset) \ | |||
DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)} | |||
#define rEffParCb(idx) \ | |||
[](const char *msg, rtosc::RtData &d) {\ | |||
rObject &obj = *(rObject*)d.obj; \ | |||
@@ -43,6 +44,32 @@ class Allocator; | |||
d.reply(d.loc, obj.getpar(idx)?"T":"F");} | |||
#endif | |||
#define rEffParCommon(pname, rshort, rdoc, idx, ...) \ | |||
{STRINGIFY(pname) "::i", rProp(parameter) rLinear(0,127) \ | |||
rShort(rshort) rDoc(rdoc), \ | |||
0, \ | |||
[](const char *msg, rtosc::RtData &d) \ | |||
{ \ | |||
rObject& eff = *(rObject*)d.obj; \ | |||
if(!rtosc_narguments(msg)) \ | |||
d.reply(d.loc, "i", eff.getpar(idx)); \ | |||
else { \ | |||
eff.changepar(0, rtosc_argument(msg, 0).i); \ | |||
d.broadcast(d.loc, "i", eff.getpar(idx)); \ | |||
} \ | |||
}} | |||
#define rEffParVol(...) rEffParCommon(Pvolume, "amt", "amount of effect", 0, \ | |||
__VA_ARGS__) | |||
#define rEffParPan(...) rEffParCommon(Ppanning, "pan", "panning", 1, \ | |||
__VA_ARGS__) | |||
namespace zyncarla { | |||
class FilterParams; | |||
class Allocator; | |||
struct EffectParams | |||
{ | |||
/** | |||
@@ -154,4 +181,6 @@ class Effect | |||
} | |||
}; | |||
} | |||
#endif |
@@ -17,6 +17,8 @@ | |||
#include <cmath> | |||
#include "globals.h" | |||
namespace zyncarla { | |||
EffectLFO::EffectLFO(float srate_f, float bufsize_f) | |||
:Pfreq(40), | |||
Prandomness(0), | |||
@@ -104,3 +106,5 @@ void EffectLFO::effectlfoout(float *outl, float *outr) | |||
} | |||
*outr = (out + 1.0f) * 0.5f; | |||
} | |||
} |
@@ -14,6 +14,8 @@ | |||
#ifndef EFFECT_LFO_H | |||
#define EFFECT_LFO_H | |||
namespace zyncarla { | |||
/**LFO for some of the Effect objects | |||
* \todo see if this should inherit LFO*/ | |||
class EffectLFO | |||
@@ -41,4 +43,6 @@ class EffectLFO | |||
float buffersize_f; | |||
}; | |||
} | |||
#endif |
@@ -16,7 +16,6 @@ | |||
#include <iostream> | |||
#include <cassert> | |||
#include "EffectMgr.h" | |||
#include "Effect.h" | |||
#include "Alienwah.h" | |||
@@ -32,21 +31,23 @@ | |||
#include "../Params/FilterParams.h" | |||
#include "../Misc/Allocator.h" | |||
namespace zyncarla { | |||
#define rObject EffectMgr | |||
#define rSubtype(name) \ | |||
{STRINGIFY(name)"/", NULL, &name::ports,\ | |||
[](const char *msg, rtosc::RtData &data){\ | |||
rObject &o = *(rObject*)data.obj; \ | |||
data.obj = o.efx; \ | |||
if(!dynamic_cast<name*>(o.efx)) \ | |||
data.obj = dynamic_cast<name*>(o.efx); \ | |||
if(!data.obj) \ | |||
return; \ | |||
SNIP \ | |||
name::ports.dispatch(msg, data); \ | |||
}} | |||
static const rtosc::Ports local_ports = { | |||
rSelf(EffectMgr), | |||
rSelf(EffectMgr, rEnabledByCondition(self-enabled)), | |||
rPaste, | |||
rEnabledCondition(self-enabled, obj->geteffect()), | |||
rRecurp(filterpars, "Filter Parameter for Dynamic Filter"), | |||
{"Pvolume::i", rProp(parameter) rLinear(0,127) rShort("amt") rDoc("amount of effect"), | |||
0, | |||
@@ -93,7 +94,8 @@ static const rtosc::Ports local_ports = { | |||
d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm))); | |||
} | |||
}}, | |||
{"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector"), NULL, | |||
{"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector") | |||
rDefault(0), NULL, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
char loc[1024]; | |||
@@ -129,18 +131,10 @@ static const rtosc::Ports local_ports = { | |||
eq->getFilter(a,b); | |||
d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b); | |||
}}, | |||
{"efftype::i", rOptions(Disabled, Reverb, Echo, Chorus, | |||
Phaser, Alienwah, Distorsion, EQ, DynFilter) | |||
rProp(parameter) rDoc("Get Effect Type"), NULL, | |||
[](const char *m, rtosc::RtData &d) | |||
{ | |||
EffectMgr *eff = (EffectMgr*)d.obj; | |||
if(rtosc_narguments(m)) { | |||
eff->changeeffectrt(rtosc_argument(m,0).i); | |||
d.broadcast(d.loc, "i", eff->nefx); | |||
} else | |||
d.reply(d.loc, "i", eff->nefx); | |||
}}, | |||
{"efftype::i:c:S", rOptions(Disabled, Reverb, Echo, Chorus, | |||
Phaser, Alienwah, Distortion, EQ, DynFilter) rDefault(Disabled) | |||
rProp(parameter) rDoc("Get Effect Type"), NULL, | |||
rCOptionCb(obj->nefx, obj->changeeffectrt(var))}, | |||
{"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
@@ -472,7 +466,12 @@ void EffectMgr::add2XML(XMLwrapper& xml) | |||
xml.beginbranch("EFFECT_PARAMETERS"); | |||
for(int n = 0; n < 128; ++n) { | |||
int par = geteffectpar(n); | |||
int par = 0; | |||
if(efx) | |||
par = efx->getpar(n); | |||
else if(n<128) | |||
par = settings[n]; | |||
if(par == 0) | |||
continue; | |||
xml.beginbranch("par_no", n); | |||
@@ -515,3 +514,5 @@ void EffectMgr::getfromXML(XMLwrapper& xml) | |||
} | |||
cleanup(); | |||
} | |||
} |
@@ -16,14 +16,16 @@ | |||
#include <pthread.h> | |||
#include "../Params/FilterParams.h" | |||
#include "../Params/Presets.h" | |||
namespace zyncarla { | |||
class Effect; | |||
class FilterParams; | |||
class XMLwrapper; | |||
class Allocator; | |||
#include "../Params/FilterParams.h" | |||
#include "../Params/Presets.h" | |||
/** Effect manager, an interface between the program and effects */ | |||
class EffectMgr:public Presets | |||
{ | |||
@@ -75,6 +77,30 @@ class EffectMgr:public Presets | |||
//Parameters Prior to initialization | |||
char preset; | |||
/** | |||
* When loading an effect from XML the child effect cannot be loaded | |||
* directly as it would require access to the realtime memory pool, | |||
* which cannot be done outside of the realtime thread. | |||
* Therefore, parameters are loaded to this array which can then be used | |||
* to construct the full effect (via init()) once the object is in the | |||
* realtime context. | |||
* | |||
* Additionally this structure is used in the case of pasting effects as | |||
* pasted effect object are *not* fully initialized when they're put on | |||
* the middleware -> backend ringbuffer, but settings has the values | |||
* loaded from the XML serialization. | |||
* The settings values can be pasted once they're on the realtime thread | |||
* and then they can be applied. | |||
* | |||
* The requirement that the realtime memory pool is used to create the | |||
* effect is in place as it is possible to change the effect type in the | |||
* realtime thread and thus the new effect would draw from the realtime | |||
* memory pool and the old object would be expected to be freed to the | |||
* realtime memory pool. | |||
* | |||
* See also: PresetExtractor.cpp | |||
*/ | |||
char settings[128]; | |||
bool dryonly; | |||
@@ -82,4 +108,6 @@ class EffectMgr:public Presets | |||
const SYNTH_T &synth; | |||
}; | |||
} | |||
#endif |
@@ -21,9 +21,10 @@ | |||
#include <rtosc/port-sugar.h> | |||
#include "../Misc/Allocator.h" | |||
#include "Phaser.h" | |||
using namespace std; | |||
namespace zyncarla { | |||
#define rObject Phaser | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -36,7 +37,8 @@ using namespace std; | |||
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)} | |||
{STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) \ | |||
rDefaultDepends(preset) DOC(__VA_ARGS__), NULL, ucharParamCb(name)} | |||
rtosc::Ports Phaser::ports = { | |||
{"preset::i", rProp(parameter) | |||
@@ -52,23 +54,52 @@ rtosc::Ports Phaser::ports = { | |||
else | |||
d.reply(d.loc, "i", o->Ppreset); | |||
rEnd}, | |||
//Pvolume/Ppanning are common | |||
rEffPar(lfo.Pfreq, 2, rShort("freq"), "LFO frequency"), | |||
rEffPar(lfo.Prandomness, 3, rShort("rnd."), "LFO randomness"), | |||
rEffParVol(rDefault(64), rPreset(3, 39), rPreset(10, 25)), | |||
rEffParPan(), | |||
rEffPar(lfo.Pfreq, 2, rShort("freq"), | |||
rPresets(36, 35, 31, 22, 20, 53, 14, 14, 9, 14, 127, 1), | |||
"LFO frequency"), | |||
rEffPar(lfo.Prandomness, 3, rShort("rnd."), | |||
rPreset(5, 100), rPreset(7, 5), rPresetsAt(9, 10, 10, 10), | |||
rDefault(0), "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"), "Use analog phaser"), | |||
rPreset(4, tri), rPresetsAt(6, tri, tri), rPreset(11, tri), | |||
rDefault(sine), | |||
rOptions(sine, tri), "lfo shape"), | |||
rEffPar(lfo.Pstereo, 5, rShort("stereo"), | |||
rPresetsAt(1, 88, 66, 66, 110, 58), rDefault(64), | |||
"Left/right channel phase shift"), | |||
rEffPar(Pdepth, 6, rShort("depth"), | |||
rPresets(110, 40, 68, 67, 67, 37, 64, 70, 60, 45, 25, 70), | |||
"LFP depth"), | |||
rEffPar(Pfb, 7, rShort("fb"), | |||
rPresets(64, 64, 107, 10, 78, 78, 40, 40, 40, 80, 16, 40), | |||
"Feedback"), | |||
rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), | |||
rPresets(1, 3, 2, 5, 10, 3, 4, 6, 8, 7, 8, 12), | |||
""), | |||
rParamPhaser(lrcross, rShort("cross"), | |||
rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), | |||
"Channel routing"), | |||
rParamPhaser(offset, rShort("off"), | |||
rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), | |||
"Offset"), | |||
rEffParTF(Poutsub, 10, rShort("sub"), | |||
rPreset(3, true), rPreset(9, true), rDefault(false), | |||
"Invert output"), | |||
rParamPhaser(phase, rShort("phase"), | |||
rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), | |||
rParamPhaser(width, rShort("width"), | |||
rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), | |||
rEffParTF(Phyper, 12, rShort("hyp."), | |||
rPresetsAt(6, true, true, false, true, false, true), | |||
rDefault(false), "Square the LFO"), | |||
rEffPar(Pdistortion, 13, rShort("distort"), | |||
rPresetsAt(6, 20, 20, 20, 20, 20, 20), rDefault(0), | |||
"Distortion"), | |||
rEffParTF(Panalog, 14, rShort("analog"), | |||
rPresetsAt(6, true, true, true, true, true, true), rDefault(false), | |||
"Use analog phaser"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -496,3 +527,5 @@ unsigned char Phaser::getpar(int npar) const | |||
default: return 0; | |||
} | |||
} | |||
} |
@@ -23,6 +23,8 @@ | |||
#define MAX_PHASER_STAGES 12 | |||
namespace zyncarla { | |||
class Phaser:public Effect | |||
{ | |||
public: | |||
@@ -87,4 +89,6 @@ class Phaser:public Effect | |||
float applyPhase(float x, float g, float *old); | |||
}; | |||
} | |||
#endif |
@@ -20,6 +20,8 @@ | |||
#include <rtosc/ports.h> | |||
#include <rtosc/port-sugar.h> | |||
namespace zyncarla { | |||
#define rObject Reverb | |||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||
#define rEnd } | |||
@@ -37,18 +39,38 @@ rtosc::Ports Reverb::ports = { | |||
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("hpf"), "High pass filter"), | |||
rEffPar(Plohidamp,9, rShort("damp"), "Dampening"), | |||
rEffParVol(rDefault(90), rPresets(80, 80, 80), | |||
rPresetsAt(5, 100, 100, 110, 85, 95)), | |||
rEffParPan(rPreset(8, 80)), | |||
rEffPar(Ptime, 2, rShort("time"), | |||
rPresets(63, 69, 69, 51, 53, 33, 21, 14, 84, 26, 40, 93, 111), | |||
"Length of Reverb"), | |||
rEffPar(Pidelay, 3, rShort("i.time"), | |||
rPresets(24, 35, 24, 10, 20, 0, 26, 0, 20, 60, 88, 15, 30), | |||
"Delay for first impulse"), | |||
rEffPar(Pidelayfb,4, rShort("i.fb"), rPresetsAt(8, 42, 71, 71), rDefault(0), | |||
"Feedback for first impulse"), | |||
rEffPar(Plpf, 7, rShort("lpf"), | |||
rPreset(1, 85), rPresetsAt(62, 127, 51, 114, 114, 114), | |||
rDefault(127), "Low pass filter"), | |||
rEffPar(Phpf, 8, rShort("hpf"), | |||
rPresets(5), rPresetsAt(2, 75, 21, 75), rPreset(7, 50), | |||
rPreset(12, 90), rDefault(0), "High pass filter"), | |||
rEffPar(Plohidamp,9, rShort("damp"), rDefault(0), | |||
rPresets(83, 71, 78, 78, 71, 106, 77, 71, 78, 64, 88, 77, 74) | |||
"Dampening"), | |||
//Todo make this a selector | |||
rEffPar(Ptype, 10,rShort("type"), | |||
rOptions(Random, Freeverb, Bandwidth), "Type"), | |||
rEffPar(Proomsize,11,rShort("size"), "Room Size"), | |||
rEffPar(Pbandwidth,12,rShort("bw"), "Bandwidth"), | |||
rEffPar(Ptype, 10, rShort("type"), | |||
rOptions(Random, Freeverb, Bandwidth), | |||
rPresets(Freeverb, Random, Freeverb, Freeverb, Freeverb, Random, | |||
Freeverb, Random, Freeverb, Freeverb, Freeverb, Random, | |||
Freeverb) | |||
rDefault(Random), "Type"), | |||
rEffPar(Proomsize,11,rShort("size"), | |||
rPreset(2, 85), rPresetsAt(5, 30, 45, 25, 105), | |||
rPresetsAt(11, 95, 80), rDefault(64), | |||
"Room Size"), | |||
rEffPar(Pbandwidth,12,rShort("bw"), rDefault(20), "Bandwidth"), | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
@@ -215,7 +237,11 @@ void Reverb::setvolume(unsigned char _Pvolume) | |||
{ | |||
Pvolume = _Pvolume; | |||
if(!insertion) { | |||
outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
if (Pvolume == 0) { | |||
outvolume = 0.0f; | |||
} else { | |||
outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
} | |||
volume = 1.0f; | |||
} | |||
else { | |||
@@ -512,3 +538,5 @@ unsigned char Reverb::getpar(int npar) const | |||
default: return 0; | |||
} | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
#define REV_COMBS 8 | |||
#define REV_APS 4 | |||
namespace zyncarla { | |||
/**Creates Reverberation Effects*/ | |||
class Reverb:public Effect | |||
{ | |||
@@ -83,4 +85,6 @@ class Reverb:public Effect | |||
class AnalogFilter * lpf, *hpf; //filters | |||
}; | |||
} | |||
#endif |
@@ -17,6 +17,8 @@ | |||
#include "tlsf/tlsf.h" | |||
#include "Allocator.h" | |||
namespace zyncarla { | |||
//Used for dummy allocations | |||
DummyAllocator DummyAlloc; | |||
@@ -230,3 +232,5 @@ void Allocator::rollbackTransaction() { | |||
* pool size and the next pool in the list as this information is not | |||
* accessible in O(good) time | |||
*/ | |||
} |
@@ -14,6 +14,8 @@ | |||
#include <utility> | |||
#include <new> | |||
namespace zyncarla { | |||
//! Allocator Base class | |||
//! subclasses must specify allocation and deallocation | |||
class Allocator | |||
@@ -198,3 +200,5 @@ extern DummyAllocator DummyAlloc; | |||
* * A new one is constructed with a deep copy | |||
* * The old one is returned to middleware for deallocation | |||
*/ | |||
} |
@@ -30,15 +30,20 @@ | |||
#include "Util.h" | |||
#include "Part.h" | |||
#include "BankDb.h" | |||
#ifdef WIN32 | |||
#include <windows.h> | |||
#endif | |||
#define INSTRUMENT_EXTENSION ".xiz" | |||
using namespace std; | |||
//if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file | |||
#define FORCE_BANK_DIR_FILE ".bankdir" | |||
namespace zyncarla { | |||
using namespace std; | |||
static const char* INSTRUMENT_EXTENSION = ".xiz"; | |||
//if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file | |||
const char* FORCE_BANK_DIR_FILE = ".bankdir"; | |||
Bank::Bank(CarlaConfig *config) | |||
Bank::Bank(Config *config) | |||
:bankpos(0), defaultinsname(" "), config(config), | |||
db(new BankDb), bank_msb(0), bank_lsb(0) | |||
{ | |||
@@ -360,6 +365,18 @@ void Bank::rescanforbanks() | |||
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
if(!config->cfg.bankRootDirList[i].empty()) | |||
scanrootdir(config->cfg.bankRootDirList[i]); | |||
#ifdef WIN32 | |||
{ | |||
//Search the VST Directory for banks/preset/etc | |||
char path[1024]; | |||
GetModuleFileName(GetModuleHandle("ZynAddSubFX.dll"), path, sizeof(path)); | |||
if(strstr(path, "ZynAddSubFX.dll")) { | |||
strstr(path, "ZynAddSubFX.dll")[0] = 0; | |||
strcat(path, "banks"); | |||
scanrootdir(path); | |||
} | |||
} | |||
#endif | |||
//sort the banks | |||
sort(banks.begin(), banks.end()); | |||
@@ -471,7 +488,7 @@ 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; | |||
@@ -544,3 +561,5 @@ void Bank::normalizedirsuffix(string &dirname) const { | |||
&& ((dirname[dirname.size() - 1]) != '\\')) | |||
dirname += "/"; | |||
} | |||
} |
@@ -22,12 +22,14 @@ | |||
//entries in a bank | |||
#define BANK_SIZE 160 | |||
namespace zyncarla { | |||
/**The instrument Bank*/ | |||
class Bank | |||
{ | |||
public: | |||
/**Constructor*/ | |||
Bank(CarlaConfig* config); | |||
Bank(Config* config); | |||
~Bank(); | |||
std::string getname(unsigned int ninstrument); | |||
std::string getnamenumbered(unsigned int ninstrument); | |||
@@ -102,7 +104,7 @@ class Bank | |||
* directory separator */ | |||
void normalizedirsuffix(std::string &dirname) const; | |||
CarlaConfig* const config; | |||
Config* const config; | |||
class BankDb *db; | |||
public: | |||
@@ -110,4 +112,6 @@ class Bank | |||
uint8_t bank_lsb; | |||
}; | |||
} | |||
#endif |
@@ -6,7 +6,9 @@ | |||
#include <dirent.h> | |||
#include <sys/stat.h> | |||
#define INSTRUMENT_EXTENSION ".xiz" | |||
namespace zyncarla { | |||
static const char* INSTRUMENT_EXTENSION = ".xiz"; | |||
using std::string; | |||
typedef BankDb::svec svec; | |||
@@ -57,7 +59,7 @@ bool BankEntry::match(string s) const | |||
bool BankEntry::operator<(const BankEntry &b) const | |||
{ | |||
return this->file < b.file; | |||
return (this->bank+this->file) < (b.bank+b.file); | |||
} | |||
static svec split(string s) | |||
@@ -227,16 +229,20 @@ BankEntry BankDb::processXiz(std::string filename, | |||
{ | |||
string fname = bank+filename; | |||
#ifdef WIN32 | |||
int ret, time = 0; | |||
#else | |||
//Grab a timestamp | |||
struct stat st; | |||
int ret = lstat(fname.c_str(), &st); | |||
int time = 0; | |||
//gah windows, just implement the darn standard APIs | |||
#ifndef WIN32 | |||
int ret = lstat(fname.c_str(), &st); | |||
if(ret != -1) | |||
time = st.st_mtim.tv_sec; | |||
#else | |||
int ret = 0; | |||
time = rand(); | |||
#endif | |||
//quickly check if the file exists in the cache and if it is up-to-date | |||
if(cache.find(fname) != cache.end() && | |||
@@ -343,3 +349,5 @@ BankEntry BankDb::processXiz(std::string filename, | |||
return entry; | |||
} | |||
} |
@@ -3,6 +3,8 @@ | |||
#include <vector> | |||
#include <map> | |||
namespace zyncarla { | |||
struct BankEntry | |||
{ | |||
BankEntry(void); | |||
@@ -53,3 +55,5 @@ class BankDb | |||
bvec fields; | |||
svec banks; | |||
}; | |||
} |
@@ -10,6 +10,9 @@ | |||
of the License, or (at your option) any later version. | |||
*/ | |||
#include "CallbackRepeater.h" | |||
namespace zyncarla { | |||
CallbackRepeater::CallbackRepeater(int interval, cb_t cb_) | |||
:last(time(0)), dt(interval), cb(cb_) | |||
{} | |||
@@ -22,3 +25,5 @@ void CallbackRepeater::tick(void) | |||
last = now; | |||
} | |||
} | |||
} |
@@ -13,6 +13,8 @@ | |||
#include <functional> | |||
#include <ctime> | |||
namespace zyncarla { | |||
struct CallbackRepeater | |||
{ | |||
typedef std::function<void(void)> cb_t ; | |||
@@ -27,3 +29,5 @@ struct CallbackRepeater | |||
std::time_t dt; | |||
cb_t cb; | |||
}; | |||
} |
@@ -1,7 +1,7 @@ | |||
/* | |||
ZynAddSubFX - a software synthesizer | |||
CarlaConfig.cpp - CarlaConfiguration file functions | |||
Config.cpp - Configuration file functions | |||
Copyright (C) 2003-2005 Nasca Octavian Paul | |||
Author: Nasca Octavian Paul | |||
@@ -22,6 +22,8 @@ | |||
#include "../globals.h" | |||
#include "XMLwrapper.h" | |||
namespace zyncarla { | |||
#define rStdString(name, len, ...) \ | |||
{STRINGIFY(name) "::s", rMap(length, len) rProp(parameter) DOC(__VA_ARGS__), NULL, rStringCb(name,len)} | |||
#define rStdStringCb(name, length) rBOIL_BEGIN \ | |||
@@ -37,7 +39,7 @@ | |||
#if 1 | |||
#define rObject CarlaConfig | |||
#define rObject Config | |||
static const rtosc::Ports ports = { | |||
//rString(cfg.LinuxOSSWaveOutDev), | |||
//rString(cfg.LinuxOSSSeqInDev), | |||
@@ -51,7 +53,7 @@ static const rtosc::Ports ports = { | |||
{"cfg.presetsDirList", rDoc("list of preset search directories"), 0, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
CarlaConfig &c = *(CarlaConfig*)d.obj; | |||
Config &c = *(Config*)d.obj; | |||
if(rtosc_narguments(msg) != 0) { | |||
std::string args = rtosc_argument_string(msg); | |||
@@ -84,7 +86,7 @@ static const rtosc::Ports ports = { | |||
{"cfg.bankRootDirList", rDoc("list of bank search directories"), 0, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
CarlaConfig &c = *(CarlaConfig*)d.obj; | |||
Config &c = *(Config*)d.obj; | |||
if(rtosc_narguments(msg) != 0) { | |||
std::string args = rtosc_argument_string(msg); | |||
@@ -120,14 +122,14 @@ static const rtosc::Ports ports = { | |||
//rArrayS(cfg.presetsDirList,MAX_BANK_ROOT_DIRS), | |||
rToggle(cfg.CheckPADsynth, "Old Check For PADsynth functionality within a patch"), | |||
rToggle(cfg.IgnoreProgramChange, "Ignore MIDI Program Change Events"), | |||
rParamI(cfg.UserInterfaceMode, "Beginner/Advanced Mode Select"), | |||
rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"), | |||
rParamI(cfg.UserInterfaceMode, "Beginner/Advanced Mode Select"), | |||
rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"), | |||
//rParamS(cfg.LinuxALSAaudioDev), | |||
//rParamS(cfg.nameTag) | |||
{"cfg.OscilPower::i", rProp(parameter) rDoc("Size Of Oscillator Wavetable"), 0, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
CarlaConfig &c = *(CarlaConfig*)d.obj; | |||
Config &c = *(Config*)d.obj; | |||
if(rtosc_narguments(msg) == 0) { | |||
d.reply(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0))); | |||
return; | |||
@@ -136,22 +138,29 @@ static const rtosc::Ports ports = { | |||
c.cfg.OscilSize = val; | |||
d.broadcast(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0))); | |||
}}, | |||
{"clear-favorites:", rDoc("Clear favorite directories"), 0, | |||
[](const char *msg, rtosc::RtData &d) { | |||
Config &c = *(Config*)d.obj; | |||
for(int i=0; i<MAX_BANK_ROOT_DIRS; ++i) | |||
c.cfg.favoriteList[i] = ""; | |||
}}, | |||
{"add-favorite:s", rDoc("Add favorite directory"), 0, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
CarlaConfig &c = *(CarlaConfig*)d.obj; | |||
Config &c = *(Config*)d.obj; | |||
const char *path = rtosc_argument(msg, 0).s; | |||
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; | |||
if(c.cfg.favoriteList[i].empty() || c.cfg.favoriteList[i] == path) { | |||
c.cfg.favoriteList[i] = path; | |||
return; | |||
} | |||
} | |||
}}, | |||
{"favorites:", rProp(parameter), 0, | |||
{"favorites:", /*rProp(parameter)*/ 0, 0, | |||
[](const char *msg, rtosc::RtData &d) | |||
{ | |||
CarlaConfig &c = *(CarlaConfig*)d.obj; | |||
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); | |||
@@ -168,13 +177,15 @@ static const rtosc::Ports ports = { | |||
delete [] args; | |||
}}, | |||
}; | |||
const rtosc::Ports &CarlaConfig::ports = ::ports; | |||
const rtosc::Ports &Config::ports = zyncarla::ports; | |||
#endif | |||
CarlaConfig::CarlaConfig() | |||
{} | |||
Config::Config() | |||
{ | |||
init(); | |||
} | |||
void CarlaConfig::init() | |||
void Config::init() | |||
{ | |||
maxstringsize = MAX_STRING_SIZE; //for ui | |||
//defaults | |||
@@ -223,14 +234,18 @@ void CarlaConfig::init() | |||
//banks | |||
cfg.bankRootDirList[0] = "~/banks"; | |||
cfg.bankRootDirList[1] = "./"; | |||
cfg.bankRootDirList[2] = "/usr/share/zynaddsubfx/banks"; | |||
cfg.bankRootDirList[3] = "/usr/local/share/zynaddsubfx/banks"; | |||
#ifdef __APPLE__ | |||
cfg.bankRootDirList[4] = "../Resources/banks"; | |||
cfg.bankRootDirList[2] = "../Resources/banks"; | |||
#else | |||
cfg.bankRootDirList[2] = "../banks"; | |||
#endif | |||
cfg.bankRootDirList[3] = "banks"; | |||
#ifdef ZYN_DATADIR | |||
cfg.bankRootDirList[4] = ZYN_DATADIR "/banks"; | |||
#else | |||
cfg.bankRootDirList[4] = "../banks"; | |||
cfg.bankRootDirList[4] = "/usr/share/zynaddsubfx/banks"; | |||
cfg.bankRootDirList[5] = "/usr/local/share/zynaddsubfx/banks"; | |||
#endif | |||
cfg.bankRootDirList[5] = "banks"; | |||
} | |||
if(cfg.presetsDirList[0].empty()) { | |||
@@ -242,14 +257,18 @@ void CarlaConfig::init() | |||
cfg.presetsDirList[1] = "../presets"; | |||
#endif | |||
cfg.presetsDirList[2] = "presets"; | |||
#ifdef ZYN_DATADIR | |||
cfg.presetsDirList[3] = ZYN_DATADIR "/presets"; | |||
#else | |||
cfg.presetsDirList[3] = "/usr/share/zynaddsubfx/presets"; | |||
cfg.presetsDirList[4] = "/usr/local/share/zynaddsubfx/presets"; | |||
#endif | |||
} | |||
cfg.LinuxALSAaudioDev = "default"; | |||
cfg.nameTag = ""; | |||
} | |||
CarlaConfig::~CarlaConfig() | |||
Config::~Config() | |||
{ | |||
delete [] cfg.oss_devs.linux_wave_out; | |||
delete [] cfg.oss_devs.linux_seq_in; | |||
@@ -260,26 +279,26 @@ CarlaConfig::~CarlaConfig() | |||
} | |||
void CarlaConfig::save() const | |||
void Config::save() const | |||
{ | |||
char filename[MAX_STRING_SIZE]; | |||
getConfigFileName(filename, MAX_STRING_SIZE); | |||
saveConfig(filename); | |||
} | |||
void CarlaConfig::clearbankrootdirlist() | |||
void Config::clearbankrootdirlist() | |||
{ | |||
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
cfg.bankRootDirList[i].clear(); | |||
} | |||
void CarlaConfig::clearpresetsdirlist() | |||
void Config::clearpresetsdirlist() | |||
{ | |||
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
cfg.presetsDirList[i].clear(); | |||
} | |||
void CarlaConfig::readConfig(const char *filename) | |||
void Config::readConfig(const char *filename) | |||
{ | |||
XMLwrapper xmlcfg; | |||
if(xmlcfg.loadXMLfile(filename) < 0) | |||
@@ -350,7 +369,7 @@ void CarlaConfig::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)) { | |||
@@ -382,7 +401,7 @@ void CarlaConfig::readConfig(const char *filename) | |||
cfg.OscilSize = (int) powf(2, ceil(logf(cfg.OscilSize - 1.0f) / logf(2.0f))); | |||
} | |||
void CarlaConfig::saveConfig(const char *filename) const | |||
void Config::saveConfig(const char *filename) const | |||
{ | |||
XMLwrapper *xmlcfg = new XMLwrapper(); | |||
@@ -418,7 +437,7 @@ void CarlaConfig::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); | |||
@@ -444,8 +463,10 @@ void CarlaConfig::saveConfig(const char *filename) const | |||
delete (xmlcfg); | |||
} | |||
void CarlaConfig::getConfigFileName(char *name, int namesize) const | |||
void Config::getConfigFileName(char *name, int namesize) const | |||
{ | |||
name[0] = 0; | |||
snprintf(name, namesize, "%s%s", getenv("HOME"), "/.zynaddsubfxXML.cfg"); | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
/* | |||
ZynAddSubFX - a software synthesizer | |||
CarlaConfig.h - CarlaConfiguration file functions | |||
Config.h - Configuration file functions | |||
Copyright (C) 2003-2005 Nasca Octavian Paul | |||
Author: Nasca Octavian Paul | |||
@@ -23,6 +23,8 @@ namespace rtosc | |||
struct Ports; | |||
} | |||
namespace zyncarla { | |||
class oss_devs_t | |||
{ | |||
public: | |||
@@ -30,13 +32,13 @@ class oss_devs_t | |||
}; | |||
/**Configuration file functions*/ | |||
class CarlaConfig | |||
class Config | |||
{ | |||
public: | |||
CarlaConfig(); | |||
CarlaConfig(const CarlaConfig& ) = delete; | |||
~CarlaConfig(); | |||
Config(); | |||
Config(const Config& ) = delete; | |||
~Config(); | |||
struct { | |||
oss_devs_t oss_devs; | |||
int SampleRate, SoundBufferSize, OscilSize, SwapStereo; | |||
@@ -73,4 +75,7 @@ class CarlaConfig | |||
void saveConfig(const char *filename) const; | |||
void getConfigFileName(char *name, int namesize) const; | |||
}; | |||
} | |||
#endif |
@@ -16,6 +16,7 @@ | |||
#include "LASHClient.h" | |||
namespace zyncarla { | |||
LASHClient::LASHClient(int *argc, char ***argv) | |||
{ | |||
@@ -92,3 +93,5 @@ void LASHClient::confirmevent(Event event) | |||
if(event == Restore) | |||
lash_send_event(client, lash_event_new_with_type(LASH_Restore_File)); | |||
} | |||
} |
@@ -17,6 +17,7 @@ | |||
#include <pthread.h> | |||
#include <lash/lash.h> | |||
namespace zyncarla { | |||
/** This class wraps up some functions for initialising and polling | |||
* the LASH daemon.*/ | |||
@@ -50,5 +51,6 @@ class LASHClient | |||
lash_client_t *client; | |||
}; | |||
} | |||
#endif |
@@ -16,6 +16,7 @@ | |||
#include "Part.h" | |||
#include "zyn-version.h" | |||
#include "../Misc/Stereo.h" | |||
#include "../Misc/Util.h" | |||
#include "../Params/LFOParams.h" | |||
@@ -32,15 +33,18 @@ | |||
#include <stdio.h> | |||
#include <sys/stat.h> | |||
#include <sys/types.h> | |||
#include <fstream> | |||
#include <iostream> | |||
#include <algorithm> | |||
#include <cmath> | |||
#include <atomic> | |||
#include <unistd.h> | |||
using namespace std; | |||
using namespace rtosc; | |||
namespace zyncarla { | |||
#define rObject Master | |||
static const Ports sysefxPort = | |||
@@ -49,12 +53,18 @@ static const Ports sysefxPort = | |||
rDoc("gain on part to sysefx routing"), 0, | |||
[](const char *m, RtData&d) | |||
{ | |||
//ok, this is going to be an ugly workaround | |||
//we know that if we are here the message previously MUST have | |||
//matched Psysefxvol#/ | |||
//and the number is one or two digits at most | |||
const char *index_1 = m; | |||
index_1 -=2; | |||
//we know that if we are here the location must | |||
//be ...Psysefxvol#N/part#M | |||
//and the number "N" is one or two digits at most | |||
// go backto the '/' | |||
const char* m_findslash = m + strlen(m), | |||
* loc_findslash = d.loc + strlen(d.loc); | |||
for(;*loc_findslash != '/'; --m_findslash, --loc_findslash) | |||
assert(*loc_findslash == *m_findslash); | |||
assert(m_findslash + 1 == m); | |||
const char *index_1 = loc_findslash-1; | |||
assert(isdigit(*index_1)); | |||
if(isdigit(index_1[-1])) | |||
index_1--; | |||
@@ -78,9 +88,15 @@ static const Ports sysefsendto = | |||
{"to#" STRINGIFY(NUM_SYS_EFX) "::i", | |||
rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d) | |||
{ | |||
//same ugly workaround as before | |||
const char *index_1 = m; | |||
index_1 -=2; | |||
//same workaround as before | |||
//go backto the '/' | |||
const char* m_findslash = m + strlen(m), | |||
* loc_findslash = d.loc + strlen(d.loc); | |||
for(;*loc_findslash != '/'; --m_findslash, --loc_findslash) | |||
assert(*loc_findslash == *m_findslash); | |||
assert(m_findslash + 1 == m); | |||
const char *index_1 = loc_findslash-1; | |||
assert(isdigit(*index_1)); | |||
if(isdigit(index_1[-1])) | |||
index_1--; | |||
@@ -98,6 +114,236 @@ static const Ports sysefsendto = | |||
}} | |||
}; | |||
#define rBegin [](const char *msg, RtData &d) { rtosc::AutomationMgr &a = *(AutomationMgr*)d.obj | |||
#define rEnd } | |||
static int extract_num(const char *&msg) | |||
{ | |||
while(*msg && !isdigit(*msg)) msg++; | |||
int num = atoi(msg); | |||
while(isdigit(*msg)) msg++; | |||
return num; | |||
} | |||
static int get_next_int(const char *msg) | |||
{ | |||
return extract_num(msg); | |||
} | |||
static const Ports mapping_ports = { | |||
{"offset::f", rProp(parameter) rDefault(0) rShort("off") rLinear(-50, 50) rMap(unit, percent), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
if(!strcmp("f",rtosc_argument_string(msg))) { | |||
a.setSlotSubOffset(slot, param, rtosc_argument(msg, 0).f); | |||
a.updateMapping(slot, param); | |||
d.broadcast(d.loc, "f", a.getSlotSubOffset(slot, param)); | |||
} else | |||
d.reply(d.loc, "f", a.getSlotSubOffset(slot, param)); | |||
rEnd}, | |||
{"gain::f", rProp(parameter) rDefault(100) rShort("gain") rLinear(-200, 200) rMap(unit, percent), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
if(!strcmp("f",rtosc_argument_string(msg))) { | |||
a.setSlotSubGain(slot, param, rtosc_argument(msg, 0).f); | |||
a.updateMapping(slot, param); | |||
d.broadcast(d.loc, "f", a.getSlotSubGain(slot, param)); | |||
} else | |||
d.reply(d.loc, "f", a.getSlotSubGain(slot, param)); | |||
rEnd}, | |||
}; | |||
static const Ports auto_param_ports = { | |||
{"used::T:F", rProp(parameter) rProp(read-only) rDoc("If automation is assigned to anything"), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
d.reply(d.loc, a.slots[slot].automations[param].used ? "T" : "F"); | |||
rEnd}, | |||
{"active::T:F", rProp(parameter) rDoc("If automation is being actively used"), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
if(rtosc_narguments(msg)) | |||
a.slots[slot].automations[param].active = rtosc_argument(msg, 0).T; | |||
else | |||
d.reply(d.loc, a.slots[slot].automations[param].active ? "T" : "F"); | |||
rEnd}, | |||
{"path::s", rProp(parameter) rProp(read-only) rDoc("Path of parameter"), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
d.reply(d.loc, "s", a.slots[slot].automations[param].param_path); | |||
rEnd}, | |||
{"clear:", rDoc("Clear automation param"), 0, | |||
rBegin; | |||
int slot = d.idx[1]; | |||
int param = d.idx[0]; | |||
a.clearSlotSub(slot, param); | |||
rEnd}, | |||
{"mapping/", 0, &mapping_ports, | |||
rBegin; | |||
SNIP; | |||
mapping_ports.dispatch(msg, d); | |||
rEnd}, | |||
//{"mapping", rDoc("Parameter mapping control"), 0, | |||
// rBegin; | |||
// int slot = d.idx[1]; | |||
// int param = d.idx[0]; | |||
// if(!strcmp("b", rtosc_argument_string(msg))) { | |||
// int len = rtosc_argument(msg, 0).b.len / sizeof(float); | |||
// float *data = (float*)rtosc_argument(msg, 0).b.data; | |||
// } else { | |||
// d.reply(d.loc, "b", | |||
// a.slots[slot].automations[param].map.npoints*sizeof(float), | |||
// a.slots[slot].automations[param].map.control_points); | |||
// } | |||
// rEnd}, | |||
}; | |||
static const Ports slot_ports = { | |||
//{"learn-binding:s", rDoc("Create binding for automation path with midi-learn"), 0, | |||
// rBegin; | |||
// (void) m; | |||
// //m->automate.createBinding(rtosc_argument(msg, 0).i, | |||
// // rtosc_argument(msg, 1).s, | |||
// // rtosc_argument(msg, 2).T); | |||
// rEnd}, | |||
//{"create-binding:s", rDoc("Create binding for automation path"), 0, | |||
// rBegin; | |||
// m->automate.createBinding(rtosc_argument(msg, 0).i, | |||
// rtosc_argument(msg, 1).s, | |||
// rtosc_argument(msg, 2).T); | |||
// rEnd}, | |||
{"value::f", rProp(no learn) rProp(parameter) rMap(default, 0.5) rLinear(0, 1) rDoc("Access current value in slot 'i' (0..1)"), 0, | |||
rBegin; | |||
int num = d.idx[0]; | |||
if(!strcmp("f",rtosc_argument_string(msg))) { | |||
a.setSlot(num, rtosc_argument(msg, 0).f); | |||
d.broadcast(d.loc, "f", a.getSlot(num)); | |||
} else | |||
d.reply(d.loc, "f", a.getSlot(num)); | |||
rEnd}, | |||
{"name::s", rProp(parameter) rDoc("Access name of automation slot"), 0, | |||
rBegin; | |||
int num = d.idx[0]; | |||
if(!strcmp("s",rtosc_argument_string(msg))) { | |||
a.setName(num, rtosc_argument(msg, 0).s); | |||
d.broadcast(d.loc, "s", a.getName(num)); | |||
} else | |||
d.reply(d.loc, "s", a.getName(num)); | |||
rEnd}, | |||
{"midi-cc::i", rProp(parameter) rMap(default, -1) rDoc("Access assigned midi CC slot") , 0, | |||
rBegin; | |||
int slot = d.idx[0]; | |||
if(rtosc_narguments(msg)) | |||
a.slots[slot].midi_cc = rtosc_argument(msg, 0).i; | |||
else | |||
d.reply(d.loc, "i", a.slots[slot].midi_cc); | |||
rEnd}, | |||
{"active::T:F", rProp(parameter) rMap(default, F) rDoc("If Slot is enabled"), 0, | |||
rBegin; | |||
int slot = d.idx[0]; | |||
if(rtosc_narguments(msg)) | |||
a.slots[slot].active = rtosc_argument(msg, 0).T; | |||
else | |||
d.reply(d.loc, a.slots[slot].active ? "T" : "F"); | |||
rEnd}, | |||
{"learning::i", rProp(parameter) rMap(default, -1) rDoc("If slot is trying to find a midi learn binding"), 0, | |||
rBegin; | |||
int slot = d.idx[0]; | |||
d.reply(d.loc, "i", a.slots[slot].learning); | |||
rEnd}, | |||
{"clear:", rDoc("Clear automation slot"), 0, | |||
rBegin; | |||
int slot = d.idx[0]; | |||
a.clearSlot(slot); | |||
rEnd}, | |||
{"param#4/", rDoc("Info on individual param mappings"), &auto_param_ports, | |||
rBegin; | |||
(void)a; | |||
d.push_index(get_next_int(msg)); | |||
SNIP; | |||
auto_param_ports.dispatch(msg, d); | |||
d.pop_index(); | |||
rEnd}, | |||
}; | |||
static const Ports automate_ports = { | |||
{"active-slot::i", rProp(parameter) rMap(min, -1) rMap(max, 16) rDoc("Active Slot for macro learning"), 0, | |||
rBegin; | |||
if(!strcmp("i",rtosc_argument_string(msg))) { | |||
a.active_slot = rtosc_argument(msg, 0).i; | |||
d.broadcast(d.loc, "i", a.active_slot); | |||
} else | |||
d.reply(d.loc, "i", a.active_slot); | |||
rEnd}, | |||
{"learn-binding-new-slot:s", rDoc("Learn a parameter assigned to a new slot"), 0, | |||
rBegin; | |||
int free_slot = a.free_slot(); | |||
if(free_slot >= 0) { | |||
a.createBinding(free_slot, rtosc_argument(msg, 0).s, true); | |||
a.active_slot = free_slot; | |||
} | |||
rEnd}, | |||
{"learn-binding-same-slot:s", rDoc("Learn a parameter appending to the active-slot"), 0, | |||
rBegin; | |||
if(a.active_slot >= 0) | |||
a.createBinding(a.active_slot, rtosc_argument(msg, 0).s, true); | |||
rEnd}, | |||
// TODO: remove rNoWalk | |||
{"slot#16/", rNoWalk rDoc("Parameters of individual automation slots"), &slot_ports, | |||
rBegin; | |||
(void)a; | |||
d.push_index(get_next_int(msg)); | |||
SNIP; | |||
slot_ports.dispatch(msg, d); | |||
d.pop_index(); | |||
rEnd}, | |||
{"clear", rDoc("Clear all automation slots"), 0, | |||
rBegin; | |||
for(int i=0; i<a.nslots; ++i) | |||
a.clearSlot(i); | |||
rEnd}, | |||
{"load-blob:b", rProp(internal) rDoc("Load blob from middleware"), 0, | |||
rBegin; | |||
auto &b = **(rtosc::AutomationMgr **)rtosc_argument(msg, 0).b.data; | |||
//XXX this code should likely be in rtosc | |||
for(int i=0; i<a.nslots; ++i) { | |||
auto &slota = a.slots[i]; | |||
auto &slotb = b.slots[i]; | |||
std::swap(slota.learning, slotb.learning); | |||
std::swap(slota.midi_cc, slotb.midi_cc); | |||
std::swap(slota.used, slotb.used); | |||
std::swap(slota.active, slotb.active); | |||
for(int j=0; j<a.per_slot; ++j) { | |||
auto &aa = slota.automations[j]; | |||
auto &ab = slotb.automations[j]; | |||
std::swap(aa.used, ab.used); | |||
std::swap(aa.active, ab.active); | |||
std::swap(aa.param_path, ab.param_path); | |||
std::swap(aa.param_min, ab.param_min); | |||
std::swap(aa.param_max, ab.param_max); | |||
std::swap(aa.param_step, ab.param_step); | |||
std::swap(aa.param_type, ab.param_type); | |||
std::swap(aa.map.offset, ab.map.offset); | |||
std::swap(aa.map.gain, ab.map.gain); | |||
std::swap(aa.map.upoints, ab.map.upoints); | |||
for(int k=0; k<aa.map.npoints; ++k) | |||
std::swap(aa.map.control_points[k], ab.map.control_points[k]); | |||
} | |||
} | |||
rEnd}, | |||
}; | |||
#undef rBegin | |||
#undef rEnd | |||
#define rBegin [](const char *msg, RtData &d) { Master *m = (Master*)d.obj | |||
#define rEnd } | |||
@@ -108,20 +354,22 @@ static const Ports watchPorts = { | |||
rEnd}, | |||
}; | |||
extern const Ports bankPorts; | |||
static const Ports master_ports = { | |||
rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."), | |||
rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS | |||
rRecursp(sysefx, 4, "System Effect"),//NUM_SYS_EFX | |||
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX | |||
rRecur(microtonal, "Micrtonal Mapping Functionality"), | |||
rRecur(microtonal, "Microtonal Mapping Functionality"), | |||
rRecur(ctl, "Controller"), | |||
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), | |||
"Part to insert part onto"), | |||
{"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { | |||
rArrayOption(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) rDefault(Off), | |||
"Part to insert part onto"), | |||
{"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) | |||
rDefault(64) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { | |||
if(rtosc_narguments(m)==0) { | |||
d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift); | |||
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | |||
@@ -160,6 +408,8 @@ static const Ports master_ports = { | |||
d.reply("/free", "sb", "Part", sizeof(void*), &m->part[i]); | |||
m->part[i] = p; | |||
p->initialize_rt(); | |||
for(int i=0; i<128; ++i) | |||
m->activeNotes[i] = 0; | |||
}}, | |||
{"active_keys:", rProp("Obtain a list of active notes"), 0, | |||
rBegin; | |||
@@ -168,14 +418,16 @@ static const Ports master_ports = { | |||
keys[i] = m->activeNotes[i] ? 'T' : 'F'; | |||
d.broadcast(d.loc, keys); | |||
rEnd}, | |||
{"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0, | |||
{"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) | |||
rDefault(80) rDoc("Master Volume"), 0, | |||
[](const char *m, rtosc::RtData &d) { | |||
if(rtosc_narguments(m)==0) { | |||
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | |||
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | |||
((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127)); | |||
d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}}, | |||
{"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0, | |||
{"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) | |||
rDefault(80) rDoc("Master Volume"), 0, | |||
[](const char *m, rtosc::RtData &d) { | |||
if(rtosc_narguments(m)==0) { | |||
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | |||
@@ -229,13 +481,12 @@ static const Ports master_ports = { | |||
[](const char *,RtData &d) { | |||
Master *M = (Master*)d.obj; | |||
M->frozenState = false;}}, | |||
{"midi-learn/", 0, &rtosc::MidiMapperRT::ports, | |||
{"automate/", rDoc("MIDI Learn/Plugin Automation support"), &automate_ports, | |||
[](const char *msg, RtData &d) { | |||
Master *M = (Master*)d.obj; | |||
SNIP; | |||
printf("residue message = <%s>\n", msg); | |||
d.obj = &M->midi; | |||
rtosc::MidiMapperRT::ports.dispatch(msg,d);}}, | |||
d.obj = (void*)&((Master*)d.obj)->automate; | |||
automate_ports.dispatch(msg, d); | |||
}}, | |||
{"close-ui:", rDoc("Request to close any connection named \"GUI\""), 0, | |||
[](const char *, RtData &d) { | |||
d.reply("/close-ui", "");}}, | |||
@@ -261,8 +512,8 @@ static const Ports master_ports = { | |||
[](const char *, rtosc::RtData &d) {d.reply("/undo_pause", "");}}, | |||
{"undo_resume:",rProp(internal) rDoc("resume undo event recording"),0, | |||
[](const char *, rtosc::RtData &d) {d.reply("/undo_resume", "");}}, | |||
{"config/", rDoc("Top Level Application CarlaConfiguration Parameters"), &CarlaConfig::ports, | |||
[](const char *, rtosc::RtData &d){d.forward();}}, | |||
{"config/", rNoWalk rDoc("Top Level Application Configuration Parameters"), | |||
&Config::ports, [](const char *, rtosc::RtData &d){d.forward();}}, | |||
{"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN | |||
SNIP | |||
preset_ports.dispatch(msg, data); | |||
@@ -286,6 +537,14 @@ static const Ports master_ports = { | |||
rBOIL_END}, | |||
{"bank/", rDoc("Controls for instrument banks"), &bankPorts, | |||
[](const char*,RtData&) {}}, | |||
{"learn:s", rProp(depricated) rDoc("MIDI Learn"), 0, | |||
rBegin; | |||
int free_slot = m->automate.free_slot(); | |||
if(free_slot >= 0) { | |||
m->automate.createBinding(free_slot, rtosc_argument(msg, 0).s, true); | |||
m->automate.active_slot = free_slot; | |||
} | |||
rEnd}, | |||
}; | |||
#undef rBegin | |||
@@ -359,18 +618,97 @@ vuData::vuData(void) | |||
rmspeakl(0.0f), rmspeakr(0.0f), clipped(0) | |||
{} | |||
Master::Master(const SYNTH_T &synth_, CarlaConfig* config) | |||
void Master::saveAutomation(XMLwrapper &xml, const rtosc::AutomationMgr &midi) | |||
{ | |||
xml.beginbranch("automation"); | |||
{ | |||
XmlNode metadata("mgr-info"); | |||
metadata["nslots"] = to_s(midi.nslots); | |||
metadata["nautomations"] = to_s(midi.per_slot); | |||
metadata["ncontrol"] = to_s(midi.slots[0].automations[0].map.npoints); | |||
xml.add(metadata); | |||
for(int i=0; i<midi.nslots; ++i) { | |||
const auto &slot = midi.slots[i]; | |||
if(!slot.used) | |||
continue; | |||
xml.beginbranch("slot", i); | |||
XmlNode params("params"); | |||
params["midi-cc"] = to_s(slot.midi_cc); | |||
xml.add(params); | |||
for(int j=0; j<midi.per_slot; ++j) { | |||
const auto &au = slot.automations[j]; | |||
if(!au.used) | |||
continue; | |||
xml.beginbranch("automation", j); | |||
XmlNode automation("params"); | |||
automation["path"] = au.param_path; | |||
XmlNode mapping("mapping"); | |||
mapping["gain"] = to_s(au.map.gain); | |||
mapping["offset"] = to_s(au.map.offset); | |||
xml.add(automation); | |||
xml.add(mapping); | |||
xml.endbranch(); | |||
} | |||
xml.endbranch(); | |||
} | |||
} | |||
xml.endbranch(); | |||
} | |||
void Master::loadAutomation(XMLwrapper &xml, rtosc::AutomationMgr &midi) | |||
{ | |||
if(xml.enterbranch("automation")) { | |||
for(int i=0; i<midi.nslots; ++i) { | |||
auto &slot = midi.slots[i]; | |||
if(xml.enterbranch("slot", i)) { | |||
for(int j=0; j<midi.per_slot; ++j) { | |||
auto &au = slot.automations[j]; | |||
if(xml.enterbranch("automation", j)) { | |||
float gain = 1.0; | |||
float offset = 0.0; | |||
std::string path = ""; | |||
for(auto node:xml.getBranch()) { | |||
if(node.name == "params") | |||
path = node["path"]; | |||
else if(node.name == "mapping") { | |||
gain = atof(node["gain"].c_str()); | |||
offset = atof(node["offset"].c_str()); | |||
} | |||
} | |||
printf("createBinding(%d, %s, false)\n", i, path.c_str()); | |||
midi.createBinding(i, path.c_str(), false); | |||
midi.setSlotSubGain(i, j, gain); | |||
midi.setSlotSubOffset(i, j, offset); | |||
xml.exitbranch(); | |||
} | |||
} | |||
for(auto node:xml.getBranch()) | |||
if(node.name == "params") | |||
slot.midi_cc = atoi(node["midi-cc"].c_str()); | |||
xml.exitbranch(); | |||
} | |||
} | |||
xml.exitbranch(); | |||
} | |||
} | |||
Master::Master(const SYNTH_T &synth_, Config* config) | |||
:HDDRecorder(synth_), time(synth_), ctl(synth_, &time), | |||
microtonal(config->cfg.GzipCompression), bank(config), | |||
automate(16,4,8), | |||
frozenState(false), pendingMemory(false), | |||
synth(synth_), gzip_compression(config->cfg.GzipCompression) | |||
{ | |||
bToU = NULL; | |||
uToB = NULL; | |||
//Setup MIDI | |||
midi.frontend = [this](const char *msg) {bToU->raw_write(msg);}; | |||
midi.backend = [this](const char *msg) {applyOscEvent(msg);}; | |||
//Setup MIDI Learn | |||
automate.set_ports(master_ports); | |||
automate.set_instance(this); | |||
//midi.frontend = [this](const char *msg) {bToU->raw_write(msg);}; | |||
automate.backend = [this](const char *msg) {applyOscEvent(msg);}; | |||
memory = new AllocatorClass(); | |||
swaplr = 0; | |||
@@ -441,6 +779,7 @@ void Master::defaults() | |||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
part[npart]->defaults(); | |||
part[npart]->partno = npart % NUM_MIDI_CHANNELS; | |||
part[npart]->Prcvchn = npart % NUM_MIDI_CHANNELS; | |||
} | |||
@@ -519,8 +858,7 @@ void Master::setController(char chan, int type, int par) | |||
{ | |||
if(frozenState) | |||
return; | |||
//TODO add chan back | |||
midi.handleCC(type,par); | |||
automate.handleMidi(chan, type, par); | |||
if((type == C_dataentryhi) || (type == C_dataentrylo) | |||
|| (type == C_nrpnhi) || (type == C_nrpnlo)) { //Process RPN and NRPN by the Master (ignore the chan) | |||
ctl.setparameternumber(type, par); | |||
@@ -724,13 +1062,19 @@ bool Master::runOSC(float *outl, float *outr, bool offline) | |||
} | |||
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:%s'\n", | |||
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(automate.damaged) { | |||
d.broadcast("/damage", "s", "/automate/"); | |||
automate.damaged = 0; | |||
} | |||
if(events>1 && false) | |||
fprintf(stderr, "backend: %d events per cycle\n",events); | |||
@@ -1074,6 +1418,8 @@ void Master::add2XML(XMLwrapper& xml) | |||
microtonal.add2XML(xml); | |||
xml.endbranch(); | |||
saveAutomation(xml, automate); | |||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
xml.beginbranch("PART", npart); | |||
part[npart]->add2XML(xml); | |||
@@ -1198,6 +1544,8 @@ void Master::getfromXML(XMLwrapper& xml) | |||
xml.exitbranch(); | |||
} | |||
loadAutomation(xml, automate); | |||
sysefx[0]->changeeffect(0); | |||
if(xml.enterbranch("SYSTEM_EFFECTS")) { | |||
for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) { | |||
@@ -1248,3 +1596,114 @@ void Master::getfromXML(XMLwrapper& xml) | |||
xml.exitbranch(); | |||
} | |||
} | |||
static rtosc_version version_in_rtosc_fmt() | |||
{ | |||
return rtosc_version | |||
{ | |||
(unsigned char) version.get_major(), | |||
(unsigned char) version.get_minor(), | |||
(unsigned char) version.get_revision() | |||
}; | |||
} | |||
char* Master::getXMLData() | |||
{ | |||
XMLwrapper xml; | |||
xml.beginbranch("MASTER"); | |||
add2XML(xml); | |||
xml.endbranch(); | |||
return xml.getXMLdata(); | |||
} | |||
int Master::saveOSC(const char *filename) | |||
{ | |||
std::string savefile = rtosc::save_to_file(ports, this, | |||
"ZynAddSubFX", | |||
version_in_rtosc_fmt()); | |||
zyncarla::Config config; | |||
zyncarla::SYNTH_T* synth = new zyncarla::SYNTH_T; | |||
synth->buffersize = 256; | |||
synth->samplerate = 48000; | |||
synth->alias(); | |||
zyncarla::Master master2(*synth, &config); | |||
int rval = master2.loadOSCFromStr(savefile.c_str()); | |||
if(rval < 0) | |||
{ | |||
std::cerr << "invalid savefile!" << std::endl; | |||
std::cerr << "complete savefile:" << std::endl; | |||
std::cerr << savefile << std::endl; | |||
std::cerr << "first entry that could not be parsed:" << std::endl; | |||
for(int i = -rval + 1; savefile[i]; ++i) | |||
if(savefile[i] == '\n') | |||
{ | |||
savefile.resize(i); | |||
break; | |||
} | |||
std::cerr << (savefile.c_str() - rval) << std::endl; | |||
rval = -1; | |||
} | |||
else | |||
{ | |||
char* xml = getXMLData(), | |||
* xml2 = master2.getXMLData(); | |||
rval = strcmp(xml, xml2) ? -1 : 0; | |||
if(rval == 0) | |||
{ | |||
if(filename) | |||
{ | |||
std::ofstream ofs(filename); | |||
ofs << savefile; | |||
} | |||
else if(!filename) | |||
std::cout << savefile << std::endl; | |||
} | |||
else | |||
{ | |||
std::cout << savefile << std::endl; | |||
std::cerr << "Can not write OSC savefile!! (see tmp1.txt and tmp2.txt)" | |||
<< std::endl; | |||
std::ofstream tmp1("tmp1.txt"), tmp2("tmp2.txt"); | |||
tmp1 << xml; | |||
tmp2 << xml2; | |||
} | |||
free(xml); | |||
free(xml2); | |||
} | |||
return rval; | |||
} | |||
int Master::loadOSCFromStr(const char *filename) | |||
{ | |||
return rtosc::load_from_file(filename, | |||
ports, this, | |||
"ZynAddSubFX", version_in_rtosc_fmt()); | |||
} | |||
string loadfile(string fname) | |||
{ | |||
std::ifstream t(fname.c_str()); | |||
std::string str((std::istreambuf_iterator<char>(t)), | |||
std::istreambuf_iterator<char>()); | |||
return str; | |||
} | |||
int Master::loadOSC(const char *filename) | |||
{ | |||
int rval = loadOSCFromStr(loadfile(filename).c_str()); | |||
return rval < 0 ? rval : 0; | |||
} | |||
} |
@@ -16,7 +16,7 @@ | |||
#define MASTER_H | |||
#include "../globals.h" | |||
#include "Microtonal.h" | |||
#include <rtosc/miditable.h> | |||
#include <rtosc/automations.h> | |||
#include <rtosc/ports.h> | |||
#include "Time.h" | |||
@@ -26,6 +26,8 @@ | |||
#include "../Params/Controller.h" | |||
#include "../Synth/WatchPoint.h" | |||
namespace zyncarla { | |||
class Allocator; | |||
struct vuData { | |||
@@ -42,7 +44,7 @@ class Master | |||
{ | |||
public: | |||
/** Constructor TODO make private*/ | |||
Master(const SYNTH_T &synth, class CarlaConfig *config); | |||
Master(const SYNTH_T &synth, class Config *config); | |||
/** Destructor*/ | |||
~Master(); | |||
@@ -57,12 +59,23 @@ class Master | |||
/**This adds the parameters to the XML data*/ | |||
void add2XML(XMLwrapper& xml); | |||
static void saveAutomation(XMLwrapper &xml, const rtosc::AutomationMgr &midi); | |||
static void loadAutomation(XMLwrapper &xml, rtosc::AutomationMgr &midi); | |||
void defaults(); | |||
/**loads all settings from a XML file | |||
* @return 0 for ok or -1 if there is an error*/ | |||
int loadXML(const char *filename); | |||
/**Save all settings to an OSC file (as specified by RT OSC) | |||
* @param filename File to save to or NULL (useful for testing) | |||
* @return 0 for ok or <0 if there is an error*/ | |||
int saveOSC(const char *filename); | |||
/**loads all settings from an OSC file (as specified by RT OSC) | |||
* @return 0 for ok or <0 if there is an error*/ | |||
int loadOSC(const char *filename); | |||
/**Regenerate PADsynth and other non-RT parameters | |||
* It is NOT SAFE to call this from a RT context*/ | |||
void applyparameters(void) NONREALTIME; | |||
@@ -169,7 +182,7 @@ class Master | |||
WatchManager watcher; | |||
//Midi Learn | |||
rtosc::MidiMapperRT midi; | |||
rtosc::AutomationMgr automate; | |||
bool frozenState;//read-only parameters for threadsafe actions | |||
Allocator *memory; | |||
@@ -181,8 +194,8 @@ class Master | |||
//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; | |||
uint32_t last_beat = 0; | |||
uint32_t last_ack = 0; | |||
private: | |||
float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; | |||
float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; | |||
@@ -197,6 +210,13 @@ class Master | |||
//Callback When Master changes | |||
void(*mastercb)(void*,Master*); | |||
void* mastercb_ptr; | |||
//Return XML data as string. Must be freed. | |||
char* getXMLData(); | |||
//Used by loadOSC and saveOSC | |||
int loadOSCFromStr(const char *filename); | |||
}; | |||
} | |||
#endif |
@@ -25,11 +25,13 @@ | |||
#include "Util.h" | |||
#include "Microtonal.h" | |||
using namespace rtosc; | |||
#define MAX_LINE_SIZE 80 | |||
namespace zyncarla { | |||
#define rObject Microtonal | |||
using namespace rtosc; | |||
/** | |||
* TODO | |||
@@ -40,25 +42,37 @@ using namespace rtosc; | |||
* A good lookup table should be a good finalization of this | |||
*/ | |||
const rtosc::Ports Microtonal::ports = { | |||
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"), | |||
rToggle(Pinvertupdown, rShort("inv."), rDefault(false), | |||
"key mapping inverse"), | |||
rParamZyn(Pinvertupdowncenter, rShort("center"), rDefault(60), | |||
"center of the inversion"), | |||
rToggle(Penabled, rShort("enable"), rDefault(false), | |||
"Enable for microtonal mode"), | |||
rParamZyn(PAnote, rShort("1/1 midi note"), rDefault(69), | |||
"The note for 'A'"), | |||
rParamF(PAfreq, rShort("ref freq"), rDefault(440.0f), | |||
"Frequency of the 'A' note"), | |||
rParamZyn(Pscaleshift, rShort("shift"), rDefault(64), | |||
"UNDOCUMENTED"), | |||
rParamZyn(Pfirstkey, rShort("first key"), rDefault(0), | |||
"First key to retune"), | |||
rParamZyn(Plastkey, rShort("last key"), rDefault(127), | |||
"Last key to retune"), | |||
rParamZyn(Pmiddlenote, rShort("middle"), rDefault(60), | |||
"Scale degree 0 note"), | |||
//TODO check to see if this should be exposed | |||
rParamZyn(Pmapsize, "Size of key map"), | |||
rToggle(Pmappingenabled, "Mapping Enable"), | |||
rParamZyn(Pmapsize, rDefault(12), "Size of key map"), | |||
rToggle(Pmappingenabled, rDefault(false), "Mapping Enable"), | |||
rParams(Pmapping, 128, "Mapping of keys"), | |||
rParamZyn(Pglobalfinedetune, rShort("fine"), "Fine detune for all notes"), | |||
rParams(Pmapping, 128, rDefaultMissing, "Mapping of keys"), | |||
rParamZyn(Pglobalfinedetune, rShort("fine"), rDefault(64), | |||
"Fine detune for all notes"), | |||
rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), "Microtonal Name"), | |||
rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), "Microtonal comments"), | |||
rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), | |||
rDefault("12tET"), "Microtonal Name"), | |||
rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), | |||
rDefault("Equal Temperament 12 notes per octave"), "Microtonal comments"), | |||
{"octavesize:", rDoc("Get octave size"), 0, [](const char*, RtData &d) | |||
{ | |||
@@ -570,6 +584,9 @@ int Microtonal::loadscl(SclInfo &scl, const char *filename) | |||
char tmp[500]; | |||
OctaveTuning tmpoctave[MAX_OCTAVE_SIZE]; | |||
if(!file) | |||
return 2; | |||
fseek(file, 0, SEEK_SET); | |||
//loads the short description | |||
@@ -621,6 +638,9 @@ int Microtonal::loadkbm(KbmInfo &kbm, const char *filename) | |||
float tmpPAfreq = 440.0f; | |||
char tmp[500]; | |||
if(!file) | |||
return 2; | |||
fseek(file, 0, SEEK_SET); | |||
//loads the mapsize | |||
if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) | |||
@@ -843,7 +863,7 @@ void Microtonal::apply(void) | |||
{ | |||
char buf[100*MAX_OCTAVE_SIZE] = {0}; | |||
char tmpbuf[100] = {0}; | |||
for (int i=0;i<getoctavesize();i++){ | |||
for (int i=0;i<octavesize;i++){ | |||
if (i!=0) | |||
strncat(buf, "\n", sizeof(buf)-1); | |||
tuningtoline(i,tmpbuf,100); | |||
@@ -852,3 +872,5 @@ void Microtonal::apply(void) | |||
int err = texttotunings(buf); | |||
} | |||
} | |||
} |
@@ -20,6 +20,9 @@ | |||
#define MAX_OCTAVE_SIZE 128 | |||
#define MICROTONAL_MAX_NAME_LEN 120 | |||
namespace zyncarla { | |||
class XMLwrapper; | |||
struct KbmInfo | |||
@@ -154,4 +157,6 @@ class Microtonal | |||
const int& gzip_compression; | |||
}; | |||
} | |||
#endif |
@@ -56,6 +56,8 @@ | |||
#include <err.h> | |||
#endif | |||
namespace zyncarla { | |||
using std::string; | |||
int Pexitprogram = 0; | |||
@@ -221,55 +223,6 @@ void preparePadSynth(string path, PADnoteParameters *p, rtosc::RtData &d) | |||
} | |||
} | |||
/****************************************************************************** | |||
* MIDI Serialization * | |||
* * | |||
******************************************************************************/ | |||
void saveMidiLearn(XMLwrapper &xml, const rtosc::MidiMappernRT &midi) | |||
{ | |||
xml.beginbranch("midi-learn"); | |||
for(auto value:midi.inv_map) { | |||
XmlNode binding("midi-binding"); | |||
auto biject = std::get<3>(value.second); | |||
binding["osc-path"] = value.first; | |||
binding["coarse-CC"] = to_s(std::get<1>(value.second)); | |||
binding["fine-CC"] = to_s(std::get<2>(value.second)); | |||
binding["type"] = "i"; | |||
binding["minimum"] = to_s(biject.min); | |||
binding["maximum"] = to_s(biject.max); | |||
xml.add(binding); | |||
} | |||
xml.endbranch(); | |||
} | |||
void loadMidiLearn(XMLwrapper &xml, rtosc::MidiMappernRT &midi) | |||
{ | |||
using rtosc::Port; | |||
if(xml.enterbranch("midi-learn")) { | |||
auto nodes = xml.getBranch(); | |||
//TODO clear mapper | |||
for(auto node:nodes) { | |||
if(node.name != "midi-binding" || | |||
!node.has("osc-path") || | |||
!node.has("coarse-CC")) | |||
continue; | |||
const string path = node["osc-path"]; | |||
const int CC = atoi(node["coarse-CC"].c_str()); | |||
const Port *p = Master::ports.apropos(path.c_str()); | |||
if(p) { | |||
printf("loading midi port...\n"); | |||
midi.addNewMapper(CC, *p, path); | |||
} else { | |||
printf("unknown midi bindable <%s>\n", path.c_str()); | |||
} | |||
} | |||
xml.exitbranch(); | |||
} else | |||
printf("cannot find 'midi-learn' branch...\n"); | |||
} | |||
/****************************************************************************** | |||
* Non-RealTime Object Store * | |||
* * | |||
@@ -451,17 +404,17 @@ namespace Nio | |||
/* Implementation */ | |||
class CarlaMiddleWareImpl | |||
class MiddleWareImpl | |||
{ | |||
public: | |||
MiddleWare *parent; | |||
private: | |||
public: | |||
CarlaConfig* const config; | |||
CarlaMiddleWareImpl(MiddleWare *mw, SYNTH_T synth, CarlaConfig* config, | |||
Config* const config; | |||
MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, Config* config, | |||
int preferred_port); | |||
~CarlaMiddleWareImpl(void); | |||
~MiddleWareImpl(void); | |||
//Check offline vs online mode in plugins | |||
void heartBeat(Master *m); | |||
@@ -745,7 +698,7 @@ public: | |||
rtosc::UndoHistory undo; | |||
//MIDI Learn | |||
rtosc::MidiMappernRT midi_mapper; | |||
//rtosc::MidiMappernRT midi_mapper; | |||
//Link To the Realtime | |||
rtosc::ThreadLink *bToU; | |||
@@ -774,7 +727,7 @@ public: | |||
class MwDataObj:public rtosc::RtData | |||
{ | |||
public: | |||
MwDataObj(CarlaMiddleWareImpl *mwi_) | |||
MwDataObj(MiddleWareImpl *mwi_) | |||
{ | |||
loc_size = 1024; | |||
loc = new char[loc_size]; | |||
@@ -797,7 +750,7 @@ class MwDataObj:public rtosc::RtData | |||
//Chain calls repeat the call into handle() | |||
//Forward calls send the message directly to the realtime | |||
virtual void reply(const char *path, const char *args, ...) | |||
virtual void reply(const char *path, const char *args, ...) override | |||
{ | |||
//printf("reply building '%s'\n", path); | |||
va_list va; | |||
@@ -823,7 +776,7 @@ class MwDataObj:public rtosc::RtData | |||
reply(buffer); | |||
} | |||
} | |||
virtual void reply(const char *msg){ | |||
virtual void reply(const char *msg) override{ | |||
mwi->sendToCurrentRemote(msg); | |||
}; | |||
//virtual void broadcast(const char *path, const char *args, ...){(void)path;(void)args;}; | |||
@@ -854,7 +807,7 @@ class MwDataObj:public rtosc::RtData | |||
bool forwarded; | |||
private: | |||
char *buffer; | |||
CarlaMiddleWareImpl *mwi; | |||
MiddleWareImpl *mwi; | |||
}; | |||
static std::vector<std::string> getFiles(const char *folder, bool finddir) | |||
@@ -885,11 +838,12 @@ static std::vector<std::string> getFiles(const char *folder, bool finddir) | |||
} | |||
#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("error = %x\n", INVALID_FILE_ATTRIBUTES); | |||
//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) | |||
if(finddir == is_dir && strcmp(".", fn->d_name)) | |||
files.push_back(fn->d_name); | |||
} | |||
@@ -935,13 +889,28 @@ extern const rtosc::Ports bankPorts; | |||
const rtosc::Ports bankPorts = { | |||
{"rescan:", 0, 0, | |||
rBegin; | |||
impl.bankpos = 0; | |||
impl.rescanforbanks(); | |||
//Send updated banks | |||
int i = 0; | |||
for(auto &elm : impl.banks) | |||
d.reply("/bank/bank_select", "iss", i++, elm.name.c_str(), elm.dir.c_str()); | |||
d.reply("/bank/bank_select", "i", impl.bankpos); | |||
if (i > 0) { | |||
impl.loadbank(impl.banks[0].dir); | |||
//Reload bank slots | |||
for(int i=0; i<BANK_SIZE; ++i) { | |||
d.reply("/bankview", "iss", | |||
i, impl.ins[i].name.c_str(), | |||
impl.ins[i].filename.c_str()); | |||
} | |||
} else { | |||
//Clear all bank slots | |||
for(int i=0; i<BANK_SIZE; ++i) { | |||
d.reply("/bankview", "iss", i, "", ""); | |||
} | |||
} | |||
rEnd}, | |||
{"bank_list:", 0, 0, | |||
rBegin; | |||
@@ -1089,8 +1058,8 @@ const rtosc::Ports bankPorts = { | |||
rBegin; | |||
auto res = impl.search(rtosc_argument(msg, 0).s); | |||
#define MAX_SEARCH 300 | |||
char res_type[MAX_SEARCH+1] = {0}; | |||
rtosc_arg_t res_dat[MAX_SEARCH] = {0}; | |||
char res_type[MAX_SEARCH+1] = {}; | |||
rtosc_arg_t res_dat[MAX_SEARCH] = {}; | |||
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) { | |||
res_type[i] = 's'; | |||
res_dat[i].s = res[i].c_str(); | |||
@@ -1102,8 +1071,8 @@ const rtosc::Ports bankPorts = { | |||
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}; | |||
char res_type[MAX_SEARCH+1] = {}; | |||
rtosc_arg_t res_dat[MAX_SEARCH] = {}; | |||
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) { | |||
res_type[i] = 's'; | |||
res_dat[i].s = res[i].c_str(); | |||
@@ -1128,7 +1097,7 @@ const rtosc::Ports bankPorts = { | |||
******************************************************************************/ | |||
#undef rObject | |||
#define rObject CarlaMiddleWareImpl | |||
#define rObject MiddleWareImpl | |||
#ifndef STRINGIFY | |||
#define STRINGIFY2(a) #a | |||
@@ -1180,13 +1149,13 @@ static rtosc::Ports middwareSnoopPorts = { | |||
GUI::raiseUi(impl.ui, buffer); | |||
} | |||
rEnd}, | |||
{"config/", 0, &CarlaConfig::ports, | |||
{"config/", 0, &Config::ports, | |||
rBegin; | |||
d.obj = impl.config; | |||
CarlaConfig::ports.dispatch(chomp(msg), d); | |||
Config::ports.dispatch(chomp(msg), d); | |||
rEnd}, | |||
{"presets/", 0, &real_preset_ports, [](const char *msg, RtData &d) { | |||
CarlaMiddleWareImpl *obj = (CarlaMiddleWareImpl*)d.obj; | |||
MiddleWareImpl *obj = (MiddleWareImpl*)d.obj; | |||
d.obj = (void*)obj->parent; | |||
real_preset_ports.dispatch(chomp(msg), d); | |||
if(strstr(msg, "paste") && rtosc_argument_string(msg)[0] == 's') | |||
@@ -1201,21 +1170,26 @@ static rtosc::Ports middwareSnoopPorts = { | |||
rEnd}, | |||
{"save_xlz:s", 0, 0, | |||
rBegin; | |||
const char *file = rtosc_argument(msg, 0).s; | |||
XMLwrapper xml; | |||
saveMidiLearn(xml, impl.midi_mapper); | |||
xml.saveXMLfile(file, impl.master->gzip_compression); | |||
impl.doReadOnlyOp([&]() { | |||
const char *file = rtosc_argument(msg, 0).s; | |||
XMLwrapper xml; | |||
Master::saveAutomation(xml, impl.master->automate); | |||
xml.saveXMLfile(file, impl.master->gzip_compression); | |||
}); | |||
rEnd}, | |||
{"load_xlz:s", 0, 0, | |||
rBegin; | |||
const char *file = rtosc_argument(msg, 0).s; | |||
XMLwrapper xml; | |||
xml.loadXMLfile(file); | |||
loadMidiLearn(xml, impl.midi_mapper); | |||
rtosc::AutomationMgr *mgr = new rtosc::AutomationMgr(16,4,8); | |||
mgr->set_ports(Master::ports); | |||
Master::loadAutomation(xml, *mgr); | |||
d.chain("/automate/load-blob", "b", sizeof(void*), &mgr); | |||
rEnd}, | |||
{"clear_xlz:", 0, 0, | |||
rBegin; | |||
impl.midi_mapper.clear(); | |||
d.chain("/automate/clear", ""); | |||
rEnd}, | |||
//scale file stuff | |||
{"load_xsz:s", 0, 0, | |||
@@ -1388,51 +1362,51 @@ static rtosc::Ports middwareSnoopPorts = { | |||
impl.undo.seekHistory(+1); | |||
rEnd}, | |||
//port to observe the midi mappings | |||
{"midi-learn-values:", 0, 0, | |||
rBegin; | |||
auto &midi = impl.midi_mapper; | |||
auto key = keys(midi.inv_map); | |||
//cc-id, path, min, max | |||
#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]]; | |||
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); | |||
#undef MAX_MIDI | |||
rEnd}, | |||
{"learn:s", 0, 0, | |||
rBegin; | |||
string addr = rtosc_argument(msg, 0).s; | |||
auto &midi = impl.midi_mapper; | |||
auto map = midi.getMidiMappingStrings(); | |||
if(map.find(addr) != map.end()) | |||
midi.map(addr.c_str(), false); | |||
else | |||
midi.map(addr.c_str(), true); | |||
rEnd}, | |||
{"unlearn:s", 0, 0, | |||
rBegin; | |||
string addr = rtosc_argument(msg, 0).s; | |||
auto &midi = impl.midi_mapper; | |||
auto map = midi.getMidiMappingStrings(); | |||
midi.unMap(addr.c_str(), false); | |||
midi.unMap(addr.c_str(), true); | |||
rEnd}, | |||
//{"midi-learn-values:", 0, 0, | |||
// rBegin; | |||
// auto &midi = impl.midi_mapper; | |||
// auto key = keys(midi.inv_map); | |||
// //cc-id, path, min, max | |||
//#define MAX_MIDI 32 | |||
// rtosc_arg_t args[MAX_MIDI*4]; | |||
// char argt[MAX_MIDI*4+1] = {}; | |||
// int j=0; | |||
// for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) { | |||
// auto val = midi.inv_map[key[i]]; | |||
// 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); | |||
//#undef MAX_MIDI | |||
// rEnd}, | |||
//{"learn:s", 0, 0, | |||
// rBegin; | |||
// string addr = rtosc_argument(msg, 0).s; | |||
// auto &midi = impl.midi_mapper; | |||
// auto map = midi.getMidiMappingStrings(); | |||
// if(map.find(addr) != map.end()) | |||
// midi.map(addr.c_str(), false); | |||
// else | |||
// midi.map(addr.c_str(), true); | |||
// rEnd}, | |||
//{"unlearn:s", 0, 0, | |||
// rBegin; | |||
// string addr = rtosc_argument(msg, 0).s; | |||
// auto &midi = impl.midi_mapper; | |||
// auto map = midi.getMidiMappingStrings(); | |||
// midi.unMap(addr.c_str(), false); | |||
// midi.unMap(addr.c_str(), true); | |||
// rEnd}, | |||
//drop this message into the abyss | |||
{"ui/title:", 0, 0, [](const char *msg, RtData &d) {}}, | |||
{"quit:", 0, 0, [](const char *, RtData&) {Pexitprogram = 1;}}, | |||
@@ -1479,10 +1453,6 @@ static rtosc::Ports middlewareReplyPorts = { | |||
if(impl.recording_undo) | |||
impl.undo.recordEvent(msg); | |||
rEnd}, | |||
{"midi-use-CC:i", 0, 0, | |||
rBegin; | |||
impl.midi_mapper.useFreeID(rtosc_argument(msg, 0).i); | |||
rEnd}, | |||
{"broadcast:", 0, 0, rBegin; impl.broadcast = true; rEnd}, | |||
{"forward:", 0, 0, rBegin; impl.forward = true; rEnd}, | |||
}; | |||
@@ -1493,8 +1463,8 @@ static rtosc::Ports middlewareReplyPorts = { | |||
* MiddleWare Implementation * | |||
******************************************************************************/ | |||
CarlaMiddleWareImpl::CarlaMiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, | |||
CarlaConfig* config, int preferrred_port) | |||
MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, | |||
Config* config, int preferrred_port) | |||
:parent(mw), config(config), ui(nullptr), synth(std::move(synth_)), | |||
presetsstore(*config), autoSave(-1, [this]() { | |||
auto master = this->master; | |||
@@ -1507,8 +1477,8 @@ CarlaMiddleWareImpl::CarlaMiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, | |||
{ | |||
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);}; | |||
//midi_mapper.base_ports = &Master::ports; | |||
//midi_mapper.rt_cb = [this](const char *msg){handleMsg(msg);}; | |||
if(preferrred_port != -1) | |||
server = lo_server_new_with_proto(to_s(preferrred_port).c_str(), | |||
LO_UDP, liblo_error_cb); | |||
@@ -1561,7 +1531,7 @@ CarlaMiddleWareImpl::CarlaMiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, | |||
offline = false; | |||
} | |||
CarlaMiddleWareImpl::~CarlaMiddleWareImpl(void) | |||
MiddleWareImpl::~MiddleWareImpl(void) | |||
{ | |||
if(server) | |||
@@ -1597,7 +1567,7 @@ CarlaMiddleWareImpl::~CarlaMiddleWareImpl(void) | |||
* 4) Observe /thaw_state and resume normal processing | |||
*/ | |||
void CarlaMiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn) | |||
void MiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn) | |||
{ | |||
assert(uToB); | |||
uToB->write("/freeze_state",""); | |||
@@ -1606,7 +1576,7 @@ void CarlaMiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn) | |||
int tries = 0; | |||
while(tries++ < 10000) { | |||
if(!bToU->hasNext()) { | |||
usleep(500); | |||
os_usleep(500); | |||
continue; | |||
} | |||
const char *msg = bToU->read(); | |||
@@ -1641,13 +1611,13 @@ void CarlaMiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn) | |||
// 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 CarlaMiddleWareImpl::heartBeat(Master *master) | |||
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 + | |||
@@ -1691,7 +1661,7 @@ void CarlaMiddleWareImpl::heartBeat(Master *master) | |||
} | |||
void CarlaMiddleWareImpl::doReadOnlyOpPlugin(std::function<void()> read_only_fn) | |||
void MiddleWareImpl::doReadOnlyOpPlugin(std::function<void()> read_only_fn) | |||
{ | |||
assert(uToB); | |||
int offline = 0; | |||
@@ -1710,7 +1680,7 @@ void CarlaMiddleWareImpl::doReadOnlyOpPlugin(std::function<void()> read_only_fn) | |||
} | |||
} | |||
bool CarlaMiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, bool canfail) | |||
bool MiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, bool canfail) | |||
{ | |||
assert(uToB); | |||
uToB->write("/freeze_state",""); | |||
@@ -1719,7 +1689,7 @@ bool CarlaMiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, | |||
int tries = 0; | |||
while(tries++ < 2000) { | |||
if(!bToU->hasNext()) { | |||
usleep(500); | |||
os_usleep(500); | |||
continue; | |||
} | |||
const char *msg = bToU->read(); | |||
@@ -1757,7 +1727,7 @@ bool CarlaMiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, | |||
return true; | |||
} | |||
void CarlaMiddleWareImpl::broadcastToRemote(const char *rtmsg) | |||
void MiddleWareImpl::broadcastToRemote(const char *rtmsg) | |||
{ | |||
//Always send to the local UI | |||
sendToRemote(rtmsg, "GUI"); | |||
@@ -1770,7 +1740,7 @@ void CarlaMiddleWareImpl::broadcastToRemote(const char *rtmsg) | |||
broadcast = false; | |||
} | |||
void CarlaMiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest) | |||
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); | |||
@@ -1804,7 +1774,7 @@ void CarlaMiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest) | |||
* This includes forwarded events which need to be retransmitted to the backend | |||
* after the snooping code inspects the message | |||
*/ | |||
void CarlaMiddleWareImpl::bToUhandle(const char *rtmsg) | |||
void MiddleWareImpl::bToUhandle(const char *rtmsg) | |||
{ | |||
//Verify Message isn't a known corruption bug | |||
assert(strcmp(rtmsg, "/part0/kit0/Ppadenableda")); | |||
@@ -1845,7 +1815,7 @@ void CarlaMiddleWareImpl::bToUhandle(const char *rtmsg) | |||
} | |||
//Allocate kits on a as needed basis | |||
void CarlaMiddleWareImpl::kitEnable(const char *msg) | |||
void MiddleWareImpl::kitEnable(const char *msg) | |||
{ | |||
const string argv = rtosc_argument_string(msg); | |||
if(argv != "T") | |||
@@ -1879,7 +1849,7 @@ void CarlaMiddleWareImpl::kitEnable(const char *msg) | |||
kitEnable(part, kit, type); | |||
} | |||
void CarlaMiddleWareImpl::kitEnable(int part, int kit, int type) | |||
void MiddleWareImpl::kitEnable(int part, int kit, int type) | |||
{ | |||
//printf("attempting a kit enable<%d,%d,%d>\n", part, kit, type); | |||
string url = "/part"+to_s(part)+"/kit"+to_s(kit)+"/"; | |||
@@ -1908,7 +1878,7 @@ void CarlaMiddleWareImpl::kitEnable(int part, int kit, int type) | |||
/* | |||
* Handle all messages traveling to the realtime side. | |||
*/ | |||
void CarlaMiddleWareImpl::handleMsg(const char *msg) | |||
void MiddleWareImpl::handleMsg(const char *msg) | |||
{ | |||
//Check for known bugs | |||
assert(msg && *msg && strrchr(msg, '/')[1]); | |||
@@ -1947,7 +1917,7 @@ void CarlaMiddleWareImpl::handleMsg(const char *msg) | |||
} | |||
} | |||
void CarlaMiddleWareImpl::write(const char *path, const char *args, ...) | |||
void MiddleWareImpl::write(const char *path, const char *args, ...) | |||
{ | |||
//We have a free buffer in the threadlink, so use it | |||
va_list va; | |||
@@ -1956,7 +1926,7 @@ void CarlaMiddleWareImpl::write(const char *path, const char *args, ...) | |||
va_end(va); | |||
} | |||
void CarlaMiddleWareImpl::write(const char *path, const char *args, va_list va) | |||
void MiddleWareImpl::write(const char *path, const char *args, va_list va) | |||
{ | |||
//printf("is that a '%s' I see there?\n", path); | |||
char *buffer = uToB->buffer(); | |||
@@ -1973,9 +1943,9 @@ void CarlaMiddleWareImpl::write(const char *path, const char *args, va_list va) | |||
/****************************************************************************** | |||
* MidleWare Forwarding Stubs * | |||
******************************************************************************/ | |||
MiddleWare::MiddleWare(SYNTH_T synth, CarlaConfig* config, | |||
MiddleWare::MiddleWare(SYNTH_T synth, Config* config, | |||
int preferred_port) | |||
:impl(new CarlaMiddleWareImpl(this, std::move(synth), config, preferred_port)) | |||
:impl(new MiddleWareImpl(this, std::move(synth), config, preferred_port)) | |||
{} | |||
MiddleWare::~MiddleWare(void) | |||
@@ -2164,3 +2134,5 @@ PresetsStore& MiddleWare::getPresetsStore() | |||
{ | |||
return impl->presetsstore; | |||
} | |||
} |
@@ -14,6 +14,10 @@ | |||
#include <cstdarg> | |||
#include <string> | |||
class Fl_Osc_Interface; | |||
namespace zyncarla { | |||
struct SYNTH_T; | |||
class Master; | |||
class PresetsStore; | |||
@@ -22,7 +26,7 @@ class PresetsStore; | |||
class MiddleWare | |||
{ | |||
public: | |||
MiddleWare(SYNTH_T synth, class CarlaConfig *config, | |||
MiddleWare(SYNTH_T synth, class Config *config, | |||
int preferred_port = -1); | |||
~MiddleWare(void); | |||
void updateResources(Master *m); | |||
@@ -41,7 +45,7 @@ class MiddleWare | |||
void removeAutoSave(void); | |||
//return UI interface | |||
class Fl_Osc_Interface *spawnUiApi(void); | |||
Fl_Osc_Interface *spawnUiApi(void); | |||
//Set callback to push UI events to | |||
void setUiCallback(void(*cb)(void*,const char *),void *ui); | |||
//Set callback to run while busy | |||
@@ -79,5 +83,8 @@ class MiddleWare | |||
const PresetsStore& getPresetsStore() const; | |||
PresetsStore& getPresetsStore(); | |||
private: | |||
class CarlaMiddleWareImpl *impl; | |||
class MiddleWareImpl *impl; | |||
}; | |||
} | |||
@@ -37,6 +37,8 @@ | |||
#include <rtosc/port-sugar.h> | |||
#include <iostream> | |||
namespace zyncarla { | |||
using rtosc::Ports; | |||
using rtosc::RtData; | |||
@@ -45,41 +47,55 @@ static const Ports partPorts = { | |||
rRecurs(kit, 16, "Kit"),//NUM_KIT_ITEMS | |||
rRecursp(partefx, 3, "Part Effect"), | |||
rRecur(ctl, "Controller"), | |||
rToggle(Penabled, rShort("enable"), "Part enable"), | |||
rParamZyn(partno, rProp(internal), | |||
"How many parts are before this in the Master"), | |||
#undef rChangeCb | |||
#define rChangeCb if(obj->Penabled == false) obj->AllNotesOff(); | |||
rToggle(Penabled, rShort("enable"), rDefaultDepends(partno), | |||
rPresets(true), rDefault(false), "Part enable"), | |||
#undef rChangeCb | |||
#define rChangeCb | |||
#undef rChangeCb | |||
#define rChangeCb obj->setPvolume(obj->Pvolume); | |||
rParamZyn(Pvolume, rShort("Vol"), "Part Volume"), | |||
rParamZyn(Pvolume, rShort("Vol"), rDefault(96),"Part Volume"), | |||
#undef rChangeCb | |||
#define rChangeCb obj->setPpanning(obj->Ppanning); | |||
rParamZyn(Ppanning, rShort("pan"), "Set Panning"), | |||
rParamZyn(Ppanning, rShort("pan"), rDefault(64), "Set Panning"), | |||
#undef rChangeCb | |||
#define rChangeCb obj->setkeylimit(obj->Pkeylimit); | |||
rParamI(Pkeylimit, rShort("limit"), rProp(parameter), rMap(min,0), rMap(max, POLYPHONY), "Key limit per part"), | |||
rParamI(Pkeylimit, rShort("limit"), rProp(parameter), | |||
rMap(min,0), rMap(max, POLYPHONY), rDefault(15), "Key limit per part"), | |||
#undef rChangeCb | |||
#define rChangeCb | |||
rParamZyn(Pminkey, rShort("min"), "Min Used Key"), | |||
rParamZyn(Pmaxkey, rShort("max"), "Max Used Key"), | |||
rParamZyn(Pkeyshift, rShort("shift"), "Part keyshift"), | |||
rParamZyn(Pminkey, rShort("min"), rDefault(0), "Min Used Key"), | |||
rParamZyn(Pmaxkey, rShort("max"), rDefault(127), "Max Used Key"), | |||
rParamZyn(Pkeyshift, rShort("shift"), rDefault(64), "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, 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" | |||
rPresets(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16), | |||
"Active MIDI channel"), | |||
rParamZyn(Pvelsns, rShort("sense"), rDefault(64), "Velocity sensing"), | |||
rParamZyn(Pveloffs, rShort("offset"), rDefault(64),"Velocity offset"), | |||
rToggle(Pnoteon, rDefault(true), "If the channel accepts note on events"), | |||
rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), rDefault(Off), | |||
"Kit mode/enable\n" | |||
"Off - Only the first kit is ever utilized\n" | |||
"Multi-kit - Every applicable kit is run for a note\n" | |||
"Single-kit - The first applicable kit is run for a given note"), | |||
rToggle(Pdrummode, "Drum mode enable\n" | |||
rToggle(Pdrummode, rDefault(false), "Drum mode enable\n" | |||
"When drum mode is enabled all keys are mapped to 12tET and legato is disabled"), | |||
rToggle(Ppolymode, "Polyphony mode"), | |||
rToggle(Plegatomode, "Legato mode"), | |||
rParamZyn(info.Ptype, "Class of Instrument"), | |||
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"), | |||
rToggle(Ppolymode, rDefault(true), "Polyphony mode"), | |||
rToggle(Plegatomode, rDefault(false), "Legato mode"), | |||
rParamZyn(info.Ptype, rDefault(0), "Class of Instrument"), | |||
rString(info.Pauthor, MAX_INFO_TEXT_SIZE, rDefault(""), | |||
"Instrument author"), | |||
rString(info.Pcomments, MAX_INFO_TEXT_SIZE, rDefault(""), | |||
"Instrument comments"), | |||
rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "User specified label"), | |||
rArrayI(Pefxroute, NUM_PART_EFX, | |||
rOptions(Next Effect,Part Out,Dry Out), "Effect Routing"), | |||
rArrayT(Pefxbypass, NUM_PART_EFX, "If an effect is bypassed"), | |||
rOptions(Next Effect,Part Out,Dry Out), rDefaultId(Next Effect), | |||
"Effect Routing"), | |||
rArrayT(Pefxbypass, NUM_PART_EFX, rDefault(false), | |||
"If an effect is bypassed"), | |||
{"captureMin:", rDoc("Capture minimum valid note"), NULL, | |||
[](const char *, RtData &r) | |||
{Part *p = (Part*)r.obj; p->Pminkey = p->lastnote;}}, | |||
@@ -156,20 +172,26 @@ static const Ports partPorts = { | |||
#undef rObject | |||
#define rObject Part::Kit | |||
static const Ports kitPorts = { | |||
rSelf(Part::Kit, rEnabledBy(Penabled)), | |||
rRecurp(padpars, "Padnote parameters"), | |||
rRecurp(adpars, "Adnote parameters"), | |||
rRecurp(subpars, "Adnote parameters"), | |||
rToggle(Penabled, "Kit item enable"), | |||
rToggle(Pmuted, "Kit item mute"), | |||
rParamZyn(Pminkey, "Kit item min key"), | |||
rParamZyn(Pmaxkey, "Kit item max key"), | |||
rToggle(Padenabled, "ADsynth enable"), | |||
rToggle(Psubenabled, "SUBsynth enable"), | |||
rToggle(Ppadenabled, "PADsynth enable"), | |||
rToggle(firstkit, rProp(internal), "If this is the part's first kit"), | |||
rToggle(Penabled, rDefaultDepends(firstkit), | |||
rPreset(true, true), rPreset(false, false), | |||
"Kit item enable"), | |||
rToggle(Pmuted, rDefault(false), "Kit item mute"), | |||
rParamZyn(Pminkey, rDefault(0), "Kit item min key"), | |||
rParamZyn(Pmaxkey, rDefault(127) "Kit item max key"), | |||
rToggle(Padenabled, rDefaultDepends(firstkit), | |||
rPreset(true, true), rPreset(false, false) | |||
"ADsynth enable"), | |||
rToggle(Psubenabled, rDefault(false), "SUBsynth enable"), | |||
rToggle(Ppadenabled, rDefault(false), "PADsynth enable"), | |||
rParamZyn(Psendtoparteffect, | |||
rOptions(FX1, FX2, FX3, Off), | |||
rOptions(FX1, FX2, FX3, Off), rDefault(FX1), | |||
"Effect Levels"), | |||
rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"), | |||
rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "Kit User Specified Label"), | |||
{"captureMin:", rDoc("Capture minimum valid note"), NULL, | |||
[](const char *, RtData &r) | |||
{Part::Kit *p = (Part::Kit*)r.obj; p->Pminkey = p->parent->lastnote;}}, | |||
@@ -326,6 +348,7 @@ void Part::defaultsinstrument() | |||
for(int n = 0; n < NUM_KIT_ITEMS; ++n) { | |||
//kit[n].Penabled = false; | |||
kit[n].firstkit = false; | |||
kit[n].Pmuted = false; | |||
kit[n].Pminkey = 0; | |||
kit[n].Pmaxkey = 127; | |||
@@ -337,6 +360,7 @@ void Part::defaultsinstrument() | |||
if(n != 0) | |||
setkititemstatus(n, 0); | |||
} | |||
kit[0].firstkit = true; | |||
kit[0].Penabled = 1; | |||
kit[0].Padenabled = 1; | |||
kit[0].adpars->defaults(); | |||
@@ -1208,3 +1232,5 @@ bool Part::Kit::validNote(char note) const | |||
{ | |||
return !Pmuted && inRange((uint8_t)note, Pminkey, Pmaxkey); | |||
} | |||
} |
@@ -22,6 +22,8 @@ | |||
#include <functional> | |||
namespace zyncarla { | |||
/** Part implementation*/ | |||
class Part | |||
{ | |||
@@ -83,6 +85,7 @@ class Part | |||
struct Kit { | |||
Kit(void); | |||
Part *parent; | |||
bool firstkit; | |||
bool Penabled, Pmuted; | |||
unsigned char Pminkey, Pmaxkey; | |||
char *Pname; | |||
@@ -104,13 +107,14 @@ class Part | |||
void setkeylimit(unsigned char Pkeylimit); | |||
void setkititemstatus(unsigned kititem, bool Penabled_); | |||
unsigned char partno; /**<if it's the Master's first part*/ | |||
bool Penabled; /**<if the part is enabled*/ | |||
unsigned char Pvolume; /**<part volume*/ | |||
unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/ | |||
unsigned char Pmaxkey; //the maximum key that the part receives noteon messages | |||
void setPvolume(char Pvolume); | |||
unsigned char Pkeyshift; //Part keyshift | |||
unsigned char Prcvchn; //from what midi channel it receive commnads | |||
unsigned char Prcvchn; //from what midi channel it receives commands | |||
unsigned char Ppanning; //part panning | |||
void setPpanning(char Ppanning); | |||
unsigned char Pvelsns; //velocity sensing (amplitude velocity scale) | |||
@@ -200,4 +204,6 @@ class Part | |||
const int &gzip_compression, &interpolation; | |||
}; | |||
} | |||
#endif |
@@ -31,8 +31,10 @@ | |||
#include <rtosc/ports.h> | |||
#include <rtosc/port-sugar.h> | |||
#include <string> | |||
using std::string; | |||
namespace zyncarla { | |||
using std::string; | |||
static void dummy(const char *, rtosc::RtData&) {} | |||
const rtosc::Ports real_preset_ports = | |||
@@ -491,3 +493,5 @@ bool presetCheckClipboardType() | |||
printf("PresetCheckClipboardType()<UNIMPLEMENTED>\n"); | |||
return true; | |||
} | |||
} |
@@ -13,8 +13,11 @@ | |||
#include <string> | |||
#include <rtosc/ports.h> | |||
namespace zyncarla { | |||
extern const rtosc::Ports real_preset_ports; | |||
extern const rtosc::Ports preset_ports; | |||
struct Clipboard { | |||
std::string data; | |||
std::string type; | |||
@@ -31,3 +34,5 @@ void presetDelete(int); | |||
void presetRescan(); | |||
std::string presetClipboardType(); | |||
bool presetCheckClipboardType(); | |||
} |
@@ -17,6 +17,8 @@ | |||
#include "../globals.h" | |||
#include "../Nio/Nio.h" | |||
namespace zyncarla { | |||
Recorder::Recorder(const SYNTH_T &synth_) | |||
:status(0), notetrigger(0),synth(synth_) | |||
{} | |||
@@ -81,3 +83,4 @@ void Recorder::triggernow() | |||
} | |||
//TODO move recorder inside nio system | |||
} |
@@ -15,6 +15,8 @@ | |||
#define RECORDER_H | |||
#include <string> | |||
namespace zyncarla { | |||
struct SYNTH_T; | |||
/**Records sound to a file*/ | |||
class Recorder | |||
@@ -43,4 +45,6 @@ class Recorder | |||
const SYNTH_T &synth; | |||
}; | |||
} | |||
#endif |
@@ -1,6 +1,40 @@ | |||
#include <ostream> | |||
#include <rtosc/ports.h> | |||
using namespace rtosc; | |||
// forwards declaration from rtosc lib | |||
void walk_ports2(const rtosc::Ports *base, | |||
char *name_buffer, | |||
size_t buffer_size, | |||
void *data, | |||
rtosc::port_walker_t walker); | |||
namespace zyncarla { | |||
static const char *escape_string(const char *msg) | |||
{ | |||
if(!msg) | |||
return NULL; | |||
char *out = (char*)malloc(strlen(msg)*2+1); | |||
memset(out, 0, strlen(msg)*2+1); | |||
char *itr = out; | |||
while(*msg) { | |||
if(*msg == '"') { | |||
*itr++ = '\\'; | |||
*itr++ = '\"'; | |||
} else if(*msg == '\\') { | |||
*itr++ = '\\'; | |||
*itr++ = '\\'; | |||
} else { | |||
*itr++ = *msg; | |||
} | |||
msg++; | |||
} | |||
return out; | |||
} | |||
/* | |||
* root : | |||
* - 'parameters' : [parameter...] | |||
@@ -11,8 +45,12 @@ using namespace rtosc; | |||
* - 'shortname' : string [OPTIONAL] | |||
* - 'tooltip' : string [OPTIONAL] | |||
* - 'type' : type | |||
* - 'units' : unit-type | |||
* - 'scale' : scale-type | |||
* - 'domain' : range [OPTIONAL] | |||
* - 'options' : [option...] [OPTIONAL] | |||
* - 'default' : string | |||
* - 'defaults' : defaults | |||
* type : {'int', 'float', 'boolean'} | |||
* action : | |||
* - 'path' : path-id | |||
@@ -23,15 +61,11 @@ using namespace rtosc; | |||
* option : | |||
* - 'id' : id-number | |||
* - 'value' : string-rep | |||
* defaults : | |||
* - 'id' : id-number | |||
* - 'value' : string-rep | |||
*/ | |||
void walk_ports2(const rtosc::Ports *base, | |||
char *name_buffer, | |||
size_t buffer_size, | |||
void *data, | |||
rtosc::port_walker_t walker); | |||
using std::ostream; | |||
using std::string; | |||
static int enum_min(Port::MetaContainer meta) | |||
@@ -102,7 +136,8 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta) | |||
* - 'domain' : range [OPTIONAL] | |||
*/ | |||
static bool first = true; | |||
void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) | |||
void dump_param_cb(const rtosc::Port *p, const char *full_name, const char*, | |||
const Ports&,void *v, void*) | |||
{ | |||
typedef std::vector<std::pair<int,string>> opts; | |||
std::ostream &o = *(std::ostream*)v; | |||
@@ -111,6 +146,9 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) | |||
auto mparameter = meta.find("parameter"); | |||
auto mdoc = meta.find("documentation"); | |||
auto msname = meta.find("shortname"); | |||
auto units = meta.find("unit"); | |||
auto scale = meta.find("scale"); | |||
opts options; | |||
string doc; | |||
string name = p->name;; | |||
@@ -166,6 +204,8 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) | |||
const char *min = meta["min"]; | |||
const char *max = meta["max"]; | |||
const char *def = meta["default"]; | |||
def = escape_string(def); | |||
for(auto m:meta) { | |||
if(strlen(m.title) >= 5 && !memcmp(m.title, "map ", 4)) { | |||
@@ -186,9 +226,15 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) | |||
o << " \"shortname\": \"" << msname.value << "\",\n"; | |||
o << " \"name\" : \"" << name << "\",\n"; | |||
o << " \"tooltip\" : \"" << doc << "\",\n"; | |||
if(units != meta.end()) | |||
o << " \"units\" : \"" << units.value << "\",\n"; | |||
if(scale != meta.end()) | |||
o << " \"scale\" : \"" << scale.value << "\",\n"; | |||
o << " \"type\" : \"" << type << "\""; | |||
if(min && max) | |||
o << ",\n \"range\" : [" << min << "," << max << "]"; | |||
if(def) | |||
o << ",\n \"default\" : \"" << def << "\"\n"; | |||
if(!options.empty()) { | |||
o << ",\n \"options\" : [\n"; | |||
int N = options.size(); | |||
@@ -221,4 +267,4 @@ void dump_json(std::ostream &o, const rtosc::Ports &p) | |||
o << "}"; | |||
} | |||
} |
@@ -11,6 +11,8 @@ | |||
of the License, or (at your option) any later version. | |||
*/ | |||
namespace zyncarla { | |||
template<class T> | |||
Stereo<T>::Stereo(const T &left, const T &right) | |||
:l(left), r(right) | |||
@@ -28,3 +30,5 @@ Stereo<T> &Stereo<T>::operator=(const Stereo<T> &nstr) | |||
r = nstr.r; | |||
return *this; | |||
} | |||
} |
@@ -13,6 +13,8 @@ | |||
#ifndef STEREO_H | |||
#define STEREO_H | |||
namespace zyncarla { | |||
template<class T> | |||
struct Stereo { | |||
public: | |||
@@ -28,5 +30,8 @@ struct Stereo { | |||
//data | |||
T l, r; | |||
}; | |||
} | |||
#include "Stereo.cpp" | |||
#endif |
@@ -13,6 +13,8 @@ | |||
#include <stdint.h> | |||
#include "../globals.h" | |||
namespace zyncarla { | |||
class AbsTime | |||
{ | |||
public: | |||
@@ -51,3 +53,5 @@ class RelTime | |||
int32_t sample; | |||
const AbsTime &t; | |||
}; | |||
} |
@@ -36,6 +36,8 @@ | |||
#include <rtosc/rtosc.h> | |||
namespace zyncarla { | |||
bool isPlugin = false; | |||
prng_t prng_state = 0x1234; | |||
@@ -127,10 +129,31 @@ void set_realtime() | |||
#endif | |||
} | |||
void os_sleep(long length) | |||
#ifdef WIN32 | |||
#include <windows.h> | |||
//https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw | |||
void os_usleep(long usec) | |||
{ | |||
HANDLE timer; | |||
LARGE_INTEGER ft; | |||
ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time | |||
timer = CreateWaitableTimer(NULL, TRUE, NULL); | |||
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); | |||
WaitForSingleObject(timer, INFINITE); | |||
CloseHandle(timer); | |||
} | |||
#else | |||
void os_usleep(long length) | |||
{ | |||
usleep(length); | |||
} | |||
#endif | |||
//!< maximum lenght a pid has on any POSIX system | |||
//!< this is an estimation, but more than 12 looks insane | |||
@@ -225,3 +248,5 @@ char *rtosc_splat(const char *path, std::set<std::string> v) | |||
rtosc_amessage(buf, len, path, argT, arg); | |||
return buf; | |||
} | |||
} |
@@ -23,16 +23,17 @@ | |||
#include <rtosc/ports.h> | |||
#include <rtosc/port-sugar.h> | |||
namespace zyncarla { | |||
extern bool isPlugin; | |||
bool fileexists(const char *filename); | |||
using std::min; | |||
using std::max; | |||
//Velocity Sensing function | |||
extern float VelF(float velocity, unsigned char scaling); | |||
extern bool isPlugin; | |||
bool fileexists(const char *filename); | |||
#define N_DETUNE_TYPES 4 //the number of detune types | |||
extern float getdetune(unsigned char type, | |||
unsigned short int coarsedetune, | |||
@@ -45,7 +46,7 @@ extern float getdetune(unsigned char type, | |||
void set_realtime(); | |||
/**Os independent sleep in microsecond*/ | |||
void os_sleep(long length); | |||
void os_usleep(long length); | |||
//! returns pid padded to maximum pid lenght, posix conform | |||
std::string os_pid_as_padded_string(); | |||
@@ -152,11 +153,6 @@ char *rtosc_splat(const char *path, std::set<std::string>); | |||
#define rParamZyn(name, ...) \ | |||
{STRINGIFY(name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, rParamICb(name)} | |||
#define rSelf(type) \ | |||
{"self:", rProp(internal) rMap(class, type) rDoc("port metadata"), 0, \ | |||
[](const char *, rtosc::RtData &d){ \ | |||
d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\ | |||
#define rPresetType \ | |||
{"preset-type:", rProp(internal) rDoc("clipboard type of object"), 0, \ | |||
[](const char *, rtosc::RtData &d){ \ | |||
@@ -181,4 +177,8 @@ rPresetType, \ | |||
rObject &o = *(rObject*)d.obj;\ | |||
o.pasteArray(paste,field);}} | |||
} | |||
#define rUnit(x) rMap(unit, x) | |||
#endif |
@@ -19,6 +19,8 @@ | |||
#include "WavFile.h" | |||
using namespace std; | |||
namespace zyncarla { | |||
WavFile::WavFile(string filename, int samplerate, int channels) | |||
:sampleswritten(0), samplerate(samplerate), channels(channels), | |||
file(fopen(filename.c_str(), "w")) | |||
@@ -90,3 +92,5 @@ void WavFile::writeMonoSamples(int nsmps, short int *smps) | |||
sampleswritten += nsmps; | |||
} | |||
} | |||
} |
@@ -16,6 +16,8 @@ | |||
#define WAVFILE_H | |||
#include <string> | |||
namespace zyncarla { | |||
class WavFile | |||
{ | |||
public: | |||
@@ -33,4 +35,7 @@ class WavFile | |||
int channels; | |||
FILE *file; | |||
}; | |||
} | |||
#endif |
@@ -14,6 +14,8 @@ | |||
#include "WaveShapeSmps.h" | |||
#include <cmath> | |||
namespace zyncarla { | |||
void waveShapeSmps(int n, | |||
float *smps, | |||
unsigned char type, | |||
@@ -178,3 +180,5 @@ void waveShapeSmps(int n, | |||
break; | |||
} | |||
} | |||
} |
@@ -13,10 +13,14 @@ | |||
#ifndef WAVESHAPESMPS_H | |||
#define WAVESHAPESMPS_H | |||
namespace zyncarla { | |||
//Waveshaping(called by Distorsion effect and waveshape from OscilGen) | |||
void waveShapeSmps(int n, | |||
float *smps, | |||
unsigned char type, | |||
unsigned char drive); | |||
} | |||
#endif |
@@ -27,6 +27,8 @@ | |||
using namespace std; | |||
namespace zyncarla { | |||
int xml_k = 0; | |||
bool verbose = false; | |||
@@ -251,7 +253,7 @@ void XMLwrapper::addparreal(const string &name, float val) | |||
union { float in; uint32_t out; } convert; | |||
char buf[11]; | |||
convert.in = val; | |||
sprintf(buf, "0x%8X", convert.out); | |||
sprintf(buf, "0x%0.8X", convert.out); | |||
addparams("par_real", 3, "name", name.c_str(), "value", | |||
stringFrom<float>(val).c_str(), "exact_value", buf); | |||
} | |||
@@ -395,6 +397,12 @@ bool XMLwrapper::putXMLdata(const char *xmldata) | |||
if(root == NULL) | |||
return false; | |||
//fetch version information | |||
_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"))); | |||
return true; | |||
} | |||
@@ -677,3 +685,5 @@ std::vector<XmlNode> XMLwrapper::getBranch(void) const | |||
} | |||
return res; | |||
} | |||
} |
@@ -21,6 +21,8 @@ | |||
#ifndef XML_WRAPPER_H | |||
#define XML_WRAPPER_H | |||
namespace zyncarla { | |||
class XmlAttr | |||
{ | |||
public: | |||
@@ -285,4 +287,6 @@ public: | |||
version_type _fileversion; | |||
}; | |||
} | |||
#endif |
@@ -15,8 +15,6 @@ | |||
#include <iostream> | |||
#include <cmath> | |||
using namespace std; | |||
#include "../Misc/Util.h" | |||
#include "../Misc/Config.h" | |||
#include "InMgr.h" | |||
@@ -24,6 +22,10 @@ using namespace std; | |||
#include "Compressor.h" | |||
#include "Nio.h" | |||
using namespace std; | |||
namespace zyncarla { | |||
AlsaEngine::AlsaEngine(const SYNTH_T &synth) | |||
:AudioOut(synth) | |||
{ | |||
@@ -397,3 +399,5 @@ void *AlsaEngine::processAudio() | |||
} | |||
return NULL; | |||
} | |||
} |
@@ -24,6 +24,8 @@ | |||
#include "OutMgr.h" | |||
#include "../Misc/Stereo.h" | |||
namespace zyncarla { | |||
class AlsaEngine:public AudioOut, MidiIn | |||
{ | |||
public: | |||
@@ -74,4 +76,6 @@ class AlsaEngine:public AudioOut, MidiIn | |||
void *processAudio(); | |||
}; | |||
} | |||
#endif |
@@ -15,12 +15,14 @@ | |||
#include <cstring> | |||
#include "SafeQueue.h" | |||
using namespace std; | |||
#include "OutMgr.h" | |||
#include "../Misc/Master.h" | |||
#include "AudioOut.h" | |||
using namespace std; | |||
namespace zyncarla { | |||
AudioOut::AudioOut(const SYNTH_T &synth_) | |||
:synth(synth_), samplerate(synth.samplerate), bufferSize(synth.buffersize) | |||
{} | |||
@@ -47,3 +49,5 @@ const Stereo<float *> AudioOut::getNext() | |||
{ | |||
return OutMgr::getInstance().tick(bufferSize); | |||
} | |||
} |
@@ -18,6 +18,8 @@ | |||
#include "../globals.h" | |||
#include "Engine.h" | |||
namespace zyncarla { | |||
class AudioOut:public virtual Engine | |||
{ | |||
public: | |||
@@ -50,4 +52,6 @@ class AudioOut:public virtual Engine | |||
int bufferSize; | |||
}; | |||
} | |||
#endif |
@@ -12,8 +12,12 @@ | |||
*/ | |||
#include "Engine.h" | |||
namespace zyncarla { | |||
Engine::Engine() | |||
{} | |||
Engine::~Engine() | |||
{} | |||
} |
@@ -14,6 +14,9 @@ | |||
#ifndef ENGINE_H | |||
#define ENGINE_H | |||
#include <string> | |||
namespace zyncarla { | |||
/**Marker for input/output driver*/ | |||
class Engine | |||
{ | |||
@@ -29,4 +32,7 @@ class Engine | |||
std::string name; | |||
}; | |||
} | |||
#endif |
@@ -19,6 +19,8 @@ | |||
#include "AudioOut.h" | |||
#include "MidiIn.h" | |||
#include "NulEngine.h" | |||
using namespace std; | |||
#if OSS | |||
#include "OssEngine.h" | |||
#include "OssMultiEngine.h" | |||
@@ -34,7 +36,7 @@ | |||
#include "PaEngine.h" | |||
#endif | |||
using namespace std; | |||
namespace zyncarla { | |||
EngineMgr &EngineMgr::getInstance(const SYNTH_T *synth, | |||
const oss_devs_t *oss_devs) | |||
@@ -172,3 +174,5 @@ bool EngineMgr::setOutDefault(string name) | |||
cerr << " Defaulting to the NULL audio backend" << endl; | |||
return false; | |||
} | |||
} |
@@ -16,6 +16,7 @@ | |||
#include <string> | |||
#include "Engine.h" | |||
namespace zyncarla { | |||
class MidiIn; | |||
class AudioOut; | |||
@@ -54,4 +55,7 @@ class EngineMgr | |||
private: | |||
EngineMgr(const SYNTH_T *synth, const oss_devs_t &oss_devs); | |||
}; | |||
} | |||
#endif |
@@ -17,10 +17,11 @@ | |||
#include "../Misc/MiddleWare.h" | |||
#include <rtosc/thread-link.h> | |||
#include <iostream> | |||
using namespace std; | |||
extern MiddleWare *middleware; | |||
extern zyncarla::MiddleWare *middleware; | |||
namespace zyncarla { | |||
ostream &operator<<(ostream &out, const MidiEvent &ev) | |||
{ | |||
@@ -172,3 +173,5 @@ void InMgr::setMaster(Master *master_) | |||
{ | |||
master = master_; | |||
} | |||
} |
@@ -16,6 +16,8 @@ | |||
#include "ZynSema.h" | |||
#include "SafeQueue.h" | |||
namespace zyncarla { | |||
enum midi_type { | |||
M_NOTE = 1, | |||
M_CONTROLLER = 2, | |||
@@ -65,4 +67,6 @@ class InMgr | |||
class Master *master; | |||
}; | |||
} | |||
#endif |
@@ -32,10 +32,12 @@ | |||
#include "JackEngine.h" | |||
using namespace std; | |||
extern char *instance_name; | |||
namespace zyncarla { | |||
using namespace std; | |||
JackEngine::JackEngine(const SYNTH_T &synth) | |||
:AudioOut(synth), jackClient(NULL) | |||
{ | |||
@@ -438,3 +440,5 @@ void JackEngine::handleMidi(unsigned long frames) | |||
} | |||
} | |||
} | |||
} |
@@ -23,6 +23,8 @@ | |||
#include "MidiIn.h" | |||
#include "AudioOut.h" | |||
namespace zyncarla { | |||
typedef jack_default_audio_sample_t jsample_t; | |||
class JackEngine:public AudioOut, MidiIn | |||
@@ -83,4 +85,6 @@ class JackEngine:public AudioOut, MidiIn | |||
void handleMidi(unsigned long frames); | |||
}; | |||
} | |||
#endif |
@@ -26,7 +26,10 @@ | |||
#include "JackMultiEngine.h" | |||
extern MiddleWare *middleware; | |||
extern zyncarla::MiddleWare *middleware; | |||
namespace zyncarla { | |||
using std::string; | |||
struct jack_multi | |||
@@ -170,3 +173,5 @@ void JackMultiEngine::Stop() | |||
impl->running = false; | |||
} | |||
} |
@@ -15,6 +15,8 @@ | |||
#include "AudioOut.h" | |||
namespace zyncarla { | |||
class JackMultiEngine:public AudioOut | |||
{ | |||
public: | |||
@@ -34,4 +36,6 @@ class JackMultiEngine:public AudioOut | |||
struct jack_multi *impl; | |||
}; | |||
} | |||
#endif |
@@ -15,6 +15,8 @@ | |||
#include "../globals.h" | |||
#include "InMgr.h" | |||
namespace zyncarla { | |||
void MidiIn::midiProcess(unsigned char head, | |||
unsigned char num, | |||
unsigned char value) | |||
@@ -66,3 +68,5 @@ void MidiIn::midiProcess(unsigned char head, | |||
break; | |||
} | |||
} | |||
} |
@@ -18,6 +18,8 @@ | |||
#include "Engine.h" | |||
namespace zyncarla { | |||
/**This class is inherited by all the Midi input classes*/ | |||
class MidiIn:public virtual Engine | |||
{ | |||
@@ -31,4 +33,6 @@ class MidiIn:public virtual Engine | |||
unsigned char value); | |||
}; | |||
} | |||
#endif |
@@ -20,6 +20,9 @@ | |||
#include <cstring> | |||
#include <iostream> | |||
#include <algorithm> | |||
namespace zyncarla { | |||
using std::string; | |||
using std::set; | |||
using std::cerr; | |||
@@ -183,3 +186,5 @@ void Nio::waveEnd(void) | |||
{ | |||
out->wave->destroyFile(); | |||
} | |||
} |
@@ -14,6 +14,8 @@ | |||
#include <string> | |||
#include <set> | |||
namespace zyncarla { | |||
class WavFile; | |||
class Master; | |||
struct SYNTH_T; | |||
@@ -61,4 +63,6 @@ namespace Nio | |||
extern std::string defaultSink; | |||
}; | |||
} | |||
#endif |