diff --git a/.gitignore b/.gitignore index 27c684e7d..4c345e482 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/data/copy-zynaddsubfx b/data/copy-zynaddsubfx index 4127c39df..f38c968d7 100755 --- a/data/copy-zynaddsubfx +++ b/data/copy-zynaddsubfx @@ -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 diff --git a/source/native-plugins/Makefile b/source/native-plugins/Makefile index c31b86560..c4bc741cc 100644 --- a/source/native-plugins/Makefile +++ b/source/native-plugins/Makefile @@ -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) diff --git a/source/native-plugins/zynaddsubfx-fx.cpp b/source/native-plugins/zynaddsubfx-fx.cpp index f3e28e5ac..223635a3f 100644 --- a/source/native-plugins/zynaddsubfx-fx.cpp +++ b/source/native-plugins/zynaddsubfx-fx.cpp @@ -34,6 +34,8 @@ using juce::roundToIntAccurate; using juce::FloatVectorOperations; using juce::SharedResourcePointer; +using namespace zyncarla; + // ----------------------------------------------------------------------- template diff --git a/source/native-plugins/zynaddsubfx-src.cpp b/source/native-plugins/zynaddsubfx-src.cpp index ea953e41d..5663e3443 100644 --- a/source/native-plugins/zynaddsubfx-src.cpp +++ b/source/native-plugins/zynaddsubfx-src.cpp @@ -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(){} } +} diff --git a/source/native-plugins/zynaddsubfx-synth.cpp b/source/native-plugins/zynaddsubfx-synth.cpp index db63373f4..e2d050f02 100644 --- a/source/native-plugins/zynaddsubfx-synth.cpp +++ b/source/native-plugins/zynaddsubfx-synth.cpp @@ -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 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]; diff --git a/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp b/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp index 0065bb159..ade59b74e 100644 --- a/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp +++ b/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp @@ -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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h b/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h index 713567883..5d91a750e 100644 --- a/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h +++ b/source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h @@ -13,6 +13,8 @@ #include #include +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(); } }; + +} diff --git a/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp b/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp index 2f6c3514a..4248fc468 100644 --- a/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp +++ b/source/native-plugins/zynaddsubfx/Containers/NotePool.cpp @@ -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"); } + +} diff --git a/source/native-plugins/zynaddsubfx/Containers/NotePool.h b/source/native-plugins/zynaddsubfx/Containers/NotePool.h index 8a5afbfbc..c08b87eb6 100644 --- a/source/native-plugins/zynaddsubfx/Containers/NotePool.h +++ b/source/native-plugins/zynaddsubfx/Containers/NotePool.h @@ -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); }; + +} diff --git a/source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp b/source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp index bcb9921bb..270181371 100644 --- a/source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp +++ b/source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp @@ -2,6 +2,8 @@ #include #include +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; //} + +} diff --git a/source/native-plugins/zynaddsubfx/Containers/ScratchString.h b/source/native-plugins/zynaddsubfx/Containers/ScratchString.h index 5e2a69f08..7ae2cb8f0 100644 --- a/source/native-plugins/zynaddsubfx/Containers/ScratchString.h +++ b/source/native-plugins/zynaddsubfx/Containers/ScratchString.h @@ -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]; }; + +} + diff --git a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp index 435256b80..932bdb9c6 100644 --- a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp @@ -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); } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h index 95d7e6714..9641f2a0f 100644 --- a/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h +++ b/source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.cpp b/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.cpp index 062c09fd4..e8d96fa73 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.cpp @@ -17,6 +17,8 @@ #include #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; } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.h b/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.h index 418bfb894..b7bed00a9 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.h +++ b/source/native-plugins/zynaddsubfx/DSP/FFTwrapper.h @@ -17,6 +17,8 @@ #include #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 diff --git a/source/native-plugins/zynaddsubfx/DSP/Filter.cpp b/source/native-plugins/zynaddsubfx/DSP/Filter.cpp index 0872201c3..d6dd4ed75 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Filter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/Filter.cpp @@ -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 } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/Filter.h b/source/native-plugins/zynaddsubfx/DSP/Filter.h index 4bf86f420..649b5e09a 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Filter.h +++ b/source/native-plugins/zynaddsubfx/DSP/Filter.h @@ -16,6 +16,8 @@ #include "../globals.h" +namespace zyncarla { + class Filter { public: @@ -53,4 +55,6 @@ class Filter } }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp index 1d52d10d1..402360bae 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp @@ -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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h index 8b3fd46a2..764b9ff8a 100644 --- a/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h +++ b/source/native-plugins/zynaddsubfx/DSP/FormantFilter.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp b/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp index db1f32f08..36269073b 100644 --- a/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/SVFilter.cpp @@ -24,6 +24,8 @@ #include #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; } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/SVFilter.h b/source/native-plugins/zynaddsubfx/DSP/SVFilter.h index 319889309..200e95ce3 100644 --- a/source/native-plugins/zynaddsubfx/DSP/SVFilter.h +++ b/source/native-plugins/zynaddsubfx/DSP/SVFilter.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/DSP/Unison.cpp b/source/native-plugins/zynaddsubfx/DSP/Unison.cpp index 307f1c5e5..a919e199d 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Unison.cpp +++ b/source/native-plugins/zynaddsubfx/DSP/Unison.cpp @@ -24,6 +24,8 @@ #include #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; } + +} diff --git a/source/native-plugins/zynaddsubfx/DSP/Unison.h b/source/native-plugins/zynaddsubfx/DSP/Unison.h index 485eb8031..d2324b30a 100644 --- a/source/native-plugins/zynaddsubfx/DSP/Unison.h +++ b/source/native-plugins/zynaddsubfx/DSP/Unison.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp b/source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp index ae4e1c859..979293c19 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp @@ -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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Alienwah.h b/source/native-plugins/zynaddsubfx/Effects/Alienwah.h index a5fdf3096..bbf4d8528 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Alienwah.h +++ b/source/native-plugins/zynaddsubfx/Effects/Alienwah.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/Chorus.cpp b/source/native-plugins/zynaddsubfx/Effects/Chorus.cpp index 87d2cc760..9922acaf7 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Chorus.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Chorus.cpp @@ -17,9 +17,10 @@ #include "../Misc/Allocator.h" #include "Chorus.h" #include - 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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Chorus.h b/source/native-plugins/zynaddsubfx/Effects/Chorus.h index f4fb95341..b1556e0f7 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Chorus.h +++ b/source/native-plugins/zynaddsubfx/Effects/Chorus.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp b/source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp index b71772c67..3a558f425 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp @@ -19,6 +19,8 @@ #include #include +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 } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Distorsion.h b/source/native-plugins/zynaddsubfx/Effects/Distorsion.h index 255fcd848..7b8771ca6 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Distorsion.h +++ b/source/native-plugins/zynaddsubfx/Effects/Distorsion.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp b/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp index a777c28a2..82fa0e1ce 100644 --- a/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp @@ -20,6 +20,8 @@ #include #include +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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h b/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h index 501f30ad2..beaeea64e 100644 --- a/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h +++ b/source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/EQ.cpp b/source/native-plugins/zynaddsubfx/Effects/EQ.cpp index 96bf13aeb..b65c030c3 100644 --- a/source/native-plugins/zynaddsubfx/Effects/EQ.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/EQ.cpp @@ -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; iPpreset); 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 } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Echo.h b/source/native-plugins/zynaddsubfx/Effects/Echo.h index be4420db8..a46f296e4 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Echo.h +++ b/source/native-plugins/zynaddsubfx/Effects/Echo.h @@ -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 ndelta; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Effects/Effect.cpp b/source/native-plugins/zynaddsubfx/Effects/Effect.cpp index 3fddf04c3..68e8e947d 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Effect.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Effect.cpp @@ -17,6 +17,8 @@ #include "../Params/FilterParams.h" #include +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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Effect.h b/source/native-plugins/zynaddsubfx/Effects/Effect.h index 1e28048df..ed2f6e77d 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Effect.h +++ b/source/native-plugins/zynaddsubfx/Effects/Effect.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/EffectLFO.cpp b/source/native-plugins/zynaddsubfx/Effects/EffectLFO.cpp index 4be73b81e..6d3048e70 100644 --- a/source/native-plugins/zynaddsubfx/Effects/EffectLFO.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/EffectLFO.cpp @@ -17,6 +17,8 @@ #include #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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/EffectLFO.h b/source/native-plugins/zynaddsubfx/Effects/EffectLFO.h index 108c818d8..76f4a249c 100644 --- a/source/native-plugins/zynaddsubfx/Effects/EffectLFO.h +++ b/source/native-plugins/zynaddsubfx/Effects/EffectLFO.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp b/source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp index 1e2148b2a..2b53c5575 100644 --- a/source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp @@ -16,7 +16,6 @@ #include #include - #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(o.efx)) \ + data.obj = dynamic_cast(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(); } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/EffectMgr.h b/source/native-plugins/zynaddsubfx/Effects/EffectMgr.h index 47081cfc7..5652af34c 100644 --- a/source/native-plugins/zynaddsubfx/Effects/EffectMgr.h +++ b/source/native-plugins/zynaddsubfx/Effects/EffectMgr.h @@ -16,14 +16,16 @@ #include +#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 diff --git a/source/native-plugins/zynaddsubfx/Effects/Phaser.cpp b/source/native-plugins/zynaddsubfx/Effects/Phaser.cpp index d0ef170bd..9ea38b1c4 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Phaser.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Phaser.cpp @@ -21,9 +21,10 @@ #include #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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Phaser.h b/source/native-plugins/zynaddsubfx/Effects/Phaser.h index b62078f27..5fcde26b9 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Phaser.h +++ b/source/native-plugins/zynaddsubfx/Effects/Phaser.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Effects/Reverb.cpp b/source/native-plugins/zynaddsubfx/Effects/Reverb.cpp index f1c5b8419..fb5d97beb 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Reverb.cpp +++ b/source/native-plugins/zynaddsubfx/Effects/Reverb.cpp @@ -20,6 +20,8 @@ #include #include +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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Effects/Reverb.h b/source/native-plugins/zynaddsubfx/Effects/Reverb.h index cd88c13e7..088c01f87 100644 --- a/source/native-plugins/zynaddsubfx/Effects/Reverb.h +++ b/source/native-plugins/zynaddsubfx/Effects/Reverb.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Misc/Allocator.cpp b/source/native-plugins/zynaddsubfx/Misc/Allocator.cpp index cb6ca9a9b..9544b5311 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Allocator.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Allocator.cpp @@ -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 */ + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Allocator.h b/source/native-plugins/zynaddsubfx/Misc/Allocator.h index 1c68e735b..e2d2a4fb8 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Allocator.h +++ b/source/native-plugins/zynaddsubfx/Misc/Allocator.h @@ -14,6 +14,8 @@ #include #include +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 */ + + } diff --git a/source/native-plugins/zynaddsubfx/Misc/Bank.cpp b/source/native-plugins/zynaddsubfx/Misc/Bank.cpp index bdacb5e64..512fee5bc 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Bank.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Bank.cpp @@ -30,15 +30,20 @@ #include "Util.h" #include "Part.h" #include "BankDb.h" +#ifdef WIN32 +#include +#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 Bank::search(std::string s) const } return out; } - + std::vector Bank::blist(std::string s) { std::vector out; @@ -544,3 +561,5 @@ void Bank::normalizedirsuffix(string &dirname) const { && ((dirname[dirname.size() - 1]) != '\\')) dirname += "/"; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Bank.h b/source/native-plugins/zynaddsubfx/Misc/Bank.h index 478899870..43f822f72 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Bank.h +++ b/source/native-plugins/zynaddsubfx/Misc/Bank.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Misc/BankDb.cpp b/source/native-plugins/zynaddsubfx/Misc/BankDb.cpp index 7d7b74819..a21ae0a2c 100644 --- a/source/native-plugins/zynaddsubfx/Misc/BankDb.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/BankDb.cpp @@ -6,7 +6,9 @@ #include #include -#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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/BankDb.h b/source/native-plugins/zynaddsubfx/Misc/BankDb.h index 60b2a3823..6408e4e95 100644 --- a/source/native-plugins/zynaddsubfx/Misc/BankDb.h +++ b/source/native-plugins/zynaddsubfx/Misc/BankDb.h @@ -3,6 +3,8 @@ #include #include +namespace zyncarla { + struct BankEntry { BankEntry(void); @@ -53,3 +55,5 @@ class BankDb bvec fields; svec banks; }; + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp b/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp index 60c077b8a..f8bff2eef 100644 --- a/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp @@ -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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h b/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h index 72bb43419..60de59d4e 100644 --- a/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h +++ b/source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h @@ -13,6 +13,8 @@ #include #include +namespace zyncarla { + struct CallbackRepeater { typedef std::function cb_t ; @@ -27,3 +29,5 @@ struct CallbackRepeater std::time_t dt; cb_t cb; }; + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Config.cpp b/source/native-plugins/zynaddsubfx/Misc/Config.cpp index 4510ae0f8..0fe47a474 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Config.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Config.cpp @@ -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; iaddparstr("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"); } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Config.h b/source/native-plugins/zynaddsubfx/Misc/Config.h index e4b5395ab..3c37a572c 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Config.h +++ b/source/native-plugins/zynaddsubfx/Misc/Config.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Misc/LASHClient.cpp b/source/native-plugins/zynaddsubfx/Misc/LASHClient.cpp index 43cfd500d..869200aeb 100644 --- a/source/native-plugins/zynaddsubfx/Misc/LASHClient.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/LASHClient.cpp @@ -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)); } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/LASHClient.h b/source/native-plugins/zynaddsubfx/Misc/LASHClient.h index 1a466a498..c432f6e96 100644 --- a/source/native-plugins/zynaddsubfx/Misc/LASHClient.h +++ b/source/native-plugins/zynaddsubfx/Misc/LASHClient.h @@ -17,6 +17,7 @@ #include #include +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 diff --git a/source/native-plugins/zynaddsubfx/Misc/Master.cpp b/source/native-plugins/zynaddsubfx/Misc/Master.cpp index d20027127..5955571d2 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Master.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Master.cpp @@ -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 #include #include +#include #include #include #include #include - #include 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; iPkeyshift); } 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(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; icfg.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 '%s:%s'\n", + fprintf(stderr, "Unknown address '%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(t)), + std::istreambuf_iterator()); + return str; +} + +int Master::loadOSC(const char *filename) +{ + int rval = loadOSCFromStr(loadfile(filename).c_str()); + return rval < 0 ? rval : 0; +} + + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Master.h b/source/native-plugins/zynaddsubfx/Misc/Master.h index 4f45e479e..e551e3a2a 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Master.h +++ b/source/native-plugins/zynaddsubfx/Misc/Master.h @@ -16,7 +16,7 @@ #define MASTER_H #include "../globals.h" #include "Microtonal.h" -#include +#include #include #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 diff --git a/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp b/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp index 3ce81dc07..82b8717fc 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp @@ -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 #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 getFiles(const char *folder, bool finddir) @@ -885,11 +838,12 @@ static std::vector 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; iparent; 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(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(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 read_only_fn) +void MiddleWareImpl::doReadOnlyOp(std::function read_only_fn) { assert(uToB); uToB->write("/freeze_state",""); @@ -1606,7 +1576,7 @@ void CarlaMiddleWareImpl::doReadOnlyOp(std::function 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 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 read_only_fn) +void MiddleWareImpl::doReadOnlyOpPlugin(std::function read_only_fn) { assert(uToB); int offline = 0; @@ -1710,7 +1680,7 @@ void CarlaMiddleWareImpl::doReadOnlyOpPlugin(std::function read_only_fn) } } -bool CarlaMiddleWareImpl::doReadOnlyOpNormal(std::function read_only_fn, bool canfail) +bool MiddleWareImpl::doReadOnlyOpNormal(std::function read_only_fn, bool canfail) { assert(uToB); uToB->write("/freeze_state",""); @@ -1719,7 +1689,7 @@ bool CarlaMiddleWareImpl::doReadOnlyOpNormal(std::function 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 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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/MiddleWare.h b/source/native-plugins/zynaddsubfx/Misc/MiddleWare.h index 9c5d5c5ee..bb623dd7b 100644 --- a/source/native-plugins/zynaddsubfx/Misc/MiddleWare.h +++ b/source/native-plugins/zynaddsubfx/Misc/MiddleWare.h @@ -14,6 +14,10 @@ #include #include +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; }; + +} + diff --git a/source/native-plugins/zynaddsubfx/Misc/Part.cpp b/source/native-plugins/zynaddsubfx/Misc/Part.cpp index a8098aaba..ed2e0a26b 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Part.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Part.cpp @@ -37,6 +37,8 @@ #include #include +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); } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Part.h b/source/native-plugins/zynaddsubfx/Misc/Part.h index fd538303e..507775428 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Part.h +++ b/source/native-plugins/zynaddsubfx/Misc/Part.h @@ -22,6 +22,8 @@ #include +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; /** #include #include -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()\n"); return true; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/PresetExtractor.h b/source/native-plugins/zynaddsubfx/Misc/PresetExtractor.h index 7753d1d8c..df5ef59fb 100644 --- a/source/native-plugins/zynaddsubfx/Misc/PresetExtractor.h +++ b/source/native-plugins/zynaddsubfx/Misc/PresetExtractor.h @@ -13,8 +13,11 @@ #include #include +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(); + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Recorder.cpp b/source/native-plugins/zynaddsubfx/Misc/Recorder.cpp index 1710ddb8e..6b3c37e8a 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Recorder.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Recorder.cpp @@ -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 +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Recorder.h b/source/native-plugins/zynaddsubfx/Misc/Recorder.h index b3a1711cc..91a2df095 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Recorder.h +++ b/source/native-plugins/zynaddsubfx/Misc/Recorder.h @@ -15,6 +15,8 @@ #define RECORDER_H #include +namespace zyncarla { + struct SYNTH_T; /**Records sound to a file*/ class Recorder @@ -43,4 +45,6 @@ class Recorder const SYNTH_T &synth; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Misc/Schema.cpp b/source/native-plugins/zynaddsubfx/Misc/Schema.cpp index 6b3df02e5..fed04fef4 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Schema.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Schema.cpp @@ -1,6 +1,40 @@ #include #include 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> 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 << "}"; } - +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Stereo.cpp b/source/native-plugins/zynaddsubfx/Misc/Stereo.cpp index b6b00b379..ca00b877b 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Stereo.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Stereo.cpp @@ -11,6 +11,8 @@ of the License, or (at your option) any later version. */ +namespace zyncarla { + template Stereo::Stereo(const T &left, const T &right) :l(left), r(right) @@ -28,3 +30,5 @@ Stereo &Stereo::operator=(const Stereo &nstr) r = nstr.r; return *this; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Stereo.h b/source/native-plugins/zynaddsubfx/Misc/Stereo.h index 3c1d58240..2fa2212ee 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Stereo.h +++ b/source/native-plugins/zynaddsubfx/Misc/Stereo.h @@ -13,6 +13,8 @@ #ifndef STEREO_H #define STEREO_H +namespace zyncarla { + template struct Stereo { public: @@ -28,5 +30,8 @@ struct Stereo { //data T l, r; }; + +} + #include "Stereo.cpp" #endif diff --git a/source/native-plugins/zynaddsubfx/Misc/Time.h b/source/native-plugins/zynaddsubfx/Misc/Time.h index fc228422b..d7cb99959 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Time.h +++ b/source/native-plugins/zynaddsubfx/Misc/Time.h @@ -13,6 +13,8 @@ #include #include "../globals.h" +namespace zyncarla { + class AbsTime { public: @@ -51,3 +53,5 @@ class RelTime int32_t sample; const AbsTime &t; }; + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Util.cpp b/source/native-plugins/zynaddsubfx/Misc/Util.cpp index c9145fcba..d3bc1d4ec 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Util.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/Util.cpp @@ -36,6 +36,8 @@ #include +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 + +//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 v) rtosc_amessage(buf, len, path, argT, arg); return buf; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/Util.h b/source/native-plugins/zynaddsubfx/Misc/Util.h index 2a27d9e17..d10c216cf 100644 --- a/source/native-plugins/zynaddsubfx/Misc/Util.h +++ b/source/native-plugins/zynaddsubfx/Misc/Util.h @@ -23,16 +23,17 @@ #include #include +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); #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 diff --git a/source/native-plugins/zynaddsubfx/Misc/WavFile.cpp b/source/native-plugins/zynaddsubfx/Misc/WavFile.cpp index e8f12c1ec..07f37b73b 100644 --- a/source/native-plugins/zynaddsubfx/Misc/WavFile.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/WavFile.cpp @@ -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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/WavFile.h b/source/native-plugins/zynaddsubfx/Misc/WavFile.h index b86ec1a23..863b91442 100644 --- a/source/native-plugins/zynaddsubfx/Misc/WavFile.h +++ b/source/native-plugins/zynaddsubfx/Misc/WavFile.h @@ -16,6 +16,8 @@ #define WAVFILE_H #include +namespace zyncarla { + class WavFile { public: @@ -33,4 +35,7 @@ class WavFile int channels; FILE *file; }; + +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.cpp b/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.cpp index 3272c1cd3..9b4b06de2 100644 --- a/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.cpp @@ -14,6 +14,8 @@ #include "WaveShapeSmps.h" #include +namespace zyncarla { + void waveShapeSmps(int n, float *smps, unsigned char type, @@ -178,3 +180,5 @@ void waveShapeSmps(int n, break; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.h b/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.h index 78daf51fe..624a6541d 100644 --- a/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.h +++ b/source/native-plugins/zynaddsubfx/Misc/WaveShapeSmps.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp index a15b8bbb9..31998d4cb 100644 --- a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp +++ b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp @@ -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(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(mxmlElementGetAttr(root, "version-major"))); + _fileversion.set_minor(stringTo(mxmlElementGetAttr(root, "version-minor"))); + _fileversion.set_revision( + stringTo(mxmlElementGetAttr(root, "version-revision"))); + return true; } @@ -677,3 +685,5 @@ std::vector XMLwrapper::getBranch(void) const } return res; } + +} diff --git a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h index 107adb1e7..1b589818e 100644 --- a/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h +++ b/source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp index 9b50b187a..99edaae91 100644 --- a/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp @@ -15,8 +15,6 @@ #include #include -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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h b/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h index f7ca43e9d..6c291f13d 100644 --- a/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/AudioOut.cpp b/source/native-plugins/zynaddsubfx/Nio/AudioOut.cpp index 865a5d545..1bc1592da 100644 --- a/source/native-plugins/zynaddsubfx/Nio/AudioOut.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/AudioOut.cpp @@ -15,12 +15,14 @@ #include #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 AudioOut::getNext() { return OutMgr::getInstance().tick(bufferSize); } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/AudioOut.h b/source/native-plugins/zynaddsubfx/Nio/AudioOut.h index 6f068eb31..d93fd7596 100644 --- a/source/native-plugins/zynaddsubfx/Nio/AudioOut.h +++ b/source/native-plugins/zynaddsubfx/Nio/AudioOut.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/Engine.cpp b/source/native-plugins/zynaddsubfx/Nio/Engine.cpp index 6b9582898..7869c63f3 100644 --- a/source/native-plugins/zynaddsubfx/Nio/Engine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/Engine.cpp @@ -12,8 +12,12 @@ */ #include "Engine.h" +namespace zyncarla { + Engine::Engine() {} Engine::~Engine() {} + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/Engine.h b/source/native-plugins/zynaddsubfx/Nio/Engine.h index 71b1d3118..0a972591b 100644 --- a/source/native-plugins/zynaddsubfx/Nio/Engine.h +++ b/source/native-plugins/zynaddsubfx/Nio/Engine.h @@ -14,6 +14,9 @@ #ifndef ENGINE_H #define ENGINE_H #include + +namespace zyncarla { + /**Marker for input/output driver*/ class Engine { @@ -29,4 +32,7 @@ class Engine std::string name; }; + +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/EngineMgr.cpp b/source/native-plugins/zynaddsubfx/Nio/EngineMgr.cpp index 9bbdd0f8e..40d689289 100644 --- a/source/native-plugins/zynaddsubfx/Nio/EngineMgr.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/EngineMgr.cpp @@ -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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/EngineMgr.h b/source/native-plugins/zynaddsubfx/Nio/EngineMgr.h index 2198ae8fe..41bb0d8da 100644 --- a/source/native-plugins/zynaddsubfx/Nio/EngineMgr.h +++ b/source/native-plugins/zynaddsubfx/Nio/EngineMgr.h @@ -16,6 +16,7 @@ #include #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 diff --git a/source/native-plugins/zynaddsubfx/Nio/InMgr.cpp b/source/native-plugins/zynaddsubfx/Nio/InMgr.cpp index 83b09dafb..16bd311c3 100644 --- a/source/native-plugins/zynaddsubfx/Nio/InMgr.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/InMgr.cpp @@ -17,10 +17,11 @@ #include "../Misc/MiddleWare.h" #include #include - 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_; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/InMgr.h b/source/native-plugins/zynaddsubfx/Nio/InMgr.h index b0360b09e..739b513f4 100644 --- a/source/native-plugins/zynaddsubfx/Nio/InMgr.h +++ b/source/native-plugins/zynaddsubfx/Nio/InMgr.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/JackEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/JackEngine.cpp index de76d49c0..406a47f17 100644 --- a/source/native-plugins/zynaddsubfx/Nio/JackEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/JackEngine.cpp @@ -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) } } } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/JackEngine.h b/source/native-plugins/zynaddsubfx/Nio/JackEngine.h index 26c605c15..a509329a9 100644 --- a/source/native-plugins/zynaddsubfx/Nio/JackEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/JackEngine.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp index 85ca9b7f3..685e19d03 100644 --- a/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp @@ -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; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.h b/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.h index 48c8cace3..bd6169fd1 100644 --- a/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/MidiIn.cpp b/source/native-plugins/zynaddsubfx/Nio/MidiIn.cpp index 3d99e77aa..8f802af6f 100644 --- a/source/native-plugins/zynaddsubfx/Nio/MidiIn.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/MidiIn.cpp @@ -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; } } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/MidiIn.h b/source/native-plugins/zynaddsubfx/Nio/MidiIn.h index f3fe6d26d..24fa6db55 100644 --- a/source/native-plugins/zynaddsubfx/Nio/MidiIn.h +++ b/source/native-plugins/zynaddsubfx/Nio/MidiIn.h @@ -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 diff --git a/source/native-plugins/zynaddsubfx/Nio/Nio.cpp b/source/native-plugins/zynaddsubfx/Nio/Nio.cpp index 1e26b6508..12cb3aee3 100644 --- a/source/native-plugins/zynaddsubfx/Nio/Nio.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/Nio.cpp @@ -20,6 +20,9 @@ #include #include #include + +namespace zyncarla { + using std::string; using std::set; using std::cerr; @@ -183,3 +186,5 @@ void Nio::waveEnd(void) { out->wave->destroyFile(); } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/Nio.h b/source/native-plugins/zynaddsubfx/Nio/Nio.h index c3ca495d8..d838e3e09 100644 --- a/source/native-plugins/zynaddsubfx/Nio/Nio.h +++ b/source/native-plugins/zynaddsubfx/Nio/Nio.h @@ -14,6 +14,8 @@ #include #include +namespace zyncarla { + class WavFile; class Master; struct SYNTH_T; @@ -61,4 +63,6 @@ namespace Nio extern std::string defaultSink; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/NulEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/NulEngine.cpp index 5e4d75e2e..b6f42be4c 100644 --- a/source/native-plugins/zynaddsubfx/Nio/NulEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/NulEngine.cpp @@ -13,12 +13,13 @@ #include "NulEngine.h" #include "../globals.h" +#include "../Misc/Util.h" -#include #include - using namespace std; +namespace zyncarla { + NulEngine::NulEngine(const SYNTH_T &synth_) :AudioOut(synth_), pThread(NULL) { @@ -49,7 +50,7 @@ void *NulEngine::AudioThread() + (playing_until.tv_sec - now.tv_sec) * 1000000; if(remaining > 10000) //Don't sleep() less than 10ms. //This will add latency... - usleep(remaining - 10000); + os_usleep(remaining - 10000); if(remaining < 0) cerr << "WARNING - too late" << endl; } @@ -102,3 +103,5 @@ bool NulEngine::getAudioEn() const { return pThread; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/NulEngine.h b/source/native-plugins/zynaddsubfx/Nio/NulEngine.h index 2e63ee142..1ae46a265 100644 --- a/source/native-plugins/zynaddsubfx/Nio/NulEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/NulEngine.h @@ -20,6 +20,8 @@ #include "AudioOut.h" #include "MidiIn.h" +namespace zyncarla { + class NulEngine:public AudioOut, MidiIn { public: @@ -44,4 +46,6 @@ class NulEngine:public AudioOut, MidiIn pthread_t *pThread; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp index 3e113c24f..a2b2fc268 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp @@ -34,6 +34,8 @@ using namespace std; +namespace zyncarla { + /* * The following statemachine converts MIDI commands to USB MIDI * packets, derived from Linux's usbmidi.c, which was written by @@ -471,3 +473,5 @@ done: pthread_exit(NULL); return NULL; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/OssEngine.h b/source/native-plugins/zynaddsubfx/Nio/OssEngine.h index b5be7cd65..6dafeb045 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OssEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/OssEngine.h @@ -19,6 +19,8 @@ #include "AudioOut.h" #include "MidiIn.h" +namespace zyncarla { + struct OssMidiParse { unsigned char *temp_cmd; unsigned char temp_0[4]; @@ -95,4 +97,6 @@ class OssEngine:public AudioOut, MidiIn const char* linux_oss_seq_in_dev; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp index d6229e662..5dd9046ec 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp @@ -31,10 +31,12 @@ #include "OssMultiEngine.h" #include "Compressor.h" -extern MiddleWare *middleware; - using namespace std; +extern zyncarla::MiddleWare *middleware; + +namespace zyncarla { + OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth, const oss_devs_t &oss_devs) :AudioOut(synth), @@ -265,3 +267,5 @@ done: pthread_exit(0); return (0); } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h b/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h index b77c99346..ce13e0f0e 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h @@ -17,6 +17,8 @@ #include "../globals.h" #include "AudioOut.h" +namespace zyncarla { + class OssMultiEngine : public AudioOut { public: @@ -61,4 +63,6 @@ class OssMultiEngine : public AudioOut const char* linux_oss_wave_out_dev; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/OutMgr.cpp b/source/native-plugins/zynaddsubfx/Nio/OutMgr.cpp index 0e34ef142..4874d6931 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OutMgr.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/OutMgr.cpp @@ -20,9 +20,10 @@ #include "WavEngine.h" #include "../Misc/Master.h" #include "../Misc/Util.h" //for set_realtime() - using namespace std; +namespace zyncarla { + OutMgr &OutMgr::getInstance(const SYNTH_T *synth) { static OutMgr instance(synth); @@ -199,3 +200,5 @@ void OutMgr::removeStaleSmps() stales = 0; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/OutMgr.h b/source/native-plugins/zynaddsubfx/Nio/OutMgr.h index 36b57051e..964aa931b 100644 --- a/source/native-plugins/zynaddsubfx/Nio/OutMgr.h +++ b/source/native-plugins/zynaddsubfx/Nio/OutMgr.h @@ -18,6 +18,7 @@ #include #include +namespace zyncarla { class AudioOut; struct SYNTH_T; @@ -78,4 +79,6 @@ class OutMgr const SYNTH_T &synth; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/PaEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/PaEngine.cpp index a46c302de..73989172c 100644 --- a/source/native-plugins/zynaddsubfx/Nio/PaEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/PaEngine.cpp @@ -13,9 +13,10 @@ #include "PaEngine.h" #include - using namespace std; +namespace zyncarla { + PaEngine::PaEngine(const SYNTH_T &synth) :AudioOut(synth), stream(NULL) { @@ -107,3 +108,5 @@ void PaEngine::Stop() stream = NULL; Pa_Terminate(); } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/PaEngine.h b/source/native-plugins/zynaddsubfx/Nio/PaEngine.h index e6b7ca279..df6e4c9b6 100644 --- a/source/native-plugins/zynaddsubfx/Nio/PaEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/PaEngine.h @@ -18,6 +18,8 @@ #include "../globals.h" #include "AudioOut.h" +namespace zyncarla { + class PaEngine:public AudioOut { public: @@ -42,7 +44,8 @@ class PaEngine:public AudioOut PaStream *stream; }; - void PAfinish(); +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/SafeQueue.cpp b/source/native-plugins/zynaddsubfx/Nio/SafeQueue.cpp index 5a16aff93..288066ee8 100644 --- a/source/native-plugins/zynaddsubfx/Nio/SafeQueue.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/SafeQueue.cpp @@ -10,6 +10,8 @@ of the License, or (at your option) any later version. */ +namespace zyncarla { + template SafeQueue::SafeQueue(size_t maxlen) :writePtr(0), readPtr(0), bufSize(maxlen) @@ -98,3 +100,5 @@ void SafeQueue::clear() w_space.post(); readPtr = writePtr; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/SafeQueue.h b/source/native-plugins/zynaddsubfx/Nio/SafeQueue.h index 4ec919c6d..741c4b1c6 100644 --- a/source/native-plugins/zynaddsubfx/Nio/SafeQueue.h +++ b/source/native-plugins/zynaddsubfx/Nio/SafeQueue.h @@ -16,6 +16,8 @@ #include "ZynSema.h" #include +namespace zyncarla { + /** * C++ thread safe lockless queue * Based off of jack's ringbuffer*/ @@ -55,5 +57,7 @@ class SafeQueue T *buffer; }; +} + #include "SafeQueue.cpp" #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp b/source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp index 42489cc5d..dc30c29db 100644 --- a/source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp +++ b/source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp @@ -17,9 +17,10 @@ #include #include "../Misc/WavFile.h" #include "../Misc/Util.h" - using namespace std; +namespace zyncarla { + WavEngine::WavEngine(const SYNTH_T &synth_) :AudioOut(synth_), file(NULL), buffer(synth.samplerate * 4), pThread(NULL) { @@ -127,3 +128,5 @@ void *WavEngine::AudioThread() return NULL; } + +} diff --git a/source/native-plugins/zynaddsubfx/Nio/WavEngine.h b/source/native-plugins/zynaddsubfx/Nio/WavEngine.h index ee0c50e44..dc272f50f 100644 --- a/source/native-plugins/zynaddsubfx/Nio/WavEngine.h +++ b/source/native-plugins/zynaddsubfx/Nio/WavEngine.h @@ -20,6 +20,8 @@ #include "ZynSema.h" #include "SafeQueue.h" +namespace zyncarla { + class WavFile; class WavEngine:public AudioOut { @@ -50,4 +52,6 @@ class WavEngine:public AudioOut pthread_t *pThread; }; + +} #endif diff --git a/source/native-plugins/zynaddsubfx/Nio/ZynSema.h b/source/native-plugins/zynaddsubfx/Nio/ZynSema.h index aeb5f851f..d365ce82a 100644 --- a/source/native-plugins/zynaddsubfx/Nio/ZynSema.h +++ b/source/native-plugins/zynaddsubfx/Nio/ZynSema.h @@ -16,6 +16,8 @@ #include +namespace zyncarla { + class ZynSema { public: @@ -77,10 +79,14 @@ private: pthread_cond_t _cond; }; +} + #else // POSIX sempahore #include +namespace zyncarla { + class ZynSema { public: @@ -118,6 +124,8 @@ private: sem_t _sema; }; +} + #endif // POSIX semapore #endif // ZYNSEMA_H diff --git a/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp b/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp index 6eb9efcbf..8944f4ace 100644 --- a/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp +++ b/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp @@ -27,6 +27,9 @@ #include #include + +namespace zyncarla { + using rtosc::Ports; using rtosc::RtData; @@ -67,19 +70,26 @@ static const Ports voicePorts = { rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"), rRecurp(VoiceFilter, "Optional Voice Filter"), - rToggle(Enabled, rShort("enable"), "Voice Enable"), - rParamZyn(Unison_size, rShort("size"), "Number of subvoices"), - rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), "Phase Randomness"), - rParamZyn(Unison_frequency_spread, rShort("detune"), "Subvoice detune"), - rParamZyn(Unison_stereo_spread, rShort("spread"), - "Subvoice L/R Separation"), - rParamZyn(Unison_vibratto, rShort("vib."), "Subvoice vibratto"), - rParamZyn(Unison_vibratto_speed, rShort("speed"), - "Subvoice vibratto speed"), +// rToggle(Enabled, rShort("enable"), "Voice Enable"), + rParamI(Unison_size, rShort("size"), rMap(min, 0), rMap(max, 50), + rDefault(1), "Number of subvoices"), + rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), rDefault(127), + "Phase Randomness"), + rParamZyn(Unison_frequency_spread, rShort("detune"), rDefault(60), + "Subvoice detune"), + rParamZyn(Unison_stereo_spread, rShort("spread"), rDefault(64), + "Subvoice L/R Separation"), + rParamZyn(Unison_vibratto, rShort("vib."), rDefault(64), + "Subvoice vibratto"), + rParamZyn(Unison_vibratto_speed, rShort("speed"), rDefault(64), + "Subvoice vibratto speed"), rOption(Unison_invert_phase, rShort("inv."), - rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"), - rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), "Type of Sound"), - rParamZyn(PDelay, rShort("delay"), "Voice Startup Delay"), + rOptions(none, random, 50%, 33%, 25%), rDefault(none), + "Subvoice Phases"), + rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), + rDefault(Sound), "Type of Sound"), + rParamZyn(PDelay, rShort("delay"), rDefault(0), + "Voice Startup Delay"), rToggle(Presonance, rShort("enable"), "Resonance Enable"), rParamI(Pextoscil, rShort("ext."), rMap(min, -1), rMap(max, 16), "External Oscillator Selection"), @@ -106,37 +116,56 @@ static const Ports voicePorts = { //Amplitude Stuff rParamZyn(PPanning, rShort("pan."), "Panning"), - rParamZyn(PVolume, rShort("vol."), "Volume"), - rToggle(PVolumeminus, rShort("inv."), "Signal Inverter"), //do we really need this?? - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Velocity Sensing"), - rToggle(PAmpEnvelopeEnabled, rShort("enable"), "Amplitude Envelope Enable"), - rToggle(PAmpLfoEnabled, rShort("enable"), "Amplitude LFO Enable"), + rParamZyn(PVolume, rShort("vol."), rDefault(100), + "Volume"), + rToggle(PVolumeminus, rShort("inv."), rDefault(false), + "Signal Inverter"), //do we really need this?? + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(127), + "Velocity Sensing"), + rToggle(PAmpEnvelopeEnabled, rShort("enable"), rDefault(false), + "Amplitude Envelope Enable"), + rToggle(PAmpLfoEnabled, rShort("enable"), rDefault(false), + "Amplitude LFO Enable"), //Filter Stuff - rToggle(PFilterEnabled, rShort("enable"), "Filter Enable"), - rToggle(PFilterEnvelopeEnabled, rShort("enable"), "Filter Envelope Enable"), - rToggle(PFilterLfoEnabled, rShort("enable"), "Filter LFO Enable"), - rParamZyn(PFilterVelocityScale, rShort("v.scale"), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), "Filter Velocity Function Shape"), + rToggle(PFilterEnabled, rShort("enable"), rDefault(false), + "Filter Enable"), + rToggle(PFilterEnvelopeEnabled, rShort("enable"), rDefault(false), + "Filter Envelope Enable"), + rToggle(PFilterLfoEnabled, rShort("enable"), rDefault(false), + "Filter LFO Enable"), + rParamZyn(PFilterVelocityScale, rShort("v.scale"), rDefault(0), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), rDefault(64), + "Filter Velocity Function Shape"), //Modulator Stuff rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase, - frequency, pulse), "Modulator mode"), - rParamI(PFMVoice, rShort("voice"), "Modulator Oscillator Selection"), - rParamZyn(PFMVolume, rShort("vol."), "Modulator Magnitude"), - rParamZyn(PFMVolumeDamp, rShort("damp."), "Modulator HF dampening"), - rParamZyn(PFMVelocityScaleFunction, rShort("sense"), "Modulator Velocity Function"), + frequency, pulse), rDefault(none), "Modulator mode"), + rParamI(PFMVoice, rShort("voice"), rDefault(-1), + "Modulator Oscillator Selection"), + rParamZyn(PFMVolume, rShort("vol."), rDefault(90), + "Modulator Magnitude"), + rParamZyn(PFMVolumeDamp, rShort("damp."), rDefault(64), + "Modulator HF dampening"), + rParamZyn(PFMVelocityScaleFunction, rShort("sense"), rDefault(64), + "Modulator Velocity Function"), //nominally -8192..8191 rParamI(PFMDetune, rShort("fine"), - rLinear(0, 16383), "Modulator Fine Detune"), - rParamI(PFMCoarseDetune, rShort("coarse"), "Modulator Coarse Detune"), + rLinear(0, 16383), rDefault(8192), "Modulator Fine Detune"), + rParamI(PFMCoarseDetune, rShort("coarse"), rDefault(0), + "Modulator Coarse Detune"), rParamZyn(PFMDetuneType, rShort("type"), - rOptions(L35cents, L10cents, E100cents, E1200cents), - "Modulator Detune Magnitude"), - rToggle(PFMFixedFreq, rShort("fixed"), "Modulator Frequency Fixed"), - rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), "Modulator Frequency Envelope"), - rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), "Modulator Amplitude Envelope"), + rOptions(L35cents, L10cents, E100cents, E1200cents), + rDefault(L35cents), + "Modulator Detune Magnitude"), + rToggle(PFMFixedFreq, rShort("fixed"), rDefault(false), + "Modulator Frequency Fixed"), + rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), rDefault(false), + "Modulator Frequency Envelope"), + rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), rDefault(false), + "Modulator Amplitude Envelope"), //weird stuff for PCoarseDetune @@ -247,36 +276,48 @@ static const Ports globalPorts = { rRecurp(FilterEnvelope, "Frequency Envelope"), rRecurp(GlobalFilter, "Filter"), - rToggle(PStereo, rShort("stereo"), "Mono/Stereo Enable"), + rToggle(PStereo, rShort("stereo"), rDefault(true), "Mono/Stereo Enable"), //Frequency //nominally -8192..8191 rParamI(PDetune, rShort("fine"), - rLinear(0, 16383), "Fine Detune"), - rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"), + rLinear(0, 16383), rDefault(8192), "Fine Detune"), + rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"), rParamZyn(PDetuneType, rShort("type"), - rOptions(L35cents, L10cents, E100cents, E1200cents), - "Detune Scaling Type"), - rParamZyn(PBandwidth, rShort("bw."), "Relative Fine Detune Gain"), + rOptions(L35cents, L10cents, E100cents, E1200cents), + rDefault(L10cents), + "Detune Scaling Type"), + rParamZyn(PBandwidth, rShort("bw."), rDefault(64), + "Relative Fine Detune Gain"), //Amplitude - rParamZyn(PPanning, rShort("pan"), "Panning of ADsynth (0 random, 1 left, 127 right)"), - rParamZyn(PVolume, rShort("vol"), "volume control"), - rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), "Volume Velocity Control"), - - rParamZyn(Fadein_adjustment, "Adjustment for anti-pop strategy."), - rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"), - rParamZyn(PPunchTime, rShort("time"), "Length of Punch"), - rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"), - rParamZyn(PPunchVelocitySensing, rShort("v.sns"), "Punch Velocity control"), + rParamZyn(PPanning, rShort("pan"), rDefault(64), + "Panning of ADsynth (0 random, 1 left, 127 right)"), + rParamZyn(PVolume, rShort("vol"), rDefault(90), "volume control"), + rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), rDefault(64), + "Volume Velocity Control"), + + rParamZyn(Fadein_adjustment, rDefault(FADEIN_ADJUSTMENT_SCALE), + "Adjustment for anti-pop strategy."), + rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), + "Punch Strength"), + rParamZyn(PPunchTime, rShort("time"), rDefault(60), + "Length of Punch"), + rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), + "How Punch changes with note frequency"), + rParamZyn(PPunchVelocitySensing, rShort("v.sns"), rDefault(72), + "Punch Velocity control"), //Filter - rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"), + rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //Resonance - rToggle(Hrandgrouping, "How randomness is applied to multiple voices using the same oscil"), + rToggle(Hrandgrouping, rDefault(false), + "How randomness is applied to multiple voices using the same oscil"), //weird stuff for PCoarseDetune {"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL, @@ -322,12 +363,15 @@ static const Ports globalPorts = { #undef rObject #define rObject ADnoteParameters -#define rChangeCb obj->last_update_timestamp = obj->time.time(); +#define rChangeCb obj->last_update_timestamp = obj->time->time(); static const Ports adPorts = {//XXX 16 should not be hard coded rSelf(ADnoteParameters), rPaste, rArrayPaste, rRecurs(VoicePar, NUM_VOICES), + {"VoicePar#" STRINGIFY(NUM_VOICES) "/Enabled::T:F", + rProp(parameter) rShort("enable") rDoc("Voice Enable"), + NULL, rArrayTCbMember(VoicePar, Enabled)}, rRecur(GlobalPar, "Adnote Parameters"), }; #undef rChangeCb @@ -356,16 +400,16 @@ ADnoteGlobalParam::ADnoteGlobalParam(const AbsTime *time_) : time(time_), last_update_timestamp(0) { FreqEnvelope = new EnvelopeParams(0, 0, time_); - FreqEnvelope->ASRinit(64, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_global_freq_env); FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_); GlobalFilter = new FilterParams(2, 94, 40, time_); FilterEnvelope = new EnvelopeParams(0, 1, time_); - FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + FilterEnvelope->init(EnvelopeParams::ad_global_filter_env); FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_); Reson = new Resonance(); } @@ -512,22 +556,22 @@ void ADnoteVoiceParam::enable(const SYNTH_T &synth, FFTwrapper *fft, FMSmp = new OscilGen(synth, fft, NULL); AmpEnvelope = new EnvelopeParams(64, 1, time); - AmpEnvelope->ADSRinit_dB(0, 100, 127, 100); + AmpEnvelope->init(EnvelopeParams::ad_voice_amp_env); AmpLfo = new LFOParams(90, 32, 64, 0, 0, 30, 0, 1, time); FreqEnvelope = new EnvelopeParams(0, 0, time); - FreqEnvelope->ASRinit(30, 40, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_voice_freq_env); FreqLfo = new LFOParams(50, 40, 0, 0, 0, 0, 0, 0, time); VoiceFilter = new FilterParams(2, 50, 60, time); FilterEnvelope = new EnvelopeParams(0, 0, time); - FilterEnvelope->ADSRinit_filter(90, 70, 40, 70, 10, 40); + FilterEnvelope->init(EnvelopeParams::ad_voice_filter_env); FilterLfo = new LFOParams(50, 20, 64, 0, 0, 0, 0, 2, time); FMFreqEnvelope = new EnvelopeParams(0, 0, time); - FMFreqEnvelope->ASRinit(20, 90, 40, 80); + FMFreqEnvelope->init(EnvelopeParams::ad_voice_fm_freq_env); FMAmpEnvelope = new EnvelopeParams(64, 1, time); - FMAmpEnvelope->ADSRinit(80, 90, 127, 100); + FMAmpEnvelope->init(EnvelopeParams::ad_voice_fm_amp_env); } /* @@ -1111,7 +1155,7 @@ void ADnoteVoiceParam::getfromXML(XMLwrapper& xml, unsigned nvoice) Unison_invert_phase = xml.getpar127("unison_invert_phase", Unison_invert_phase); Unison_phase_randomness = xml.getpar127("unison_phase_randomness", - Unison_phase_randomness); + Unison_phase_randomness); Type = xml.getpar127("type", Type); PDelay = xml.getpar127("delay", PDelay); @@ -1247,3 +1291,5 @@ void ADnoteVoiceParam::getfromXML(XMLwrapper& xml, unsigned nvoice) xml.exitbranch(); } } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h b/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h index f2acfdb59..b74f6b250 100644 --- a/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h +++ b/source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h @@ -17,6 +17,8 @@ #include "../globals.h" #include "PresetsArray.h" +namespace zyncarla { + enum FMTYPE { NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PW_MOD }; @@ -328,14 +330,16 @@ class ADnoteParameters:public PresetsArray void defaults(int n); //n is the nvoice void add2XMLsection(XMLwrapper& xml, int n); void getfromXMLsection(XMLwrapper& xml, int n); - private: + const AbsTime *time; + int64_t last_update_timestamp; + + private: void EnableVoice(const SYNTH_T &synth, int nvoice, const AbsTime* time); void KillVoice(int nvoice); FFTwrapper *fft; - - const AbsTime *time; - int64_t last_update_timestamp; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/Controller.cpp b/source/native-plugins/zynaddsubfx/Params/Controller.cpp index 40e1a0b4c..197da961a 100644 --- a/source/native-plugins/zynaddsubfx/Params/Controller.cpp +++ b/source/native-plugins/zynaddsubfx/Params/Controller.cpp @@ -22,38 +22,66 @@ #include using namespace rtosc; +namespace zyncarla { + #define rObject Controller #undef rChangeCb #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } const rtosc::Ports Controller::ports = { - rParamZyn(panning.depth, rShort("pan.d"), "Depth of Panning MIDI Control"), - rParamZyn(filtercutoff.depth, rShort("fc.d"), "Depth of Filter Cutoff MIDI Control"), - rParamZyn(filterq.depth, rShort("fq.d"), "Depth of Filter Q MIDI Control"), - rParamZyn(bandwidth.depth, rShort("bw.d"), "Depth of Bandwidth MIDI Control"), - rToggle(bandwidth.exponential, rShort("bw.exp"), "Bandwidth Exponential Mode"), - rParamZyn(modwheel.depth, rShort("mdw.d"), "Depth of Modwheel MIDI Control"), - rToggle(modwheel.exponential, rShort("mdw.exp"), "Modwheel Exponential Mode"), - rToggle(pitchwheel.is_split, "If PitchWheel Has unified bendrange or not"), - rParamI(pitchwheel.bendrange, rShort("pch.d"), "Range of MIDI Pitch Wheel"), - rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"), - rToggle(expression.receive, rShort("exp.rcv"), "Expression MIDI Receive"), - rToggle(fmamp.receive, rShort("fma.rcv"), "FM amplitude MIDI Receive"), - rToggle(volume.receive, rShort("vol.rcv"), "Volume MIDI Receive"), - rToggle(sustain.receive, rShort("sus.rcv"), "Sustain MIDI Receive"), - rToggle(portamento.receive, rShort("prt.rcv"), "Portamento MIDI Receive"), - rToggle(portamento.portamento, "Portamento Enable"), - rParamZyn(portamento.time, rShort("time"), "Portamento Length"), - rToggle(portamento.proportional, rShort("propt."), "Whether the portamento time is proportional" + rParamZyn(panning.depth, rShort("pan.d"), rDefault(64), + "Depth of Panning MIDI Control"), + rParamZyn(filtercutoff.depth, rShort("fc.d"), rDefault(64), + "Depth of Filter Cutoff MIDI Control"), + rParamZyn(filterq.depth, rShort("fq.d"), rDefault(64), + "Depth of Filter Q MIDI Control"), + rParamZyn(bandwidth.depth, rShort("bw.d"), rDefault(64), + "Depth of Bandwidth MIDI Control"), + rToggle(bandwidth.exponential, rShort("bw.exp"), rDefault(false), + "Bandwidth Exponential Mode"), + rParamZyn(modwheel.depth, rShort("mdw.d"), rDefault(80), + "Depth of Modwheel MIDI Control"), + rToggle(modwheel.exponential, rShort("mdw.exp"), rDefault(false), + "Modwheel Exponential Mode"), + rToggle(pitchwheel.is_split, rDefault(false), + "If PitchWheel Has unified bendrange or not"), + rParamI(pitchwheel.bendrange, rShort("pch.d"), rDefault(200), + rLinear(-6400, 6400), + "Range of MIDI Pitch Wheel"), + rParamI(pitchwheel.bendrange_down, rDefault(0), + "Lower Range of MIDI Pitch Wheel"), + rToggle(expression.receive, rShort("exp.rcv"), rDefault(true), + "Expression MIDI Receive"), + rToggle(fmamp.receive, rShort("fma.rcv"), rDefault(true), + "FM amplitude MIDI Receive"), + rToggle(volume.receive, rShort("vol.rcv"), rDefault(true), + "Volume MIDI Receive"), + rToggle(sustain.receive, rShort("sus.rcv"), rDefault(true), + "Sustain MIDI Receive"), + rToggle(portamento.receive, rShort("prt.rcv"), rDefault(true), + "Portamento MIDI Receive"), + rToggle(portamento.portamento, rDefault(false), + "Portamento Enable"), + rParamZyn(portamento.time, rShort("time"), rDefault(64), + "Portamento Length"), + rToggle(portamento.proportional, rShort("propt."), rDefault(false), + "Whether the portamento time is proportional" "to the size of the interval between two notes."), - rParamZyn(portamento.propRate, rShort("scale"), "Portamento proportional scale"), - rParamZyn(portamento.propDepth, rShort("depth"), "Portamento proportional depth"), - rParamZyn(portamento.pitchthresh, rShort("thresh"), "Threshold for portamento"), - rToggle(portamento.pitchthreshtype, rShort("tr.type"), "Type of threshold"), - rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), "Relative length of glide up vs glide down"), - rParamZyn(resonancecenter.depth, rShort("rfc.d"), "Resonance Center MIDI Depth"), - rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), "Resonance Bandwidth MIDI Depth"), - rToggle(NRPN.receive, "NRPN MIDI Enable"), + rParamZyn(portamento.propRate, rShort("scale"), rDefault(80), + "Portamento proportional scale"), + rParamZyn(portamento.propDepth, rShort("depth"), rDefault(90), + "Portamento proportional depth"), + rParamZyn(portamento.pitchthresh, rShort("thresh"), rDefault(3), + "Threshold for portamento"), + rToggle(portamento.pitchthreshtype, rShort("tr.type"), rDefault(true), + "Type of threshold"), + rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), rDefault(64), + "Relative length of glide up vs glide down"), + rParamZyn(resonancecenter.depth, rShort("rfc.d"), rDefault(64), + "Resonance Center MIDI Depth"), + rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), rDefault(64), + "Resonance Bandwidth MIDI Depth"), + rToggle(NRPN.receive, rDefault(true), "NRPN MIDI Enable"), rAction(defaults), }; #undef rChangeCb @@ -467,3 +495,5 @@ void Controller::getfromXML(XMLwrapper& xml) resonancebandwidth.depth = xml.getpar127("resonance_bandwidth_depth", resonancebandwidth.depth); } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/Controller.h b/source/native-plugins/zynaddsubfx/Params/Controller.h index 30ed2171c..f0a70f851 100644 --- a/source/native-plugins/zynaddsubfx/Params/Controller.h +++ b/source/native-plugins/zynaddsubfx/Params/Controller.h @@ -18,6 +18,8 @@ #include #include "../globals.h" +namespace zyncarla { + /**(Midi) Controllers implementation*/ class Controller { @@ -216,4 +218,6 @@ class Controller const SYNTH_T &synth; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp b/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp index daefe8824..ed07b4293 100644 --- a/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp +++ b/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp @@ -22,8 +22,11 @@ #include "../Misc/Util.h" #include "../Misc/Time.h" -#define rObject EnvelopeParams using namespace rtosc; + +namespace zyncarla { + +#define rObject EnvelopeParams #define rBegin [](const char *msg, RtData &d) { \ EnvelopeParams *env = (rObject*) d.obj #define rEnd } @@ -34,27 +37,54 @@ static const rtosc::Ports localPorts = { #undef rChangeCb #define rChangeCb if(!obj->Pfreemode) obj->converttofree(); if (obj->time) { \ obj->last_update_timestamp = obj->time->time(); } - rToggle(Pfreemode, "Complex Envelope Definitions"), + rToggle(Pfreemode, rDefault(false), "Complex Envelope Definitions"), #undef rChangeCb #define rChangeCb if(!obj->Pfreemode) obj->converttofree(); \ if(obj->time) { obj->last_update_timestamp = obj->time->time(); } - rParamZyn(Penvpoints, rProp(internal), "Number of points in complex definition"), - rParamZyn(Penvsustain, "Location of the sustain point"), + rOption(envelope_type, rProp(internal), + rOptions(ad_global_amp, ad_global_freq, ad_global_filter, + ad_voice_amp, ad_voice_freq, ad_voice_filter, + ad_voice_fm_freq, ad_voice_fm_amp, + sub_freq_env, sub_bandwidth_env), "function of the envelope"), + rParamZyn(Penvpoints, rProp(internal), rDefaultDepends(envelope_type), + rPresets(4, 3, 4, 4, 3, 4, 3, 4, 3, 3), + "Number of points in complex definition"), + rParamZyn(Penvsustain, rDefaultDepends(envelope_type), + rPresets(2, 1, 2, 2, 1, 2, 1, 2, 1, 1), + "Location of the sustain point"), rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"), rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"), - rParamZyn(Penvstretch, rShort("stretch"), + rParamZyn(Penvstretch, rShort("stretch"), rDefaultDepends(envelope_type), + rPresets(64, 0, 0, 64, 0, 0, 0, 64, 64, 64), "Stretch with respect to frequency"), - rToggle(Pforcedrelease, rShort("frcr"), + rToggle(Pforcedrelease, rShort("frcr"), rDefaultDepends(envelope_type), + rPresets(true, false, true, true, false, + false, false, true, false, false), "Force Envelope to fully evaluate"), - rToggle(Plinearenvelope, rShort("lin/log"), + rToggle(Plinearenvelope, rShort("lin/log"), rDefault(false), "Linear or Logarithmic Envelopes"), - rParamZyn(PA_dt, rShort("a.dt"), "Attack Time"), - rParamZyn(PA_val, rShort("a.val"), "Attack Value"), - rParamZyn(PD_dt, rShort("d.dt"), "Decay Time"), - rParamZyn(PD_val, rShort("d.val"), "Decay Value"), - rParamZyn(PS_val, rShort("s.val"), "Sustain Value"), - rParamZyn(PR_dt, rShort("r.dt"), "Release Time"), - rParamZyn(PR_val, rShort("r.val"), "Release Value"), + rParamZyn(PA_dt, rShort("a.dt"), rDefaultDepends(envelope_type), + rPresets(0, 50, 40, 0, 40, 70, 90, 80, 50, 70), + "Attack Time"), + rParamZyn(PA_val, rShort("a.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(4, 30, 90, 20, 64, 30, 100), + "Attack Value"), + rParamZyn(PD_dt, rShort("d.dt"), rDefaultDepends(envelope_type), + rDefault(10), rPresets(40, 10, 70, 100, 10, 70, 10, 90), + "Decay Time"), + rParamZyn(PD_val, rShort("d.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(5, 40), + "Decay Value"), + rParamZyn(PS_val, rShort("s.val"), rDefaultDepends(envelope_type), + rDefault(64), + rPresets(127), rPresetsAt(3, 127), rPresetsAt(7, 127), + "Sustain Value"), + rParamZyn(PR_dt, rShort("r.dt"), rDefaultDepends(envelope_type), + rPresets(25, 60, 60, 100, 60, 10, 80, 100, 60, 60), + "Release Time"), + rParamZyn(PR_val, rShort("r.val"), rDefaultDepends(envelope_type), + rDefault(64), rPresetsAt(5, 40, 40), + "Release Value"), {"Envmode:", rDoc("Envelope variant type"), NULL, rBegin; @@ -199,6 +229,26 @@ void EnvelopeParams::paste(const EnvelopeParams &ep) } #undef COPY +void EnvelopeParams::init(EnvelopeParams::envelope_type_t etype) +{ + switch(etype) + { + case ad_global_amp_env: ADSRinit_dB(0, 40, 127, 25); break; + case ad_global_freq_env: ASRinit(64, 50, 64, 60); break; + case ad_global_filter_env: ADSRinit_filter(64, 40, 64, 70, 60, 64); + break; + case ad_voice_amp_env: ADSRinit_dB(0, 100, 127, 100); break; + case ad_voice_freq_env: ASRinit(30, 40, 64, 60); break; + case ad_voice_filter_env: ADSRinit_filter(90, 70, 40, 70, 10, 40); + break; + case ad_voice_fm_freq_env: ASRinit(20, 90, 40, 80); break; + case ad_voice_fm_amp_env: ADSRinit(80, 90, 127, 100); break; + case sub_freq_env: ASRinit(30, 50, 64, 60); break; + case sub_bandwidth_env: ASRinit_bw(100, 70, 64, 60); break; + }; + envelope_type = etype; +} + float EnvelopeParams::getdt(char i) const { return EnvelopeParams::dt(Penvdt[(int)i]); @@ -301,16 +351,6 @@ void EnvelopeParams::converttofree() { switch(Envmode) { case 1: - Penvpoints = 4; - Penvsustain = 2; - Penvval[0] = 0; - Penvdt[1] = PA_dt; - Penvval[1] = 127; - Penvdt[2] = PD_dt; - Penvval[2] = PS_val; - Penvdt[3] = PR_dt; - Penvval[3] = 0; - break; case 2: Penvpoints = 4; Penvsustain = 2; @@ -323,6 +363,7 @@ void EnvelopeParams::converttofree() Penvval[3] = 0; break; case 3: + case 5: Penvpoints = 3; Penvsustain = 1; Penvval[0] = PA_val; @@ -342,15 +383,6 @@ void EnvelopeParams::converttofree() Penvdt[3] = PR_dt; Penvval[3] = PR_val; break; - case 5: - Penvpoints = 3; - Penvsustain = 1; - Penvval[0] = PA_val; - Penvdt[1] = PA_dt; - Penvval[1] = 64; - Penvdt[2] = PR_dt; - Penvval[2] = PR_val; - break; } } @@ -410,7 +442,7 @@ public: // f^{-1} o (env_dB2rap^{-1}) o dB2rap o f // from the xml file. This results in the following formula: ? roundf(127.0f * (0.5f * - log10f( 0.01f + 0.99f * + log10f( 0.01f + 0.99f * powf(100, input/127.0f - 1)) + 1)) : input; @@ -482,3 +514,5 @@ void EnvelopeParams::store2defaults() DS_val = PS_val; DR_val = PR_val; } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h b/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h index 41a08a937..3a8644634 100644 --- a/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h +++ b/source/native-plugins/zynaddsubfx/Params/EnvelopeParams.h @@ -18,24 +18,33 @@ #include "../Misc/XMLwrapper.h" #include "Presets.h" +namespace zyncarla { + class EnvelopeParams:public Presets { public: + enum envelope_type_t + { + ad_global_amp_env, // ADSRinit_dB(0, 40, 127, 25); + ad_global_freq_env, // ASRinit(64, 50, 64, 60); + ad_global_filter_env, // ADSRinit_filter(64, 40, 64, 70, 60, 64) + + ad_voice_amp_env, // ADSRinit_dB(0, 100, 127, 100); + ad_voice_freq_env, // ASRinit(30, 40, 64, 60); + ad_voice_filter_env, // ADSRinit_filter(90, 70, 40, 70, 10, 40); + ad_voice_fm_freq_env, // ASRinit(20, 90, 40, 80); + ad_voice_fm_amp_env, // ADSRinit(80, 90, 127, 100) + sub_freq_env, // ASRinit(30, 50, 64, 60); + sub_bandwidth_env, // ASRinit_bw(100, 70, 64, 60) + }; + EnvelopeParams(unsigned char Penvstretch_=64, unsigned char Pforcedrelease_=0, const AbsTime *time_ = nullptr); ~EnvelopeParams(); void paste(const EnvelopeParams &ep); - void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt); - void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt); - void ASRinit(char A_val, char A_dt, char R_val, char R_dt); - void ADSRinit_filter(char A_val, - char A_dt, - char D_val, - char D_dt, - char R_dt, - char R_val); - void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt); + + void init(envelope_type_t etype); void converttofree(); void add2XML(XMLwrapper& xml); @@ -46,6 +55,10 @@ class EnvelopeParams:public Presets static float dt(char val); static char inv_dt(float val); + //! @brief defines where it is used and its default settings + //! corresponds to envelope_type_t + int envelope_type; + /* MIDI Parameters */ unsigned char Pfreemode; //1 for free mode, 0 otherwise unsigned char Penvpoints; @@ -76,6 +89,17 @@ class EnvelopeParams:public Presets static float env_dB2rap(float db); private: + void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt); + void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt); + void ASRinit(char A_val, char A_dt, char R_val, char R_dt); + void ADSRinit_filter(char A_val, + char A_dt, + char D_val, + char D_dt, + char R_dt, + char R_val); + void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt); + void store2defaults(); /* Default parameters */ @@ -86,4 +110,6 @@ class EnvelopeParams:public Presets DA_val, DD_val, DS_val, DR_val; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp b/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp index 7a869f393..908e4ad53 100644 --- a/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp +++ b/source/native-plugins/zynaddsubfx/Params/FilterParams.cpp @@ -3,7 +3,9 @@ FilterParams.cpp - Parameters for filter Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2017 Mark McCurry Author: Nasca Octavian Paul + Mark McCurry This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,9 +25,10 @@ #include #include #include - using namespace rtosc; +namespace zyncarla { + // g++ 4.8 needs this variable saved separately, otherwise it segfaults constexpr int sizeof_pvowels = sizeof(FilterParams::Pvowels); @@ -65,14 +68,16 @@ const rtosc::Ports FilterParams::ports = { rOption(Ptype, rShort("type"), rOptions(LP1, HP1, LP2, HP2, BP, notch, peak, l.shelf, h.shelf), "Filter Type"), - rParamZyn(Pfreq, rShort("cutoff"), "Center Freq"), - rParamZyn(Pq, rShort("q"), - "Quality Factor (resonance/bandwidth)"), rParamI(Pstages, rShort("stages"), rLinear(0,5), "Filter Stages"), - rParamZyn(Pfreqtrack, rShort("f.track"), + rParamF(baseq, rShort("q"), rUnit(none), rLog(0.1, 1000), + "Quality Factor (resonance/bandwidth)"), + rParamF(basefreq, rShort("cutoff"), rUnit(Hz), rLog(31.25, 32000), + "Base cutoff frequency"), + rParamF(freqtracking, rShort("f.track"), rUnit(%), rLinear(-100, 100), "Frequency Tracking amount"), - rParamZyn(Pgain, rShort("gain"), "Output Gain"), + rParamF(gain, rShort("gain"), rUnit(dB), rLinear(-30, 30), + "Output Gain"), rParamI(Pnumformants, rShort("formants"), rLinear(1,12), "Number of formants to be used"), rParamZyn(Pformantslowness, rShort("slew"), @@ -96,8 +101,9 @@ const rtosc::Ports FilterParams::ports = { unsigned idx = atoi(mm); if(rtosc_narguments(msg)) { obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i; - } else d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel); + } else + d.reply(d.loc, "i", obj->Psequence[idx].nvowel); }}, {"type-svf::i", rProp(parameter) rShort("type") rOptions(low, high, band, notch) @@ -221,6 +227,65 @@ const rtosc::Ports FilterParams::ports = { } d.replyArray(d.loc, type, args); }}, + + //Old 0..127 parameter mappings + {"Pfreq::i", rLinear(0, 127) rShort("cutoff") rProp(deprecated) rDoc("Center Freq"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pfreq = rtosc_argument(msg, 0).i; + obj->basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + obj->basefreq = powf(2.0f, obj->basefreq + 9.96578428f); + rChangeCb; + d.broadcast(d.loc, "i", Pfreq); + } else { + float tmp = obj->basefreq; + tmp = log2f(tmp) - 9.96578428f; + tmp = (tmp / 5.0 + 1.0) * 64.0f; + int Pfreq = roundf(tmp); + d.reply(d.loc, "i", Pfreq); + } + }}, + {"Pfreqtrack::i", rLinear(0, 127) rShort("f.track") rProp(deprecated) rDoc("Frequency Tracking amount"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pfreqtracking = rtosc_argument(msg, 0).i; + obj->freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f); + rChangeCb; + d.broadcast(d.loc, "i", Pfreqtracking); + } else { + int Pfreqtracking = obj->freqtracking/100.0*64.0 + 64.0; + d.reply(d.loc, "i", Pfreqtracking); + } + }}, + {"Pgain::i", rLinear(0, 127) rShort("gain") rProp(deprecated) rDoc("Output Gain"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pgain = rtosc_argument(msg, 0).i; + obj->gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + rChangeCb; + d.broadcast(d.loc, "i", Pgain); + } else { + int Pgain = roundf((obj->gain/30.0f + 1.0f) * 64.0f); + d.reply(d.loc, "i", Pgain); + } + }}, + {"Pq::i", rLinear(0,127) rShort("q") rProp(deprecated) + rDoc("Quality Factor (resonance/bandwidth)"), 0, + [](const char *msg, RtData &d) { + FilterParams *obj = (FilterParams*)d.obj; + if(rtosc_narguments(msg)) { + int Pq = rtosc_argument(msg, 0).i; + obj->baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + rChangeCb; + d.broadcast(d.loc, "i", Pq); + } else { + int Pq = roundf(127.0f * sqrtf(logf(0.9f + obj->baseq)/logf(1000.0f))); + d.reply(d.loc, "i", Pq); + } + }}, }; #undef rChangeCb #define rChangeCb @@ -256,16 +321,21 @@ void FilterParams::defaults() Pfreq = Dfreq; Pq = Dq; - Pstages = 0; - Pfreqtrack = 64; - Pgain = 64; - Pcategory = 0; + Pstages = 0; + basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + basefreq = powf(2.0f, basefreq + 9.96578428f); + baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + + gain = 0.0f; + freqtracking = 0.0f; + + Pcategory = 0; Pnumformants = 3; Pformantslowness = 64; for(int j = 0; j < FF_MAX_VOWELS; ++j) defaults(j); - ; + Psequencesize = 3; for(int i = 0; i < FF_MAX_SEQUENCE; ++i) @@ -305,10 +375,10 @@ void FilterParams::getfromFilterParams(FilterParams *pars) Pfreq = pars->Pfreq; Pq = pars->Pq; - Pstages = pars->Pstages; - Pfreqtrack = pars->Pfreqtrack; - Pgain = pars->Pgain; - Pcategory = pars->Pcategory; + Pstages = pars->Pstages; + freqtracking = pars->freqtracking; + gain = pars->gain; + Pcategory = pars->Pcategory; Pnumformants = pars->Pnumformants; Pformantslowness = pars->Pformantslowness; @@ -336,21 +406,21 @@ void FilterParams::getfromFilterParams(FilterParams *pars) */ float FilterParams::getfreq() const { - return (Pfreq / 64.0f - 1.0f) * 5.0f; + return log2(basefreq) - log2f(1000.0f); } float FilterParams::getq() const { - return expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + return baseq; } float FilterParams::getfreqtracking(float notefreq) const { - return logf(notefreq / 440.0f) * (Pfreqtrack - 64.0f) / (64.0f * LOG_2); + return log2f(notefreq / 440.0f) * (freqtracking / 100.0); } float FilterParams::getgain() const { - return (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + return gain; } /* @@ -426,11 +496,11 @@ void FilterParams::add2XML(XMLwrapper& xml) //filter parameters xml.addpar("category", Pcategory); xml.addpar("type", Ptype); - xml.addpar("freq", Pfreq); - xml.addpar("q", Pq); + xml.addparreal("basefreq", basefreq); + xml.addparreal("baseq", baseq); xml.addpar("stages", Pstages); - xml.addpar("freq_track", Pfreqtrack); - xml.addpar("gain", Pgain); + xml.addparreal("freq_tracking", freqtracking); + xml.addparreal("gain", gain); //formant filter parameters if((Pcategory == 1) || (!xml.minimal)) { @@ -480,14 +550,28 @@ void FilterParams::getfromXMLsection(XMLwrapper& xml, int n) void FilterParams::getfromXML(XMLwrapper& xml) { + const bool upgrade_3_0_2 = (xml.fileversion() < version_type(3,0,2)) && (xml.getparreal("basefreq", -1) < 0); + //filter parameters - Pcategory = xml.getpar127("category", Pcategory); - Ptype = xml.getpar127("type", Ptype); - Pfreq = xml.getpar127("freq", Pfreq); - Pq = xml.getpar127("q", Pq); - Pstages = xml.getpar127("stages", Pstages); - Pfreqtrack = xml.getpar127("freq_track", Pfreqtrack); - Pgain = xml.getpar127("gain", Pgain); + Pcategory = xml.getpar127("category", Pcategory); + Ptype = xml.getpar127("type", Ptype); + Pstages = xml.getpar127("stages", Pstages); + if(upgrade_3_0_2) { + int Pfreq = xml.getpar127("freq", 0); + basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; + basefreq = powf(2.0f, basefreq + 9.96578428f); + int Pq = xml.getpar127("q", 0); + baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; + int Pgain = xml.getpar127("gain", 0); + gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB + int Pfreqtracking = xml.getpar127("freq_track", 0); + freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f); + } else { + basefreq = xml.getparreal("basefreq", 1000); + baseq = xml.getparreal("baseq", 10); + gain = xml.getparreal("gain", 0); + freqtracking = xml.getparreal("freq_tracking", 0); + } //formant filter parameters if(xml.enterbranch("FORMANT_FILTER")) { @@ -525,11 +609,11 @@ void FilterParams::paste(FilterParams &x) { COPY(Pcategory); COPY(Ptype); - COPY(Pfreq); + COPY(basefreq); COPY(Pq); COPY(Pstages); - COPY(Pfreqtrack); - COPY(Pgain); + COPY(freqtracking); + COPY(gain); COPY(Pnumformants); COPY(Pformantslowness); @@ -564,7 +648,6 @@ void FilterParams::paste(FilterParams &x) void FilterParams::pasteArray(FilterParams &x, int nvowel) { - printf("FilterParameters::pasting-an-array<%d>\n", nvowel); for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) { auto &self = Pvowels[nvowel].formants[nformant]; auto &update = x.Pvowels[nvowel].formants[nformant]; @@ -577,3 +660,5 @@ void FilterParams::pasteArray(FilterParams &x, int nvowel) last_update_timestamp = time->time(); } } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/FilterParams.h b/source/native-plugins/zynaddsubfx/Params/FilterParams.h index c108e59fd..356dea193 100644 --- a/source/native-plugins/zynaddsubfx/Params/FilterParams.h +++ b/source/native-plugins/zynaddsubfx/Params/FilterParams.h @@ -18,6 +18,8 @@ #include "../Misc/XMLwrapper.h" #include "PresetsArray.h" +namespace zyncarla { + class FilterParams:public PresetsArray { public: @@ -44,13 +46,18 @@ class FilterParams:public PresetsArray float getfreqtracking(float notefreq) const ; float getgain() const ; - unsigned char Pcategory; //Filter category (Analog/Formant/StVar) - unsigned char Ptype; // Filter type (for analog lpf,hpf,bpf..) - unsigned char Pfreq; // Frequency (64-central frequency) - unsigned char Pq; // Q parameters (resonance or bandwidth) - unsigned char Pstages; //filter stages+1 - unsigned char Pfreqtrack; //how the filter frequency is changing according the note frequency - unsigned char Pgain; //filter's output gain + unsigned Pcategory:2; //< Filter category (Analog/Formant/StVar) + unsigned Ptype:8; //< Filter type (for analog lpf,hpf,bpf..) + unsigned Pstages:8; //< filter stages+1 + float basefreq; //< Base cutoff frequency (Hz) + float baseq; //< Q parameters (resonance or bandwidth) + float freqtracking; //< Tracking of center frequency with note frequency (percentage) + float gain; //< filter's output gain (dB) + + int Pq; //dummy + int Pfreq; //dummy + int Pfreqtrack; //dummy + int Pgain; //dummy //Formant filter parameters unsigned char Pnumformants; //how many formants are used @@ -98,4 +105,6 @@ class FilterParams:public PresetsArray unsigned char Dq; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/LFOParams.cpp b/source/native-plugins/zynaddsubfx/Params/LFOParams.cpp index d52fd0984..37e830d64 100644 --- a/source/native-plugins/zynaddsubfx/Params/LFOParams.cpp +++ b/source/native-plugins/zynaddsubfx/Params/LFOParams.cpp @@ -23,6 +23,7 @@ #include using namespace rtosc; +namespace zyncarla { #define rObject LFOParams #undef rChangeCb @@ -41,13 +42,15 @@ static const rtosc::Ports _ports = { exp1, exp2), "Shape of LFO"), rParamZyn(Prandomness, rShort("a.r."), rSpecial(disable), "Amplitude Randomness (calculated uniformly at each cycle)"), - rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable), + rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable), rDefault(0), "Frequency Randomness (calculated uniformly at each cycle)"), rParamZyn(Pdelay, rShort("delay"), rSpecial(disable), "Delay before LFO start\n" "0..4 second delay"), rToggle(Pcontinous, rShort("c"), "Enable for global operation"), - rParamZyn(Pstretch, rShort("str"), rCentered, "Note frequency stretch"), - + rParamZyn(Pstretch, rShort("str"), rCentered, rDefault(64), + "Note frequency stretch"), +// these are currently not yet implemented at must be hidden therefore +#ifdef DEAD_PORTS //Float valued aliases {"delay::f", rProp(parameter) rMap(units, ms) rLog(0,4000), 0, rBegin; @@ -57,6 +60,7 @@ static const rtosc::Ports _ports = { {"period::f", rProp(parameter) rMap(units, ms) rPseudoLog(0.10, 1500.0), 0, rBegin; rEnd}, +#endif }; #undef rPseudoLog #undef rBegin @@ -173,3 +177,5 @@ void LFOParams::paste(LFOParams &x) } } #undef COPY + +} diff --git a/source/native-plugins/zynaddsubfx/Params/LFOParams.h b/source/native-plugins/zynaddsubfx/Params/LFOParams.h index e5bb0d427..f9e934266 100644 --- a/source/native-plugins/zynaddsubfx/Params/LFOParams.h +++ b/source/native-plugins/zynaddsubfx/Params/LFOParams.h @@ -18,8 +18,6 @@ #include #include "Presets.h" -class XMLwrapper; - #define LFO_SINE 0 #define LFO_TRIANGLE 1 #define LFO_SQUARE 2 @@ -29,6 +27,10 @@ class XMLwrapper; #define LFO_EXP_DOWN2 6 #define LFO_RANDOM 7 +namespace zyncarla { + +class XMLwrapper; + class LFOParams:public Presets { public: @@ -78,4 +80,6 @@ class LFOParams:public Presets unsigned char Dcontinous; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp b/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp index b0fae260e..cb9b3e389 100644 --- a/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp +++ b/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp @@ -25,6 +25,7 @@ #include using namespace rtosc; +namespace zyncarla { #define rObject PADnoteParameters #undef rChangeCb @@ -40,33 +41,46 @@ static const rtosc::Ports realtime_ports = rRecurp(GlobalFilter, "Post Filter"), //Volume - rToggle(PStereo, rShort("stereo"), "Stereo/Mono Mode"), - rParamZyn(PPanning, rShort("panning"), "Left Right Panning"), - rParamZyn(PVolume, rShort("vol"), "Synth Volume"), - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"), + rToggle(PStereo, rShort("stereo"), rDefault(true), "Stereo/Mono Mode"), + rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"), + rParamZyn(PVolume, rShort("vol"), rDefault(90), "Synth Volume"), + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(64), + "Amplitude Velocity Sensing function"), - rParamZyn(Fadein_adjustment, rShort("a.pop."), "Adjustment for anti-pop strategy."), + rParamZyn(Fadein_adjustment, rShort("a.pop."), + rDefault(FADEIN_ADJUSTMENT_SCALE), "Adjustment for anti-pop strategy."), //Punch - rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"), - rParamZyn(PPunchTime, rShort("time"), "Length of punch"), - rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"), - rParamZyn(PPunchVelocitySensing, rShort("sense"), "Punch Velocity control"), + rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), + "Punch Strength"), + rParamZyn(PPunchTime, rShort("time"), rDefault(60), + "Length of punch"), + rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), + "How Punch changes with note frequency"), + rParamZyn(PPunchVelocitySensing, rShort("sense"), rDefault(72), + "Punch Velocity control"), //Filter - rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"), + rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //Freq - rToggle(Pfixedfreq, rShort("fixed"), "Base frequency fixed frequency enable"), - rParamZyn(PfixedfreqET, rShort("f.ET"), "Equal temeperate control for fixed frequency operation"), - rParamZyn(PBendAdjust, "Pitch bend adjustment"), - rParamZyn(POffsetHz, rShort("offset"), "Voice constant offset"), - rParamI(PDetune, rShort("fine"), rLinear(0, 16383), "Fine Detune"), - rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"), + rToggle(Pfixedfreq, rShort("fixed"), rDefault(false), + "Base frequency fixed frequency enable"), + rParamZyn(PfixedfreqET, rShort("f.ET"), rDefault(0), + "Equal temeperate control for fixed frequency operation"), + rParamZyn(PBendAdjust, rDefault(88), + "Pitch bend adjustment"), + rParamZyn(POffsetHz, rShort("offset"), rDefault(64), + "Voice constant offset"), + rParamI(PDetune, rShort("fine"), rLinear(0, 16383), rDefault(8192), + "Fine Detune"), + rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"), rParamZyn(PDetuneType, rShort("type"), rOptions(L35cents, L10cents, E100cents, E1200cents), - "Magnitude of Detune"), + rDefault(L10cents), "Magnitude of Detune"), {"sample#64:ifb", rProp(internal) rDoc("Nothing to see here"), 0, [](const char *m, rtosc::RtData &d) @@ -141,58 +155,78 @@ static const rtosc::Ports non_realtime_ports = rRecurp(resonance, "Resonance"), //Harmonic Shape - rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), rOptions(bandwidth,discrete,continious), + rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), + rOptions(bandwidth,discrete,continious), + rDefault(bandwidth), "Harmonic Distribution Model"), - rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), rShort("shape"), + rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), + rShort("shape"), rDefault(Gaussian), "Harmonic profile shape"), - rParamZyn(Php.base.par1, rShort("warp"), "Harmonic shape distribution parameter"), - rParamZyn(Php.freqmult, rShort("clone"), "Frequency multiplier on distribution"), - rParamZyn(Php.modulator.par1, rShort("p1"), "Distribution modulator parameter"), - rParamZyn(Php.modulator.freq, rShort("freq"), "Frequency of modulator parameter"), - rParamZyn(Php.width, rShort("bandwidth"), "Width of base harmonic"), - rOption(Php.amp.mode, rShort("mode"), rOptions(Sum, Mult, Div1, Div2), + rParamZyn(Php.base.par1, rShort("warp"), rDefault(80), + "Harmonic shape distribution parameter"), + rParamZyn(Php.freqmult, rShort("clone"), rDefault(0), + "Frequency multiplier on distribution"), + rParamZyn(Php.modulator.par1, rShort("p1"), rDefault(0), + "Distribution modulator parameter"), + rParamZyn(Php.modulator.freq, rShort("freq"), rDefault(30), + "Frequency of modulator parameter"), + rParamZyn(Php.width, rShort("bandwidth"), rDefault(127), + "Width of base harmonic"), + rOption(Php.amp.mode, rShort("mode"), + rOptions(Sum, Mult, Div1, Div2), rDefault(Sum), "Amplitude harmonic multiplier type"), //Harmonic Modulation rOption(Php.amp.type, rShort("mult"), rOptions(Off, Gauss, Sine, Flat), - "Type of amplitude multipler"), - rParamZyn(Php.amp.par1, rShort("p1"), "Amplitude multiplier parameter"), - rParamZyn(Php.amp.par2, rShort("p2"), "Amplitude multiplier parameter"), - rToggle(Php.autoscale, rShort("auto"), "Autoscaling Harmonics"), + rDefault(Off), "Type of amplitude multipler"), + rParamZyn(Php.amp.par1, rShort("p1"), rDefault(80), + "Amplitude multiplier parameter"), + rParamZyn(Php.amp.par2, rShort("p2"), rDefault(60), + "Amplitude multiplier parameter"), + rToggle(Php.autoscale, rShort("auto"), rDefault(true), + "Autoscaling Harmonics"), rOption(Php.onehalf, rShort("side"), - rOptions(Full, Upper Half, Lower Half), + rOptions(Full, Upper Half, Lower Half), rDefault(Full) "Harmonic cutoff model"), //Harmonic Bandwidth rOption(Pbwscale, rShort("bw scale"), rOptions(Normal, - EqualHz, Quater, + EqualHz, Quarter, Half, 75%, 150%, Double, Inv. Half), + rDefault(Normal), "Bandwidth scaling"), //Harmonic Position Modulation rOption(Phrpos.type, rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, Power, Shift), + rDefault(Harmonic) "Harmonic Overtone shifting mode"), - rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), "Harmonic position parameter"), - rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), "Harmonic position parameter"), - rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), "Harmonic position parameter"), + rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), + rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), + rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), rDefault(0), + "Harmonic position parameter"), //Quality rOption(Pquality.samplesize, rShort("quality"), rOptions(16k (Tiny), 32k, 64k (Small), 128k, 256k (Normal), 512k, 1M (Big)), + rDefaultId(128k), "Size of each wavetable element"), rOption(Pquality.basenote, rShort("basenote"), rOptions(C-2, G-2, C-3, G-3, C-4, G-4, C-5, G-5, G-6,), + rDefaultId(C-4), "Base note for wavetable"), rOption(Pquality.smpoct, rShort("smp/oct"), rOptions(0.5, 1, 2, 3, 4, 6, 12), + rDefault(2), "Samples per octave"), - rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7), + rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7), rDefault(3), "Number of octaves to sample (above the first sample"), {"Pbandwidth::i", rShort("bandwidth") rProp(parameter) rLinear(0,1000) rDoc("Bandwith Of Harmonics"), NULL, @@ -253,8 +287,8 @@ static const rtosc::Ports non_realtime_ports = }; #undef rChangeCb -const rtosc::Ports &PADnoteParameters::non_realtime_ports = ::non_realtime_ports; -const rtosc::Ports &PADnoteParameters::realtime_ports = ::realtime_ports; +const rtosc::Ports &PADnoteParameters::non_realtime_ports = zyncarla::non_realtime_ports; +const rtosc::Ports &PADnoteParameters::realtime_ports = zyncarla::realtime_ports; const rtosc::MergePorts PADnoteParameters::ports = @@ -277,16 +311,16 @@ PADnoteParameters::PADnoteParameters(const SYNTH_T &synth_, FFTwrapper *fft_, oscilgen->ADvsPAD = true; FreqEnvelope = new EnvelopeParams(0, 0, time_); - FreqEnvelope->ASRinit(64, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_global_freq_env); FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_); GlobalFilter = new FilterParams(2, 94, 40, time_); FilterEnvelope = new EnvelopeParams(0, 1, time_); - FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + FilterEnvelope->init(EnvelopeParams::ad_global_filter_env); FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_); for(int i = 0; i < PAD_MAX_SAMPLES; ++i) @@ -848,6 +882,9 @@ void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb, if(samplemax == 0) samplemax = 1; + if(samplemax > PAD_MAX_SAMPLES) + samplemax = PAD_MAX_SAMPLES; + //prepare a BIG FFT FFTwrapper *fft = new FFTwrapper(samplesize); fft_t *fftfreqs = new fft_t[samplesize / 2]; @@ -1241,3 +1278,5 @@ void PADnoteParameters::pasteRT(PADnoteParameters &x) } } #undef COPY + +} diff --git a/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h b/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h index f27bee2b4..c307de5ff 100644 --- a/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h +++ b/source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h @@ -20,6 +20,8 @@ #include #include +namespace zyncarla { + /** * Parameters for PAD synthesis * @@ -190,6 +192,6 @@ class PADnoteParameters:public Presets const SYNTH_T &synth; }; - +} #endif diff --git a/source/native-plugins/zynaddsubfx/Params/Presets.cpp b/source/native-plugins/zynaddsubfx/Params/Presets.cpp index 06ed5fda5..04a8b7911 100644 --- a/source/native-plugins/zynaddsubfx/Params/Presets.cpp +++ b/source/native-plugins/zynaddsubfx/Params/Presets.cpp @@ -16,6 +16,7 @@ #include "PresetsStore.h" #include +namespace zyncarla { Presets::Presets() { @@ -95,3 +96,5 @@ void Presets::deletepreset(PresetsStore &ps, int npreset) { ps.deletepreset(npreset); } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/Presets.h b/source/native-plugins/zynaddsubfx/Params/Presets.h index d3014c667..8cc11a4e2 100644 --- a/source/native-plugins/zynaddsubfx/Params/Presets.h +++ b/source/native-plugins/zynaddsubfx/Params/Presets.h @@ -15,6 +15,9 @@ #define PRESETS_H #include "../globals.h" + +namespace zyncarla { + class PresetsStore; /**Presets and Clipboard management*/ @@ -40,4 +43,6 @@ class Presets //virtual void defaults() = 0; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/PresetsArray.cpp b/source/native-plugins/zynaddsubfx/Params/PresetsArray.cpp index 846d4f1b8..258b1d8f2 100644 --- a/source/native-plugins/zynaddsubfx/Params/PresetsArray.cpp +++ b/source/native-plugins/zynaddsubfx/Params/PresetsArray.cpp @@ -15,6 +15,7 @@ #include "PresetsArray.h" #include +namespace zyncarla { PresetsArray::PresetsArray() { @@ -126,3 +127,5 @@ bool PresetsArray::checkclipboardtype(PresetsStore &ps) // // presetsstore.rescanforpresets(type); //} + +} diff --git a/source/native-plugins/zynaddsubfx/Params/PresetsArray.h b/source/native-plugins/zynaddsubfx/Params/PresetsArray.h index 76d4821a5..069500c05 100644 --- a/source/native-plugins/zynaddsubfx/Params/PresetsArray.h +++ b/source/native-plugins/zynaddsubfx/Params/PresetsArray.h @@ -18,6 +18,8 @@ #include "Presets.h" +namespace zyncarla { + /**PresetsArray and Clipboard management*/ class PresetsArray:public Presets { @@ -39,4 +41,6 @@ class PresetsArray:public Presets //virtual void defaults(int n) = 0; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/PresetsStore.cpp b/source/native-plugins/zynaddsubfx/Params/PresetsStore.cpp index e390f56b6..aa3f09ec0 100644 --- a/source/native-plugins/zynaddsubfx/Params/PresetsStore.cpp +++ b/source/native-plugins/zynaddsubfx/Params/PresetsStore.cpp @@ -25,10 +25,12 @@ using namespace std; +namespace zyncarla { + //XXX to remove //PresetsStore presetsstore; -PresetsStore::PresetsStore(const CarlaConfig& config) : config(config) +PresetsStore::PresetsStore(const Config& config) : config(config) { } @@ -181,3 +183,5 @@ void PresetsStore::deletepreset(std::string filename) } } } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/PresetsStore.h b/source/native-plugins/zynaddsubfx/Params/PresetsStore.h index 6a2e73d20..a6a57266a 100644 --- a/source/native-plugins/zynaddsubfx/Params/PresetsStore.h +++ b/source/native-plugins/zynaddsubfx/Params/PresetsStore.h @@ -17,12 +17,14 @@ #include #include +namespace zyncarla { + class XMLwrapper; class PresetsStore { - const class CarlaConfig& config; + const class Config& config; public: - PresetsStore(const class CarlaConfig &config); + PresetsStore(const class Config &config); ~PresetsStore(); //Clipboard stuff @@ -55,4 +57,7 @@ class PresetsStore }; //extern PresetsStore presetsstore; + +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp b/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp index 9fc4ba1cd..38995b8d5 100644 --- a/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp +++ b/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp @@ -22,10 +22,11 @@ #include #include - -#define rObject SUBnoteParameters using namespace rtosc; +namespace zyncarla { + +#define rObject SUBnoteParameters #define rBegin [](const char *msg, RtData &d) { \ SUBnoteParameters *obj = (SUBnoteParameters*) d.obj #define rEnd } @@ -36,52 +37,74 @@ using namespace rtosc; static const rtosc::Ports SUBnotePorts = { rSelf(SUBnoteParameters), rPaste, - rToggle(Pstereo, rShort("stereo"), "Stereo Enable"), - rParamZyn(PVolume, rShort("volume"), "Volume"), - rParamZyn(PPanning, rShort("panning"), "Left Right Panning"), - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"), - rParamI(PDetune, rShort("detune"), rLinear(0, 16383), "Detune in detune type units"), - rParamI(PCoarseDetune, rShort("cdetune"), "Coarse Detune"), + rToggle(Pstereo, rShort("stereo"), rDefault(true), "Stereo Enable"), + rParamZyn(PVolume, rShort("volume"), rDefault(96), "Volume"), + rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"), + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(90), + "Amplitude Velocity Sensing function"), + rParamI(PDetune, rShort("detune"), rLinear(0, 16383), rDefault(8192), + "Detune in detune type units"), + rParamI(PCoarseDetune, rShort("cdetune"), rDefault(0), "Coarse Detune"), //Real values needed rOption(PDetuneType, rShort("det. scl."), - rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), "Detune Scale"), - rToggle(PFreqEnvelopeEnabled, rShort("enable"), "Enable for Frequency Envelope"), - rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), "Enable for Bandwidth Envelope"), - rToggle(PGlobalFilterEnabled, rShort("enable"), "Enable for Global Filter"), - rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"), - rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"), + rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), + rDefaultId(L10 cents), "Detune Scale"), + rToggle(PFreqEnvelopeEnabled, rShort("enable"), rDefault(false), + "Enable for Frequency Envelope"), + rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), rDefault(false), + "Enable for Bandwidth Envelope"), + rToggle(PGlobalFilterEnabled, rShort("enable"), + rDefault(false), "Enable for Global Filter"), + rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //rRecur(FreqEnvelope, EnvelopeParams), //rToggle(),//continue - rToggle(Pfixedfreq, rShort("fixed freq"), "Base frequency fixed frequency enable"), - rParamZyn(PfixedfreqET, rShort("fixed ET"), "Equal temeperate control for fixed frequency operation"), - rParamZyn(PBendAdjust, rShort("bend"), "Pitch bend adjustment"), - rParamZyn(POffsetHz, rShort("+ Hz"), "Voice constant offset"), + rToggle(Pfixedfreq, rShort("fixed freq"), rDefault(false), + "Base frequency fixed frequency enable"), + rParamZyn(PfixedfreqET, rShort("fixed ET"), rDefault(0), + "Equal temeperate control for fixed frequency operation"), + rParamZyn(PBendAdjust, rShort("bend"), rDefault(88), + "Pitch bend adjustment"), + rParamZyn(POffsetHz, rShort("+ Hz"), rDefault(64), + "Voice constant offset"), #undef rChangeCb #define rChangeCb obj->updateFrequencyMultipliers(); if (obj->time) { \ obj->last_update_timestamp = obj->time->time(); } rParamI(POvertoneSpread.type, rMap(min, 0), rMap(max, 7), rShort("spread type") rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, Power, Shift), + rDefault(Harmonic) "Spread of harmonic frequencies"), rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), rShort("p1"), - "Overtone Parameter"), + rDefault(0), "Overtone Parameter"), rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"), - "Overtone Parameter"), + rDefault(0), "Overtone Parameter"), rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("forceH"), - "Force Overtones To Harmonics"), + rDefault(0), "Force Overtones To Harmonics"), #undef rChangeCb #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } - rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), "Number of filter stages"), - rParamZyn(Pbandwidth, rShort("bandwidth"), "Bandwidth of filters"), - rParamZyn(Phmagtype, rShort("mag. type"), rOptions(linear, -40dB, -60dB, -80dB, -100dB), "Magnitude scale"), - rArray(Phmag, MAX_SUB_HARMONICS, "Harmonic magnitudes"), - rArray(Phrelbw, MAX_SUB_HARMONICS, "Relative bandwidth"), - rParamZyn(Pbwscale, rShort("stretch"), "Bandwidth scaling with frequency"), + rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), + rDefault(2), "Number of filter stages"), + rParamZyn(Pbandwidth, rShort("bandwidth"), rDefault(40), + "Bandwidth of filters"), + rParamZyn(Phmagtype, rShort("mag. type"), + rOptions(linear, -40dB, -60dB, -80dB, -100dB), + rDefault(linear), "Magnitude scale"), + rArray(Phmag, MAX_SUB_HARMONICS, rDefaultMissing, + "Harmonic magnitudes"), + rArray(Phrelbw, MAX_SUB_HARMONICS, rDefaultMissing, + "Relative bandwidth"), + rParamZyn(Pbwscale, rShort("stretch"), rDefault(64), + "Bandwidth scaling with frequency"), rRecurp(AmpEnvelope, "Amplitude envelope"), rRecurp(FreqEnvelope, "Frequency Envelope"), rRecurp(BandWidthEnvelope, "Bandwidth Envelope"), rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"), rRecurp(GlobalFilter, "Post Filter"), - rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), "How harmonics are initialized"), + rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), + rDefault(random), + "How harmonics are initialized"), {"clear:", rDoc("Reset all harmonics to equal bandwidth/zero amplitude"), NULL, rBegin; @@ -178,15 +201,15 @@ SUBnoteParameters::SUBnoteParameters(const AbsTime *time_) { setpresettype("Psubsynth"); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); FreqEnvelope = new EnvelopeParams(64, 0, time_); - FreqEnvelope->ASRinit(30, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::sub_freq_env); BandWidthEnvelope = new EnvelopeParams(64, 0, time_); - BandWidthEnvelope->ASRinit_bw(100, 70, 64, 60); + BandWidthEnvelope->init(EnvelopeParams::sub_bandwidth_env); GlobalFilter = new FilterParams(2, 80, 40, time_); GlobalFilterEnvelope = new EnvelopeParams(0, 1, time_); - GlobalFilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + GlobalFilterEnvelope->init(EnvelopeParams::ad_global_filter_env); defaults(); } @@ -590,3 +613,5 @@ void SUBnoteParameters::getfromXML(XMLwrapper& xml) xml.exitbranch(); } } + +} diff --git a/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h b/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h index b5385765c..63e994e0c 100644 --- a/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h +++ b/source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h @@ -18,6 +18,8 @@ #include "../globals.h" #include "Presets.h" +namespace zyncarla { + class SUBnoteParameters:public Presets { public: @@ -112,4 +114,6 @@ class SUBnoteParameters:public Presets static const rtosc::Ports &ports; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp b/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp index a6e5e7927..da5494c83 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/ADnote.cpp @@ -27,6 +27,8 @@ #include "OscilGen.h" #include "ADnote.h" +namespace zyncarla { + ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars, WatchManager *wm, const char *prefix) :SynthNote(spars), pars(*pars_) @@ -76,384 +78,397 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars, NoteGlobalPar.Punch.Enabled = 0; for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - for (int i = 0; i < 14; i++) - pinking[nvoice][i] = 0.0; + setupVoice(nvoice); + } - pars.VoicePar[nvoice].OscilSmp->newrandseed(prng()); - NoteVoicePar[nvoice].OscilSmp = NULL; - NoteVoicePar[nvoice].FMSmp = NULL; - NoteVoicePar[nvoice].VoiceOut = NULL; + max_unison = 1; + for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) + if(unison_size[nvoice] > max_unison) + max_unison = unison_size[nvoice]; - NoteVoicePar[nvoice].FMVoice = -1; - unison_size[nvoice] = 1; - if(!pars.VoicePar[nvoice].Enabled) { - NoteVoicePar[nvoice].Enabled = OFF; - continue; //the voice is disabled - } + tmpwave_unison = memory.valloc(max_unison); + for(int k = 0; k < max_unison; ++k) { + tmpwave_unison[k] = memory.valloc(synth.buffersize); + memset(tmpwave_unison[k], 0, synth.bufferbytes); + } - int BendAdj = pars.VoicePar[nvoice].PBendAdjust - 64; - if (BendAdj % 24 == 0) - NoteVoicePar[nvoice].BendAdjust = BendAdj / 24; - else - NoteVoicePar[nvoice].BendAdjust = BendAdj / 24.0f; - - float offset_val = (pars.VoicePar[nvoice].POffsetHz - 64)/64.0f; - NoteVoicePar[nvoice].OffsetHz = - 15.0f*(offset_val * sqrtf(fabsf(offset_val))); - - unison_stereo_spread[nvoice] = - pars.VoicePar[nvoice].Unison_stereo_spread / 127.0f; - - int unison = pars.VoicePar[nvoice].Unison_size; - if(unison < 1) - unison = 1; - - bool is_pwm = pars.VoicePar[nvoice].PFMEnabled == PW_MOD; - - if (pars.VoicePar[nvoice].Type != 0) { - // Since noise unison of greater than two is touch goofy... - if (unison > 2) - unison = 2; - } else if (is_pwm) { - /* Pulse width mod uses pairs of subvoices. */ - unison *= 2; - // This many is likely to sound like noise anyhow. - if (unison > 64) - unison = 64; - } + initparameters(wm, prefix); + memory.endTransaction(); +} - //compute unison - unison_size[nvoice] = unison; +void ADnote::setupVoice(int nvoice) +{ + auto ¶m = pars.VoicePar[nvoice]; + auto &voice = NoteVoicePar[nvoice]; - unison_base_freq_rap[nvoice] = memory.valloc(unison); - unison_freq_rap[nvoice] = memory.valloc(unison); - unison_invert_phase[nvoice] = memory.valloc(unison); - float unison_spread = - pars.getUnisonFrequencySpreadCents(nvoice); - float unison_real_spread = powf(2.0f, (unison_spread * 0.5f) / 1200.0f); - float unison_vibratto_a = - pars.VoicePar[nvoice].Unison_vibratto / 127.0f; //0.0f .. 1.0f - int true_unison = unison / (is_pwm ? 2 : 1); - switch(true_unison) { - case 1: - unison_base_freq_rap[nvoice][0] = 1.0f; //if the unison is not used, always make the only subvoice to have the default note - break; - case 2: { //unison for 2 subvoices - unison_base_freq_rap[nvoice][0] = 1.0f / unison_real_spread; - unison_base_freq_rap[nvoice][1] = unison_real_spread; - }; + for (int i = 0; i < 14; i++) + pinking[nvoice][i] = 0.0; + + param.OscilSmp->newrandseed(prng()); + voice.OscilSmp = NULL; + voice.FMSmp = NULL; + voice.VoiceOut = NULL; + + voice.FMVoice = -1; + unison_size[nvoice] = 1; + + if(!pars.VoicePar[nvoice].Enabled) { + voice.Enabled = OFF; + return; //the voice is disabled + } + + const int BendAdj = pars.VoicePar[nvoice].PBendAdjust - 64; + if (BendAdj % 24 == 0) + voice.BendAdjust = BendAdj / 24; + else + voice.BendAdjust = BendAdj / 24.0f; + + const float offset_val = (param.POffsetHz - 64)/64.0f; + voice.OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val))); + + unison_stereo_spread[nvoice] = + pars.VoicePar[nvoice].Unison_stereo_spread / 127.0f; + + int unison = setupVoiceUnison(nvoice); + + + oscfreqhi[nvoice] = memory.valloc(unison); + oscfreqlo[nvoice] = memory.valloc(unison); + oscfreqhiFM[nvoice] = memory.valloc(unison); + oscfreqloFM[nvoice] = memory.valloc(unison); + oscposhi[nvoice] = memory.valloc(unison); + oscposlo[nvoice] = memory.valloc(unison); + oscposhiFM[nvoice] = memory.valloc(unison); + oscposloFM[nvoice] = memory.valloc(unison); + + voice.Enabled = ON; + voice.fixedfreq = pars.VoicePar[nvoice].Pfixedfreq; + voice.fixedfreqET = pars.VoicePar[nvoice].PfixedfreqET; + + setupVoiceDetune(nvoice); + + for(int k = 0; k < unison; ++k) { + oscposhi[nvoice][k] = 0; + oscposlo[nvoice][k] = 0.0f; + oscposhiFM[nvoice][k] = 0; + oscposloFM[nvoice][k] = 0.0f; + } + + //the extra points contains the first point + voice.OscilSmp = + memory.valloc(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES); + + //Get the voice's oscil or external's voice oscil + int vc = nvoice; + if(pars.VoicePar[nvoice].Pextoscil != -1) + vc = pars.VoicePar[nvoice].Pextoscil; + if(!pars.GlobalPar.Hrandgrouping) + pars.VoicePar[vc].OscilSmp->newrandseed(prng()); + int oscposhi_start = + pars.VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp, + getvoicebasefreq(nvoice), + pars.VoicePar[nvoice].Presonance); + + // This code was planned for biasing the carrier in MOD_RING + // but that's on hold for the moment. Disabled 'cos small + // machines run this stuff too. + // + // //Find range of generated wave + // float min = NoteVoicePar[nvoice].OscilSmp[0]; + // float max = min; + // float *smpls = &(NoteVoicePar[nvoice].OscilSmp[1]); + // for (int i = synth.oscilsize-1; i--; smpls++) + // if (*smpls > max) + // max = *smpls; + // else if (*smpls < min) + // min = *smpls; + // NoteVoicePar[nvoice].OscilSmpMin = min; + // NoteVoicePar[nvoice].OscilSmpMax = max; + + //I store the first elments to the last position for speedups + for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) + voice.OscilSmp[synth.oscilsize + i] = voice.OscilSmp[i]; + + voice.phase_offset = (int)((pars.VoicePar[nvoice].Poscilphase + - 64.0f) / 128.0f * synth.oscilsize + synth.oscilsize * 4); + oscposhi_start += NoteVoicePar[nvoice].phase_offset; + + int kth_start = oscposhi_start; + for(int k = 0; k < unison; ++k) { + oscposhi[nvoice][k] = kth_start % synth.oscilsize; + //put random starting point for other subvoices + kth_start = oscposhi_start + + (int)(RND * pars.VoicePar[nvoice].Unison_phase_randomness / + 127.0f * (synth.oscilsize - 1)); + } + + voice.FreqLfo = NULL; + voice.FreqEnvelope = NULL; + + voice.AmpLfo = NULL; + voice.AmpEnvelope = NULL; + + voice.Filter = NULL; + voice.FilterEnvelope = NULL; + voice.FilterLfo = NULL; + + voice.filterbypass = param.Pfilterbypass; + + setupVoiceMod(nvoice); + + voice.FMVoice = param.PFMVoice; + voice.FMFreqEnvelope = NULL; + voice.FMAmpEnvelope = NULL; + + FMoldsmp[nvoice] = memory.valloc(unison); + for(int k = 0; k < unison; ++k) + FMoldsmp[nvoice][k] = 0.0f; //this is for FM (integration) + + firsttick[nvoice] = 1; + voice.DelayTicks = + (int)((expf(param.PDelay / 127.0f * logf(50.0f)) + - 1.0f) / synth.buffersize_f / 10.0f * synth.samplerate_f); +} + +int ADnote::setupVoiceUnison(int nvoice) +{ + int unison = pars.VoicePar[nvoice].Unison_size; + if(unison < 1) + unison = 1; + + bool is_pwm = pars.VoicePar[nvoice].PFMEnabled == PW_MOD; + + if (pars.VoicePar[nvoice].Type != 0) { + // Since noise unison of greater than two is touch goofy... + if (unison > 2) + unison = 2; + } else if (is_pwm) { + /* Pulse width mod uses pairs of subvoices. */ + unison *= 2; + // This many is likely to sound like noise anyhow. + if (unison > 64) + unison = 64; + } + + //compute unison + unison_size[nvoice] = unison; + + unison_base_freq_rap[nvoice] = memory.valloc(unison); + unison_freq_rap[nvoice] = memory.valloc(unison); + unison_invert_phase[nvoice] = memory.valloc(unison); + const float unison_spread = + pars.getUnisonFrequencySpreadCents(nvoice); + const float unison_real_spread = powf(2.0f, (unison_spread * 0.5f) / 1200.0f); + const float unison_vibratto_a = + pars.VoicePar[nvoice].Unison_vibratto / 127.0f; //0.0f .. 1.0f + + const int true_unison = unison / (is_pwm ? 2 : 1); + switch(true_unison) { + case 1: + unison_base_freq_rap[nvoice][0] = 1.0f; //if the unison is not used, always make the only subvoice to have the default note + break; + case 2: { //unison for 2 subvoices + unison_base_freq_rap[nvoice][0] = 1.0f / unison_real_spread; + unison_base_freq_rap[nvoice][1] = unison_real_spread; + }; break; - default: { //unison for more than 2 subvoices - float unison_values[true_unison]; - float min = -1e-6, max = 1e-6; - for(int k = 0; k < true_unison; ++k) { - float step = (k / (float) (true_unison - 1)) * 2.0f - 1.0f; //this makes the unison spread more uniform - float val = step + (RND * 2.0f - 1.0f) / (true_unison - 1); - unison_values[k] = val; - if (min > val) { - min = val; - } - if (max < val) { - max = val; - } - } - float diff = max - min; - for(int k = 0; k < true_unison; ++k) { - unison_values[k] = - (unison_values[k] - (max + min) * 0.5f) / diff; //the lowest value will be -1 and the highest will be 1 - unison_base_freq_rap[nvoice][k] = - powf(2.0f, (unison_spread * unison_values[k]) / 1200); - } - }; + default: { //unison for more than 2 subvoices + float unison_values[true_unison]; + float min = -1e-6, max = 1e-6; + for(int k = 0; k < true_unison; ++k) { + float step = (k / (float) (true_unison - 1)) * 2.0f - 1.0f; //this makes the unison spread more uniform + float val = step + (RND * 2.0f - 1.0f) / (true_unison - 1); + unison_values[k] = val; + if (min > val) { + min = val; + } + if (max < val) { + max = val; + } + } + const float diff = max - min; + for(int k = 0; k < true_unison; ++k) { + unison_values[k] = + (unison_values[k] - (max + min) * 0.5f) / diff; //the lowest value will be -1 and the highest will be 1 + unison_base_freq_rap[nvoice][k] = + powf(2.0f, (unison_spread * unison_values[k]) / 1200); + } + }; + } + if (is_pwm) + for (int i = true_unison - 1; i >= 0; i--) { + unison_base_freq_rap[nvoice][2*i + 1] = + unison_base_freq_rap[nvoice][i]; + unison_base_freq_rap[nvoice][2*i] = + unison_base_freq_rap[nvoice][i]; } + + //unison vibrattos + if(unison > 2 || (!is_pwm && unison > 1)) + for(int k = 0; k < unison; ++k) //reduce the frequency difference for larger vibrattos + unison_base_freq_rap[nvoice][k] = 1.0f + + (unison_base_freq_rap[ + nvoice][k] - 1.0f) + * (1.0f - unison_vibratto_a); + unison_vibratto[nvoice].step = memory.valloc(unison); + unison_vibratto[nvoice].position = memory.valloc(unison); + unison_vibratto[nvoice].amplitude = + (unison_real_spread - 1.0f) * unison_vibratto_a; + + const float increments_per_second = synth.samplerate_f / synth.buffersize_f; + const float vib_speed = pars.VoicePar[nvoice].Unison_vibratto_speed / 127.0f; + const float vibratto_base_period = 0.25f * powf(2.0f, (1.0f - vib_speed) * 4.0f); + for(int k = 0; k < unison; ++k) { + unison_vibratto[nvoice].position[k] = RND * 1.8f - 0.9f; + //make period to vary randomly from 50% to 200% vibratto base period + const float vibratto_period = vibratto_base_period + * powf(2.0f, RND * 2.0f - 1.0f); + + const float m = (RND < 0.5f ? -1.0f : 1.0f) * + 4.0f / (vibratto_period * increments_per_second); + unison_vibratto[nvoice].step[k] = m; + + // Ugly, but the alternative is likely uglier. if (is_pwm) - for (int i = true_unison - 1; i >= 0; i--) { - unison_base_freq_rap[nvoice][2*i + 1] = - unison_base_freq_rap[nvoice][i]; - unison_base_freq_rap[nvoice][2*i] = - unison_base_freq_rap[nvoice][i]; + for (int i = 0; i < unison; i += 2) { + unison_vibratto[nvoice].step[i+1] = + unison_vibratto[nvoice].step[i]; + unison_vibratto[nvoice].position[i+1] = + unison_vibratto[nvoice].position[i]; } + } - //unison vibrattos - if(unison > 2 || (!is_pwm && unison > 1)) - for(int k = 0; k < unison; ++k) //reduce the frequency difference for larger vibrattos - unison_base_freq_rap[nvoice][k] = 1.0f - + (unison_base_freq_rap[ - nvoice][k] - 1.0f) - * (1.0f - unison_vibratto_a); - unison_vibratto[nvoice].step = memory.valloc(unison); - unison_vibratto[nvoice].position = memory.valloc(unison); - unison_vibratto[nvoice].amplitude = - (unison_real_spread - 1.0f) * unison_vibratto_a; - - float increments_per_second = synth.samplerate_f / synth.buffersize_f; - const float vib_speed = pars.VoicePar[nvoice].Unison_vibratto_speed / 127.0f; - float vibratto_base_period = 0.25f * powf(2.0f, (1.0f - vib_speed) * 4.0f); - for(int k = 0; k < unison; ++k) { - unison_vibratto[nvoice].position[k] = RND * 1.8f - 0.9f; - //make period to vary randomly from 50% to 200% vibratto base period - float vibratto_period = vibratto_base_period - * powf(2.0f, RND * 2.0f - 1.0f); - - float m = 4.0f / (vibratto_period * increments_per_second); - if(RND < 0.5f) - m = -m; - unison_vibratto[nvoice].step[k] = m; - - // Ugly, but the alternative is likely uglier. - if (is_pwm) - for (int i = 0; i < unison; i += 2) { - unison_vibratto[nvoice].step[i+1] = - unison_vibratto[nvoice].step[i]; - unison_vibratto[nvoice].position[i+1] = - unison_vibratto[nvoice].position[i]; - } + if(unison <= 2) { //no vibratto for a single voice + if (is_pwm) { + unison_vibratto[nvoice].step[1] = 0.0f; + unison_vibratto[nvoice].position[1] = 0.0f; } - - if(unison <= 2) { //no vibratto for a single voice - if (is_pwm) { - unison_vibratto[nvoice].step[1] = 0.0f; - unison_vibratto[nvoice].position[1] = 0.0f; - } - if (is_pwm || unison == 1) { - unison_vibratto[nvoice].step[0] = 0.0f; - unison_vibratto[nvoice].position[0] = 0.0f; - unison_vibratto[nvoice].amplitude = 0.0f; - } + if (is_pwm || unison == 1) { + unison_vibratto[nvoice].step[0] = 0.0f; + unison_vibratto[nvoice].position[0] = 0.0f; + unison_vibratto[nvoice].amplitude = 0.0f; } + } - //phase invert for unison - unison_invert_phase[nvoice][0] = false; - if(unison != 1) { - int inv = pars.VoicePar[nvoice].Unison_invert_phase; - switch(inv) { - case 0: for(int k = 0; k < unison; ++k) - unison_invert_phase[nvoice][k] = false; - break; - case 1: for(int k = 0; k < unison; ++k) - unison_invert_phase[nvoice][k] = (RND > 0.5f); - break; - default: for(int k = 0; k < unison; ++k) - unison_invert_phase[nvoice][k] = - (k % inv == 0) ? true : false; - break; - } + //phase invert for unison + unison_invert_phase[nvoice][0] = false; + if(unison != 1) { + int inv = pars.VoicePar[nvoice].Unison_invert_phase; + switch(inv) { + case 0: + for(int k = 0; k < unison; ++k) + unison_invert_phase[nvoice][k] = false; + break; + case 1: + for(int k = 0; k < unison; ++k) + unison_invert_phase[nvoice][k] = (RND > 0.5f); + break; + default: + for(int k = 0; k < unison; ++k) + unison_invert_phase[nvoice][k] = + (k % inv == 0) ? true : false; + break; } + } + return unison; +} - - oscfreqhi[nvoice] = memory.valloc(unison); - oscfreqlo[nvoice] = memory.valloc(unison); - oscfreqhiFM[nvoice] = memory.valloc(unison); - oscfreqloFM[nvoice] = memory.valloc(unison); - oscposhi[nvoice] = memory.valloc(unison); - oscposlo[nvoice] = memory.valloc(unison); - oscposhiFM[nvoice] = memory.valloc(unison); - oscposloFM[nvoice] = memory.valloc(unison); - - NoteVoicePar[nvoice].Enabled = ON; - NoteVoicePar[nvoice].fixedfreq = pars.VoicePar[nvoice].Pfixedfreq; - NoteVoicePar[nvoice].fixedfreqET = pars.VoicePar[nvoice].PfixedfreqET; - - //use the Globalpars.detunetype if the detunetype is 0 - if(pars.VoicePar[nvoice].PDetuneType != 0) { - NoteVoicePar[nvoice].Detune = getdetune( +void ADnote::setupVoiceDetune(int nvoice) +{ + //use the Globalpars.detunetype if the detunetype is 0 + if(pars.VoicePar[nvoice].PDetuneType != 0) { + NoteVoicePar[nvoice].Detune = getdetune( pars.VoicePar[nvoice].PDetuneType, pars.VoicePar[nvoice]. PCoarseDetune, 8192); //coarse detune - NoteVoicePar[nvoice].FineDetune = getdetune( + NoteVoicePar[nvoice].FineDetune = getdetune( pars.VoicePar[nvoice].PDetuneType, 0, pars.VoicePar[nvoice].PDetune); //fine detune - } - else { - NoteVoicePar[nvoice].Detune = getdetune( + } + else { + NoteVoicePar[nvoice].Detune = getdetune( pars.GlobalPar.PDetuneType, pars.VoicePar[nvoice]. PCoarseDetune, 8192); //coarse detune - NoteVoicePar[nvoice].FineDetune = getdetune( + NoteVoicePar[nvoice].FineDetune = getdetune( pars.GlobalPar.PDetuneType, 0, pars.VoicePar[nvoice].PDetune); //fine detune - } - if(pars.VoicePar[nvoice].PFMDetuneType != 0) - NoteVoicePar[nvoice].FMDetune = getdetune( + } + if(pars.VoicePar[nvoice].PFMDetuneType != 0) + NoteVoicePar[nvoice].FMDetune = getdetune( pars.VoicePar[nvoice].PFMDetuneType, pars.VoicePar[nvoice]. PFMCoarseDetune, pars.VoicePar[nvoice].PFMDetune); - else - NoteVoicePar[nvoice].FMDetune = getdetune( + else + NoteVoicePar[nvoice].FMDetune = getdetune( pars.GlobalPar.PDetuneType, pars.VoicePar[nvoice]. PFMCoarseDetune, pars.VoicePar[nvoice].PFMDetune); +} - - - for(int k = 0; k < unison; ++k) { - oscposhi[nvoice][k] = 0; - oscposlo[nvoice][k] = 0.0f; - oscposhiFM[nvoice][k] = 0; - oscposloFM[nvoice][k] = 0.0f; - } - - //the extra points contains the first point - NoteVoicePar[nvoice].OscilSmp = - memory.valloc(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES); - - //Get the voice's oscil or external's voice oscil - int vc = nvoice; - if(pars.VoicePar[nvoice].Pextoscil != -1) - vc = pars.VoicePar[nvoice].Pextoscil; - if(!pars.GlobalPar.Hrandgrouping) - pars.VoicePar[vc].OscilSmp->newrandseed(prng()); - int oscposhi_start = - pars.VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp, - getvoicebasefreq(nvoice), - pars.VoicePar[nvoice].Presonance); - - // This code was planned for biasing the carrier in MOD_RING - // but that's on hold for the moment. Disabled 'cos small - // machines run this stuff too. - // - // //Find range of generated wave - // float min = NoteVoicePar[nvoice].OscilSmp[0]; - // float max = min; - // float *smpls = &(NoteVoicePar[nvoice].OscilSmp[1]); - // for (int i = synth.oscilsize-1; i--; smpls++) - // if (*smpls > max) - // max = *smpls; - // else if (*smpls < min) - // min = *smpls; - // NoteVoicePar[nvoice].OscilSmpMin = min; - // NoteVoicePar[nvoice].OscilSmpMax = max; - - //I store the first elments to the last position for speedups - for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) - NoteVoicePar[nvoice].OscilSmp[synth.oscilsize - + i] = - NoteVoicePar[nvoice].OscilSmp[i]; - - NoteVoicePar[nvoice].phase_offset = - (int)((pars.VoicePar[nvoice].Poscilphase - - 64.0f) / 128.0f * synth.oscilsize - + synth.oscilsize * 4); - oscposhi_start += NoteVoicePar[nvoice].phase_offset; - - int kth_start = oscposhi_start; - for(int k = 0; k < unison; ++k) { - oscposhi[nvoice][k] = kth_start % synth.oscilsize; - //put random starting point for other subvoices - kth_start = oscposhi_start + - (int)(RND * pars.VoicePar[nvoice].Unison_phase_randomness / - 127.0f * (synth.oscilsize - 1)); - } - - NoteVoicePar[nvoice].FreqLfo = NULL; - NoteVoicePar[nvoice].FreqEnvelope = NULL; - - NoteVoicePar[nvoice].AmpLfo = NULL; - NoteVoicePar[nvoice].AmpEnvelope = NULL; - - NoteVoicePar[nvoice].Filter = NULL; - NoteVoicePar[nvoice].FilterEnvelope = NULL; - NoteVoicePar[nvoice].FilterLfo = NULL; - - NoteVoicePar[nvoice].filterbypass = - pars.VoicePar[nvoice].Pfilterbypass; - - if (pars.VoicePar[nvoice].Type != 0) - NoteVoicePar[nvoice].FMEnabled = NONE; - else - switch(pars.VoicePar[nvoice].PFMEnabled) { - case 1: - NoteVoicePar[nvoice].FMEnabled = MORPH; - break; - case 2: - NoteVoicePar[nvoice].FMEnabled = RING_MOD; - break; - case 3: - NoteVoicePar[nvoice].FMEnabled = PHASE_MOD; - break; - case 4: - NoteVoicePar[nvoice].FMEnabled = FREQ_MOD; - break; - case 5: - NoteVoicePar[nvoice].FMEnabled = PW_MOD; - break; - default: - NoteVoicePar[nvoice].FMEnabled = NONE; - } - - NoteVoicePar[nvoice].FMVoice = pars.VoicePar[nvoice].PFMVoice; - NoteVoicePar[nvoice].FMFreqEnvelope = NULL; - NoteVoicePar[nvoice].FMAmpEnvelope = NULL; - NoteVoicePar[nvoice].FMFreqFixed = pars.VoicePar[nvoice].PFMFixedFreq; - - - //Compute the Voice's modulator volume (incl. damping) - float fmvoldamp = powf(440.0f / getvoicebasefreq( - nvoice), - pars.VoicePar[nvoice].PFMVolumeDamp / 64.0f - - 1.0f); - switch(NoteVoicePar[nvoice].FMEnabled) { - case PHASE_MOD: - case PW_MOD: - fmvoldamp = - powf(440.0f / getvoicebasefreq( - nvoice), pars.VoicePar[nvoice].PFMVolumeDamp - / 64.0f); - NoteVoicePar[nvoice].FMVolume = - (expf(pars.VoicePar[nvoice].PFMVolume / 127.0f - * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f; +void ADnote::setupVoiceMod(int nvoice) +{ + auto ¶m = pars.VoicePar[nvoice]; + auto &voice = NoteVoicePar[nvoice]; + if (param.Type != 0) + voice.FMEnabled = NONE; + else + switch(param.PFMEnabled) { + case 1: + voice.FMEnabled = MORPH; break; - case FREQ_MOD: - NoteVoicePar[nvoice].FMVolume = - (expf(pars.VoicePar[nvoice].PFMVolume / 127.0f - * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f; + case 2: + voice.FMEnabled = RING_MOD; + break; + case 3: + voice.FMEnabled = PHASE_MOD; + break; + case 4: + voice.FMEnabled = FREQ_MOD; + break; + case 5: + voice.FMEnabled = PW_MOD; break; default: - if(fmvoldamp > 1.0f) - fmvoldamp = 1.0f; - NoteVoicePar[nvoice].FMVolume = - pars.VoicePar[nvoice].PFMVolume - / 127.0f * fmvoldamp; + voice.FMEnabled = NONE; } - //Voice's modulator velocity sensing - NoteVoicePar[nvoice].FMVolume *= - VelF(velocity, - pars.VoicePar[nvoice].PFMVelocityScaleFunction); - - FMoldsmp[nvoice] = memory.valloc(unison); - for(int k = 0; k < unison; ++k) - FMoldsmp[nvoice][k] = 0.0f; //this is for FM (integration) - - firsttick[nvoice] = 1; - NoteVoicePar[nvoice].DelayTicks = - (int)((expf(pars.VoicePar[nvoice].PDelay / 127.0f - * logf(50.0f)) - - 1.0f) / synth.buffersize_f / 10.0f * synth.samplerate_f); - } - - max_unison = 1; - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) - if(unison_size[nvoice] > max_unison) - max_unison = unison_size[nvoice]; - - - tmpwave_unison = memory.valloc(max_unison); - for(int k = 0; k < max_unison; ++k) { - tmpwave_unison[k] = memory.valloc(synth.buffersize); - memset(tmpwave_unison[k], 0, synth.bufferbytes); + voice.FMFreqFixed = param.PFMFixedFreq; + + + //Compute the Voice's modulator volume (incl. damping) + float fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice), + param.PFMVolumeDamp / 64.0f - 1.0f); + const float fmvolume_ = param.PFMVolume / 127.0f; + switch(voice.FMEnabled) { + case PHASE_MOD: + case PW_MOD: + fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice), + param.PFMVolumeDamp / 64.0f); + voice.FMVolume = (expf(fmvolume_ * FM_AMP_MULTIPLIER) - 1.0f) + * fmvoldamp * 4.0f; + break; + case FREQ_MOD: + voice.FMVolume = (expf(fmvolume_ * FM_AMP_MULTIPLIER) - 1.0f) + * fmvoldamp * 4.0f; + break; + default: + if(fmvoldamp > 1.0f) + fmvoldamp = 1.0f; + voice.FMVolume = fmvolume_ * fmvoldamp; } - initparameters(wm, prefix); - memory.endTransaction(); + //Voice's modulator velocity sensing + NoteVoicePar[nvoice].FMVolume *= + VelF(velocity, pars.VoicePar[nvoice].PFMVelocityScaleFunction); } SynthNote *ADnote::cloneLegato(void) @@ -914,7 +929,7 @@ void ADnote::initparameters(WatchManager *wm, const char *prefix) FMnewamplitude[nvoice] = vce.FMVolume * ctl.fmamp.relamp; - if(param.PFMAmpEnvelopeEnabled ) { + if(param.PFMAmpEnvelopeEnabled) { vce.FMAmpEnvelope = memory.alloc(*param.FMAmpEnvelope, basefreq, synth.dt(), wm, @@ -1552,6 +1567,16 @@ int ADnote::noteout(float *outl, float *outr) memset(bypassl, 0, synth.bufferbytes); memset(bypassr, 0, synth.bufferbytes); + + //Update Changed Parameters From UI + for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { + if((NoteVoicePar[nvoice].Enabled != ON) + || (NoteVoicePar[nvoice].DelayTicks > 0)) + continue; + setupVoiceDetune(nvoice); + setupVoiceMod(nvoice); + } + computecurrentparameters(); for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { @@ -1939,3 +1964,5 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam ¶m, param.PFilterVelocityScaleFunction); } } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/ADnote.h b/source/native-plugins/zynaddsubfx/Synth/ADnote.h index 0ed176c2c..210a04c7a 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ADnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/ADnote.h @@ -27,6 +27,8 @@ #define OSCIL_SMP_EXTRA_SAMPLES 5 +namespace zyncarla { + /**The "additive" synthesizer*/ class ADnote:public SynthNote { @@ -51,6 +53,11 @@ class ADnote:public SynthNote virtual SynthNote *cloneLegato(void) override; private: + void setupVoice(int nvoice); + int setupVoiceUnison(int nvoice); + void setupVoiceDetune(int nvoice); + void setupVoiceMod(int nvoice); + /**Changes the frequency of an oscillator. * @param nvoice voice to run computations on * @param in_freq new frequency*/ @@ -317,4 +324,6 @@ class ADnote:public SynthNote float bandwidthDetuneMultiplier; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/Envelope.cpp b/source/native-plugins/zynaddsubfx/Synth/Envelope.cpp index be69ca760..db2793eb9 100644 --- a/source/native-plugins/zynaddsubfx/Synth/Envelope.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/Envelope.cpp @@ -15,6 +15,8 @@ #include "Envelope.h" #include "../Params/EnvelopeParams.h" +namespace zyncarla { + Envelope::Envelope(EnvelopeParams &pars, float basefreq, float bufferdt, WatchManager *m, const char *watch_prefix) :watchOut(m, watch_prefix, "out") @@ -212,3 +214,5 @@ bool Envelope::finished() const { return envfinish; } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/Envelope.h b/source/native-plugins/zynaddsubfx/Synth/Envelope.h index 5199145d6..6346ea93d 100644 --- a/source/native-plugins/zynaddsubfx/Synth/Envelope.h +++ b/source/native-plugins/zynaddsubfx/Synth/Envelope.h @@ -17,6 +17,8 @@ #include "../globals.h" #include "WatchPoint.h" +namespace zyncarla { + /**Implementation of a general Envelope*/ class Envelope { @@ -54,5 +56,6 @@ class Envelope VecWatchPoint watchOut; }; +} #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/LFO.cpp b/source/native-plugins/zynaddsubfx/Synth/LFO.cpp index 0f55fde1a..9773f62ff 100644 --- a/source/native-plugins/zynaddsubfx/Synth/LFO.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/LFO.cpp @@ -19,6 +19,8 @@ #include #include +namespace zyncarla { + LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManager *m, const char *watch_prefix) :first_half(-1), @@ -191,3 +193,5 @@ void LFO::computeNextFreqRnd() incrnd = nextincrnd; nextincrnd = powf(0.5f, lfofreqrnd) + RND * (powf(2.0f, lfofreqrnd) - 1.0f); } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/LFO.h b/source/native-plugins/zynaddsubfx/Synth/LFO.h index 123015ee9..d9cafe39a 100644 --- a/source/native-plugins/zynaddsubfx/Synth/LFO.h +++ b/source/native-plugins/zynaddsubfx/Synth/LFO.h @@ -18,6 +18,8 @@ #include "../Misc/Time.h" #include "WatchPoint.h" +namespace zyncarla { + /**Class for creating Low Frequency Oscillators*/ class LFO { @@ -70,4 +72,6 @@ class LFO void computeNextFreqRnd(void); }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp b/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp index fe2da1533..084588067 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/ModFilter.cpp @@ -21,6 +21,8 @@ #include "../DSP/FormantFilter.h" #include +namespace zyncarla { + ModFilter::ModFilter(const FilterParams &pars_, const SYNTH_T &synth_, const AbsTime &time_, @@ -159,3 +161,5 @@ void ModFilter::anParamUpdate(AnalogFilter &an) an.setstages(pars.Pstages); an.setgain(pars.getgain()); } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/ModFilter.h b/source/native-plugins/zynaddsubfx/Synth/ModFilter.h index 17546988d..59f20a6a6 100644 --- a/source/native-plugins/zynaddsubfx/Synth/ModFilter.h +++ b/source/native-plugins/zynaddsubfx/Synth/ModFilter.h @@ -13,6 +13,8 @@ #include "../globals.h" #include "../Misc/Time.h" +namespace zyncarla { + //Modulated instance of one of the filters in src/DSP/ //Supports stereo modes class ModFilter @@ -64,3 +66,5 @@ class ModFilter Envelope *env; //center freq envelope LFO *lfo; //center freq lfo }; + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp b/source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp index b718e7113..555939647 100644 --- a/source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp @@ -27,6 +27,8 @@ #include #include +namespace zyncarla { + #define rObject OscilGen const rtosc::Ports OscilGen::non_realtime_ports = { rSelf(OscilGen), @@ -36,27 +38,30 @@ const rtosc::Ports OscilGen::non_realtime_ports = { rOptions(linear,dB scale (-40), dB scale (-60), dB scale (-80), dB scale (-100)), + rDefault(linear), "Type of magnitude for harmonics"), rOption(Pcurrentbasefunc, rShort("base"), rOptions(sine, triangle, pulse, saw, power, gauss, diode, abssine, pulsesine, stretchsine, chirp, absstretchsine, chebyshev, sqr, spike, circle), rOpt(127,use-as-base waveform), + rDefault(sine), "Base Waveform for harmonics"), - rParamZyn(Pbasefuncpar, rShort("shape"), + rParamZyn(Pbasefuncpar, rShort("shape"), rDefault(64), "Morph between possible base function shapes " "(e.g. rising sawtooth vs a falling sawtooth)"), rOption(Pbasefuncmodulation, rShort("mod"), - rOptions(None, Rev, Sine, Power, Chop), + rOptions(None, Rev, Sine, Power, Chop), rDefault(None), "Modulation applied to Base function spectra"), - rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), + rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), rDefault(64), "Base function modulation parameter"), - rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), + rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), rDefault(64), "Base function modulation parameter"), - rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), + rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), rDefault(32), "Base function modulation parameter"), - rParamZyn(Pwaveshaping, rShort("amount"), "Degree Of Waveshaping"), - rOption(Pwaveshapingfunction, rShort("distort"), + rParamZyn(Pwaveshaping, rShort("amount"), rDefault(64), + "Degree Of Waveshaping"), + rOption(Pwaveshapingfunction, rShort("distort"), rDefault(Undistorted), rOptions(Undistorted, Arctangent, Asymmetric, Pow, Sine, Quantisize, Zigzag, Limiter, Upper Limiter, Lower Limiter, @@ -64,22 +69,29 @@ const rtosc::Ports OscilGen::non_realtime_ports = { "Shape of distortion to be applied"), rOption(Pfiltertype, rShort("filter"), rOptions(No Filter, lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2, - cos, sin, low_shelf, s), "Harmonic Filter"), - rParamZyn(Pfilterpar1, rShort("p1"), "Filter parameter"), - rParamZyn(Pfilterpar2, rShort("p2"), "Filter parameter"), - rToggle(Pfilterbeforews, rShort("pre/post"), "Filter before waveshaping spectra;" + cos, sin, low_shelf, s), rDefaultId(No Filter), "Harmonic Filter"), + rParamZyn(Pfilterpar1, rShort("p1"), rDefault(64), "Filter parameter"), + rParamZyn(Pfilterpar2, rShort("p2"), rDefault(64), "Filter parameter"), + rToggle(Pfilterbeforews, rShort("pre/post"), rDefault(false), + "Filter before waveshaping spectra;" "When enabled oscilfilter(freqs); then waveshape(freqs);, " "otherwise waveshape(freqs); then oscilfilter(freqs);"), rOption(Psatype, rShort("spec. adj."), rOptions(None, Pow, ThrsD, ThrsU), - "Spectral Adjustment Type"), - rParamZyn(Psapar, rShort("p1"), "Spectral Adjustment Parameter"), - rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), "Amount of shift on harmonics"), - rToggle(Pharmonicshiftfirst, rShort("pre/post"), "If harmonics are shifted before waveshaping/filtering"), + rDefault(None), "Spectral Adjustment Type"), + rParamZyn(Psapar, rShort("p1"), rDefault(64), + "Spectral Adjustment Parameter"), + rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), rDefault(0), + "Amount of shift on harmonics"), + rToggle(Pharmonicshiftfirst, rShort("pre/post"), rDefault(false), + "If harmonics are shifted before waveshaping/filtering"), rOption(Pmodulation, rShort("FM"), rOptions(None, Rev, Sine, Power), - "Frequency Modulation To Combined Spectra"), - rParamZyn(Pmodulationpar1, rShort("p1"), "modulation parameter"), - rParamZyn(Pmodulationpar2, rShort("p2"), "modulation parameter"), - rParamZyn(Pmodulationpar3, rShort("p3"), "modulation parameter"), + rDefault(None), "Frequency Modulation To Combined Spectra"), + rParamZyn(Pmodulationpar1, rShort("p1"), rDefault(64), + "modulation parameter"), + rParamZyn(Pmodulationpar2, rShort("p2"), rDefault(64), + "modulation parameter"), + rParamZyn(Pmodulationpar3, rShort("p3"), rDefault(32), + "modulation parameter"), //TODO update to rArray and test @@ -188,19 +200,21 @@ const rtosc::Ports OscilGen::realtime_ports{ rPresetType, rParamZyn(Prand, rLinear(-64, 63), rShort("phase rnd"), "Oscillator Phase Randomness: smaller than 0 is \"" "group\", larger than 0 is for each harmonic"), - rParamZyn(Pamprandpower, rShort("variance"), + rParamZyn(Pamprandpower, rShort("variance"), rDefault(64), "Variance of harmonic randomness"), rOption(Pamprandtype, rShort("distribution"), rOptions(None, Pow, Sin), + rDefault(None), "Harmonic random distribution to select from"), rOption(Padaptiveharmonics, rShort("adapt") rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd), + rDefault(OFF), "Adaptive Harmonics Mode"), rParamI(Padaptiveharmonicsbasefreq, rShort("c. freq"), rLinear(0,255), - "Base frequency of adaptive harmonic (30..3000Hz)"), + rDefault(128), "Base frequency of adaptive harmonic (30..3000Hz)"), rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200), - "Adaptive Harmonic Strength"), + rDefault(100), "Adaptive Harmonic Strength"), rParamI(Padaptiveharmonicspar, rShort("power"), rLinear(0,100), - "Adaptive Harmonics Postprocessing Power"), + rDefault(50), "Adaptive Harmonics Postprocessing Power"), {"waveform:", rDoc("Returns waveform points"), NULL, [](const char *, rtosc::RtData &d) { OscilGen &o = *((OscilGen*)d.obj); @@ -772,7 +786,7 @@ void OscilGen::shiftharmonics(fft_t *freqs) } else for(int i = 0; i < synth.oscilsize / 2 - 1; ++i) { - int oldh = i + abs(harmonicshift); + int oldh = i + ::abs(harmonicshift); if(oldh >= (synth.oscilsize / 2 - 1)) h = 0.0f; else { @@ -1790,3 +1804,5 @@ filter_func getFilter(unsigned char func) }; return functions[func]; } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/OscilGen.h b/source/native-plugins/zynaddsubfx/Synth/OscilGen.h index 38e5c1734..c26629169 100644 --- a/source/native-plugins/zynaddsubfx/Synth/OscilGen.h +++ b/source/native-plugins/zynaddsubfx/Synth/OscilGen.h @@ -18,6 +18,8 @@ #include #include "../Params/Presets.h" +namespace zyncarla { + class OscilGen:public Presets { public: @@ -183,5 +185,6 @@ filter_func getFilter(unsigned char func); typedef float (*base_func)(float, float); base_func getBaseFunction(unsigned char func); +} #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp b/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp index 0407a036b..0a258d36d 100644 --- a/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/PADnote.cpp @@ -22,6 +22,8 @@ #include "../Containers/ScratchString.h" #include "../Misc/Util.h" +namespace zyncarla { + PADnote::PADnote(const PADnoteParameters *parameters, SynthParams pars, const int& interpolation, WatchManager *wm, const char *prefix) @@ -446,3 +448,5 @@ void PADnote::releasekey() NoteGlobalPar.FilterEnvelope->releasekey(); NoteGlobalPar.AmpEnvelope->releasekey(); } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/PADnote.h b/source/native-plugins/zynaddsubfx/Synth/PADnote.h index b60dc61b3..ea3b865fa 100644 --- a/source/native-plugins/zynaddsubfx/Synth/PADnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/PADnote.h @@ -18,6 +18,8 @@ #include "Envelope.h" #include "LFO.h" +namespace zyncarla { + /**The "pad" synthesizer*/ class PADnote:public SynthNote { @@ -100,5 +102,6 @@ class PADnote:public SynthNote const int& interpolation; }; +} #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/Resonance.cpp b/source/native-plugins/zynaddsubfx/Synth/Resonance.cpp index 528eb8ccd..45034e748 100644 --- a/source/native-plugins/zynaddsubfx/Synth/Resonance.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/Resonance.cpp @@ -18,21 +18,28 @@ #include #include +using namespace rtosc; + +namespace zyncarla { #define rObject Resonance #define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj - #define rEnd } -using namespace rtosc; + const rtosc::Ports Resonance::ports = { rSelf(Resonance), rPaste, - rToggle(Penabled, rShort("enable"), "resonance enable"), - rToggle(Pprotectthefundamental, rShort("p.fund."), "Disable resonance filter on first harmonic"), - rParams(Prespoints, N_RES_POINTS, "Resonance data points"), - rParamZyn(PmaxdB, rShort("max"), "how many dB the signal may be amplified"), - rParamZyn(Pcenterfreq, rShort("c.freq"), "Center frequency"), - rParamZyn(Poctavesfreq, rShort("oct"), "The number of octaves..."), + rToggle(Penabled, rShort("enable"), rDefault(false), + "resonance enable"), + rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false), + "Disable resonance filter on first harmonic"), + rParams(Prespoints, N_RES_POINTS, rDefaultMissing, + "Resonance data points"), + rParamZyn(PmaxdB, rShort("max"), rDefault(20), + "how many dB the signal may be amplified"), + rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"), + rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64), + "The number of octaves..."), rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"), rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"), rAction(smooth, "Smooth out frequency response"), @@ -319,3 +326,5 @@ void Resonance::getfromXML(XMLwrapper& xml) xml.exitbranch(); } } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/Resonance.h b/source/native-plugins/zynaddsubfx/Synth/Resonance.h index cae9334d4..4bb9f1da7 100644 --- a/source/native-plugins/zynaddsubfx/Synth/Resonance.h +++ b/source/native-plugins/zynaddsubfx/Synth/Resonance.h @@ -21,6 +21,8 @@ #define N_RES_POINTS 256 +namespace zyncarla { + class Resonance:public Presets { public: @@ -61,4 +63,6 @@ class Resonance:public Presets static const rtosc::Ports ports; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp b/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp index c064e90a0..195f42600 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp @@ -32,6 +32,8 @@ # define M_PI 3.14159265358979323846 /* pi */ #endif +namespace zyncarla { + SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars) :SynthNote(spars), pars(*parameters), AmpEnvelope(nullptr), @@ -618,3 +620,5 @@ void SUBnote::entomb(void) { AmpEnvelope->forceFinish(); } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/SUBnote.h b/source/native-plugins/zynaddsubfx/Synth/SUBnote.h index 398578706..6267371cf 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SUBnote.h +++ b/source/native-plugins/zynaddsubfx/Synth/SUBnote.h @@ -17,6 +17,8 @@ #include "SynthNote.h" #include "../globals.h" +namespace zyncarla { + class SUBnote:public SynthNote { public: @@ -104,4 +106,6 @@ class SUBnote:public SynthNote WatchManager *wm; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp b/source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp index 135b33352..c93dcf39f 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp @@ -15,6 +15,8 @@ #include #include +namespace zyncarla { + SynthNote::SynthNote(SynthParams &pars) :memory(pars.memory), legato(pars.synth, pars.frequency, pars.velocity, pars.portamento, @@ -158,3 +160,5 @@ void SynthNote::setVelocity(float velocity_) { } legato.setDecounter(0); //avoid chopping sound due fade-in } + +} diff --git a/source/native-plugins/zynaddsubfx/Synth/SynthNote.h b/source/native-plugins/zynaddsubfx/Synth/SynthNote.h index 938cf9a18..5d792b6dd 100644 --- a/source/native-plugins/zynaddsubfx/Synth/SynthNote.h +++ b/source/native-plugins/zynaddsubfx/Synth/SynthNote.h @@ -14,6 +14,8 @@ #define SYNTH_NOTE_H #include "../globals.h" +namespace zyncarla { + class Allocator; class Controller; struct SynthParams @@ -111,4 +113,6 @@ class SynthNote WatchManager *wm; }; +} + #endif diff --git a/source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp b/source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp index c91caa189..ca765121e 100644 --- a/source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp +++ b/source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp @@ -23,6 +23,7 @@ #include #include +namespace zyncarla { WatchPoint::WatchPoint(WatchManager *ref, const char *prefix, const char *id) :active(false), samples_left(0), reference(ref) @@ -166,3 +167,5 @@ void WatchManager::satisfy(const char *id, float *f, int n) for(int i=0; i} {public local decl {\#include } {public local } +decl {\#include } {public local +} + decl {\#include "Fl_Osc_Interface.h"} {public local } @@ -95,6 +98,15 @@ refreshmainwindow();} banklist->value(0);} tooltip {Refresh the bank list (rescan)} xywh {230 8 105 20} box THIN_UP_BOX color 50 labelsize 11 } + Fl_Input {} { + label {Search by name: } + code0 {o->when(FL_WHEN_CHANGED);} + callback { + std::string str = o->value(); + update_search(str)} + tooltip {Enter text to search for} + xywh {460 8 105 20} box THIN_UP_BOX color 50 labelsize 11 + } } } Function {BankUI(int *npart_, Fl_Osc_Interface *osc_)} {open @@ -139,6 +151,15 @@ bankview->refresh();} {} if (banklist->size() == 0) banklist->add(" ");} {} } + Function {update_search(std::string search_string)} {open + } { + code {if (search_string.empty()) { + refreshmainwindow(); +} else { + osc->write("/bank/search", "s", search_string.c_str()); +} + } {} + } decl {Fl_Osc_Interface *osc;} {private local } decl {Fl_Valuator *cbwig;} {public local diff --git a/source/native-plugins/zynaddsubfx/UI/BankView.cpp b/source/native-plugins/zynaddsubfx/UI/BankView.cpp index d440e2035..ee50a60ce 100644 --- a/source/native-plugins/zynaddsubfx/UI/BankView.cpp +++ b/source/native-plugins/zynaddsubfx/UI/BankView.cpp @@ -19,6 +19,8 @@ #include #include +using namespace zyncarla; + BankList::BankList(int x,int y, int w, int h, const char *label) :Fl_Osc_Choice(x,y,w,h,label) {} @@ -223,15 +225,17 @@ void BankViewControls::mode(int m) BankView::BankView(int x,int y, int w, int h, const char *label) - :Fl_Group(x,y,w,h,label), bvc(NULL), slots{0}, osc(0), - loc(""), nselected(-1), npart(0), cbwig_(0) + :Fl_Group(x,y,w,h,label), Fl_Osc_Widget(), + bvc(NULL), slots{0}, nselected(-1), npart(0), cbwig_(0) {} BankView::~BankView(void) { - if(osc) - osc->removeLink("/bankview", this); + if(osc) { + osc->removeLink("/bankview", this); + osc->removeLink("/bank/search_results", this); + } } void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_) @@ -243,6 +247,7 @@ void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_) npart = npart_; osc->createLink("/bankview", this); + osc->createLink("/bank/search_results", this); //Element Size const float width = w()/5.0; @@ -344,14 +349,30 @@ void BankView::react(int event, int nslot) void BankView::OSC_raw(const char *msg) { - if(!strcmp(rtosc_argument_string(msg), "iss")) { + if(!strcmp(msg, "/bank/search_results")) { + const char *ptr = rtosc_argument_string(msg); + int slot = 0; + + while (ptr[0] == 's' && ptr[1] == 's') { + const char *bank = rtosc_argument(msg, 2*slot).s; + const char *fname = rtosc_argument(msg, 2*slot + 1).s; + + /* store search results directly into slot */ + slots[slot]->update(bank, fname); + if (++slot == 160) + break; + ptr += 2; + } + while (slot < 160) + slots[slot++]->update("", ""); + } else if(!strcmp(rtosc_argument_string(msg), "iss")) { int nslot = rtosc_argument(msg,0).i; const char *name = rtosc_argument(msg,1).s; const char *fname = rtosc_argument(msg,2).s; if(0 <= nslot && nslot < 160) slots[nslot]->update(name, fname); - } if(!strcmp(rtosc_argument_string(msg), "ss")) { + } else if(!strcmp(rtosc_argument_string(msg), "ss")) { while(*msg && !isdigit(*msg)) msg++; int nslot = atoi(msg); const char *name = rtosc_argument(msg,0).s; diff --git a/source/native-plugins/zynaddsubfx/UI/BankView.h b/source/native-plugins/zynaddsubfx/UI/BankView.h index 11f50397a..f1d56812a 100644 --- a/source/native-plugins/zynaddsubfx/UI/BankView.h +++ b/source/native-plugins/zynaddsubfx/UI/BankView.h @@ -96,9 +96,6 @@ class BankView: public Fl_Group, public Fl_Osc_Widget BankViewControls *bvc; BankSlot *slots[160]; - Fl_Osc_Interface *osc; - std::string loc; - //XXX TODO locked banks... int nselected; int *npart; diff --git a/source/native-plugins/zynaddsubfx/UI/ConfigUI.fl b/source/native-plugins/zynaddsubfx/UI/ConfigUI.fl index 274f36e7a..fc0e9a3d8 100644 --- a/source/native-plugins/zynaddsubfx/UI/ConfigUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/ConfigUI.fl @@ -1,56 +1,59 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0302 -header_name {.h} +version 1.0302 +header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {private local -} +} decl {//License: GNU GPL version 2 or later} {private local -} +} decl {\#include } {public local -} +} decl {\#include } {public local -} +} decl {\#include } {public local -} +} decl {\#include } {public local -} +} decl {\#include "Fl_Osc_Button.H"} {public local -} +} decl {\#include "Fl_Osc_Counter.H"} {public local -} +} decl {\#include "Fl_Osc_Choice.H"} {public local -} +} decl {\#include "Osc_IntModel.h"} {public local -} +} decl {\#include "Fl_Osc_Check.H"} {public local -} +} decl {\#include "Fl_Osc_Input.H"} {public local -} +} decl {\#include "Fl_Osc_Numeric_Input.H"} {public local -} +} decl {\#include "Fl_Osc_ListView.H"} {public local -} +} decl {\#include "Fl_Osc_Pane.H"} {public local } decl {\#include "../globals.h"} {public local -} +} decl {\#include "../Misc/Util.h"} {public local +} + +decl {using namespace zyncarla;} {public local } class ConfigUI {} { @@ -294,7 +297,7 @@ activatebutton_presetdir(true);} oscilsize_widget->value(i-7); }; oscilsize->doUpdate("/config/cfg.OscilPower"); - + } {} } Function {activatebutton_rootdir(bool active)} {} { @@ -329,4 +332,4 @@ if (isPlugin) { } decl {class Osc_IntModel *oscilsize;} {public local } -} +} diff --git a/source/native-plugins/zynaddsubfx/UI/Connection.h b/source/native-plugins/zynaddsubfx/UI/Connection.h index e87c9cb48..62506c5d7 100644 --- a/source/native-plugins/zynaddsubfx/UI/Connection.h +++ b/source/native-plugins/zynaddsubfx/UI/Connection.h @@ -14,7 +14,11 @@ //remove the tendrils of the UI from the RT code class Fl_Osc_Interface; -class MiddleWare; +namespace zyncarla +{ + class MiddleWare; +} + namespace GUI { typedef void *ui_handle_t; @@ -25,5 +29,5 @@ void raiseUi(ui_handle_t, const char *); void raiseUi(ui_handle_t, const char *, const char *, ...); void tickUi(ui_handle_t); -Fl_Osc_Interface *genOscInterface(MiddleWare*); +Fl_Osc_Interface *genOscInterface(zyncarla::MiddleWare*); }; diff --git a/source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp b/source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp index 17c177665..0f6d5b987 100644 --- a/source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp +++ b/source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp @@ -29,7 +29,7 @@ void tickUi(ui_handle_t) { usleep(1000); } -Fl_Osc_Interface *genOscInterface(MiddleWare*) +Fl_Osc_Interface *genOscInterface(zyncarla::MiddleWare*) { return NULL; } diff --git a/source/native-plugins/zynaddsubfx/UI/EffUI.fl b/source/native-plugins/zynaddsubfx/UI/EffUI.fl index e448cf7a8..eb19459b6 100644 --- a/source/native-plugins/zynaddsubfx/UI/EffUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/EffUI.fl @@ -54,7 +54,10 @@ decl {\#include "PresetsUI.h"} {public local } decl {\#include "common.H"} {public local -} +} + +decl {using namespace zyncarla;} {public local +} class EffUI {open : {public Fl_Osc_Group,public PresetsUI_} } { diff --git a/source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp b/source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp index b29e6776d..4979c534d 100644 --- a/source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp +++ b/source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp @@ -17,6 +17,8 @@ #include #include +using namespace zyncarla; + EnvelopeFreeEdit::EnvelopeFreeEdit(int x,int y, int w, int h, const char *label) :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this) { diff --git a/source/native-plugins/zynaddsubfx/UI/FilterUI.fl b/source/native-plugins/zynaddsubfx/UI/FilterUI.fl index 3562d79dc..621259f06 100644 --- a/source/native-plugins/zynaddsubfx/UI/FilterUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/FilterUI.fl @@ -68,6 +68,9 @@ decl {\#include "common.H"} {public local decl {\#include "FormantFilterGraph.H"} {public local } +decl {using namespace zyncarla;} {public local +} + class FilterUI {open : {public Fl_Osc_Group,PresetsUI_} } { Function {FilterUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h)} {} { diff --git a/source/native-plugins/zynaddsubfx/UI/Fl_EQGraph.cpp b/source/native-plugins/zynaddsubfx/UI/Fl_EQGraph.cpp index c1daa02fb..ad3b3f395 100644 --- a/source/native-plugins/zynaddsubfx/UI/Fl_EQGraph.cpp +++ b/source/native-plugins/zynaddsubfx/UI/Fl_EQGraph.cpp @@ -19,6 +19,8 @@ #include +using namespace zyncarla; + #define MAX_DB 30 Fl_EQGraph::Fl_EQGraph(int x,int y, int w, int h, const char *label) diff --git a/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Tree.H b/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Tree.H index 890bc99bf..2ca9e3859 100644 --- a/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Tree.H +++ b/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Tree.H @@ -107,7 +107,7 @@ class Fl_Osc_Tree: public Fl_Tree const char *name = port.name; if(!index(name, '/'))//only accept objects that will have subports continue; - if(rtosc_match(name, s.c_str())) { + if(rtosc_match(name, s.c_str(), NULL)) { return subtree_lookup(port.ports, s.substr(index(s.c_str(), '/')-s.c_str()+1)); } diff --git a/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.cpp b/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.cpp index 1b4691d39..bad037cf4 100644 --- a/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.cpp +++ b/source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.cpp @@ -96,7 +96,7 @@ void Fl_Osc_Widget::oscRegister(const char *path) void Fl_Osc_Widget::update(void) { - if(*((loc+ext).rbegin()) != '/') + if(*((loc+ext).rbegin()) != '/' && osc) osc->requestValue(loc+ext); } diff --git a/source/native-plugins/zynaddsubfx/UI/Fl_Resonance_Graph.cpp b/source/native-plugins/zynaddsubfx/UI/Fl_Resonance_Graph.cpp index 800d84f74..4c6df84fb 100644 --- a/source/native-plugins/zynaddsubfx/UI/Fl_Resonance_Graph.cpp +++ b/source/native-plugins/zynaddsubfx/UI/Fl_Resonance_Graph.cpp @@ -14,6 +14,7 @@ #include #include #include +using namespace zyncarla; Fl_Resonance_Graph::Fl_Resonance_Graph(int x,int y, int w, int h, const char *label) :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this), khzvalue(NULL), dbvalue(NULL), diff --git a/source/native-plugins/zynaddsubfx/UI/MasterUI.fl b/source/native-plugins/zynaddsubfx/UI/MasterUI.fl index caeeb178c..97bf447dc 100644 --- a/source/native-plugins/zynaddsubfx/UI/MasterUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/MasterUI.fl @@ -1,94 +1,94 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0302 -header_name {.h} +version 1.0302 +header_name {.h} code_name {.cc} -decl {//Copyright (c) 2002-2009 Nasca Octavian Paul - (c) 2009-2016 Mark McCurry} {private local -} +decl {//Copyright (c) 2002-2009 Nasca Octavian Paul - (c) 2009-2017 Mark McCurry} {private local +} decl {//License: GNU GPL version 2 or later} {private local -} +} decl {\#include } {public local -} +} decl {\#include } {public local -} +} decl {\#include } {public local -} +} decl {\#if ! defined(PLUGINVERSION) && HAS_X11 \#include "zynaddsubfx.xpm" \#endif} {private local -} +} decl {\#include "WidgetPDial.h"} {public local -} +} decl {\#include "ADnoteUI.h"} {public local -} +} decl {\#include "SUBnoteUI.h"} {public local -} +} decl {\#include "EffUI.h"} {public local -} +} decl {\#include "VirKeyboard.h"} {public local -} +} decl {\#include "ConfigUI.h"} {public local -} +} decl {\#include "BankUI.h"} {public local -} +} decl {\#include "PartUI.h"} {public local -} +} decl {\#include "MicrotonalUI.h"} {public local -} +} decl {\#include "PresetsUI.h"} {public local -} +} decl {\#include "NioUI.h"} {public global -} +} decl {\#include "VuPartMeter.h"} {public local -} +} decl {\#include "Fl_Osc_Dial.H"} {private local -} +} decl {\#include "Osc_DataModel.h"} {private local -} +} decl {\#include "Fl_Osc_TSlider.H"} {private local -} +} decl {\#include "VuMasterMeter.h"} {public local -} +} decl {\#include "PartNameButton.h"} {public local -} +} decl {\#include "common.H"} {public local -} +} decl {\#if USE_NSM \#include "NSM.H" extern NSM_Client *nsm; \#endif} {public local -} +} decl {\#if !defined(PLUGINVERSION) && HAS_X11 \#include \#endif} {public local -} +} decl {\#include "../globals.h"} {public local -} +} class SysEffSend {: {public Fl_Osc_Dial} } { @@ -111,7 +111,7 @@ this->copy_label(tmp);} {} Function {~SysEffSend()} {} { code {hide();} {} } -} +} class Panellistitem {open : {public Fl_Osc_Group} } { @@ -213,10 +213,10 @@ end();} {} partpanning->update(); partvolume->update(); partname->update(); - + if ((int)bankui->cbwig->value()!=(npart+1)) panellistitemgroup->color(fl_rgb_color(160,160,160)); -else +else panellistitemgroup->color(fl_rgb_color(50,190,240)); panellistitemgroup->redraw();} {} @@ -230,7 +230,7 @@ panellistitemgroup->redraw();} {} } decl {PartUI *partui;} {private local } -} +} class MasterUI {open } { @@ -357,7 +357,7 @@ result=fileexists(filename); if (result) { result=0; if (!fl_choice("The file exists. \\nOverwrite it?","No","Yes",NULL)) return; - + }; @@ -433,7 +433,7 @@ int result=fileexists(filename); if (result) { result=0; if (!fl_choice("The file exists. \\nOverwrite it?","No","Yes",NULL)) return; - + }; osc->write("/save_xiz", "is", npart, filename); @@ -873,11 +873,11 @@ panelwindow->show();} xywh {15 35 335 55} labeltype EMBOSSED_LABEL labelsize 15 align 208 } Fl_Box {} { - label {This is free software; you may redistribute it and/or modify it under the terms of the + label {This is free software; you may redistribute it and/or modify it under the terms of the version 2 (or any later version) of the GNU General Public License as published by the Free Software Fundation. This program comes with - ABSOLUTELY NO WARRANTY. - See the version 2 (or any later version) of the + ABSOLUTELY NO WARRANTY. + See the version 2 (or any later version) of the GNU General Public License for details.} xywh {15 90 335 145} labelfont 1 labelsize 11 align 144 } @@ -1511,7 +1511,7 @@ osc->write("/config/cfg.UserInterfaceMode", "i", 2);} } } Function {updatesendwindow()} {} { - code {/*for (int neff1=0;neff1value(master->Psysefxsend[neff1][neff2]);*/} {} } @@ -1666,7 +1666,7 @@ return 1;} {} updatepanel(); setfilelabel(display_name); - + return 1;} {} } Function {do_load_master(const char* file = NULL)} {} { @@ -1697,7 +1697,7 @@ char *tmp; if (result) { result=0; if (!fl_choice("The file exists. Overwrite it?","No","Yes",NULL)) return; - + } } else { @@ -1780,4 +1780,4 @@ bankui->hide();} {} } { code {*exitprogram=1;} {} } -} +} diff --git a/source/native-plugins/zynaddsubfx/UI/NSM.C b/source/native-plugins/zynaddsubfx/UI/NSM.C index ba6ef18ce..621d0874c 100644 --- a/source/native-plugins/zynaddsubfx/UI/NSM.C +++ b/source/native-plugins/zynaddsubfx/UI/NSM.C @@ -41,7 +41,7 @@ extern MasterUI *ui; extern NSM_Client *nsm; extern char *instance_name; -NSM_Client::NSM_Client(MiddleWare *m) +NSM_Client::NSM_Client(zyn::MiddleWare *m) :project_filename(0), display_name(0), middleware(m) @@ -71,14 +71,14 @@ NSM_Client::command_open(const char *name, const char *client_id, char **out_msg) { - Nio::stop(); + zyn::Nio::stop(); if(instance_name) free(instance_name); instance_name = strdup(client_id); - Nio::start(); + zyn::Nio::start(); char *new_filename; diff --git a/source/native-plugins/zynaddsubfx/UI/NSM.H b/source/native-plugins/zynaddsubfx/UI/NSM.H index 8e3577ccd..54c258dec 100644 --- a/source/native-plugins/zynaddsubfx/UI/NSM.H +++ b/source/native-plugins/zynaddsubfx/UI/NSM.H @@ -29,9 +29,9 @@ class NSM_Client:public NSM::Client char *project_filename; char *display_name; - MiddleWare *middleware; + zyn::MiddleWare *middleware; - NSM_Client(MiddleWare *m); + NSM_Client(zyn::MiddleWare *m); ~NSM_Client() { } protected: diff --git a/source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl b/source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl index dc1e9057e..80ba3276b 100644 --- a/source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl +++ b/source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl @@ -71,6 +71,9 @@ decl {\#include "PresetsUI.h"} {public local decl {\#include } {public local } +decl {using namespace zyncarla;} {public local +} + class OGSlider {: {public Fl_Osc_TSlider} } { Function {OGSlider(int x,int y, int w, int h, const char *label=0) diff --git a/source/native-plugins/zynaddsubfx/UI/VirKeyboard.fl b/source/native-plugins/zynaddsubfx/UI/VirKeyboard.fl index 9af6c53b5..3902900e5 100644 --- a/source/native-plugins/zynaddsubfx/UI/VirKeyboard.fl +++ b/source/native-plugins/zynaddsubfx/UI/VirKeyboard.fl @@ -37,6 +37,9 @@ decl {\#ifdef NTK_GUI \#endif} {public local } +decl {using namespace zyncarla;} {public local +} + decl {const int keyspos[12]={0,-1,1,-2,2,3,-4,4,-5,5,-6,6};} {private local } diff --git a/source/native-plugins/zynaddsubfx/UI/VuMasterMeter.h b/source/native-plugins/zynaddsubfx/UI/VuMasterMeter.h index d8897a8e2..e8b540b4a 100644 --- a/source/native-plugins/zynaddsubfx/UI/VuMasterMeter.h +++ b/source/native-plugins/zynaddsubfx/UI/VuMasterMeter.h @@ -12,6 +12,7 @@ #include "VuMeter.h" #include "Fl_Osc_Interface.h" #define MIN_DB (-48) +using namespace zyncarla; class VuMasterMeter: public VuMeter { diff --git a/source/native-plugins/zynaddsubfx/UI/guimain.cpp b/source/native-plugins/zynaddsubfx/UI/guimain.cpp index 7190dffbe..29f646006 100644 --- a/source/native-plugins/zynaddsubfx/UI/guimain.cpp +++ b/source/native-plugins/zynaddsubfx/UI/guimain.cpp @@ -36,16 +36,6 @@ void exitprogram() GUI::destroyUi(gui); } -bool fileexists(const char *filename) -{ - struct stat tmp; - int result = stat(filename, &tmp); - if(result >= 0) - return true; - - return false; -} - int Pexitprogram=0; @@ -77,7 +67,21 @@ int Pexitprogram=0; using namespace GUI; class MasterUI *ui=0; -bool isPlugin = false; + +// exceptionally extension of the namespace outside the core +namespace zyncarla +{ + bool isPlugin = false; + bool fileexists(const char *filename) + { + struct stat tmp; + int result = stat(filename, &tmp); + if(result >= 0) + return true; + + return false; + } +} #ifdef NTK_GUI static Fl_Tiled_Image *module_backdrop; diff --git a/source/native-plugins/zynaddsubfx/globals.cpp b/source/native-plugins/zynaddsubfx/globals.cpp index dfc3e3dfd..a131a0fd4 100644 --- a/source/native-plugins/zynaddsubfx/globals.cpp +++ b/source/native-plugins/zynaddsubfx/globals.cpp @@ -15,6 +15,8 @@ #include "Misc/Util.h" #include "globals.h" +namespace zyncarla { + void SYNTH_T::alias(bool randomize) { halfsamplerate_f = (samplerate_f = samplerate) / 2.0f; @@ -32,3 +34,5 @@ void SYNTH_T::alias(bool randomize) else denormalkillbuf[i] = 0; } + +} diff --git a/source/native-plugins/zynaddsubfx/globals.h b/source/native-plugins/zynaddsubfx/globals.h index e21a639e2..6d57b34b2 100644 --- a/source/native-plugins/zynaddsubfx/globals.h +++ b/source/native-plugins/zynaddsubfx/globals.h @@ -25,7 +25,18 @@ #endif //Forward Declarations -namespace rtosc{struct Ports; struct ClonePorts; struct MergePorts; class ThreadLink;}; + +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#else +namespace std { + template struct complex; +} +#endif + +namespace rtosc{struct Ports; struct ClonePorts; struct MergePorts; class ThreadLink;} +namespace zyncarla { + class EffectMgr; class ADnoteParameters; struct ADnoteGlobalParam; @@ -60,14 +71,6 @@ class SVFilter; class FormantFilter; class ModFilter; -#if defined(__APPLE__) || defined(__FreeBSD__) -#include -#else -namespace std { - template struct complex; -}; -#endif - typedef double fftw_real; typedef std::complex fft_t; @@ -336,4 +339,6 @@ struct SYNTH_T { void alias(bool randomize=true); static float numRandom(void); //defined in Util.cpp for now }; + +} #endif diff --git a/source/native-plugins/zynaddsubfx/main.cpp b/source/native-plugins/zynaddsubfx/main.cpp index f5e79406d..114644a88 100644 --- a/source/native-plugins/zynaddsubfx/main.cpp +++ b/source/native-plugins/zynaddsubfx/main.cpp @@ -3,7 +3,7 @@ main.cpp - Main file of the synthesizer Copyright (C) 2002-2005 Nasca Octavian Paul - Copyright (C) 2012-2016 Mark McCurry + Copyright (C) 2012-2017 Mark McCurry This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,7 +21,9 @@ #include #include +#ifndef WIN32 #include +#endif #include #include @@ -47,16 +49,30 @@ #include "UI/Connection.h" GUI::ui_handle_t gui; +#ifdef ZEST_GUI +#ifndef WIN32 +#include +#endif +#endif + //Glue Layer #include "Misc/MiddleWare.h" -MiddleWare *middleware; using namespace std; +using namespace zyncarla; + +MiddleWare *middleware; Master *master; int swaplr = 0; //1 for left-right swapping -extern int Pexitprogram; //if the UI set this to 1, the program will exit +// forward declarations of namespace zyncarla +namespace zyncarla +{ + extern int Pexitprogram; //if the UI set this to 1, the program will exit + void dump_json(std::ostream &o, + const rtosc::Ports &p); +} #if LASH #include "Misc/LASHClient.h" @@ -71,7 +87,7 @@ NSM_Client *nsm = 0; char *instance_name = 0; -void exitprogram(const CarlaConfig &config); +void exitprogram(const Config &config); //cleanup on signaled exit @@ -85,7 +101,7 @@ void sigterm_exit(int /*sig*/) /* * Program initialisation */ -void initprogram(SYNTH_T synth, CarlaConfig* config, int prefered_port) +void initprogram(SYNTH_T synth, Config* config, int prefered_port) { middleware = new MiddleWare(std::move(synth), config, prefered_port); master = middleware->spawnMaster(); @@ -99,7 +115,7 @@ void initprogram(SYNTH_T synth, CarlaConfig* config, int prefered_port) /* * Program exit */ -void exitprogram(const CarlaConfig& config) +void exitprogram(const Config& config) { Nio::stop(); config.save(); @@ -123,7 +139,9 @@ void exitprogram(const CarlaConfig& config) #ifdef WIN32 #include #include +namespace zyncarla{ extern InMgr *in; +} HMIDIIN winmidiinhandle = 0; void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance, @@ -202,14 +220,13 @@ void InitWinMidi(int) {} int main(int argc, char *argv[]) { SYNTH_T synth; - CarlaConfig config; - config.init(); + Config config; int noui = 0; cerr << "\nZynAddSubFX - Copyright (c) 2002-2013 Nasca Octavian Paul and others" << endl; cerr - << " Copyright (c) 2009-2016 Mark McCurry [active maintainer]" + << " Copyright (c) 2009-2017 Mark McCurry [active maintainer]" << endl; cerr << "Compiled: " << __DATE__ << " " << __TIME__ << endl; cerr << "This program is free software (GNU GPL v2 or later) and \n"; @@ -217,7 +234,7 @@ int main(int argc, char *argv[]) if(argc == 1) cerr << "Try 'zynaddsubfx --help' for command-line options." << endl; - /* Get the settings from the CarlaConfig*/ + /* Get the settings from the Config*/ synth.samplerate = config.cfg.SampleRate; synth.buffersize = config.cfg.SoundBufferSize; synth.oscilsize = config.cfg.OscilSize; @@ -301,7 +318,7 @@ int main(int argc, char *argv[]) opterr = 0; int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0; int prefered_port = -1; - int auto_save_interval = 60; + int auto_save_interval = 0; int wmidi = -1; string loadfile, loadinstrument, execAfterInit, loadmidilearn; @@ -312,7 +329,7 @@ int wmidi = -1; /**\todo check this process for a small memory leak*/ opt = getopt_long(argc, argv, - "l:L:M:r:b:o:I:O:N:e:P:A:D:hvapSDUYZ", + "l:L:M:r:b:o:I:O:N:e:P:A:d:D:hvapSDUYZ", opts, &option_index); char *optarguments = optarg; @@ -431,8 +448,6 @@ int wmidi = -1; if(optarguments) { ofstream outfile(optarguments); - void dump_json(std::ostream &o, - const rtosc::Ports &p); dump_json(outfile, Master::ports); } break; @@ -469,7 +484,8 @@ int wmidi = -1; " -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n" << " -N , --named\t\t\t\t Postfix IO Name when possible\n" << " -a , --auto-connect\t\t\t AutoConnect when using JACK\n" - << " -A , --auto-save=INTERVAL\t\t Automatically save at interval (disabled with 0 interval)\n" + << " -A , --auto-save=INTERVAL\t\t Automatically save at interval\n" + << "\t\t\t\t\t (disabled with 0 interval)\n" << " -p , --pid-in-client-name\t\t Append PID to (JACK) " "client name\n" << " -P , --preferred-port\t\t\t Preferred OSC Port\n" @@ -477,6 +493,7 @@ int wmidi = -1; << " -I , --input\t\t\t\t Set Input Engine\n" << " -e , --exec-after-init\t\t Run post-initialization script\n" << " -d , --dump-oscdoc=FILE\t\t Dump oscdoc xml to file\n" + << " -D , --dump-json-schema=FILE\t\t Dump osc schema (.json) to file\n" << endl; return 0; @@ -586,7 +603,7 @@ int wmidi = -1; } printf("[INFO] auto_save setup\n"); - if(auto_save_interval > 0 && false) { + if(auto_save_interval > 0) { int old_save = middleware->checkAutoSave(); if(old_save > 0) GUI::raiseUi(gui, "/alert-reload", "i", old_save); @@ -632,15 +649,42 @@ int wmidi = -1; } #ifdef ZEST_GUI +#ifndef WIN32 + pid_t gui_pid = 0; +#endif if(!noui) { printf("[INFO] Launching Zyn-Fusion...\n"); const char *addr = middleware->getServerAddress(); - if(fork() == 0) { +#ifndef WIN32 + gui_pid = fork(); + if(gui_pid == 0) { execlp("zyn-fusion", "zyn-fusion", addr, "--builtin", "--no-hotload", 0); execlp("./zyn-fusion", "zyn-fusion", addr, "--builtin", "--no-hotload", 0); err(1,"Failed to launch Zyn-Fusion"); } +#else + STARTUPINFO si; +PROCESS_INFORMATION pi; +memset(&si, 0, sizeof(si)); +memset(&pi, 0, sizeof(pi)); +char *why_windows = strrchr(addr, ':'); +char *seriously_why = why_windows + 1; +char start_line[256] = {0}; +if(why_windows) + snprintf(start_line, sizeof(start_line), "zyn-fusion.exe osc.udp://127.0.0.1:%s", seriously_why); +else { + printf("COULD NOT PARSE <%s>\n", addr); + exit(1); +} +printf("[INFO] starting subprocess via <%s>\n", start_line); +if(!CreateProcess(NULL, start_line, +NULL, NULL, 0, 0, NULL, NULL, &si, &pi)) { + printf("Failed to launch Zyn-Fusion...\n"); + exit(1); +} + +#endif } #endif @@ -681,6 +725,17 @@ done: middleware->tick(); #ifdef WIN32 Sleep(1); +#endif + +#ifdef ZEST_GUI +#ifndef WIN32 + if(!noui) { + int status = 0; + int ret = waitpid(gui_pid, &status, WNOHANG); + if(ret == gui_pid) + Pexitprogram = 1; + } +#endif #endif } diff --git a/source/native-plugins/zynaddsubfx/rtosc/automations.h b/source/native-plugins/zynaddsubfx/rtosc/automations.h new file mode 100644 index 000000000..74d982b18 --- /dev/null +++ b/source/native-plugins/zynaddsubfx/rtosc/automations.h @@ -0,0 +1,132 @@ +#include +#include +#include +namespace rtosc { +struct AutomationMapping +{ + //0 - linear + //1 - log + int control_scale; + + //0 - simple linear (only first four control points are used) + //1 - piecewise linear + int control_type; + + float *control_points; + int npoints; + int upoints; + + float gain; + float offset; +}; + +struct Automation +{ + //If automation is allocated to anything or not + bool used; + + //If automation is used or not + bool active; + + //relative or absolute + bool relative; + + //Cached infomation + float param_base_value; + char param_path[128]; + char param_type; + float param_min; + float param_max; + float param_step; //resolution of parameter. Useful for: + //- integer valued controls + AutomationMapping map; +}; + +#define RTOSC_AUTOMATION_SLOT_NAME_LEN +struct AutomationSlot +{ + //If automation slot has active automations or not + bool active; + + //If automation slot has active automations or not + bool used; + + //Non-negative if a new MIDI binding is being learned + int learning; + + //-1 or a valid MIDI CC + MIDI Channel + int midi_cc; + + //Current state supplied by MIDI value or host + float current_state; + + //Current name + char name[128]; + + //Collection of automations + Automation *automations; +}; + +class AutomationMgr +{ + public: + AutomationMgr(int slots, int per_slot, int control_points); + ~AutomationMgr(void); + + /** + * Create an Automation binding + * + * - Assumes that each binding takes a new automation slot unless learning + * a macro + * - Can trigger a MIDI learn (recommended for standalone and not + * recommended for plugin modes) + */ + void createBinding(int slot, const char *path, bool start_midi_learn); + + void updateMapping(int slot, int sub); + + + + //Get/Set Automation Slot values 0..1 + void setSlot(int slot_id, float value); + void setSlotSub(int slot_id, int sub, float value); + float getSlot(int slot_id); + + void clearSlot(int slot_id); + void clearSlotSub(int slot_id, int sub); + + + void setSlotSubGain(int slot_id, int sub, float f); + float getSlotSubGain(int slot_id, int sub); + void setSlotSubOffset(int slot_id, int sub, float f); + float getSlotSubOffset(int slot_id, int sub); + + + + void setName(int slot_id, const char *msg); + const char * getName(int slot_id); + + bool handleMidi(int channel, int cc, int val); + + void set_ports(const struct Ports &p); + + void set_instance(void *v); + + void simpleSlope(int slot, int au, float slope, float offset); + + int free_slot(void) const; + + AutomationSlot *slots; + int nslots; + int per_slot; + int active_slot; + int learn_queue_len; + struct AutomationMgrImpl *impl; + const rtosc::Ports *p; + void *instance; + + std::function backend; + + int damaged; +}; +}; diff --git a/source/native-plugins/zynaddsubfx/rtosc/cpp/automations.cpp b/source/native-plugins/zynaddsubfx/rtosc/cpp/automations.cpp new file mode 100644 index 000000000..f4d3a7460 --- /dev/null +++ b/source/native-plugins/zynaddsubfx/rtosc/cpp/automations.cpp @@ -0,0 +1,317 @@ +#include +#include + +using namespace rtosc; + +AutomationMgr::AutomationMgr(int slots, int per_slot, int control_points) + :nslots(slots), per_slot(per_slot), active_slot(0), learn_queue_len(0), p(NULL), damaged(0) +{ + this->slots = new AutomationSlot[slots]; + memset(this->slots, 0, sizeof(AutomationSlot)*slots); + for(int i=0; islots[i]; + sprintf(s.name, "Slot %d", i); + s.midi_cc = -1; + s.learning = -1; + + s.automations = new Automation[per_slot]; + memset(s.automations, 0, sizeof(Automation)*per_slot); + for(int j=0; japropos(path); + if(!port) { + fprintf(stderr, "[Zyn:Error] port '%s' does not exist\n", path); + return; + } + auto meta = port->meta(); + if(!(meta.find("min") && meta.find("max"))) { + fprintf(stderr, "No bounds for '%s' known\n", path); + return; + } + if(meta.find("internal") || meta.find("no learn")) { + fprintf(stderr, "[Warning] port '%s' is unlearnable\n", path); + return; + } + int ind = -1; + for(int i=0; iname, ":f")) + au.param_type = 'f'; + strncpy(au.param_path, path, sizeof(au.param_path)); + + au.map.gain = 100.0; + au.map.offset = 0; + updateMapping(slot, ind); + + if(start_midi_learn && slots[slot].learning == -1 && slots[slot].midi_cc == -1) + slots[slot].learning = ++learn_queue_len; + + damaged = true; + +}; + +void AutomationMgr::updateMapping(int slot_id, int sub) +{ + if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return; + + + auto &au = slots[slot_id].automations[sub]; + + float mn = au.param_min; + float mx = au.param_max; + float center = (mn+mx)*(0.5 + au.map.offset/100.0); + float range = (mx-mn)*au.map.gain/100.0; + + au.map.upoints = 2; + au.map.control_points[0] = 0; + au.map.control_points[1] = center-range/2.0; + au.map.control_points[2] = 1; + au.map.control_points[3] = center+range/2.0; +} + +void AutomationMgr::setSlot(int slot_id, float value) +{ + if(slot_id >= nslots || slot_id < 0) + return; + for(int i=0; i= nslots || slot_id < 0 || par >= per_slot || par < 0) + return; + auto &au = slots[slot_id].automations[par]; + if(au.used == false) + return; + const char *path = au.param_path; + float mn = au.param_min; + float mx = au.param_max; + + float a = au.map.control_points[1]; + float b = au.map.control_points[3]; + + char type = au.param_type; + + char msg[256] = {0}; + if(type == 'i') { + float v = value*(b-a) + a; + if(v > mx) + v = mx; + else if(v < mn) + v = mn; + + rtosc_message(msg, 256, path, "i", (int)roundf(v)); + } else if(type == 'f') { + float v = value*(b-a) + a; + if(v > mx) + v = mx; + else if(v < mn) + v = mn; + + rtosc_message(msg, 256, path, "f", v); + } else if(type == 'T' || type == 'F') { + float v = value*(b-a) + a; + if(v > 0.5) + v = 1.0; + else + v = 0.0; + + rtosc_message(msg, 256, path, v == 1.0 ? "T" : "F"); + } else + return; + + if(backend) + backend(msg); +} + +float AutomationMgr::getSlot(int slot_id) +{ + if(slot_id >= nslots || slot_id < 0) + return 0.0; + return slots[slot_id].current_state; +} + + +void AutomationMgr::clearSlot(int slot_id) +{ + if(slot_id >= nslots || slot_id < 0) + return; + auto &s = slots[slot_id]; + s.active = false; + s.used = false; + if(s.learning) + learn_queue_len--; + for(int i=0; i s.learning) + slots[i].learning--; + s.learning = -1; + s.midi_cc = -1; + s.current_state = 0; + memset(s.name, 0, sizeof(s.name)); + sprintf(s.name, "Slot %d", slot_id); + for(int i=0; i= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return; + auto &a = slots[slot_id].automations[sub]; + a.used = false; + a.active = false; + a.relative = false; + a.param_base_value = false; + memset(a.param_path, 0, sizeof(a.param_path)); + a.param_type = 0; + a.param_min = 0; + a.param_max = 0; + a.param_step = 0; + a.map.gain = 100; + a.map.offset = 0; + + damaged = true; +} + +void AutomationMgr::setSlotSubGain(int slot_id, int sub, float f) +{ + if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return; + auto &m = slots[slot_id].automations[sub].map; + m.gain = f; +} +float AutomationMgr::getSlotSubGain(int slot_id, int sub) +{ + if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return 0.0; + auto &m = slots[slot_id].automations[sub].map; + return m.gain; +} +void AutomationMgr::setSlotSubOffset(int slot_id, int sub, float f) +{ + if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return; + auto &m = slots[slot_id].automations[sub].map; + m.offset = f; +} +float AutomationMgr::getSlotSubOffset(int slot_id, int sub) +{ + if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0) + return 0.0; + auto &m = slots[slot_id].automations[sub].map; + return m.offset; +} + +void AutomationMgr::setName(int slot_id, const char *msg) +{ + if(slot_id >= nslots || slot_id < 0) + return; + strncpy(slots[slot_id].name, msg, sizeof(slots[slot_id].name)); + damaged = 1; +} +const char *AutomationMgr::getName(int slot_id) +{ + if(slot_id >= nslots || slot_id < 0) + return ""; + return slots[slot_id].name; +} +bool AutomationMgr::handleMidi(int channel, int cc, int val) +{ + int ccid = channel*128 + cc; + + bool bound_cc = false; + for(int i=0; i 1) + slots[j].learning -= 1; + learn_queue_len--; + setSlot(i, val/127.0); + damaged = 1; + break; + } + } + return 0; +} + +void AutomationMgr::set_ports(const struct Ports &p_) { + p = &p_; +}; +// +// AutomationSlot *slots; +// struct AutomationMgrImpl *impl; +//}; +void AutomationMgr::set_instance(void *v) +{ + this->instance = v; +} + +void AutomationMgr::simpleSlope(int slot_id, int par, float slope, float offset) +{ + if(slot_id >= nslots || slot_id < 0 || par >= per_slot || par < 0) + return; + auto &map = slots[slot_id].automations[par].map; + map.upoints = 2; + map.control_points[0] = 0; + map.control_points[1] = -(slope/2)+offset; + map.control_points[2] = 1; + map.control_points[3] = slope/2+offset; + +} + +int AutomationMgr::free_slot(void) const +{ + for(int i=0; i(imap), get<1>(imap), -1, get<3>(imap)); } + { + auto tmp = inv_map[addr]; + if(get<1>(tmp) == -1 && get<2>(tmp) == -1) + inv_map.erase(addr); + } + if(kill_id == -1) return; diff --git a/source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp b/source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp index 64db8b184..fdbee18bd 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp +++ b/source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp @@ -1,23 +1,65 @@ #include "../ports.h" +#include "../rtosc.h" +#include "../pretty-format.h" + +#include #include #include -#include +#include #include #include +/* Compatibility with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif +#ifndef __has_extension +# define __has_extension __has_feature +#endif + +/* Check for C++11 support */ +#if defined(HAVE_CPP11_SUPPORT) +# if HAVE_CPP11_SUPPORT +# define DISTRHO_PROPER_CPP11_SUPPORT +# endif +#elif __cplusplus >= 201103L || (defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405) || __has_extension(cxx_noexcept) +# define DISTRHO_PROPER_CPP11_SUPPORT +# if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 407 && ! defined(__clang__)) || (defined(__clang__) && ! __has_extension(cxx_override_control)) +# define override // gcc4.7+ only +# define final // gcc4.7+ only +# endif +#endif + using namespace rtosc; static inline void scat(char *dest, const char *src) { while(*dest) dest++; - if(*dest) dest++; while(*src && *src!=':') *dest++ = *src++; *dest = 0; } RtData::RtData(void) :loc(NULL), loc_size(0), obj(NULL), matches(0), message(NULL) -{} +{ + for(int i=0; i<(int)(sizeof(idx)/sizeof(int)); ++i) + idx[i] = 0; +} + +void RtData::push_index(int ind) +{ + for(int i=1; i<(int)(sizeof(idx)/sizeof(int)); ++i) + idx[i] = idx[i-1]; + idx[0] = ind; +} + +void RtData::pop_index(void) +{ + int n = sizeof(idx)/sizeof(int); + for(int i=n-2; i >= 0; --i) + idx[i] = idx[i+1]; + idx[n-1] = 0; +} void RtData::replyArray(const char *path, const char *args, rtosc_arg_t *vals) @@ -34,9 +76,9 @@ void RtData::reply(const char *path, const char *args, ...) rtosc_vmessage(buffer,1024,path,args,va); reply(buffer); va_end(va); -}; +} void RtData::reply(const char *msg) -{(void)msg;}; +{(void)msg;} void RtData::chain(const char *path, const char *args, ...) { (void) path; @@ -46,7 +88,7 @@ void RtData::chain(const char *path, const char *args, ...) void RtData::chain(const char *msg) { (void) msg; -}; +} void RtData::chainArray(const char *path, const char *args, rtosc_arg_t *vals) { @@ -122,6 +164,11 @@ Port::MetaIterator& Port::MetaIterator::operator++(void) return *this; } +Port::MetaIterator::operator bool(void) const +{ + return title; +} + Port::MetaContainer::MetaContainer(const char *str_) :str_ptr(str_) {} @@ -214,7 +261,7 @@ class Port_Matcher bool rtosc_match_args(const char *pattern, const char *msg) { - //match anything if now arg restriction is present + //match anything if no arg restriction is present //(ie the ':') if(*pattern++ != ':') return true; @@ -245,6 +292,7 @@ class Port_Matcher return true; } }; + } @@ -302,7 +350,7 @@ static ivec_t find_pos(words_t &strs) N = int_max(N,w.length()); int pos_best = -1; - int pos_best_val = INT_MAX; + int pos_best_val = std::numeric_limits::max(); while(true) { for(int i=0; i::max();; for(int k=0; k<4; ++k) { for(int i:useful_chars) { - assoc_best_val = INT_MAX; + assoc_best_val = std::numeric_limits::max(); for(int j=0; j<100; ++j) { //printf("."); assoc[i] = j; @@ -468,6 +516,13 @@ Ports::~Ports() void Ports::dispatch(const char *m, rtosc::RtData &d, bool base_dispatch) const { + if(!strcmp(m, "pointer")) + { + // rRecur*Cb have already set d.loc to the pointer we need, + // so we just return + return; + } + void *obj = d.obj; //handle the first dispatch layer @@ -483,7 +538,7 @@ void Ports::dispatch(const char *m, rtosc::RtData &d, bool base_dispatch) const //simple case if(!d.loc || !d.loc_size) { for(const Port &port: ports) { - if(rtosc_match(port.name,m)) + if(rtosc_match(port.name,m, NULL)) d.port = &port, port.cb(m,d), d.obj = obj; } } else { @@ -502,7 +557,8 @@ void Ports::dispatch(const char *m, rtosc::RtData &d, bool base_dispatch) const if(impl->pos.empty()) { //No perfect minimal hash function for(unsigned i=0; i= 8); + // append type + memset(buffer_with_port + addr_len, 0, 8); // cover string end and arguments + buffer_with_port[addr_len + (4-addr_len%4)] = ','; + + d.message = buffer_with_port; + + // buffer_with_port is a message in this call: + ports.dispatch(buffer_with_port, d, false); + + return d.value(); +} + +//! RtData subclass to capture argument values from a runtime object +class Capture : public RtData +{ + size_t max_args; + rtosc_arg_val_t* arg_vals; + int nargs; + + void chain(const char *path, const char *args, ...) override + { + nargs = 0; + } + + void chain(const char *msg) override + { + nargs = 0; + } + + void reply(const char *) override { assert(false); } + + void replyArray(const char*, const char *args, + rtosc_arg_t *vals) override + { + size_t cur_idx = 0; + for(const char* ptr = args; *ptr; ++ptr, ++cur_idx) + { + assert(cur_idx < max_args); + arg_vals[cur_idx].type = *ptr; + arg_vals[cur_idx].val = vals[cur_idx]; + } + nargs = cur_idx; + } + + void reply(const char *, const char *args, ...) override + { + va_list va; + va_start(va,args); + + nargs = strlen(args); + assert((size_t)nargs <= max_args); + + rtosc_v2argvals(arg_vals, nargs, args, va); + + va_end(va); + } +public: + //! Return the number of argument values stored + int size() const { return nargs; } + Capture(std::size_t max_args, rtosc_arg_val_t* arg_vals) : + max_args(max_args), arg_vals(arg_vals), nargs(-1) {} +}; + +/** + * @brief Returns a port's current value(s) + * + * This function returns the value(s) of a known port object and stores them as + * rtosc_arg_val_t. + * @param runtime The runtime object + * @param port the port where the value shall be retrieved + * @param loc A buffer where dispatch can write down the currently dispatched + * path + * @param loc_size Size of loc + * @param portname_from_base The name of the port, relative to its base + * @param buffer_with_port A buffer which already contains the port. + * This buffer will be modified and must at least have space for 8 more bytes. + * @param buffersize Size of @p buffer_with_port + * @param max_args Maximum capacity of @p arg_vals + * @param arg_vals Argument buffer for returned argument values + * @return The number of argument values stored in @p arg_vals + */ +static size_t get_value_from_runtime(void* runtime, + const Port& port, + size_t loc_size, + char* loc, + const char* portname_from_base, + char* buffer_with_port, + std::size_t buffersize, + std::size_t max_args, + rtosc_arg_val_t* arg_vals) +{ + strncpy(buffer_with_port, portname_from_base, buffersize); + std::size_t addr_len = strlen(buffer_with_port); + + Capture d(max_args, arg_vals); + d.obj = runtime; + d.loc_size = loc_size; + d.loc = loc; + d.port = &port; + d.matches = 0; + assert(*loc); + + // does the message at least fit the arguments? + assert(buffersize - addr_len >= 8); + // append type + memset(buffer_with_port + addr_len, 0, 8); // cover string end and arguments + buffer_with_port[addr_len + (4-addr_len%4)] = ','; + + // TODO? code duplication + + // buffer_with_port is a message in this call: + d.message = buffer_with_port; + port.cb(buffer_with_port, d); + + assert(d.size() >= 0); + return d.size(); +} + +/* + * default values + */ + +const char* rtosc::get_default_value(const char* port_name, const Ports& ports, + void* runtime, const Port* port_hint, + int32_t idx, int recursive) +{ + constexpr std::size_t buffersize = 1024; + char buffer[buffersize]; + char loc[buffersize] = ""; + + assert(recursive >= 0); // forbid recursing twice + + char default_annotation[20] = "default"; +// if(idx > 0) +// snprintf(default_annotation + 7, 13, "[%" PRId32 "]", idx); + const char* const dependent_annotation = "default depends"; + const char* return_value = nullptr; + + if(!port_hint) + port_hint = ports.apropos(port_name); + assert(port_hint); // port must be found + const Port::MetaContainer metadata = port_hint->meta(); + + // Let complex cases depend upon a marker variable + // If the runtime is available the exact preset number can be found + // This generalizes to envelope types nicely if envelopes have a read + // only port which indicates if they're amplitude/frequency/etc + const char* dependent = metadata[dependent_annotation]; + if(dependent) + { + char* dependent_port = buffer; + *dependent_port = 0; + + assert(strlen(port_name) + strlen(dependent_port) + 5 < buffersize); + strncat(dependent_port, port_name, + buffersize - strlen(dependent_port) - 1); + strncat(dependent_port, "/../", + buffersize - strlen(dependent_port) - 1); + strncat(dependent_port, dependent, + buffersize - strlen(dependent_port) - 1); + dependent_port = Ports::collapsePath(dependent_port); + + // TODO: collapsePath bug? + // Relative paths should not start with a slash after collapsing ... + if(*dependent_port == '/') + ++dependent_port; + + const char* dependent_value = + runtime + ? get_value_from_runtime(runtime, ports, + buffersize, loc, + dependent_port, + buffersize-1, 0) + : get_default_value(dependent_port, ports, + runtime, NULL, recursive-1); + + assert(strlen(dependent_value) < 16); // must be an int + + char* default_variant = buffer; + *default_variant = 0; + assert(strlen(default_annotation) + 1 + 16 < buffersize); + strncat(default_variant, default_annotation, + buffersize - strlen(default_variant)); + strncat(default_variant, " ", buffersize - strlen(default_variant)); + strncat(default_variant, dependent_value, + buffersize - strlen(default_variant)); + + return_value = metadata[default_variant]; + } + + // If return_value is NULL, this can have two meanings: + // 1. there was no depedent annotation + // => check for a direct (non-dependent) default value + // (a non existing direct default value is OK) + // 2. there was a dependent annotation, but the dependent value has no + // mapping (mapping for default_variant was NULL) + // => check for the direct default value, which acts as a default + // mapping for all presets; a missing default value indicates an + // error in the metadata + if(!return_value) + { + return_value = metadata[default_annotation]; + assert(!dependent || return_value); + } + + return return_value; +} + +int rtosc::canonicalize_arg_vals(rtosc_arg_val_t* av, size_t n, + const char* port_args, + Port::MetaContainer meta) +{ + const char* first = port_args; + int errors_found = 0; + + for( ; *first && (*first == ':' || *first == '[' || *first == ']'); + ++first) ; + + for(size_t i = 0; i < n; ++i, ++first, ++av) + { + for( ; *first && (*first == '[' || *first == ']'); ++first) ; + + if(!*first || *first == ':') + { + // (n-i) arguments left, but we have no recipe to convert them + return n-i; + } + + if(av->type == 'S' && *first == 'i') + { + int val = enum_key(meta, av->val.s); + if(val == std::numeric_limits::min()) + ++errors_found; + else + { + av->type = 'i'; + av->val.i = val; + } + } + } + return errors_found; +} + +void rtosc::map_arg_vals(rtosc_arg_val_t* av, size_t n, + Port::MetaContainer meta) +{ + char mapbuf[20] = "map "; + + for(size_t i = 0; i < n; ++i, ++av) + { + if(av->type == 'i') + { + snprintf(mapbuf + 4, 16, "%d", av->val.i); + const char* val = meta[mapbuf]; + if(val) + { + av->type = 'S'; + av->val.s = val; + } + } + } +} + +int rtosc::get_default_value(const char* port_name, const char* port_args, + const Ports& ports, + void* runtime, const Port* port_hint, + int32_t idx, + size_t n, rtosc_arg_val_t* res, + char* strbuf, size_t strbufsize) +{ + const char* pretty = get_default_value(port_name, ports, runtime, port_hint, + idx, 0); + + int nargs; + if(pretty) + { + nargs = rtosc_count_printed_arg_vals(pretty); + assert(nargs > 0); // parse error => error in the metadata? + assert((size_t)nargs < n); + + rtosc_scan_arg_vals(pretty, res, nargs, strbuf, strbufsize); + + { + int errs_found = canonicalize_arg_vals(res, + nargs, + port_args, + port_hint->meta()); + if(errs_found) + fprintf(stderr, "Could not canonicalize %s\n", pretty); + assert(!errs_found); // error in the metadata? + } + } + else + nargs = -1; + + return nargs; +} + +std::string rtosc::get_changed_values(const Ports& ports, void* runtime) +{ + std::string res; + constexpr std::size_t buffersize = 1024; + char port_buffer[buffersize]; + memset(port_buffer, 0, buffersize); // requirement for walk_ports + + const size_t max_arg_vals = 256; + + auto on_reach_port = + [](const Port* p, const char* port_buffer, + const char* port_from_base, const Ports& base, + void* data, void* runtime) + { + assert(runtime); + const Port::MetaContainer meta = p->meta(); + + if((p->name[strlen(p->name)-1] != ':' && !strstr(p->name, "::")) + || meta.find("parameter") == meta.end()) + { + // runtime information can not be retrieved, + // thus, it can not be compared with the default value + return; + } + + char loc[buffersize] = ""; + rtosc_arg_val_t arg_vals_default[max_arg_vals]; + rtosc_arg_val_t arg_vals_runtime[max_arg_vals]; + char buffer_with_port[buffersize]; + char cur_value_pretty[buffersize] = " "; + char strbuf[buffersize]; // temporary string buffer for pretty-printing + + std::string* res = (std::string*)data; + assert(strlen(port_buffer) + 1 < buffersize); + strncpy(loc, port_buffer, buffersize); // TODO: +-1? + + strncpy(buffer_with_port, port_from_base, buffersize); + const char* portargs = strchr(p->name, ':'); + if(!portargs) + portargs = p->name + strlen(p->name); + +#if 0 // debugging stuff + if(!strncmp(port_buffer, "/part1/Penabled", 5) && + !strncmp(port_buffer+6, "/Penabled", 9)) + { + printf("runtime: %ld\n", (long int)runtime); + } +#endif +// TODO: p->name: duplicate to p + int nargs_default = get_default_value(p->name, + portargs, + base, + runtime, + p, + -1, + max_arg_vals, + arg_vals_default, + strbuf, + buffersize); + size_t nargs_runtime = get_value_from_runtime(runtime, + *p, + buffersize, loc, + port_from_base, + buffer_with_port, + buffersize, + max_arg_vals, + arg_vals_runtime); + + if(nargs_default == (int) nargs_runtime) + { + canonicalize_arg_vals(arg_vals_default, nargs_default, + strchr(p->name, ':'), meta); + if(!rtosc_arg_vals_eq(arg_vals_default, + arg_vals_runtime, + nargs_default, + nargs_runtime, + NULL)) + { + map_arg_vals(arg_vals_runtime, nargs_runtime, meta); + rtosc_print_arg_vals(arg_vals_runtime, nargs_runtime, + cur_value_pretty + 1, buffersize - 1, + NULL, strlen(port_buffer) + 1); + + *res += port_buffer; + *res += cur_value_pretty; + *res += "\n"; + } + } + }; + + walk_ports(&ports, port_buffer, buffersize, &res, on_reach_port, + runtime); + + if(res.length()) // remove trailing newline + res.resize(res.length()-1); + return res; +} + +void rtosc::savefile_dispatcher_t::operator()(const char* msg) +{ + *loc = 0; + RtData d; + d.obj = runtime; + d.loc = loc; // we're always dispatching at the base + d.loc_size = 1024; + ports->dispatch(msg, d, true); +} + +int savefile_dispatcher_t::default_response(size_t nargs, + bool first_round, + savefile_dispatcher_t::dependency_t + dependency) +{ + // default implementation: + // no dependencies => round 0, + // has dependencies => round 1, + // not specified => both rounds + return (dependency == not_specified + || !(dependency ^ first_round)) + ? nargs // argument number is not changed + : (int)discard; +} + +int savefile_dispatcher_t::on_dispatch(size_t, char *, + size_t, size_t nargs, + rtosc_arg_val_t *, + bool round2, + dependency_t dependency) +{ + return default_response(nargs, round2, dependency); +} + +int rtosc::dispatch_printed_messages(const char* messages, + const Ports& ports, void* runtime, + savefile_dispatcher_t* dispatcher) +{ + constexpr std::size_t buffersize = 1024; + char portname[buffersize], message[buffersize], strbuf[buffersize]; + int rd, rd_total = 0; + int nargs; + int msgs_read = 0; + + savefile_dispatcher_t dummy_dispatcher; + if(!dispatcher) + dispatcher = &dummy_dispatcher; + dispatcher->ports = &ports; + dispatcher->runtime = runtime; + + // scan all messages twice: + // * in the second round, only dispatch those with ports that depend on + // other ports + // * in the first round, only dispatch all others + for(int round = 0; round < 2 && msgs_read >= 0; ++round) + { + msgs_read = 0; + rd_total = 0; + const char* msg_ptr = messages; + while(*msg_ptr && (msgs_read >= 0)) + { + nargs = rtosc_count_printed_arg_vals_of_msg(msg_ptr); + if(nargs >= 0) + { + // 16 is usually too much, but it allows the user to add + // arguments if necessary + size_t maxargs = 16; + rtosc_arg_val_t arg_vals[maxargs]; + rd = rtosc_scan_message(msg_ptr, portname, buffersize, + arg_vals, nargs, strbuf, buffersize); + rd_total += rd; + + const Port* port = ports.apropos(portname); + savefile_dispatcher_t::dependency_t dependency = + (savefile_dispatcher_t::dependency_t) + (port + ? !!port->meta()["default depends"] + : (int)savefile_dispatcher_t::not_specified); + + // let the user modify the message and the args + // the argument number may have changed, or the user + // wants to discard the message or abort the savefile loading + nargs = dispatcher->on_dispatch(buffersize, portname, + maxargs, nargs, arg_vals, + round, dependency); + + if(nargs == savefile_dispatcher_t::abort) + msgs_read = -rd_total-1; // => causes abort + else + { + if(nargs != savefile_dispatcher_t::discard) + { + rtosc_arg_t vals[nargs]; + char argstr[nargs+1]; + for(int i = 0; i < nargs; ++i) { + vals[i] = arg_vals[i].val; + argstr[i] = arg_vals[i].type; + } + argstr[nargs] = 0; + + rtosc_amessage(message, buffersize, portname, + argstr, vals); + + (*dispatcher)(message); + } + } + + msg_ptr += rd; + ++msgs_read; + } + else if(nargs == std::numeric_limits::min()) + { + // this means the (rest of the) file is whitespace only + // => don't increase msgs_read + while(*++msg_ptr) ; + } + else { + // overwrite meaning of msgs_read in order to + // inform the user where the read error occurred + msgs_read = -rd_total-1; + } + } + } + return msgs_read; +} + +std::string rtosc::save_to_file(const Ports &ports, void *runtime, + const char *appname, rtosc_version appver) +{ + std::string res; + char rtosc_vbuf[12], app_vbuf[12]; + + { + rtosc_version rtoscver = rtosc_current_version(); + rtosc_version_print_to_12byte_str(&rtoscver, rtosc_vbuf); + rtosc_version_print_to_12byte_str(&appver, app_vbuf); + } + + res += "% RT OSC v"; res += rtosc_vbuf; res += " savefile\n" + "% "; res += appname; res += " v"; res += app_vbuf; res += "\n"; + res += get_changed_values(ports, runtime); + + return res; +} + +int rtosc::load_from_file(const char* file_content, + const Ports& ports, void* runtime, + const char* appname, + rtosc_version appver, + savefile_dispatcher_t* dispatcher) +{ + char appbuf[128]; + int bytes_read = 0; + + if(dispatcher) + { + dispatcher->app_curver = appver; + dispatcher->rtosc_curver = rtosc_current_version(); + } + + unsigned vma, vmi, vre; + int n = 0; + + sscanf(file_content, + "%% RT OSC v%u.%u.%u savefile%n ", &vma, &vmi, &vre, &n); + if(n <= 0 || vma > 255 || vmi > 255 || vre > 255) + return -bytes_read-1; + if(dispatcher) + { + dispatcher->rtosc_filever.major = vma; + dispatcher->rtosc_filever.minor = vmi; + dispatcher->rtosc_filever.revision = vre; + } + file_content += n; + bytes_read += n; + n = 0; + + sscanf(file_content, + "%% %128s v%u.%u.%u%n ", appbuf, &vma, &vmi, &vre, &n); + if(n <= 0 || strcmp(appbuf, appname) || vma > 255 || vmi > 255 || vre > 255) + return -bytes_read-1; + + if(dispatcher) + { + dispatcher->app_filever.major = vma; + dispatcher->app_filever.minor = vmi; + dispatcher->app_filever.revision = vre; + } + file_content += n; + bytes_read += n; + n = 0; + + int rval = dispatch_printed_messages(file_content, + ports, runtime, dispatcher); + return (rval < 0) ? (rval-bytes_read) : rval; +} + +/* + * Miscellaneous + */ + const Port *Ports::operator[](const char *name) const { for(const Port &port:ports) { @@ -615,14 +1350,14 @@ const Port *Ports::apropos(const char *path) const ++path; for(const Port &port: ports) - if(strchr(port.name,'/') && rtosc_match_path(port.name,path)) + if(strchr(port.name,'/') && rtosc_match_path(port.name,path, NULL)) return (strchr(path,'/')[1]==0) ? &port : port.ports->apropos(snip(path)); //This is the lowest level, now find the best port for(const Port &port: ports) if(*path && (strstr(port.name, path)==port.name || - rtosc_match_path(port.name, path))) + rtosc_match_path(port.name, path, NULL))) return &port; return NULL; @@ -750,17 +1485,138 @@ MergePorts::MergePorts(std::initializer_list c) refreshMagic(); } -void rtosc::walk_ports(const Ports *base, +/** + * @brief Check if the port @p port is enabled + * @param port The port to be checked. Usually of type rRecur* or rSelf. + * @param loc The absolute path of @p port + * @param loc_size The maximum usable size of @p loc + * @param ports The Ports object containing @p port + * @param runtime TODO + * @return TODO + */ +bool port_is_enabled(const Port* port, char* loc, size_t loc_size, + const Ports& base, void *runtime) +{ + if(port && runtime) + { + const char* enable_port = port->meta()["enabled by"]; + if(enable_port) + { + /* + find out which Ports object to dispatch at + (the current one or its child?) + */ + const char* n = port->name; + const char* e = enable_port; + for( ; *n && (*n == *e) && *n != '/' && *e != '/'; ++n, ++e) ; + + bool subport = (*e == '/' && *n == '/'); + + const char* ask_port_str = subport + ? e+1 + : enable_port; + + const Ports& ask_ports = subport ? *base[port->name]->ports + : base; + + assert(!strchr(ask_port_str, '/')); + const Port* ask_port = ask_ports[ask_port_str]; + assert(ask_port); + + rtosc_arg_val_t rval; + + /* + concatenate the location string + */ + if(subport) + strncat(loc, "/../", loc_size - strlen(loc) - 1); + strncat(loc, enable_port, loc_size - strlen(loc) - 1); + + char* collapsed_loc = Ports::collapsePath(loc); + loc_size -= (collapsed_loc - loc); + +// TODO: collapse, use .. only in one case + /* + receive the "enabled" property + */ + char buf[loc_size]; +#ifdef NEW_CODE + strncpy(buf, collapsed_loc, loc_size); +#else + // TODO: try to use portname_from_base, since Ports might + // also be of type a#N/b + const char* last_slash = strrchr(collapsed_loc, '/'); + strncpy(buf, + last_slash ? last_slash + 1 : collapsed_loc, + loc_size); +#endif + get_value_from_runtime(runtime, *ask_port, + loc_size, collapsed_loc, ask_port_str, + buf, 0, 1, &rval); + assert(rval.type == 'T' || rval.type == 'F'); + return rval.val.T == 'T'; + } + else // Port has no "enabled" property, so it is always enabled + return true; + } + else // no runtime provided, so run statically through all subports + return true; +} + +// TODO: copy the changes into walk_ports_2 +void rtosc::walk_ports(const Ports *base, char *name_buffer, size_t buffer_size, void *data, - port_walker_t walker) + port_walker_t walker, + void* runtime) { + auto walk_ports_recurse = [](const Port& p, char* name_buffer, + size_t buffer_size, const Ports& base, + void* data, port_walker_t walker, + void* runtime, const char* old_end) + { + // TODO: all/most of these checks must also be done for the + // first, non-recursive call + bool enabled = true; + if(runtime) + { + enabled = (p.meta().find("no walk") == p.meta().end()); + if(enabled) + { + // get child runtime and check if it's NULL + RtData r; + r.obj = runtime; + r.port = &p; + + char buf[1024]; + strncpy(buf, old_end, 1024); + strncat(buf, "pointer", 1024 - strlen(buf) - 1); + assert(1024 - strlen(buf) >= 8); + strncpy(buf + strlen(buf) + 1, ",", 2); + + p.cb(buf, r); + runtime = r.obj; // callback has stored the child pointer here + // if there is runtime information, but the pointer is NULL, + // the port is not enabled + enabled = (bool) runtime; + if(enabled) + { + // check if the port is disabled by a switch + enabled = port_is_enabled(&p, name_buffer, buffer_size, + base, runtime); + } + } + } + if(enabled) + rtosc::walk_ports(p.ports, name_buffer, buffer_size, + data, walker, runtime); + }; + //only walk valid ports if(!base) return; - assert(name_buffer); //XXX buffer_size is not properly handled yet if(name_buffer[0] == 0) @@ -769,8 +1625,11 @@ void rtosc::walk_ports(const Ports *base, char *old_end = name_buffer; while(*old_end) ++old_end; + if(port_is_enabled((*base)["self:"], name_buffer, buffer_size, *base, + runtime)) for(const Port &p: *base) { - if(strchr(p.name, '/')) {//it is another tree + //if(strchr(p.name, '/')) {//it is another tree + if(p.ports) {//it is another tree if(strchr(p.name,'#')) { const char *name = p.name; char *pos = old_end; @@ -786,16 +1645,17 @@ void rtosc::walk_ports(const Ports *base, strcat(name_buffer, "/"); //Recurse - rtosc::walk_ports(p.ports, name_buffer, buffer_size, - data, walker); + walk_ports_recurse(p, name_buffer, buffer_size, + *base, data, walker, runtime, old_end); } } else { //Append the path + const char* old_end = name_buffer + strlen(name_buffer); scat(name_buffer, p.name); //Recurse - rtosc::walk_ports(p.ports, name_buffer, buffer_size, - data, walker); + walk_ports_recurse(p, name_buffer, buffer_size, + *base, data, walker, runtime, old_end); } } else { if(strchr(p.name,'#')) { @@ -803,20 +1663,26 @@ void rtosc::walk_ports(const Ports *base, char *pos = old_end; while(*name != '#') *pos++ = *name++; const unsigned max = atoi(name+1); + while(isdigit(*++name)) ; for(unsigned i=0; i::min(); + + for(auto m:meta) + if(strstr(m.title, "map ")) + if(!strcmp(m.value, value)) + { + result = atoi(m.title+4); + break; + } + + return result; +} + static ostream &add_options(ostream &o, Port::MetaContainer meta) { string sym_names = "xyzabcdefghijklmnopqrstuvw"; @@ -1024,7 +1905,8 @@ static ostream &dump_generic_port(ostream &o, string name, string doc, string ty return o; } -void dump_ports_cb(const rtosc::Port *p, const char *name, void *v) +void dump_ports_cb(const rtosc::Port *p, const char *name,const char*, + const Ports&,void *v, void*) { std::ostream &o = *(std::ostream*)v; auto meta = p->meta(); diff --git a/source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp b/source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp index 63d853f58..9042513e4 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp +++ b/source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp @@ -125,7 +125,10 @@ size_t subtree_serialize(char *buffer, size_t buffer_size, //TODO FIXME this is not currently RT safe at the moment - walk_ports(ports, args.v.loc, 128, &args, [](const Port *p, const char *, void *dat) { + walk_ports(ports, args.v.loc, 128, &args, [](const Port *p, const char *, + const char*, + const Ports&, void *dat, + void*) { if(p->meta().find("internal") != p->meta().end()) return; diff --git a/source/native-plugins/zynaddsubfx/rtosc/dispatch.c b/source/native-plugins/zynaddsubfx/rtosc/dispatch.c index 990a641f6..9e15e3174 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/dispatch.c +++ b/source/native-plugins/zynaddsubfx/rtosc/dispatch.c @@ -67,12 +67,15 @@ try_next: return NULL; } -const char *rtosc_match_path(const char *pattern, const char *msg) +const char *rtosc_match_path(const char *pattern, + const char *msg, const char** path_end) { + if(!path_end) + path_end = &msg; // writing *path_end = msg later will have no effect while(1) { //Check for special characters if(*pattern == ':' && !*msg) - return pattern; + return *path_end = msg, pattern; else if(*pattern == '{') { pattern = rtosc_match_options(pattern, &msg); if(!pattern) @@ -88,7 +91,7 @@ const char *rtosc_match_path(const char *pattern, const char *msg) ++pattern; ++msg; if(*pattern == '\0' || *pattern == ':') - return pattern; + return *path_end = msg, pattern; } else if(*pattern == '#') { ++pattern; if(!rtosc_match_number(&pattern, &msg)) @@ -97,7 +100,7 @@ const char *rtosc_match_path(const char *pattern, const char *msg) if(*msg) ++pattern, ++msg; else - return pattern; + return *path_end = msg, pattern; } else return NULL; } @@ -126,9 +129,10 @@ static bool rtosc_match_args(const char *pattern, const char *msg) return arg_match; } -bool rtosc_match(const char *pattern, const char *msg) +bool rtosc_match(const char *pattern, + const char *msg, const char** path_end) { - const char *arg_pattern = rtosc_match_path(pattern, msg); + const char *arg_pattern = rtosc_match_path(pattern, msg, path_end); if(!arg_pattern) return false; else if(*arg_pattern == ':') diff --git a/source/native-plugins/zynaddsubfx/rtosc/port-sugar.h b/source/native-plugins/zynaddsubfx/rtosc/port-sugar.h index 8bb828f2f..0f53f4799 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/port-sugar.h +++ b/source/native-plugins/zynaddsubfx/rtosc/port-sugar.h @@ -22,6 +22,9 @@ * DEALINGS IN THE SOFTWARE. */ +#include +#include + #ifndef RTOSC_PORT_SUGAR #define RTOSC_PORT_SUGAR @@ -61,21 +64,52 @@ struct rtosc_hack_decltype_t #define DOC_I(count, ...) DOC_IMP(count,__VA_ARGS__) #define DOC(...) DOC_I(LAST_IMP(__VA_ARGS__), __VA_ARGS__) -//XXX Currently unused macro -#define MAC_EACH_0(mac, x, ...) INSUFFICIENT_ARGUMENTS_PROVIDED_TO_MAC_EACH -#define MAC_EACH_1(mac, x, ...) mac(x) -#define MAC_EACH_2(mac, x, ...) mac(x) MAC_EACH_1(mac, __VA_ARGS__) -#define MAC_EACH_3(mac, x, ...) mac(x) MAC_EACH_2(mac, __VA_ARGS__) -#define MAC_EACH_4(mac, x, ...) mac(x) MAC_EACH_3(mac, __VA_ARGS__) -#define MAC_EACH_5(mac, x, ...) mac(x) MAC_EACH_4(mac, __VA_ARGS__) -#define MAC_EACH_6(mac, x, ...) mac(x) MAC_EACH_5(mac, __VA_ARGS__) -#define MAC_EACH_7(mac, x, ...) mac(x) MAC_EACH_6(mac, __VA_ARGS__) -#define MAC_EACH_8(mac, x, ...) mac(x) MAC_EACH_7(mac, __VA_ARGS__) -#define MAC_EACH_9(mac, x, ...) mac(x) MAC_EACH_8(mac, __VA_ARGS__) - -#define MAC_EACH_IMP(mac, count, ...) MAC_EACH_ ##count(mac,__VA_ARGS__) -#define MAC_EACH_I(mac, count, ...) MAC_EACH_IMP(mac, count, __VA_ARGS__) -#define MAC_EACH(mac, ...) MAC_EACH_I(mac, LAST_IMP(__VA_ARGS__), __VA_ARGS__) + +#define rINC(x) rINC_ ## x +#define rINC_0 1 +#define rINC_1 2 +#define rINC_2 3 +#define rINC_3 4 +#define rINC_4 5 +#define rINC_5 6 +#define rINC_6 7 +#define rINC_7 8 +#define rINC_8 9 +#define rINC_9 10 +#define rINC_10 11 +#define rINC_11 12 +#define rINC_12 13 +#define rINC_13 14 +#define rINC_14 15 +#define rINC_15 16 + +//Helper for applying macro on varargs +//arguments: counting offset, macro, macro args +#define MAC_EACH_0(o, m, x, ...) INSUFFICIENT_ARGUMENTS_PROVIDED_TO_MAC_EACH +#define MAC_EACH_1(o, m, x, ...) m(o, x) +#define MAC_EACH_2(o, m, x, ...) m(o, x) MAC_EACH_1(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_3(o, m, x, ...) m(o, x) MAC_EACH_2(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_4(o, m, x, ...) m(o, x) MAC_EACH_3(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_5(o, m, x, ...) m(o, x) MAC_EACH_4(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_6(o, m, x, ...) m(o, x) MAC_EACH_5(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_7(o, m, x, ...) m(o, x) MAC_EACH_6(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_8(o, m, x, ...) m(o, x) MAC_EACH_7(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_9(o, m, x, ...) m(o, x) MAC_EACH_8(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_10(o, m, x, ...) m(o, x) MAC_EACH_9(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_11(o, m, x, ...) m(o, x) MAC_EACH_10(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_12(o, m, x, ...) m(o, x) MAC_EACH_11(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_13(o, m, x, ...) m(o, x) MAC_EACH_12(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_14(o, m, x, ...) m(o, x) MAC_EACH_13(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_15(o, m, x, ...) m(o, x) MAC_EACH_14(rINC(o), m, __VA_ARGS__) +#define MAC_EACH_16(o, m, x, ...) m(o, x) MAC_EACH_15(rINC(o), m, __VA_ARGS__) + +#define MAC_EACH_IMP(off, mac, count, ...) \ + MAC_EACH_ ##count(off, mac,__VA_ARGS__) +#define MAC_EACH_I(off, mac, count, ...) \ + MAC_EACH_IMP(off, mac, count, __VA_ARGS__) +#define MAC_EACH_OFF(off, mac, ...) \ + MAC_EACH_I(off, mac, LAST_IMP(__VA_ARGS__), __VA_ARGS__) +#define MAC_EACH(mac, ...) MAC_EACH_OFF(0, mac, __VA_ARGS__) // 1 2 3 4 5 6 7 8 910111213141516 #define OPTIONS_IMP16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \ @@ -140,7 +174,7 @@ struct rtosc_hack_decltype_t #define rToggle(name, ...) \ {STRINGIFY(name) "::T:F",rProp(parameter) DOC(__VA_ARGS__), NULL, rToggleCb(name)} #define rOption(name, ...) \ - {STRINGIFY(name) "::i:c",rProp(parameter) rProp(enumerated) DOC(__VA_ARGS__), NULL, rOptionCb(name)} + {STRINGIFY(name) "::i:c:S",rProp(parameter) rProp(enumerated) DOC(__VA_ARGS__), NULL, rOptionCb(name)} //Array operators #define rArrayF(name, length, ...) \ @@ -151,6 +185,8 @@ struct rtosc_hack_decltype_t {STRINGIFY(name) "#" STRINGIFY(length) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayTCb(name)} #define rArrayI(name, length, ...) \ {STRINGIFY(name) "#" STRINGIFY(length) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayICb(name)} +#define rArrayOption(name, length, ...) \ +{STRINGIFY(name) "#" STRINGIFY(length) "::i:c:S", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayOptionCb(name)} //Method callback Actions @@ -191,8 +227,23 @@ template constexpr T spice(T*t) {return *t;} //{STRINGIFY(name) ":", rProp(internal), NULL, rRecurPtrCb(name)} +//let this recurring parameter depend on another port +#define rEnabledBy(portname) rMap(enabled by, portname) +#define rEnabledByCondition(cond_name) rEnabledBy(cond_name) +#define rEnabledCondition(cond_name, condition) \ + {STRINGIFY(cond_name) ":", rProp(internal), NULL, rEnabledIfCb(condition)} +#define rEnabledIfCb(condition) rBOIL_BEGIN \ + assert(!rtosc_narguments(msg)); \ + data.reply(loc, (condition)?"T":"F"); \ + rBOIL_END \ + +#define rSelf(type, ...) \ +{"self:", rProp(internal) rMap(class, type) __VA_ARGS__ rDoc("port metadata"), 0, \ + [](const char *, rtosc::RtData &d){ \ + d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\ + //Misc -#define rDummy(name, ...) {STRINIFY(name), rProp(dummy), NULL, [](msg_t, rtosc::RtData &){}} +#define rDummy(name, ...) {STRINGIFY(name), rProp(dummy), NULL, [](msg_t, rtosc::RtData &){}} #define rString(name, len, ...) \ {STRINGIFY(name) "::s", rMap(length, len) rProp(parameter) DOC(__VA_ARGS__), NULL, rStringCb(name,len)} @@ -208,6 +259,21 @@ template constexpr T spice(T*t) {return *t;} #define rSpecial(doc) ":special\0" STRINGIFY(doc) "\0" #define rCentered ":centered\0" +//Default values +#define rDefault(default_value_) rMap(default, default_value_) +#define rDefaultId(default_value_) ":default\0=\"" STRINGIFY(default_value_) "\"S\0" +//#define rDefaultArr(default_value_, idx_) rMap(default[idx_], default_value_) +#define rPreset(no, default_value) \ + ":default " STRINGIFY(no) "\0=" STRINGIFY(default_value) "\0" +#define rPresetsAt(offs, ...) MAC_EACH_OFF(offs, rPreset, __VA_ARGS__) +#define rPresets(...) rPresetsAt(0, __VA_ARGS__) +#define rDefaultDepends(dep_path_) rMap(default depends, dep_path_) +#define rDefaultMissing "" // macro to denote yet missing default values +//#define rNoDefaults() ":no defaults\0" //!< this port (and all children) have no defaults +//! @brief Denote that this port and its children must always be skipped from +//! port-walking if a runtime is being given. +#define rNoWalk rProp(no walk) + //Misc properties #define rDoc(doc) ":documentation\0=" doc "\0" #define rOpt(numeric,symbolic) rMap(map numeric, symbolic) @@ -228,14 +294,16 @@ template constexpr T spice(T*t) {return *t;} #define rBOIL_END } #define rLIMIT(var, convert) \ - if(prop["min"] && var < (decltype(var))convert(prop["min"])) \ + if(prop["min"] && var < convert(prop["min"])) \ var = convert(prop["min"]);\ - if(prop["max"] && var > (decltype(var))convert(prop["max"])) \ + if(prop["max"] && var > convert(prop["max"])) \ var = convert(prop["max"]); #define rTYPE(n) decltype(obj->n) -#define rAPPLY(n,t) if(obj->n != var) data.reply("undo_change", "s" #t #t, data.loc, obj->n, var); obj->n = var; +//#define rAPPLY(n,t) if(obj->n != var) data.reply("undo_change", "s" #t #t, data.loc, obj->n, var); obj->n = var; +#define rCAPPLY(getcode, t, setcode) if(getcode != var) data.reply("undo_change", "s" #t #t, data.loc, getcode, var); setcode; +#define rAPPLY(n,t) rCAPPLY(obj->n, t, obj->n = var) #define rParamCb(name) rBOIL_BEGIN \ if(!strcmp("", args)) {\ @@ -270,17 +338,40 @@ template constexpr T spice(T*t) {return *t;} rChangeCb \ } rBOIL_END -//TODO finish me (include string mapper action?) +#define rCOptionCb_(getcode, setcode) { \ + if(!strcmp("", args)) {\ + data.reply(loc, "i", getcode); \ + } else if(!strcmp("s", args) || !strcmp("S", args)) { \ + auto var = \ + enum_key(prop, rtosc_argument(msg, 0).s); \ + /* make sure we have no out-of-bound options */ \ + assert(!prop["min"] || \ + var >= atoi(prop["min"])); \ + assert(!prop["max"] || \ + var <= atoi(prop["max"])); \ + rCAPPLY(getcode, i, setcode) \ + data.broadcast(loc, "i", getcode); \ + rChangeCb \ + } else {\ + auto var = \ + rtosc_argument(msg, 0).i; \ + rLIMIT(var, atoi) \ + rCAPPLY(getcode, i, setcode) \ + data.broadcast(loc, rtosc_argument_string(msg), getcode);\ + rChangeCb \ + } \ + } + +#define rOptionCb_(name) rCOptionCb_(obj->name, obj->name = var) + #define rOptionCb(name) rBOIL_BEGIN \ - if(!strcmp("", args)) {\ - data.reply(loc, "i", obj->name); \ - } else { \ - rTYPE(name) var = rtosc_argument(msg, 0).i; \ - rLIMIT(var, atoi) \ - rAPPLY(name, i) \ - data.broadcast(loc, rtosc_argument_string(msg), obj->name);\ - rChangeCb \ - } rBOIL_END + rOptionCb_(name) \ + rBOIL_END + +#define rCOptionCb(getcode, setcode) rBOIL_BEGIN \ + rCOptionCb_(getcode, setcode) \ + rBOIL_END + #define rToggleCb(name) rBOIL_BEGIN \ if(!strcmp("", args)) {\ @@ -309,8 +400,8 @@ template constexpr T spice(T*t) {return *t;} rBOIL_END #define rRecurpCb(name) rBOIL_BEGIN \ - if(obj->name == NULL) return; \ data.obj = obj->name; \ + if(obj->name == NULL) return; \ SNIP \ decltype(spice(rObject::name))::ports.dispatch(msg, data); \ rBOIL_END @@ -373,6 +464,18 @@ template constexpr T spice(T*t) {return *t;} obj->name[idx] = rtosc_argument(msg, 0).T; \ } rBOILS_END +#define rArrayTCbMember(name, member) rBOILS_BEGIN \ + if(!strcmp("", args)) {\ + data.reply(loc, obj->name[idx].member ? "T" : "F"); \ + } else { \ + if(obj->name[idx].member != rtosc_argument(msg, 0).T) { \ + data.broadcast(loc, args);\ + rChangeCb \ + } \ + obj->name[idx].member = rtosc_argument(msg, 0).T; \ + } rBOILS_END + + #define rArrayICb(name) rBOILS_BEGIN \ if(!strcmp("", args)) {\ data.reply(loc, "i", obj->name[idx]); \ @@ -384,6 +487,11 @@ template constexpr T spice(T*t) {return *t;} rChangeCb \ } rBOILS_END + +#define rArrayOptionCb(name) rBOILS_BEGIN \ + rOptionCb_(name[idx]) \ + rBOILS_END + #define rParamsCb(name, length) rBOIL_BEGIN \ data.reply(loc, "b", length, obj->name); rBOIL_END @@ -391,7 +499,8 @@ template constexpr T spice(T*t) {return *t;} if(!strcmp("", args)) {\ data.reply(loc, "s", obj->name); \ } else { \ - strncpy(obj->name, rtosc_argument(msg, 0).s, length); \ + strncpy(obj->name, rtosc_argument(msg, 0).s, length-1); \ + obj->name[length-1] = '\0'; \ data.broadcast(loc, "s", obj->name);\ rChangeCb \ } rBOIL_END diff --git a/source/native-plugins/zynaddsubfx/rtosc/ports.h b/source/native-plugins/zynaddsubfx/rtosc/ports.h index 65a7dc2e4..2eb6aa83a 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/ports.h +++ b/source/native-plugins/zynaddsubfx/rtosc/ports.h @@ -22,6 +22,10 @@ * DEALINGS IN THE SOFTWARE. */ +/** + * @file ports.h + */ + #ifndef RTOSC_PORTS #define RTOSC_PORTS @@ -29,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -43,25 +48,41 @@ typedef const char *msg_t; struct Port; struct Ports; +//! data object for the dispatch routine struct RtData { RtData(void); + /** + * @brief location of where the dispatch routine is currently being called + * + * If non-NULL, the dispatch routine will update the port name here while + * walking through the Ports tree + */ char *loc; size_t loc_size; - void *obj; - int matches; - const Port *port; + void *obj; //!< runtime object to dispatch this object to + int matches; //!< number of matches returned from dispatch routine + const Port *port; //!< dispatch will write the matching port's pointer here + //! @brief Will be set to point to the full OSC message in case of + //! a base dispatch const char *message; + int idx[16]; + void push_index(int ind); + void pop_index(void); + virtual void replyArray(const char *path, const char *args, rtosc_arg_t *vals); virtual void reply(const char *path, const char *args, ...); + //!Reply if information has been requested virtual void reply(const char *msg); virtual void chain(const char *path, const char *args, ...); + //!Bypass message to some kind of backend if the message can not be handled virtual void chain(const char *msg); virtual void chainArray(const char *path, const char *args, rtosc_arg_t *vals); + //!Transmit initialization/change of a value to all listeners virtual void broadcast(const char *path, const char *args, ...); virtual void broadcast(const char *msg); virtual void broadcastArray(const char *path, const char *args, @@ -75,10 +96,10 @@ struct RtData * Port in rtosc dispatching hierarchy */ struct Port { - const char *name; //< Pattern for messages to match - const char *metadata;//< Statically accessable data about port - const Ports *ports; //< Pointer to further ports - std::function cb;//< Callback for matching functions + const char *name; //!< Pattern for messages to match + const char *metadata;//!< Statically accessable data about port + const Ports *ports; //!< Pointer to further ports + std::function cb;//!< Callback for matching functions class MetaIterator { @@ -92,6 +113,7 @@ struct Port { bool operator==(MetaIterator a) {return title == a.title;} bool operator!=(MetaIterator a) {return title != a.title;} MetaIterator& operator++(void); + operator bool() const; const char *title; const char *value; @@ -107,6 +129,8 @@ struct Port { MetaIterator find(const char *str) const; size_t length(void) const; + //!Return the key to the value @p str, or NULL if the key is + //!invalid or if there's no value for that key. const char *operator[](const char *str) const; const char *str_ptr; @@ -119,6 +143,7 @@ struct Port { else return MetaContainer(metadata); } + }; /** @@ -159,9 +184,13 @@ struct Ports * Dispatches message to all matching ports. * This uses simple pattern matching available in rtosc::match. * - * @param m a valid OSC message + * @param m A valid OSC message. Note that the address part shall not + * contain any type specifier. * @param d The RtData object shall contain a path buffer (or null), the length of - * the buffer, a pointer to data. + * the buffer, a pointer to data. It must also contain the location + * if an answer is being expected. + * @param base_dispatch Whether the OSC path is to be interpreted as a full + * OSC path beginning at the root */ void dispatch(const char *m, RtData &d, bool base_dispatch=false) const; @@ -215,7 +244,7 @@ struct ClonePort struct ClonePorts:public Ports { ClonePorts(const Ports &p, - std::initializer_list c); + std::initializer_list c); }; struct MergePorts:public Ports @@ -223,18 +252,235 @@ struct MergePorts:public Ports MergePorts(std::initializer_list c); }; +/** + * @brief Returns a port's default value + * + * Returns the default value of a given port, if any exists, as a string. + * For the parameters, see the overloaded function. + * @note The recursive parameter should never be specified. + * @return The default value(s), pretty-printed, or NULL if there is no + * valid default annotation + */ +const char* get_default_value(const char* port_name, const Ports& ports, + void* runtime, const Port* port_hint = NULL, + int32_t idx = -1, int recursive = 1); + +/** + * @brief Returns a port's default value + * + * Returns the default value of a given port, if any exists, as an array of + * rtosc_arg_vals . The values in the resulting array are being canonicalized, + * i.e. mapped values are being converted to integers; see + * canonicalize_arg_vals() . + * + * @param port_name the port's OSC path. + * @param port_args the port's arguments, e.g. '::i:c:S' + * @param ports the ports where @a portname is to be searched + * @param runtime object holding @a ports . Optional. Helps finding + * default values dependent on others, such as presets. + * @param port_hint The port itself corresponding to portname (including + * the args). If not specified, will be found using @p portname . + * @param idx If the port is an array (using the '#' notation), this specifies + * the index required for the default value + * @param n Size of the output parameter @res . This size can not be known, + * so you should provide a large enough array. + * @param res The output parameter for the argument values. + * @param strbuf String buffer for storing pretty printed strings and blobs. + * @param strbufsize Size of @p strbuf + * @return The actual number of aruments written to @p res (can be smaller + * than @p n) or -1 if there is no valid default annotation + */ +int get_default_value(const char* port_name, const char *port_args, + const Ports& ports, + void* runtime, const Port* port_hint, + int32_t idx, + size_t n, rtosc_arg_val_t* res, + char *strbuf, size_t strbufsize); + + +/** + * @brief Return a string list of all changed values + * + * Return a human readable list of the value that changed + * corresponding to the rDefault macro + * @param ports The static ports structure + * @param runtime The runtime object + * @return The list of ports and their changed values, linewise + */ +std::string get_changed_values(const Ports& ports, void* runtime); + +//! @brief Class to modify messages loaded from savefiles +//! +//! Object of this class shall be passed to savefile loading routines. You can +//! inherit to change the behaviour, e.g. to modify or discard such messages. +class savefile_dispatcher_t +{ + const Ports* ports; + void* runtime; + char loc[1024]; + +protected: + enum proceed { + abort = -2, //!< the message shall lead to abort the savefile loading + discard = -1 //!< the message shall not be dispatched + }; + + enum dependency_t { + no_dependencies, //! default values don't depend on others + has_dependencies, //! default values do depend on others + not_specified //! it's not know which of the other enum values fit + }; + + rtosc_version rtosc_filever, //!< rtosc versinon savefile was written with + rtosc_curver, //!< rtosc version of this library + app_filever, //!< app version savefile was written with + app_curver; //!< current app version + + //! call this to dispatch a message + void operator()(const char* msg); + + static int default_response(size_t nargs, bool first_round, + dependency_t dependency); + +private: + //! callback for when a message shall be dispatched + //! implement this if you need to change a message + virtual int on_dispatch(size_t portname_max, char* portname, + size_t maxargs, size_t nargs, + rtosc_arg_val_t* args, + bool round2, dependency_t dependency); + + friend int dispatch_printed_messages(const char* messages, + const Ports& ports, void* runtime, + savefile_dispatcher_t *dispatcher); + + friend int load_from_file(const char* file_content, + const Ports& ports, void* runtime, + const char* appname, + rtosc_version appver, + savefile_dispatcher_t* dispatcher); +}; + +/** + * @brief Scan OSC messages from human readable format and dispatch them + * + * @param messages The OSC messages, whitespace-separated + * @param ports The static ports structure + * @param runtime The runtime object + * @param dispatcher Object to modify messages prior to dispatching, or NULL. + * You can overwrite its virtual functions, and you should specify any of the + * version structs if needed. All other members shall not be initialized. + * @return The number of messages read, or, if there was a read error, + * the number of bytes read until the read error occured minus one + */ +int dispatch_printed_messages(const char* messages, + const Ports& ports, void* runtime, + savefile_dispatcher_t *dispatcher = NULL); + +/** + * @brief Return a savefile containing all values that differ from the default + * values. + * + * @param ports The static ports structure + * @param runtime The runtime object + * @param appname Name of the application calling this function + * @param appver Version of the application calling this function + * @return The resulting savefile as an std::sting + */ +std::string save_to_file(const Ports& ports, void* runtime, + const char* appname, rtosc_version appver); + +/** + * @brief Read save file and dispatch contained parameters + * + * @param file_content The file as a C string + * @param ports The static ports structure + * @param runtime The runtime object + * @param appname Name of the application calling this function; must + * match the file's application name + * @param appver Version of the application calling this function + * @param dispatcher Modifier for the messages; NULL if no modifiers are needed + * @return The number of messages read, or, if there was a read error, + * the negated number of bytes read until the read error occured minus one + */ +int load_from_file(const char* file_content, + const Ports& ports, void* runtime, + const char* appname, + rtosc_version appver, + savefile_dispatcher_t* dispatcher = NULL); + +/** + * @brief Convert given argument values to their canonical representation, e.g. + * to the ports first (or-wise) argument types. + * + * E.g. if passing two 'S' argument values, the + * port could be `portname::ii:cc:SS` or `portname::ii:t`. + * + * @param av The input and output argument values + * @param n The size of @p av + * @param port_args The port arguments string, e.g. `::i:c:s`. The first + * non-colon letter sequence marks the canonical types + * @param meta The port's metadata container + * @return The number of argument values that should have need conversion, + * but failed, e.g. because of values missing in rMap. + */ +int canonicalize_arg_vals(rtosc_arg_val_t* av, size_t n, + const char* port_args, Port::MetaContainer meta); + +/** + * @brief Converts each of the given arguments to their mapped symbol, if + * possible + * @param av The input and output argument values + * @param n The size of @p av + * @param meta The port's metadata container + */ +void map_arg_vals(rtosc_arg_val_t* av, size_t n, + Port::MetaContainer meta); /********************* * Port walking code * *********************/ //typedef std::function port_walker_t; -typedef void(*port_walker_t)(const Port*,const char*,void*); +/** + * @brief function pointer type for port walking + * + * accepts: + * - the currently walked port + * - the port's absolute location + * - the part of the location which makes up the port; this is usually the + * location's substring after the last slash, but it can also contain multiple + * slashes + * - the port's base, i.e. it's parent Ports struct + * - the custom data supplied to walk_ports + * - the runtime object (which may be NULL if not known) + */ +typedef void(*port_walker_t)(const Port*,const char*,const char*, + const Ports&,void*,void*); +/** + * @brief Call a function on all ports and subports + * @param base The base port of traversing + * @param name_buffer Buffer which will be filled with the port name; must be + * reset to zero over the full length! + * @param buffer_size Size of name_buffer + * @param data Data that should be available in the callback + * @param walker Callback function + */ void walk_ports(const Ports *base, - char *name_buffer, - size_t buffer_size, - void *data, - port_walker_t walker); + char *name_buffer, + size_t buffer_size, + void *data, + port_walker_t walker, + void *runtime = NULL); + +/** + * @brief Return the index with value @p value from the metadata's enumeration + * @param meta The metadata + * @param value The value to search the key for + * @return The first key holding value, or `std::numeric_limits::min()` + * if none was found + */ +int enum_key(Port::MetaContainer meta, const char* value); /********************* * Port Dumping code * diff --git a/source/native-plugins/zynaddsubfx/rtosc/pretty-format.c b/source/native-plugins/zynaddsubfx/rtosc/pretty-format.c new file mode 100644 index 000000000..a34ed3512 --- /dev/null +++ b/source/native-plugins/zynaddsubfx/rtosc/pretty-format.c @@ -0,0 +1,1108 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** Call snprintf and assert() that it did fit into the buffer */ +static int asnprintf(char* str, size_t size, const char* format, ...) +{ + va_list args; + va_start(args, format); + int written = vsnprintf(str, size, format, args); + assert(written >= 0); // no error + // snprintf(3) says that a return value of size or more bytes means + // that the output has been truncated + assert((size_t)written < size); + va_end(args); + return written; +} + +static const rtosc_print_options* default_print_options + = &((rtosc_print_options) { true, 2, " ", 80}); + +/** + * Return the char that represents the escape sequence + * + * @param c The escape sequence, e.g. '\n' + * @param chr True if the character appears in a single character + * (vs in a string) + * @return The character describing the escape sequence, e.g. 'n'; + * -1 if none exists + */ +static int as_escaped_char(int c, int chr) +{ + switch(c) + { + case '\a': return 'a'; + case '\b': return 'b'; + case '\t': return 't'; + case '\n': return 'n'; + case '\v': return 'v'; + case '\f': return 'f'; + case '\r': return 'r'; + case '\\': return '\\'; + default: + if(chr && c == '\'') + return '\''; + else if(!chr && c == '"') + return '"'; + else return -1; + } +} + +// internal function for rtosc_print_arg_val +static void break_string(char** buffer, size_t bs, int wrt, int* cols_used) +{ + // unquoted, this means: "\ " + int tmp = asnprintf(*buffer, bs, "\"\\\n \""); + wrt += tmp; + *buffer += tmp; + *cols_used = 5; +} + +size_t rtosc_print_arg_val(const rtosc_arg_val_t *arg, + char *buffer, size_t bs, + const rtosc_print_options* opt, + int *cols_used) +{ + size_t wrt = 0; + if(!opt) + opt = default_print_options; + assert(arg); + const rtosc_arg_t* val = &arg->val; + + switch(arg->type) { + case 'T': + assert(bs>4); + strncpy(buffer, "true", bs); + wrt = 4; + break; + case 'F': + assert(bs>5); + strncpy(buffer, "false", bs); + wrt = 5; + break; + case 'N': + assert(bs>3); + strncpy(buffer, "nil", bs); + wrt = 3; + break; + case 'I': + assert(bs>3); + strncpy(buffer, "inf", bs); + wrt = 3; + break; + case 'h': + wrt = asnprintf(buffer, bs, "%"PRId64"h", val->h); + break; + case 't': // write to ISO 8601 date + { + if(val->t == 1) + wrt = asnprintf(buffer, bs, "immediately"); + else + { + time_t t = (time_t)(val->t >> 32); + int32_t secfracs = val->t & (0xffffffff); + struct tm* m_tm = localtime(&t); + + const char* strtimefmt = (secfracs || m_tm->tm_sec) + ? "%Y-%m-%d %H:%M:%S" + : (m_tm->tm_hour || m_tm->tm_min) + ? "%Y-%m-%d %H:%M" + : "%Y-%m-%d"; + + wrt = strftime(buffer, bs, strtimefmt, m_tm); + assert(wrt); + + if(secfracs) + { + int rd = 0; + int prec = opt->floating_point_precision; + assert(prec>=0); + assert(prec<100); + + // convert fractions -> float + char lossless[16]; + asnprintf(lossless, 16, "0x%xp-32", secfracs); + float flt; + sscanf(lossless, "%f%n", &flt, &rd); + assert(rd); + + // append float + char fmtstr[8]; + asnprintf(fmtstr, 5, "%%.%df", prec); + int lastwrt = wrt; + wrt += asnprintf(buffer + wrt, bs - wrt, + fmtstr, flt); + // snip part before separator + const char* sep = strchr(buffer + lastwrt, '.'); + assert(sep); + memmove(buffer + lastwrt, sep, strlen(sep)+1); + wrt -= (sep - (buffer + lastwrt)); + + if(opt->lossless) + wrt += asnprintf(buffer + wrt, bs - wrt, + " (...+%as)", flt); + } // if secfracs + } // else + break; + } + case 'r': + wrt = asnprintf(buffer, bs, "#%02x%02x%02x%02x", + (val->i >> 24) & 0xff, + (val->i >> 16) & 0xff, + (val->i >> 8) & 0xff, + val->i & 0xff + ); + break; + case 'd': + case 'f': + { + int prec = opt->floating_point_precision; + assert(prec>=0); + assert(prec<100); + char fmtstr[9]; + if(arg->type == 'f') + { + // e.g. "%.42f" or "%.0f.": + asnprintf(fmtstr, 6, "%%#.%df", prec); + wrt = asnprintf(buffer, bs, fmtstr, val->f); + if(opt->lossless) + wrt += asnprintf(buffer + wrt, bs - wrt, + " (%a)", val->f); + } + else + { + // e.g. "%.42lfd" or "%.0lf.d" + asnprintf(fmtstr, 8, "%%#.%dlfd", prec); + wrt = asnprintf(buffer, bs, fmtstr, val->d); + if(opt->lossless) + wrt += asnprintf(buffer + wrt, bs - wrt, + " (%la)", val->d); + } + break; + } + case 'c': + { + int is_esc = (as_escaped_char(val->i, true) != -1); + wrt = asnprintf(buffer, bs, "'%s%c'", + is_esc ? "\\" : "", + is_esc ? as_escaped_char(val->i, true) + : val->i); + break; + } + case 'i': + wrt = asnprintf(buffer, bs, "%"PRId32, val->i); + break; + case 'm': + wrt = asnprintf(buffer, bs, "MIDI [0x%02x 0x%02x 0x%02x 0x%02x]", + val->m[0], val->m[1], val->m[2], val->m[3]); + break; + case 's': + case 'S': + { + bool plain; // e.g. without quotes + if(arg->type == 'S') + { + plain = true; // "Symbol": are quotes required? + if(*val->s != '_' && !isalpha(*val->s)) + plain = false; + else for(const char* s = val->s + 1; *s && plain; ++s) + plain = (*s == '_' || (isalnum(*s))); + } + else plain = false; + + if(plain) + { + wrt = asnprintf(buffer, bs, "%s", val->s); + break; + } + else + { + char* b = buffer; + *b++ = '"'; + for(const char* s = val->s; *s; ++s) + { + if(*cols_used >= opt->linelength - 2) + break_string(&b, bs, wrt, cols_used); + assert(bs); + int as_esc = as_escaped_char(*s, false); + if(as_esc != -1) { + assert(bs-1); + *b++ = '\\'; + *b++ = as_esc; + *cols_used += 2; + if(as_esc == 'n') + break_string(&b, bs, wrt, cols_used); + } + else { + *b++ = *s; + ++*cols_used; + } + } + assert(bs >= 2); + *b++ = '"'; + if(arg->type == 'S') { + assert(bs >= 2); + *b++ = 'S'; + } + *b = 0; + wrt += (b-buffer); + break; + } + } + case 'b': + wrt = asnprintf(buffer, bs, "[%d ", val->b.len); + *cols_used += wrt; + buffer += wrt; + for(int32_t i = 0; i < val->b.len; ++i) + { + if(*cols_used >= opt->linelength - 6) + { + int tmp = asnprintf(buffer-1, bs+1, "\n "); + wrt += (tmp-1); + buffer += (tmp-1); + *cols_used = 4; + } + wrt += asnprintf(buffer, bs, "0x%02x ", val->b.data[i]); + bs -= 5; + buffer += 5; + *cols_used += 5; + } + buffer[-1] = ']'; + break; + default: + ; + } + + switch(arg->type) + { + case 's': + case 'b': + // these can break the line, so they compute *cols_used themselves + break; + default: + *cols_used += wrt; + } + + return wrt; +} + +size_t rtosc_print_arg_vals(const rtosc_arg_val_t *args, size_t n, + char *buffer, size_t bs, + const rtosc_print_options *opt, int cols_used) +{ + size_t wrt=0; + int args_written_this_line = (cols_used) ? 1 : 0; + if(!opt) + opt = default_print_options; + size_t sep_len = strlen(opt->sep); + char* last_sep = buffer - 1; + for(size_t i = 0; i < n; ++i) + { + size_t tmp = rtosc_print_arg_val(args++, buffer, bs, opt, &cols_used); + + wrt += tmp; + buffer += tmp; + bs -= tmp; + ++args_written_this_line; + // did we break the line length, + // and this is not the first arg written in this line? + if(cols_used > opt->linelength && (args_written_this_line > 1)) + { + // insert "\n " + *last_sep = '\n'; + assert(bs >= 4); + memmove(last_sep+5, last_sep+1, tmp); + last_sep[1] = last_sep[2] = last_sep[3] = last_sep[4] = ' '; + cols_used = 4 + wrt; + wrt += 4; + buffer += 4; + bs -= 4; + args_written_this_line = 0; + } + if(isep, bs); + cols_used += sep_len; + wrt += sep_len; + buffer += sep_len; + bs -= sep_len; + } + } + return wrt; +} + +size_t rtosc_print_message(const char* address, + const rtosc_arg_val_t *args, size_t n, + char *buffer, size_t bs, + const rtosc_print_options* opt, + int cols_used) +{ + size_t wrt = asnprintf(buffer, bs, "%s ", address); + cols_used += wrt; + buffer += wrt; + bs -= wrt; + wrt += rtosc_print_arg_vals(args, n, buffer, bs, opt, cols_used); + return wrt; +} + +/** + * Increase @p s while property @property is true and the end has not yet + * been reached + */ +static void skip_while(const char** s, int (*property)(int)) +{ + for(;**s && (*property)(**s);++*s); +} + +/** + * Parse the string pointed to by @p src conforming to the format string @p + * @param src Pointer to the input string + * @param fmt Format string for sscanf(). Must suppress all assignments, + * except the last one, which must be "%n" and be at the string's end. + * @return The number of bytes skipped from the string pointed to by @p src + */ +static int skip_fmt(const char** src, const char* fmt) +{ + assert(!strncmp(fmt + strlen(fmt) - 2, "%n", 2)); + int rd = 0; + sscanf(*src, fmt, &rd); + *src += rd; + return rd; +} + +/** + * Behave like skip_fmt() , but set *src to NULL if the string didn't match + * @see skip_fmt + */ +static int skip_fmt_null(const char** src, const char* fmt) +{ + int result = skip_fmt(src, fmt); + if(!result) + *src = NULL; + return result; +} + +/** Helper function for scanf_fmtstr() */ +static const char* try_fmt(const char* src, int exp, const char* fmt, + char* typesrc, char type) +{ + int rd = 0; + sscanf(src, fmt, &rd); + if(rd == exp) + { + *typesrc = type; + return fmt; + } + else + return NULL; +} + +/** + * Return the right format string for skipping the next numeric value + * + * This can be used to find out how to sscanf() ints, floats and doubles. + * If the string needs to be read, too, see scanf_fmtstr_scan() below. + * @param src The beginning of the numeric value to scan + * @param type If non-NULL, the corresponding rtosc argument character + * (h,i,f,d) will be written here + * @return The format string to use or NULL + */ +static const char* scanf_fmtstr(const char* src, char* type) +{ + const char* end = src; + // skip to string end, word end or a closing paranthesis + for(;*end && !isspace(*end) && (*end != ')');++end); + + int exp = end - src; + + // store type byte in the parameter, or in a temporary variable? + char tmp; + char* _type = type ? type : &tmp; + + const char i32[] = "%*"PRIi32"%n"; + + const char* r; // result + int ok = (r = try_fmt(src, exp, "%*"PRIi64"h%n", _type, 'h')) + || (r = try_fmt(src, exp, "%*d%n", _type, 'i')) + || (r = try_fmt(src, exp, "%*"PRIi32"i%n", _type, 'i')) + || (r = try_fmt(src, exp, i32, _type, 'i')) + || (r = try_fmt(src, exp, "%*lfd%n", _type, 'd')) + || (r = try_fmt(src, exp, "%*ff%n", _type, 'f')) + || (r = try_fmt(src, exp, "%*f%n", _type, 'f')); + (void)ok; + if(r == i32) + r = "%*x%n"; + return r; +} + +/** Return the right format string for reading the next numeric value */ +static const char* scanf_fmtstr_scan(const char* src, char* bytes8, + char* type) +{ + const char *buf = scanf_fmtstr(src, type); + assert(buf); + assert(bytes8); + strncpy(bytes8, buf, 8); + *++bytes8 = '%'; // transform "%*" to "%" + return bytes8; +} + +/** Skip the next numeric at @p src */ +static size_t skip_numeric(const char** src, char* type) +{ + const char* scan_str = scanf_fmtstr(*src, type); + if(!scan_str) return 0; + else return skip_fmt(src, scan_str); +} + +/** + * Return the escape sequence that's generated with the given character + * @param c The character, e.g. 'n' + * @param chr True if the character appears in a single character + * (vs in a string) + * @return The escape sequence generated by the character, e.g. '\n'; + * 0 if none exists + */ +static char get_escaped_char(char c, int chr) +{ + switch(c) + { + case 'a': return '\a'; + case 'b': return '\b'; + case 't': return '\t'; + case 'n': return '\n'; + case 'v': return '\v'; + case 'f': return '\f'; + case 'r': return '\r'; + case '\\': return '\\'; + default: + if(chr && c == '\'') + return '\''; + else if(!chr && c == '"') + return '"'; + else + return 0; + } +} + +/** Called inside a string at @p src, skips until after the closing quote */ +static const char* end_of_printed_string(const char* src) +{ + bool escaped = false; + ++src; + bool cont; + do + { + for(; *src && (escaped || *src != '"') ; ++src) + { + if(escaped) // last char introduced an escape sequence? + { + if(!get_escaped_char(*src, false)) + return NULL; // bad escape sequence + } + escaped = (*src == '\\') ? (!escaped) : false; + } + if(*src == '"' && src[1] == '\\') { + skip_fmt_null(&src, "\"\\ \"%n"); + cont = true; + } + else + cont = false; + } while(cont); + if(!src || !*src) + return NULL; + return ++src; +} + +/** + * Skips string @p exp at the current string pointed to by @p str, + * but only if it's a separated word, i.e. if there's a char after the string, + * it mus be a slash or whitespace. + * + * @return The position after the word, or NULL if the word was not present + * at @p str . + */ +static const char* skip_word(const char* exp, const char** str) +{ + size_t explen = strlen(exp); + const char* cur = *str; + int match = (!strncmp(exp, cur, explen) && + (!cur[explen] || cur[explen] == '/' || isspace(cur[explen]))); + if(match) { + *str += explen; + return *str; + } + else return NULL; +} + +/** + * Tries to skip the next identifier beginning at @p str + * + * @return The position after the identifier, or NULL if there's no identifier + * at @p str . + */ +static const char* skip_identifier(const char* str) +{ + if(!isalpha(*str) && *str != '_') + return NULL; + else + { + ++str; + for(; isalnum(*str) || *str == '_'; ++str) ; + return str; + } +} + +const char* rtosc_skip_next_printed_arg(const char* src) +{ + switch(*src) + { + case 't': + if(!skip_word("true", &src)) + src = skip_identifier(src); + break; + case 'f': + if(!skip_word("false", &src)) + src = skip_identifier(src); + break; + case 'n': + if(!skip_word("nil", &src)) + if(!skip_word("now", &src)) + src = skip_identifier(src); + break; + case 'i': + if(!skip_word("inf", &src)) + if(!skip_word("immediately", &src)) + src = skip_identifier(src); + break; + case '#': + for(size_t i = 0; i<8; ++i) + { + ++src; + if(!isxdigit(*src)) { + src = NULL; + i = 8; + } + } + if(src) ++src; + break; + case '\'': + { + int esc = -1; + if(strlen(src) < 3) + return NULL; + // type 1: '' => normal char + // type 2: '\' => escaped char + // type 3: '\'' => escaped quote + // type 4: '\' => mistyped backslash + if(src[1] == '\\') { + if(src[2] == '\'' && (!src[3] || isspace(src[3]))) + { + // type 4 + // the user inputs '\', which is wrong, but + // we accept it as a backslash anyways + } + else + { + ++src; // type 2 or 3 + esc = get_escaped_char(src[1], 1); + } + } + // if the last char was no single quote, + // or we had an invalid escape sequence, return NULL + src = (!esc || src[2] != '\'') ? NULL : (src + 3); + break; + } + case '"': + src = end_of_printed_string(src); + if(src && *src == 'S') + ++src; + break; + case 'M': + if(!strncmp("MIDI", src, 4) && (isspace(src[4]) || src[4] == '[')) + skip_fmt_null(&src, "MIDI [ 0x%*x 0x%*x 0x%*x 0x%*x ]%n"); + else + src = skip_identifier(src); + break; + case '[': + { + int rd = 0, blobsize = 0; + sscanf(src, "[ %i %n", &blobsize, &rd); + src = rd ? (src + rd) : NULL; + for(;src && *src == '0';) // i.e. 0x... + { + skip_fmt_null(&src, "0x%*x %n"); + blobsize--; + } + if(blobsize) + src = NULL; + if(src) + src = (*src == ']') ? (src + 1) : NULL; + break; + } + default: + { + // is it an identifier? + if(*src == '_' || isalpha(*src)) + { + for(; *src == '_' || isalnum(*src); ++src) ; + } + // is it a date? (vs a numeric) + else if(skip_fmt(&src, "%*4d-%*1d%*1d-%*1d%*1d%n")) + { + if(skip_fmt(&src, " %*2d:%*1d%*1d%n")) + if(skip_fmt(&src, ":%*1d%*1d%n")) + if(skip_fmt(&src, ".%*d%n")) + { + if(skip_fmt(&src, " ( ... + 0x%n")) + { + skip_fmt(&src, "%*x.%n"); + if(skip_fmt(&src, "%*xp%n")) + { + int rd = 0, expm; + sscanf(src, "-%d s )%n", &expm, &rd); + if(rd && expm > 0 && expm <= 32) + { + // ok + src += rd; + } + else + src = NULL; + + } + else + src = NULL; + } + } + } + else + { + char type; + int rd = skip_numeric(&src, &type); + if(!rd) { src = NULL; break; } + const char* after_num = src; + skip_while(&after_num, isspace); + if(*after_num == '(') + { + if (type == 'f' || type =='d') + { + // skip lossless representation + src = ++after_num; + skip_while(&src, isspace); + rd = skip_numeric(&src, NULL); + if(!rd) { src = NULL; break; } + skip_fmt_null(&src, " )%n"); + } + else + src = NULL; + } + } + } + } + return src; +} + +int rtosc_count_printed_arg_vals(const char* src) +{ + int num = 0; + + skip_while(&src, isspace); + while (*src == '%') + skip_fmt(&src, "%*[^\n] %n"); + + for(; src && *src && *src != '/'; ++num) + { + src = rtosc_skip_next_printed_arg(src); + if(src) // parse error + { + skip_while(&src, isspace); + if(*src && !isspace(*src)) + { + while (*src == '%') + skip_fmt(&src, "%*[^\n] %n"); + } + } + } + return src ? num : -num; +} + +int rtosc_count_printed_arg_vals_of_msg(const char* msg) +{ + skip_while(&msg, isspace); + while (*msg == '%') + skip_fmt(&msg, "%*[^\n] %n"); + + if (*msg == '/') { + for(; *msg && !isspace(*msg); ++msg); + return rtosc_count_printed_arg_vals(msg); + } + else if(!*msg) + return INT_MIN; + else + return -1; +} + +//! Tries to parse an identifier at @p src and stores it in @p arg +const char* parse_identifier(const char* src, rtosc_arg_val_t *arg, + char* buffer_for_strings, + size_t* bufsize) +{ + if(*src == '_' || isalpha(*src)) + { + arg->type = 'S'; + arg->val.s = buffer_for_strings; + for(; *src == '_' || isalnum(*src); ++src) + { + --*bufsize; + assert(*bufsize); + *buffer_for_strings = *src; + ++buffer_for_strings; + } + --*bufsize; + assert(*bufsize); + *buffer_for_strings = 0; + ++buffer_for_strings; + } + return src; +} + +size_t rtosc_scan_arg_val(const char* src, + rtosc_arg_val_t *arg, + char* buffer_for_strings, size_t* bufsize) +{ + int rd = 0; + const char* start = src; + switch(*src) + { + case 't': + case 'f': + case 'n': + case 'i': + { + const char* src_backup = src; + // timestamps "immediately" or "now"? + if(skip_word("immediately", &src) || skip_word("now", &src)) + { + arg->type = 't'; + arg->val.t = 1; + } + else if(skip_word("nil", &src) || + skip_word("inf", &src) || + skip_word("true", &src) || + skip_word("false", &src) ) + { + arg->type = arg->val.T = toupper(*src_backup); + } + else + { + // no reserved keyword => identifier + src = parse_identifier(src, arg, buffer_for_strings, bufsize); + } + break; + } + case '#': + { + arg->type = 'r'; + sscanf(++src, "%x", &arg->val.i); + src+=8; + break; + } + case '\'': + // type 1: '' => normal char + // type 2: '\' => escaped char + // type 3: '\'' => escaped quote + // type 4: '\' => mistyped backslash + arg->type = 'c'; + if(*++src == '\\') + { + if(src[2] && !isspace(src[2])) // escaped and 4 chars + arg->val.i = get_escaped_char(*++src, true); + else // escaped, but only 3 chars: type 4 + arg->val.i = '\\'; + } + else // non-escaped + arg->val.i = *src; + src+=2; + break; + case '"': + { + ++src; // skip obligatory '"' + char* dest = buffer_for_strings; + bool cont; + do + { + while(*src != '"') + { + (*bufsize)--; + assert(*bufsize); + if(*src == '\\') { + *dest++ = get_escaped_char(*++src, false); + ++src; + } + else + *dest++ = *src++; + } + if(src[1] == '\\') + { + skip_fmt(&src, "\"\\ \"%n"); + cont = true; + } + else + cont = false; + } while (cont); + *dest = 0; + ++src; // skip final '"' + (*bufsize)--; + arg->val.s = buffer_for_strings; + if(*src == 'S') + { + ++src; + (*bufsize)--; + arg->type = 'S'; + } + else + arg->type = 's'; + break; + } + case 'M': + { + if(!strncmp("MIDI", src, 4) && (isspace(src[4]) || src[4] == '[')) + { + arg->type = 'm'; + int32_t tmp[4]; + sscanf(src, "MIDI [ 0x%"PRIx32" 0x%"PRIx32 + " 0x%"PRIx32" 0x%"PRIx32" ]%n", + tmp, tmp + 1, tmp + 2, tmp + 3, &rd); src+=rd; + for(size_t i = 0; i < 4; ++i) + arg->val.m[i] = tmp[i]; // copy to 8 bit array + } + else + src = parse_identifier(src, arg, buffer_for_strings, bufsize); + break; + } + case '[': // blob + { + arg->type = 'b'; + while( isspace(*++src) ) ; + sscanf(src, "%"PRIi32" %n", &arg->val.b.len, &rd); + src +=rd; + + assert(*bufsize >= (size_t)arg->val.b.len); + *bufsize -= (size_t)arg->val.b.len; + + arg->val.b.data = (uint8_t*)buffer_for_strings; + for(int32_t i = 0; i < arg->val.b.len; ++i) + { + int32_t tmp; + int rd; + sscanf(src, "0x%x %n", &tmp, &rd); + arg->val.b.data[i] = tmp; + src+=rd; + } + + ++src; // skip ']' + break; + } + default: + // is it an identifier? + if(*src == '_' || isalpha(*src)) + { + arg->type = 'S'; + arg->val.s = buffer_for_strings; + for(; *src == '_' || isalnum(*src); ++src) + { + --*bufsize; + assert(*bufsize); + *buffer_for_strings = *src; + ++buffer_for_strings; + } + --*bufsize; + assert(*bufsize); + *buffer_for_strings = 0; + ++buffer_for_strings; + } + // "YYYY-" => it's a date + else if(src[0] && src[1] && src[2] && src[3] && src[4] == '-') + { + arg->val.t = 0; + + struct tm m_tm; + m_tm.tm_hour = 0; + m_tm.tm_min = 0; + m_tm.tm_sec = 0; + sscanf(src, "%4d-%2d-%2d%n", + &m_tm.tm_year, &m_tm.tm_mon, &m_tm.tm_mday, &rd); + src+=rd; + float secfracsf; + + rd = 0; + sscanf(src, " %2d:%2d%n", &m_tm.tm_hour, &m_tm.tm_min, &rd); + if(rd) + src+=rd; + + rd = 0; + sscanf(src, ":%2d%n", &m_tm.tm_sec, &rd); + if(rd) + src+=rd; + + // lossless format is appended in parantheses? + // => take it directly from there + if(skip_fmt(&src, "%*f (%n")) + { + + sscanf(src, " ... + 0x%8"PRIx64"p-32 s )%n", + &arg->val.t, &rd); + src += rd; + } + // float number, but not lossless? + // => convert it to fractions of seconds + else if(*src == '.') + { + sscanf(src, "%f%n", &secfracsf, &rd); + src += rd; + + // convert float -> secfracs + char secfracs_as_hex[16]; + asnprintf(secfracs_as_hex, 16, "%a", secfracsf); + assert(secfracs_as_hex[3]=='.'); // 0x?. + secfracs_as_hex[3] = secfracs_as_hex[2]; // remove '.' + uint64_t secfracs; + int exp; + sscanf(secfracs_as_hex + 3, + "%"PRIx64"p-%i", &secfracs, &exp); + const char* p = strchr(secfracs_as_hex, 'p'); + assert(p); + int lshift = 32-exp-((int)(p-(secfracs_as_hex+4))<<2); + assert(lshift > 0); + secfracs <<= lshift; + assert((secfracs & 0xFFFFFFFF) == secfracs); + + arg->val.t = secfracs; + } + else + { + // no fractional / floating seconds part + } + + // adjust ranges to be POSIX conform + m_tm.tm_year -= 1900; + --m_tm.tm_mon; + // don't mess around with Daylight Saving Time + m_tm.tm_isdst = -1; + + arg->val.t |= (((uint64_t)mktime(&m_tm)) << ((uint64_t)32)); + arg->type = 't'; + } + else + { + char bytes8[8]; + char type = arg->type = 0; + + bool repeat_once = false; + do + { + rd = 0; + + const char *fmtstr = scanf_fmtstr_scan(src, bytes8, + &type); + if(!arg->type) // the first occurence determins the type + arg->type = type; + + switch(type) + { + case 'h': + sscanf(src, fmtstr, &arg->val.h, &rd); break; + case 'i': + sscanf(src, fmtstr, &arg->val.i, &rd); break; + case 'f': + sscanf(src, fmtstr, &arg->val.f, &rd); break; + case 'd': + sscanf(src, fmtstr, &arg->val.d, &rd); break; + } + src += rd; + + if(repeat_once) + { + // we have read the lossless part. skip spaces and ')' + skip_fmt(&src, " )%n"); + repeat_once = false; + } + else + { + // is a lossless part appended in parantheses? + const char* after_num = src; + skip_while(&after_num, isspace); + if(*after_num == '(') { + ++after_num; + skip_while(&after_num, isspace); + src = after_num; + repeat_once = true; + } + } + } while(repeat_once); + } // date vs integer + // case ident + } // switch + return (size_t)(src-start); +} + +size_t rtosc_scan_arg_vals(const char* src, + rtosc_arg_val_t *args, size_t n, + char* buffer_for_strings, size_t bufsize) +{ + size_t last_bufsize; + size_t rd=0; + for(size_t i = 0; i < n; ++i) + { + last_bufsize = bufsize; + size_t tmp = rtosc_scan_arg_val(src, args + i, + buffer_for_strings, &bufsize); + src += tmp; + rd += tmp; + + size_t written = last_bufsize - bufsize; + buffer_for_strings += written; + + do + { + rd += skip_fmt(&src, " %n"); + while(*src == '%') + rd += skip_fmt(&src, "%*[^\n]%n"); + } while(isspace(*src)); + } + return rd; +} + +size_t rtosc_scan_message(const char* src, + char* address, size_t adrsize, + rtosc_arg_val_t *args, size_t n, + char* buffer_for_strings, size_t bufsize) +{ + size_t rd = 0; + for(;*src && isspace(*src); ++src) ++rd; + while (*src == '%') + rd += skip_fmt(&src, "%*[^\n] %n"); + + assert(*src == '/'); + for(; *src && !isspace(*src) && rd < adrsize; ++rd) + *address++ = *src++; + assert(rd < adrsize); // otherwise, the address was too long + *address = 0; + + for(;*src && isspace(*src); ++src) ++rd; + + rd += rtosc_scan_arg_vals(src, args, n, buffer_for_strings, bufsize); + + return rd; +} + diff --git a/source/native-plugins/zynaddsubfx/rtosc/pretty-format.h b/source/native-plugins/zynaddsubfx/rtosc/pretty-format.h new file mode 100644 index 000000000..41265565c --- /dev/null +++ b/source/native-plugins/zynaddsubfx/rtosc/pretty-format.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2017 Johannes Lorenz + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * @file pretty-format.h + */ + +#ifndef PRETTYFORMAT_H +#define PRETTYFORMAT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + bool lossless; //!< will add hex notation behind floats + int floating_point_precision; + const char* sep; //!< separator for multiple argument values + int linelength; +} rtosc_print_options; + +/** + * @brief Pretty-print rtosct_arg_val_t structure into buffer + * + * @param arg Pointer to the structure that shall be printed + * @param buffer The buffer to write to + * @param buffersize The maximum size to write to, includin a trailing 0 byte + * @param opt Printer options, NULL for default options + * @param cols_used How many columns have been used for writing in this line + * (will be updated by this function) + * @return The number of bytes written, excluding the null byte + */ +size_t rtosc_print_arg_val(const rtosc_arg_val_t* arg, char* buffer, + size_t buffersize, const rtosc_print_options* opt, + int* cols_used); + +/** + * @brief Pretty-print rtosct_arg_val_t array into buffer + * + * @see rtosc_print_message + * @warning in case of possible line breaks (almost always), buffer[-1] must + * be accessible and be whitespace (since it can be converted to a newline) + */ +size_t rtosc_print_arg_vals(const rtosc_arg_val_t *args, size_t n, + char *buffer, size_t bs, + const rtosc_print_options* opt, + int cols_used); + +/** + * @brief Pretty-print OSC message into string buffer + * + * A newline will be appended. + * + * @param address OSC pattern to send message to + * @param args The array to print + * @param n Number of args from the array that should be printed + * @param buffer The buffer to write to + * @param bs The maximum size to write to, includin a trailing 0 byte + * @param opt Printer options, NULL for default options + * @param cols_used How many columns have been used for writing in this line + * @return The number of bytes written, excluding the null byte + */ +size_t rtosc_print_message(const char* address, + const rtosc_arg_val_t *args, size_t n, + char *buffer, size_t bs, + const rtosc_print_options* opt, + int cols_used); + +/** + * @brief Skip characters from a string until one argument value + * would have been scanned + * @param src The string + * @return The first character after that argument value + */ +const char* rtosc_skip_next_printed_arg(const char* src); + +/** + * @brief Count arguments that would be scanned and do a complete syntax check + * + * This functions should be run before rtosc_scan_arg_vals() in order + * to know the number of argument values. Also, rtosc_scan_arg_vals() does + * no complete syntax check. + * + * @param src The string to scan from + * @return The number of arguments that can be scanned (>=0), or if the nth arg + * (range 1...) can not be scanned, -n + */ +int rtosc_count_printed_arg_vals(const char* src); + +/** + * @brief Count arguments of a message that would be scanned and + * do a complete syntax check + * + * @param msg The message to scan from + * @return -1 if the address could not be scanned, + * INT_MIN if the whole string is whitespace, + * otherwise @see rtosc_count_printed_arg_vals + */ +int rtosc_count_printed_arg_vals_of_msg(const char* msg); + +/** + * @brief Scans one argument value from a string + * + * This function does no complete syntaxcheck. Call + * rtosc_count_printed_arg_vals() before. + * + * @param src The string + * @param arg Pointer to where to store the argument value; must be allocated + * @param buffer_for_strings A buffer with enough space for scanned + * strings and blobs + * @param bufsize Size of @p buffer_for_strings , will be shrinked to the + * bufferbytes left after the scan + * @return The number of bytes scanned + */ +size_t rtosc_scan_arg_val(const char* src, + rtosc_arg_val_t *arg, + char* buffer_for_strings, size_t* bufsize); + +/** + * @brief Scan a fixed number of argument values from a string. + * + * This function does no complete syntaxcheck. Call + * rtosc_count_printed_arg_vals() before. This will also give you the @p n + * parameter. + * + * @see rtosc_scan_message + */ +size_t rtosc_scan_arg_vals(const char* src, + rtosc_arg_val_t *args, size_t n, + char* buffer_for_strings, size_t bufsize); + +/** + * @brief Scan an OSC message from a string. + * + * This function does no complete syntaxcheck. Call + * rtosc_count_printed_arg_vals() before. This will also give you the @p n + * parameter. Preceding and trailing whitespace will be consumed. + * + * @param src The string + * @param address A buffer where the port address will be written + * @param adrsize Size of buffer @p address + * @param args Pointer to an array of argument values; the output will be + * written here + * @param n The amount of argument values to scan + * @param buffer_for_strings A buffer with enough space for scanned + * strings and blobs + * @param bufsize Size of @p buffer_for_strings + * @return The number of bytes scanned + */ +size_t rtosc_scan_message(const char* src, + char* address, size_t adrsize, + rtosc_arg_val_t *args, size_t n, + char* buffer_for_strings, size_t bufsize); + +#ifdef __cplusplus +}; +#endif +#endif // PRETTYFORMAT_H diff --git a/source/native-plugins/zynaddsubfx/rtosc/rtosc-version.h b/source/native-plugins/zynaddsubfx/rtosc/rtosc-version.h new file mode 100644 index 000000000..4f8540d96 --- /dev/null +++ b/source/native-plugins/zynaddsubfx/rtosc/rtosc-version.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017 Johannes Lorenz + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * @file rtosc-version.h + * @note the implementation is in version.c.in + */ + +#ifndef RTOSC_VERSION_H +#define RTOSC_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +//! @brief struct containing an rtosc version +typedef struct +{ + unsigned char major; + unsigned char minor; + unsigned char revision; +} rtosc_version; + +//! @brief memcmp-like version compare +//! @return an integer greater than, equal to, or less than 0, if +//! v1 is greater than, equal to, or less than v2, respectively +int rtosc_version_cmp(const rtosc_version v1, + const rtosc_version v2); + +//! @brief Return the version RT OSC has been compiled with +rtosc_version rtosc_current_version(); + +//! @brief Print the version pointed to by @p v to the buffer @p _12bytes +//! +//! The format ".." is being used +//! @param v Pointer to the version that shall be printed +//! @param _12bytes A buffer with a size of at least 12 bytes +void rtosc_version_print_to_12byte_str(const rtosc_version* v, + char* _12bytes); + +#ifdef __cplusplus +}; +#endif + +#endif + diff --git a/source/native-plugins/zynaddsubfx/rtosc/rtosc.c b/source/native-plugins/zynaddsubfx/rtosc/rtosc.c index e996e861c..cc73cf41a 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/rtosc.c +++ b/source/native-plugins/zynaddsubfx/rtosc/rtosc.c @@ -231,38 +231,214 @@ static size_t vsosc_null(const char *address, return pos; } -size_t rtosc_vmessage(char *buffer, - size_t len, - const char *address, - const char *arguments, - va_list ap) + +static const rtosc_cmp_options* default_cmp_options + = &((rtosc_cmp_options) { 0.0 }); + +int rtosc_arg_vals_eq(rtosc_arg_val_t* lhs, rtosc_arg_val_t* rhs, + size_t lsize, size_t rsize, + const rtosc_cmp_options* opt) { - const unsigned nargs = nreserved(arguments); - if(!nargs) - return rtosc_amessage(buffer,len,address,arguments,NULL); +#define mfabs(val) (((val) >= 0) ? (val) : -(val)) - rtosc_arg_t args[nargs]; + if(!opt) + opt = default_cmp_options; + if(lsize != rsize) + return 0; + + int rval = 1; + for(size_t i = 0; i < lsize && rval; ++i, ++lhs, ++rhs) + { + if(lhs->type == rhs->type) + switch(lhs->type) + { + case 'i': + case 'c': + case 'r': + rval = lhs->val.i == rhs->val.i; + break; + case 'I': + case 'T': + case 'F': + case 'N': + rval = 1; + break; + case 'f': + rval = (opt->float_tolerance == 0.0) + ? lhs->val.f == rhs->val.f + : mfabs(lhs->val.f - rhs->val.f) <= + (float)opt->float_tolerance; + break; + case 'd': + rval = (opt->float_tolerance == 0.0) + ? lhs->val.d == rhs->val.d + : mfabs(lhs->val.d - rhs->val.d) <= + opt->float_tolerance; + break; + case 'h': + rval = lhs->val.h == rhs->val.h; + break; + case 't': + rval = lhs->val.t == rhs->val.t; + break; + case 'm': + rval = 0 == memcmp(lhs->val.m, rhs->val.m, 4); + break; + case 's': + case 'S': + rval = (lhs->val.s == NULL || rhs->val.s == NULL) + ? lhs->val.s == rhs->val.s + : (0 == strcmp(lhs->val.s, rhs->val.s)); + break; + case 'b': + { + int32_t lbs = lhs->val.b.len, + rbs = rhs->val.b.len; + rval = lbs == rbs; + if(rval) + rval = 0 == memcmp(lhs->val.b.data, rhs->val.b.data, lbs); + break; + } + } + else + { + rval = 0; + } + } + return rval; +#undef mfabs +} +int rtosc_arg_vals_cmp(rtosc_arg_val_t* lhs, rtosc_arg_val_t* rhs, + size_t lsize, size_t rsize, + const rtosc_cmp_options* opt) +{ +#define cmp_3way(val1,val2) (((val1) == (val2)) \ + ? 0 \ + : (((val1) > (val2)) ? 1 : -1)) +#define mfabs(val) (((val) >= 0) ? (val) : -(val)) + + if(!opt) + opt = default_cmp_options; + + size_t rval = 0; + size_t min = lsize > rsize ? rsize : lsize; + for(size_t i = 0; i < min && !rval; ++i, ++lhs, ++rhs) + { + if(lhs->type == rhs->type) + switch(lhs->type) + { + case 'i': + case 'c': + case 'r': + rval = cmp_3way(lhs->val.i, rhs->val.i); + break; + case 'I': + case 'T': + case 'F': + case 'N': + rval = 0; + break; + case 'f': + rval = (opt->float_tolerance == 0.0) + ? cmp_3way(lhs->val.f, rhs->val.f) + : (mfabs(lhs->val.f - rhs->val.f) + <= (float)opt->float_tolerance) + ? 0 + : ((lhs->val.f > rhs->val.f) ? 1 : -1); + break; + case 'd': + rval = (opt->float_tolerance == 0.0) + ? cmp_3way(lhs->val.d, rhs->val.d) + : (mfabs(lhs->val.d - rhs->val.d) + <= opt->float_tolerance) + ? 0 + : ((lhs->val.d > rhs->val.d) ? 1 : -1); + break; + case 'h': + rval = cmp_3way(lhs->val.h, rhs->val.h); + break; + case 't': + // immediately is considered lower than everything else + // this means if you send two events to a client, + // one being "immediately" and one being different, the + // immediately-event has the higher priority, event if the + // other one is in the past + rval = (lhs->val.t == 1) + ? (rhs->val.t == 1) + ? 0 + : -1 // lhs has higher priority => lhs < rhs + : (rhs->val.t == 1) + ? 1 + : cmp_3way(lhs->val.t, rhs->val.t); + break; + case 'm': + rval = memcmp(lhs->val.m, rhs->val.m, 4); + break; + case 's': + case 'S': + rval = (lhs->val.s == NULL || rhs->val.s == NULL) + ? cmp_3way(lhs->val.s, rhs->val.s) + : strcmp(lhs->val.s, rhs->val.s); + break; + case 'b': + { + int32_t lbs = lhs->val.b.len, + rbs = rhs->val.b.len; + int32_t minlen = (lbs < rbs) ? lbs : rbs; + rval = memcmp(lhs->val.b.data, rhs->val.b.data, minlen); + if(lbs != rbs && !rval) + { + // both equal until here + // the string that ends here is lexicographically smaller + rval = (lbs > rbs) + ? lhs->val.b.data[minlen] + : -rhs->val.b.data[minlen]; + } + else + return rval; + break; + } + } + else + { + rval = (lhs->type > rhs->type) ? 1 : -1; + } + } + + if(rval == 0 && lsize != rsize) + { + return (lsize > rsize) ? 1 : -1; + } + return rval; + +#undef mfabs +#undef cmp_3way +} + +void rtosc_v2args(rtosc_arg_t* args, size_t nargs, const char* arg_str, + rtosc_va_list_t* ap) +{ unsigned arg_pos = 0; - const char *arg_str = arguments; uint8_t *midi_tmp; + while(arg_pos < nargs) { switch(*arg_str++) { case 'h': case 't': - args[arg_pos++].h = va_arg(ap, int64_t); + args[arg_pos++].h = va_arg(ap->a, int64_t); break; case 'd': - args[arg_pos++].d = va_arg(ap, double); + args[arg_pos++].d = va_arg(ap->a, double); break; case 'c': case 'i': case 'r': - args[arg_pos++].i = va_arg(ap, int); + args[arg_pos++].i = va_arg(ap->a, int); break; case 'm': - midi_tmp = va_arg(ap, uint8_t *); + midi_tmp = va_arg(ap->a, uint8_t *); args[arg_pos].m[0] = midi_tmp[0]; args[arg_pos].m[1] = midi_tmp[1]; args[arg_pos].m[2] = midi_tmp[2]; @@ -270,20 +446,69 @@ size_t rtosc_vmessage(char *buffer, break; case 'S': case 's': - args[arg_pos++].s = va_arg(ap, const char *); + args[arg_pos++].s = va_arg(ap->a, const char *); break; case 'b': - args[arg_pos].b.len = va_arg(ap, int); - args[arg_pos].b.data = va_arg(ap, unsigned char *); + args[arg_pos].b.len = va_arg(ap->a, int); + args[arg_pos].b.data = va_arg(ap->a, unsigned char *); arg_pos++; break; case 'f': - args[arg_pos++].f = va_arg(ap, double); + args[arg_pos++].f = va_arg(ap->a, double); + break; + case 'T': + case 'F': + case 'N': + case 'I': + args[arg_pos++].T = arg_str[-1]; break; default: ; } } +} + +void rtosc_2args(rtosc_arg_t* args, size_t nargs, const char* arg_str, ...) +{ + rtosc_va_list_t va; + va_start(va.a, arg_str); + rtosc_v2args(args, nargs, arg_str, &va); + va_end(va.a); +} + +void rtosc_v2argvals(rtosc_arg_val_t* args, size_t nargs, const char* arg_str, va_list ap) +{ + rtosc_va_list_t ap2; + va_copy(ap2.a, ap); + for(size_t i=0; itype = *arg_str; + rtosc_v2args(&args->val, 1, arg_str, &ap2); + } +} + +void rtosc_2argvals(rtosc_arg_val_t* args, size_t nargs, const char* arg_str, ...) +{ + va_list va; + va_start(va, arg_str); + rtosc_v2argvals(args, nargs, arg_str, va); + va_end(va); +} + +size_t rtosc_vmessage(char *buffer, + size_t len, + const char *address, + const char *arguments, + va_list ap) +{ + const unsigned nargs = nreserved(arguments); + if(!nargs) + return rtosc_amessage(buffer,len,address,arguments,NULL); + + rtosc_arg_t args[nargs]; + rtosc_va_list_t ap2; + va_copy(ap2.a, ap); + rtosc_v2args(args, nargs, arguments, &ap2); return rtosc_amessage(buffer,len,address,arguments,args); } diff --git a/source/native-plugins/zynaddsubfx/rtosc/rtosc.h b/source/native-plugins/zynaddsubfx/rtosc/rtosc.h index 3a8aa35ed..59b5b5db8 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/rtosc.h +++ b/source/native-plugins/zynaddsubfx/rtosc/rtosc.h @@ -20,9 +20,12 @@ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + */ + +/** * @file rtosc.h */ + #ifndef RTOSC_H #define RTOSC_H #include @@ -125,6 +128,70 @@ typedef struct { rtosc_arg_t val; } rtosc_arg_val_t; +typedef struct +{ + //!< tolerance to when two floats or doubles are equal + double float_tolerance; +} rtosc_cmp_options; + +/** + * @brief Check if two arrays of rtosc_arg_val_t are equal + * + * @param opt Comparison options or NULL for default options + * @return One if they are equal, zero if not + */ +int rtosc_arg_vals_eq(rtosc_arg_val_t* lhs, rtosc_arg_val_t* rhs, + size_t lsize, size_t rsize, + const rtosc_cmp_options* opt); + +/** + * @brief Compare two arrays of rtosc_arg_val_t. + * + * Whether an argument value is less or greater than another is computed + * - using memcmp for blobs + * - using strcmp for strings and identifiers + * - using numerical comparison for all other types. + * As an exception, the timestamp "immediately" is defined to be smaller than + * every other timestamp. + * + * @param opt Comparison options or NULL for default options + * @return An integer less than, equal to, or greater than zero if lhs is found, + * respectively, to be less than, to match, or be greater than rhs. + */ +int rtosc_arg_vals_cmp(rtosc_arg_val_t* lhs, rtosc_arg_val_t* rhs, + size_t lsize, size_t rsize, + const rtosc_cmp_options* opt); + +//! va_list container, required for passing va_list as pointers to functions +typedef struct { va_list a; } rtosc_va_list_t; + +/** + * @brief Pack arguments into pre-allocated rtosc_arg_t array + * + * @param args Pre-allocated array; size must be greater or equal @p nargs + * @param nargs Size of elements to pack + * @param arg_str Rtosc string specifying the arguments' types + * @param ap The parameters that shall be packed + */ +void rtosc_v2args(rtosc_arg_t* args, size_t nargs, + const char* arg_str, rtosc_va_list_t* ap); + +/** + * @brief Pack parameters into pre-allocated rtosc_arg_val-t array + * + * @see rtosc_v2args + */ +void rtosc_v2argvals(rtosc_arg_val_t* args, size_t nargs, + const char* arg_str, va_list ap); + +/** + * @brief Pack parameters into pre-allocated rtosc_arg_val-t array + * + * @see rtosc_v2args + */ +void rtosc_2argvals(rtosc_arg_val_t* args, size_t nargs, + const char* arg_str, ...); + /** * Create an argument iterator for a message * @param msg OSC message @@ -197,7 +264,7 @@ const char *rtosc_argument_string(const char *msg); * @param tt OSC time tag * @param elms Number of sub messages * @param ... Messages - * @returns legnth of generated bundle or zero on failure + * @returns length of generated bundle or zero on failure */ size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...); @@ -250,9 +317,12 @@ uint64_t rtosc_bundle_timetag(const char *msg); * * @param pattern The pattern string stored in the Port * @param msg The OSC message to be matched + * @param path_end if non-NULL, will point to where parsing stopped in the path + * (in case of a match, *path_end is always '/' or '\0') * @returns true if a normal match and false if unmatched */ -bool rtosc_match(const char *pattern, const char *msg); +bool rtosc_match(const char *pattern, + const char *msg, const char** path_end); /** @@ -260,8 +330,11 @@ bool rtosc_match(const char *pattern, const char *msg); * * @param pattern rtosc pattern * @param msg a normal C string or a rtosc message + * @param path_end if non-NULL, will point to where parsing stopped in the path + * (in case of a match, *path_end is always '/' or '\0') */ -const char *rtosc_match_path(const char *pattern, const char *msg); +const char *rtosc_match_path(const char *pattern, + const char *msg, const char** path_end); #ifdef __cplusplus }; diff --git a/source/native-plugins/zynaddsubfx/rtosc/typed-message.h b/source/native-plugins/zynaddsubfx/rtosc/typed-message.h index d1a5a6b35..8bc92b4d9 100644 --- a/source/native-plugins/zynaddsubfx/rtosc/typed-message.h +++ b/source/native-plugins/zynaddsubfx/rtosc/typed-message.h @@ -19,7 +19,7 @@ template<> class rtMsg<> rtMsg(const char *arg = NULL, const char *spec=NULL, bool _=false) :msg(arg) { - if(arg && spec && !rtosc_match_path(spec, arg)) + if(arg && spec && !rtosc_match_path(spec, arg, NULL)) msg = NULL; (void)_; } @@ -62,7 +62,7 @@ bool validate(const char *arg) template bool match_path(std::false_type, const char *arg) { - return rtosc_match_path(T::data(), arg); + return rtosc_match_path(T::data(), arg, NULL); } template diff --git a/source/native-plugins/zynaddsubfx/version.cpp b/source/native-plugins/zynaddsubfx/version.cpp index 2d5ce83e2..8ec23e8ae 100644 --- a/source/native-plugins/zynaddsubfx/version.cpp +++ b/source/native-plugins/zynaddsubfx/version.cpp @@ -15,6 +15,8 @@ #include "zyn-version.h" +namespace zyncarla { + std::ostream& operator<< (std::ostream& os, const version_type& v) { @@ -30,3 +32,5 @@ static_assert(version_type(2,9,9) < version_type(3,4,3), static_assert(!(version_type(2,4,3) < version_type(2,4,3)), "version operator failed"); +} + diff --git a/source/native-plugins/zynaddsubfx/zyn-version.h b/source/native-plugins/zynaddsubfx/zyn-version.h index 4600b8e95..259487f13 100644 --- a/source/native-plugins/zynaddsubfx/zyn-version.h +++ b/source/native-plugins/zynaddsubfx/zyn-version.h @@ -17,6 +17,8 @@ #include +namespace zyncarla { + //! class containing a zynaddsubfx version class version_type { @@ -42,7 +44,7 @@ public: constexpr version_type() : version_type(3, 0, - 1) + 2) { } @@ -67,5 +69,7 @@ public: //! the current zynaddsubfx version constexpr version_type version; +} + #endif