@@ -67,7 +67,10 @@ extern "C" { | |||||
#include "zynaddsubfx/rtosc/cpp/undo-history.cpp" | #include "zynaddsubfx/rtosc/cpp/undo-history.cpp" | ||||
// zynaddsubfx includes | // zynaddsubfx includes | ||||
#include "zynaddsubfx/version.cpp" | |||||
#include "zynaddsubfx/Containers/MultiPseudoStack.cpp" | #include "zynaddsubfx/Containers/MultiPseudoStack.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -75,6 +78,15 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Containers/NotePool.cpp" | #include "zynaddsubfx/Containers/NotePool.cpp" | ||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Containers/ScratchString.cpp" | |||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -82,6 +94,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/AnalogFilter.cpp" | #include "zynaddsubfx/DSP/AnalogFilter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -89,6 +102,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/FFTwrapper.cpp" | #include "zynaddsubfx/DSP/FFTwrapper.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -96,6 +110,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/Filter.cpp" | #include "zynaddsubfx/DSP/Filter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -103,6 +118,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/FormantFilter.cpp" | #include "zynaddsubfx/DSP/FormantFilter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -110,6 +126,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/SVFilter.cpp" | #include "zynaddsubfx/DSP/SVFilter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -117,6 +134,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/DSP/Unison.cpp" | #include "zynaddsubfx/DSP/Unison.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -124,6 +142,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/Alienwah.cpp" | #include "zynaddsubfx/Effects/Alienwah.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -131,6 +150,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/Chorus.cpp" | #include "zynaddsubfx/Effects/Chorus.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -138,6 +158,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/Distorsion.cpp" | #include "zynaddsubfx/Effects/Distorsion.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -145,6 +166,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/DynamicFilter.cpp" | #include "zynaddsubfx/Effects/DynamicFilter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -153,6 +175,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Effects/Echo.cpp" | #include "zynaddsubfx/Effects/Echo.cpp" | ||||
#undef MAX_DELAY | #undef MAX_DELAY | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -160,6 +183,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/Effect.cpp" | #include "zynaddsubfx/Effects/Effect.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -167,6 +191,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/EffectLFO.cpp" | #include "zynaddsubfx/Effects/EffectLFO.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -174,6 +199,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/EffectMgr.cpp" | #include "zynaddsubfx/Effects/EffectMgr.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -181,6 +207,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/EQ.cpp" | #include "zynaddsubfx/Effects/EQ.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -188,16 +215,18 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Effects/Phaser.cpp" | #include "zynaddsubfx/Effects/Phaser.cpp" | ||||
#undef PHASER_LFO_SHAPE | |||||
#undef ONE_ | |||||
#undef ZERO_ | |||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb | #define rChangeCb | ||||
#undef PHASER_LFO_SHAPE | |||||
#undef ONE_ | |||||
#undef ZERO_ | |||||
#include "zynaddsubfx/Effects/Reverb.cpp" | #include "zynaddsubfx/Effects/Reverb.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -205,6 +234,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/Allocator.cpp" | #include "zynaddsubfx/Misc/Allocator.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -214,6 +244,15 @@ extern "C" { | |||||
#include "zynaddsubfx/Misc/Bank.cpp" | #include "zynaddsubfx/Misc/Bank.cpp" | ||||
#undef INSTRUMENT_EXTENSION | #undef INSTRUMENT_EXTENSION | ||||
#undef FORCE_BANK_DIR_FILE | #undef FORCE_BANK_DIR_FILE | ||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/BankDb.cpp" | |||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -221,6 +260,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/CallbackRepeater.cpp" | #include "zynaddsubfx/Misc/CallbackRepeater.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -228,6 +268,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/Config.cpp" | #include "zynaddsubfx/Misc/Config.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -243,6 +284,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Misc/Microtonal.cpp" | #include "zynaddsubfx/Misc/Microtonal.cpp" | ||||
#undef MAX_LINE_SIZE | #undef MAX_LINE_SIZE | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -250,6 +292,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/MiddleWare.cpp" | #include "zynaddsubfx/Misc/MiddleWare.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -258,6 +301,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Misc/Part.cpp" | #include "zynaddsubfx/Misc/Part.cpp" | ||||
#undef CLONE | #undef CLONE | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -265,6 +309,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/PresetExtractor.cpp" | #include "zynaddsubfx/Misc/PresetExtractor.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -272,6 +317,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/Recorder.cpp" | #include "zynaddsubfx/Misc/Recorder.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -279,6 +325,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/Util.cpp" | #include "zynaddsubfx/Misc/Util.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -286,6 +333,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/WavFile.cpp" | #include "zynaddsubfx/Misc/WavFile.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -293,6 +341,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/WaveShapeSmps.cpp" | #include "zynaddsubfx/Misc/WaveShapeSmps.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -300,6 +349,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Misc/XMLwrapper.cpp" | #include "zynaddsubfx/Misc/XMLwrapper.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -308,6 +358,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Params/ADnoteParameters.cpp" | #include "zynaddsubfx/Params/ADnoteParameters.cpp" | ||||
#undef EXPAND | #undef EXPAND | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -315,6 +366,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/Controller.cpp" | #include "zynaddsubfx/Params/Controller.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -322,6 +374,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/EnvelopeParams.cpp" | #include "zynaddsubfx/Params/EnvelopeParams.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -329,6 +382,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/FilterParams.cpp" | #include "zynaddsubfx/Params/FilterParams.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -336,6 +390,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/LFOParams.cpp" | #include "zynaddsubfx/Params/LFOParams.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -345,6 +400,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Params/PADnoteParameters.cpp" | #include "zynaddsubfx/Params/PADnoteParameters.cpp" | ||||
#undef PC | #undef PC | ||||
#undef P_C | #undef P_C | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -352,6 +408,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/Presets.cpp" | #include "zynaddsubfx/Params/Presets.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -359,6 +416,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/PresetsArray.cpp" | #include "zynaddsubfx/Params/PresetsArray.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -366,6 +424,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Params/PresetsStore.cpp" | #include "zynaddsubfx/Params/PresetsStore.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -375,6 +434,7 @@ extern "C" { | |||||
#include "zynaddsubfx/Params/SUBnoteParameters.cpp" | #include "zynaddsubfx/Params/SUBnoteParameters.cpp" | ||||
#undef doPaste | #undef doPaste | ||||
#undef doPPaste | #undef doPPaste | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -382,6 +442,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/ADnote.cpp" | #include "zynaddsubfx/Synth/ADnote.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -389,6 +450,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/Envelope.cpp" | #include "zynaddsubfx/Synth/Envelope.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -396,6 +458,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/LFO.cpp" | #include "zynaddsubfx/Synth/LFO.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -403,6 +466,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/ModFilter.cpp" | #include "zynaddsubfx/Synth/ModFilter.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -416,6 +480,7 @@ extern "C" { | |||||
#undef RESTORE | #undef RESTORE | ||||
#undef FUNC | #undef FUNC | ||||
#undef FILTER | #undef FILTER | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -423,6 +488,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/PADnote.cpp" | #include "zynaddsubfx/Synth/PADnote.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -430,6 +496,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/Resonance.cpp" | #include "zynaddsubfx/Synth/Resonance.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -437,6 +504,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/SUBnote.cpp" | #include "zynaddsubfx/Synth/SUBnote.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -444,6 +512,15 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/Synth/SynthNote.cpp" | #include "zynaddsubfx/Synth/SynthNote.cpp" | ||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/WatchPoint.cpp" | |||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -451,6 +528,7 @@ extern "C" { | |||||
#define rChangeCb | #define rChangeCb | ||||
#include "zynaddsubfx/UI/ConnectionDummy.cpp" | #include "zynaddsubfx/UI/ConnectionDummy.cpp" | ||||
#undef rBegin | |||||
#undef rObject | #undef rObject | ||||
#undef rStdString | #undef rStdString | ||||
#undef rStdStringCb | #undef rStdStringCb | ||||
@@ -28,6 +28,11 @@ LockFreeQueue::LockFreeQueue(qli_t *data_, int n) | |||||
tag[i] = INVALID; | tag[i] = INVALID; | ||||
} | } | ||||
LockFreeQueue::~LockFreeQueue(void) | |||||
{ | |||||
delete [] tag; | |||||
} | |||||
qli_t *LockFreeQueue::read(void) { | qli_t *LockFreeQueue::read(void) { | ||||
retry: | retry: | ||||
@@ -34,6 +34,7 @@ class LockFreeQueue | |||||
std::atomic<int32_t> avail; | std::atomic<int32_t> avail; | ||||
public: | public: | ||||
LockFreeQueue(qli_t *data_, int n); | LockFreeQueue(qli_t *data_, int n); | ||||
~LockFreeQueue(void); | |||||
qli_t *read(void); | qli_t *read(void); | ||||
void write(qli_t *Q); | void write(qli_t *Q); | ||||
}; | }; | ||||
@@ -0,0 +1,39 @@ | |||||
#include "ScratchString.h" | |||||
#include <cstring> | |||||
#include <cstdio> | |||||
ScratchString::ScratchString(void) | |||||
{ | |||||
memset(c_str, 0, sizeof(c_str)); | |||||
} | |||||
ScratchString::ScratchString(int num) | |||||
{ | |||||
snprintf(c_str, SCRATCH_SIZE, "%d", num); | |||||
} | |||||
ScratchString::ScratchString(unsigned char num) | |||||
{ | |||||
snprintf(c_str, SCRATCH_SIZE, "%d", num); | |||||
} | |||||
ScratchString::ScratchString(const char *str) | |||||
{ | |||||
if(str) | |||||
strncpy(c_str, str, SCRATCH_SIZE); | |||||
else | |||||
memset(c_str, 0, sizeof(c_str)); | |||||
} | |||||
ScratchString ScratchString::operator+(const ScratchString s) | |||||
{ | |||||
ScratchString ss; | |||||
strncpy(ss.c_str, c_str, SCRATCH_SIZE); | |||||
strncat(ss.c_str, s.c_str, SCRATCH_SIZE-strlen(c_str)); | |||||
return ss; | |||||
} | |||||
//ScratchString::operator const char*() const | |||||
//{ | |||||
// return c_str; | |||||
//} |
@@ -0,0 +1,17 @@ | |||||
#pragma once | |||||
#define SCRATCH_SIZE 128 | |||||
//Fixed Size String Substitute | |||||
struct ScratchString | |||||
{ | |||||
ScratchString(void); | |||||
ScratchString(int num); | |||||
ScratchString(unsigned char num); | |||||
ScratchString(const char *str); | |||||
ScratchString operator+(const ScratchString s); | |||||
//operator const char*() const; | |||||
char c_str[SCRATCH_SIZE]; | |||||
}; |
@@ -61,28 +61,35 @@ void AnalogFilter::cleanup() | |||||
needsinterpolation = false; | needsinterpolation = false; | ||||
} | } | ||||
void AnalogFilter::computefiltercoefs(void) | |||||
AnalogFilter::Coeff AnalogFilter::computeCoeff(int type, float cutoff, float q, | |||||
int stages, float gain, float fs, int &order) | |||||
{ | { | ||||
float tmp; | |||||
AnalogFilter::Coeff coeff; | |||||
bool zerocoefs = false; //this is used if the freq is too high | bool zerocoefs = false; //this is used if the freq is too high | ||||
const float samplerate_f = fs; | |||||
const float halfsamplerate_f = fs/2; | |||||
//do not allow frequencies bigger than samplerate/2 | //do not allow frequencies bigger than samplerate/2 | ||||
float freq = this->freq; | |||||
float freq = cutoff; | |||||
if(freq > (halfsamplerate_f - 500.0f)) { | if(freq > (halfsamplerate_f - 500.0f)) { | ||||
freq = halfsamplerate_f - 500.0f; | freq = halfsamplerate_f - 500.0f; | ||||
zerocoefs = true; | zerocoefs = true; | ||||
} | } | ||||
if(freq < 0.1f) | if(freq < 0.1f) | ||||
freq = 0.1f; | freq = 0.1f; | ||||
//do not allow bogus Q | //do not allow bogus Q | ||||
if(q < 0.0f) | if(q < 0.0f) | ||||
q = 0.0f; | q = 0.0f; | ||||
float tmpq, tmpgain; | float tmpq, tmpgain; | ||||
if(stages == 0) { | if(stages == 0) { | ||||
tmpq = q; | tmpq = q; | ||||
tmpgain = gain; | tmpgain = gain; | ||||
} | |||||
else { | |||||
} else { | |||||
tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q; | tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q; | ||||
tmpgain = powf(gain, 1.0f / (stages + 1)); | tmpgain = powf(gain, 1.0f / (stages + 1)); | ||||
} | } | ||||
@@ -100,6 +107,9 @@ void AnalogFilter::computefiltercoefs(void) | |||||
//the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson | //the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson | ||||
//The original location of the Cookbook is: | //The original location of the Cookbook is: | ||||
//http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt | //http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt | ||||
float tmp; | |||||
float tgp1; | |||||
float tgm1; | |||||
switch(type) { | switch(type) { | ||||
case 0: //LPF 1 pole | case 0: //LPF 1 pole | ||||
if(!zerocoefs) | if(!zerocoefs) | ||||
@@ -205,20 +215,15 @@ void AnalogFilter::computefiltercoefs(void) | |||||
if(!zerocoefs) { | if(!zerocoefs) { | ||||
tmpq = sqrtf(tmpq); | tmpq = sqrtf(tmpq); | ||||
beta = sqrtf(tmpgain) / tmpq; | beta = sqrtf(tmpgain) / tmpq; | ||||
tmp = (tmpgain + 1.0f) + (tmpgain - 1.0f) * cs + beta * sn; | |||||
c[0] = tmpgain | |||||
* ((tmpgain | |||||
+ 1.0f) - (tmpgain - 1.0f) * cs + beta * sn) / tmp; | |||||
c[1] = 2.0f * tmpgain | |||||
* ((tmpgain - 1.0f) - (tmpgain + 1.0f) * cs) / tmp; | |||||
c[2] = tmpgain | |||||
* ((tmpgain | |||||
+ 1.0f) - (tmpgain - 1.0f) * cs - beta * sn) / tmp; | |||||
d[1] = -2.0f * ((tmpgain - 1.0f) + (tmpgain + 1.0f) * cs) | |||||
/ tmp * -1.0f; | |||||
d[2] = ((tmpgain + 1.0f) + (tmpgain - 1.0f) * cs - beta * sn) | |||||
/ tmp * -1.0f; | |||||
tgp1 = tmpgain + 1.0f; | |||||
tgm1 = tmpgain - 1.0f; | |||||
tmp = tgp1 + tgm1 * cs + beta * sn; | |||||
c[0] = tmpgain * (tgp1 - tgm1 * cs + beta * sn) / tmp; | |||||
c[1] = 2.0f * tmpgain * (tgm1 - tgp1 * cs) / tmp; | |||||
c[2] = tmpgain * (tgp1 - tgm1 * cs - beta * sn) / tmp; | |||||
d[1] = -2.0f * (tgm1 + tgp1 * cs) / tmp * -1.0f; | |||||
d[2] = (tgp1 + tgm1 * cs - beta * sn) / tmp * -1.0f; | |||||
} | } | ||||
else { | else { | ||||
c[0] = tmpgain; | c[0] = tmpgain; | ||||
@@ -230,20 +235,15 @@ void AnalogFilter::computefiltercoefs(void) | |||||
if(!zerocoefs) { | if(!zerocoefs) { | ||||
tmpq = sqrtf(tmpq); | tmpq = sqrtf(tmpq); | ||||
beta = sqrtf(tmpgain) / tmpq; | beta = sqrtf(tmpgain) / tmpq; | ||||
tmp = (tmpgain + 1.0f) - (tmpgain - 1.0f) * cs + beta * sn; | |||||
c[0] = tmpgain | |||||
* ((tmpgain | |||||
+ 1.0f) + (tmpgain - 1.0f) * cs + beta * sn) / tmp; | |||||
c[1] = -2.0f * tmpgain | |||||
* ((tmpgain - 1.0f) + (tmpgain + 1.0f) * cs) / tmp; | |||||
c[2] = tmpgain | |||||
* ((tmpgain | |||||
+ 1.0f) + (tmpgain - 1.0f) * cs - beta * sn) / tmp; | |||||
d[1] = 2.0f * ((tmpgain - 1.0f) - (tmpgain + 1.0f) * cs) | |||||
/ tmp * -1.0f; | |||||
d[2] = ((tmpgain + 1.0f) - (tmpgain - 1.0f) * cs - beta * sn) | |||||
/ tmp * -1.0f; | |||||
tgp1 = tmpgain + 1.0f; | |||||
tgm1 = tmpgain - 1.0f; | |||||
tmp = tgp1 - tgm1 * cs + beta * sn; | |||||
c[0] = tmpgain * (tgp1 + tgm1 * cs + beta * sn) / tmp; | |||||
c[1] = -2.0f * tmpgain * (tgm1 + tgp1 * cs) / tmp; | |||||
c[2] = tmpgain * (tgp1 + tgm1 * cs - beta * sn) / tmp; | |||||
d[1] = 2.0f * (tgm1 - tgp1 * cs) / tmp * -1.0f; | |||||
d[2] = (tgp1 - tgm1 * cs - beta * sn) / tmp * -1.0f; | |||||
} | } | ||||
else { | else { | ||||
c[0] = 1.0f; | c[0] = 1.0f; | ||||
@@ -252,10 +252,16 @@ void AnalogFilter::computefiltercoefs(void) | |||||
order = 2; | order = 2; | ||||
break; | break; | ||||
default: //wrong type | default: //wrong type | ||||
type = 0; | |||||
computefiltercoefs(); | |||||
assert(false && "wrong type for a filter"); | |||||
break; | break; | ||||
} | } | ||||
return coeff; | |||||
} | |||||
void AnalogFilter::computefiltercoefs(void) | |||||
{ | |||||
coeff = AnalogFilter::computeCoeff(type, freq, q, stages, gain, | |||||
samplerate_f, order); | |||||
} | } | ||||
@@ -46,6 +46,9 @@ class AnalogFilter:public Filter | |||||
d[3]; //Feed Back | d[3]; //Feed Back | ||||
} coeff, oldCoeff; | } coeff, oldCoeff; | ||||
static Coeff computeCoeff(int type, float cutoff, float q, int stages, | |||||
float gain, float fs, int &order); | |||||
private: | private: | ||||
struct fstage { | struct fstage { | ||||
float x1, x2; //Input History | float x1, x2; //Input History | ||||
@@ -12,11 +12,37 @@ | |||||
*/ | */ | ||||
#include <cmath> | #include <cmath> | ||||
#include <rtosc/port-sugar.h> | |||||
#include <rtosc/ports.h> | |||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "Alienwah.h" | #include "Alienwah.h" | ||||
using std::complex; | using std::complex; | ||||
#define rObject Alienwah | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports Alienwah::ports = { | |||||
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
//Pvolume/Ppanning are common | |||||
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), | |||||
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), | |||||
rEffPar(PLFOtype, 4, rShort("shape"), "LFO Shape"), | |||||
rEffParTF(PStereo, 5, rShort("stereo"), "Stereo/Mono Mode"), | |||||
rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"), | |||||
rEffPar(Pfeedback, 7, rShort("fb"), "Feedback"), | |||||
rEffPar(Pdelay, 8, rShort("delay"), "Delay"), | |||||
rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"), | |||||
rEffPar(Pphase, 10, rShort("phase"), "Phase"), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
Alienwah::Alienwah(EffectParams pars) | Alienwah::Alienwah(EffectParams pars) | ||||
:Effect(pars), | :Effect(pars), | ||||
lfo(pars.srate, pars.bufsize), | lfo(pars.srate, pars.bufsize), | ||||
@@ -33,6 +33,7 @@ class Alienwah:public Effect | |||||
unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
void cleanup(void); | void cleanup(void); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Alienwah Parameters | //Alienwah Parameters | ||||
EffectLFO lfo; //lfo-ul Alienwah | EffectLFO lfo; //lfo-ul Alienwah | ||||
@@ -12,12 +12,39 @@ | |||||
*/ | */ | ||||
#include <cmath> | #include <cmath> | ||||
#include <rtosc/ports.h> | |||||
#include <rtosc/port-sugar.h> | |||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "Chorus.h" | #include "Chorus.h" | ||||
#include <iostream> | #include <iostream> | ||||
using namespace std; | using namespace std; | ||||
#define rObject Chorus | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports Chorus::ports = { | |||||
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
//Pvolume/Ppanning are common | |||||
rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), | |||||
rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), | |||||
rEffPar(PLFOtype, 4, rShort("shape"), "LFO Shape"), | |||||
rEffParTF(PStereo,5, rShort("stereo"), "Stereo/Mono Mode"), | |||||
rEffPar(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"), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
Chorus::Chorus(EffectParams pars) | Chorus::Chorus(EffectParams pars) | ||||
:Effect(pars), | :Effect(pars), | ||||
lfo(pars.srate, pars.bufsize), | lfo(pars.srate, pars.bufsize), | ||||
@@ -68,6 +68,7 @@ class Chorus:public Effect | |||||
unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
void cleanup(void); | void cleanup(void); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Chorus Parameters | //Chorus Parameters | ||||
unsigned char Pvolume; | unsigned char Pvolume; | ||||
@@ -16,6 +16,33 @@ | |||||
#include "../Misc/WaveShapeSmps.h" | #include "../Misc/WaveShapeSmps.h" | ||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include <cmath> | #include <cmath> | ||||
#include <rtosc/ports.h> | |||||
#include <rtosc/port-sugar.h> | |||||
#define rObject Distorsion | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports Distorsion::ports = { | |||||
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
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"), | |||||
rEffPar(Ptype, 5, rShort("type"), "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"), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
Distorsion::Distorsion(EffectParams pars) | Distorsion::Distorsion(EffectParams pars) | ||||
:Effect(pars), | :Effect(pars), | ||||
@@ -29,6 +29,7 @@ class Distorsion:public Effect | |||||
void cleanup(void); | void cleanup(void); | ||||
void applyfilters(float *efxoutl, float *efxoutr); | void applyfilters(float *efxoutl, float *efxoutr); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Parameters | //Parameters | ||||
unsigned char Pvolume; //Volume or E/R | unsigned char Pvolume; //Volume or E/R | ||||
@@ -16,6 +16,55 @@ | |||||
#include "DynamicFilter.h" | #include "DynamicFilter.h" | ||||
#include "../DSP/Filter.h" | #include "../DSP/Filter.h" | ||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include <rtosc/ports.h> | |||||
#include <rtosc/port-sugar.h> | |||||
#define rObject DynamicFilter | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports DynamicFilter::ports = { | |||||
{"preset::i", rOptions(WahWah, AutoWah, Sweep, VocalMorph1, VocalMorph1) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
//Pvolume/Ppanning are common | |||||
{"Pfreq::i", rShort("freq") | |||||
rDoc("Effect Frequency"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"Pfreqrnd::i", rShort("rand") | |||||
rDoc("Frequency Randomness"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"PLFOtype::i", rShort("shape") | |||||
rDoc("LFO Shape"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"PStereo::T:F", rShort("stereo") | |||||
rDoc("Stereo/Mono Mode"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"Pdepth::i", rShort("depth") | |||||
rDoc("LFO Depth"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"Pampsns::i", rShort("sense") | |||||
rDoc("how the filter varies according to the input amplitude"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"Pampsnsinv::T:F", rShort("sns.inv") | |||||
rDoc("Sense Inversion"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
{"Pampsmooth::i", rShort("smooth") | |||||
rDoc("how smooth the input amplitude changes the filter"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
DynamicFilter::DynamicFilter(EffectParams pars, const AbsTime *time) | DynamicFilter::DynamicFilter(EffectParams pars, const AbsTime *time) | ||||
:Effect(pars), | :Effect(pars), | ||||
@@ -30,6 +30,7 @@ class DynamicFilter:public Effect | |||||
unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
void cleanup(void); | void cleanup(void); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Parametrii DynamicFilter | //Parametrii DynamicFilter | ||||
EffectLFO lfo; //lfo-ul DynamicFilter | EffectLFO lfo; //lfo-ul DynamicFilter | ||||
@@ -14,11 +14,34 @@ | |||||
*/ | */ | ||||
#include <cmath> | #include <cmath> | ||||
#include <rtosc/ports.h> | |||||
#include <rtosc/port-sugar.h> | |||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "Echo.h" | #include "Echo.h" | ||||
#define MAX_DELAY 2 | #define MAX_DELAY 2 | ||||
#define rObject Echo | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports Echo::ports = { | |||||
{"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1, Panning Echo 2, Panning Echo 3, Feedback Echo) | |||||
rProp(parameter) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
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"), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
Echo::Echo(EffectParams pars) | Echo::Echo(EffectParams pars) | ||||
:Effect(pars), | :Effect(pars), | ||||
Pvolume(50), | Pvolume(50), | ||||
@@ -59,6 +59,8 @@ class Echo:public Effect | |||||
unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
int getnumparams(void); | int getnumparams(void); | ||||
void cleanup(void); | void cleanup(void); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Parameters | //Parameters | ||||
unsigned char Pvolume; /**<#1 Volume or Dry/Wetness*/ | unsigned char Pvolume; /**<#1 Volume or Dry/Wetness*/ | ||||
@@ -22,6 +22,27 @@ | |||||
class FilterParams; | class FilterParams; | ||||
class Allocator; | class Allocator; | ||||
#ifndef rEffPar | |||||
#define rEffPar(name, idx, ...) \ | |||||
{STRINGIFY(name) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParCb(idx)} | |||||
#define rEffParTF(name, idx, ...) \ | |||||
{STRINGIFY(name) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)} | |||||
#define rEffParCb(idx) \ | |||||
[](const char *msg, rtosc::RtData &d) {\ | |||||
rObject &obj = *(rObject*)d.obj; \ | |||||
if(rtosc_narguments(msg)) \ | |||||
obj.changepar(idx, rtosc_argument(msg, 0).i); \ | |||||
else \ | |||||
d.reply(d.loc, "i", obj.getpar(idx));} | |||||
#define rEffParTFCb(idx) \ | |||||
[](const char *msg, rtosc::RtData &d) {\ | |||||
rObject &obj = *(rObject*)d.obj; \ | |||||
if(rtosc_narguments(msg)) \ | |||||
obj.changepar(idx, rtosc_argument(msg, 0).T*127); \ | |||||
else \ | |||||
d.reply(d.loc, obj.getpar(idx)?"T":"F");} | |||||
#endif | |||||
struct EffectParams | struct EffectParams | ||||
{ | { | ||||
/** | /** | ||||
@@ -33,6 +33,14 @@ | |||||
#define rObject EffectMgr | #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; \ | |||||
SNIP \ | |||||
name::ports.dispatch(msg, data); \ | |||||
}} | |||||
static const rtosc::Ports local_ports = { | static const rtosc::Ports local_ports = { | ||||
rSelf(EffectMgr), | rSelf(EffectMgr), | ||||
rPaste, | rPaste, | ||||
@@ -71,7 +79,7 @@ static const rtosc::Ports local_ports = { | |||||
//update parameters as well | //update parameters as well | ||||
strncpy(loc, d.loc, 1024); | strncpy(loc, d.loc, 1024); | ||||
char *tail = rindex(loc, '/'); | |||||
char *tail = strrchr(loc, '/'); | |||||
if(!tail) | if(!tail) | ||||
return; | return; | ||||
for(int i=0;i<128;++i) { | for(int i=0;i<128;++i) { | ||||
@@ -94,7 +102,9 @@ static const rtosc::Ports local_ports = { | |||||
eq->getFilter(a,b); | eq->getFilter(a,b); | ||||
d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b); | d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b); | ||||
}}, | }}, | ||||
{"efftype::i", rProp(parameter) rDoc("Get Effect Type"), NULL, | |||||
{"efftype::i", rOptions(Disabled, Reverb, Echo, Chorus, | |||||
Phaser, Alienwah, Distorsion, EQ, DynamicFilter) | |||||
rProp(parameter) rDoc("Get Effect Type"), NULL, | |||||
[](const char *m, rtosc::RtData &d) | [](const char *m, rtosc::RtData &d) | ||||
{ | { | ||||
EffectMgr *eff = (EffectMgr*)d.obj; | EffectMgr *eff = (EffectMgr*)d.obj; | ||||
@@ -121,7 +131,9 @@ static const rtosc::Ports local_ports = { | |||||
//Return the old data for distruction | //Return the old data for distruction | ||||
d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_); | d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_); | ||||
}}, | }}, | ||||
rSubtype(Echo), | |||||
rSubtype(Alienwah), | |||||
rSubtype(Distorsion), | |||||
}; | }; | ||||
const rtosc::Ports &EffectMgr::ports = local_ports; | const rtosc::Ports &EffectMgr::ports = local_ports; | ||||
@@ -17,11 +17,43 @@ | |||||
#include <cmath> | #include <cmath> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <rtosc/ports.h> | |||||
#include <rtosc/port-sugar.h> | |||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "Phaser.h" | #include "Phaser.h" | ||||
using namespace std; | using namespace std; | ||||
#define rObject Phaser | |||||
#define rBegin [](const char *, rtosc::RtData &) { | |||||
#define rEnd } | |||||
rtosc::Ports Phaser::ports = { | |||||
{"preset::i", rOptions(Alienwah 1, Alienwah 2, Alienwah 3, Alienwah 4) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
//Pvolume/Ppanning are common | |||||
rEffPar(lfo.Pfreq, 2, ""), | |||||
rEffPar(lfo.Prandomness, 3, ""), | |||||
rEffPar(lfo.PLFOtype, 4, ""), | |||||
rEffPar(lfo.Pstereo, 5, ""), | |||||
rEffPar(Pdepth, 6, ""), | |||||
rEffPar(Pfb, 7, ""), | |||||
rEffPar(Pstages, 8, ""), | |||||
rEffPar(Plrcross, 9, ""), | |||||
rEffPar(Poffset, 9, ""), | |||||
rEffParTF(Poutsub, 10, ""), | |||||
rEffPar(Pphase, 11, ""), | |||||
rEffPar(Pwidth, 11, ""), | |||||
rEffPar(Phyper, 12, ""), | |||||
rEffPar(Pdistortion, 13, ""), | |||||
rEffPar(Panalog, 14, ""), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
#define PHASER_LFO_SHAPE 2 | #define PHASER_LFO_SHAPE 2 | ||||
#define ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes | #define ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes | ||||
#define ZERO_ 0.00001f // Same idea as above. | #define ZERO_ 0.00001f // Same idea as above. | ||||
@@ -34,6 +34,7 @@ class Phaser:public Effect | |||||
unsigned char getpar(int npar) const; | unsigned char getpar(int npar) const; | ||||
void cleanup(); | void cleanup(); | ||||
static rtosc::Ports ports; | |||||
private: | private: | ||||
//Phaser parameters | //Phaser parameters | ||||
EffectLFO lfo; //Phaser modulator | EffectLFO lfo; //Phaser modulator | ||||
@@ -29,6 +29,7 @@ | |||||
#include "Config.h" | #include "Config.h" | ||||
#include "Util.h" | #include "Util.h" | ||||
#include "Part.h" | #include "Part.h" | ||||
#include "BankDb.h" | |||||
#define INSTRUMENT_EXTENSION ".xiz" | #define INSTRUMENT_EXTENSION ".xiz" | ||||
@@ -39,7 +40,7 @@ using namespace std; | |||||
Bank::Bank(Config *config) | Bank::Bank(Config *config) | ||||
:bankpos(0), defaultinsname(" "), config(config), | :bankpos(0), defaultinsname(" "), config(config), | ||||
bank_msb(0), bank_lsb(0) | |||||
db(new BankDb), bank_msb(0), bank_lsb(0) | |||||
{ | { | ||||
clearbank(); | clearbank(); | ||||
bankfiletitle = dirname; | bankfiletitle = dirname; | ||||
@@ -57,6 +58,7 @@ Bank::Bank(Config *config) | |||||
Bank::~Bank() | Bank::~Bank() | ||||
{ | { | ||||
clearbank(); | clearbank(); | ||||
delete db; | |||||
} | } | ||||
/* | /* | ||||
@@ -179,7 +181,8 @@ int Bank::savetoslot(unsigned int ninstrument, Part *part) | |||||
err = part->saveXML(filename.c_str()); | err = part->saveXML(filename.c_str()); | ||||
if(err) | if(err) | ||||
return err; | return err; | ||||
addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz", (char *) part->Pname); | |||||
addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz", | |||||
(char *) part->Pname); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -350,6 +353,7 @@ bool Bank::bankstruct::operator<(const bankstruct &b) const | |||||
void Bank::rescanforbanks() | void Bank::rescanforbanks() | ||||
{ | { | ||||
db->clear(); | |||||
//remove old banks | //remove old banks | ||||
banks.clear(); | banks.clear(); | ||||
@@ -362,6 +366,7 @@ void Bank::rescanforbanks() | |||||
//remove duplicate bank names | //remove duplicate bank names | ||||
for(int j = 0; j < (int) banks.size() - 1; ++j) { | for(int j = 0; j < (int) banks.size() - 1; ++j) { | ||||
db->addBankDir(banks[j].dir); | |||||
int dupl = 0; | int dupl = 0; | ||||
for(int i = j + 1; i < (int) banks.size(); ++i) { | for(int i = j + 1; i < (int) banks.size(); ++i) { | ||||
if(banks[i].name == banks[j].name) { | if(banks[i].name == banks[j].name) { | ||||
@@ -376,6 +381,7 @@ void Bank::rescanforbanks() | |||||
if(dupl) | if(dupl) | ||||
j += dupl; | j += dupl; | ||||
} | } | ||||
db->scanBanks(); | |||||
} | } | ||||
void Bank::setMsb(uint8_t msb) | void Bank::setMsb(uint8_t msb) | ||||
@@ -453,6 +459,17 @@ void Bank::clearbank() | |||||
dirname.clear(); | dirname.clear(); | ||||
} | } | ||||
std::vector<std::string> Bank::search(std::string s) const | |||||
{ | |||||
std::vector<std::string> out; | |||||
auto vec = db->search(s); | |||||
for(auto e:vec) { | |||||
out.push_back(e.name); | |||||
out.push_back(e.bank+e.file); | |||||
} | |||||
return out; | |||||
} | |||||
int Bank::addtobank(int pos, string filename, string name) | int Bank::addtobank(int pos, string filename, string name) | ||||
{ | { | ||||
if((pos >= 0) && (pos < BANK_SIZE)) { | if((pos >= 0) && (pos < BANK_SIZE)) { | ||||
@@ -68,7 +68,7 @@ class Bank | |||||
std::vector<bankstruct> banks; | std::vector<bankstruct> banks; | ||||
int bankpos; | int bankpos; | ||||
struct ins_t { | struct ins_t { | ||||
ins_t(void); | ins_t(void); | ||||
std::string name; | std::string name; | ||||
@@ -76,6 +76,8 @@ class Bank | |||||
std::string filename; | std::string filename; | ||||
} ins[BANK_SIZE]; | } ins[BANK_SIZE]; | ||||
std::vector<std::string> search(std::string) const; | |||||
private: | private: | ||||
//it adds a filename to the bank | //it adds a filename to the bank | ||||
@@ -100,6 +102,7 @@ class Bank | |||||
void normalizedirsuffix(std::string &dirname) const; | void normalizedirsuffix(std::string &dirname) const; | ||||
Config* const config; | Config* const config; | ||||
class BankDb *db; | |||||
public: | public: | ||||
uint8_t bank_msb; | uint8_t bank_msb; | ||||
@@ -0,0 +1,219 @@ | |||||
#include "BankDb.h" | |||||
#include "XMLwrapper.h" | |||||
#include "../globals.h" | |||||
#include <cstring> | |||||
#include <dirent.h> | |||||
#define INSTRUMENT_EXTENSION ".xiz" | |||||
using std::string; | |||||
typedef BankDb::svec svec; | |||||
typedef BankDb::bvec bvec; | |||||
BankEntry::BankEntry(void) | |||||
:id(0), add(false), pad(false), sub(false) | |||||
{} | |||||
bool sfind(std::string hay, std::string needle) | |||||
{ | |||||
return strcasestr(hay.c_str(), needle.c_str()); | |||||
} | |||||
bool BankEntry::match(string s) const | |||||
{ | |||||
if(s == "#pad") | |||||
return pad; | |||||
else if(s == "#sub") | |||||
return sub; | |||||
else if(s == "#add") | |||||
return add; | |||||
return sfind(file,s) || sfind(name,s) || sfind(bank, s) || | |||||
sfind(type, s) || sfind(comments,s) || sfind(author,s); | |||||
} | |||||
static svec split(string s) | |||||
{ | |||||
svec vec; | |||||
string ss; | |||||
for(char c:s) { | |||||
if(isspace(c) && !ss.empty()) { | |||||
vec.push_back(ss); | |||||
ss.clear(); | |||||
} else if(!isspace(c)) { | |||||
ss.push_back(c); | |||||
} | |||||
} | |||||
if(!ss.empty()) | |||||
vec.push_back(ss); | |||||
return vec; | |||||
} | |||||
static string line(string s) | |||||
{ | |||||
string ss; | |||||
for(char c:s) { | |||||
if(c != '\n') | |||||
ss.push_back(c); | |||||
else | |||||
return ss; | |||||
} | |||||
return ss; | |||||
} | |||||
bvec BankDb::search(std::string ss) const | |||||
{ | |||||
bvec vec; | |||||
const svec sterm = split(ss); | |||||
for(auto field:fields) { | |||||
bool match = true; | |||||
for(auto s:sterm) | |||||
match &= field.match(s); | |||||
if(match) | |||||
vec.push_back(field); | |||||
} | |||||
return vec; | |||||
} | |||||
void BankDb::addBankDir(std::string bnk) | |||||
{ | |||||
bool repeat = false; | |||||
for(auto b:banks) | |||||
repeat |= b == bnk; | |||||
if(!repeat) | |||||
banks.push_back(bnk); | |||||
} | |||||
void BankDb::clear(void) | |||||
{ | |||||
banks.clear(); | |||||
fields.clear(); | |||||
} | |||||
void BankDb::scanBanks(void) | |||||
{ | |||||
fields.clear(); | |||||
for(auto bank:banks) | |||||
{ | |||||
DIR *dir = opendir(bank.c_str()); | |||||
if(!dir) | |||||
continue; | |||||
struct dirent *fn; | |||||
while((fn = readdir(dir))) { | |||||
const char *filename = fn->d_name; | |||||
//check for extension | |||||
if(!strstr(filename, INSTRUMENT_EXTENSION)) | |||||
continue; | |||||
auto xiz = processXiz(filename, bank); | |||||
fields.push_back(xiz); | |||||
} | |||||
closedir(dir); | |||||
} | |||||
} | |||||
BankEntry BankDb::processXiz(std::string filename, std::string bank) const | |||||
{ | |||||
//verify if the name is like this NNNN-name (where N is a digit) | |||||
int no = 0; | |||||
unsigned int startname = 0; | |||||
for(unsigned int i = 0; i < 4; ++i) { | |||||
if(filename.length() <= i) | |||||
break; | |||||
if(isdigit(filename[i])) { | |||||
no = no * 10 + (filename[i] - '0'); | |||||
startname++; | |||||
} | |||||
} | |||||
if(startname + 1 < filename.length()) | |||||
startname++; //to take out the "-" | |||||
std::string name = filename; | |||||
//remove the file extension | |||||
for(int i = name.size() - 1; i >= 2; i--) { | |||||
if(name[i] == '.') { | |||||
name = name.substr(0, i); | |||||
break; | |||||
} | |||||
} | |||||
BankEntry entry; | |||||
entry.file = filename; | |||||
entry.bank = bank; | |||||
entry.id = no; | |||||
if(no != 0) //the instrument position in the bank is found | |||||
entry.name = name.substr(startname); | |||||
else | |||||
entry.name = name; | |||||
const char *types[] = { | |||||
"None", | |||||
"Piano", | |||||
"Chromatic Percussion", | |||||
"Organ", | |||||
"Guitar", | |||||
"Bass", | |||||
"Solo Strings", | |||||
"Ensemble", | |||||
"Brass", | |||||
"Reed", | |||||
"Pipe", | |||||
"Synth Lead", | |||||
"Synth Pad", | |||||
"Synth Effects", | |||||
"Ethnic", | |||||
"Percussive", | |||||
"Sound Effects", | |||||
}; | |||||
//Try to obtain other metadata (expensive) | |||||
XMLwrapper xml; | |||||
string fname = bank+filename; | |||||
int ret = xml.loadXMLfile(fname); | |||||
if(xml.enterbranch("INSTRUMENT")) { | |||||
if(xml.enterbranch("INFO")) { | |||||
char author[1024]; | |||||
char comments[1024]; | |||||
int type = 0; | |||||
xml.getparstr("author", author, 1024); | |||||
xml.getparstr("comments", comments, 1024); | |||||
type = xml.getpar("type", 0, 0, 16); | |||||
entry.author = author; | |||||
entry.comments = comments; | |||||
entry.type = types[type]; | |||||
xml.exitbranch(); | |||||
} | |||||
if(xml.enterbranch("INSTRUMENT_KIT")) { | |||||
for(int i = 0; i < NUM_KIT_ITEMS; ++i) { | |||||
if(xml.enterbranch("INSTRUMENT_KIT_ITEM", i) == 0) { | |||||
entry.add |= xml.getparbool("add_enabled", false); | |||||
entry.sub |= xml.getparbool("sub_enabled", false); | |||||
entry.pad |= xml.getparbool("pad_enabled", false); | |||||
xml.exitbranch(); | |||||
} | |||||
} | |||||
xml.exitbranch(); | |||||
} | |||||
xml.exitbranch(); | |||||
} | |||||
//printf("Bank Entry:\n"); | |||||
//printf("\tname - %s\n", entry.name.c_str()); | |||||
//printf("\tauthor - %s\n", line(entry.author).c_str()); | |||||
//printf("\tadd/pad/sub - %d/%d/%d\n", entry.add, entry.pad, entry.sub); | |||||
return entry; | |||||
} |
@@ -0,0 +1,50 @@ | |||||
#pragma once | |||||
#include <string> | |||||
#include <vector> | |||||
struct BankEntry | |||||
{ | |||||
BankEntry(void); | |||||
std::string file; | |||||
std::string bank; | |||||
std::string name; | |||||
std::string comments; | |||||
std::string author; | |||||
std::string type; | |||||
int id; | |||||
bool add; | |||||
bool pad; | |||||
bool sub; | |||||
typedef std::vector<std::string> svec; | |||||
svec tags(void) const; | |||||
bool match(std::string) const; | |||||
}; | |||||
class BankDb | |||||
{ | |||||
public: | |||||
typedef std::vector<std::string> svec; | |||||
typedef std::vector<BankEntry> bvec; | |||||
//search for banks | |||||
//uses a space separated list of keywords and | |||||
//finds something that matches ALL keywords | |||||
bvec search(std::string) const; | |||||
//fully qualified paths only | |||||
void addBankDir(std::string); | |||||
//clear all known entries and banks | |||||
void clear(void); | |||||
//List of all tags | |||||
svec tags(void) const; | |||||
//scan banks | |||||
void scanBanks(void); | |||||
private: | |||||
BankEntry processXiz(std::string, std::string) const; | |||||
bvec fields; | |||||
svec banks; | |||||
}; |
@@ -22,6 +22,7 @@ | |||||
#include "../Effects/EffectMgr.h" | #include "../Effects/EffectMgr.h" | ||||
#include "../DSP/FFTwrapper.h" | #include "../DSP/FFTwrapper.h" | ||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "../Containers/ScratchString.h" | |||||
#include "../Nio/Nio.h" | #include "../Nio/Nio.h" | ||||
#include "PresetExtractor.h" | #include "PresetExtractor.h" | ||||
@@ -74,7 +75,7 @@ static const Ports sysefxPort = | |||||
static const Ports sysefsendto = | static const Ports sysefsendto = | ||||
{ | { | ||||
{"to#" STRINGIFY(NUM_SYS_EFX) "::i", | |||||
{"to#" STRINGIFY(NUM_SYS_EFX) "::i", | |||||
rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d) | rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d) | ||||
{ | { | ||||
//same ugly workaround as before | //same ugly workaround as before | ||||
@@ -97,6 +98,17 @@ static const Ports sysefsendto = | |||||
}} | }} | ||||
}; | }; | ||||
#define rBegin [](const char *msg, RtData &d) { Master *m = (Master*)d.obj | |||||
#define rEnd } | |||||
static const Ports watchPorts = { | |||||
{"add:s", rDoc("Add synthesis state to watch"), 0, | |||||
rBegin; | |||||
m->watcher.add_watch(rtosc_argument(msg,0).s); | |||||
rEnd}, | |||||
}; | |||||
extern const Ports bankPorts; | |||||
static const Ports master_ports = { | static const Ports master_ports = { | ||||
rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."), | rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."), | ||||
rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS | rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS | ||||
@@ -104,8 +116,12 @@ static const Ports master_ports = { | |||||
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX | rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX | ||||
rRecur(microtonal, "Micrtonal Mapping Functionality"), | rRecur(microtonal, "Micrtonal Mapping Functionality"), | ||||
rRecur(ctl, "Controller"), | rRecur(ctl, "Controller"), | ||||
rArrayI(Pinsparts, NUM_INS_EFX, "Part to insert part onto"), | |||||
{"Pkeyshift::i", rProp(parameter) rLinear(0,127) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { | |||||
rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-1, Master), | |||||
rOptions(Part1, Part2, Part3, Part4, Part5, Part6, | |||||
Part7, Part8, Part9, Part10, Part11, Part12, | |||||
Part13, Part14, Part15, Part16), | |||||
"Part to insert part onto"), | |||||
{"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { | |||||
if(rtosc_narguments(m)==0) { | if(rtosc_narguments(m)==0) { | ||||
d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift); | d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift); | ||||
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | ||||
@@ -116,6 +132,22 @@ static const Ports master_ports = { | |||||
{"get-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) { | {"get-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) { | ||||
Master *m = (Master*)d.obj; | Master *m = (Master*)d.obj; | ||||
d.reply("/vu-meter", "bb", sizeof(m->vu), &m->vu, sizeof(float)*NUM_MIDI_PARTS, m->vuoutpeakpart);}}, | d.reply("/vu-meter", "bb", sizeof(m->vu), &m->vu, sizeof(float)*NUM_MIDI_PARTS, m->vuoutpeakpart);}}, | ||||
{"vu-meter:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) { | |||||
Master *m = (Master*)d.obj; | |||||
char types[6+NUM_MIDI_PARTS+1] = {0}; | |||||
rtosc_arg_t args[6+NUM_MIDI_PARTS+1]; | |||||
for(int i=0; i<6+NUM_MIDI_PARTS; ++i) | |||||
types[i] = 'f'; | |||||
args[0].f = m->vu.outpeakl; | |||||
args[1].f = m->vu.outpeakr; | |||||
args[2].f = m->vu.maxoutpeakl; | |||||
args[3].f = m->vu.maxoutpeakr; | |||||
args[4].f = m->vu.rmspeakl; | |||||
args[5].f = m->vu.rmspeakr; | |||||
for(int i=0; i<NUM_MIDI_PARTS; ++i) | |||||
args[6+i].f = m->vuoutpeakpart[i]; | |||||
d.replyArray("/vu-meter", types, args);}}, | |||||
{"reset-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) { | {"reset-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) { | ||||
Master *m = (Master*)d.obj; | Master *m = (Master*)d.obj; | ||||
m->vuresetpeaks();}}, | m->vuresetpeaks();}}, | ||||
@@ -129,14 +161,21 @@ static const Ports master_ports = { | |||||
m->part[i] = p; | m->part[i] = p; | ||||
p->initialize_rt(); | p->initialize_rt(); | ||||
}}, | }}, | ||||
{"Pvolume::i", rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0, | |||||
{"active_keys:", rProp("Obtain a list of active notes"), 0, | |||||
rBegin; | |||||
char keys[129] = {0}; | |||||
for(int i=0; i<128; ++i) | |||||
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, | |||||
[](const char *m, rtosc::RtData &d) { | [](const char *m, rtosc::RtData &d) { | ||||
if(rtosc_narguments(m)==0) { | if(rtosc_narguments(m)==0) { | ||||
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | ||||
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { | ||||
((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127)); | ((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127)); | ||||
d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}}, | d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}}, | ||||
{"volume::i", rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0, | |||||
{"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0, | |||||
[](const char *m, rtosc::RtData &d) { | [](const char *m, rtosc::RtData &d) { | ||||
if(rtosc_narguments(m)==0) { | if(rtosc_narguments(m)==0) { | ||||
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); | ||||
@@ -240,8 +279,18 @@ static const Ports master_ports = { | |||||
{"HDDRecorder/pause:", rDoc("Pause recording"), 0, [](const char *, RtData &d) { | {"HDDRecorder/pause:", rDoc("Pause recording"), 0, [](const char *, RtData &d) { | ||||
Master *m = (Master*)d.obj; | Master *m = (Master*)d.obj; | ||||
m->HDDRecorder.pause();}}, | m->HDDRecorder.pause();}}, | ||||
{"watch/", rDoc("Interface to grab out live synthesis state"), &watchPorts, | |||||
rBOIL_BEGIN; | |||||
SNIP; | |||||
watchPorts.dispatch(msg, data); | |||||
rBOIL_END}, | |||||
{"bank/", rDoc("Controls for instrument banks"), &bankPorts, | |||||
[](const char*,RtData&) {}}, | |||||
}; | }; | ||||
#undef rBegin | |||||
#undef rEnd | |||||
const Ports &Master::ports = master_ports; | const Ports &Master::ports = master_ports; | ||||
class DataObj:public rtosc::RtData | class DataObj:public rtosc::RtData | ||||
@@ -257,6 +306,12 @@ class DataObj:public rtosc::RtData | |||||
forwarded = false; | forwarded = false; | ||||
} | } | ||||
virtual void replyArray(const char *path, const char *args, rtosc_arg_t *vals) override | |||||
{ | |||||
char *buffer = bToU->buffer(); | |||||
rtosc_amessage(buffer,bToU->buffer_size(),path,args,vals); | |||||
reply(buffer); | |||||
} | |||||
virtual void reply(const char *path, const char *args, ...) override | virtual void reply(const char *path, const char *args, ...) override | ||||
{ | { | ||||
va_list va; | va_list va; | ||||
@@ -333,9 +388,11 @@ Master::Master(const SYNTH_T &synth_, Config* config) | |||||
fakepeakpart[npart] = 0; | fakepeakpart[npart] = 0; | ||||
} | } | ||||
ScratchString ss; | |||||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | ||||
part[npart] = new Part(*memory, synth, time, config->cfg.GzipCompression, | part[npart] = new Part(*memory, synth, time, config->cfg.GzipCompression, | ||||
config->cfg.Interpolation, µtonal, fft); | |||||
config->cfg.Interpolation, µtonal, fft, &watcher, | |||||
(ss+"/part"+npart+"/").c_str); | |||||
//Insertion Effects init | //Insertion Effects init | ||||
for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | ||||
@@ -345,6 +402,9 @@ Master::Master(const SYNTH_T &synth_, Config* config) | |||||
for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | ||||
sysefx[nefx] = new EffectMgr(*memory, synth, 0, &time); | sysefx[nefx] = new EffectMgr(*memory, synth, 0, &time); | ||||
//Note Visualization | |||||
for(int i=0; i<128; ++i) | |||||
activeNotes[i] = 0; | |||||
defaults(); | defaults(); | ||||
@@ -358,7 +418,7 @@ void Master::applyOscEvent(const char *msg) | |||||
DataObj d{loc_buf, 1024, this, bToU}; | DataObj d{loc_buf, 1024, this, bToU}; | ||||
memset(loc_buf, 0, sizeof(loc_buf)); | memset(loc_buf, 0, sizeof(loc_buf)); | ||||
d.matches = 0; | d.matches = 0; | ||||
if(strcmp(msg, "/get-vu") && false) { | if(strcmp(msg, "/get-vu") && false) { | ||||
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40); | fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40); | ||||
fprintf(stdout, "backend[*]: '%s'<%s>\n", msg, | fprintf(stdout, "backend[*]: '%s'<%s>\n", msg, | ||||
@@ -411,12 +471,14 @@ void Master::defaults() | |||||
void Master::noteOn(char chan, char note, char velocity) | void Master::noteOn(char chan, char note, char velocity) | ||||
{ | { | ||||
if(velocity) { | if(velocity) { | ||||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||||
if(chan == part[npart]->Prcvchn) { | if(chan == part[npart]->Prcvchn) { | ||||
fakepeakpart[npart] = velocity * 2; | fakepeakpart[npart] = velocity * 2; | ||||
if(part[npart]->Penabled) | if(part[npart]->Penabled) | ||||
part[npart]->NoteOn(note, velocity, keyshift); | part[npart]->NoteOn(note, velocity, keyshift); | ||||
} | } | ||||
} | |||||
activeNotes[(int)note] = 1; | |||||
} | } | ||||
else | else | ||||
this->noteOff(chan, note); | this->noteOff(chan, note); | ||||
@@ -431,6 +493,7 @@ void Master::noteOff(char chan, char note) | |||||
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | ||||
if((chan == part[npart]->Prcvchn) && part[npart]->Penabled) | if((chan == part[npart]->Prcvchn) && part[npart]->Penabled) | ||||
part[npart]->NoteOff(note); | part[npart]->NoteOff(note); | ||||
activeNotes[(int)note] = 0; | |||||
} | } | ||||
/* | /* | ||||
@@ -633,6 +696,13 @@ bool Master::AudioOut(float *outr, float *outl) | |||||
bToU->write("/request-memory", ""); | bToU->write("/request-memory", ""); | ||||
pendingMemory = true; | pendingMemory = true; | ||||
} | } | ||||
//Handle watch points | |||||
if(bToU) | |||||
watcher.write_back = bToU; | |||||
watcher.tick(); | |||||
//Handle user events TODO move me to a proper location | //Handle user events TODO move me to a proper location | ||||
char loc_buf[1024]; | char loc_buf[1024]; | ||||
DataObj d{loc_buf, 1024, this, bToU}; | DataObj d{loc_buf, 1024, this, bToU}; | ||||
@@ -677,7 +747,7 @@ bool Master::AudioOut(float *outr, float *outl) | |||||
} | } | ||||
if(events>1 && false) | if(events>1 && false) | ||||
fprintf(stderr, "backend: %d events per cycle\n",events); | fprintf(stderr, "backend: %d events per cycle\n",events); | ||||
//Swaps the Left channel with Right Channel | //Swaps the Left channel with Right Channel | ||||
if(swaplr) | if(swaplr) | ||||
@@ -24,6 +24,7 @@ | |||||
#include "Recorder.h" | #include "Recorder.h" | ||||
#include "../Params/Controller.h" | #include "../Params/Controller.h" | ||||
#include "../Synth/WatchPoint.h" | |||||
class Allocator; | class Allocator; | ||||
@@ -158,6 +159,13 @@ class Master | |||||
//Statistics on output levels | //Statistics on output levels | ||||
vuData vu; | vuData vu; | ||||
//Display info on midi notes | |||||
bool activeNotes[128]; | |||||
//Other watchers | |||||
WatchManager watcher; | |||||
//Midi Learn | |||||
rtosc::MidiMapperRT midi; | rtosc::MidiMapperRT midi; | ||||
bool frozenState;//read-only parameters for threadsafe actions | bool frozenState;//read-only parameters for threadsafe actions | ||||
@@ -73,8 +73,8 @@ void path_search(const char *m, const char *url) | |||||
using rtosc::Port; | using rtosc::Port; | ||||
//assumed upper bound of 32 ports (may need to be resized) | //assumed upper bound of 32 ports (may need to be resized) | ||||
char types[129]; | |||||
rtosc_arg_t args[128]; | |||||
char types[256+1]; | |||||
rtosc_arg_t args[256]; | |||||
size_t pos = 0; | size_t pos = 0; | ||||
const Ports *ports = NULL; | const Ports *ports = NULL; | ||||
const char *str = rtosc_argument(m,0).s; | const char *str = rtosc_argument(m,0).s; | ||||
@@ -95,7 +95,7 @@ void path_search(const char *m, const char *url) | |||||
if(ports) { | if(ports) { | ||||
//RTness not confirmed here | //RTness not confirmed here | ||||
for(const Port &p:*ports) { | for(const Port &p:*ports) { | ||||
if(strstr(p.name, needle)!=p.name) | |||||
if(strstr(p.name, needle) != p.name || !p.name) | |||||
continue; | continue; | ||||
types[pos] = 's'; | types[pos] = 's'; | ||||
args[pos++].s = p.name; | args[pos++].s = p.name; | ||||
@@ -120,6 +120,8 @@ void path_search(const char *m, const char *url) | |||||
lo_address addr = lo_address_new_from_url(url); | lo_address addr = lo_address_new_from_url(url); | ||||
if(addr) | if(addr) | ||||
lo_send_message(addr, buffer, msg); | lo_send_message(addr, buffer, msg); | ||||
lo_address_free(addr); | |||||
lo_message_free(msg); | |||||
} | } | ||||
} | } | ||||
@@ -137,7 +139,7 @@ static int handler_function(const char *path, const char *types, lo_arg **argv, | |||||
mw->transmitMsg("/echo", "ss", "OSC_URL", tmp); | mw->transmitMsg("/echo", "ss", "OSC_URL", tmp); | ||||
mw->activeUrl(tmp); | mw->activeUrl(tmp); | ||||
} | } | ||||
free((void*)tmp); | |||||
} | } | ||||
char buffer[2048]; | char buffer[2048]; | ||||
@@ -146,7 +148,7 @@ static int handler_function(const char *path, const char *types, lo_arg **argv, | |||||
lo_message_serialise(msg, path, buffer, &size); | lo_message_serialise(msg, path, buffer, &size); | ||||
if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) { | if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) { | ||||
path_search(buffer, mw->activeUrl().c_str()); | path_search(buffer, mw->activeUrl().c_str()); | ||||
} else if(buffer[0]=='/' && rindex(buffer, '/')[1]) { | |||||
} else if(buffer[0]=='/' && strrchr(buffer, '/')[1]) { | |||||
mw->transmitMsg(rtosc::Ports::collapsePath(buffer)); | mw->transmitMsg(rtosc::Ports::collapsePath(buffer)); | ||||
} | } | ||||
@@ -155,6 +157,16 @@ static int handler_function(const char *path, const char *types, lo_arg **argv, | |||||
typedef void(*cb_t)(void*,const char*); | typedef void(*cb_t)(void*,const char*); | ||||
//utility method (should be moved to a better location) | |||||
template <class T, class V> | |||||
std::vector<T> keys(const std::map<T,V> &m) | |||||
{ | |||||
std::vector<T> vec; | |||||
for(auto &kv: m) | |||||
vec.push_back(kv.first); | |||||
return vec; | |||||
} | |||||
/***************************************************************************** | /***************************************************************************** | ||||
* Memory Deallocation * | * Memory Deallocation * | ||||
@@ -484,7 +496,8 @@ public: | |||||
master->time, | master->time, | ||||
config->cfg.GzipCompression, | config->cfg.GzipCompression, | ||||
config->cfg.Interpolation, | config->cfg.Interpolation, | ||||
&master->microtonal, master->fft); | |||||
&master->microtonal, master->fft, &master->watcher, | |||||
("/part"+to_s(npart)+"/").c_str()); | |||||
if(p->loadXMLinstrument(filename)) | if(p->loadXMLinstrument(filename)) | ||||
fprintf(stderr, "Warning: failed to load part<%s>!\n", filename); | fprintf(stderr, "Warning: failed to load part<%s>!\n", filename); | ||||
@@ -662,6 +675,11 @@ public: | |||||
void write(const char *path, const char *args, ...); | void write(const char *path, const char *args, ...); | ||||
void write(const char *path, const char *args, va_list va); | void write(const char *path, const char *args, va_list va); | ||||
void currentUrl(string addr) | |||||
{ | |||||
curr_url = addr; | |||||
known_remotes.insert(addr); | |||||
} | |||||
// Send a message to a remote client | // Send a message to a remote client | ||||
void sendToRemote(const char *msg, std::string dest); | void sendToRemote(const char *msg, std::string dest); | ||||
@@ -720,6 +738,7 @@ public: | |||||
//LIBLO | //LIBLO | ||||
lo_server server; | lo_server server; | ||||
string last_url, curr_url; | string last_url, curr_url; | ||||
std::set<string> known_remotes; | |||||
//Synthesis Rate Parameters | //Synthesis Rate Parameters | ||||
const SYNTH_T synth; | const SYNTH_T synth; | ||||
@@ -750,6 +769,7 @@ class MwDataObj:public rtosc::RtData | |||||
~MwDataObj(void) | ~MwDataObj(void) | ||||
{ | { | ||||
delete[] loc; | |||||
delete[] buffer; | delete[] buffer; | ||||
} | } | ||||
@@ -773,6 +793,17 @@ class MwDataObj:public rtosc::RtData | |||||
} | } | ||||
va_end(va); | va_end(va); | ||||
} | } | ||||
virtual void replyArray(const char *path, const char *args, rtosc_arg_t *argd) override | |||||
{ | |||||
//printf("reply building '%s'\n", path); | |||||
if(!strcmp(path, "/forward")) { //forward the information to the backend | |||||
args++; | |||||
rtosc_amessage(buffer,4*4096,path,args,argd); | |||||
} else { | |||||
rtosc_amessage(buffer,4*4096,path,args,argd); | |||||
reply(buffer); | |||||
} | |||||
} | |||||
virtual void reply(const char *msg){ | virtual void reply(const char *msg){ | ||||
mwi->sendToCurrentRemote(msg); | mwi->sendToCurrentRemote(msg); | ||||
}; | }; | ||||
@@ -841,7 +872,8 @@ using rtosc::RtData; | |||||
* - Load Bank * | * - Load Bank * | ||||
* - Refresh List of Banks * | * - Refresh List of Banks * | ||||
*****************************************************************************/ | *****************************************************************************/ | ||||
rtosc::Ports bankPorts = { | |||||
extern const rtosc::Ports bankPorts; | |||||
const rtosc::Ports bankPorts = { | |||||
{"rescan:", 0, 0, | {"rescan:", 0, 0, | ||||
rBegin; | rBegin; | ||||
impl.rescanforbanks(); | impl.rescanforbanks(); | ||||
@@ -851,6 +883,48 @@ rtosc::Ports bankPorts = { | |||||
d.reply("/bank/bank_select", "iss", i++, elm.name.c_str(), elm.dir.c_str()); | d.reply("/bank/bank_select", "iss", i++, elm.name.c_str(), elm.dir.c_str()); | ||||
d.reply("/bank/bank_select", "i", impl.bankpos); | d.reply("/bank/bank_select", "i", impl.bankpos); | ||||
rEnd}, | |||||
{"bank_list:", 0, 0, | |||||
rBegin; | |||||
#define MAX_BANKS 256 | |||||
char types[MAX_BANKS*2+1]={0}; | |||||
rtosc_arg_t args[MAX_BANKS*2]; | |||||
int i = 0; | |||||
for(auto &elm : impl.banks) { | |||||
types[i] = types [i + 1] = 's'; | |||||
args[i++].s = elm.name.c_str(); | |||||
args[i++].s = elm.dir.c_str(); | |||||
} | |||||
d.replyArray("/bank/bank_list", types, args); | |||||
#undef MAX_BANKS | |||||
rEnd}, | |||||
{"types:", 0, 0, | |||||
rBegin; | |||||
const char *types[17]; | |||||
types[ 0] = "None"; | |||||
types[ 1] = "Piano"; | |||||
types[ 2] = "Chromatic Percussion"; | |||||
types[ 3] = "Organ"; | |||||
types[ 4] = "Guitar"; | |||||
types[ 5] = "Bass"; | |||||
types[ 6] = "Solo Strings"; | |||||
types[ 7] = "Ensemble"; | |||||
types[ 8] = "Brass"; | |||||
types[ 9] = "Reed"; | |||||
types[10] = "Pipe"; | |||||
types[11] = "Synth Lead"; | |||||
types[12] = "Synth Pad"; | |||||
types[13] = "Synth Effects"; | |||||
types[14] = "Ethnic"; | |||||
types[15] = "Percussive"; | |||||
types[16] = "Sound Effects"; | |||||
char t[17+1]={0}; | |||||
rtosc_arg_t args[17]; | |||||
for(int i=0; i<17; ++i) { | |||||
t[i] = 's'; | |||||
args[i].s = types[i]; | |||||
} | |||||
d.replyArray("/bank/types", t, args); | |||||
rEnd}, | rEnd}, | ||||
{"slot#1024:", 0, 0, | {"slot#1024:", 0, 0, | ||||
rBegin; | rBegin; | ||||
@@ -913,13 +987,19 @@ rtosc::Ports bankPorts = { | |||||
d.reply("/alert", "s", | d.reply("/alert", "s", | ||||
"Failed To Clear Bank Slot, please check file permissions"); | "Failed To Clear Bank Slot, please check file permissions"); | ||||
rEnd}, | rEnd}, | ||||
{"msb:i", 0, 0, | |||||
{"msb::i", 0, 0, | |||||
rBegin; | rBegin; | ||||
impl.setMsb(rtosc_argument(msg, 0).i); | |||||
if(rtosc_narguments(msg)) | |||||
impl.setMsb(rtosc_argument(msg, 0).i); | |||||
else | |||||
d.reply(d.loc, "i", impl.bank_msb); | |||||
rEnd}, | rEnd}, | ||||
{"lsb:i", 0, 0, | |||||
{"lsb::i", 0, 0, | |||||
rBegin; | rBegin; | ||||
impl.setLsb(rtosc_argument(msg, 0).i); | |||||
if(rtosc_narguments(msg)) | |||||
impl.setLsb(rtosc_argument(msg, 0).i); | |||||
else | |||||
d.reply(d.loc, "i", impl.bank_lsb); | |||||
rEnd}, | rEnd}, | ||||
{"newbank:s", 0, 0, | {"newbank:s", 0, 0, | ||||
rBegin; | rBegin; | ||||
@@ -927,6 +1007,19 @@ rtosc::Ports bankPorts = { | |||||
if(err) | if(err) | ||||
d.reply("/alert", "s", "Error: Could not make a new bank (directory).."); | d.reply("/alert", "s", "Error: Could not make a new bank (directory).."); | ||||
rEnd}, | rEnd}, | ||||
{"search:s", 0, 0, | |||||
rBegin; | |||||
auto res = impl.search(rtosc_argument(msg, 0).s); | |||||
#define MAX_SEARCH 128 | |||||
char res_type[MAX_SEARCH+1] = {0}; | |||||
rtosc_arg_t res_dat[MAX_SEARCH] = {0}; | |||||
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) { | |||||
res_type[i] = 's'; | |||||
res_dat[i].s = res[i].c_str(); | |||||
} | |||||
d.replyArray("/bank/search_results", res_type, res_dat); | |||||
#undef MAX_SEARCH | |||||
rEnd}, | |||||
}; | }; | ||||
/****************************************************************************** | /****************************************************************************** | ||||
@@ -1025,6 +1118,10 @@ static rtosc::Ports middwareSnoopPorts = { | |||||
xml.loadXMLfile(file); | xml.loadXMLfile(file); | ||||
loadMidiLearn(xml, impl.midi_mapper); | loadMidiLearn(xml, impl.midi_mapper); | ||||
rEnd}, | rEnd}, | ||||
{"clear_xlz:", 0, 0, | |||||
rBegin; | |||||
impl.midi_mapper.clear(); | |||||
rEnd}, | |||||
//scale file stuff | //scale file stuff | ||||
{"load_xsz:s", 0, 0, | {"load_xsz:s", 0, 0, | ||||
rBegin; | rBegin; | ||||
@@ -1134,6 +1231,30 @@ static rtosc::Ports middwareSnoopPorts = { | |||||
rBegin; | rBegin; | ||||
impl.undo.seekHistory(+1); | impl.undo.seekHistory(+1); | ||||
rEnd}, | 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}; | |||||
for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) { | |||||
auto val = midi.inv_map[key[i]]; | |||||
argt[4*i+0] = 'i'; | |||||
args[4*i+0].i = std::get<1>(val); | |||||
argt[4*i+1] = 's'; | |||||
args[4*i+1].s = key[i].c_str(); | |||||
argt[4*i+2] = 'i'; | |||||
args[4*i+2].i = 0; | |||||
argt[4*i+3] = 'i'; | |||||
args[4*i+3].i = 127; | |||||
} | |||||
d.replyArray(d.loc, argt, args); | |||||
#undef MAX_MIDI | |||||
rEnd}, | |||||
{"learn:s", 0, 0, | {"learn:s", 0, 0, | ||||
rBegin; | rBegin; | ||||
string addr = rtosc_argument(msg, 0).s; | string addr = rtosc_argument(msg, 0).s; | ||||
@@ -1162,7 +1283,7 @@ static rtosc::Ports middlewareReplyPorts = { | |||||
const char *type = rtosc_argument(msg, 0).s; | const char *type = rtosc_argument(msg, 0).s; | ||||
const char *url = rtosc_argument(msg, 1).s; | const char *url = rtosc_argument(msg, 1).s; | ||||
if(!strcmp(type, "OSC_URL")) | if(!strcmp(type, "OSC_URL")) | ||||
impl.curr_url = url; | |||||
impl.currentUrl(url); | |||||
rEnd}, | rEnd}, | ||||
{"free:sb", 0, 0, | {"free:sb", 0, 0, | ||||
rBegin; | rBegin; | ||||
@@ -1349,8 +1470,9 @@ void MiddleWareImpl::broadcastToRemote(const char *rtmsg) | |||||
sendToRemote(rtmsg, "GUI"); | sendToRemote(rtmsg, "GUI"); | ||||
//Send to remote UI if there's one listening | //Send to remote UI if there's one listening | ||||
if(curr_url != "GUI") | |||||
sendToRemote(rtmsg, curr_url); | |||||
for(auto rem:known_remotes) | |||||
if(rem != "GUI") | |||||
sendToRemote(rtmsg, rem); | |||||
broadcast = false; | broadcast = false; | ||||
} | } | ||||
@@ -1369,6 +1491,8 @@ void MiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest) | |||||
lo_address addr = lo_address_new_from_url(dest.c_str()); | lo_address addr = lo_address_new_from_url(dest.c_str()); | ||||
if(addr) | if(addr) | ||||
lo_send_message(addr, rtmsg, msg); | lo_send_message(addr, rtmsg, msg); | ||||
lo_address_free(addr); | |||||
lo_message_free(msg); | |||||
} | } | ||||
} | } | ||||
@@ -1480,7 +1604,7 @@ void MiddleWareImpl::kitEnable(int part, int kit, int type) | |||||
void MiddleWareImpl::handleMsg(const char *msg) | void MiddleWareImpl::handleMsg(const char *msg) | ||||
{ | { | ||||
//Check for known bugs | //Check for known bugs | ||||
assert(msg && *msg && rindex(msg, '/')[1]); | |||||
assert(msg && *msg && strrchr(msg, '/')[1]); | |||||
assert(strstr(msg,"free") == NULL || strstr(rtosc_argument_string(msg), "b") == NULL); | assert(strstr(msg,"free") == NULL || strstr(rtosc_argument_string(msg), "b") == NULL); | ||||
assert(strcmp(msg, "/part0/Psysefxvol")); | assert(strcmp(msg, "/part0/Psysefxvol")); | ||||
assert(strcmp(msg, "/Penabled")); | assert(strcmp(msg, "/Penabled")); | ||||
@@ -1495,7 +1619,7 @@ void MiddleWareImpl::handleMsg(const char *msg) | |||||
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); | fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); | ||||
} | } | ||||
const char *last_path = rindex(msg, '/'); | |||||
const char *last_path = strrchr(msg, '/'); | |||||
if(!last_path) { | if(!last_path) { | ||||
printf("Bad message in handleMsg() <%s>\n", msg); | printf("Bad message in handleMsg() <%s>\n", msg); | ||||
assert(false); | assert(false); | ||||
@@ -25,6 +25,7 @@ | |||||
#include "../Synth/ADnote.h" | #include "../Synth/ADnote.h" | ||||
#include "../Synth/SUBnote.h" | #include "../Synth/SUBnote.h" | ||||
#include "../Synth/PADnote.h" | #include "../Synth/PADnote.h" | ||||
#include "../Containers/ScratchString.h" | |||||
#include "../DSP/FFTwrapper.h" | #include "../DSP/FFTwrapper.h" | ||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
#include <cstdlib> | #include <cstdlib> | ||||
@@ -59,7 +60,8 @@ static const Ports partPorts = { | |||||
rParamZyn(Pminkey, rShort("min"), "Min Used Key"), | rParamZyn(Pminkey, rShort("min"), "Min Used Key"), | ||||
rParamZyn(Pmaxkey, rShort("max"), "Max Used Key"), | rParamZyn(Pmaxkey, rShort("max"), "Max Used Key"), | ||||
rParamZyn(Pkeyshift, rShort("shift"), "Part keyshift"), | rParamZyn(Pkeyshift, rShort("shift"), "Part keyshift"), | ||||
rParamZyn(Prcvchn, "Active MIDI channel"), | |||||
rParamZyn(Prcvchn, rOptions(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16), | |||||
"Active MIDI channel"), | |||||
rParamZyn(Pvelsns, "Velocity sensing"), | rParamZyn(Pvelsns, "Velocity sensing"), | ||||
rParamZyn(Pveloffs, "Velocity offset"), | rParamZyn(Pveloffs, "Velocity offset"), | ||||
rToggle(Pnoteon, "If the channel accepts note on events"), | rToggle(Pnoteon, "If the channel accepts note on events"), | ||||
@@ -163,7 +165,9 @@ static const Ports kitPorts = { | |||||
rToggle(Padenabled, "ADsynth enable"), | rToggle(Padenabled, "ADsynth enable"), | ||||
rToggle(Psubenabled, "SUBsynth enable"), | rToggle(Psubenabled, "SUBsynth enable"), | ||||
rToggle(Ppadenabled, "PADsynth enable"), | rToggle(Ppadenabled, "PADsynth enable"), | ||||
rParamZyn(Psendtoparteffect, "Effect Levels"), | |||||
rParamZyn(Psendtoparteffect, | |||||
rOptions(FX1, FX2, FX3, Off), | |||||
"Effect Levels"), | |||||
rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"), | rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"), | ||||
{"captureMin:", rDoc("Capture minimum valid note"), NULL, | {"captureMin:", rDoc("Capture minimum valid note"), NULL, | ||||
[](const char *, RtData &r) | [](const char *, RtData &r) | ||||
@@ -195,7 +199,7 @@ const Ports &Part::ports = partPorts; | |||||
Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_, | Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_, | ||||
const int &gzip_compression, const int &interpolation, | const int &gzip_compression, const int &interpolation, | ||||
Microtonal *microtonal_, FFTwrapper *fft_) | |||||
Microtonal *microtonal_, FFTwrapper *fft_, WatchManager *wm_, const char *prefix_) | |||||
:Pdrummode(false), | :Pdrummode(false), | ||||
Ppolymode(true), | Ppolymode(true), | ||||
Plegatomode(false), | Plegatomode(false), | ||||
@@ -204,12 +208,18 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_, | |||||
ctl(synth_, &time_), | ctl(synth_, &time_), | ||||
microtonal(microtonal_), | microtonal(microtonal_), | ||||
fft(fft_), | fft(fft_), | ||||
wm(wm_), | |||||
memory(alloc), | memory(alloc), | ||||
synth(synth_), | synth(synth_), | ||||
time(time_), | time(time_), | ||||
gzip_compression(gzip_compression), | gzip_compression(gzip_compression), | ||||
interpolation(interpolation) | interpolation(interpolation) | ||||
{ | { | ||||
if(prefix_) | |||||
strncpy(prefix, prefix_, sizeof(prefix)); | |||||
else | |||||
memset(prefix, 0, sizeof(prefix)); | |||||
monomemClear(); | monomemClear(); | ||||
for(int n = 0; n < NUM_KIT_ITEMS; ++n) { | for(int n = 0; n < NUM_KIT_ITEMS; ++n) { | ||||
@@ -482,6 +492,7 @@ bool Part::NoteOn(unsigned char note, | |||||
//Create New Notes | //Create New Notes | ||||
for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) { | for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) { | ||||
ScratchString pre = prefix; | |||||
auto &item = kit[i]; | auto &item = kit[i]; | ||||
if(Pkitmode != 0 && !item.validNote(note)) | if(Pkitmode != 0 && !item.validNote(note)) | ||||
continue; | continue; | ||||
@@ -493,13 +504,15 @@ bool Part::NoteOn(unsigned char note, | |||||
try { | try { | ||||
if(item.Padenabled) | if(item.Padenabled) | ||||
notePool.insertNote(note, sendto, | notePool.insertNote(note, sendto, | ||||
{memory.alloc<ADnote>(kit[i].adpars, pars), 0, i}); | |||||
{memory.alloc<ADnote>(kit[i].adpars, pars, | |||||
wm, (pre+"kit"+i+"/adpars/").c_str), 0, i}); | |||||
if(item.Psubenabled) | if(item.Psubenabled) | ||||
notePool.insertNote(note, sendto, | notePool.insertNote(note, sendto, | ||||
{memory.alloc<SUBnote>(kit[i].subpars, pars), 1, i}); | {memory.alloc<SUBnote>(kit[i].subpars, pars), 1, i}); | ||||
if(item.Ppadenabled) | if(item.Ppadenabled) | ||||
notePool.insertNote(note, sendto, | notePool.insertNote(note, sendto, | ||||
{memory.alloc<PADnote>(kit[i].padpars, pars, interpolation), 2, i}); | |||||
{memory.alloc<PADnote>(kit[i].padpars, pars, interpolation, wm, | |||||
(pre+"kit"+i+"/padpars/").c_str), 2, i}); | |||||
} catch (std::bad_alloc & ba) { | } catch (std::bad_alloc & ba) { | ||||
std::cerr << "dropped new note: " << ba.what() << std::endl; | std::cerr << "dropped new note: " << ba.what() << std::endl; | ||||
} | } | ||||
@@ -31,7 +31,7 @@ class Part | |||||
* @param fft_ Pointer to the FFTwrapper*/ | * @param fft_ Pointer to the FFTwrapper*/ | ||||
Part(Allocator &alloc, const SYNTH_T &synth, const AbsTime &time, | Part(Allocator &alloc, const SYNTH_T &synth, const AbsTime &time, | ||||
const int& gzip_compression, const int& interpolation, | const int& gzip_compression, const int& interpolation, | ||||
Microtonal *microtonal_, FFTwrapper *fft_); | |||||
Microtonal *microtonal_, FFTwrapper *fft_, WatchManager *wm=0, const char *prefix=0); | |||||
/**Destructor*/ | /**Destructor*/ | ||||
~Part(); | ~Part(); | ||||
@@ -192,6 +192,8 @@ class Part | |||||
float oldfreq; //this is used for portamento | float oldfreq; //this is used for portamento | ||||
Microtonal *microtonal; | Microtonal *microtonal; | ||||
FFTwrapper *fft; | FFTwrapper *fft; | ||||
WatchManager *wm; | |||||
char prefix[64]; | |||||
Allocator &memory; | Allocator &memory; | ||||
const SYNTH_T &synth; | const SYNTH_T &synth; | ||||
const AbsTime &time; | const AbsTime &time; | ||||
@@ -12,6 +12,7 @@ using namespace rtosc; | |||||
* - 'tooltip' : string [OPTIONAL] | * - 'tooltip' : string [OPTIONAL] | ||||
* - 'type' : type | * - 'type' : type | ||||
* - 'domain' : range [OPTIONAL] | * - 'domain' : range [OPTIONAL] | ||||
* - 'options' : [option...] [OPTIONAL] | |||||
* type : {'int', 'float', 'boolean'} | * type : {'int', 'float', 'boolean'} | ||||
* action : | * action : | ||||
* - 'path' : path-id | * - 'path' : path-id | ||||
@@ -19,6 +20,9 @@ using namespace rtosc; | |||||
* arg : | * arg : | ||||
* - 'type' : type | * - 'type' : type | ||||
* - 'domain' : range [OPTIONAL] | * - 'domain' : range [OPTIONAL] | ||||
* option : | |||||
* - 'id' : id-number | |||||
* - 'value' : string-rep | |||||
*/ | */ | ||||
void walk_ports2(const rtosc::Ports *base, | void walk_ports2(const rtosc::Ports *base, | ||||
@@ -98,15 +102,24 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta) | |||||
* - 'domain' : range [OPTIONAL] | * - 'domain' : range [OPTIONAL] | ||||
*/ | */ | ||||
static bool first = true; | static bool first = true; | ||||
void dump_param_cb(const rtosc::Port *p, const char *name, void *v) | |||||
void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v) | |||||
{ | { | ||||
typedef std::vector<std::pair<int,string>> opts; | |||||
std::ostream &o = *(std::ostream*)v; | std::ostream &o = *(std::ostream*)v; | ||||
auto meta = p->meta(); | auto meta = p->meta(); | ||||
const char *args = strchr(p->name, ':'); | const char *args = strchr(p->name, ':'); | ||||
auto mparameter = meta.find("parameter"); | auto mparameter = meta.find("parameter"); | ||||
auto mdoc = meta.find("documentation"); | auto mdoc = meta.find("documentation"); | ||||
auto msname = meta.find("shortname"); | auto msname = meta.find("shortname"); | ||||
opts options; | |||||
string doc; | string doc; | ||||
string name = p->name;; | |||||
{ | |||||
size_t pos = 0; | |||||
if((pos = name.find_first_of(":")) != string::npos) | |||||
name = name.substr(0, pos); | |||||
} | |||||
//Escape Characters | //Escape Characters | ||||
if(mdoc != p->meta().end()) { | if(mdoc != p->meta().end()) { | ||||
@@ -139,7 +152,7 @@ void dump_param_cb(const rtosc::Port *p, const char *name, void *v) | |||||
} | } | ||||
if(!type) { | if(!type) { | ||||
fprintf(stderr, "rtosc port dumper: Cannot handle '%s'\n", name); | |||||
fprintf(stderr, "rtosc port dumper: Cannot handle '%s'\n", full_name); | |||||
fprintf(stderr, " args = <%s>\n", args); | fprintf(stderr, " args = <%s>\n", args); | ||||
return; | return; | ||||
} | } | ||||
@@ -154,23 +167,43 @@ void dump_param_cb(const rtosc::Port *p, const char *name, void *v) | |||||
const char *min = meta["min"]; | const char *min = meta["min"]; | ||||
const char *max = meta["max"]; | const char *max = meta["max"]; | ||||
for(auto m:meta) { | |||||
if(strlen(m.title) >= 5 && !bcmp(m.title, "map ", 4)) { | |||||
int id = atoi(m.title+4); | |||||
std::string val = m.value; | |||||
options.push_back(std::make_pair(id, val)); | |||||
} | |||||
} | |||||
if(!first) | if(!first) | ||||
o << ",\n"; | o << ",\n"; | ||||
else | else | ||||
first = false; | first = false; | ||||
o << " {\n"; | o << " {\n"; | ||||
o << " \"path\" : \"" << name << "\",\n"; | |||||
o << " \"path\" : \"" << full_name << "\",\n"; | |||||
if(msname != meta.end()) | if(msname != meta.end()) | ||||
o << " \"shortname\": \"" << msname.value << "\",\n"; | o << " \"shortname\": \"" << msname.value << "\",\n"; | ||||
o << " \"name\" : \"" << p->name << "\",\n"; | |||||
o << " \"name\" : \"" << name << "\",\n"; | |||||
o << " \"tooltip\" : \"" << doc << "\",\n"; | o << " \"tooltip\" : \"" << doc << "\",\n"; | ||||
o << " \"type\" : \"" << type << "\""; | o << " \"type\" : \"" << type << "\""; | ||||
if(min && max) | if(min && max) | ||||
o << ",\n \"range\" : [" << min << "," << max << "]\n"; | |||||
else | |||||
o << "\n"; | |||||
o << " }"; | |||||
o << ",\n \"range\" : [" << min << "," << max << "]"; | |||||
if(!options.empty()) { | |||||
o << ",\n \"options\" : [\n"; | |||||
int N = options.size(); | |||||
for(int i=0; i<N; ++i) { | |||||
o << " {\n"; | |||||
o << " \"id\" : " << options[i].first << ",\n"; | |||||
o << " \"value\" : \"" << options[i].second << "\"\n"; | |||||
o << " }"; | |||||
if(i != N-1) | |||||
o << ","; | |||||
o << "\n"; | |||||
} | |||||
o << " ]"; | |||||
} | |||||
o << "\n }"; | |||||
} | } | ||||
void dump_json(std::ostream &o, const rtosc::Ports &p) | void dump_json(std::ostream &o, const rtosc::Ports &p) | ||||
@@ -87,10 +87,6 @@ const char *mxmlElementGetAttr(const mxml_node_t *node, const char *name) | |||||
XMLwrapper::XMLwrapper() | XMLwrapper::XMLwrapper() | ||||
{ | { | ||||
version.Major = 2; | |||||
version.Minor = 5; | |||||
version.Revision = 3; | |||||
minimal = true; | minimal = true; | ||||
node = tree = mxmlNewElement(MXML_NO_PARENT, | node = tree = mxmlNewElement(MXML_NO_PARENT, | ||||
@@ -106,11 +102,11 @@ XMLwrapper::XMLwrapper() | |||||
node = root = addparams("ZynAddSubFX-data", 4, | node = root = addparams("ZynAddSubFX-data", 4, | ||||
"version-major", stringFrom<int>( | "version-major", stringFrom<int>( | ||||
version.Major).c_str(), | |||||
version.major()).c_str(), | |||||
"version-minor", stringFrom<int>( | "version-minor", stringFrom<int>( | ||||
version.Minor).c_str(), | |||||
version.minor()).c_str(), | |||||
"version-revision", | "version-revision", | ||||
stringFrom<int>(version.Revision).c_str(), | |||||
stringFrom<int>(version.revision()).c_str(), | |||||
"ZynAddSubFX-author", "Nasca Octavian Paul"); | "ZynAddSubFX-author", "Nasca Octavian Paul"); | ||||
//make the empty branch that will contain the information parameters | //make the empty branch that will contain the information parameters | ||||
@@ -327,14 +323,13 @@ int XMLwrapper::loadXMLfile(const string &filename) | |||||
return -3; //the XML doesnt embbed zynaddsubfx data | return -3; //the XML doesnt embbed zynaddsubfx data | ||||
//fetch version information | //fetch version information | ||||
version.Major = stringTo<int>(mxmlElementGetAttr(root, "version-major")); | |||||
version.Minor = stringTo<int>(mxmlElementGetAttr(root, "version-minor")); | |||||
version.Revision = | |||||
stringTo<int>(mxmlElementGetAttr(root, "version-revision")); | |||||
fileversion.set_major(stringTo<int>(mxmlElementGetAttr(root, "version-major"))); | |||||
fileversion.set_minor(stringTo<int>(mxmlElementGetAttr(root, "version-minor"))); | |||||
fileversion.set_revision( | |||||
stringTo<int>(mxmlElementGetAttr(root, "version-revision"))); | |||||
if(verbose) | if(verbose) | ||||
cout << "loadXMLfile() version: " << version.Major << '.' | |||||
<< version.Minor << '.' << version.Revision << endl; | |||||
cout << "loadXMLfile() version: " << fileversion << endl; | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -16,6 +16,7 @@ | |||||
#include <mxml.h> | #include <mxml.h> | ||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
#include "../version.h" | |||||
#ifndef XML_WRAPPER_H | #ifndef XML_WRAPPER_H | ||||
#define XML_WRAPPER_H | #define XML_WRAPPER_H | ||||
@@ -272,12 +273,7 @@ class XMLwrapper | |||||
mxml_node_t *addparams(const char *name, unsigned int params, | mxml_node_t *addparams(const char *name, unsigned int params, | ||||
...) const; | ...) const; | ||||
/**@todo keep these numbers up to date*/ | |||||
struct { | |||||
int Major; /**<major version number.*/ | |||||
int Minor; /**<minor version number.*/ | |||||
int Revision; /**<version revision number.*/ | |||||
} version; | |||||
version_type fileversion; | |||||
}; | }; | ||||
#endif | #endif |
@@ -11,6 +11,7 @@ | |||||
of the License, or (at your option) any later version. | of the License, or (at your option) any later version. | ||||
*/ | */ | ||||
#include <stdlib.h> | |||||
#include <iostream> | #include <iostream> | ||||
#include <cmath> | #include <cmath> | ||||
@@ -20,6 +21,7 @@ using namespace std; | |||||
#include "../Misc/Config.h" | #include "../Misc/Config.h" | ||||
#include "InMgr.h" | #include "InMgr.h" | ||||
#include "AlsaEngine.h" | #include "AlsaEngine.h" | ||||
#include "Compressor.h" | |||||
#include "Nio.h" | #include "Nio.h" | ||||
AlsaEngine::AlsaEngine(const SYNTH_T &synth) | AlsaEngine::AlsaEngine(const SYNTH_T &synth) | ||||
@@ -28,6 +30,7 @@ AlsaEngine::AlsaEngine(const SYNTH_T &synth) | |||||
audio.buffer = new short[synth.buffersize * 2]; | audio.buffer = new short[synth.buffersize * 2]; | ||||
name = "ALSA"; | name = "ALSA"; | ||||
audio.handle = NULL; | audio.handle = NULL; | ||||
audio.peaks[0] = 0; | |||||
midi.handle = NULL; | midi.handle = NULL; | ||||
midi.alsaId = -1; | midi.alsaId = -1; | ||||
@@ -251,9 +254,13 @@ short *AlsaEngine::interleave(const Stereo<float *> &smps) | |||||
int idx = 0; //possible off by one error here | int idx = 0; //possible off by one error here | ||||
double scaled; | double scaled; | ||||
for(int frame = 0; frame < bufferSize; ++frame) { // with a nod to libsamplerate ... | for(int frame = 0; frame < bufferSize; ++frame) { // with a nod to libsamplerate ... | ||||
scaled = smps.l[frame] * (8.0f * 0x10000000); | |||||
float l = smps.l[frame]; | |||||
float r = smps.r[frame]; | |||||
stereoCompressor(synth.samplerate, audio.peaks[0], l, r); | |||||
scaled = l * (8.0f * 0x10000000); | |||||
shortInterleaved[idx++] = (short int)(lrint(scaled) >> 16); | shortInterleaved[idx++] = (short int)(lrint(scaled) >> 16); | ||||
scaled = smps.r[frame] * (8.0f * 0x10000000); | |||||
scaled = r * (8.0f * 0x10000000); | |||||
shortInterleaved[idx++] = (short int)(lrint(scaled) >> 16); | shortInterleaved[idx++] = (short int)(lrint(scaled) >> 16); | ||||
} | } | ||||
return shortInterleaved; | return shortInterleaved; | ||||
@@ -267,7 +274,12 @@ bool AlsaEngine::openAudio() | |||||
int rc = 0; | int rc = 0; | ||||
/* Open PCM device for playback. */ | /* Open PCM device for playback. */ | ||||
audio.handle = NULL; | audio.handle = NULL; | ||||
rc = snd_pcm_open(&audio.handle, "hw:0", | |||||
const char *device = getenv("ALSA_DEVICE"); | |||||
if(device == 0) | |||||
device = "hw:0"; | |||||
rc = snd_pcm_open(&audio.handle, device, | |||||
SND_PCM_STREAM_PLAYBACK, 0); | SND_PCM_STREAM_PLAYBACK, 0); | ||||
if(rc < 0) { | if(rc < 0) { | ||||
fprintf(stderr, | fprintf(stderr, | ||||
@@ -67,6 +67,7 @@ class AlsaEngine:public AudioOut, MidiIn | |||||
unsigned int periods; | unsigned int periods; | ||||
short *buffer; | short *buffer; | ||||
pthread_t pThread; | pthread_t pThread; | ||||
float peaks[1]; | |||||
} audio; | } audio; | ||||
void *processAudio(); | void *processAudio(); | ||||
@@ -0,0 +1,59 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Compressor.h - simple audio compressor macros | |||||
Copyright (C) 2016 Hans Petter Selasky | |||||
This program is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU General Public License | |||||
as published by the Free Software Foundation; either version 2 | |||||
of the License, or (at your option) any later version. | |||||
*/ | |||||
#ifndef _COMPRESSOR_H_ | |||||
#define _COMPRESSOR_H_ | |||||
#define floatIsValid(x) ({ \ | |||||
float __r = (x) * 0.0; \ | |||||
__r == 0.0 || __r == -0.0; \ | |||||
}) | |||||
#define stereoCompressor(div,pv,l,r) do { \ | |||||
/* \ | |||||
* Don't max the output range to avoid \ | |||||
* overflowing sample rate conversion and \ | |||||
* equalizer filters in the DSP's output \ | |||||
* path. Keep one 10th, 1dB, reserved. \ | |||||
*/ \ | |||||
const float __limit = 1.0 - (1.0 / 10.0); \ | |||||
float __peak; \ | |||||
\ | |||||
/* sanity checks */ \ | |||||
__peak = (pv); \ | |||||
if (!floatIsValid(__peak)) \ | |||||
__peak = 0.0; \ | |||||
if (!floatIsValid(l)) \ | |||||
(l) = 0.0; \ | |||||
if (!floatIsValid(r)) \ | |||||
(r) = 0.0; \ | |||||
/* compute maximum */ \ | |||||
if ((l) < -__peak) \ | |||||
__peak = -(l); \ | |||||
else if ((l) > __peak) \ | |||||
__peak = (l); \ | |||||
if ((r) < -__peak) \ | |||||
__peak = -(r); \ | |||||
else if ((r) > __peak) \ | |||||
__peak = (r); \ | |||||
/* compressor */ \ | |||||
if (__peak > __limit) { \ | |||||
(l) /= __peak; \ | |||||
(r) /= __peak; \ | |||||
(l) *= __limit; \ | |||||
(r) *= __limit; \ | |||||
__peak -= __peak / (div); \ | |||||
} \ | |||||
(pv) = __peak; \ | |||||
} while (0) | |||||
#endif /* _COMPRESSOR_H_ */ |
@@ -131,6 +131,10 @@ int JackMultiEngine::processAudio(jack_nframes_t nframes) | |||||
float *buffers[NUM_MIDI_PARTS * 2 + 2]; | float *buffers[NUM_MIDI_PARTS * 2 + 2]; | ||||
for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) { | for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) { | ||||
//Abort if ports are only partially initialized | |||||
if(!impl->ports[i]) | |||||
return false; | |||||
buffers[i] = | buffers[i] = | ||||
(float *)jack_port_get_buffer(impl->ports[i], nframes); | (float *)jack_port_get_buffer(impl->ports[i], nframes); | ||||
assert(buffers[i]); | assert(buffers[i]); | ||||
@@ -12,6 +12,8 @@ | |||||
*/ | */ | ||||
#include "OssEngine.h" | #include "OssEngine.h" | ||||
#include "Compressor.h" | |||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
#include "../Misc/Config.h" | #include "../Misc/Config.h" | ||||
#include "../globals.h" | #include "../globals.h" | ||||
@@ -186,6 +188,8 @@ OssEngine::OssEngine(const SYNTH_T &synth, | |||||
audio.smps.ps32 = new int[synth.buffersize * 2]; | audio.smps.ps32 = new int[synth.buffersize * 2]; | ||||
memset(audio.smps.ps32, 0, sizeof(int) * synth.buffersize * 2); | memset(audio.smps.ps32, 0, sizeof(int) * synth.buffersize * 2); | ||||
memset(&midi.state, 0, sizeof(midi.state)); | memset(&midi.state, 0, sizeof(midi.state)); | ||||
audio.peaks[0] = 0; | |||||
} | } | ||||
OssEngine::~OssEngine() | OssEngine::~OssEngine() | ||||
@@ -401,21 +405,10 @@ void *OssEngine::audioThreadCb() | |||||
while(getAudioEn()) { | while(getAudioEn()) { | ||||
const Stereo<float *> smps = getNext(); | const Stereo<float *> smps = getNext(); | ||||
float l, r; | |||||
for(int i = 0; i < synth.buffersize; ++i) { | for(int i = 0; i < synth.buffersize; ++i) { | ||||
l = smps.l[i]; | |||||
r = smps.r[i]; | |||||
if(l < -1.0f) | |||||
l = -1.0f; | |||||
else | |||||
if(l > 1.0f) | |||||
l = 1.0f; | |||||
if(r < -1.0f) | |||||
r = -1.0f; | |||||
else | |||||
if(r > 1.0f) | |||||
r = 1.0f; | |||||
float l = smps.l[i]; | |||||
float r = smps.r[i]; | |||||
stereoCompressor(synth.samplerate, audio.peaks[0], l, r); | |||||
if (audio.is32bit) { | if (audio.is32bit) { | ||||
audio.smps.ps32[i * 2] = (int) (l * 2147483647.0f); | audio.smps.ps32[i * 2] = (int) (l * 2147483647.0f); | ||||
@@ -71,6 +71,10 @@ class OssEngine:public AudioOut, MidiIn | |||||
short int *ps16; | short int *ps16; | ||||
int *ps32; | int *ps32; | ||||
} smps; | } smps; | ||||
/* peak values used for compressor */ | |||||
float peaks[1]; | |||||
bool en; | bool en; | ||||
bool is32bit; | bool is32bit; | ||||
} audio; | } audio; | ||||
@@ -29,6 +29,7 @@ | |||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
#include "OssMultiEngine.h" | #include "OssMultiEngine.h" | ||||
#include "Compressor.h" | |||||
extern MiddleWare *middleware; | extern MiddleWare *middleware; | ||||
@@ -53,12 +54,18 @@ OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth, | |||||
/* allocate buffer */ | /* allocate buffer */ | ||||
smps.ps32 = new int[maxbuffersize / sizeof(int)]; | smps.ps32 = new int[maxbuffersize / sizeof(int)]; | ||||
memset(smps.ps32, 0, maxbuffersize); | memset(smps.ps32, 0, maxbuffersize); | ||||
/* setup compressor */ | |||||
unsigned peaksize = NUM_MIDI_PARTS * sizeof(float); | |||||
peaks = new float[peaksize / sizeof(float)]; | |||||
memset(peaks, 0, peaksize); | |||||
} | } | ||||
OssMultiEngine :: ~OssMultiEngine() | OssMultiEngine :: ~OssMultiEngine() | ||||
{ | { | ||||
Stop(); | Stop(); | ||||
delete [] smps.ps32; | delete [] smps.ps32; | ||||
delete [] peaks; | |||||
} | } | ||||
bool | bool | ||||
@@ -213,8 +220,6 @@ OssMultiEngine :: audioThreadCb() | |||||
while(getAudioEn()) { | while(getAudioEn()) { | ||||
int error; | int error; | ||||
float l; | |||||
float r; | |||||
int x; | int x; | ||||
int y; | int y; | ||||
@@ -227,32 +232,18 @@ OssMultiEngine :: audioThreadCb() | |||||
if (is32bit) { | if (is32bit) { | ||||
for (y = 0; y != synth.buffersize; y++) { | for (y = 0; y != synth.buffersize; y++) { | ||||
l = part->partoutl[y]; | |||||
if (l < -1.0f) | |||||
l = -1.0f; | |||||
else if (l > 1.0f) | |||||
l = 1.0f; | |||||
float l = part->partoutl[y]; | |||||
float r = part->partoutr[y]; | |||||
stereoCompressor(synth.samplerate, peaks[x/2], l, r); | |||||
smps.ps32[y * channels + x] = (int)(l * 2147483647.0f); | smps.ps32[y * channels + x] = (int)(l * 2147483647.0f); | ||||
r = part->partoutr[y]; | |||||
if (r < -1.0f) | |||||
r = -1.0f; | |||||
else if (r > 1.0f) | |||||
r = 1.0f; | |||||
smps.ps32[y * channels + x + 1] = (int)(r * 2147483647.0f); | smps.ps32[y * channels + x + 1] = (int)(r * 2147483647.0f); | ||||
} | } | ||||
} else { | } else { | ||||
for (y = 0; y != synth.buffersize; y++) { | for (y = 0; y != synth.buffersize; y++) { | ||||
l = part->partoutl[y]; | |||||
if (l < -1.0f) | |||||
l = -1.0f; | |||||
else if (l > 1.0f) | |||||
l = 1.0f; | |||||
float l = part->partoutl[y]; | |||||
float r = part->partoutr[y]; | |||||
stereoCompressor(synth.samplerate, peaks[x/2], l, r); | |||||
smps.ps16[y * channels + x] = (short int)(l * 32767.0f); | smps.ps16[y * channels + x] = (short int)(l * 32767.0f); | ||||
r = part->partoutr[y]; | |||||
if (r < -1.0f) | |||||
r = -1.0f; | |||||
else if (r > 1.0f) | |||||
r = 1.0f; | |||||
smps.ps16[y * channels + x + 1] = (short int)(r * 32767.0f); | smps.ps16[y * channels + x + 1] = (short int)(r * 32767.0f); | ||||
} | } | ||||
} | } | ||||
@@ -52,6 +52,9 @@ class OssMultiEngine : public AudioOut | |||||
int *ps32; | int *ps32; | ||||
} smps; | } smps; | ||||
/* peak values used for compressor */ | |||||
float *peaks; | |||||
bool en; | bool en; | ||||
bool is32bit; | bool is32bit; | ||||
@@ -18,6 +18,7 @@ | |||||
#include "ADnoteParameters.h" | #include "ADnoteParameters.h" | ||||
#include "EnvelopeParams.h" | #include "EnvelopeParams.h" | ||||
#include "LFOParams.h" | #include "LFOParams.h" | ||||
#include "../Misc/Time.h" | |||||
#include "../Misc/XMLwrapper.h" | #include "../Misc/XMLwrapper.h" | ||||
#include "../DSP/FFTwrapper.h" | #include "../DSP/FFTwrapper.h" | ||||
#include "../Synth/OscilGen.h" | #include "../Synth/OscilGen.h" | ||||
@@ -66,63 +67,68 @@ static const Ports voicePorts = { | |||||
rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"), | rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"), | ||||
rRecurp(VoiceFilter, "Optional Voice Filter"), | rRecurp(VoiceFilter, "Optional Voice Filter"), | ||||
rToggle(Enabled, "Voice Enable"), | |||||
rParamZyn(Unison_size, "Number of subvoices"), | |||||
rParamZyn(Unison_phase_randomness, "Phase Randomness"), | |||||
rParamZyn(Unison_frequency_spread, "Subvoice detune"), | |||||
rParamZyn(Unison_stereo_spread, "Subvoice L/R Separation"), | |||||
rParamZyn(Unison_vibratto, "Subvoice vibratto"), | |||||
rParamZyn(Unison_vibratto_speed, "Subvoice vibratto speed"), | |||||
rOption(Unison_invert_phase, rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"), | |||||
rOption(Type, rOptions(Sound,White,Pink), "Type of Sound"), | |||||
rParamZyn(PDelay, "Voice Startup Delay"), | |||||
rToggle(Presonance, "Resonance Enable"), | |||||
rParamI(Pextoscil, rMap(min, -1), rMap(max, 16), "External Oscilator Selection"), | |||||
rParamI(PextFMoscil, rMap(min, -1), rMap(max, 16), "External FM Oscilator Selection"), | |||||
rParamZyn(Poscilphase, "Oscillator Phase"), | |||||
rParamZyn(PFMoscilphase, "FM Oscillator Phase"), | |||||
rToggle(Pfilterbypass, "Filter Bypass"), | |||||
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"), | |||||
rOption(Unison_invert_phase, rShort("inv."), | |||||
rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"), | |||||
rOption(Type, rShort("type"), rOptions(Sound,White,Pink), "Type of Sound"), | |||||
rParamZyn(PDelay, rShort("delay"), "Voice Startup Delay"), | |||||
rToggle(Presonance, rShort("enable"), "Resonance Enable"), | |||||
rParamI(Pextoscil, rShort("ext."), | |||||
rMap(min, -1), rMap(max, 16), "External Oscilator Selection"), | |||||
rParamI(PextFMoscil, rShort("ext."), | |||||
rMap(min, -1), rMap(max, 16), "External FM Oscilator Selection"), | |||||
rParamZyn(Poscilphase, rShort("phase"), "Oscillator Phase"), | |||||
rParamZyn(PFMoscilphase, rShort("phase"), "FM Oscillator Phase"), | |||||
rToggle(Pfilterbypass, rShort("bypass"), "Filter Bypass"), | |||||
//Freq Stuff | //Freq Stuff | ||||
rToggle(Pfixedfreq, "If frequency is fixed"), | |||||
rParamZyn(PfixedfreqET, "Equal Tempermant Parameter"), | |||||
rParamZyn(PBendAdjust, "Pitch bend adjustment"), | |||||
rParamZyn(POffsetHz, "Voice constant offset"), | |||||
rParamI(PDetune, "Fine Detune"), | |||||
rParamI(PCoarseDetune, "Coarse Detune"), | |||||
rParamZyn(PDetuneType, "Magnitude of Detune"), | |||||
rToggle(PFreqEnvelopeEnabled, "Frequency Envelope Enable"), | |||||
rToggle(PFreqLfoEnabled, "Frequency LFO Enable"), | |||||
rToggle(Pfixedfreq, rShort("fixed"), "If frequency is fixed"), | |||||
rParamZyn(PfixedfreqET, rShort("e.t."), "Equal Tempermant Parameter"), | |||||
rParamZyn(PBendAdjust, rShort("bend"), "Pitch bend adjustment"), | |||||
rParamZyn(POffsetHz, rShort("offset"), "Voice constant offset"), | |||||
rParamI(PDetune, rShort("fine"), "Fine Detune"), | |||||
rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"), | |||||
rParamZyn(PDetuneType, rShort("type"), "Magnitude of Detune"), | |||||
rToggle(PFreqEnvelopeEnabled, rShort("enable"), "Frequency Envelope Enable"), | |||||
rToggle(PFreqLfoEnabled, rShort("enable"), "Frequency LFO Enable"), | |||||
//Amplitude Stuff | //Amplitude Stuff | ||||
rParamZyn(PPanning, "Panning"), | |||||
rParamZyn(PVolume, "Volume"), | |||||
rToggle(PVolumeminus, "Signal Inverter"), //do we really need this?? | |||||
rParamZyn(PAmpVelocityScaleFunction, "Velocity Sensing"), | |||||
rToggle(PAmpEnvelopeEnabled, "Amplitude Envelope Enable"), | |||||
rToggle(PAmpLfoEnabled, "Amplitude LFO Enable"), | |||||
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"), | |||||
//Filter Stuff | //Filter Stuff | ||||
rToggle(PFilterEnabled, "Filter Enable"), | |||||
rToggle(PFilterEnvelopeEnabled, "Filter Envelope Enable"), | |||||
rToggle(PFilterLfoEnabled, "Filter LFO Enable"), | |||||
rParamZyn(PFilterVelocityScale, "Filter Velocity Magnitude"), | |||||
rParamZyn(PFilterVelocityScaleFunction, "Filter Velocity Function Shape"), | |||||
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"), | |||||
//Modulator Stuff | //Modulator Stuff | ||||
rOption(PFMEnabled, rOptions(none, morph, ring modulation, phase modulation, | |||||
frequency modulation, pitch modulation), "Modulator mode"), | |||||
rParamI(PFMVoice, "Modulator Oscillator Selection"), | |||||
rParamZyn(PFMVolume, "Modulator Magnitude"), | |||||
rParamZyn(PFMVolumeDamp, "Modulator HF dampening"), | |||||
rParamZyn(PFMVelocityScaleFunction, "Modulator Velocity Function"), | |||||
rParamI(PFMDetune, "Modulator Fine Detune"), | |||||
rParamI(PFMCoarseDetune, "Modulator Coarse Detune"), | |||||
rParamZyn(PFMDetuneType, "Modulator Detune Magnitude"), | |||||
rToggle(PFMFixedFreq, "Modulator Frequency Fixed"), | |||||
rToggle(PFMFreqEnvelopeEnabled, "Modulator Frequency Envelope"), | |||||
rToggle(PFMAmpEnvelopeEnabled, "Modulator Amplitude Envelope"), | |||||
rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase, | |||||
frequency, pitch), "Modulator mode"), | |||||
rParamI(PFMVoice, rShort("voice"), "Modulator Oscillator Selection"), | |||||
rParamZyn(PFMVolume, rShort("vol."), "Modulator Magnitude"), | |||||
rParamZyn(PFMVolumeDamp, rShort("damp."), "Modulator HF dampening"), | |||||
rParamZyn(PFMVelocityScaleFunction, rShort("sense"), "Modulator Velocity Function"), | |||||
rParamI(PFMDetune, rShort("fine"), "Modulator Fine Detune"), | |||||
rParamI(PFMCoarseDetune, rShort("coarse"), "Modulator Coarse Detune"), | |||||
rParamZyn(PFMDetuneType, rShort("type"), "Modulator Detune Magnitude"), | |||||
rToggle(PFMFixedFreq, rShort("fixed"), "Modulator Frequency Fixed"), | |||||
rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), "Modulator Frequency Envelope"), | |||||
rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), "Modulator Amplitude Envelope"), | |||||
//weird stuff for PCoarseDetune | //weird stuff for PCoarseDetune | ||||
@@ -229,28 +235,31 @@ static const Ports globalPorts = { | |||||
rRecurp(AmpEnvelope, "Frequency Envelope"), | rRecurp(AmpEnvelope, "Frequency Envelope"), | ||||
rRecurp(FilterEnvelope, "Frequency Envelope"), | rRecurp(FilterEnvelope, "Frequency Envelope"), | ||||
rRecurp(GlobalFilter, "Filter"), | rRecurp(GlobalFilter, "Filter"), | ||||
rToggle(PStereo, "Mono/Stereo Enable"), | |||||
rToggle(PStereo, rShort("stereo"), "Mono/Stereo Enable"), | |||||
//Frequency | //Frequency | ||||
rParamI(PDetune, "Fine Detune"), | |||||
rParamI(PCoarseDetune, "Coarse Detune"), | |||||
rParamZyn(PDetuneType, "Detune Scaling Type"), | |||||
rParamZyn(PBandwidth, "Relative Fine Detune Gain"), | |||||
rParamI(PDetune, rShort("fine"), "Fine Detune"), | |||||
rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"), | |||||
rParamZyn(PDetuneType, rShort("type"), | |||||
rOptions(L35cents, L10cents, E100cents, E1200cents), | |||||
"Detune Scaling Type"), | |||||
rParamZyn(PBandwidth, rShort("bw."), "Relative Fine Detune Gain"), | |||||
//Amplitude | //Amplitude | ||||
rParamZyn(PPanning, "Panning of ADsynth (0 random, 1 left, 127 right)"), | |||||
rParamZyn(PVolume, "volume control"), | |||||
rParamZyn(PAmpVelocityScaleFunction, "Volume Velocity Control"), | |||||
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(Fadein_adjustment, "Adjustment for anti-pop strategy."), | ||||
rParamZyn(PPunchStrength, "Punch Strength"), | |||||
rParamZyn(PPunchTime, "UNKNOWN"), | |||||
rParamZyn(PPunchStretch, "How Punch changes with note frequency"), | |||||
rParamZyn(PPunchVelocitySensing, "Punch Velocity control"), | |||||
rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"), | |||||
rParamZyn(PPunchTime, rShort("time"), "Length of Punch"), | |||||
rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"), | |||||
rParamZyn(PPunchVelocitySensing, rShort("v.sns"), "Punch Velocity control"), | |||||
//Filter | //Filter | ||||
rParamZyn(PFilterVelocityScale, "Filter Velocity Magnitude"), | |||||
rParamZyn(PFilterVelocityScaleFunction, "Filter Velocity Function Shape"), | |||||
rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"), | |||||
rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"), | |||||
//Resonance | //Resonance | ||||
@@ -27,31 +27,31 @@ using namespace rtosc; | |||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | ||||
const rtosc::Ports Controller::ports = { | const rtosc::Ports Controller::ports = { | ||||
rParamZyn(panning.depth, "Depth of Panning MIDI Control"), | |||||
rParamZyn(filtercutoff.depth, "Depth of Filter Cutoff MIDI Control"), | |||||
rParamZyn(filterq.depth, "Depth of Filter Q MIDI Control"), | |||||
rParamZyn(bandwidth.depth, "Depth of Bandwidth MIDI Control"), | |||||
rToggle(bandwidth.exponential, "Bandwidth Exponential Mode"), | |||||
rParamZyn(modwheel.depth, "Depth of Modwheel MIDI Control"), | |||||
rToggle(modwheel.exponential, "Modwheel Exponential Mode"), | |||||
rToggle(pitchwheel.is_split, "If PitchWheel Has unified bendrange or not"), | |||||
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, "Range of MIDI Pitch Wheel"), | rParamI(pitchwheel.bendrange, "Range of MIDI Pitch Wheel"), | ||||
rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"), | rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"), | ||||
rToggle(expression.receive, "Expression MIDI Receive"), | |||||
rToggle(fmamp.receive, "FM amplitude MIDI Receive"), | |||||
rToggle(volume.receive, "Volume MIDI Receive"), | |||||
rToggle(sustain.receive, "Sustain MIDI Receive"), | |||||
rToggle(portamento.receive, "Portamento MIDI Receive"), | |||||
rToggle(expression.receive, rShort("exp.rcv"), "Expression MIDI Receive"), | |||||
rToggle(fmamp.receive, rShort("fma.rcv"), "FM amplitude MIDI Receive"), | |||||
rToggle(volume.receive, rShort("vol.rcv"), "Volume MIDI Receive"), | |||||
rToggle(sustain.receive, rShort("sus.rcv"), "Sustain MIDI Receive"), | |||||
rToggle(portamento.receive, rShort("prt.rcv"), "Portamento MIDI Receive"), | |||||
rToggle(portamento.portamento, "UNDOCUMENTED"), | rToggle(portamento.portamento, "UNDOCUMENTED"), | ||||
rParamZyn(portamento.time, "Portamento Length"), | |||||
rToggle(portamento.proportional, "If all portamentos are proportional to the distance they span"), | |||||
rParamZyn(portamento.propRate, "Portamento proportional rate"), | |||||
rParamZyn(portamento.propDepth, "Portamento proportional depth"), | |||||
rParamZyn(portamento.pitchthresh, "Threshold for portamento"), | |||||
rToggle(portamento.pitchthreshtype, "Type of threshold"), | |||||
rParamZyn(portamento.time, rShort("time"), "Portamento Length"), | |||||
rToggle(portamento.proportional, rShort("propt."), "If all portamentos are proportional to the distance they span"), | |||||
rParamZyn(portamento.propRate, rShort("rate"), "Portamento proportional rate"), | |||||
rParamZyn(portamento.propDepth, rShort("depth"), "Portamento proportional depth"), | |||||
rParamZyn(portamento.pitchthresh, rShort("thresh"), "Threshold for portamento"), | |||||
rToggle(portamento.pitchthreshtype, rShort("tr.type"), "Type of threshold"), | |||||
rParamZyn(portamento.updowntimestretch, "UNDOCUMENTED"), | rParamZyn(portamento.updowntimestretch, "UNDOCUMENTED"), | ||||
rParamZyn(resonancecenter.depth, "Resonance Center MIDI Depth"), | |||||
rParamZyn(resonancebandwidth.depth, "Resonance Bandwidth MIDI Depth"), | |||||
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"), | rToggle(NRPN.receive, "NRPN MIDI Enable"), | ||||
rAction(defaults), | rAction(defaults), | ||||
}; | }; | ||||
@@ -23,6 +23,9 @@ | |||||
#define rObject EnvelopeParams | #define rObject EnvelopeParams | ||||
using namespace rtosc; | using namespace rtosc; | ||||
#define rBegin [](const char *msg, RtData &d) { \ | |||||
EnvelopeParams *env = (rObject*) d.obj | |||||
#define rEnd } | |||||
static const rtosc::Ports localPorts = { | static const rtosc::Ports localPorts = { | ||||
rSelf(EnvelopeParams), | rSelf(EnvelopeParams), | ||||
@@ -32,60 +35,85 @@ static const rtosc::Ports localPorts = { | |||||
obj->last_update_timestamp = obj->time->time(); } | obj->last_update_timestamp = obj->time->time(); } | ||||
rToggle(Pfreemode, "Complex Envelope Definitions"), | rToggle(Pfreemode, "Complex Envelope Definitions"), | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | |||||
#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(Penvpoints, rProp(internal), "Number of points in complex definition"), | ||||
rParamZyn(Penvsustain, rProp(internal), "Location of the sustain point"), | rParamZyn(Penvsustain, rProp(internal), "Location of the sustain point"), | ||||
rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"), | rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"), | ||||
rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"), | rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"), | ||||
rParamZyn(Penvstretch, "Stretch with respect to frequency"), | |||||
rToggle(Pforcedrelease, "Force Envelope to fully evaluate"), | |||||
rToggle(Plinearenvelope, "Linear or Logarithmic Envelopes"), | |||||
rParamZyn(PA_dt, "Attack Time"), | |||||
rParamZyn(PA_val, "Attack Value"), | |||||
rParamZyn(PD_dt, "Decay Time"), | |||||
rParamZyn(PD_val, "Decay Value"), | |||||
rParamZyn(PS_val, "Sustain Value"), | |||||
rParamZyn(PR_dt, "Release Time"), | |||||
rParamZyn(PR_val, "Release Value"), | |||||
{"addPoint:i", rProp(internal) rDoc("Add point to envelope"), NULL, [](const char *msg, RtData &d) | |||||
{ | |||||
EnvelopeParams *env = (rObject*) d.obj; | |||||
const int curpoint = rtosc_argument(msg, 0).i; | |||||
//int curpoint=freeedit->lastpoint; | |||||
if (curpoint<0 || curpoint>env->Penvpoints || env->Penvpoints>=MAX_ENVELOPE_POINTS) | |||||
return; | |||||
for (int i=env->Penvpoints; i>=curpoint+1; i--) { | |||||
env->Penvdt[i]=env->Penvdt[i-1]; | |||||
env->Penvval[i]=env->Penvval[i-1]; | |||||
} | |||||
if (curpoint==0) { | |||||
env->Penvdt[1]=64; | |||||
} | |||||
env->Penvpoints++; | |||||
if (curpoint<=env->Penvsustain) env->Penvsustain++; | |||||
}}, | |||||
{"delPoint:i", rProp(internal) rDoc("Delete Envelope Point"), NULL, [](const char *msg, RtData &d) | |||||
{ | |||||
EnvelopeParams *env = (rObject*) d.obj; | |||||
const int curpoint=rtosc_argument(msg, 0).i; | |||||
if(curpoint<1 || curpoint>=env->Penvpoints-1 || env->Penvpoints<=3) | |||||
return; | |||||
for (int i=curpoint+1;i<env->Penvpoints;i++){ | |||||
env->Penvdt[i-1]=env->Penvdt[i]; | |||||
env->Penvval[i-1]=env->Penvval[i]; | |||||
}; | |||||
env->Penvpoints--; | |||||
if (curpoint<=env->Penvsustain) | |||||
env->Penvsustain--; | |||||
}}, | |||||
rParamZyn(Penvstretch, rShort("stretch"), | |||||
"Stretch with respect to frequency"), | |||||
rToggle(Pforcedrelease, rShort("frcr"), | |||||
"Force Envelope to fully evaluate"), | |||||
rToggle(Plinearenvelope, rShort("lin/log"), | |||||
"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"), | |||||
{"envdt:", rDoc("Envelope Delay Times"), NULL, | |||||
rBegin; | |||||
const int N = MAX_ENVELOPE_POINTS; | |||||
rtosc_arg_t args[N]; | |||||
char arg_types[N+1] = {0}; | |||||
for(int i=0; i<N; ++i) { | |||||
args[i].f = env->getdt(i); | |||||
arg_types[i] = 'f'; | |||||
} | |||||
d.replyArray(d.loc, arg_types, args); | |||||
rEnd}, | |||||
{"envval:", rDoc("Envelope Delay Times"), NULL, | |||||
rBegin; | |||||
const int N = MAX_ENVELOPE_POINTS; | |||||
rtosc_arg_t args[N]; | |||||
char arg_types[N+1] = {0}; | |||||
for(int i=0; i<N; ++i) { | |||||
args[i].f = env->Penvval[i]/127.0f; | |||||
arg_types[i] = 'f'; | |||||
} | |||||
d.replyArray(d.loc, arg_types, args); | |||||
rEnd}, | |||||
{"addPoint:i", rProp(internal) rDoc("Add point to envelope"), NULL, | |||||
rBegin; | |||||
const int curpoint = rtosc_argument(msg, 0).i; | |||||
//int curpoint=freeedit->lastpoint; | |||||
if (curpoint<0 || curpoint>env->Penvpoints || env->Penvpoints>=MAX_ENVELOPE_POINTS) | |||||
return; | |||||
for (int i=env->Penvpoints; i>=curpoint+1; i--) { | |||||
env->Penvdt[i]=env->Penvdt[i-1]; | |||||
env->Penvval[i]=env->Penvval[i-1]; | |||||
} | |||||
if (curpoint==0) | |||||
env->Penvdt[1]=64; | |||||
env->Penvpoints++; | |||||
if (curpoint<=env->Penvsustain) | |||||
env->Penvsustain++; | |||||
rEnd}, | |||||
{"delPoint:i", rProp(internal) rDoc("Delete Envelope Point"), NULL, | |||||
rBegin; | |||||
const int curpoint=rtosc_argument(msg, 0).i; | |||||
if(curpoint<1 || curpoint>=env->Penvpoints-1 || env->Penvpoints<=3) | |||||
return; | |||||
for (int i=curpoint+1;i<env->Penvpoints;i++){ | |||||
env->Penvdt[i-1]=env->Penvdt[i]; | |||||
env->Penvval[i-1]=env->Penvval[i]; | |||||
}; | |||||
env->Penvpoints--; | |||||
if (curpoint<=env->Penvsustain) | |||||
env->Penvsustain--; | |||||
rEnd}, | |||||
}; | }; | ||||
#undef rChangeCb | #undef rChangeCb | ||||
@@ -14,6 +14,7 @@ | |||||
#include "FilterParams.h" | #include "FilterParams.h" | ||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
#include "../Misc/Time.h" | #include "../Misc/Time.h" | ||||
#include "../DSP/AnalogFilter.h" | |||||
#include <cmath> | #include <cmath> | ||||
#include <cstdio> | #include <cstdio> | ||||
#include <cstdlib> | #include <cstdlib> | ||||
@@ -58,18 +59,29 @@ const rtosc::Ports FilterParams::ports = { | |||||
rSelf(FilterParams), | rSelf(FilterParams), | ||||
rPaste, | rPaste, | ||||
rArrayPaste, | rArrayPaste, | ||||
rParamZyn(Pcategory, "Class of filter"), | |||||
rParamZyn(Ptype, "Filter Type"), | |||||
rParamZyn(Pfreq, "Center Freq"), | |||||
rParamZyn(Pq, "Quality Factor (resonance/bandwidth)"), | |||||
rParamZyn(Pstages, "Filter Stages + 1"), | |||||
rParamZyn(Pfreqtrack, "Frequency Tracking amount"), | |||||
rParamZyn(Pgain, "Output Gain"), | |||||
rParamZyn(Pnumformants, "Number of formants to be used"), | |||||
rParamZyn(Pformantslowness, "Rate that formants change"), | |||||
rParamZyn(Pvowelclearness, "Cost for mixing vowels"), | |||||
rParamZyn(Pcenterfreq, "Center Freq (formant)"), | |||||
rParamZyn(Poctavesfreq, "Number of octaves for formant"), | |||||
rOption(Pcategory, rShort("class"), | |||||
rOptions(analog, formant, st.var.), "Class of filter"), | |||||
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)"), | |||||
rOption(Pstages, rShort("stages"), | |||||
rOptions(1, 2, 3, 4, 5), "Filter Stages"), | |||||
rParamZyn(Pfreqtrack, rShort("f.track"), | |||||
"Frequency Tracking amount"), | |||||
rParamZyn(Pgain, rShort("gain"), "Output Gain"), | |||||
rParamZyn(Pnumformants, rShort("formants"), | |||||
"Number of formants to be used"), | |||||
rParamZyn(Pformantslowness, rShort("slew"), | |||||
"Rate that formants change"), | |||||
rParamZyn(Pvowelclearness, rShort("clarity"), | |||||
"Cost for mixing vowels"), | |||||
rParamZyn(Pcenterfreq, rShort("cutoff"), | |||||
"Center Freq (formant)"), | |||||
rParamZyn(Poctavesfreq, rShort("octaves"), | |||||
"Number of octaves for formant"), | |||||
//TODO check if FF_MAX_SEQUENCE is acutally expanded or not | //TODO check if FF_MAX_SEQUENCE is acutally expanded or not | ||||
rParamZyn(Psequencesize, rMap(max, FF_MAX_SEQUENCE), "Length of vowel sequence"), | rParamZyn(Psequencesize, rMap(max, FF_MAX_SEQUENCE), "Length of vowel sequence"), | ||||
@@ -110,11 +122,79 @@ const rtosc::Ports FilterParams::ports = { | |||||
FilterParams *obj = (FilterParams *) d.obj; | FilterParams *obj = (FilterParams *) d.obj; | ||||
d.reply(d.loc, "f", obj->getoctavesfreq()); | d.reply(d.loc, "f", obj->getoctavesfreq()); | ||||
}}, | }}, | ||||
{"q_value:", | |||||
rDoc("Q value for UI Response Graphs"), | |||||
NULL, [](const char *, RtData &d) { | |||||
FilterParams *obj = (FilterParams *) d.obj; | |||||
d.reply(d.loc, "f", obj->getq()); | |||||
}}, | |||||
{"response:", | |||||
rDoc("Get a frequency response"), | |||||
NULL, [](const char *, RtData &d) { | |||||
FilterParams *obj = (FilterParams *) d.obj; | |||||
int order = 0; | |||||
float gain = dB2rap(obj->getgain()); | |||||
if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) | |||||
gain = 1.0; | |||||
auto cf = AnalogFilter::computeCoeff(obj->Ptype, | |||||
Filter::getrealfreq(obj->getfreq()), | |||||
obj->getq(), obj->Pstages, | |||||
gain, 48000, order); | |||||
if(order == 2) { | |||||
d.reply(d.loc, "fffffff", | |||||
(float)obj->Pstages, | |||||
cf.c[0], cf.c[1], cf.c[2], | |||||
0.0, cf.d[1], cf.d[2]); | |||||
} else if(order == 1) { | |||||
d.reply(d.loc, "fffff", | |||||
(float)obj->Pstages, | |||||
cf.c[0], cf.c[1], | |||||
0.0, cf.d[1]); | |||||
} | |||||
}}, | |||||
// "", NULL, [](){}},"/freq" | // "", NULL, [](){}},"/freq" | ||||
//{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/amp", | //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/amp", | ||||
// "", NULL, [](){}}, | // "", NULL, [](){}}, | ||||
//{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/q", | //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/q", | ||||
// "", NULL, [](){}}, | // "", NULL, [](){}}, | ||||
// | |||||
//struct Pvowels_t { | |||||
// struct formants_t { | |||||
// unsigned char freq, amp, q; //frequency,amplitude,Q | |||||
// } formants[FF_MAX_FORMANTS]; | |||||
//} Pvowels[FF_MAX_VOWELS]; | |||||
{"vowels:", | |||||
rDoc("Get info for formant graph"), | |||||
NULL, [](const char *, RtData &d) { | |||||
FilterParams *obj = (FilterParams *) d.obj; | |||||
rtosc_arg_t args[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS]; | |||||
char type[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS + 1] = {0}; | |||||
type[0] = 'i'; | |||||
type[1] = 'i'; | |||||
args[0].i = FF_MAX_VOWELS; | |||||
args[1].i = FF_MAX_FORMANTS; | |||||
for(int i=0; i<FF_MAX_VOWELS; ++i) { | |||||
auto &val = obj->Pvowels[i]; | |||||
for(int j=0; j<FF_MAX_FORMANTS; ++j) { | |||||
auto &f = val.formants[j]; | |||||
//each formant is 3 arguments | |||||
//each vowel is FF_MAX_FORMANTS * length of formants long | |||||
auto *a = args + i*FF_MAX_FORMANTS*3 + j*3 + 2; | |||||
auto *t = type + i*FF_MAX_FORMANTS*3 + j*3 + 2; | |||||
a[0].f = obj->getformantfreq(f.freq); | |||||
a[1].f = obj->getformantamp(f.amp); | |||||
a[2].f = obj->getformantq(f.q); | |||||
//printf("<%d,%d,%d,%d,%d,%f,%f,%f>\n", i, j, f.freq, f.amp, f.q, a[0].f, a[1].f, a[2].f); | |||||
t[0] = t[1] = t[2] = 'f'; | |||||
} | |||||
} | |||||
d.replyArray(d.loc, type, args); | |||||
}}, | |||||
}; | }; | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb | #define rChangeCb | ||||
@@ -287,21 +367,18 @@ float FilterParams::getfreqpos(float freq) const | |||||
*/ | */ | ||||
float FilterParams::getformantfreq(unsigned char freq) const | float FilterParams::getformantfreq(unsigned char freq) const | ||||
{ | { | ||||
float result = getfreqx(freq / 127.0f); | |||||
return result; | |||||
return getfreqx(freq / 127.0f); | |||||
} | } | ||||
float FilterParams::getformantamp(unsigned char amp) const | float FilterParams::getformantamp(unsigned char amp) const | ||||
{ | { | ||||
float result = powf(0.1f, (1.0f - amp / 127.0f) * 4.0f); | |||||
return result; | |||||
return powf(0.1f, (1.0f - amp / 127.0f) * 4.0f); | |||||
} | } | ||||
float FilterParams::getformantq(unsigned char q) const | float FilterParams::getformantq(unsigned char q) const | ||||
{ | { | ||||
//temp | //temp | ||||
float result = powf(25.0f, (q - 32.0f) / 64.0f); | |||||
return result; | |||||
return powf(25.0f, (q - 32.0f) / 64.0f); | |||||
} | } | ||||
@@ -27,6 +27,8 @@ using namespace rtosc; | |||||
#define rObject LFOParams | #define rObject LFOParams | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | ||||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||||
#define rEnd } | |||||
static const rtosc::Ports _ports = { | static const rtosc::Ports _ports = { | ||||
rSelf(LFOParams), | rSelf(LFOParams), | ||||
rPaste, | rPaste, | ||||
@@ -35,8 +37,8 @@ static const rtosc::Ports _ports = { | |||||
"true frequency is [0,85.33] Hz"), | "true frequency is [0,85.33] Hz"), | ||||
rParamZyn(Pintensity, rShort("depth"), "Intensity of LFO"), | rParamZyn(Pintensity, rShort("depth"), "Intensity of LFO"), | ||||
rParamZyn(Pstartphase, rShort("start"), rSpecial(random), "Starting Phase"), | rParamZyn(Pstartphase, rShort("start"), rSpecial(random), "Starting Phase"), | ||||
rOption(PLFOtype, rShort("type"), rOptions(sine, triangle, square, ramp-up, ramp-down, | |||||
exponential-down1, exponential-down2), "Shape of LFO"), | |||||
rOption(PLFOtype, rShort("type"), rOptions(sine, triangle, square, up, down, | |||||
exp1, exp2), "Shape of LFO"), | |||||
rParamZyn(Prandomness, rShort("a.r."), rSpecial(disable), | rParamZyn(Prandomness, rShort("a.r."), rSpecial(disable), | ||||
"Amplitude Randomness (calculated uniformly at each cycle)"), | "Amplitude Randomness (calculated uniformly at each cycle)"), | ||||
rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable), | rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable), | ||||
@@ -45,7 +47,20 @@ static const rtosc::Ports _ports = { | |||||
"0..4 second delay"), | "0..4 second delay"), | ||||
rToggle(Pcontinous, rShort("c"), "Enable for global operation"), | rToggle(Pcontinous, rShort("c"), "Enable for global operation"), | ||||
rParamZyn(Pstretch, rShort("str"), rCentered, "Note frequency stretch"), | rParamZyn(Pstretch, rShort("str"), rCentered, "Note frequency stretch"), | ||||
//Float valued aliases | |||||
{"delay::f", rProp(parameter) rMap(units, ms) rLog(0,4000), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
#define rPseudoLog(a,b) rLog(a,b) | |||||
{"period::f", rProp(parameter) rMap(units, ms) rPseudoLog(0.10, 1500.0), 0, | |||||
rBegin; | |||||
rEnd}, | |||||
}; | }; | ||||
#undef rPseudoLog | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rChangeCb | #undef rChangeCb | ||||
const rtosc::Ports &LFOParams::ports = _ports; | const rtosc::Ports &LFOParams::ports = _ports; | ||||
@@ -18,6 +18,7 @@ | |||||
#include "../Synth/Resonance.h" | #include "../Synth/Resonance.h" | ||||
#include "../Synth/OscilGen.h" | #include "../Synth/OscilGen.h" | ||||
#include "../Misc/WavFile.h" | #include "../Misc/WavFile.h" | ||||
#include "../Misc/Time.h" | |||||
#include <cstdio> | #include <cstdio> | ||||
#include <rtosc/ports.h> | #include <rtosc/ports.h> | ||||
@@ -136,30 +137,30 @@ static const rtosc::Ports non_realtime_ports = | |||||
rRecurp(resonance, "Resonance"), | rRecurp(resonance, "Resonance"), | ||||
//Harmonic Shape | //Harmonic Shape | ||||
rOption(Pmode, rMap(min, 0), rMap(max, 2), rOptions(bandwidth,discrete,continious), | |||||
rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), rOptions(bandwidth,discrete,continious), | |||||
"Harmonic Distribution Model"), | "Harmonic Distribution Model"), | ||||
rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), | |||||
rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), rShort("shape"), | |||||
"Harmonic profile shape"), | "Harmonic profile shape"), | ||||
rParamZyn(Php.base.par1, "Harmonic shape distribution parameter"), | |||||
rParamZyn(Php.freqmult, "Frequency multiplier on distribution"), | |||||
rParamZyn(Php.modulator.par1, "Distribution modulator parameter"), | |||||
rParamZyn(Php.modulator.freq, "Frequency of modulator parameter"), | |||||
rParamZyn(Php.width, "Width of base harmonic"), | |||||
rOption(Php.amp.mode, rOptions(Sum, Mult, Div1, Div2), | |||||
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), | |||||
"Amplitude harmonic multiplier type"), | "Amplitude harmonic multiplier type"), | ||||
//Harmonic Modulation | //Harmonic Modulation | ||||
rOption(Php.amp.type, rOptions(Off, Gauss, Sine, Flat), | |||||
rOption(Php.amp.type, rShort("mult"), rOptions(Off, Gauss, Sine, Flat), | |||||
"Type of amplitude multipler"), | "Type of amplitude multipler"), | ||||
rParamZyn(Php.amp.par1, "Amplitude multiplier parameter"), | |||||
rParamZyn(Php.amp.par2, "Amplitude multiplier parameter"), | |||||
rToggle(Php.autoscale, "Autoscaling Harmonics"), | |||||
rOption(Php.onehalf, | |||||
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"), | |||||
rOption(Php.onehalf, rShort("side"), | |||||
rOptions(Full, Upper Half, Lower Half), | rOptions(Full, Upper Half, Lower Half), | ||||
"Harmonic cutoff model"), | "Harmonic cutoff model"), | ||||
//Harmonic Bandwidth | //Harmonic Bandwidth | ||||
rOption(Pbwscale, | |||||
rOption(Pbwscale, rShort("bw scale"), | |||||
rOptions(Normal, | rOptions(Normal, | ||||
EqualHz, Quater, | EqualHz, Quater, | ||||
Half, 75%, 150%, | Half, 75%, 150%, | ||||
@@ -171,26 +172,26 @@ static const rtosc::Ports non_realtime_ports = | |||||
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, | rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, | ||||
Power, Shift), | Power, Shift), | ||||
"Harmonic Overtone shifting mode"), | "Harmonic Overtone shifting mode"), | ||||
rParamI(Phrpos.par1, rLinear(0,255), "Harmonic position parameter"), | |||||
rParamI(Phrpos.par2, rLinear(0,255), "Harmonic position parameter"), | |||||
rParamI(Phrpos.par3, rLinear(0,255), "Harmonic position parameter"), | |||||
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"), | |||||
//Quality | //Quality | ||||
rOption(Pquality.samplesize, | |||||
rOption(Pquality.samplesize, rShort("quality"), | |||||
rOptions(16k (Tiny), 32k, 64k (Small), 128k, | rOptions(16k (Tiny), 32k, 64k (Small), 128k, | ||||
256k (Normal), 512k, 1M (Big)), | 256k (Normal), 512k, 1M (Big)), | ||||
"Size of each wavetable element"), | "Size of each wavetable element"), | ||||
rOption(Pquality.basenote, | |||||
rOptions( C-2, G-2, C-3, G-3, C-4, | |||||
rOption(Pquality.basenote, rShort("basenote"), | |||||
rOptions(C-2, G-2, C-3, G-3, C-4, | |||||
G-4, C-5, G-5, G-6,), | G-4, C-5, G-5, G-6,), | ||||
"Base note for wavetable"), | "Base note for wavetable"), | ||||
rOption(Pquality.smpoct, | |||||
rOption(Pquality.smpoct, rShort("smp/oct"), | |||||
rOptions(0.5, 1, 2, 3, 4, 6, 12), | rOptions(0.5, 1, 2, 3, 4, 6, 12), | ||||
"Samples per octave"), | "Samples per octave"), | ||||
rParamI(Pquality.oct, rLinear(0,7), | |||||
rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7), | |||||
"Number of octaves to sample (above the first sample"), | "Number of octaves to sample (above the first sample"), | ||||
{"Pbandwidth::i", rProp(parameter) rLinear(0,1000) rDoc("Bandwith Of Harmonics"), NULL, | |||||
{"Pbandwidth::i", rShort("bandwidth") rProp(parameter) rLinear(0,1000) rDoc("Bandwith Of Harmonics"), NULL, | |||||
[](const char *msg, rtosc::RtData &d) { | [](const char *msg, rtosc::RtData &d) { | ||||
PADnoteParameters *p = ((PADnoteParameters*)d.obj); | PADnoteParameters *p = ((PADnoteParameters*)d.obj); | ||||
if(rtosc_narguments(msg)) { | if(rtosc_narguments(msg)) { | ||||
@@ -225,8 +226,24 @@ static const rtosc::Ports non_realtime_ports = | |||||
float *tmp = new float[n]; | float *tmp = new float[n]; | ||||
float realbw = p->getprofile(tmp, n); | float realbw = p->getprofile(tmp, n); | ||||
d.reply(d.loc, "b", n*sizeof(float), tmp); | d.reply(d.loc, "b", n*sizeof(float), tmp); | ||||
d.reply(d.loc, "i", realbw); | |||||
d.reply(d.loc, "i", (int)realbw); | |||||
delete[] tmp;}}, | delete[] tmp;}}, | ||||
{"harmonic_profile:", rProp(non-realtime) rDoc("UI display of the harmonic profile"), | |||||
NULL, [](const char *m, rtosc::RtData &d) { | |||||
PADnoteParameters *p = ((PADnoteParameters*)d.obj); | |||||
#define RES 512 | |||||
char types[RES+2] = {0}; | |||||
rtosc_arg_t args[RES+1]; | |||||
float tmp[RES]; | |||||
types[0] = 'f'; | |||||
args[0].f = p->getprofile(tmp, RES); | |||||
for(int i=0; i<RES; ++i) { | |||||
types[i+1] = 'f'; | |||||
args[i+1].f = tmp[i]; | |||||
} | |||||
d.replyArray(d.loc, types, args); | |||||
#undef RES | |||||
}}, | |||||
{"needPrepare:", rDoc("Unimplemented Stub"), | {"needPrepare:", rDoc("Unimplemented Stub"), | ||||
NULL, [](const char *, rtosc::RtData&) {}}, | NULL, [](const char *, rtosc::RtData&) {}}, | ||||
}; | }; | ||||
@@ -26,102 +26,147 @@ | |||||
#define rObject SUBnoteParameters | #define rObject SUBnoteParameters | ||||
using namespace rtosc; | using namespace rtosc; | ||||
#define rBegin [](const char *msg, RtData &d) { \ | |||||
SUBnoteParameters *obj = (SUBnoteParameters*) d.obj | |||||
#define rEnd } | |||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | ||||
static const rtosc::Ports SUBnotePorts = { | static const rtosc::Ports SUBnotePorts = { | ||||
rSelf(SUBnoteParameters), | rSelf(SUBnoteParameters), | ||||
rPaste, | rPaste, | ||||
rToggle(Pstereo, "Stereo Enable"), | |||||
rParamZyn(PVolume, "Volume"), | |||||
rParamZyn(PPanning, "Left Right Panning"), | |||||
rParamZyn(PAmpVelocityScaleFunction, "Amplitude Velocity Sensing function"), | |||||
rParamI(PDetune, "Detune in detune type units"), | |||||
rParamI(PCoarseDetune, "Coarse Detune"), | |||||
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"), "Detune in detune type units"), | |||||
rParamI(PCoarseDetune, rShort("cdetune"), "Coarse Detune"), | |||||
//Real values needed | //Real values needed | ||||
rOption(PDetuneType, rOptions("100 cents", "200 cents", "500 cents"), "Detune Scale"), | |||||
rToggle(PFreqEnvelopeEnabled, "Enable for Frequency Envelope"), | |||||
rToggle(PBandWidthEnvelopeEnabled, "Enable for Bandwidth Envelope"), | |||||
rToggle(PGlobalFilterEnabled, "Enable for Global Filter"), | |||||
rParamZyn(PGlobalFilterVelocityScale, "Filter Velocity Magnitude"), | |||||
rParamZyn(PGlobalFilterVelocityScaleFunction, "Filter Velocity Function Shape"), | |||||
rOption(PDetuneType, rShort("det. scl."), rOptions(100 cents, 200 cents, 500 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"), | |||||
//rRecur(FreqEnvelope, EnvelopeParams), | //rRecur(FreqEnvelope, EnvelopeParams), | ||||
//rToggle(),//continue | //rToggle(),//continue | ||||
rToggle(Pfixedfreq, "Base frequency fixed frequency enable"), | |||||
rParamZyn(PfixedfreqET, "Equal temeperate control for fixed frequency operation"), | |||||
rParamZyn(PBendAdjust, "Pitch bend adjustment"), | |||||
rParamZyn(POffsetHz, "Voice constant offset"), | |||||
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"), | |||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb obj->updateFrequencyMultipliers(); if (obj->time) { \ | #define rChangeCb obj->updateFrequencyMultipliers(); if (obj->time) { \ | ||||
obj->last_update_timestamp = obj->time->time(); } | obj->last_update_timestamp = obj->time->time(); } | ||||
rParamI(POvertoneSpread.type, rMap(min, 0), rMap(max, 7), | |||||
rParamI(POvertoneSpread.type, rMap(min, 0), rMap(max, 7), rShort("spread type") | |||||
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, Power, Shift), | |||||
"Spread of harmonic frequencies"), | "Spread of harmonic frequencies"), | ||||
rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), | |||||
rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), rShort("p1"), | |||||
"Overtone Parameter"), | "Overtone Parameter"), | ||||
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), | |||||
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"), | |||||
"Overtone Parameter"), | "Overtone Parameter"), | ||||
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), | |||||
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("p3"), | |||||
"Overtone Parameter"), | "Overtone Parameter"), | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); } | ||||
rParamZyn(Pnumstages, rMap(min, 1), rMap(max, 5), "Number of filter stages"), | |||||
rParamZyn(Pbandwidth, "Bandwidth of filters"), | |||||
rParamZyn(Phmagtype, "How the magnitudes are computed (0=linear,1=-60dB,2=-60dB)"), | |||||
rParamZyn(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), "Number of filter stages"), | |||||
rParamZyn(Pbandwidth, rShort("bandwidth"), "Bandwidth of filters"), | |||||
rParamZyn(Phmagtype, rShort("mag. type"),"How the magnitudes are computed (0=linear,1=-60dB,2=-60dB)"), | |||||
rArray(Phmag, MAX_SUB_HARMONICS, "Harmonic magnitudes"), | rArray(Phmag, MAX_SUB_HARMONICS, "Harmonic magnitudes"), | ||||
rArray(Phrelbw, MAX_SUB_HARMONICS, "Relative bandwidth"), | rArray(Phrelbw, MAX_SUB_HARMONICS, "Relative bandwidth"), | ||||
rParamZyn(Pbwscale, "Bandwidth scaling with frequency"), | |||||
rParamZyn(Pbwscale, rShort("stretch"), "Bandwidth scaling with frequency"), | |||||
rRecurp(AmpEnvelope, "Amplitude envelope"), | rRecurp(AmpEnvelope, "Amplitude envelope"), | ||||
rRecurp(FreqEnvelope, "Frequency Envelope"), | rRecurp(FreqEnvelope, "Frequency Envelope"), | ||||
rRecurp(BandWidthEnvelope, "Bandwidth Envelope"), | rRecurp(BandWidthEnvelope, "Bandwidth Envelope"), | ||||
rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"), | rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"), | ||||
rRecurp(GlobalFilter, "Post Filter"), | rRecurp(GlobalFilter, "Post Filter"), | ||||
rOption(Pstart, rOptions("zero", "random", "ones"), "How harmonics are initialized"), | |||||
{"clear:", rDoc("Reset all harmonics to equal bandwidth/zero amplitude"), NULL, [](const char *, RtData &d) | |||||
{ | |||||
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj; | |||||
for(int i=0; i<MAX_SUB_HARMONICS; ++i) { | |||||
obj->Phmag[i] = 0; | |||||
obj->Phrelbw[i] = 64; | |||||
} | |||||
obj->Phmag[0] = 127; | |||||
}}, | |||||
{"detunevalue:", rDoc("Get note detune value"), NULL, [](const char *, RtData &d) | |||||
{ | |||||
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj; | |||||
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune)); | |||||
}}, | |||||
rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), "How harmonics are initialized"), | |||||
{"clear:", rDoc("Reset all harmonics to equal bandwidth/zero amplitude"), NULL, | |||||
rBegin; | |||||
for(int i=0; i<MAX_SUB_HARMONICS; ++i) { | |||||
obj->Phmag[i] = 0; | |||||
obj->Phrelbw[i] = 64; | |||||
} | |||||
obj->Phmag[0] = 127; | |||||
rEnd}, | |||||
{"detunevalue:", rDoc("Get note detune value"), NULL, | |||||
rBegin; | |||||
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune)); | |||||
rEnd}, | |||||
//weird stuff for PCoarseDetune | //weird stuff for PCoarseDetune | ||||
{"octave::c:i", rProp(parameter) rDoc("Note octave shift"), NULL, | {"octave::c:i", rProp(parameter) rDoc("Note octave shift"), NULL, | ||||
[](const char *msg, RtData &d) | |||||
{ | |||||
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj; | |||||
if(!rtosc_narguments(msg)) { | |||||
int k=obj->PCoarseDetune/1024; | |||||
if (k>=8) k-=16; | |||||
d.reply(d.loc, "i", k); | |||||
} else { | |||||
int k=(int) rtosc_argument(msg, 0).i; | |||||
if (k<0) k+=16; | |||||
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024; | |||||
} | |||||
}}, | |||||
rBegin; | |||||
if(!rtosc_narguments(msg)) { | |||||
int k=obj->PCoarseDetune/1024; | |||||
if (k>=8) k-=16; | |||||
d.reply(d.loc, "i", k); | |||||
} else { | |||||
int k=(int) rtosc_argument(msg, 0).i; | |||||
if (k<0) k+=16; | |||||
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024; | |||||
} | |||||
rEnd}, | |||||
{"coarsedetune::c:i", rProp(parameter) rDoc("Note coarse detune"), NULL, | {"coarsedetune::c:i", rProp(parameter) rDoc("Note coarse detune"), NULL, | ||||
[](const char *msg, RtData &d) | |||||
{ | |||||
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj; | |||||
if(!rtosc_narguments(msg)) { | |||||
int k=obj->PCoarseDetune%1024; | |||||
if (k>=512) k-=1024; | |||||
d.reply(d.loc, "i", k); | |||||
} else { | |||||
int k=(int) rtosc_argument(msg, 0).i; | |||||
if (k<0) k+=1024; | |||||
obj->PCoarseDetune = k + (obj->PCoarseDetune/1024)*1024; | |||||
} | |||||
}}, | |||||
rBegin; | |||||
if(!rtosc_narguments(msg)) { | |||||
int k=obj->PCoarseDetune%1024; | |||||
if (k>=512) k-=1024; | |||||
d.reply(d.loc, "i", k); | |||||
} else { | |||||
int k=(int) rtosc_argument(msg, 0).i; | |||||
if (k<0) k+=1024; | |||||
obj->PCoarseDetune = k + (obj->PCoarseDetune/1024)*1024; | |||||
} | |||||
rEnd}, | |||||
{"response:", rDoc("Filter response at 440Hz. with 48kHz sample rate\n\n" | |||||
"Format: stages, filter*active_filters\n" | |||||
" filter = [frequency, bandwidth, amplitude]"), | |||||
NULL, | |||||
rBegin; | |||||
//Identify the active harmonics | |||||
int pos[MAX_SUB_HARMONICS]; | |||||
int harmonics; | |||||
obj->activeHarmonics(pos, harmonics); | |||||
float base_freq = 440.0f; | |||||
char types[3*MAX_SUB_HARMONICS+2]; | |||||
rtosc_arg_t args[3*MAX_SUB_HARMONICS+1]; | |||||
args[0].i = obj->Pnumstages; | |||||
types[0] = 'i'; | |||||
for(int n=0; n<harmonics; ++n) { | |||||
const float freq = base_freq * obj->POvertoneFreqMult[pos[n]]; | |||||
//the bandwidth is not absolute(Hz); it is relative to frequency | |||||
const float bw = obj->convertBandwidth(obj->Pbandwidth, | |||||
obj->Pnumstages, freq, obj->Pbwscale, obj->Phrelbw[pos[n]]); | |||||
//try to keep same amplitude on all freqs and bw. (empirically) | |||||
const float hgain = obj->convertHarmonicMag(obj->Phmag[pos[n]], | |||||
obj->Phmagtype); | |||||
const float gain = hgain * sqrt(1500.0f / (bw * freq)); | |||||
int base = 1+3*n; | |||||
args[base + 0].f = freq; | |||||
args[base + 1].f = bw; | |||||
args[base + 2].f = gain; | |||||
types[base + 0] = 'f'; | |||||
types[base + 1] = 'f'; | |||||
types[base + 2] = 'f'; | |||||
} | |||||
types[3*harmonics+1] = 0; | |||||
d.replyArray(d.loc, types, args); | |||||
rEnd}, | |||||
}; | }; | ||||
#undef rChangeCb | #undef rChangeCb | ||||
#undef rBegin | |||||
#undef rEnd | |||||
const rtosc::Ports &SUBnoteParameters::ports = SUBnotePorts; | const rtosc::Ports &SUBnoteParameters::ports = SUBnotePorts; | ||||
@@ -143,6 +188,56 @@ SUBnoteParameters::SUBnoteParameters(const AbsTime *time_) | |||||
defaults(); | defaults(); | ||||
} | } | ||||
void SUBnoteParameters::activeHarmonics(int *pos, int &harmonics) const | |||||
{ | |||||
harmonics = 0; | |||||
for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { | |||||
if(Phmag[n] == 0) | |||||
continue; | |||||
pos[harmonics++] = n; | |||||
} | |||||
} | |||||
float SUBnoteParameters::convertBandwidth(int bw_, int stages, float freq, | |||||
int scale, int relbw) | |||||
{ | |||||
//the bandwidth is not absolute(Hz); it is relative to frequency | |||||
float bw = powf(10, (bw_ - 127.0f) / 127.0f * 4) * stages; | |||||
//Bandwidth Scale | |||||
bw *= powf(1000 / freq, (scale - 64.0f) / 64.0f * 3.0f); | |||||
//Relative BandWidth | |||||
bw *= powf(100, (relbw - 64.0f) / 64.0f); | |||||
if(bw > 25.0f) | |||||
bw = 25.0f; | |||||
return bw; | |||||
} | |||||
float SUBnoteParameters::convertHarmonicMag(int mag, int type) | |||||
{ | |||||
const float hmagnew = 1.0f - mag / 127.0f; | |||||
switch(type) { | |||||
case 1: | |||||
return expf(hmagnew * logf(0.01f)); | |||||
break; | |||||
case 2: | |||||
return expf(hmagnew * logf(0.001f)); | |||||
break; | |||||
case 3: | |||||
return expf(hmagnew * logf(0.0001f)); | |||||
break; | |||||
case 4: | |||||
return expf(hmagnew * logf(0.00001f)); | |||||
break; | |||||
default: | |||||
return 1.0f - hmagnew; | |||||
} | |||||
} | |||||
void SUBnoteParameters::defaults() | void SUBnoteParameters::defaults() | ||||
{ | { | ||||
@@ -24,6 +24,15 @@ class SUBnoteParameters:public Presets | |||||
SUBnoteParameters(const AbsTime *time_ = nullptr); | SUBnoteParameters(const AbsTime *time_ = nullptr); | ||||
~SUBnoteParameters(); | ~SUBnoteParameters(); | ||||
//Identify active harmonic positions | |||||
// - pos : int[MAX_SUB_HARMONICS] offsets of active harmonics | |||||
// - harmonics : number of active harmonics | |||||
void activeHarmonics(int *pos, int &harmonics) const; | |||||
static float convertBandwidth(int bw, int stages, float freq, | |||||
int scale, int relbw); | |||||
static float convertHarmonicMag(int mag, int type); | |||||
void add2XML(XMLwrapper& xml); | void add2XML(XMLwrapper& xml); | ||||
void defaults(); | void defaults(); | ||||
void getfromXML(XMLwrapper& xml); | void getfromXML(XMLwrapper& xml); | ||||
@@ -31,7 +40,7 @@ class SUBnoteParameters:public Presets | |||||
void paste(SUBnoteParameters &sub); | void paste(SUBnoteParameters &sub); | ||||
//Parameters | //Parameters | ||||
//AMPLITUDE PARAMETRERS | |||||
//AMPLITUDE PARAMETERS | |||||
unsigned char Pstereo; //0 for mono,1 for stereo | unsigned char Pstereo; //0 for mono,1 for stereo | ||||
unsigned char PVolume; | unsigned char PVolume; | ||||
unsigned char PPanning; | unsigned char PPanning; | ||||
@@ -22,11 +22,13 @@ | |||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
#include "../Misc/Allocator.h" | #include "../Misc/Allocator.h" | ||||
#include "../Params/ADnoteParameters.h" | #include "../Params/ADnoteParameters.h" | ||||
#include "../Containers/ScratchString.h" | |||||
#include "ModFilter.h" | #include "ModFilter.h" | ||||
#include "OscilGen.h" | #include "OscilGen.h" | ||||
#include "ADnote.h" | #include "ADnote.h" | ||||
ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars) | |||||
ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars, | |||||
WatchManager *wm, const char *prefix) | |||||
:SynthNote(spars), pars(*pars_) | :SynthNote(spars), pars(*pars_) | ||||
{ | { | ||||
memory.beginTransaction(); | memory.beginTransaction(); | ||||
@@ -450,7 +452,7 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars) | |||||
memset(tmpwave_unison[k], 0, synth.bufferbytes); | memset(tmpwave_unison[k], 0, synth.bufferbytes); | ||||
} | } | ||||
initparameters(); | |||||
initparameters(wm, prefix); | |||||
memory.endTransaction(); | memory.endTransaction(); | ||||
} | } | ||||
@@ -772,16 +774,17 @@ ADnote::~ADnote() | |||||
/* | /* | ||||
* Init the parameters | * Init the parameters | ||||
*/ | */ | ||||
void ADnote::initparameters() | |||||
void ADnote::initparameters(WatchManager *wm, const char *prefix) | |||||
{ | { | ||||
int tmp[NUM_VOICES]; | int tmp[NUM_VOICES]; | ||||
ScratchString pre = prefix; | |||||
//ADnoteParameters &pars = *partparams; | //ADnoteParameters &pars = *partparams; | ||||
// Global Parameters | // Global Parameters | ||||
NoteGlobalPar.initparameters(pars.GlobalPar, synth, | NoteGlobalPar.initparameters(pars.GlobalPar, synth, | ||||
time, | time, | ||||
memory, basefreq, velocity, | memory, basefreq, velocity, | ||||
stereo); | |||||
stereo, wm, prefix); | |||||
NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output | NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output | ||||
globalnewamplitude = NoteGlobalPar.Volume | globalnewamplitude = NoteGlobalPar.Volume | ||||
@@ -816,22 +819,28 @@ void ADnote::initparameters() | |||||
newamplitude[nvoice] = 1.0f; | newamplitude[nvoice] = 1.0f; | ||||
if(param.PAmpEnvelopeEnabled) { | if(param.PAmpEnvelopeEnabled) { | ||||
vce.AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, synth.dt()); | |||||
vce.AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, | |||||
basefreq, synth.dt(), wm, | |||||
(pre+"VoicePar"+nvoice+"/AmpEnvelope/").c_str); | |||||
vce.AmpEnvelope->envout_dB(); //discard the first envelope sample | vce.AmpEnvelope->envout_dB(); //discard the first envelope sample | ||||
newamplitude[nvoice] *= vce.AmpEnvelope->envout_dB(); | newamplitude[nvoice] *= vce.AmpEnvelope->envout_dB(); | ||||
} | } | ||||
if(param.PAmpLfoEnabled) { | if(param.PAmpLfoEnabled) { | ||||
vce.AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time); | |||||
vce.AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time, wm, | |||||
(pre+"VoicePar"+nvoice+"/AmpLfo/").c_str); | |||||
newamplitude[nvoice] *= vce.AmpLfo->amplfoout(); | newamplitude[nvoice] *= vce.AmpLfo->amplfoout(); | ||||
} | } | ||||
/* Voice Frequency Parameters Init */ | /* Voice Frequency Parameters Init */ | ||||
if(param.PFreqEnvelopeEnabled) | if(param.PFreqEnvelopeEnabled) | ||||
vce.FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, synth.dt()); | |||||
vce.FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, | |||||
basefreq, synth.dt(), wm, | |||||
(pre+"VoicePar"+nvoice+"/FreqEnvelope/").c_str); | |||||
if(param.PFreqLfoEnabled) | if(param.PFreqLfoEnabled) | ||||
vce.FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time); | |||||
vce.FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time, wm, | |||||
(pre+"VoicePar"+nvoice+"/FreqLfo/").c_str); | |||||
/* Voice Filter Parameters Init */ | /* Voice Filter Parameters Init */ | ||||
if(param.PFilterEnabled) { | if(param.PFilterEnabled) { | ||||
@@ -843,12 +852,15 @@ void ADnote::initparameters() | |||||
if(param.PFilterEnvelopeEnabled) { | if(param.PFilterEnvelopeEnabled) { | ||||
vce.FilterEnvelope = | vce.FilterEnvelope = | ||||
memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, synth.dt()); | |||||
memory.alloc<Envelope>(*param.FilterEnvelope, | |||||
basefreq, synth.dt(), wm, | |||||
(pre+"VoicePar"+nvoice+"/FilterEnvelope/").c_str); | |||||
vce.Filter->addMod(*vce.FilterEnvelope); | vce.Filter->addMod(*vce.FilterEnvelope); | ||||
} | } | ||||
if(param.PFilterLfoEnabled) { | if(param.PFilterLfoEnabled) { | ||||
vce.FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time); | |||||
vce.FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time, wm, | |||||
(pre+"VoicePar"+nvoice+"/FilterLfo/").c_str); | |||||
vce.Filter->addMod(*vce.FilterLfo); | vce.Filter->addMod(*vce.FilterLfo); | ||||
} | } | ||||
} | } | ||||
@@ -892,13 +904,17 @@ void ADnote::initparameters() | |||||
} | } | ||||
if(param.PFMFreqEnvelopeEnabled) | if(param.PFMFreqEnvelopeEnabled) | ||||
vce.FMFreqEnvelope = memory.alloc<Envelope>(*param.FMFreqEnvelope, basefreq, synth.dt()); | |||||
vce.FMFreqEnvelope = memory.alloc<Envelope>(*param.FMFreqEnvelope, | |||||
basefreq, synth.dt(), wm, | |||||
(pre+"VoicePar"+nvoice+"/FMFreqEnvelope/").c_str); | |||||
FMnewamplitude[nvoice] = vce.FMVolume * ctl.fmamp.relamp; | FMnewamplitude[nvoice] = vce.FMVolume * ctl.fmamp.relamp; | ||||
if(param.PFMAmpEnvelopeEnabled ) { | if(param.PFMAmpEnvelopeEnabled ) { | ||||
vce.FMAmpEnvelope = | vce.FMAmpEnvelope = | ||||
memory.alloc<Envelope>(*param.FMAmpEnvelope, basefreq, synth.dt()); | |||||
memory.alloc<Envelope>(*param.FMAmpEnvelope, | |||||
basefreq, synth.dt(), wm, | |||||
(pre+"VoicePar"+nvoice+"/FMAmpEnvelope/").c_str); | |||||
FMnewamplitude[nvoice] *= vce.FMAmpEnvelope->envout_dB(); | FMnewamplitude[nvoice] *= vce.FMAmpEnvelope->envout_dB(); | ||||
} | } | ||||
} | } | ||||
@@ -1873,13 +1889,20 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam ¶m, | |||||
const AbsTime &time, | const AbsTime &time, | ||||
class Allocator &memory, | class Allocator &memory, | ||||
float basefreq, float velocity, | float basefreq, float velocity, | ||||
bool stereo) | |||||
bool stereo, | |||||
WatchManager *wm, | |||||
const char *prefix) | |||||
{ | { | ||||
FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, synth.dt()); | |||||
FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time); | |||||
ScratchString pre = prefix; | |||||
FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, | |||||
synth.dt(), wm, (pre+"GlobalPar/FreqEnvelope/").c_str); | |||||
FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time, wm, | |||||
(pre+"GlobalPar/FreqLfo/").c_str); | |||||
AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, synth.dt()); | |||||
AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time); | |||||
AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, | |||||
synth.dt(), wm, (pre+"GlobalPar/AmpEnvelope/").c_str); | |||||
AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time, wm, | |||||
(pre+"GlobalPar/AmpLfo/").c_str); | |||||
Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB | Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB | ||||
* VelF(velocity, param.PAmpVelocityScaleFunction); //sensing | * VelF(velocity, param.PAmpVelocityScaleFunction); //sensing | ||||
@@ -1887,8 +1910,10 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam ¶m, | |||||
Filter = memory.alloc<ModFilter>(*param.GlobalFilter, synth, time, memory, | Filter = memory.alloc<ModFilter>(*param.GlobalFilter, synth, time, memory, | ||||
stereo, basefreq); | stereo, basefreq); | ||||
FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, synth.dt()); | |||||
FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time); | |||||
FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, | |||||
synth.dt(), wm, (pre+"GlobalPar/FilterEnvelope/").c_str); | |||||
FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time, wm, | |||||
(pre+"GlobalPar/FilterLfo/").c_str); | |||||
Filter->addMod(*FilterEnvelope); | Filter->addMod(*FilterEnvelope); | ||||
Filter->addMod(*FilterLfo); | Filter->addMod(*FilterLfo); | ||||
@@ -34,7 +34,8 @@ class ADnote:public SynthNote | |||||
/**Constructor. | /**Constructor. | ||||
* @param pars Note Parameters | * @param pars Note Parameters | ||||
* @param spars Synth Engine Agnostic Parameters*/ | * @param spars Synth Engine Agnostic Parameters*/ | ||||
ADnote(ADnoteParameters *pars, SynthParams &spars); | |||||
ADnote(ADnoteParameters *pars, SynthParams &spars, | |||||
WatchManager *wm=0, const char *prefix=0); | |||||
/**Destructor*/ | /**Destructor*/ | ||||
~ADnote(); | ~ADnote(); | ||||
@@ -62,7 +63,7 @@ class ADnote:public SynthNote | |||||
/**Compute parameters for next tick*/ | /**Compute parameters for next tick*/ | ||||
void computecurrentparameters(); | void computecurrentparameters(); | ||||
/**Initializes All Parameters*/ | /**Initializes All Parameters*/ | ||||
void initparameters(); | |||||
void initparameters(WatchManager *wm, const char *prefix); | |||||
/**Deallocate/Cleanup given voice*/ | /**Deallocate/Cleanup given voice*/ | ||||
void KillVoice(int nvoice); | void KillVoice(int nvoice); | ||||
/**Deallocate Note resources and voice resources*/ | /**Deallocate Note resources and voice resources*/ | ||||
@@ -117,7 +118,9 @@ class ADnote:public SynthNote | |||||
const AbsTime &time, | const AbsTime &time, | ||||
class Allocator &memory, | class Allocator &memory, | ||||
float basefreq, float velocity, | float basefreq, float velocity, | ||||
bool stereo); | |||||
bool stereo, | |||||
WatchManager *wm, | |||||
const char *prefix); | |||||
/****************************************** | /****************************************** | ||||
* FREQUENCY GLOBAL PARAMETERS * | * FREQUENCY GLOBAL PARAMETERS * | ||||
******************************************/ | ******************************************/ | ||||
@@ -15,7 +15,9 @@ | |||||
#include "Envelope.h" | #include "Envelope.h" | ||||
#include "../Params/EnvelopeParams.h" | #include "../Params/EnvelopeParams.h" | ||||
Envelope::Envelope(EnvelopeParams &pars, float basefreq, float bufferdt) | |||||
Envelope::Envelope(EnvelopeParams &pars, float basefreq, float bufferdt, | |||||
WatchManager *m, const char *watch_prefix) | |||||
:watchOut(m, watch_prefix, "out") | |||||
{ | { | ||||
envpoints = pars.Penvpoints; | envpoints = pars.Penvpoints; | ||||
if(envpoints > MAX_ENVELOPE_POINTS) | if(envpoints > MAX_ENVELOPE_POINTS) | ||||
@@ -88,7 +90,7 @@ void Envelope::releasekey() | |||||
if(keyreleased) | if(keyreleased) | ||||
return; | return; | ||||
keyreleased = true; | keyreleased = true; | ||||
if(forcedrelease != 0) | |||||
if(forcedrelease) | |||||
t = 0.0f; | t = 0.0f; | ||||
} | } | ||||
@@ -100,20 +102,28 @@ void Envelope::forceFinish(void) | |||||
/* | /* | ||||
* Envelope Output | * Envelope Output | ||||
*/ | */ | ||||
float Envelope::envout() | |||||
float Envelope::envout(bool doWatch) | |||||
{ | { | ||||
float out; | float out; | ||||
if(envfinish) { //if the envelope is finished | if(envfinish) { //if the envelope is finished | ||||
envoutval = envval[envpoints - 1]; | envoutval = envval[envpoints - 1]; | ||||
if(doWatch) { | |||||
float pos[2] = {(float)envpoints - 1, envoutval}; | |||||
watchOut(pos, 2); | |||||
} | |||||
return envoutval; | return envoutval; | ||||
} | } | ||||
if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now | if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now | ||||
envoutval = envval[envsustain]; | envoutval = envval[envsustain]; | ||||
if(doWatch) { | |||||
float pos[2] = {(float)envsustain, envoutval}; | |||||
watchOut(pos, 2); | |||||
} | |||||
return envoutval; | return envoutval; | ||||
} | } | ||||
if(keyreleased && (forcedrelease != 0)) { //do the forced release | |||||
if(keyreleased && forcedrelease) { //do the forced release | |||||
int tmp = (envsustain < 0) ? (envpoints - 1) : (envsustain + 1); //if there is no sustain point, use the last point for release | int tmp = (envsustain < 0) ? (envpoints - 1) : (envsustain + 1); //if there is no sustain point, use the last point for release | ||||
if(envdt[tmp] < 0.00000001f) | if(envdt[tmp] < 0.00000001f) | ||||
@@ -130,6 +140,12 @@ float Envelope::envout() | |||||
if((currentpoint >= envpoints) || (envsustain < 0)) | if((currentpoint >= envpoints) || (envsustain < 0)) | ||||
envfinish = true; | envfinish = true; | ||||
} | } | ||||
if(doWatch) { | |||||
float pos[2] = {(float)tmp + t, envoutval}; | |||||
watchOut(pos, 2); | |||||
} | |||||
return out; | return out; | ||||
} | } | ||||
if(inct >= 1.0f) | if(inct >= 1.0f) | ||||
@@ -149,6 +165,11 @@ float Envelope::envout() | |||||
} | } | ||||
envoutval = out; | envoutval = out; | ||||
if(doWatch) { | |||||
float pos[2] = {(float)currentpoint + t, envoutval}; | |||||
watchOut(pos, 2); | |||||
} | |||||
return out; | return out; | ||||
} | } | ||||
@@ -166,10 +187,10 @@ inline float Envelope::env_rap2dB(float rap) { | |||||
float Envelope::envout_dB() | float Envelope::envout_dB() | ||||
{ | { | ||||
float out; | float out; | ||||
if(linearenvelope != 0) | |||||
return envout(); | |||||
if(linearenvelope) | |||||
return envout(true); | |||||
if((currentpoint == 1) && (!keyreleased || (forcedrelease == 0))) { //first point is always lineary interpolated | |||||
if((currentpoint == 1) && (!keyreleased || !forcedrelease)) { //first point is always lineary interpolated | |||||
float v1 = env_dB2rap(envval[0]); | float v1 = env_dB2rap(envval[0]); | ||||
float v2 = env_dB2rap(envval[1]); | float v2 = env_dB2rap(envval[1]); | ||||
out = v1 + (v2 - v1) * t; | out = v1 + (v2 - v1) * t; | ||||
@@ -186,9 +207,11 @@ float Envelope::envout_dB() | |||||
envoutval = env_rap2dB(out); | envoutval = env_rap2dB(out); | ||||
else | else | ||||
envoutval = MIN_ENVELOPE_DB; | envoutval = MIN_ENVELOPE_DB; | ||||
} | |||||
else | |||||
out = env_dB2rap(envout()); | |||||
} else | |||||
out = env_dB2rap(envout(false)); | |||||
float pos[2] = {(float)currentpoint + t, out}; | |||||
watchOut(pos, 2); | |||||
return out; | return out; | ||||
} | } | ||||
@@ -15,6 +15,7 @@ | |||||
#define ENVELOPE_H | #define ENVELOPE_H | ||||
#include "../globals.h" | #include "../globals.h" | ||||
#include "WatchPoint.h" | |||||
/**Implementation of a general Envelope*/ | /**Implementation of a general Envelope*/ | ||||
class Envelope | class Envelope | ||||
@@ -22,17 +23,18 @@ class Envelope | |||||
public: | public: | ||||
/**Constructor*/ | /**Constructor*/ | ||||
Envelope(class EnvelopeParams &pars, float basefreq, float dt); | |||||
Envelope(class EnvelopeParams &pars, float basefreq, float dt, WatchManager *m=0, | |||||
const char *watch_prefix=0); | |||||
/**Destructor*/ | /**Destructor*/ | ||||
~Envelope(); | |||||
void releasekey(); | |||||
~Envelope(void); | |||||
void releasekey(void); | |||||
/**Push Envelope to finishing state*/ | /**Push Envelope to finishing state*/ | ||||
void forceFinish(void); | void forceFinish(void); | ||||
float envout(); | |||||
float envout_dB(); | |||||
float envout(bool doWatch=true); | |||||
float envout_dB(void); | |||||
/**Determines the status of the Envelope | /**Determines the status of the Envelope | ||||
* @return returns 1 if the envelope is finished*/ | * @return returns 1 if the envelope is finished*/ | ||||
bool finished() const; | |||||
bool finished(void) const; | |||||
private: | private: | ||||
float env_rap2dB(float rap); | float env_rap2dB(float rap); | ||||
float env_dB2rap(float db); | float env_dB2rap(float db); | ||||
@@ -44,12 +46,14 @@ class Envelope | |||||
int linearenvelope; | int linearenvelope; | ||||
int currentpoint; //current envelope point (starts from 1) | int currentpoint; //current envelope point (starts from 1) | ||||
int forcedrelease; | |||||
bool forcedrelease; | |||||
bool keyreleased; //if the key was released | bool keyreleased; //if the key was released | ||||
bool envfinish; | bool envfinish; | ||||
float t; // the time from the last point | float t; // the time from the last point | ||||
float inct; // the time increment | float inct; // the time increment | ||||
float envoutval; //used to do the forced release | float envoutval; //used to do the forced release | ||||
VecWatchPoint watchOut; | |||||
}; | }; | ||||
@@ -19,13 +19,15 @@ | |||||
#include <cstdio> | #include <cstdio> | ||||
#include <cmath> | #include <cmath> | ||||
LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t) | |||||
LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManager *m, | |||||
const char *watch_prefix) | |||||
:first_half(-1), | :first_half(-1), | ||||
delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec | delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec | ||||
waveShape(lfopars.PLFOtype), | waveShape(lfopars.PLFOtype), | ||||
deterministic(!lfopars.Pfreqrand), | deterministic(!lfopars.Pfreqrand), | ||||
dt_(t.dt()), | dt_(t.dt()), | ||||
lfopars_(lfopars), basefreq_(basefreq) | |||||
lfopars_(lfopars), basefreq_(basefreq), | |||||
watchOut(m, watch_prefix, "out") | |||||
{ | { | ||||
int stretch = lfopars.Pstretch; | int stretch = lfopars.Pstretch; | ||||
if(stretch == 0) | if(stretch == 0) | ||||
@@ -166,6 +168,10 @@ float LFO::lfoout() | |||||
computeNextFreqRnd(); | computeNextFreqRnd(); | ||||
} | } | ||||
float watch_data[2] = {phase, out}; | |||||
watchOut(watch_data, 2); | |||||
return out; | return out; | ||||
} | } | ||||
@@ -16,6 +16,7 @@ | |||||
#include "../globals.h" | #include "../globals.h" | ||||
#include "../Misc/Time.h" | #include "../Misc/Time.h" | ||||
#include "WatchPoint.h" | |||||
/**Class for creating Low Frequency Oscillators*/ | /**Class for creating Low Frequency Oscillators*/ | ||||
class LFO | class LFO | ||||
@@ -26,7 +27,8 @@ class LFO | |||||
* @param lfopars pointer to a LFOParams object | * @param lfopars pointer to a LFOParams object | ||||
* @param basefreq base frequency of LFO | * @param basefreq base frequency of LFO | ||||
*/ | */ | ||||
LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t); | |||||
LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManager *m=0, | |||||
const char *watch_prefix=0); | |||||
~LFO(); | ~LFO(); | ||||
float lfoout(); | float lfoout(); | ||||
@@ -63,6 +65,8 @@ class LFO | |||||
const LFOParams &lfopars_; | const LFOParams &lfopars_; | ||||
const float basefreq_; | const float basefreq_; | ||||
VecWatchPoint watchOut; | |||||
void computeNextFreqRnd(void); | void computeNextFreqRnd(void); | ||||
}; | }; | ||||
@@ -34,54 +34,54 @@ const rtosc::Ports OscilGen::non_realtime_ports = { | |||||
rSelf(OscilGen), | rSelf(OscilGen), | ||||
rPaste, | rPaste, | ||||
//TODO ensure min/max | //TODO ensure min/max | ||||
rOption(Phmagtype, | |||||
rOption(Phmagtype, rShort("scale"), | |||||
rOptions(linear,dB scale (-40), | rOptions(linear,dB scale (-40), | ||||
dB scale (-60), dB scale (-80), | dB scale (-60), dB scale (-80), | ||||
dB scale (-100)), | dB scale (-100)), | ||||
"Type of magnitude for harmonics"), | "Type of magnitude for harmonics"), | ||||
rOption(Pcurrentbasefunc, | |||||
rOption(Pcurrentbasefunc, rShort("base"), | |||||
rOptions(sine, triangle, pulse, saw, power, gauss, | rOptions(sine, triangle, pulse, saw, power, gauss, | ||||
diode, abssine, pulsesine, stretchsine, | diode, abssine, pulsesine, stretchsine, | ||||
chirp, absstretchsine, chebyshev, sqr, | chirp, absstretchsine, chebyshev, sqr, | ||||
spike, circle), rOpt(127,use-as-base waveform), | spike, circle), rOpt(127,use-as-base waveform), | ||||
"Base Waveform for harmonics"), | "Base Waveform for harmonics"), | ||||
rParamZyn(Pbasefuncpar, | |||||
rParamZyn(Pbasefuncpar, rShort("shape"), | |||||
"Morph between possible base function shapes " | "Morph between possible base function shapes " | ||||
"(e.g. rising sawtooth vs a falling sawtooth)"), | "(e.g. rising sawtooth vs a falling sawtooth)"), | ||||
rOption(Pbasefuncmodulation, | |||||
rOption(Pbasefuncmodulation, rShort("mod"), | |||||
rOptions(None, Rev, Sine, Power, Chop), | rOptions(None, Rev, Sine, Power, Chop), | ||||
"Modulation applied to Base function spectra"), | "Modulation applied to Base function spectra"), | ||||
rParamZyn(Pbasefuncmodulationpar1, | |||||
rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), | |||||
"Base function modulation parameter"), | "Base function modulation parameter"), | ||||
rParamZyn(Pbasefuncmodulationpar2, | |||||
rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), | |||||
"Base function modulation parameter"), | "Base function modulation parameter"), | ||||
rParamZyn(Pbasefuncmodulationpar3, | |||||
rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), | |||||
"Base function modulation parameter"), | "Base function modulation parameter"), | ||||
rParamZyn(Pwaveshaping, "Degree Of Waveshaping"), | rParamZyn(Pwaveshaping, "Degree Of Waveshaping"), | ||||
rOption(Pwaveshapingfunction, | |||||
rOption(Pwaveshapingfunction, rShort("distort"), | |||||
rOptions(Undistorted, | rOptions(Undistorted, | ||||
Arctangent, Asymmetric, Pow, Sine, Quantisize, | Arctangent, Asymmetric, Pow, Sine, Quantisize, | ||||
Zigzag, Limiter, Upper Limiter, Lower Limiter, | Zigzag, Limiter, Upper Limiter, Lower Limiter, | ||||
Inverse Limiter, Clip, Asym2, Pow2, sigmoid), | Inverse Limiter, Clip, Asym2, Pow2, sigmoid), | ||||
"Shape of distortion to be applied"), | "Shape of distortion to be applied"), | ||||
rOption(Pfiltertype, rOptions(No Filter, | |||||
rOption(Pfiltertype, rShort("filter"), rOptions(No Filter, | |||||
lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2, | lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2, | ||||
cos, sin, low_shelf, s), "Harmonic Filter"), | cos, sin, low_shelf, s), "Harmonic Filter"), | ||||
rParamZyn(Pfilterpar1, "Filter parameter"), | |||||
rParamZyn(Pfilterpar2, "Filter parameter"), | |||||
rToggle(Pfilterbeforews, "Filter before waveshaping spectra;" | |||||
rParamZyn(Pfilterpar1, rShort("p1"), "Filter parameter"), | |||||
rParamZyn(Pfilterpar2, rShort("p2"), "Filter parameter"), | |||||
rToggle(Pfilterbeforews, rShort("pre/post"), "Filter before waveshaping spectra;" | |||||
"When enabled oscilfilter(freqs); then waveshape(freqs);, " | "When enabled oscilfilter(freqs); then waveshape(freqs);, " | ||||
"otherwise waveshape(freqs); then oscilfilter(freqs);"), | "otherwise waveshape(freqs); then oscilfilter(freqs);"), | ||||
rOption(Psatype, rOptions(None, Pow, ThrsD, ThrsU), | |||||
rOption(Psatype, rShort("spec. adj."), rOptions(None, Pow, ThrsD, ThrsU), | |||||
"Spectral Adjustment Type"), | "Spectral Adjustment Type"), | ||||
rParamZyn(Psapar, "Spectral Adjustment Parameter"), | |||||
rParamI(Pharmonicshift, "Amount of shift on harmonics"), | |||||
rToggle(Pharmonicshiftfirst, "If harmonics are shifted before waveshaping/filtering"), | |||||
rOption(Pmodulation, rOptions(None, Rev, Sine, Power), | |||||
rParamZyn(Psapar, rShort("p1"), "Spectral Adjustment Parameter"), | |||||
rParamI(Pharmonicshift, rShort("shift"), "Amount of shift on harmonics"), | |||||
rToggle(Pharmonicshiftfirst, rShort("pre/post"), "If harmonics are shifted before waveshaping/filtering"), | |||||
rOption(Pmodulation, rShort("FM"), rOptions(None, Rev, Sine, Power), | |||||
"Frequency Modulation To Combined Spectra"), | "Frequency Modulation To Combined Spectra"), | ||||
rParamZyn(Pmodulationpar1, "modulation parameter"), | |||||
rParamZyn(Pmodulationpar2, "modulation parameter"), | |||||
rParamZyn(Pmodulationpar3, "modulation parameter"), | |||||
rParamZyn(Pmodulationpar1, rShort("p1"), "modulation parameter"), | |||||
rParamZyn(Pmodulationpar2, rShort("p2"), "modulation parameter"), | |||||
rParamZyn(Pmodulationpar3, rShort("p3"), "modulation parameter"), | |||||
//TODO update to rArray and test | //TODO update to rArray and test | ||||
@@ -91,9 +91,20 @@ const rtosc::Ports OscilGen::non_realtime_ports = { | |||||
while(*mm && !isdigit(*mm)) ++mm; | while(*mm && !isdigit(*mm)) ++mm; | ||||
unsigned char &phase = ((OscilGen*)d.obj)->Phphase[atoi(mm)]; | unsigned char &phase = ((OscilGen*)d.obj)->Phphase[atoi(mm)]; | ||||
if(!rtosc_narguments(m)) | if(!rtosc_narguments(m)) | ||||
d.reply(d.loc, "c", phase); | |||||
else | |||||
d.reply(d.loc, "i", phase); | |||||
else { | |||||
phase = rtosc_argument(m,0).i; | phase = rtosc_argument(m,0).i; | ||||
//XXX hack hack | |||||
char *repath = strdup(d.loc); | |||||
char *edit = strrchr(repath, '/')+1; | |||||
strcpy(edit, "prepare"); | |||||
OscilGen &o = *((OscilGen*)d.obj); | |||||
fft_t *data = new fft_t[o.synth.oscilsize / 2]; | |||||
o.prepare(data); | |||||
// fprintf(stderr, "sending '%p' of fft data\n", data); | |||||
d.chain(repath, "b", sizeof(fft_t*), &data); | |||||
o.pendingfreqs = data; | |||||
} | |||||
}}, | }}, | ||||
//TODO update to rArray and test | //TODO update to rArray and test | ||||
{"magnitude#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic magnitude"), | {"magnitude#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic magnitude"), | ||||
@@ -103,13 +114,13 @@ const rtosc::Ports OscilGen::non_realtime_ports = { | |||||
while(*mm && !isdigit(*mm)) ++mm; | while(*mm && !isdigit(*mm)) ++mm; | ||||
unsigned char &mag = ((OscilGen*)d.obj)->Phmag[atoi(mm)]; | unsigned char &mag = ((OscilGen*)d.obj)->Phmag[atoi(mm)]; | ||||
if(!rtosc_narguments(m)) | if(!rtosc_narguments(m)) | ||||
d.reply(d.loc, "c", mag); | |||||
d.reply(d.loc, "i", mag); | |||||
else { | else { | ||||
mag = rtosc_argument(m,0).i; | mag = rtosc_argument(m,0).i; | ||||
//printf("setting magnitude\n\n"); | //printf("setting magnitude\n\n"); | ||||
//XXX hack hack | //XXX hack hack | ||||
char *repath = strdup(d.loc); | char *repath = strdup(d.loc); | ||||
char *edit = rindex(repath, '/')+1; | |||||
char *edit = strrchr(repath, '/')+1; | |||||
strcpy(edit, "prepare"); | strcpy(edit, "prepare"); | ||||
OscilGen &o = *((OscilGen*)d.obj); | OscilGen &o = *((OscilGen*)d.obj); | ||||
fft_t *data = new fft_t[o.synth.oscilsize / 2]; | fft_t *data = new fft_t[o.synth.oscilsize / 2]; | ||||
@@ -163,20 +174,20 @@ const rtosc::Ports OscilGen::non_realtime_ports = { | |||||
const rtosc::Ports OscilGen::realtime_ports{ | const rtosc::Ports OscilGen::realtime_ports{ | ||||
rSelf(OscilGen), | rSelf(OscilGen), | ||||
rPresetType, | rPresetType, | ||||
rParamZyn(Prand, "Oscilator Phase Randomness: smaller than 0 is \"" | |||||
rParamZyn(Prand, rShort("phase rnd"), "Oscilator Phase Randomness: smaller than 0 is \"" | |||||
"group\", larger than 0 is for each harmonic"), | "group\", larger than 0 is for each harmonic"), | ||||
rParamZyn(Pamprandpower, | |||||
rParamZyn(Pamprandpower, rShort("variance"), | |||||
"Variance of harmonic randomness"), | "Variance of harmonic randomness"), | ||||
rOption(Pamprandtype, rOptions(None, Pow, Sin), | |||||
rOption(Pamprandtype, rShort("distribution"), rOptions(None, Pow, Sin), | |||||
"Harmonic random distribution to select from"), | "Harmonic random distribution to select from"), | ||||
rOption(Padaptiveharmonics, | |||||
rOption(Padaptiveharmonics, rShort("adapt") | |||||
rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd), | rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd), | ||||
"Adaptive Harmonics Mode"), | "Adaptive Harmonics Mode"), | ||||
rParamI(Padaptiveharmonicsbasefreq, rLinear(0,255), | |||||
rParamI(Padaptiveharmonicsbasefreq, rShort("c. freq"), rLinear(0,255), | |||||
"Base frequency of adaptive harmonic (30..3000Hz)"), | "Base frequency of adaptive harmonic (30..3000Hz)"), | ||||
rParamI(Padaptiveharmonicspower,rLinear(0,200), | |||||
rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200), | |||||
"Adaptive Harmonic Strength"), | "Adaptive Harmonic Strength"), | ||||
rParamZyn(Padaptiveharmonicspar, | |||||
rParamZyn(Padaptiveharmonicspar, rShort("par"), | |||||
"Adaptive Harmonics Postprocessing Power"), | "Adaptive Harmonics Postprocessing Power"), | ||||
{"waveform:", rDoc("Returns waveform points"), | {"waveform:", rDoc("Returns waveform points"), | ||||
NULL, [](const char *, rtosc::RtData &d) { | NULL, [](const char *, rtosc::RtData &d) { | ||||
@@ -19,10 +19,12 @@ | |||||
#include "../Params/PADnoteParameters.h" | #include "../Params/PADnoteParameters.h" | ||||
#include "../Params/Controller.h" | #include "../Params/Controller.h" | ||||
#include "../Params/FilterParams.h" | #include "../Params/FilterParams.h" | ||||
#include "../Containers/ScratchString.h" | |||||
#include "../Misc/Util.h" | #include "../Misc/Util.h" | ||||
PADnote::PADnote(const PADnoteParameters *parameters, | PADnote::PADnote(const PADnoteParameters *parameters, | ||||
SynthParams pars, const int& interpolation) | |||||
SynthParams pars, const int& interpolation, WatchManager *wm, | |||||
const char *prefix) | |||||
:SynthNote(pars), pars(*parameters), interpolation(interpolation) | :SynthNote(pars), pars(*parameters), interpolation(interpolation) | ||||
{ | { | ||||
NoteGlobalPar.GlobalFilter = nullptr; | NoteGlobalPar.GlobalFilter = nullptr; | ||||
@@ -30,14 +32,16 @@ PADnote::PADnote(const PADnoteParameters *parameters, | |||||
NoteGlobalPar.FilterLfo = nullptr; | NoteGlobalPar.FilterLfo = nullptr; | ||||
firsttime = true; | firsttime = true; | ||||
setup(pars.frequency, pars.velocity, pars.portamento, pars.note); | |||||
setup(pars.frequency, pars.velocity, pars.portamento, pars.note, false, wm, prefix); | |||||
} | } | ||||
void PADnote::setup(float freq, | void PADnote::setup(float freq, | ||||
float velocity_, | float velocity_, | ||||
int portamento_, | int portamento_, | ||||
int midinote, | int midinote, | ||||
bool legato) | |||||
bool legato, | |||||
WatchManager *wm, | |||||
const char *prefix) | |||||
{ | { | ||||
portamento = portamento_; | portamento = portamento_; | ||||
velocity = velocity_; | velocity = velocity_; | ||||
@@ -129,11 +133,21 @@ void PADnote::setup(float freq, | |||||
else | else | ||||
NoteGlobalPar.Punch.Enabled = 0; | NoteGlobalPar.Punch.Enabled = 0; | ||||
NoteGlobalPar.FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, basefreq, synth.dt()); | |||||
NoteGlobalPar.FreqLfo = memory.alloc<LFO>(*pars.FreqLfo, basefreq, time); | |||||
NoteGlobalPar.AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, basefreq, synth.dt()); | |||||
NoteGlobalPar.AmpLfo = memory.alloc<LFO>(*pars.AmpLfo, basefreq, time); | |||||
ScratchString pre = prefix; | |||||
NoteGlobalPar.FreqEnvelope = | |||||
memory.alloc<Envelope>(*pars.FreqEnvelope, basefreq, synth.dt(), | |||||
wm, (pre+"FreqEnvelope/").c_str); | |||||
NoteGlobalPar.FreqLfo = | |||||
memory.alloc<LFO>(*pars.FreqLfo, basefreq, time, | |||||
wm, (pre+"FreqLfo/").c_str); | |||||
NoteGlobalPar.AmpEnvelope = | |||||
memory.alloc<Envelope>(*pars.AmpEnvelope, basefreq, synth.dt(), | |||||
wm, (pre+"AmpEnvelope/").c_str); | |||||
NoteGlobalPar.AmpLfo = | |||||
memory.alloc<LFO>(*pars.AmpLfo, basefreq, time, | |||||
wm, (pre+"AmpLfo/").c_str); | |||||
} | } | ||||
NoteGlobalPar.Volume = 4.0f | NoteGlobalPar.Volume = 4.0f | ||||
@@ -147,6 +161,7 @@ void PADnote::setup(float freq, | |||||
* NoteGlobalPar.AmpLfo->amplfoout(); | * NoteGlobalPar.AmpLfo->amplfoout(); | ||||
if(!legato) { | if(!legato) { | ||||
ScratchString pre = prefix; | |||||
auto &flt = NoteGlobalPar.GlobalFilter; | auto &flt = NoteGlobalPar.GlobalFilter; | ||||
auto &env = NoteGlobalPar.FilterEnvelope; | auto &env = NoteGlobalPar.FilterEnvelope; | ||||
auto &lfo = NoteGlobalPar.FilterLfo; | auto &lfo = NoteGlobalPar.FilterLfo; | ||||
@@ -154,8 +169,10 @@ void PADnote::setup(float freq, | |||||
flt = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, true, basefreq); | flt = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, true, basefreq); | ||||
//setup mod | //setup mod | ||||
env = memory.alloc<Envelope>(*pars.FilterEnvelope, basefreq, synth.dt()); | |||||
lfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, time); | |||||
env = memory.alloc<Envelope>(*pars.FilterEnvelope, basefreq, | |||||
synth.dt(), wm, (pre+"FilterEnvelope/").c_str); | |||||
lfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, time, | |||||
wm, (pre+"FilterLfo/").c_str); | |||||
flt->addMod(*env); | flt->addMod(*env); | ||||
flt->addMod(*lfo); | flt->addMod(*lfo); | ||||
} | } | ||||
@@ -23,7 +23,7 @@ class PADnote:public SynthNote | |||||
{ | { | ||||
public: | public: | ||||
PADnote(const PADnoteParameters *parameters, SynthParams pars, | PADnote(const PADnoteParameters *parameters, SynthParams pars, | ||||
const int &interpolation); | |||||
const int &interpolation, WatchManager *wm=0, const char *prefix=0); | |||||
~PADnote(); | ~PADnote(); | ||||
SynthNote *cloneLegato(void); | SynthNote *cloneLegato(void); | ||||
@@ -36,7 +36,7 @@ class PADnote:public SynthNote | |||||
void releasekey(); | void releasekey(); | ||||
private: | private: | ||||
void setup(float freq, float velocity, int portamento_, | void setup(float freq, float velocity, int portamento_, | ||||
int midinote, bool legato = false); | |||||
int midinote, bool legato = false, WatchManager *wm=0, const char *prefix=0); | |||||
void fadein(float *smps); | void fadein(float *smps); | ||||
void computecurrentparameters(); | void computecurrentparameters(); | ||||
bool finished_; | bool finished_; | ||||
@@ -20,17 +20,19 @@ | |||||
#include <rtosc/port-sugar.h> | #include <rtosc/port-sugar.h> | ||||
#define rObject Resonance | #define rObject Resonance | ||||
#define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj | |||||
#define rEnd } | |||||
using namespace rtosc; | using namespace rtosc; | ||||
const rtosc::Ports Resonance::ports = { | const rtosc::Ports Resonance::ports = { | ||||
rSelf(Resonance), | rSelf(Resonance), | ||||
rPaste, | rPaste, | ||||
rToggle(Penabled, "resonance enable"), | |||||
rToggle(Pprotectthefundamental, "Disable resonance filter on first harmonic"), | |||||
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"), | rParams(Prespoints, N_RES_POINTS, "Resonance data points"), | ||||
rParamZyn(PmaxdB, "how many dB the signal may be amplified"), | |||||
rParamZyn(Pcenterfreq, "Center frequency"), | |||||
rParamZyn(Poctavesfreq, "The number of octaves..."), | |||||
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..."), | |||||
rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"), | rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"), | ||||
rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"), | rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"), | ||||
rAction(smooth, "Smooth out frequency response"), | rAction(smooth, "Smooth out frequency response"), | ||||
@@ -42,7 +44,29 @@ const rtosc::Ports Resonance::ports = { | |||||
{"octavesfreq:", rDoc("Get center freq of graph"), NULL, | {"octavesfreq:", rDoc("Get center freq of graph"), NULL, | ||||
[](const char *, RtData &d) | [](const char *, RtData &d) | ||||
{d.reply(d.loc, "f", ((rObject*)d.obj)->getoctavesfreq());}}, | {d.reply(d.loc, "f", ((rObject*)d.obj)->getoctavesfreq());}}, | ||||
{"respoints", 0, 0, | |||||
rBegin; | |||||
if(rtosc_narguments(msg)) { | |||||
int i=0; | |||||
auto itr = rtosc_itr_begin(msg); | |||||
while(!rtosc_itr_end(itr) && i < N_RES_POINTS) { | |||||
auto ival = rtosc_itr_next(&itr); | |||||
if(ival.type == 'f') | |||||
o.Prespoints[i++] = ival.val.f*127; | |||||
} | |||||
} else { | |||||
rtosc_arg_t args[N_RES_POINTS]; | |||||
char types[N_RES_POINTS+1] = {0}; | |||||
for(int i=0; i<N_RES_POINTS; ++i) { | |||||
args[i].f = o.Prespoints[i]/127.0; | |||||
types[i] = 'f'; | |||||
} | |||||
d.replyArray(d.loc, types, args); | |||||
} | |||||
rEnd}, | |||||
}; | }; | ||||
#undef rBegin | |||||
#undef rEnd | |||||
Resonance::Resonance():Presets() | Resonance::Resonance():Presets() | ||||
{ | { | ||||
@@ -20,6 +20,7 @@ | |||||
#include "SUBnote.h" | #include "SUBnote.h" | ||||
#include "Envelope.h" | #include "Envelope.h" | ||||
#include "ModFilter.h" | #include "ModFilter.h" | ||||
#include "../Containers/ScratchString.h" | |||||
#include "../Params/Controller.h" | #include "../Params/Controller.h" | ||||
#include "../Params/SUBnoteParameters.h" | #include "../Params/SUBnoteParameters.h" | ||||
#include "../Params/FilterParams.h" | #include "../Params/FilterParams.h" | ||||
@@ -35,7 +36,8 @@ SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars) | |||||
GlobalFilter(nullptr), | GlobalFilter(nullptr), | ||||
GlobalFilterEnvelope(nullptr), | GlobalFilterEnvelope(nullptr), | ||||
NoteEnabled(true), | NoteEnabled(true), | ||||
lfilter(nullptr), rfilter(nullptr) | |||||
lfilter(nullptr), rfilter(nullptr), | |||||
wm(nullptr) | |||||
{ | { | ||||
setup(spars.frequency, spars.velocity, spars.portamento, spars.note); | setup(spars.frequency, spars.velocity, spars.portamento, spars.note); | ||||
} | } | ||||
@@ -46,46 +48,19 @@ float SUBnote::setupFilters(int *pos, bool automation) | |||||
float reduceamp = 0.0f; | float reduceamp = 0.0f; | ||||
for(int n = 0; n < numharmonics; ++n) { | for(int n = 0; n < numharmonics; ++n) { | ||||
float freq = basefreq * pars.POvertoneFreqMult[pos[n]]; | |||||
const float freq = basefreq * pars.POvertoneFreqMult[pos[n]]; | |||||
overtone_freq[n] = freq; | overtone_freq[n] = freq; | ||||
overtone_rolloff[n] = computerolloff(freq); | overtone_rolloff[n] = computerolloff(freq); | ||||
//the bandwidth is not absolute(Hz); it is relative to frequency | //the bandwidth is not absolute(Hz); it is relative to frequency | ||||
float bw = | |||||
powf(10, (pars.Pbandwidth - 127.0f) / 127.0f * 4) * numstages; | |||||
//Bandwidth Scale | |||||
bw *= powf(1000 / freq, (pars.Pbwscale - 64.0f) / 64.0f * 3.0f); | |||||
//Relative BandWidth | |||||
bw *= powf(100, (pars.Phrelbw[pos[n]] - 64.0f) / 64.0f); | |||||
if(bw > 25.0f) | |||||
bw = 25.0f; | |||||
const float bw = SUBnoteParameters::convertBandwidth(pars.Pbandwidth, | |||||
numstages, freq, pars.Pbwscale, pars.Phrelbw[pos[n]]); | |||||
//try to keep same amplitude on all freqs and bw. (empirically) | //try to keep same amplitude on all freqs and bw. (empirically) | ||||
float gain = sqrt(1500.0f / (bw * freq)); | |||||
float hmagnew = 1.0f - pars.Phmag[pos[n]] / 127.0f; | |||||
float hgain; | |||||
switch(pars.Phmagtype) { | |||||
case 1: | |||||
hgain = expf(hmagnew * logf(0.01f)); | |||||
break; | |||||
case 2: | |||||
hgain = expf(hmagnew * logf(0.001f)); | |||||
break; | |||||
case 3: | |||||
hgain = expf(hmagnew * logf(0.0001f)); | |||||
break; | |||||
case 4: | |||||
hgain = expf(hmagnew * logf(0.00001f)); | |||||
break; | |||||
default: | |||||
hgain = 1.0f - hmagnew; | |||||
} | |||||
gain *= hgain; | |||||
const float hgain = SUBnoteParameters::convertHarmonicMag(pars.Phmag[pos[n]], | |||||
pars.Phmagtype); | |||||
const float gain = hgain * sqrt(1500.0f / (bw * freq)); | |||||
reduceamp += hgain; | reduceamp += hgain; | ||||
for(int nph = 0; nph < numstages; ++nph) { | for(int nph = 0; nph < numstages; ++nph) { | ||||
@@ -158,14 +133,10 @@ void SUBnote::setup(float freq, | |||||
// basefreq*=ctl.pitchwheel.relfreq;//pitch wheel | // basefreq*=ctl.pitchwheel.relfreq;//pitch wheel | ||||
int pos[MAX_SUB_HARMONICS]; | int pos[MAX_SUB_HARMONICS]; | ||||
int harmonics = 0; | |||||
int harmonics; | |||||
pars.activeHarmonics(pos, harmonics); | |||||
//select only harmonics that desire to compute | |||||
for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { | |||||
if(pars.Phmag[n] == 0) | |||||
continue; | |||||
pos[harmonics++] = n; | |||||
} | |||||
if(!legato) //normal note | if(!legato) //normal note | ||||
firstnumharmonics = numharmonics = harmonics; | firstnumharmonics = numharmonics = harmonics; | ||||
else { | else { | ||||
@@ -198,9 +169,9 @@ void SUBnote::setup(float freq, | |||||
oldbandwidth = 64; | oldbandwidth = 64; | ||||
if(!legato) { //normal note | if(!legato) { //normal note | ||||
if(pars.Pfixedfreq == 0) | if(pars.Pfixedfreq == 0) | ||||
initparameters(basefreq); | |||||
initparameters(basefreq, wm); | |||||
else | else | ||||
initparameters(basefreq / 440.0f * freq); | |||||
initparameters(basefreq / 440.0f * freq, wm); | |||||
} | } | ||||
else { | else { | ||||
if(pars.Pfixedfreq == 0) | if(pars.Pfixedfreq == 0) | ||||
@@ -376,18 +347,25 @@ void SUBnote::filter(bpfilter &filter, float *smps) | |||||
/* | /* | ||||
* Init Parameters | * Init Parameters | ||||
*/ | */ | ||||
void SUBnote::initparameters(float freq) | |||||
void SUBnote::initparameters(float freq, WatchManager *wm) | |||||
{ | { | ||||
AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, freq, synth.dt()); | |||||
//TODO populate this base string | |||||
ScratchString pre; | |||||
AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, freq, | |||||
synth.dt(), wm, (pre+"AmpEnvelope/").c_str); | |||||
if(pars.PFreqEnvelopeEnabled) | if(pars.PFreqEnvelopeEnabled) | ||||
FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, freq, synth.dt()); | |||||
FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, freq, | |||||
synth.dt(), wm, (pre+"FreqEnvelope/").c_str); | |||||
if(pars.PBandWidthEnvelopeEnabled) | if(pars.PBandWidthEnvelopeEnabled) | ||||
BandWidthEnvelope = memory.alloc<Envelope>(*pars.BandWidthEnvelope, freq, synth.dt()); | |||||
BandWidthEnvelope = memory.alloc<Envelope>(*pars.BandWidthEnvelope, | |||||
freq, synth.dt(), wm, (pre+"BandWidthEnvelope/").c_str); | |||||
if(pars.PGlobalFilterEnabled) { | if(pars.PGlobalFilterEnabled) { | ||||
GlobalFilterEnvelope = memory.alloc<Envelope>(*pars.GlobalFilterEnvelope, freq, synth.dt()); | |||||
GlobalFilterEnvelope = | |||||
memory.alloc<Envelope>(*pars.GlobalFilterEnvelope, freq, | |||||
synth.dt(), wm, (pre+"GlobalFilterEnvelope/").c_str); | |||||
GlobalFilter = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, stereo, freq); | GlobalFilter = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, stereo, freq); | ||||
@@ -429,14 +407,9 @@ void SUBnote::computecurrentparameters() | |||||
//A little bit of copy/paste for now | //A little bit of copy/paste for now | ||||
int pos[MAX_SUB_HARMONICS]; | int pos[MAX_SUB_HARMONICS]; | ||||
int harmonics = 0; | |||||
int harmonics; | |||||
//select only harmonics that desire to compute | |||||
for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { | |||||
if(pars.Phmag[n] == 0) | |||||
continue; | |||||
pos[harmonics++] = n; | |||||
} | |||||
pars.activeHarmonics(pos, harmonics); | |||||
bool delta_harmonics = (harmonics != numharmonics); | bool delta_harmonics = (harmonics != numharmonics); | ||||
if(delta_harmonics) { | if(delta_harmonics) { | ||||
@@ -43,7 +43,7 @@ class SUBnote:public SynthNote | |||||
* Initialize envelopes and global filter | * Initialize envelopes and global filter | ||||
* calls computercurrentparameters() | * calls computercurrentparameters() | ||||
*/ | */ | ||||
void initparameters(float freq); | |||||
void initparameters(float freq, WatchManager *wm); | |||||
void KillNote(); | void KillNote(); | ||||
const SUBnoteParameters &pars; | const SUBnoteParameters &pars; | ||||
@@ -101,6 +101,7 @@ class SUBnote:public SynthNote | |||||
int oldpitchwheel, oldbandwidth; | int oldpitchwheel, oldbandwidth; | ||||
float globalfiltercenterq; | float globalfiltercenterq; | ||||
float velocity; | float velocity; | ||||
WatchManager *wm; | |||||
}; | }; | ||||
#endif | #endif |
@@ -108,6 +108,7 @@ class SynthNote | |||||
const Controller &ctl; | const Controller &ctl; | ||||
const SYNTH_T &synth; | const SYNTH_T &synth; | ||||
const AbsTime &time; | const AbsTime &time; | ||||
WatchManager *wm; | |||||
}; | }; | ||||
#endif | #endif |
@@ -0,0 +1,163 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
WatchPoint.cpp - Synthesis State Watcher | |||||
Copyright (C) 2015-2015 Mark McCurry | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of version 2 of the GNU General Public License | |||||
as published by the Free Software Foundation. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License (version 2 or later) for more details. | |||||
You should have received a copy of the GNU General Public License (version 2) | |||||
along with this program; if not, write to the Free Software Foundation, | |||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
*/ | |||||
#include "WatchPoint.h" | |||||
#include <cstring> | |||||
#include <rtosc/thread-link.h> | |||||
WatchPoint::WatchPoint(WatchManager *ref, const char *prefix, const char *id) | |||||
:active(false), samples_left(0), reference(ref) | |||||
{ | |||||
identity[0] = 0; | |||||
if(prefix) | |||||
strncpy(identity, prefix, 128); | |||||
if(id) | |||||
strncat(identity, id, 128); | |||||
} | |||||
bool WatchPoint::is_active(void) | |||||
{ | |||||
//Either the watchpoint is already active or the watchpoint manager has | |||||
//received another activation this frame | |||||
if(active) | |||||
return true; | |||||
if(reference && reference->active(identity)) { | |||||
active = true; | |||||
samples_left = 1; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
FloatWatchPoint::FloatWatchPoint(WatchManager *ref, const char *prefix, const char *id) | |||||
:WatchPoint(ref, prefix, id) | |||||
{} | |||||
VecWatchPoint::VecWatchPoint(WatchManager *ref, const char *prefix, const char *id) | |||||
:WatchPoint(ref, prefix, id) | |||||
{} | |||||
WatchManager::WatchManager(thrlnk *link) | |||||
:write_back(link), new_active(false) | |||||
{ | |||||
memset(active_list, 0, sizeof(active_list)); | |||||
memset(sample_list, 0, sizeof(sample_list)); | |||||
memset(data_list, 0, sizeof(data_list)); | |||||
memset(deactivate, 0, sizeof(deactivate)); | |||||
} | |||||
void WatchManager::add_watch(const char *id) | |||||
{ | |||||
//Apply to a free slot | |||||
for(int i=0; i<MAX_WATCH; ++i) { | |||||
if(!active_list[i][0]) { | |||||
strncpy(active_list[i], id, 128); | |||||
new_active = true; | |||||
sample_list[i] = 0; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
void WatchManager::del_watch(const char *id) | |||||
{ | |||||
//Queue up the delete | |||||
for(int i=0; i<MAX_WATCH; ++i) | |||||
if(!strcmp(active_list[i], id)) | |||||
return (void) (deactivate[i] = true); | |||||
} | |||||
void WatchManager::tick(void) | |||||
{ | |||||
//Try to send out any vector stuff | |||||
for(int i=0; i<MAX_WATCH; ++i) { | |||||
if(sample_list[i]) { | |||||
char arg_types[MAX_SAMPLE+1] = {0}; | |||||
rtosc_arg_t arg_val[MAX_SAMPLE]; | |||||
for(int j=0; j<sample_list[i]; ++j) { | |||||
arg_types[j] = 'f'; | |||||
arg_val[j].f = data_list[i][j]; | |||||
} | |||||
write_back->writeArray(active_list[i], arg_types, arg_val); | |||||
deactivate[i] = true; | |||||
} | |||||
} | |||||
//Cleanup internal data | |||||
new_active = false; | |||||
//Clear deleted slots | |||||
for(int i=0; i<MAX_WATCH; ++i) { | |||||
if(deactivate[i]) { | |||||
memset(active_list[i], 0, 128); | |||||
sample_list[i] = 0; | |||||
deactivate[i] = false; | |||||
} | |||||
} | |||||
} | |||||
bool WatchManager::active(const char *id) const | |||||
{ | |||||
assert(this); | |||||
assert(id); | |||||
if(new_active || true) | |||||
for(int i=0; i<MAX_WATCH; ++i) | |||||
if(!strcmp(active_list[i], id)) | |||||
return true; | |||||
return false; | |||||
} | |||||
int WatchManager::samples(const char *id) const | |||||
{ | |||||
for(int i=0; i<MAX_WATCH; ++i) | |||||
if(!strcmp(active_list[i], id)) | |||||
return sample_list[i]; | |||||
return 0; | |||||
} | |||||
void WatchManager::satisfy(const char *id, float f) | |||||
{ | |||||
//printf("trying to satisfy '%s'\n", id); | |||||
if(write_back) | |||||
write_back->write(id, "f", f); | |||||
del_watch(id); | |||||
} | |||||
void WatchManager::satisfy(const char *id, float *f, int n) | |||||
{ | |||||
int selected = -1; | |||||
for(int i=0; i<MAX_WATCH; ++i) | |||||
if(!strcmp(active_list[i], id)) | |||||
selected = i; | |||||
if(selected == -1) | |||||
return; | |||||
//FIXME buffer overflow | |||||
for(int i=0; i<n; ++i) | |||||
data_list[selected][sample_list[selected]++] = f[i]; | |||||
} |
@@ -0,0 +1,81 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
WatchPoint.h - Synthesis State Watcher | |||||
Copyright (C) 2015-2015 Mark McCurry | |||||
Author: Mark McCurry | |||||
This program is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU General Public License | |||||
as published by the Free Software Foundation; either version 2 | |||||
of the License, or (at your option) any later version. | |||||
*/ | |||||
#pragma once | |||||
struct WatchManager; | |||||
namespace rtosc {class ThreadLink;} | |||||
struct WatchPoint | |||||
{ | |||||
bool active; | |||||
int samples_left; | |||||
WatchManager *reference; | |||||
char identity[128]; | |||||
WatchPoint(WatchManager *ref, const char *prefix, const char *id); | |||||
bool is_active(void); | |||||
}; | |||||
#define MAX_WATCH 16 | |||||
#define MAX_WATCH_PATH 128 | |||||
#define MAX_SAMPLE 128 | |||||
struct WatchManager | |||||
{ | |||||
typedef rtosc::ThreadLink thrlnk; | |||||
thrlnk *write_back; | |||||
bool new_active; | |||||
char active_list[MAX_WATCH][MAX_WATCH_PATH]; | |||||
float data_list[MAX_SAMPLE][MAX_WATCH]; | |||||
int sample_list[MAX_WATCH]; | |||||
bool deactivate[MAX_WATCH]; | |||||
//External API | |||||
WatchManager(thrlnk *link=0); | |||||
void add_watch(const char *); | |||||
void del_watch(const char *); | |||||
void tick(void); | |||||
//Watch Point Query API | |||||
bool active(const char *) const; | |||||
int samples(const char *) const; | |||||
//Watch Point Response API | |||||
void satisfy(const char *, float); | |||||
void satisfy(const char *, float*, int); | |||||
}; | |||||
struct FloatWatchPoint:public WatchPoint | |||||
{ | |||||
FloatWatchPoint(WatchManager *ref, const char *prefix, const char *id); | |||||
inline void operator()(float f) | |||||
{ | |||||
if(is_active() && reference) { | |||||
reference->satisfy(identity, f); | |||||
active = false; | |||||
} | |||||
} | |||||
}; | |||||
//basically the same as the float watch point, only it consumes tuples | |||||
struct VecWatchPoint : public WatchPoint | |||||
{ | |||||
VecWatchPoint(WatchManager *ref, const char *prefix, const char *id); | |||||
inline void operator()(float *f, int n) | |||||
{ | |||||
if(is_active() && reference) { | |||||
reference->satisfy(identity, f, n); | |||||
active = false; | |||||
} | |||||
} | |||||
}; |
@@ -407,7 +407,7 @@ class UI_Interface:public Fl_Osc_Interface | |||||
virtual void damage(const char *path) override | virtual void damage(const char *path) override | ||||
{ | { | ||||
#ifndef NO_UI | #ifndef NO_UI | ||||
printf("\n\nDamage(\"%s\")\n", path); | |||||
//printf("\n\nDamage(\"%s\")\n", path); | |||||
std::set<Fl_Osc_Widget*> to_update; | std::set<Fl_Osc_Widget*> to_update; | ||||
for(auto pair:map) { | for(auto pair:map) { | ||||
if(strstr(pair.first.c_str(), path)) { | if(strstr(pair.first.c_str(), path)) { | ||||
@@ -428,7 +428,7 @@ class UI_Interface:public Fl_Osc_Interface | |||||
//DEBUG | //DEBUG | ||||
//if(strcmp(msg, "/vu-meter"))//Ignore repeated message | //if(strcmp(msg, "/vu-meter"))//Ignore repeated message | ||||
// printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); | // printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); | ||||
const char *handle = rindex(msg,'/'); | |||||
const char *handle = strrchr(msg,'/'); | |||||
if(handle) | if(handle) | ||||
++handle; | ++handle; | ||||
@@ -312,6 +312,11 @@ if (filename==NULL) return; | |||||
osc->write("/load_xlz", "s", filename);} | osc->write("/load_xlz", "s", filename);} | ||||
xywh {40 40 100 20} | xywh {40 40 100 20} | ||||
} | } | ||||
MenuItem {} { | |||||
label {Clear Midi Learn...} | |||||
callback {osc->write("/clear_xlz", "");} | |||||
xywh {40 40 100 20} | |||||
} | |||||
MenuItem {} { | MenuItem {} { | ||||
label {Save Midi Learn...} | label {Save Midi Learn...} | ||||
callback {char *filename; | callback {char *filename; | ||||
@@ -1485,7 +1490,7 @@ selectuiwindow->hide();} | |||||
xywh {10 165 100 35} color 229 labelfont 1 labelsize 16 | xywh {10 165 100 35} color 229 labelfont 1 labelsize 16 | ||||
} | } | ||||
Fl_Box {} { | Fl_Box {} { | ||||
label {.. if you have used ZynAddSubFX before, or you like to have full controll to all parameters.} | |||||
label {.. if you have used ZynAddSubFX before, or you like to have full control to all parameters.} | |||||
xywh {110 165 310 35} labelfont 1 labelsize 11 align 144 | xywh {110 165 310 35} labelfont 1 labelsize 11 align 144 | ||||
} | } | ||||
Fl_Button {} { | Fl_Button {} { | ||||
@@ -470,7 +470,7 @@ class UI_Interface:public Fl_Osc_Interface | |||||
//DEBUG | //DEBUG | ||||
//if(strcmp(msg, "/vu-meter"))//Ignore repeated message | //if(strcmp(msg, "/vu-meter"))//Ignore repeated message | ||||
// printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); | // printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); | ||||
const char *handle = rindex(msg,'/'); | |||||
const char *handle = strrchr(msg,'/'); | |||||
if(handle) | if(handle) | ||||
++handle; | ++handle; | ||||
@@ -572,9 +572,11 @@ const char *help_message = | |||||
"zynaddsubfx-ext-gui [options] uri - Connect to remote ZynAddSubFX\n" | "zynaddsubfx-ext-gui [options] uri - Connect to remote ZynAddSubFX\n" | ||||
" --help print this help message\n" | " --help print this help message\n" | ||||
" --no-uri run without a remote ZynAddSubFX\n" | " --no-uri run without a remote ZynAddSubFX\n" | ||||
" --embed window ID [Internal Flag For Embedding Windows]\n" | |||||
"\n" | "\n" | ||||
" example: zynaddsubfx-ext-gui osc.udp://localhost:1234/\n" | " example: zynaddsubfx-ext-gui osc.udp://localhost:1234/\n" | ||||
" use the -P option for zynaddsubfx to specify the port of the backend\n"; | |||||
" This will connect to a running zynaddsubfx instance on the same\n" | |||||
" machine on port 1234.\n"; | |||||
#ifndef CARLA_VERSION_STRING | #ifndef CARLA_VERSION_STRING | ||||
int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||
@@ -45,6 +45,7 @@ class EnvelopeParams; | |||||
class LFOParams; | class LFOParams; | ||||
class FilterParams; | class FilterParams; | ||||
struct WatchManager; | |||||
class LFO; | class LFO; | ||||
class Envelope; | class Envelope; | ||||
class OscilGen; | class OscilGen; | ||||
@@ -3,7 +3,7 @@ | |||||
main.cpp - Main file of the synthesizer | main.cpp - Main file of the synthesizer | ||||
Copyright (C) 2002-2005 Nasca Octavian Paul | Copyright (C) 2002-2005 Nasca Octavian Paul | ||||
Copyright (C) 2012-2014 Mark McCurry | |||||
Copyright (C) 2012-2016 Mark McCurry | |||||
This program is free software; you can redistribute it and/or | This program is free software; you can redistribute it and/or | ||||
modify it under the terms of the GNU General Public License | modify it under the terms of the GNU General Public License | ||||
@@ -35,6 +35,7 @@ | |||||
#include "Misc/Master.h" | #include "Misc/Master.h" | ||||
#include "Misc/Part.h" | #include "Misc/Part.h" | ||||
#include "Misc/Util.h" | #include "Misc/Util.h" | ||||
#include "version.h" | |||||
//Nio System | //Nio System | ||||
#include "Nio/Nio.h" | #include "Nio/Nio.h" | ||||
@@ -364,7 +365,7 @@ int main(int argc, char *argv[]) | |||||
synth.alias(); | synth.alias(); | ||||
if(exitwithversion) { | if(exitwithversion) { | ||||
cout << "Version: " << VERSION << endl; | |||||
cout << "Version: " << version << endl; | |||||
return 0; | return 0; | ||||
} | } | ||||
if(exitwithhelp != 0) { | if(exitwithhelp != 0) { | ||||
@@ -382,7 +383,7 @@ int main(int argc, char *argv[]) | |||||
" -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n" | " -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" | << " -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-connect\t\t\t AutoConnect when using JACK\n" | ||||
<< " -A , --auto-save=INTERVAL\t\t Automatically save at interval (disabled for negative intervals)\n" | |||||
<< " -A , --auto-save=INTERVAL\t\t Automatically save at interval (disabled with 0 interval)\n" | |||||
<< " -p , --pid-in-client-name\t\t Append PID to (JACK) " | << " -p , --pid-in-client-name\t\t Append PID to (JACK) " | ||||
"client name\n" | "client name\n" | ||||
<< " -P , --preferred-port\t\t\t Preferred OSC Port\n" | << " -P , --preferred-port\t\t\t Preferred OSC Port\n" | ||||
@@ -489,7 +490,7 @@ int main(int argc, char *argv[]) | |||||
"Default IO did not initialize.\nDefaulting to NULL backend."); | "Default IO did not initialize.\nDefaulting to NULL backend."); | ||||
} | } | ||||
if(auto_save_interval >= 0) { | |||||
if(auto_save_interval > 0) { | |||||
int old_save = middleware->checkAutoSave(); | int old_save = middleware->checkAutoSave(); | ||||
if(old_save > 0) | if(old_save > 0) | ||||
GUI::raiseUi(gui, "/alert-reload", "i", old_save); | GUI::raiseUi(gui, "/alert-reload", "i", old_save); | ||||
@@ -342,6 +342,16 @@ void MidiMappernRT::delMapping(int ID, bool coarse, const char *addr){ | |||||
}; | }; | ||||
void MidiMappernRT::replaceMapping(int, bool, const char *){}; | void MidiMappernRT::replaceMapping(int, bool, const char *){}; | ||||
void MidiMappernRT::clear(void) | |||||
{ | |||||
storage = new MidiMapperStorage(); | |||||
learnQueue.clear(); | |||||
inv_map.clear(); | |||||
char buf[1024]; | |||||
rtosc_message(buf, 1024, "/midi-learn/midi-bind", "b", sizeof(storage), &storage); | |||||
rt_cb(buf); | |||||
} | |||||
std::map<std::string, std::string> MidiMappernRT::getMidiMappingStrings(void) | std::map<std::string, std::string> MidiMappernRT::getMidiMappingStrings(void) | ||||
@@ -16,6 +16,10 @@ class UndoHistoryImpl | |||||
UndoHistoryImpl(void) | UndoHistoryImpl(void) | ||||
:max_history_size(20) | :max_history_size(20) | ||||
{} | {} | ||||
~UndoHistoryImpl(void) | |||||
{ | |||||
clear(); | |||||
} | |||||
std::deque<pair<time_t, const char *>> history; | std::deque<pair<time_t, const char *>> history; | ||||
long history_pos; | long history_pos; | ||||
unsigned max_history_size;//XXX Expose this via a public API | unsigned max_history_size;//XXX Expose this via a public API | ||||
@@ -24,6 +28,7 @@ class UndoHistoryImpl | |||||
void rewind(const char *msg); | void rewind(const char *msg); | ||||
void replay(const char *msg); | void replay(const char *msg); | ||||
bool mergeEvent(time_t t, const char *msg, char *buf, size_t N); | bool mergeEvent(time_t t, const char *msg, char *buf, size_t N); | ||||
void clear(void); | |||||
}; | }; | ||||
UndoHistory::UndoHistory(void) | UndoHistory::UndoHistory(void) | ||||
@@ -32,6 +37,11 @@ UndoHistory::UndoHistory(void) | |||||
impl->history_pos = 0; | impl->history_pos = 0; | ||||
} | } | ||||
UndoHistory::~UndoHistory(void) | |||||
{ | |||||
delete impl; | |||||
} | |||||
void UndoHistory::recordEvent(const char *msg) | void UndoHistory::recordEvent(const char *msg) | ||||
{ | { | ||||
//TODO Properly account for when you have traveled back in time. | //TODO Properly account for when you have traveled back in time. | ||||
@@ -121,6 +131,14 @@ bool UndoHistoryImpl::mergeEvent(time_t now, const char *msg, char *buf, size_t | |||||
return false; | return false; | ||||
} | } | ||||
void UndoHistoryImpl::clear(void) | |||||
{ | |||||
for(auto elm : history) | |||||
delete [] elm.second; | |||||
history.clear(); | |||||
history_pos = 0; | |||||
} | |||||
void UndoHistory::seekHistory(int distance) | void UndoHistory::seekHistory(int distance) | ||||
@@ -200,8 +200,8 @@ static bool is_charwise(uint8_t c) | |||||
int rtosc_subpath_pat_type(const char *pattern) | int rtosc_subpath_pat_type(const char *pattern) | ||||
{ | { | ||||
int charwise_only = 1; | int charwise_only = 1; | ||||
const char *last_star = rindex(pattern, '*'); | |||||
const char *pound = index(pattern, '#'); | |||||
const char *last_star = strrchr(pattern, '*'); | |||||
const char *pound = strchr(pattern, '#'); | |||||
if(!strcmp("*", pattern)) | if(!strcmp("*", pattern)) | ||||
return RTOSC_MATCH_ALL; | return RTOSC_MATCH_ALL; | ||||
@@ -115,6 +115,8 @@ class MidiMappernRT | |||||
void delMapping(int ID, bool coarse, const char *addr); | void delMapping(int ID, bool coarse, const char *addr); | ||||
void replaceMapping(int, bool, const char *); | void replaceMapping(int, bool, const char *); | ||||
void clear(void); | |||||
std::map<std::string, std::string> getMidiMappingStrings(void); | std::map<std::string, std::string> getMidiMappingStrings(void); | ||||
//unclear if this should be be here as a helper or not | //unclear if this should be be here as a helper or not | ||||
@@ -144,7 +144,7 @@ struct rtosc_hack_decltype_t | |||||
#define rArrayF(name, length, ...) \ | #define rArrayF(name, length, ...) \ | ||||
{STRINGIFY(name) "#" STRINGIFY(length) "::f", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayFCb(name)} | {STRINGIFY(name) "#" STRINGIFY(length) "::f", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayFCb(name)} | ||||
#define rArray(name, length, ...) \ | #define rArray(name, length, ...) \ | ||||
{STRINGIFY(name) "#" STRINGIFY(length) "::c", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayCb(name)} | |||||
{STRINGIFY(name) "#" STRINGIFY(length) "::c:i", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayCb(name)} | |||||
#define rArrayT(name, length, ...) \ | #define rArrayT(name, length, ...) \ | ||||
{STRINGIFY(name) "#" STRINGIFY(length) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayTCb(name)} | {STRINGIFY(name) "#" STRINGIFY(length) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayTCb(name)} | ||||
#define rArrayI(name, length, ...) \ | #define rArrayI(name, length, ...) \ | ||||
@@ -54,12 +54,18 @@ struct RtData | |||||
const Port *port; | const Port *port; | ||||
const char *message; | const char *message; | ||||
virtual void replyArray(const char *path, const char *args, | |||||
rtosc_arg_t *vals){}; | |||||
virtual void reply(const char *path, const char *args, ...); | virtual void reply(const char *path, const char *args, ...); | ||||
virtual void reply(const char *msg); | virtual void reply(const char *msg); | ||||
virtual void chain(const char *path, const char *args, ...){}; | virtual void chain(const char *path, const char *args, ...){}; | ||||
virtual void chain(const char *msg){}; | virtual void chain(const char *msg){}; | ||||
virtual void chainArray(const char *path, const char *args, | |||||
rtosc_arg_t *vals){}; | |||||
virtual void broadcast(const char *path, const char *args, ...); | virtual void broadcast(const char *path, const char *args, ...); | ||||
virtual void broadcast(const char *msg); | virtual void broadcast(const char *msg); | ||||
virtual void broadcastArray(const char *path, const char *args, | |||||
rtosc_arg_t *vals){}; | |||||
virtual void forward(const char *rational=NULL); | virtual void forward(const char *rational=NULL); | ||||
}; | }; | ||||
@@ -13,6 +13,7 @@ class UndoHistory | |||||
//TODO think about the consequences of largish loads | //TODO think about the consequences of largish loads | ||||
public: | public: | ||||
UndoHistory(void); | UndoHistory(void); | ||||
~UndoHistory(void); | |||||
//Records any undoable event | //Records any undoable event | ||||
void recordEvent(const char *msg); | void recordEvent(const char *msg); | ||||
@@ -0,0 +1,46 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
version.cpp - implementation of version_type class | |||||
Copyright (C) 2016 Johannes Lorenz | |||||
Author: Johannes Lorenz | |||||
This program is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU General Public License | |||||
as published by the Free Software Foundation; either version 2 | |||||
of the License, or (at your option) any later version. | |||||
*/ | |||||
#include <iostream> | |||||
#include "version.h" | |||||
constexpr int version_type::v_strcmp(const version_type& v2, int i) const | |||||
{ | |||||
return (i == sizeof(version)) | |||||
? 0 | |||||
: ((version[i] == v2.version[i]) | |||||
? v_strcmp(v2, i+1) | |||||
: (version[i] - v2.version[i])); | |||||
} | |||||
constexpr bool version_type::operator<(const version_type& other) const | |||||
{ | |||||
return v_strcmp(other, 0) < 0; | |||||
} | |||||
std::ostream& operator<< (std::ostream& os, | |||||
const version_type& v) | |||||
{ | |||||
return os << v.major() << '.' | |||||
<< v.minor() << '.' | |||||
<< v.revision(); | |||||
} | |||||
static_assert(!(version_type(3,1,1) < version_type(1,3,3)), | |||||
"version operator failed"); | |||||
static_assert(version_type(2,9,9) < version_type(3,4,3), | |||||
"version operator failed"); | |||||
static_assert(!(version_type(2,4,3) < version_type(2,4,3)), | |||||
"version operator failed"); | |||||
@@ -0,0 +1,59 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
version.h - declaration of version_type class | |||||
contains the current zynaddsubfx version | |||||
Copyright (C) 2016 Johannes Lorenz | |||||
Author: Johannes Lorenz | |||||
This program is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU General Public License | |||||
as published by the Free Software Foundation; either version 2 | |||||
of the License, or (at your option) any later version. | |||||
*/ | |||||
#ifndef VERSION_H | |||||
#define VERSION_H | |||||
#include <iosfwd> | |||||
//! class containing a zynaddsubfx version | |||||
class version_type | |||||
{ | |||||
char version[3]; | |||||
// strcmp-like comparison against another version_type | |||||
constexpr int v_strcmp(const version_type& v2, int i) const; | |||||
public: | |||||
constexpr version_type(char maj, char min, char rev) : | |||||
version{maj, min, rev} | |||||
{ | |||||
} | |||||
//! constructs the current zynaddsubfx version | |||||
constexpr version_type() : | |||||
version_type(2, 5, 4) | |||||
{ | |||||
} | |||||
void set_major(int maj) { version[0] = maj; } | |||||
void set_minor(int min) { version[1] = min; } | |||||
void set_revision(int rev) { version[2] = rev; } | |||||
int major() const { return version[0]; } | |||||
int minor() const { return version[1]; } | |||||
int revision() const { return version[2]; } | |||||
constexpr bool operator<(const version_type& other) const; | |||||
//! prints version as <major>.<minor>.<revision> | |||||
friend std::ostream& operator<< (std::ostream& os, | |||||
const version_type& v); | |||||
}; | |||||
//! the current zynaddsubfx version | |||||
constexpr version_type version; | |||||
#endif | |||||