Browse Source

Update zynaddsubfx

tags/1.9.7
falkTX 8 years ago
parent
commit
ef61a07c35
78 changed files with 2252 additions and 545 deletions
  1. +81
    -3
      source/native-plugins/zynaddsubfx-src.cpp
  2. +5
    -0
      source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp
  3. +1
    -0
      source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h
  4. +39
    -0
      source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp
  5. +17
    -0
      source/native-plugins/zynaddsubfx/Containers/ScratchString.h
  6. +41
    -35
      source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp
  7. +3
    -0
      source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h
  8. +26
    -0
      source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp
  9. +1
    -0
      source/native-plugins/zynaddsubfx/Effects/Alienwah.h
  10. +27
    -0
      source/native-plugins/zynaddsubfx/Effects/Chorus.cpp
  11. +1
    -0
      source/native-plugins/zynaddsubfx/Effects/Chorus.h
  12. +27
    -0
      source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp
  13. +1
    -0
      source/native-plugins/zynaddsubfx/Effects/Distorsion.h
  14. +49
    -0
      source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp
  15. +1
    -0
      source/native-plugins/zynaddsubfx/Effects/DynamicFilter.h
  16. +23
    -0
      source/native-plugins/zynaddsubfx/Effects/Echo.cpp
  17. +2
    -0
      source/native-plugins/zynaddsubfx/Effects/Echo.h
  18. +21
    -0
      source/native-plugins/zynaddsubfx/Effects/Effect.h
  19. +15
    -3
      source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp
  20. +32
    -0
      source/native-plugins/zynaddsubfx/Effects/Phaser.cpp
  21. +1
    -0
      source/native-plugins/zynaddsubfx/Effects/Phaser.h
  22. +19
    -2
      source/native-plugins/zynaddsubfx/Misc/Bank.cpp
  23. +4
    -1
      source/native-plugins/zynaddsubfx/Misc/Bank.h
  24. +219
    -0
      source/native-plugins/zynaddsubfx/Misc/BankDb.cpp
  25. +50
    -0
      source/native-plugins/zynaddsubfx/Misc/BankDb.h
  26. +80
    -10
      source/native-plugins/zynaddsubfx/Misc/Master.cpp
  27. +8
    -0
      source/native-plugins/zynaddsubfx/Misc/Master.h
  28. +140
    -16
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
  29. +18
    -5
      source/native-plugins/zynaddsubfx/Misc/Part.cpp
  30. +3
    -1
      source/native-plugins/zynaddsubfx/Misc/Part.h
  31. +41
    -8
      source/native-plugins/zynaddsubfx/Misc/Schema.cpp
  32. +8
    -13
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp
  33. +2
    -6
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h
  34. +15
    -3
      source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp
  35. +1
    -0
      source/native-plugins/zynaddsubfx/Nio/AlsaEngine.h
  36. +59
    -0
      source/native-plugins/zynaddsubfx/Nio/Compressor.h
  37. +4
    -0
      source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp
  38. +7
    -14
      source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp
  39. +4
    -0
      source/native-plugins/zynaddsubfx/Nio/OssEngine.h
  40. +13
    -22
      source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp
  41. +3
    -0
      source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h
  42. +71
    -62
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp
  43. +21
    -21
      source/native-plugins/zynaddsubfx/Params/Controller.cpp
  44. +78
    -50
      source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp
  45. +95
    -18
      source/native-plugins/zynaddsubfx/Params/FilterParams.cpp
  46. +17
    -2
      source/native-plugins/zynaddsubfx/Params/LFOParams.cpp
  47. +41
    -24
      source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp
  48. +161
    -66
      source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp
  49. +10
    -1
      source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h
  50. +44
    -19
      source/native-plugins/zynaddsubfx/Synth/ADnote.cpp
  51. +6
    -3
      source/native-plugins/zynaddsubfx/Synth/ADnote.h
  52. +33
    -10
      source/native-plugins/zynaddsubfx/Synth/Envelope.cpp
  53. +11
    -7
      source/native-plugins/zynaddsubfx/Synth/Envelope.h
  54. +8
    -2
      source/native-plugins/zynaddsubfx/Synth/LFO.cpp
  55. +5
    -1
      source/native-plugins/zynaddsubfx/Synth/LFO.h
  56. +42
    -31
      source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp
  57. +27
    -10
      source/native-plugins/zynaddsubfx/Synth/PADnote.cpp
  58. +2
    -2
      source/native-plugins/zynaddsubfx/Synth/PADnote.h
  59. +29
    -5
      source/native-plugins/zynaddsubfx/Synth/Resonance.cpp
  60. +29
    -56
      source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp
  61. +2
    -1
      source/native-plugins/zynaddsubfx/Synth/SUBnote.h
  62. +1
    -0
      source/native-plugins/zynaddsubfx/Synth/SynthNote.h
  63. +163
    -0
      source/native-plugins/zynaddsubfx/Synth/WatchPoint.cpp
  64. +81
    -0
      source/native-plugins/zynaddsubfx/Synth/WatchPoint.h
  65. +2
    -2
      source/native-plugins/zynaddsubfx/UI/Connection.cpp
  66. +6
    -1
      source/native-plugins/zynaddsubfx/UI/MasterUI.fl
  67. +4
    -2
      source/native-plugins/zynaddsubfx/UI/guimain.cpp
  68. +1
    -0
      source/native-plugins/zynaddsubfx/globals.h
  69. +5
    -4
      source/native-plugins/zynaddsubfx/main.cpp
  70. +10
    -0
      source/native-plugins/zynaddsubfx/rtosc/cpp/midimapper.cpp
  71. +18
    -0
      source/native-plugins/zynaddsubfx/rtosc/cpp/undo-history.cpp
  72. +2
    -2
      source/native-plugins/zynaddsubfx/rtosc/dispatch.c
  73. +2
    -0
      source/native-plugins/zynaddsubfx/rtosc/miditable.h
  74. +1
    -1
      source/native-plugins/zynaddsubfx/rtosc/port-sugar.h
  75. +6
    -0
      source/native-plugins/zynaddsubfx/rtosc/ports.h
  76. +1
    -0
      source/native-plugins/zynaddsubfx/rtosc/undo-history.h
  77. +46
    -0
      source/native-plugins/zynaddsubfx/version.cpp
  78. +59
    -0
      source/native-plugins/zynaddsubfx/version.h

+ 81
- 3
source/native-plugins/zynaddsubfx-src.cpp View File

@@ -67,7 +67,10 @@ extern "C" {
#include "zynaddsubfx/rtosc/cpp/undo-history.cpp"

// zynaddsubfx includes
#include "zynaddsubfx/version.cpp"

#include "zynaddsubfx/Containers/MultiPseudoStack.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -75,6 +78,15 @@ extern "C" {
#define rChangeCb

#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 rStdString
#undef rStdStringCb
@@ -82,6 +94,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/AnalogFilter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -89,6 +102,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/FFTwrapper.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -96,6 +110,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/Filter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -103,6 +118,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/FormantFilter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -110,6 +126,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/SVFilter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -117,6 +134,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/DSP/Unison.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -124,6 +142,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/Alienwah.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -131,6 +150,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/Chorus.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -138,6 +158,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/Distorsion.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -145,6 +166,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/DynamicFilter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -153,6 +175,7 @@ extern "C" {

#include "zynaddsubfx/Effects/Echo.cpp"
#undef MAX_DELAY
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -160,6 +183,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/Effect.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -167,6 +191,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/EffectLFO.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -174,6 +199,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/EffectMgr.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -181,6 +207,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/EQ.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -188,16 +215,18 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Effects/Phaser.cpp"
#undef PHASER_LFO_SHAPE
#undef ONE_
#undef ZERO_
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
#undef rChangeCb
#define rChangeCb
#undef PHASER_LFO_SHAPE
#undef ONE_
#undef ZERO_

#include "zynaddsubfx/Effects/Reverb.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -205,6 +234,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/Allocator.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -214,6 +244,15 @@ extern "C" {
#include "zynaddsubfx/Misc/Bank.cpp"
#undef INSTRUMENT_EXTENSION
#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 rStdString
#undef rStdStringCb
@@ -221,6 +260,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/CallbackRepeater.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -228,6 +268,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/Config.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -243,6 +284,7 @@ extern "C" {

#include "zynaddsubfx/Misc/Microtonal.cpp"
#undef MAX_LINE_SIZE
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -250,6 +292,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/MiddleWare.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -258,6 +301,7 @@ extern "C" {

#include "zynaddsubfx/Misc/Part.cpp"
#undef CLONE
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -265,6 +309,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/PresetExtractor.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -272,6 +317,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/Recorder.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -279,6 +325,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/Util.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -286,6 +333,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/WavFile.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -293,6 +341,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/WaveShapeSmps.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -300,6 +349,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Misc/XMLwrapper.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -308,6 +358,7 @@ extern "C" {

#include "zynaddsubfx/Params/ADnoteParameters.cpp"
#undef EXPAND
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -315,6 +366,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/Controller.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -322,6 +374,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/EnvelopeParams.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -329,6 +382,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/FilterParams.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -336,6 +390,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/LFOParams.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -345,6 +400,7 @@ extern "C" {
#include "zynaddsubfx/Params/PADnoteParameters.cpp"
#undef PC
#undef P_C
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -352,6 +408,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/Presets.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -359,6 +416,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/PresetsArray.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -366,6 +424,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Params/PresetsStore.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -375,6 +434,7 @@ extern "C" {
#include "zynaddsubfx/Params/SUBnoteParameters.cpp"
#undef doPaste
#undef doPPaste
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -382,6 +442,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/ADnote.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -389,6 +450,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/Envelope.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -396,6 +458,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/LFO.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -403,6 +466,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/ModFilter.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -416,6 +480,7 @@ extern "C" {
#undef RESTORE
#undef FUNC
#undef FILTER
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -423,6 +488,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/PADnote.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -430,6 +496,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/Resonance.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -437,6 +504,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/Synth/SUBnote.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb
@@ -444,6 +512,15 @@ extern "C" {
#define rChangeCb

#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 rStdString
#undef rStdStringCb
@@ -451,6 +528,7 @@ extern "C" {
#define rChangeCb

#include "zynaddsubfx/UI/ConnectionDummy.cpp"
#undef rBegin
#undef rObject
#undef rStdString
#undef rStdStringCb


+ 5
- 0
source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.cpp View File

@@ -28,6 +28,11 @@ LockFreeQueue::LockFreeQueue(qli_t *data_, int n)
tag[i] = INVALID;
}

LockFreeQueue::~LockFreeQueue(void)
{
delete [] tag;
}


qli_t *LockFreeQueue::read(void) {
retry:


+ 1
- 0
source/native-plugins/zynaddsubfx/Containers/MultiPseudoStack.h View File

@@ -34,6 +34,7 @@ class LockFreeQueue
std::atomic<int32_t> avail;
public:
LockFreeQueue(qli_t *data_, int n);
~LockFreeQueue(void);
qli_t *read(void);
void write(qli_t *Q);
};


+ 39
- 0
source/native-plugins/zynaddsubfx/Containers/ScratchString.cpp View File

@@ -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;
//}

+ 17
- 0
source/native-plugins/zynaddsubfx/Containers/ScratchString.h View File

@@ -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];
};

+ 41
- 35
source/native-plugins/zynaddsubfx/DSP/AnalogFilter.cpp View File

@@ -61,28 +61,35 @@ void AnalogFilter::cleanup()
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

const float samplerate_f = fs;
const float halfsamplerate_f = fs/2;

//do not allow frequencies bigger than samplerate/2
float freq = this->freq;
float freq = cutoff;
if(freq > (halfsamplerate_f - 500.0f)) {
freq = halfsamplerate_f - 500.0f;
zerocoefs = true;
}

if(freq < 0.1f)
freq = 0.1f;

//do not allow bogus Q
if(q < 0.0f)
q = 0.0f;


float tmpq, tmpgain;
if(stages == 0) {
tmpq = q;
tmpgain = gain;
}
else {
} else {
tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q;
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 original location of the Cookbook is:
//http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
float tmp;
float tgp1;
float tgm1;
switch(type) {
case 0: //LPF 1 pole
if(!zerocoefs)
@@ -205,20 +215,15 @@ void AnalogFilter::computefiltercoefs(void)
if(!zerocoefs) {
tmpq = sqrtf(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 {
c[0] = tmpgain;
@@ -230,20 +235,15 @@ void AnalogFilter::computefiltercoefs(void)
if(!zerocoefs) {
tmpq = sqrtf(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 {
c[0] = 1.0f;
@@ -252,10 +252,16 @@ void AnalogFilter::computefiltercoefs(void)
order = 2;
break;
default: //wrong type
type = 0;
computefiltercoefs();
assert(false && "wrong type for a filter");
break;
}
return coeff;
}

void AnalogFilter::computefiltercoefs(void)
{
coeff = AnalogFilter::computeCoeff(type, freq, q, stages, gain,
samplerate_f, order);
}




+ 3
- 0
source/native-plugins/zynaddsubfx/DSP/AnalogFilter.h View File

@@ -46,6 +46,9 @@ class AnalogFilter:public Filter
d[3]; //Feed Back
} coeff, oldCoeff;

static Coeff computeCoeff(int type, float cutoff, float q, int stages,
float gain, float fs, int &order);

private:
struct fstage {
float x1, x2; //Input History


+ 26
- 0
source/native-plugins/zynaddsubfx/Effects/Alienwah.cpp View File

@@ -12,11 +12,37 @@
*/

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

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)
:Effect(pars),
lfo(pars.srate, pars.bufsize),


+ 1
- 0
source/native-plugins/zynaddsubfx/Effects/Alienwah.h View File

@@ -33,6 +33,7 @@ class Alienwah:public Effect
unsigned char getpar(int npar) const;
void cleanup(void);

static rtosc::Ports ports;
private:
//Alienwah Parameters
EffectLFO lfo; //lfo-ul Alienwah


+ 27
- 0
source/native-plugins/zynaddsubfx/Effects/Chorus.cpp View File

@@ -12,12 +12,39 @@
*/

#include <cmath>
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>
#include "../Misc/Allocator.h"
#include "Chorus.h"
#include <iostream>

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)
:Effect(pars),
lfo(pars.srate, pars.bufsize),


+ 1
- 0
source/native-plugins/zynaddsubfx/Effects/Chorus.h View File

@@ -68,6 +68,7 @@ class Chorus:public Effect
unsigned char getpar(int npar) const;
void cleanup(void);

static rtosc::Ports ports;
private:
//Chorus Parameters
unsigned char Pvolume;


+ 27
- 0
source/native-plugins/zynaddsubfx/Effects/Distorsion.cpp View File

@@ -16,6 +16,33 @@
#include "../Misc/WaveShapeSmps.h"
#include "../Misc/Allocator.h"
#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)
:Effect(pars),


+ 1
- 0
source/native-plugins/zynaddsubfx/Effects/Distorsion.h View File

@@ -29,6 +29,7 @@ class Distorsion:public Effect
void cleanup(void);
void applyfilters(float *efxoutl, float *efxoutr);

static rtosc::Ports ports;
private:
//Parameters
unsigned char Pvolume; //Volume or E/R


+ 49
- 0
source/native-plugins/zynaddsubfx/Effects/DynamicFilter.cpp View File

@@ -16,6 +16,55 @@
#include "DynamicFilter.h"
#include "../DSP/Filter.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)
:Effect(pars),


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

@@ -30,6 +30,7 @@ class DynamicFilter:public Effect
unsigned char getpar(int npar) const;
void cleanup(void);

static rtosc::Ports ports;
private:
//Parametrii DynamicFilter
EffectLFO lfo; //lfo-ul DynamicFilter


+ 23
- 0
source/native-plugins/zynaddsubfx/Effects/Echo.cpp View File

@@ -14,11 +14,34 @@
*/

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

#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)
:Effect(pars),
Pvolume(50),


+ 2
- 0
source/native-plugins/zynaddsubfx/Effects/Echo.h View File

@@ -59,6 +59,8 @@ class Echo:public Effect
unsigned char getpar(int npar) const;
int getnumparams(void);
void cleanup(void);

static rtosc::Ports ports;
private:
//Parameters
unsigned char Pvolume; /**<#1 Volume or Dry/Wetness*/


+ 21
- 0
source/native-plugins/zynaddsubfx/Effects/Effect.h View File

@@ -22,6 +22,27 @@
class FilterParams;
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
{
/**


+ 15
- 3
source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp View File

@@ -33,6 +33,14 @@


#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 = {
rSelf(EffectMgr),
rPaste,
@@ -71,7 +79,7 @@ static const rtosc::Ports local_ports = {

//update parameters as well
strncpy(loc, d.loc, 1024);
char *tail = rindex(loc, '/');
char *tail = strrchr(loc, '/');
if(!tail)
return;
for(int i=0;i<128;++i) {
@@ -94,7 +102,9 @@ static const rtosc::Ports local_ports = {
eq->getFilter(a,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)
{
EffectMgr *eff = (EffectMgr*)d.obj;
@@ -121,7 +131,9 @@ static const rtosc::Ports local_ports = {
//Return the old data for distruction
d.reply("/free", "sb", "EffectMgr", sizeof(EffectMgr*), &eff_);
}},

rSubtype(Echo),
rSubtype(Alienwah),
rSubtype(Distorsion),
};

const rtosc::Ports &EffectMgr::ports = local_ports;


+ 32
- 0
source/native-plugins/zynaddsubfx/Effects/Phaser.cpp View File

@@ -17,11 +17,43 @@

#include <cmath>
#include <algorithm>
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>
#include "../Misc/Allocator.h"
#include "Phaser.h"

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 ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes
#define ZERO_ 0.00001f // Same idea as above.


+ 1
- 0
source/native-plugins/zynaddsubfx/Effects/Phaser.h View File

@@ -34,6 +34,7 @@ class Phaser:public Effect
unsigned char getpar(int npar) const;
void cleanup();

static rtosc::Ports ports;
private:
//Phaser parameters
EffectLFO lfo; //Phaser modulator


+ 19
- 2
source/native-plugins/zynaddsubfx/Misc/Bank.cpp View File

@@ -29,6 +29,7 @@
#include "Config.h"
#include "Util.h"
#include "Part.h"
#include "BankDb.h"

#define INSTRUMENT_EXTENSION ".xiz"

@@ -39,7 +40,7 @@ using namespace std;

Bank::Bank(Config *config)
:bankpos(0), defaultinsname(" "), config(config),
bank_msb(0), bank_lsb(0)
db(new BankDb), bank_msb(0), bank_lsb(0)
{
clearbank();
bankfiletitle = dirname;
@@ -57,6 +58,7 @@ Bank::Bank(Config *config)
Bank::~Bank()
{
clearbank();
delete db;
}

/*
@@ -179,7 +181,8 @@ int Bank::savetoslot(unsigned int ninstrument, Part *part)
err = part->saveXML(filename.c_str());
if(err)
return err;
addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz", (char *) part->Pname);
addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz",
(char *) part->Pname);
return 0;
}

@@ -350,6 +353,7 @@ bool Bank::bankstruct::operator<(const bankstruct &b) const

void Bank::rescanforbanks()
{
db->clear();
//remove old banks
banks.clear();

@@ -362,6 +366,7 @@ void Bank::rescanforbanks()

//remove duplicate bank names
for(int j = 0; j < (int) banks.size() - 1; ++j) {
db->addBankDir(banks[j].dir);
int dupl = 0;
for(int i = j + 1; i < (int) banks.size(); ++i) {
if(banks[i].name == banks[j].name) {
@@ -376,6 +381,7 @@ void Bank::rescanforbanks()
if(dupl)
j += dupl;
}
db->scanBanks();
}

void Bank::setMsb(uint8_t msb)
@@ -453,6 +459,17 @@ void Bank::clearbank()
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)
{
if((pos >= 0) && (pos < BANK_SIZE)) {


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

@@ -68,7 +68,7 @@ class Bank

std::vector<bankstruct> banks;
int bankpos;
struct ins_t {
ins_t(void);
std::string name;
@@ -76,6 +76,8 @@ class Bank
std::string filename;
} ins[BANK_SIZE];

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

private:

//it adds a filename to the bank
@@ -100,6 +102,7 @@ class Bank
void normalizedirsuffix(std::string &dirname) const;

Config* const config;
class BankDb *db;

public:
uint8_t bank_msb;


+ 219
- 0
source/native-plugins/zynaddsubfx/Misc/BankDb.cpp View File

@@ -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;
}

+ 50
- 0
source/native-plugins/zynaddsubfx/Misc/BankDb.h View File

@@ -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;
};

+ 80
- 10
source/native-plugins/zynaddsubfx/Misc/Master.cpp View File

@@ -22,6 +22,7 @@
#include "../Effects/EffectMgr.h"
#include "../DSP/FFTwrapper.h"
#include "../Misc/Allocator.h"
#include "../Containers/ScratchString.h"
#include "../Nio/Nio.h"
#include "PresetExtractor.h"

@@ -74,7 +75,7 @@ static const Ports sysefxPort =

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)
{
//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 = {
rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."),
rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS
@@ -104,8 +116,12 @@ static const Ports master_ports = {
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX
rRecur(microtonal, "Micrtonal Mapping Functionality"),
rRecur(ctl, "Controller"),
rArrayI(Pinsparts, NUM_INS_EFX, "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) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift);
} 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) {
Master *m = (Master*)d.obj;
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) {
Master *m = (Master*)d.obj;
m->vuresetpeaks();}},
@@ -129,14 +161,21 @@ static const Ports master_ports = {
m->part[i] = p;
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) {
if(rtosc_narguments(m)==0) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127));
d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}},
{"volume::i", 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) {
if(rtosc_narguments(m)==0) {
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) {
Master *m = (Master*)d.obj;
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;

class DataObj:public rtosc::RtData
@@ -257,6 +306,12 @@ class DataObj:public rtosc::RtData
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
{
va_list va;
@@ -333,9 +388,11 @@ Master::Master(const SYNTH_T &synth_, Config* config)
fakepeakpart[npart] = 0;
}

ScratchString ss;
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
part[npart] = new Part(*memory, synth, time, config->cfg.GzipCompression,
config->cfg.Interpolation, &microtonal, fft);
config->cfg.Interpolation, &microtonal, fft, &watcher,
(ss+"/part"+npart+"/").c_str);

//Insertion Effects init
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)
sysefx[nefx] = new EffectMgr(*memory, synth, 0, &time);

//Note Visualization
for(int i=0; i<128; ++i)
activeNotes[i] = 0;

defaults();

@@ -358,7 +418,7 @@ void Master::applyOscEvent(const char *msg)
DataObj d{loc_buf, 1024, this, bToU};
memset(loc_buf, 0, sizeof(loc_buf));
d.matches = 0;
if(strcmp(msg, "/get-vu") && false) {
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40);
fprintf(stdout, "backend[*]: '%s'<%s>\n", msg,
@@ -411,12 +471,14 @@ void Master::defaults()
void Master::noteOn(char chan, char note, char 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) {
fakepeakpart[npart] = velocity * 2;
if(part[npart]->Penabled)
part[npart]->NoteOn(note, velocity, keyshift);
}
}
activeNotes[(int)note] = 1;
}
else
this->noteOff(chan, note);
@@ -431,6 +493,7 @@ void Master::noteOff(char chan, char note)
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart)
if((chan == part[npart]->Prcvchn) && part[npart]->Penabled)
part[npart]->NoteOff(note);
activeNotes[(int)note] = 0;
}

/*
@@ -633,6 +696,13 @@ bool Master::AudioOut(float *outr, float *outl)
bToU->write("/request-memory", "");
pendingMemory = true;
}


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

//Handle user events TODO move me to a proper location
char loc_buf[1024];
DataObj d{loc_buf, 1024, this, bToU};
@@ -677,7 +747,7 @@ bool Master::AudioOut(float *outr, float *outl)
}
if(events>1 && false)
fprintf(stderr, "backend: %d events per cycle\n",events);

//Swaps the Left channel with Right Channel
if(swaplr)


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

@@ -24,6 +24,7 @@
#include "Recorder.h"

#include "../Params/Controller.h"
#include "../Synth/WatchPoint.h"

class Allocator;

@@ -158,6 +159,13 @@ class Master
//Statistics on output levels
vuData vu;

//Display info on midi notes
bool activeNotes[128];

//Other watchers
WatchManager watcher;

//Midi Learn
rtosc::MidiMapperRT midi;

bool frozenState;//read-only parameters for threadsafe actions


+ 140
- 16
source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp View File

@@ -73,8 +73,8 @@ void path_search(const char *m, const char *url)
using rtosc::Port;

//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;
const Ports *ports = NULL;
const char *str = rtosc_argument(m,0).s;
@@ -95,7 +95,7 @@ void path_search(const char *m, const char *url)
if(ports) {
//RTness not confirmed here
for(const Port &p:*ports) {
if(strstr(p.name, needle)!=p.name)
if(strstr(p.name, needle) != p.name || !p.name)
continue;
types[pos] = 's';
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);
if(addr)
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->activeUrl(tmp);
}
free((void*)tmp);
}

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);
if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) {
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));
}

@@ -155,6 +157,16 @@ static int handler_function(const char *path, const char *types, lo_arg **argv,

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 *
@@ -484,7 +496,8 @@ public:
master->time,
config->cfg.GzipCompression,
config->cfg.Interpolation,
&master->microtonal, master->fft);
&master->microtonal, master->fft, &master->watcher,
("/part"+to_s(npart)+"/").c_str());
if(p->loadXMLinstrument(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, va_list va);

void currentUrl(string addr)
{
curr_url = addr;
known_remotes.insert(addr);
}

// Send a message to a remote client
void sendToRemote(const char *msg, std::string dest);
@@ -720,6 +738,7 @@ public:
//LIBLO
lo_server server;
string last_url, curr_url;
std::set<string> known_remotes;

//Synthesis Rate Parameters
const SYNTH_T synth;
@@ -750,6 +769,7 @@ class MwDataObj:public rtosc::RtData

~MwDataObj(void)
{
delete[] loc;
delete[] buffer;
}

@@ -773,6 +793,17 @@ class MwDataObj:public rtosc::RtData
}
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){
mwi->sendToCurrentRemote(msg);
};
@@ -841,7 +872,8 @@ using rtosc::RtData;
* - Load Bank *
* - Refresh List of Banks *
*****************************************************************************/
rtosc::Ports bankPorts = {
extern const rtosc::Ports bankPorts;
const rtosc::Ports bankPorts = {
{"rescan:", 0, 0,
rBegin;
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", "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},
{"slot#1024:", 0, 0,
rBegin;
@@ -913,13 +987,19 @@ rtosc::Ports bankPorts = {
d.reply("/alert", "s",
"Failed To Clear Bank Slot, please check file permissions");
rEnd},
{"msb:i", 0, 0,
{"msb::i", 0, 0,
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},
{"lsb:i", 0, 0,
{"lsb::i", 0, 0,
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},
{"newbank:s", 0, 0,
rBegin;
@@ -927,6 +1007,19 @@ rtosc::Ports bankPorts = {
if(err)
d.reply("/alert", "s", "Error: Could not make a new bank (directory)..");
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);
loadMidiLearn(xml, impl.midi_mapper);
rEnd},
{"clear_xlz:", 0, 0,
rBegin;
impl.midi_mapper.clear();
rEnd},
//scale file stuff
{"load_xsz:s", 0, 0,
rBegin;
@@ -1134,6 +1231,30 @@ static rtosc::Ports middwareSnoopPorts = {
rBegin;
impl.undo.seekHistory(+1);
rEnd},
//port to observe the midi mappings
{"midi-learn-values:", 0, 0,
rBegin;
auto &midi = impl.midi_mapper;
auto key = keys(midi.inv_map);
//cc-id, path, min, max
#define MAX_MIDI 32
rtosc_arg_t args[MAX_MIDI*4];
char argt[MAX_MIDI*4+1] = {0};
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,
rBegin;
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 *url = rtosc_argument(msg, 1).s;
if(!strcmp(type, "OSC_URL"))
impl.curr_url = url;
impl.currentUrl(url);
rEnd},
{"free:sb", 0, 0,
rBegin;
@@ -1349,8 +1470,9 @@ void MiddleWareImpl::broadcastToRemote(const char *rtmsg)
sendToRemote(rtmsg, "GUI");

//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;
}
@@ -1369,6 +1491,8 @@ void MiddleWareImpl::sendToRemote(const char *rtmsg, std::string dest)
lo_address addr = lo_address_new_from_url(dest.c_str());
if(addr)
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)
{
//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(strcmp(msg, "/part0/Psysefxvol"));
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);
}

const char *last_path = rindex(msg, '/');
const char *last_path = strrchr(msg, '/');
if(!last_path) {
printf("Bad message in handleMsg() <%s>\n", msg);
assert(false);


+ 18
- 5
source/native-plugins/zynaddsubfx/Misc/Part.cpp View File

@@ -25,6 +25,7 @@
#include "../Synth/ADnote.h"
#include "../Synth/SUBnote.h"
#include "../Synth/PADnote.h"
#include "../Containers/ScratchString.h"
#include "../DSP/FFTwrapper.h"
#include "../Misc/Util.h"
#include <cstdlib>
@@ -59,7 +60,8 @@ static const Ports partPorts = {
rParamZyn(Pminkey, rShort("min"), "Min Used Key"),
rParamZyn(Pmaxkey, rShort("max"), "Max Used Key"),
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(Pveloffs, "Velocity offset"),
rToggle(Pnoteon, "If the channel accepts note on events"),
@@ -163,7 +165,9 @@ static const Ports kitPorts = {
rToggle(Padenabled, "ADsynth enable"),
rToggle(Psubenabled, "SUBsynth 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"),
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
@@ -195,7 +199,7 @@ const Ports &Part::ports = partPorts;

Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_,
const int &gzip_compression, const int &interpolation,
Microtonal *microtonal_, FFTwrapper *fft_)
Microtonal *microtonal_, FFTwrapper *fft_, WatchManager *wm_, const char *prefix_)
:Pdrummode(false),
Ppolymode(true),
Plegatomode(false),
@@ -204,12 +208,18 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_,
ctl(synth_, &time_),
microtonal(microtonal_),
fft(fft_),
wm(wm_),
memory(alloc),
synth(synth_),
time(time_),
gzip_compression(gzip_compression),
interpolation(interpolation)
{
if(prefix_)
strncpy(prefix, prefix_, sizeof(prefix));
else
memset(prefix, 0, sizeof(prefix));

monomemClear();

for(int n = 0; n < NUM_KIT_ITEMS; ++n) {
@@ -482,6 +492,7 @@ bool Part::NoteOn(unsigned char note,

//Create New Notes
for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) {
ScratchString pre = prefix;
auto &item = kit[i];
if(Pkitmode != 0 && !item.validNote(note))
continue;
@@ -493,13 +504,15 @@ bool Part::NoteOn(unsigned char note,
try {
if(item.Padenabled)
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)
notePool.insertNote(note, sendto,
{memory.alloc<SUBnote>(kit[i].subpars, pars), 1, i});
if(item.Ppadenabled)
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) {
std::cerr << "dropped new note: " << ba.what() << std::endl;
}


+ 3
- 1
source/native-plugins/zynaddsubfx/Misc/Part.h View File

@@ -31,7 +31,7 @@ class Part
* @param fft_ Pointer to the FFTwrapper*/
Part(Allocator &alloc, const SYNTH_T &synth, const AbsTime &time,
const int& gzip_compression, const int& interpolation,
Microtonal *microtonal_, FFTwrapper *fft_);
Microtonal *microtonal_, FFTwrapper *fft_, WatchManager *wm=0, const char *prefix=0);
/**Destructor*/
~Part();

@@ -192,6 +192,8 @@ class Part
float oldfreq; //this is used for portamento
Microtonal *microtonal;
FFTwrapper *fft;
WatchManager *wm;
char prefix[64];
Allocator &memory;
const SYNTH_T &synth;
const AbsTime &time;


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

@@ -12,6 +12,7 @@ using namespace rtosc;
* - 'tooltip' : string [OPTIONAL]
* - 'type' : type
* - 'domain' : range [OPTIONAL]
* - 'options' : [option...] [OPTIONAL]
* type : {'int', 'float', 'boolean'}
* action :
* - 'path' : path-id
@@ -19,6 +20,9 @@ using namespace rtosc;
* arg :
* - 'type' : type
* - 'domain' : range [OPTIONAL]
* option :
* - 'id' : id-number
* - 'value' : string-rep
*/

void walk_ports2(const rtosc::Ports *base,
@@ -98,15 +102,24 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta)
* - 'domain' : range [OPTIONAL]
*/
static bool first = true;
void dump_param_cb(const rtosc::Port *p, const char *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;
auto meta = p->meta();
const char *args = strchr(p->name, ':');
auto mparameter = meta.find("parameter");
auto mdoc = meta.find("documentation");
auto msname = meta.find("shortname");
opts options;
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
if(mdoc != p->meta().end()) {
@@ -139,7 +152,7 @@ void dump_param_cb(const rtosc::Port *p, const char *name, void *v)
}

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);
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 *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)
o << ",\n";
else
first = false;

o << " {\n";
o << " \"path\" : \"" << name << "\",\n";
o << " \"path\" : \"" << full_name << "\",\n";
if(msname != meta.end())
o << " \"shortname\": \"" << msname.value << "\",\n";
o << " \"name\" : \"" << p->name << "\",\n";
o << " \"name\" : \"" << name << "\",\n";
o << " \"tooltip\" : \"" << doc << "\",\n";
o << " \"type\" : \"" << type << "\"";
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)


+ 8
- 13
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp View File

@@ -87,10 +87,6 @@ const char *mxmlElementGetAttr(const mxml_node_t *node, const char *name)

XMLwrapper::XMLwrapper()
{
version.Major = 2;
version.Minor = 5;
version.Revision = 3;

minimal = true;

node = tree = mxmlNewElement(MXML_NO_PARENT,
@@ -106,11 +102,11 @@ XMLwrapper::XMLwrapper()

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

//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

//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)
cout << "loadXMLfile() version: " << version.Major << '.'
<< version.Minor << '.' << version.Revision << endl;
cout << "loadXMLfile() version: " << fileversion << endl;

return 0;
}


+ 2
- 6
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h View File

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

#ifndef XML_WRAPPER_H
#define XML_WRAPPER_H
@@ -272,12 +273,7 @@ class XMLwrapper
mxml_node_t *addparams(const char *name, unsigned int params,
...) 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

+ 15
- 3
source/native-plugins/zynaddsubfx/Nio/AlsaEngine.cpp View File

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

#include <stdlib.h>
#include <iostream>
#include <cmath>

@@ -20,6 +21,7 @@ using namespace std;
#include "../Misc/Config.h"
#include "InMgr.h"
#include "AlsaEngine.h"
#include "Compressor.h"
#include "Nio.h"

AlsaEngine::AlsaEngine(const SYNTH_T &synth)
@@ -28,6 +30,7 @@ AlsaEngine::AlsaEngine(const SYNTH_T &synth)
audio.buffer = new short[synth.buffersize * 2];
name = "ALSA";
audio.handle = NULL;
audio.peaks[0] = 0;

midi.handle = NULL;
midi.alsaId = -1;
@@ -251,9 +254,13 @@ short *AlsaEngine::interleave(const Stereo<float *> &smps)
int idx = 0; //possible off by one error here
double scaled;
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);
scaled = smps.r[frame] * (8.0f * 0x10000000);
scaled = r * (8.0f * 0x10000000);
shortInterleaved[idx++] = (short int)(lrint(scaled) >> 16);
}
return shortInterleaved;
@@ -267,7 +274,12 @@ bool AlsaEngine::openAudio()
int rc = 0;
/* Open PCM device for playback. */
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);
if(rc < 0) {
fprintf(stderr,


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

@@ -67,6 +67,7 @@ class AlsaEngine:public AudioOut, MidiIn
unsigned int periods;
short *buffer;
pthread_t pThread;
float peaks[1];
} audio;

void *processAudio();


+ 59
- 0
source/native-plugins/zynaddsubfx/Nio/Compressor.h View File

@@ -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_ */

+ 4
- 0
source/native-plugins/zynaddsubfx/Nio/JackMultiEngine.cpp View File

@@ -131,6 +131,10 @@ int JackMultiEngine::processAudio(jack_nframes_t nframes)
float *buffers[NUM_MIDI_PARTS * 2 + 2];

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] =
(float *)jack_port_get_buffer(impl->ports[i], nframes);
assert(buffers[i]);


+ 7
- 14
source/native-plugins/zynaddsubfx/Nio/OssEngine.cpp View File

@@ -12,6 +12,8 @@
*/

#include "OssEngine.h"
#include "Compressor.h"

#include "../Misc/Util.h"
#include "../Misc/Config.h"
#include "../globals.h"
@@ -186,6 +188,8 @@ OssEngine::OssEngine(const SYNTH_T &synth,
audio.smps.ps32 = new int[synth.buffersize * 2];
memset(audio.smps.ps32, 0, sizeof(int) * synth.buffersize * 2);
memset(&midi.state, 0, sizeof(midi.state));

audio.peaks[0] = 0;
}

OssEngine::~OssEngine()
@@ -401,21 +405,10 @@ void *OssEngine::audioThreadCb()
while(getAudioEn()) {
const Stereo<float *> smps = getNext();

float l, r;
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) {
audio.smps.ps32[i * 2] = (int) (l * 2147483647.0f);


+ 4
- 0
source/native-plugins/zynaddsubfx/Nio/OssEngine.h View File

@@ -71,6 +71,10 @@ class OssEngine:public AudioOut, MidiIn
short int *ps16;
int *ps32;
} smps;

/* peak values used for compressor */
float peaks[1];

bool en;
bool is32bit;
} audio;


+ 13
- 22
source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.cpp View File

@@ -29,6 +29,7 @@
#include "../Misc/Util.h"

#include "OssMultiEngine.h"
#include "Compressor.h"

extern MiddleWare *middleware;

@@ -53,12 +54,18 @@ OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth,
/* allocate buffer */
smps.ps32 = new int[maxbuffersize / sizeof(int)];
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()
{
Stop();
delete [] smps.ps32;
delete [] peaks;
}

bool
@@ -213,8 +220,6 @@ OssMultiEngine :: audioThreadCb()

while(getAudioEn()) {
int error;
float l;
float r;
int x;
int y;

@@ -227,32 +232,18 @@ OssMultiEngine :: audioThreadCb()

if (is32bit) {
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);
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);
}
} else {
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);
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);
}
}


+ 3
- 0
source/native-plugins/zynaddsubfx/Nio/OssMultiEngine.h View File

@@ -52,6 +52,9 @@ class OssMultiEngine : public AudioOut
int *ps32;
} smps;

/* peak values used for compressor */
float *peaks;

bool en;
bool is32bit;



+ 71
- 62
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp View File

@@ -18,6 +18,7 @@
#include "ADnoteParameters.h"
#include "EnvelopeParams.h"
#include "LFOParams.h"
#include "../Misc/Time.h"
#include "../Misc/XMLwrapper.h"
#include "../DSP/FFTwrapper.h"
#include "../Synth/OscilGen.h"
@@ -66,63 +67,68 @@ static const Ports voicePorts = {
rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"),
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
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
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
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
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
@@ -229,28 +235,31 @@ static const Ports globalPorts = {
rRecurp(AmpEnvelope, "Frequency Envelope"),
rRecurp(FilterEnvelope, "Frequency Envelope"),
rRecurp(GlobalFilter, "Filter"),
rToggle(PStereo, "Mono/Stereo Enable"),

rToggle(PStereo, rShort("stereo"), "Mono/Stereo Enable"),

//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
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(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
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


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

@@ -27,31 +27,31 @@ using namespace rtosc;
#undef rChangeCb
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
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_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"),
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(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"),
rAction(defaults),
};


+ 78
- 50
source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp View File

@@ -23,6 +23,9 @@

#define rObject EnvelopeParams
using namespace rtosc;
#define rBegin [](const char *msg, RtData &d) { \
EnvelopeParams *env = (rObject*) d.obj
#define rEnd }

static const rtosc::Ports localPorts = {
rSelf(EnvelopeParams),
@@ -32,60 +35,85 @@ static const rtosc::Ports localPorts = {
obj->last_update_timestamp = obj->time->time(); }
rToggle(Pfreemode, "Complex Envelope Definitions"),
#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(Penvsustain, rProp(internal), "Location of the sustain point"),
rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"),
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



+ 95
- 18
source/native-plugins/zynaddsubfx/Params/FilterParams.cpp View File

@@ -14,6 +14,7 @@
#include "FilterParams.h"
#include "../Misc/Util.h"
#include "../Misc/Time.h"
#include "../DSP/AnalogFilter.h"
#include <cmath>
#include <cstdio>
#include <cstdlib>
@@ -58,18 +59,29 @@ const rtosc::Ports FilterParams::ports = {
rSelf(FilterParams),
rPaste,
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
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;
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"
//{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/amp",
// "", NULL, [](){}},
//{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/q",
// "", 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
#define rChangeCb
@@ -287,21 +367,18 @@ float FilterParams::getfreqpos(float 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 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
{
//temp
float result = powf(25.0f, (q - 32.0f) / 64.0f);
return result;
return powf(25.0f, (q - 32.0f) / 64.0f);
}




+ 17
- 2
source/native-plugins/zynaddsubfx/Params/LFOParams.cpp View File

@@ -27,6 +27,8 @@ using namespace rtosc;
#define rObject LFOParams
#undef rChangeCb
#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 = {
rSelf(LFOParams),
rPaste,
@@ -35,8 +37,8 @@ static const rtosc::Ports _ports = {
"true frequency is [0,85.33] Hz"),
rParamZyn(Pintensity, rShort("depth"), "Intensity of LFO"),
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),
"Amplitude Randomness (calculated uniformly at each cycle)"),
rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable),
@@ -45,7 +47,20 @@ static const rtosc::Ports _ports = {
"0..4 second delay"),
rToggle(Pcontinous, rShort("c"), "Enable for global operation"),
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

const rtosc::Ports &LFOParams::ports = _ports;


+ 41
- 24
source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp View File

@@ -18,6 +18,7 @@
#include "../Synth/Resonance.h"
#include "../Synth/OscilGen.h"
#include "../Misc/WavFile.h"
#include "../Misc/Time.h"
#include <cstdio>

#include <rtosc/ports.h>
@@ -136,30 +137,30 @@ static const rtosc::Ports non_realtime_ports =
rRecurp(resonance, "Resonance"),

//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"),
rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential),
rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), rShort("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"),

//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"),
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),
"Harmonic cutoff model"),

//Harmonic Bandwidth
rOption(Pbwscale,
rOption(Pbwscale, rShort("bw scale"),
rOptions(Normal,
EqualHz, Quater,
Half, 75%, 150%,
@@ -171,26 +172,26 @@ static const rtosc::Ports non_realtime_ports =
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine,
Power, Shift),
"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
rOption(Pquality.samplesize,
rOption(Pquality.samplesize, rShort("quality"),
rOptions(16k (Tiny), 32k, 64k (Small), 128k,
256k (Normal), 512k, 1M (Big)),
"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,),
"Base note for wavetable"),
rOption(Pquality.smpoct,
rOption(Pquality.smpoct, rShort("smp/oct"),
rOptions(0.5, 1, 2, 3, 4, 6, 12),
"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"),

{"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) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
if(rtosc_narguments(msg)) {
@@ -225,8 +226,24 @@ static const rtosc::Ports non_realtime_ports =
float *tmp = new float[n];
float realbw = p->getprofile(tmp, n);
d.reply(d.loc, "b", n*sizeof(float), tmp);
d.reply(d.loc, "i", realbw);
d.reply(d.loc, "i", (int)realbw);
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"),
NULL, [](const char *, rtosc::RtData&) {}},
};


+ 161
- 66
source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp View File

@@ -26,102 +26,147 @@
#define rObject SUBnoteParameters
using namespace rtosc;

#define rBegin [](const char *msg, RtData &d) { \
SUBnoteParameters *obj = (SUBnoteParameters*) d.obj
#define rEnd }


#undef rChangeCb
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
static const rtosc::Ports SUBnotePorts = {
rSelf(SUBnoteParameters),
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
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),
//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
#define rChangeCb obj->updateFrequencyMultipliers(); if (obj->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"),
rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255),
rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), rShort("p1"),
"Overtone Parameter"),
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255),
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"),
"Overtone Parameter"),
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255),
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("p3"),
"Overtone Parameter"),
#undef rChangeCb
#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(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(FreqEnvelope, "Frequency Envelope"),
rRecurp(BandWidthEnvelope, "Bandwidth Envelope"),
rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"),
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
{"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,
[](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 rBegin
#undef rEnd

const rtosc::Ports &SUBnoteParameters::ports = SUBnotePorts;

@@ -143,6 +188,56 @@ SUBnoteParameters::SUBnoteParameters(const AbsTime *time_)
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()
{


+ 10
- 1
source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.h View File

@@ -24,6 +24,15 @@ class SUBnoteParameters:public Presets
SUBnoteParameters(const AbsTime *time_ = nullptr);
~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 defaults();
void getfromXML(XMLwrapper& xml);
@@ -31,7 +40,7 @@ class SUBnoteParameters:public Presets
void paste(SUBnoteParameters &sub);

//Parameters
//AMPLITUDE PARAMETRERS
//AMPLITUDE PARAMETERS
unsigned char Pstereo; //0 for mono,1 for stereo
unsigned char PVolume;
unsigned char PPanning;


+ 44
- 19
source/native-plugins/zynaddsubfx/Synth/ADnote.cpp View File

@@ -22,11 +22,13 @@
#include "../Misc/Util.h"
#include "../Misc/Allocator.h"
#include "../Params/ADnoteParameters.h"
#include "../Containers/ScratchString.h"
#include "ModFilter.h"
#include "OscilGen.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_)
{
memory.beginTransaction();
@@ -450,7 +452,7 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
memset(tmpwave_unison[k], 0, synth.bufferbytes);
}

initparameters();
initparameters(wm, prefix);
memory.endTransaction();
}

@@ -772,16 +774,17 @@ ADnote::~ADnote()
/*
* Init the parameters
*/
void ADnote::initparameters()
void ADnote::initparameters(WatchManager *wm, const char *prefix)
{
int tmp[NUM_VOICES];
ScratchString pre = prefix;
//ADnoteParameters &pars = *partparams;

// Global Parameters
NoteGlobalPar.initparameters(pars.GlobalPar, synth,
time,
memory, basefreq, velocity,
stereo);
stereo, wm, prefix);

NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output
globalnewamplitude = NoteGlobalPar.Volume
@@ -816,22 +819,28 @@ void ADnote::initparameters()

newamplitude[nvoice] = 1.0f;
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
newamplitude[nvoice] *= vce.AmpEnvelope->envout_dB();
}

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();
}

/* Voice Frequency Parameters Init */
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)
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 */
if(param.PFilterEnabled) {
@@ -843,12 +852,15 @@ void ADnote::initparameters()

if(param.PFilterEnvelopeEnabled) {
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);
}

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);
}
}
@@ -892,13 +904,17 @@ void ADnote::initparameters()
}

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;

if(param.PFMAmpEnvelopeEnabled ) {
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();
}
}
@@ -1873,13 +1889,20 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam &param,
const AbsTime &time,
class Allocator &memory,
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
* VelF(velocity, param.PAmpVelocityScaleFunction); //sensing
@@ -1887,8 +1910,10 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam &param,
Filter = memory.alloc<ModFilter>(*param.GlobalFilter, synth, time, memory,
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(*FilterLfo);


+ 6
- 3
source/native-plugins/zynaddsubfx/Synth/ADnote.h View File

@@ -34,7 +34,8 @@ class ADnote:public SynthNote
/**Constructor.
* @param pars Note 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*/
~ADnote();

@@ -62,7 +63,7 @@ class ADnote:public SynthNote
/**Compute parameters for next tick*/
void computecurrentparameters();
/**Initializes All Parameters*/
void initparameters();
void initparameters(WatchManager *wm, const char *prefix);
/**Deallocate/Cleanup given voice*/
void KillVoice(int nvoice);
/**Deallocate Note resources and voice resources*/
@@ -117,7 +118,9 @@ class ADnote:public SynthNote
const AbsTime &time,
class Allocator &memory,
float basefreq, float velocity,
bool stereo);
bool stereo,
WatchManager *wm,
const char *prefix);
/******************************************
* FREQUENCY GLOBAL PARAMETERS *
******************************************/


+ 33
- 10
source/native-plugins/zynaddsubfx/Synth/Envelope.cpp View File

@@ -15,7 +15,9 @@
#include "Envelope.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;
if(envpoints > MAX_ENVELOPE_POINTS)
@@ -88,7 +90,7 @@ void Envelope::releasekey()
if(keyreleased)
return;
keyreleased = true;
if(forcedrelease != 0)
if(forcedrelease)
t = 0.0f;
}

@@ -100,20 +102,28 @@ void Envelope::forceFinish(void)
/*
* Envelope Output
*/
float Envelope::envout()
float Envelope::envout(bool doWatch)
{
float out;

if(envfinish) { //if the envelope is finished
envoutval = envval[envpoints - 1];
if(doWatch) {
float pos[2] = {(float)envpoints - 1, envoutval};
watchOut(pos, 2);
}
return envoutval;
}
if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now
envoutval = envval[envsustain];
if(doWatch) {
float pos[2] = {(float)envsustain, envoutval};
watchOut(pos, 2);
}
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

if(envdt[tmp] < 0.00000001f)
@@ -130,6 +140,12 @@ float Envelope::envout()
if((currentpoint >= envpoints) || (envsustain < 0))
envfinish = true;
}

if(doWatch) {
float pos[2] = {(float)tmp + t, envoutval};
watchOut(pos, 2);
}

return out;
}
if(inct >= 1.0f)
@@ -149,6 +165,11 @@ float Envelope::envout()
}

envoutval = out;

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

@@ -166,10 +187,10 @@ inline float Envelope::env_rap2dB(float rap) {
float Envelope::envout_dB()
{
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 v2 = env_dB2rap(envval[1]);
out = v1 + (v2 - v1) * t;
@@ -186,9 +207,11 @@ float Envelope::envout_dB()
envoutval = env_rap2dB(out);
else
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;
}


+ 11
- 7
source/native-plugins/zynaddsubfx/Synth/Envelope.h View File

@@ -15,6 +15,7 @@
#define ENVELOPE_H

#include "../globals.h"
#include "WatchPoint.h"

/**Implementation of a general Envelope*/
class Envelope
@@ -22,17 +23,18 @@ class Envelope
public:

/**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*/
~Envelope();
void releasekey();
~Envelope(void);
void releasekey(void);
/**Push Envelope to finishing state*/
void forceFinish(void);
float envout();
float envout_dB();
float envout(bool doWatch=true);
float envout_dB(void);
/**Determines the status of the Envelope
* @return returns 1 if the envelope is finished*/
bool finished() const;
bool finished(void) const;
private:
float env_rap2dB(float rap);
float env_dB2rap(float db);
@@ -44,12 +46,14 @@ class Envelope
int linearenvelope;

int currentpoint; //current envelope point (starts from 1)
int forcedrelease;
bool forcedrelease;
bool keyreleased; //if the key was released
bool envfinish;
float t; // the time from the last point
float inct; // the time increment
float envoutval; //used to do the forced release

VecWatchPoint watchOut;
};




+ 8
- 2
source/native-plugins/zynaddsubfx/Synth/LFO.cpp View File

@@ -19,13 +19,15 @@
#include <cstdio>
#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),
delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec
waveShape(lfopars.PLFOtype),
deterministic(!lfopars.Pfreqrand),
dt_(t.dt()),
lfopars_(lfopars), basefreq_(basefreq)
lfopars_(lfopars), basefreq_(basefreq),
watchOut(m, watch_prefix, "out")
{
int stretch = lfopars.Pstretch;
if(stretch == 0)
@@ -166,6 +168,10 @@ float LFO::lfoout()

computeNextFreqRnd();
}

float watch_data[2] = {phase, out};
watchOut(watch_data, 2);

return out;
}



+ 5
- 1
source/native-plugins/zynaddsubfx/Synth/LFO.h View File

@@ -16,6 +16,7 @@

#include "../globals.h"
#include "../Misc/Time.h"
#include "WatchPoint.h"

/**Class for creating Low Frequency Oscillators*/
class LFO
@@ -26,7 +27,8 @@ class LFO
* @param lfopars pointer to a LFOParams object
* @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();

float lfoout();
@@ -63,6 +65,8 @@ class LFO
const LFOParams &lfopars_;
const float basefreq_;

VecWatchPoint watchOut;

void computeNextFreqRnd(void);
};



+ 42
- 31
source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp View File

@@ -34,54 +34,54 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
rSelf(OscilGen),
rPaste,
//TODO ensure min/max
rOption(Phmagtype,
rOption(Phmagtype, rShort("scale"),
rOptions(linear,dB scale (-40),
dB scale (-60), dB scale (-80),
dB scale (-100)),
"Type of magnitude for harmonics"),
rOption(Pcurrentbasefunc,
rOption(Pcurrentbasefunc, rShort("base"),
rOptions(sine, triangle, pulse, saw, power, gauss,
diode, abssine, pulsesine, stretchsine,
chirp, absstretchsine, chebyshev, sqr,
spike, circle), rOpt(127,use-as-base waveform),
"Base Waveform for harmonics"),
rParamZyn(Pbasefuncpar,
rParamZyn(Pbasefuncpar, rShort("shape"),
"Morph between possible base function shapes "
"(e.g. rising sawtooth vs a falling sawtooth)"),
rOption(Pbasefuncmodulation,
rOption(Pbasefuncmodulation, rShort("mod"),
rOptions(None, Rev, Sine, Power, Chop),
"Modulation applied to Base function spectra"),
rParamZyn(Pbasefuncmodulationpar1,
rParamZyn(Pbasefuncmodulationpar1, rShort("p1"),
"Base function modulation parameter"),
rParamZyn(Pbasefuncmodulationpar2,
rParamZyn(Pbasefuncmodulationpar2, rShort("p2"),
"Base function modulation parameter"),
rParamZyn(Pbasefuncmodulationpar3,
rParamZyn(Pbasefuncmodulationpar3, rShort("p3"),
"Base function modulation parameter"),
rParamZyn(Pwaveshaping, "Degree Of Waveshaping"),
rOption(Pwaveshapingfunction,
rOption(Pwaveshapingfunction, rShort("distort"),
rOptions(Undistorted,
Arctangent, Asymmetric, Pow, Sine, Quantisize,
Zigzag, Limiter, Upper Limiter, Lower Limiter,
Inverse Limiter, Clip, Asym2, Pow2, sigmoid),
"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,
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);, "
"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"),
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"),
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
@@ -91,9 +91,20 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
while(*mm && !isdigit(*mm)) ++mm;
unsigned char &phase = ((OscilGen*)d.obj)->Phphase[atoi(mm)];
if(!rtosc_narguments(m))
d.reply(d.loc, "c", phase);
else
d.reply(d.loc, "i", phase);
else {
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
{"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;
unsigned char &mag = ((OscilGen*)d.obj)->Phmag[atoi(mm)];
if(!rtosc_narguments(m))
d.reply(d.loc, "c", mag);
d.reply(d.loc, "i", mag);
else {
mag = rtosc_argument(m,0).i;
//printf("setting magnitude\n\n");
//XXX hack hack
char *repath = strdup(d.loc);
char *edit = rindex(repath, '/')+1;
char *edit = strrchr(repath, '/')+1;
strcpy(edit, "prepare");
OscilGen &o = *((OscilGen*)d.obj);
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{
rSelf(OscilGen),
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"),
rParamZyn(Pamprandpower,
rParamZyn(Pamprandpower, rShort("variance"),
"Variance of harmonic randomness"),
rOption(Pamprandtype, rOptions(None, Pow, Sin),
rOption(Pamprandtype, rShort("distribution"), rOptions(None, Pow, Sin),
"Harmonic random distribution to select from"),
rOption(Padaptiveharmonics,
rOption(Padaptiveharmonics, rShort("adapt")
rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd),
"Adaptive Harmonics Mode"),
rParamI(Padaptiveharmonicsbasefreq, rLinear(0,255),
rParamI(Padaptiveharmonicsbasefreq, rShort("c. freq"), rLinear(0,255),
"Base frequency of adaptive harmonic (30..3000Hz)"),
rParamI(Padaptiveharmonicspower,rLinear(0,200),
rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200),
"Adaptive Harmonic Strength"),
rParamZyn(Padaptiveharmonicspar,
rParamZyn(Padaptiveharmonicspar, rShort("par"),
"Adaptive Harmonics Postprocessing Power"),
{"waveform:", rDoc("Returns waveform points"),
NULL, [](const char *, rtosc::RtData &d) {


+ 27
- 10
source/native-plugins/zynaddsubfx/Synth/PADnote.cpp View File

@@ -19,10 +19,12 @@
#include "../Params/PADnoteParameters.h"
#include "../Params/Controller.h"
#include "../Params/FilterParams.h"
#include "../Containers/ScratchString.h"
#include "../Misc/Util.h"

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)
{
NoteGlobalPar.GlobalFilter = nullptr;
@@ -30,14 +32,16 @@ PADnote::PADnote(const PADnoteParameters *parameters,
NoteGlobalPar.FilterLfo = nullptr;

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,
float velocity_,
int portamento_,
int midinote,
bool legato)
bool legato,
WatchManager *wm,
const char *prefix)
{
portamento = portamento_;
velocity = velocity_;
@@ -129,11 +133,21 @@ void PADnote::setup(float freq,
else
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
@@ -147,6 +161,7 @@ void PADnote::setup(float freq,
* NoteGlobalPar.AmpLfo->amplfoout();

if(!legato) {
ScratchString pre = prefix;
auto &flt = NoteGlobalPar.GlobalFilter;
auto &env = NoteGlobalPar.FilterEnvelope;
auto &lfo = NoteGlobalPar.FilterLfo;
@@ -154,8 +169,10 @@ void PADnote::setup(float freq,
flt = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, true, basefreq);

//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(*lfo);
}


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

@@ -23,7 +23,7 @@ class PADnote:public SynthNote
{
public:
PADnote(const PADnoteParameters *parameters, SynthParams pars,
const int &interpolation);
const int &interpolation, WatchManager *wm=0, const char *prefix=0);
~PADnote();

SynthNote *cloneLegato(void);
@@ -36,7 +36,7 @@ class PADnote:public SynthNote
void releasekey();
private:
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 computecurrentparameters();
bool finished_;


+ 29
- 5
source/native-plugins/zynaddsubfx/Synth/Resonance.cpp View File

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

#define rObject Resonance
#define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj

#define rEnd }
using namespace rtosc;
const rtosc::Ports Resonance::ports = {
rSelf(Resonance),
rPaste,
rToggle(Penabled, "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"),
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(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"),
rAction(smooth, "Smooth out frequency response"),
@@ -42,7 +44,29 @@ const rtosc::Ports Resonance::ports = {
{"octavesfreq:", rDoc("Get center freq of graph"), NULL,
[](const char *, RtData &d)
{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()
{


+ 29
- 56
source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp View File

@@ -20,6 +20,7 @@
#include "SUBnote.h"
#include "Envelope.h"
#include "ModFilter.h"
#include "../Containers/ScratchString.h"
#include "../Params/Controller.h"
#include "../Params/SUBnoteParameters.h"
#include "../Params/FilterParams.h"
@@ -35,7 +36,8 @@ SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
GlobalFilter(nullptr),
GlobalFilterEnvelope(nullptr),
NoteEnabled(true),
lfilter(nullptr), rfilter(nullptr)
lfilter(nullptr), rfilter(nullptr),
wm(nullptr)
{
setup(spars.frequency, spars.velocity, spars.portamento, spars.note);
}
@@ -46,46 +48,19 @@ float SUBnote::setupFilters(int *pos, bool automation)
float reduceamp = 0.0f;

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_rolloff[n] = computerolloff(freq);

//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)
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;

for(int nph = 0; nph < numstages; ++nph) {
@@ -158,14 +133,10 @@ void SUBnote::setup(float freq,
// basefreq*=ctl.pitchwheel.relfreq;//pitch wheel

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
firstnumharmonics = numharmonics = harmonics;
else {
@@ -198,9 +169,9 @@ void SUBnote::setup(float freq,
oldbandwidth = 64;
if(!legato) { //normal note
if(pars.Pfixedfreq == 0)
initparameters(basefreq);
initparameters(basefreq, wm);
else
initparameters(basefreq / 440.0f * freq);
initparameters(basefreq / 440.0f * freq, wm);
}
else {
if(pars.Pfixedfreq == 0)
@@ -376,18 +347,25 @@ void SUBnote::filter(bpfilter &filter, float *smps)
/*
* 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)
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)
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) {
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);

@@ -429,14 +407,9 @@ void SUBnote::computecurrentparameters()
//A little bit of copy/paste for now

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);
if(delta_harmonics) {


+ 2
- 1
source/native-plugins/zynaddsubfx/Synth/SUBnote.h View File

@@ -43,7 +43,7 @@ class SUBnote:public SynthNote
* Initialize envelopes and global filter
* calls computercurrentparameters()
*/
void initparameters(float freq);
void initparameters(float freq, WatchManager *wm);
void KillNote();

const SUBnoteParameters &pars;
@@ -101,6 +101,7 @@ class SUBnote:public SynthNote
int oldpitchwheel, oldbandwidth;
float globalfiltercenterq;
float velocity;
WatchManager *wm;
};

#endif

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

@@ -108,6 +108,7 @@ class SynthNote
const Controller &ctl;
const SYNTH_T &synth;
const AbsTime &time;
WatchManager *wm;
};

#endif

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

@@ -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];
}

+ 81
- 0
source/native-plugins/zynaddsubfx/Synth/WatchPoint.h View File

@@ -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;
}
}
};

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

@@ -407,7 +407,7 @@ class UI_Interface:public Fl_Osc_Interface
virtual void damage(const char *path) override
{
#ifndef NO_UI
printf("\n\nDamage(\"%s\")\n", path);
//printf("\n\nDamage(\"%s\")\n", path);
std::set<Fl_Osc_Widget*> to_update;
for(auto pair:map) {
if(strstr(pair.first.c_str(), path)) {
@@ -428,7 +428,7 @@ class UI_Interface:public Fl_Osc_Interface
//DEBUG
//if(strcmp(msg, "/vu-meter"))//Ignore repeated message
// 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)
++handle;



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

@@ -312,6 +312,11 @@ if (filename==NULL) return;
osc->write("/load_xlz", "s", filename);}
xywh {40 40 100 20}
}
MenuItem {} {
label {Clear Midi Learn...}
callback {osc->write("/clear_xlz", "");}
xywh {40 40 100 20}
}
MenuItem {} {
label {Save Midi Learn...}
callback {char *filename;
@@ -1485,7 +1490,7 @@ selectuiwindow->hide();}
xywh {10 165 100 35} color 229 labelfont 1 labelsize 16
}
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
}
Fl_Button {} {


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

@@ -470,7 +470,7 @@ class UI_Interface:public Fl_Osc_Interface
//DEBUG
//if(strcmp(msg, "/vu-meter"))//Ignore repeated message
// 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)
++handle;

@@ -572,9 +572,11 @@ const char *help_message =
"zynaddsubfx-ext-gui [options] uri - Connect to remote ZynAddSubFX\n"
" --help print this help message\n"
" --no-uri run without a remote ZynAddSubFX\n"
" --embed window ID [Internal Flag For Embedding Windows]\n"
"\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
int main(int argc, char *argv[])


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

@@ -45,6 +45,7 @@ class EnvelopeParams;
class LFOParams;
class FilterParams;

struct WatchManager;
class LFO;
class Envelope;
class OscilGen;


+ 5
- 4
source/native-plugins/zynaddsubfx/main.cpp View File

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

main.cpp - Main file of the synthesizer
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
modify it under the terms of the GNU General Public License
@@ -35,6 +35,7 @@
#include "Misc/Master.h"
#include "Misc/Part.h"
#include "Misc/Util.h"
#include "version.h"

//Nio System
#include "Nio/Nio.h"
@@ -364,7 +365,7 @@ int main(int argc, char *argv[])
synth.alias();

if(exitwithversion) {
cout << "Version: " << VERSION << endl;
cout << "Version: " << version << endl;
return 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"
<< " -N , --named\t\t\t\t Postfix IO Name when possible\n"
<< " -a , --auto-connect\t\t\t AutoConnect when using JACK\n"
<< " -A , --auto-save=INTERVAL\t\t Automatically save at interval (disabled 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) "
"client name\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.");
}

if(auto_save_interval >= 0) {
if(auto_save_interval > 0) {
int old_save = middleware->checkAutoSave();
if(old_save > 0)
GUI::raiseUi(gui, "/alert-reload", "i", old_save);


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

@@ -342,6 +342,16 @@ void MidiMappernRT::delMapping(int ID, bool coarse, const char *addr){
};
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)


+ 18
- 0
source/native-plugins/zynaddsubfx/rtosc/cpp/undo-history.cpp View File

@@ -16,6 +16,10 @@ class UndoHistoryImpl
UndoHistoryImpl(void)
:max_history_size(20)
{}
~UndoHistoryImpl(void)
{
clear();
}
std::deque<pair<time_t, const char *>> history;
long history_pos;
unsigned max_history_size;//XXX Expose this via a public API
@@ -24,6 +28,7 @@ class UndoHistoryImpl
void rewind(const char *msg);
void replay(const char *msg);
bool mergeEvent(time_t t, const char *msg, char *buf, size_t N);
void clear(void);
};

UndoHistory::UndoHistory(void)
@@ -32,6 +37,11 @@ UndoHistory::UndoHistory(void)
impl->history_pos = 0;
}

UndoHistory::~UndoHistory(void)
{
delete impl;
}

void UndoHistory::recordEvent(const char *msg)
{
//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;
}

void UndoHistoryImpl::clear(void)
{
for(auto elm : history)
delete [] elm.second;
history.clear();
history_pos = 0;
}



void UndoHistory::seekHistory(int distance)


+ 2
- 2
source/native-plugins/zynaddsubfx/rtosc/dispatch.c View File

@@ -200,8 +200,8 @@ static bool is_charwise(uint8_t c)
int rtosc_subpath_pat_type(const char *pattern)
{
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))
return RTOSC_MATCH_ALL;



+ 2
- 0
source/native-plugins/zynaddsubfx/rtosc/miditable.h View File

@@ -115,6 +115,8 @@ class MidiMappernRT
void delMapping(int ID, bool coarse, const char *addr);
void replaceMapping(int, bool, const char *);

void clear(void);

std::map<std::string, std::string> getMidiMappingStrings(void);

//unclear if this should be be here as a helper or not


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

@@ -144,7 +144,7 @@ struct rtosc_hack_decltype_t
#define rArrayF(name, length, ...) \
{STRINGIFY(name) "#" STRINGIFY(length) "::f", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayFCb(name)}
#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, ...) \
{STRINGIFY(name) "#" STRINGIFY(length) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayTCb(name)}
#define rArrayI(name, length, ...) \


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

@@ -54,12 +54,18 @@ struct RtData
const Port *port;
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 *msg);
virtual void chain(const char *path, const char *args, ...){};
virtual void chain(const char *msg){};
virtual void chainArray(const char *path, const char *args,
rtosc_arg_t *vals){};
virtual void broadcast(const char *path, const char *args, ...);
virtual void broadcast(const char *msg);
virtual void broadcastArray(const char *path, const char *args,
rtosc_arg_t *vals){};

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


+ 1
- 0
source/native-plugins/zynaddsubfx/rtosc/undo-history.h View File

@@ -13,6 +13,7 @@ class UndoHistory
//TODO think about the consequences of largish loads
public:
UndoHistory(void);
~UndoHistory(void);

//Records any undoable event
void recordEvent(const char *msg);


+ 46
- 0
source/native-plugins/zynaddsubfx/version.cpp View File

@@ -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");


+ 59
- 0
source/native-plugins/zynaddsubfx/version.h View File

@@ -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


Loading…
Cancel
Save