Browse Source

Update zynaddsubfx

tags/1.9.7
falkTX 10 years ago
parent
commit
60fe7319c6
100 changed files with 2806 additions and 1461 deletions
  1. +1
    -0
      source/native-plugins/zynaddsubfx-src.cpp
  2. +2
    -0
      source/native-plugins/zynaddsubfx-ui.cpp
  3. +285
    -0
      source/native-plugins/zynaddsubfx/Containers/NotePool.cpp
  4. +113
    -0
      source/native-plugins/zynaddsubfx/Containers/NotePool.h
  5. +1
    -1
      source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp
  6. +24
    -5
      source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp
  7. +0
    -1
      source/native-plugins/zynaddsubfx/Effects/EffectMgr.h
  8. +7
    -5
      source/native-plugins/zynaddsubfx/Misc/Allocator.h
  9. +4
    -4
      source/native-plugins/zynaddsubfx/Misc/Config.cpp
  10. +24
    -18
      source/native-plugins/zynaddsubfx/Misc/Master.cpp
  11. +6
    -2
      source/native-plugins/zynaddsubfx/Misc/Master.h
  12. +1
    -1
      source/native-plugins/zynaddsubfx/Misc/Microtonal.cpp
  13. +76
    -23
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
  14. +4
    -3
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.h
  15. +203
    -471
      source/native-plugins/zynaddsubfx/Misc/Part.cpp
  16. +22
    -19
      source/native-plugins/zynaddsubfx/Misc/Part.h
  17. +4
    -12
      source/native-plugins/zynaddsubfx/Misc/PresetExtractor.cpp
  18. +42
    -0
      source/native-plugins/zynaddsubfx/Misc/Time.h
  19. +2
    -2
      source/native-plugins/zynaddsubfx/Misc/Util.h
  20. +1
    -1
      source/native-plugins/zynaddsubfx/Misc/WavFile.cpp
  21. +1
    -1
      source/native-plugins/zynaddsubfx/Misc/WavFile.h
  22. +1
    -1
      source/native-plugins/zynaddsubfx/Nio/WavEngine.cpp
  23. +1
    -1
      source/native-plugins/zynaddsubfx/Nio/WavEngine.h
  24. +33
    -50
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp
  25. +2
    -4
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h
  26. +8
    -1
      source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp
  27. +5
    -4
      source/native-plugins/zynaddsubfx/Params/FilterParams.cpp
  28. +0
    -4
      source/native-plugins/zynaddsubfx/Params/LFOParams.cpp
  29. +8
    -1
      source/native-plugins/zynaddsubfx/Params/LFOParams.h
  30. +8
    -7
      source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp
  31. +4
    -2
      source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp
  32. +70
    -30
      source/native-plugins/zynaddsubfx/Synth/ADnote.cpp
  33. +7
    -3
      source/native-plugins/zynaddsubfx/Synth/ADnote.h
  34. +58
    -72
      source/native-plugins/zynaddsubfx/Synth/LFO.cpp
  35. +25
    -12
      source/native-plugins/zynaddsubfx/Synth/LFO.h
  36. +112
    -71
      source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp
  37. +1
    -1
      source/native-plugins/zynaddsubfx/Synth/OscilGen.h
  38. +13
    -6
      source/native-plugins/zynaddsubfx/Synth/PADnote.cpp
  39. +2
    -1
      source/native-plugins/zynaddsubfx/Synth/PADnote.h
  40. +1
    -1
      source/native-plugins/zynaddsubfx/Synth/Resonance.cpp
  41. +9
    -1
      source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp
  42. +3
    -1
      source/native-plugins/zynaddsubfx/Synth/SUBnote.h
  43. +3
    -3
      source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp
  44. +10
    -3
      source/native-plugins/zynaddsubfx/Synth/SynthNote.h
  45. +120
    -59
      source/native-plugins/zynaddsubfx/UI/ADnoteUI.fl
  46. +4
    -2
      source/native-plugins/zynaddsubfx/UI/BankUI.fl
  47. +2
    -2
      source/native-plugins/zynaddsubfx/UI/BankView.cpp
  48. +5
    -3
      source/native-plugins/zynaddsubfx/UI/ConfigUI.fl
  49. +5
    -1
      source/native-plugins/zynaddsubfx/UI/Connection.cpp
  50. +1
    -1
      source/native-plugins/zynaddsubfx/UI/ConnectionDummy.cpp
  51. +4
    -1
      source/native-plugins/zynaddsubfx/UI/EffUI.fl
  52. +117
    -47
      source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp
  53. +94
    -106
      source/native-plugins/zynaddsubfx/UI/EnvelopeUI.fl
  54. +3
    -0
      source/native-plugins/zynaddsubfx/UI/FilterUI.fl
  55. +1
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_DialF.cpp
  56. +3
    -2
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_ListView.cpp
  57. +1
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Numeric_Input.cpp
  58. +5
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Pane.H
  59. +29
    -2
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Pane.cpp
  60. +3
    -2
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Slider.H
  61. +68
    -3
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Slider.cpp
  62. +21
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_TSlider.H
  63. +65
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_TSlider.cpp
  64. +16
    -10
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_VSlider.H
  65. +40
    -61
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_VSlider.cpp
  66. +1
    -2
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.H
  67. +1
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.cpp
  68. +3
    -0
      source/native-plugins/zynaddsubfx/UI/LFOUI.fl
  69. +71
    -8
      source/native-plugins/zynaddsubfx/UI/MasterUI.fl
  70. +1
    -2
      source/native-plugins/zynaddsubfx/UI/MicrotonalUI.fl
  71. +9
    -9
      source/native-plugins/zynaddsubfx/UI/NioUI.cpp
  72. +2
    -2
      source/native-plugins/zynaddsubfx/UI/Osc_DataModel.h
  73. +2
    -2
      source/native-plugins/zynaddsubfx/UI/Osc_IntModel.h
  74. +2
    -2
      source/native-plugins/zynaddsubfx/UI/Osc_ListModel.h
  75. +2
    -2
      source/native-plugins/zynaddsubfx/UI/Osc_SimpleListModel.h
  76. +10
    -10
      source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl
  77. +1
    -2
      source/native-plugins/zynaddsubfx/UI/PADnoteUI.fl
  78. +7
    -11
      source/native-plugins/zynaddsubfx/UI/PartUI.fl
  79. +2
    -2
      source/native-plugins/zynaddsubfx/UI/PresetsUI.fl
  80. +1
    -1
      source/native-plugins/zynaddsubfx/UI/SUBnoteUI.fl
  81. +75
    -0
      source/native-plugins/zynaddsubfx/UI/TipWin.cpp
  82. +25
    -0
      source/native-plugins/zynaddsubfx/UI/TipWin.h
  83. +71
    -108
      source/native-plugins/zynaddsubfx/UI/WidgetPDial.cpp
  84. +10
    -0
      source/native-plugins/zynaddsubfx/UI/WidgetPDial.h
  85. +1
    -0
      source/native-plugins/zynaddsubfx/UI/guimain.cpp
  86. +5
    -2
      source/native-plugins/zynaddsubfx/globals.cpp
  87. +14
    -4
      source/native-plugins/zynaddsubfx/globals.h
  88. +25
    -4
      source/native-plugins/zynaddsubfx/main.cpp
  89. +2
    -2
      source/native-plugins/zynaddsubfx/rtosc/cpp/midimapper.cpp
  90. +1
    -1
      source/native-plugins/zynaddsubfx/rtosc/cpp/miditable.cpp
  91. +184
    -57
      source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp
  92. +12
    -4
      source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp
  93. +1
    -4
      source/native-plugins/zynaddsubfx/rtosc/cpp/thread-link.cpp
  94. +2
    -2
      source/native-plugins/zynaddsubfx/rtosc/cpp/undo-history.cpp
  95. +211
    -1
      source/native-plugins/zynaddsubfx/rtosc/dispatch.c
  96. +4
    -2
      source/native-plugins/zynaddsubfx/rtosc/miditable.h
  97. +29
    -5
      source/native-plugins/zynaddsubfx/rtosc/port-sugar.h
  98. +8
    -1
      source/native-plugins/zynaddsubfx/rtosc/ports.h
  99. +166
    -58
      source/native-plugins/zynaddsubfx/rtosc/rtosc.c
  100. +31
    -0
      source/native-plugins/zynaddsubfx/rtosc/rtosc.h

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

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

// zynaddsubfx includes
#include "zynaddsubfx/Containers/NotePool.cpp"
#include "zynaddsubfx/DSP/AnalogFilter.cpp"
#include "zynaddsubfx/DSP/FFTwrapper.cpp"
#include "zynaddsubfx/DSP/Filter.cpp"


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

@@ -91,6 +91,7 @@ extern "C" {
#include "zynaddsubfx/UI/Fl_Osc_Pane.cpp"
#include "zynaddsubfx/UI/Fl_Osc_Roller.cpp"
#include "zynaddsubfx/UI/Fl_Osc_Slider.cpp"
#include "zynaddsubfx/UI/Fl_Osc_TSlider.cpp"
#include "zynaddsubfx/UI/Fl_Osc_Value.cpp"
#include "zynaddsubfx/UI/Fl_Osc_VSlider.cpp"
#include "zynaddsubfx/UI/Fl_Osc_Widget.cpp"
@@ -106,6 +107,7 @@ extern "C" {
#include "zynaddsubfx/UI/PresetsUI.cpp"
#include "zynaddsubfx/UI/ResonanceUI.cpp"
#include "zynaddsubfx/UI/SUBnoteUI.cpp"
#include "zynaddsubfx/UI/TipWin.cpp"
#include "zynaddsubfx/UI/VirKeyboard.cpp"
#include "zynaddsubfx/UI/guimain.cpp"



+ 285
- 0
source/native-plugins/zynaddsubfx/Containers/NotePool.cpp View File

@@ -0,0 +1,285 @@
#include "NotePool.h"
//XXX eliminate dependence on Part.h
#include "../Misc/Part.h"
#include "../Misc/Allocator.h"
#include "../Synth/SynthNote.h"
#include <cstring>
#include <cassert>

NotePool::NotePool(void)
:needs_cleaning(0)
{
memset(ndesc, 0, sizeof(ndesc));
memset(sdesc, 0, sizeof(ndesc));
}
NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n)
{
const int off_d1 = &n-ndesc;
int off_d2 = 0;
assert(off_d1 <= POLYPHONY);
for(int i=0; i<off_d1; ++i)
off_d2 += ndesc[i].size;
return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size};
}

bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd)
{
return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status;
}

//return either the first unused descriptor or the last valid descriptor which
//matches note/sendto
static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
NotePool::NoteDescriptor *ndesc)
{
int desc_id = 0;
for(int i=0; i<POLYPHONY; ++i, ++desc_id)
if(ndesc[desc_id].status == Part::KEY_OFF)
break;

//Out of free descriptors
if(ndesc[desc_id].status != Part::KEY_OFF)
return -1;

if(desc_id != 0) {
auto &nd = ndesc[desc_id-1];
if(nd.age == 0 && nd.note == note && nd.sendto == sendto
&& nd.status == Part::KEY_PLAYING && nd.legatoMirror == legato)
return desc_id-1;
}
return desc_id;
}
NotePool::activeDescIter NotePool::activeDesc(void)
{
cleanup();
return activeDescIter{*this};
}

NotePool::constActiveDescIter NotePool::activeDesc(void) const
{
const_cast<NotePool*>(this)->cleanup();
return constActiveDescIter{*this};
}

void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
{
//Get first free note descriptor
int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc);
assert(desc_id != -1);

ndesc[desc_id].note = note;
ndesc[desc_id].sendto = sendto;
ndesc[desc_id].size += 1;
ndesc[desc_id].status = Part::KEY_PLAYING;
ndesc[desc_id].legatoMirror = legato;

//Get first free synth descriptor
int sdesc_id = 0;
while(sdesc[sdesc_id].note)
sdesc_id++;
sdesc[sdesc_id] = desc;
};

void NotePool::upgradeToLegato(void)
{
for(auto &d:activeDesc())
if(d.status == Part::KEY_PLAYING)
for(auto &s:activeNotes(d))
insertLegatoNote(d.note, d.sendto, s);
}

void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc)
{
assert(desc.note);
desc.note = desc.note->cloneLegato();
insertNote(note, sendto, desc, true);
};

//There should only be one pair of notes which are still playing
void NotePool::applyLegato(LegatoParams &par)
{
for(auto &desc:activeDesc()) {
desc.note = par.midinote;
for(auto &synth:activeNotes(desc))
synth.note->legatonote(par);
}
};

//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
bool NotePool::existsRunningNote(void) const
{
//printf("runing note # =%d\n", getRunningNotes());
return getRunningNotes();
}

int NotePool::getRunningNotes(void) const
{
bool running[256] = {0};
for(auto &desc:activeDesc()) {
//printf("note!(%d)\n", desc.note);
if(desc.status == Part::KEY_PLAYING)
running[desc.note] = true;
}

int running_count = 0;
for(int i=0; i<256; ++i)
running_count += running[i];

return running_count;
}
int NotePool::enforceKeyLimit(int limit) const
{
//{
//int oldestnotepos = -1;
//if(notecount > keylimit) //find out the oldest note
// for(int i = 0; i < POLYPHONY; ++i) {
// int maxtime = 0;
// if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
// maxtime = partnote[i].time;
// oldestnotepos = i;
// }
// }
//if(oldestnotepos != -1)
// ReleaseNotePos(oldestnotepos);
//}
printf("Unimplemented enforceKeyLimit()\n");
return -1;
}

void NotePool::releasePlayingNotes(void)
{
for(auto &d:activeDesc()) {
if(d.status == Part::KEY_PLAYING) {
d.status = Part::KEY_RELEASED;
for(auto s:activeNotes(d))
s.note->releasekey();
}
}
}

void NotePool::release(NoteDescriptor &d)
{
d.status = Part::KEY_RELEASED;
for(auto s:activeNotes(d))
s.note->releasekey();
}

void NotePool::killAllNotes(void)
{
for(auto &d:activeDesc())
kill(d);
}

void NotePool::killNote(uint8_t note)
{
for(auto &d:activeDesc()) {
if(d.note == note)
kill(d);
}
}

void NotePool::kill(NoteDescriptor &d)
{
d.status = Part::KEY_OFF;
for(auto &s:activeNotes(d))
kill(s);
}

void NotePool::kill(SynthDescriptor &s)
{
//printf("Kill synth...\n");
s.note->memory.dealloc(s.note);
needs_cleaning = true;
}

const char *getStatus(int status_bits)
{
switch(status_bits)
{
case 0: return "OFF ";
case 1: return "PLAY";
case 2: return "SUST";
case 3: return "RELA";
default: return "INVD";
}
}

void NotePool::cleanup(void)
{
if(!needs_cleaning)
return;
needs_cleaning = false;
int new_length[POLYPHONY] = {0};
int cur_length[POLYPHONY] = {0};
//printf("Cleanup Start\n");
//dump();

//Identify the current length of all segments
//and the lengths discarding invalid entries

int last_valid_desc = 0;
for(int i=0; i<POLYPHONY; ++i)
if(ndesc[i].status != Part::KEY_OFF)
last_valid_desc = i;

//Find the real numbers of allocated notes
{
int cum_old = 0;

for(int i=0; i<=last_valid_desc; ++i) {
cur_length[i] = ndesc[i].size;
for(int j=0; j<ndesc[i].size; ++j)
new_length[i] += (bool)sdesc[cum_old++].note;
}
}


//Move the note descriptors
{
int cum_new = 0;
for(int i=0; i<=last_valid_desc; ++i) {
ndesc[i].size = new_length[i];
if(new_length[i] != 0)
ndesc[cum_new++] = ndesc[i];
else
ndesc[i].status = Part::KEY_OFF;
}
memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
}

//Move the synth descriptors
{
int total_notes=0;
for(int i=0; i<=last_valid_desc; ++i)
total_notes+=cur_length[i];

int cum_new = 0;
for(int i=0; i<total_notes; ++i)
if(sdesc[i].note)
sdesc[cum_new++] = sdesc[i];
memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new));
}
//printf("Cleanup Done\n");
//dump();
}

void NotePool::dump(void)
{
printf("NotePool::dump<\n");
const char *format =
" Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n";
int note_id=0;
int descriptor_id=0;
for(auto &d:activeDesc()) {
descriptor_id += 1;
for(auto &s:activeNotes(d)) {
note_id += 1;
printf(format,
note_id, descriptor_id,
d.age, d.note, d.sendto,
getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note);
}
}
printf(">NotePool::dump\n");
}

+ 113
- 0
source/native-plugins/zynaddsubfx/Containers/NotePool.h View File

@@ -0,0 +1,113 @@
#pragma once
#include <stdint.h>
#include <functional>
#include "../globals.h"

//Expected upper bound of synths given that max polyphony is hit
#define EXPECTED_USAGE 3

struct LegatoParams;
class NotePool
{
public:
typedef uint8_t note_t;
//Currently this wastes a ton of bits due ot the legatoMirror flag
struct NoteDescriptor {
//acceptable overlap after 2 minutes
//run time at 48kHz 8 samples per buffer
//19 bit minimum
uint32_t age;
uint8_t note;
uint8_t sendto;
//max of 16 kit elms and 3 kit items per
uint8_t size;
uint8_t status;
bool legatoMirror;
bool operator==(NoteDescriptor);
};

//To be pedantic this wastes 2 or 6 bytes per descriptor
//depending on 32bit/64bit alignment rules
struct SynthDescriptor {
SynthNote *note;
uint8_t type;
uint8_t kit;
};


//Pool of notes
NoteDescriptor ndesc[POLYPHONY];
SynthDescriptor sdesc[POLYPHONY*EXPECTED_USAGE];
bool needs_cleaning;


//Iterators
struct activeNotesIter {
SynthDescriptor *begin() {return _b;};
SynthDescriptor *end() {return _e;};
SynthDescriptor *_b;
SynthDescriptor *_e;
};

struct activeDescIter {
activeDescIter(NotePool &_np):np(_np)
{
int off=0;
for(int i=0; i<POLYPHONY; ++i, ++off)
if(np.ndesc[i].status == 0)
break;
_end = np.ndesc+off;
}
NoteDescriptor *begin() {return np.ndesc;};
NoteDescriptor *end() { return _end; };
NoteDescriptor *_end;
NotePool &np;
};

struct constActiveDescIter {
constActiveDescIter(const NotePool &_np):np(_np)
{
int off=0;
for(int i=0; i<POLYPHONY; ++i, ++off)
if(np.ndesc[i].status == 0)
break;
_end = np.ndesc+off;
}
const NoteDescriptor *begin() const {return np.ndesc;};
const NoteDescriptor *end() const { return _end; };
const NoteDescriptor *_end;
const NotePool &np;
};

activeNotesIter activeNotes(NoteDescriptor &n);

activeDescIter activeDesc(void);
constActiveDescIter activeDesc(void) const;

NotePool(void);

//Operations
void insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato=false);
void insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc);

void upgradeToLegato(void);
void applyLegato(LegatoParams &par);

//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
bool existsRunningNote(void) const;
int getRunningNotes(void) const;
int enforceKeyLimit(int limit) const;

void releasePlayingNotes(void);
void releaseNote(note_t note);
void release(NoteDescriptor &d);

void killAllNotes(void);
void killNote(note_t note);
void kill(NoteDescriptor &d);
void kill(SynthDescriptor &s);

void cleanup(void);

void dump(void);
};

+ 1
- 1
source/native-plugins/zynaddsubfx/DSP/FormantFilter.cpp View File

@@ -71,7 +71,7 @@ FormantFilter::FormantFilter(FilterParams *pars, Allocator *alloc, unsigned int
outgain = dB2rap(pars->getgain());

oldinput = -1.0f;
Qfactor = 1.0f;
Qfactor = pars->getq();
oldQfactor = Qfactor;
firsttime = 1;
}


+ 24
- 5
source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp View File

@@ -45,7 +45,8 @@ static const rtosc::Ports local_ports = {
rSelf(EffectMgr),
rPaste,
rRecurp(filterpars, "Filter Parameter for Dynamic Filter"),
{"parameter#128::i", rProp(alias) rDoc("Parameter Accessor"), NULL,
{"parameter#128::i:T:F", rProp(parameter) rProp(alias) rDoc("Parameter Accessor"),
NULL,
[](const char *msg, rtosc::RtData &d)
{
EffectMgr *eff = (EffectMgr*)d.obj;
@@ -54,20 +55,37 @@ static const rtosc::Ports local_ports = {

if(!rtosc_narguments(msg))
d.reply(d.loc, "i", eff->geteffectparrt(atoi(mm)));
else {
else if(rtosc_type(msg, 0) == 'i'){
eff->seteffectparrt(atoi(mm), rtosc_argument(msg, 0).i);
d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
} else if(rtosc_type(msg, 0) == 'T'){
eff->seteffectparrt(atoi(mm), 127);
d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
} else if(rtosc_type(msg, 0) == 'F'){
eff->seteffectparrt(atoi(mm), 0);
d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
}
}},
{"preset::i", rProp(alias) rDoc("Effect Preset Selector"), NULL,
{"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector"), NULL,
[](const char *msg, rtosc::RtData &d)
{
char loc[1024];
EffectMgr *eff = (EffectMgr*)d.obj;
if(!rtosc_narguments(msg))
d.reply(d.loc, "i", eff->getpreset());
else {
eff->changepresetrt(rtosc_argument(msg, 0).i);
d.broadcast(d.loc, "i", eff->getpreset());

//update parameters as well
strncpy(loc, d.loc, 1024);
char *tail = rindex(loc, '/');
if(!tail)
return;
for(int i=0;i<128;++i) {
sprintf(tail+1, "parameter%d", i);
d.broadcast(loc, "i", eff->geteffectparrt(i));
}
}
}},
{"eq-coeffs:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL,
@@ -84,7 +102,8 @@ static const rtosc::Ports local_ports = {
eq->getFilter(a,b);
d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b);
}},
{"efftype::i", rDoc("Get Effect Type"), NULL, [](const char *m, rtosc::RtData &d)
{"efftype::i", rProp(parameter) rDoc("Get Effect Type"), NULL,
[](const char *m, rtosc::RtData &d)
{
EffectMgr *eff = (EffectMgr*)d.obj;
if(rtosc_narguments(m)) {
@@ -385,7 +404,7 @@ void EffectMgr::paste(EffectMgr &e)
changeeffectrt(e.nefx, true);
changepresetrt(e.preset, true);
for(int i=0;i<128;++i)
seteffectparrt(e.settings[i], i);
seteffectparrt(i, e.settings[i]);
}

void EffectMgr::add2XML(XMLwrapper *xml)


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

@@ -80,7 +80,6 @@ class EffectMgr:public Presets
private:

//Parameters Prior to initialization
char effect_id;
char preset;
char settings[128];



+ 7
- 5
source/native-plugins/zynaddsubfx/Misc/Allocator.h View File

@@ -86,12 +86,14 @@ class Allocator
//! the allocator for normal use
class AllocatorClass : public Allocator
{
void *alloc_mem(size_t mem_size);
void dealloc_mem(void *memory);
void addMemory(void *, size_t mem_size);
bool lowMemory(unsigned n, size_t chunk_size) const;
using Allocator::Allocator;
public:
void *alloc_mem(size_t mem_size);
void dealloc_mem(void *memory);
void addMemory(void *, size_t mem_size);
bool lowMemory(unsigned n, size_t chunk_size) const;
using Allocator::Allocator;
};
typedef AllocatorClass Alloc;

//! the dummy allocator, which does not allow any allocation
class DummyAllocator : public Allocator


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

@@ -32,7 +32,7 @@
#include "XMLwrapper.h"

#define rStdString(name, len, ...) \
{STRINGIFY(name) "::s", rMap(length, len) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}
{STRINGIFY(name) "::s", rMap(length, len) rProp(parameter) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}
#define rStdStringCb(name, length) rBOIL_BEGIN \
if(!strcmp("", args)) {\
data.reply(loc, "s", obj->name); \
@@ -57,7 +57,7 @@ static const rtosc::Ports ports = {
rToggle(cfg.BankUIAutoClose, "Automatic Closing of BackUI After Patch Selection"),
rParamI(cfg.GzipCompression, "Level of Gzip Compression For Save Files"),
rParamI(cfg.Interpolation, "Level of Interpolation, Linear/Cubic"),
{"cfg.presetsDirList", rProp(parameter) rDoc("list of preset search directories"), 0,
{"cfg.presetsDirList", rDoc("list of preset search directories"), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
@@ -90,7 +90,7 @@ static const rtosc::Ports ports = {
rtosc_amessage(buffer, sizeof(buffer), d.loc, types, args);
d.reply(buffer);
}},
{"cfg.bankRootDirList", rProp(parameter) rDoc("list of bank search directories"), 0,
{"cfg.bankRootDirList", rDoc("list of bank search directories"), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
@@ -133,7 +133,7 @@ static const rtosc::Ports ports = {
rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"),
//rParamS(cfg.LinuxALSAaudioDev),
//rParamS(cfg.nameTag)
{"cfg.OscilPower::i", rDoc("Size Of Oscillator Wavetable"), 0,
{"cfg.OscilPower::i", rProp(parameter) rDoc("Size Of Oscillator Wavetable"), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;


+ 24
- 18
source/native-plugins/zynaddsubfx/Misc/Master.cpp View File

@@ -53,7 +53,9 @@ using namespace rtosc;

static const Ports sysefxPort =
{
{"part#" STRINGIFY(NUM_MIDI_PARTS) "::i", 0, 0, [](const char *m, RtData&d)
{"part#" STRINGIFY(NUM_MIDI_PARTS) "::i", rProp(parameter)
rDoc("gain on part to sysefx routing"), 0,
[](const char *m, RtData&d)
{
//ok, this is going to be an ugly workaround
//we know that if we are here the message previously MUST have
@@ -80,7 +82,8 @@ static const Ports sysefxPort =

static const Ports sysefsendto =
{
{"to#" STRINGIFY(NUM_SYS_EFX) "::i", 0, 0, [](const char *m, RtData&d)
{"to#" STRINGIFY(NUM_SYS_EFX) "::i",
rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d)
{
//same ugly workaround as before
const char *index_1 = m;
@@ -103,6 +106,7 @@ static const Ports sysefsendto =
};

static const Ports master_ports = {
rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."),
rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS
rRecursp(sysefx, 4, "System Effect"),//NUM_SYS_EFX
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX
@@ -112,10 +116,10 @@ static const Ports master_ports = {
rArrayI(Pinsparts, NUM_INS_EFX, "Part to insert part onto"),
{"echo", rDoc("Hidden port to echo messages"), 0, [](const char *m, RtData&d) {
d.reply(m-1);}},
{"get-vu", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
{"get-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
Master *m = (Master*)d.obj;
d.reply("/vu-meter", "bb", sizeof(m->vu), &m->vu, sizeof(float)*NUM_MIDI_PARTS, m->vuoutpeakpart);}},
{"reset-vu", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
{"reset-vu:", rDoc("Grab VU Data"), 0, [](const char *, RtData &d) {
Master *m = (Master*)d.obj;
m->vuresetpeaks();}},
{"load-part:ib", rProp(internal) rDoc("Load Part From Middleware"), 0, [](const char *msg, RtData &d) {
@@ -129,14 +133,14 @@ static const Ports master_ports = {
p->initialize_rt();
//printf("part %d is now pointer %p\n", i, p);
}},
{"Pvolume::i", rDoc("Master Volume"), 0,
{"Pvolume::i", rProp(parameter) 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", rDoc("Master Volume"), 0,
{"volume::i", rProp(parameter) rDoc("Master Volume"), 0,
[](const char *m, rtosc::RtData &d) {
if(rtosc_narguments(m)==0) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
@@ -200,7 +204,8 @@ static const Ports master_ports = {
[](const char *m, RtData &d){
Master *M = (Master*)d.obj;
M->midi.clear_entry(rtosc_argument(m,0).s);}},
{"close-ui", rDoc("Request to close any connection named \"GUI\""), 0, [](const char *, RtData &d) {
{"close-ui:", rDoc("Request to close any connection named \"GUI\""), 0,
[](const char *, RtData &d) {
d.reply("/close-ui", "");}},
{"add-rt-memory:bi", rProp(internal) rDoc("Add Additional Memory To RT MemPool"), 0,
[](const char *msg, RtData &d)
@@ -220,12 +225,13 @@ static const Ports master_ports = {
d.reply("/oscilsize", "f", m.synth.oscilsize_f);
d.reply("/oscilsize", "i", m.synth.oscilsize);
}},
{"undo_pause",0,0,[](const char *, rtosc::RtData &d)
{d.reply("/undo_pause", "");}},
{"undo_resume",0,0,[](const char *, rtosc::RtData &d)
{d.reply("/undo_resume", "");}},
{"config/", 0, &Config::ports, [](const char *, rtosc::RtData &){}},
{"presets/", 0, &preset_ports, rBOIL_BEGIN
{"undo_pause:",rProp(internal) rDoc("pause undo event recording"),0,
[](const char *, rtosc::RtData &d) {d.reply("/undo_pause", "");}},
{"undo_resume:",rProp(internal) rDoc("resume undo event recording"),0,
[](const char *, rtosc::RtData &d) {d.reply("/undo_resume", "");}},
{"config/", rDoc("Top Level Application Configuration Parameters"), &Config::ports,
[](const char *, rtosc::RtData &){}},
{"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN
SNIP
preset_ports.dispatch(msg, data);
rBOIL_END},
@@ -292,7 +298,7 @@ Master::Master(const SYNTH_T &synth_, Config* config)
:HDDRecorder(synth_), ctl(synth_),
microtonal(config->cfg.GzipCompression), bank(config),
midi(Master::ports), frozenState(false), pendingMemory(false),
synth(synth_), gzip_compression(config->cfg.GzipCompression)
synth(synth_), time(synth), gzip_compression(config->cfg.GzipCompression)
{
bToU = NULL;
uToB = NULL;
@@ -306,6 +312,7 @@ Master::Master(const SYNTH_T &synth_, Config* config)
the_master = this;
#endif

last_xmz[0] = 0;
fft = new FFTwrapper(synth.oscilsize);

shutup = 0;
@@ -315,7 +322,7 @@ Master::Master(const SYNTH_T &synth_, Config* config)
}

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

//Insertion Effects init
@@ -819,8 +826,8 @@ void Master::AudioOut(float *outl, float *outr)
ShutUp();
}

//update the LFO's time
LFOParams::time++;
//update the global frame timer
time++;
}

//TODO review the respective code from yoshimi for this
@@ -1056,7 +1063,6 @@ int Master::saveXML(const char *filename)
}



int Master::loadXML(const char *filename)
{
XMLwrapper *xml = new XMLwrapper();


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

@@ -28,6 +28,7 @@
#include <rtosc/miditable.h>
#include <rtosc/ports.h>

#include "Time.h"
#include "Bank.h"
#include "Recorder.h"

@@ -53,6 +54,8 @@ class Master
/** Destructor*/
~Master();

char last_xmz[XMZ_PATH_MAX];

void applyOscEvent(const char *event);

/**Saves all settings to a XML file
@@ -64,7 +67,6 @@ class Master

void defaults();


/**loads all settings from a XML file
* @return 0 for ok or -1 if there is an error*/
int loadXML(const char *filename);
@@ -99,7 +101,8 @@ class Master

/**Audio Output*/
void AudioOut(float *outl, float *outr) REALTIME;
/**Audio Output (for callback mode). This allows the program to be controled by an external program*/
/**Audio Output (for callback mode).
* This allows the program to be controled by an external program*/
void GetAudioOutSamples(size_t nsamples,
unsigned samplerate,
float *outl,
@@ -171,6 +174,7 @@ class Master
rtosc::ThreadLink *uToB;
bool pendingMemory;
const SYNTH_T &synth;
AbsTime time;
const int& gzip_compression; //!< value from config
private:
float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];


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

@@ -67,7 +67,7 @@ const rtosc::Ports Microtonal::ports = {
rString(Pname, MICROTONAL_MAX_NAME_LEN, "Microtonal Name"),
rString(Pcomment, MICROTONAL_MAX_NAME_LEN, "Microtonal Name"),

{"octavesize:", 0, 0, [](const char*, RtData &d)
{"octavesize:", rDoc("Get octave size"), 0, [](const char*, RtData &d)
{
Microtonal &m = *(Microtonal*)d.obj;
d.reply(d.loc, "i", m.getoctavesize());


+ 76
- 23
source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp View File

@@ -236,6 +236,11 @@ void rescanForBanks(Bank &bank, std::function<void(const char*)> cb)

void loadBank(Bank &bank, int pos, std::function<void(const char*)> cb)
{
char response[2048];
if(!rtosc_message(response, 2048, "/loadbank", "i", pos))
errx(1, "Failure to handle bank update properly...");
if(cb)
cb(response);
if(bank.bankpos != pos) {
bank.bankpos = pos;
bank.loadbank(bank.banks[pos].dir);
@@ -433,13 +438,13 @@ namespace Nio
using std::get;
using rtosc::rtMsg;
rtosc::Ports ports = {
{"sink-list:", 0, 0, [](const char *msg, rtosc::RtData &d) {
{"sink-list:", 0, 0, [](const char *, rtosc::RtData &d) {
auto list = Nio::getSinks();
char *ret = rtosc_splat(d.loc, list);
d.reply(ret);
delete [] ret;
}},
{"source-list:", 0, 0, [](const char *msg, rtosc::RtData &d) {
{"source-list:", 0, 0, [](const char *, rtosc::RtData &d) {
auto list = Nio::getSources();
char *ret = rtosc_splat(d.loc, list);
d.reply(ret);
@@ -489,7 +494,7 @@ public:
void doReadOnlyOp(std::function<void()> read_only_fn);


void saveBankSlot(int npart, int nslot, Master *master, Fl_Osc_Interface *osc)
void saveBankSlot(int npart, int nslot, Master *master)
{
int err = 0;
doReadOnlyOp([master,nslot,npart,&err](){
@@ -502,7 +507,7 @@ public:
}
}

void renameBankSlot(int slot, string name, Master *master, Fl_Osc_Interface *osc)
void renameBankSlot(int slot, string name, Master *master)
{
int err = master->bank.setname(slot, name, -1);
if(err) {
@@ -513,7 +518,7 @@ public:
}
}

void swapBankSlot(int slota, int slotb, Master *master, Fl_Osc_Interface *osc)
void swapBankSlot(int slota, int slotb, Master *master)
{
int err = master->bank.swapslot(slota, slotb);
if(err) {
@@ -524,7 +529,7 @@ public:
}
}

void clearBankSlot(int slot, Master *master, Fl_Osc_Interface *osc)
void clearBankSlot(int slot, Master *master)
{
int err = master->bank.clearslot(slot);
if(err) {
@@ -557,7 +562,14 @@ public:
/*printf("results: '%s' '%d'\n",fname.c_str(), res);*/});
}

void loadPart(int npart, const char *filename, Master *master, Fl_Osc_Interface *osc)
void loadPendingBank(int par, Bank &bank)
{
if(((unsigned int)par < bank.banks.size())
&& (bank.banks[par].dir != bank.bankfiletitle))
bank.loadbank(bank.banks[par].dir);
}

void loadPart(int npart, const char *filename, Master *master)
{
actual_load[npart]++;

@@ -565,9 +577,12 @@ public:
return;
assert(actual_load[npart] <= pending_load[npart]);

//load part in async fashion when possible
#if HAVE_ASYNC
auto alloc = std::async(std::launch::async,
[master,filename,this,npart](){
Part *p = new Part(*master->memory, synth,
master->time,
config->cfg.GzipCompression,
config->cfg.Interpolation,
&master->microtonal, master->fft);
@@ -589,6 +604,20 @@ public:
}

Part *p = alloc.get();
#else
Part *p = new Part(*master->memory, synth, master->time,
config->cfg.GzipCompression,
config->cfg.Interpolation,
&master->microtonal, master->fft);
if(p->loadXMLinstrument(filename))
fprintf(stderr, "Warning: failed to load part<%s>!\n", filename);

auto isLateLoad = [this,npart]{
return actual_load[npart] != pending_load[npart];
};

p->applyparameters(isLateLoad);
#endif

obj_store.extractPart(p, npart);
kits.extractPart(p, npart);
@@ -605,6 +634,7 @@ public:
if(npart == -1)
return;
Part *p = new Part(*master->memory, synth,
master->time,
config->cfg.GzipCompression,
config->cfg.Interpolation,
&master->microtonal, master->fft);
@@ -628,7 +658,10 @@ public:
m->uToB = uToB;
m->bToU = bToU;
if(filename) {
m->loadXML(filename);
if ( m->loadXML(filename) ) {
delete m;
return;
}
m->applyparameters();
}

@@ -658,7 +691,8 @@ public:

void tick(void)
{
while(lo_server_recv_noblock(server, 0));
if(server)
while(lo_server_recv_noblock(server, 0));
while(bToU->hasNext()) {
const char *rtmsg = bToU->read();
bToUhandle(rtmsg);
@@ -815,13 +849,19 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_,
LO_UDP, liblo_error_cb);
else
server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb);
lo_server_add_method(server, NULL, NULL, handler_function, mw);
fprintf(stderr, "lo server running on %d\n", lo_server_get_port(server));

if(server) {
lo_server_add_method(server, NULL, NULL, handler_function, mw);
fprintf(stderr, "lo server running on %d\n", lo_server_get_port(server));
} else
fprintf(stderr, "lo server could not be started :-/\n");


#ifndef PLUGINVERSION
if(!isPlugin()) {
clean_up_tmp_nams();
create_tmp_file((unsigned)lo_server_get_port(server));
if(server)
create_tmp_file((unsigned)lo_server_get_port(server));
}
#endif

@@ -869,7 +909,8 @@ MiddleWareImpl::~MiddleWareImpl(void)

warnMemoryLeaks();

lo_server_free(server);
if(server)
lo_server_free(server);

delete master;
delete osc;
@@ -966,7 +1007,10 @@ void MiddleWareImpl::bToUhandle(const char *rtmsg, bool dummy)
uToB->write("/add-rt-memory", "bi", sizeof(void*), &mem, N);
} else if(!strcmp(rtmsg, "/setprogram")
&& !strcmp(rtosc_argument_string(rtmsg),"cc")) {
loadPart(rtosc_argument(rtmsg,0).i, master->bank.ins[rtosc_argument(rtmsg,1).i].filename.c_str(), master, osc);
loadPart(rtosc_argument(rtmsg,0).i, master->bank.ins[rtosc_argument(rtmsg,1).i].filename.c_str(), master);
} else if(!strcmp(rtmsg, "/setbank")
&& !strcmp(rtosc_argument_string(rtmsg), "c")) {
loadPendingBank(rtosc_argument(rtmsg,0).i, master->bank);
} else if(!strcmp("/undo_pause", rtmsg)) {
recording_undo = false;
} else if(!strcmp("/undo_resume", rtmsg)) {
@@ -1148,7 +1192,7 @@ void MiddleWareImpl::handleMsg(const char *msg)
if(last_url == "GUI")
bank_cb = [this](const char *msg){if(osc)osc->tryLink(msg);};
else
bank_cb = [this](const char *msg){this->bToUhandle(msg, 1);};
bank_cb = [this](const char *msg){if(osc)osc->tryLink(msg);this->bToUhandle(msg, 1);};

if(!strcmp(msg, "/refresh_bank") && !strcmp(rtosc_argument_string(msg), "i")) {
refreshBankView(master->bank, rtosc_argument(msg,0).i, bank_cb);
@@ -1184,22 +1228,22 @@ void MiddleWareImpl::handleMsg(const char *msg)
loadMaster(NULL);
} else if(!strcmp(msg, "/load_xiz") && !strcmp(rtosc_argument_string(msg), "is")) {
pending_load[rtosc_argument(msg,0).i]++;
loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master);
} else if(strstr(msg, "load-part") && !strcmp(rtosc_argument_string(msg), "is")) {
pending_load[rtosc_argument(msg,0).i]++;
loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master);
} else if(!strcmp(msg, "/setprogram")
&& !strcmp(rtosc_argument_string(msg),"c")) {
pending_load[0]++;
loadPart(0, master->bank.ins[rtosc_argument(msg,0).i].filename.c_str(), master, osc);
loadPart(0, master->bank.ins[rtosc_argument(msg,0).i].filename.c_str(), master);
} else if(strstr(msg, "save-bank-part") && !strcmp(rtosc_argument_string(msg), "ii")) {
saveBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master, osc);
saveBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master);
} else if(strstr(msg, "bank-rename") && !strcmp(rtosc_argument_string(msg), "is")) {
renameBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc);
renameBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master);
} else if(strstr(msg, "swap-bank-slots") && !strcmp(rtosc_argument_string(msg), "ii")) {
swapBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master, osc);
swapBankSlot(rtosc_argument(msg,0).i, rtosc_argument(msg,1).i, master);
} else if(strstr(msg, "clear-bank-slot") && !strcmp(rtosc_argument_string(msg), "i")) {
clearBankSlot(rtosc_argument(msg,0).i, master, osc);
clearBankSlot(rtosc_argument(msg,0).i, master);
} else if(strstr(msg, "/config/")) {
handleConfig(msg);
} else if(strstr(msg, "/presets/")) {
@@ -1215,6 +1259,8 @@ void MiddleWareImpl::handleMsg(const char *msg)
undo.seekHistory(-1);
} else if(!strcmp(msg, "/redo")) {
undo.seekHistory(+1);
} else if(!strcmp(msg, "/ui/title")) {
;//drop the message into the abyss
} else
uToB->raw_write(msg);
}
@@ -1316,6 +1362,10 @@ void MiddleWare::transmitMsg(const char *path, const char *args, va_list va)
fprintf(stderr, "Error in transmitMsg(va)n");
}

void MiddleWare::pendingSetBank(int bank)
{
impl->bToU->write("/setbank", "c", bank);
}
void MiddleWare::pendingSetProgram(int part, int program)
{
impl->pending_load[part]++;
@@ -1339,7 +1389,10 @@ const SYNTH_T &MiddleWare::getSynth(void) const

const char* MiddleWare::getServerAddress(void) const
{
return lo_server_get_url(impl->server);
if(impl->server)
return lo_server_get_url(impl->server);
else
return "NULL";
}

const PresetsStore& MiddleWare::getPresetsStore() const


+ 4
- 3
source/native-plugins/zynaddsubfx/Misc/MiddleWare.h View File

@@ -4,15 +4,14 @@
#include <string>

struct SYNTH_T;
class Config;
class Master;
class Master;
class PresetsStore;

//Link between realtime and non-realtime layers
class MiddleWare
{
public:
MiddleWare(SYNTH_T synth, Config *config,
MiddleWare(SYNTH_T synth, class Config *config,
int preferred_port = -1);
~MiddleWare(void);
void updateResources(Master *m);
@@ -34,6 +33,8 @@ class MiddleWare
void transmitMsg(const char *, const char *args, ...);
//Handle a rtosc Message uToB
void transmitMsg(const char *, const char *args, va_list va);
//Indicate that a bank will be loaded
void pendingSetBank(int bank);
//Indicate that a program will be loaded on a known part
void pendingSetProgram(int part, int program);
//Get/Set the active bToU url


+ 203
- 471
source/native-plugins/zynaddsubfx/Misc/Part.cpp View File

@@ -73,7 +73,8 @@ static const Ports partPorts = {
rToggle(Pnoteon, "If the channel accepts note on events"),
//TODO FIXME Change to 0=OFF 1=MULTI 2=SINGLE
rParamI(Pkitmode, "Kit mode enable"),
rToggle(Pdrummode, "Drum mode enable"),
rToggle(Pdrummode, "Drum mode enable\n"
"When drum mode is enabled all keys are mapped to 12tET and legato is disabled"),
rToggle(Ppolymode, "Polyphoney mode"),
rToggle(Plegatomode, "Legato enable"),
rParamZyn(info.Ptype, "Class of Instrument"),
@@ -82,11 +83,15 @@ static const Ports partPorts = {
rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"),
rArray(Pefxroute, NUM_PART_EFX, "Effect Routing"),
rArrayT(Pefxbypass, NUM_PART_EFX, "If an effect is bypassed"),
{"captureMin:", NULL, NULL, [](const char *, RtData &r)
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
{Part *p = (Part*)r.obj; p->Pminkey = p->lastnote;}},
{"captureMax:", NULL, NULL, [](const char *, RtData &r)
{"captureMax:", rDoc("Capture maximum valid note"), NULL,
[](const char *, RtData &r)
{Part *p = (Part*)r.obj; p->Pmaxkey = p->lastnote;}},
{"polyType::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"polyType::c:i", rProp(parameter) rOptions(Polyphonic, Monophonic, Legato)
rDoc("synthesis polyphony type"), NULL,
[](const char *msg, RtData &d)
{
Part *p = (Part*)d.obj;
if(!rtosc_narguments(msg)) {
@@ -108,7 +113,8 @@ static const Ports partPorts = {
p->Ppolymode = 0;
p->Plegatomode = 1;
}}},
{"clear:", rProp(internal) rDoc("Reset Part To Defaults"), 0, [](const char *, RtData &d)
{"clear:", rProp(internal) rDoc("Reset Part To Defaults"), 0,
[](const char *, RtData &d)
{
//XXX todo forward this event for middleware to handle
//Part *p = (Part*)d.obj;
@@ -159,23 +165,24 @@ static const Ports kitPorts = {
rToggle(Ppadenabled, "PADsynth enable"),
rParamZyn(Psendtoparteffect, "Effect Levels"),
rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"),
{"captureMin:", NULL, NULL, [](const char *, RtData &r)
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
{Part::Kit *p = (Part::Kit*)r.obj; p->Pminkey = p->parent->lastnote;}},
{"captureMax:", NULL, NULL, [](const char *, RtData &r)
{"captureMax:", rDoc("Capture maximum valid note"), NULL, [](const char *, RtData &r)
{Part::Kit *p = (Part::Kit*)r.obj; p->Pmaxkey = p->parent->lastnote;}},
{"padpars-data:b", rProp(internal), 0,
{"padpars-data:b", rProp(internal) rDoc("Set PADsynth data pointer"), 0,
[](const char *msg, RtData &d) {
rObject &o = *(rObject*)d.obj;
assert(o.padpars == NULL);
o.padpars = *(decltype(o.padpars)*)rtosc_argument(msg, 0).b.data;
}},
{"adpars-data:b", rProp(internal), 0,
{"adpars-data:b", rProp(internal) rDoc("Set ADsynth data pointer"), 0,
[](const char *msg, RtData &d) {
rObject &o = *(rObject*)d.obj;
assert(o.adpars == NULL);
o.adpars = *(decltype(o.adpars)*)rtosc_argument(msg, 0).b.data;
}},
{"subpars-data:b", rProp(internal), 0,
{"subpars-data:b", rProp(internal) rDoc("Set SUBsynth data pointer"), 0,
[](const char *msg, RtData &d) {
rObject &o = *(rObject*)d.obj;
assert(o.subpars == NULL);
@@ -188,18 +195,23 @@ static const Ports kitPorts = {
const Ports &Part::Kit::ports = kitPorts;
const Ports &Part::ports = partPorts;

Part::Part(Allocator &alloc, const SYNTH_T &synth_,
Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_,
const int &gzip_compression, const int &interpolation,
Microtonal *microtonal_, FFTwrapper *fft_)
:ctl(synth_), memory(alloc), synth(synth_),
:Pdrummode(false),
Ppolymode(true),
Plegatomode(false),
partoutl(new float[synth_.buffersize]),
partoutr(new float[synth_.buffersize]),
ctl(synth_),
microtonal(microtonal_),
fft(fft_),
memory(alloc),
synth(synth_),
time(time_),
gzip_compression(gzip_compression),
interpolation(interpolation)
{
microtonal = microtonal_;
fft = fft_;
partoutl = new float [synth.buffersize];
partoutr = new float [synth.buffersize];

monomemClear();

for(int n = 0; n < NUM_KIT_ITEMS; ++n) {
@@ -217,6 +229,7 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_,
partefx[nefx] = new EffectMgr(memory, synth, 1);
Pefxbypass[nefx] = false;
}
assert(partefx[0]);

for(int n = 0; n < NUM_PART_EFX + 1; ++n) {
partfxinputl[n] = new float [synth.buffersize];
@@ -226,28 +239,15 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_,
killallnotes = false;
oldfreq = -1.0f;


for(int i = 0; i < POLYPHONY; ++i) {
partnote[i].status = KEY_OFF;
partnote[i].note = -1;
partnote[i].itemsplaying = 0;
for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
partnote[i].kititem[j].adnote = NULL;
partnote[i].kititem[j].subnote = NULL;
partnote[i].kititem[j].padnote = NULL;
}
partnote[i].time = 0;
}
cleanup();

Pname = new char[PART_MAX_NAME_LEN];

oldvolumel = oldvolumer = 0.5f;
lastnote = -1;
lastpos = 0; // lastpos will store previously used NoteOn(...)'s pos.
lastlegatomodevalid = false; // To store previous legatomodevalid value.

defaults();
assert(partefx[0]);
}

void Part::cloneTraits(Part &p) const
@@ -334,8 +334,7 @@ void Part::defaultsinstrument()
*/
void Part::cleanup(bool final_)
{
for(int k = 0; k < POLYPHONY; ++k)
KillNotePos(k);
notePool.killAllNotes();
for(int i = 0; i < synth.buffersize; ++i) {
partoutl[i] = final_ ? 0.0f : synth.denormalkillbuf[i];
partoutr[i] = final_ ? 0.0f : synth.denormalkillbuf[i];
@@ -371,6 +370,16 @@ Part::~Part()
}
}

void assert_kit_sanity(const Part::Kit *kits)
{
for(int i=0; i<NUM_KIT_ITEMS; ++i) {
//an enabled kit must have a corresponding parameter object
assert(!kits[i].Padenabled || kits[i].adpars);
assert(!kits[i].Ppadenabled || kits[i].padpars);
assert(!kits[i].Psubenabled || kits[i].subpars);
}
}

/*
* Note On Messages
*/
@@ -378,299 +387,92 @@ void Part::NoteOn(unsigned char note,
unsigned char velocity,
int masterkeyshift)
{
// Legato and MonoMem used vars:
int posb = POLYPHONY - 1; // Just a dummy initial value.
bool legatomodevalid = false; //true when legato mode is determined applicable.
bool doinglegato = false; // true when we determined we do a legato note.
bool ismonofirstnote = false; /*(In Mono/Legato) true when we determined
no other notes are held down or sustained.*/
int lastnotecopy = lastnote; //Useful after lastnote has been changed.
//Verify Basic Mode and sanity
const bool isRunningNote = notePool.existsRunningNote();
const bool doingLegato = isRunningNote && isLegatoMode() &&
lastlegatomodevalid;

if(!Pnoteon || !inRange(note, Pminkey, Pmaxkey))
return;

// MonoMem stuff:
if(!Ppolymode) { // If Poly is off
monomemPush(note); // Add note to the list.
monomem[note].velocity = velocity; // Store this note's velocity.
monomem[note].mkeyshift = masterkeyshift; /* Store masterkeyshift too*/
if((partnote[lastpos].status != KEY_PLAYING)
&& (partnote[lastpos].status != KEY_RELEASED_AND_SUSTAINED))
ismonofirstnote = true; // No other keys are held or sustained.
} else if(!monomemEmpty())
monomemClear();

lastnote = note;

int pos = -1;
for(int i = 0; i < POLYPHONY; ++i)
if(partnote[i].status == KEY_OFF) {
pos = i;
break;
}

if(Plegatomode && !Pdrummode) {
if(Ppolymode != 0) {
fprintf(
stderr,
"ZynAddSubFX WARNING: Poly and Legato modes are both On, that should not happen ! ... Disabling Legato mode ! - (Part.cpp::NoteOn(..))\n");
Plegatomode = 0;
}
else {
// Legato mode is on and applicable.
legatomodevalid = true;
if((not ismonofirstnote) && (lastlegatomodevalid)) {
// At least one other key is held or sustained, and the
// previous note was played while in valid legato mode.
doinglegato = true; // So we'll do a legato note.
pos = lastpos; // A legato note uses same pos as previous..
posb = lastposb; // .. same goes for posb.
}
else {
// Legato mode is valid, but this is only a first note.
for(int i = 0; i < POLYPHONY; ++i)
if((partnote[i].status == KEY_PLAYING)
|| (partnote[i].status == KEY_RELEASED_AND_SUSTAINED))
ReleaseNotePos(i);

// Set posb
posb = (pos + 1) % POLYPHONY; //We really want it (if the following fails)
for(int i = 0; i < POLYPHONY; ++i)
if((partnote[i].status == KEY_OFF) && (pos != i)) {
posb = i;
break;
}
}
lastposb = posb; // Keep a trace of used posb
}
}
else // Legato mode is either off or non-applicable.
if(!Ppolymode) { //if the mode is 'mono' turn off all other notes
for(int i = 0; i < POLYPHONY; ++i)
if(partnote[i].status == KEY_PLAYING)
ReleaseNotePos(i);
ReleaseSustainedKeys();
}
lastlegatomodevalid = legatomodevalid;

if(pos == -1)
fprintf(stderr,
"%s",
"NOTES TOO MANY (> POLYPHONY) - (Part.cpp::NoteOn(..))\n");
else {
//start the note
partnote[pos].status = KEY_PLAYING;
partnote[pos].note = note;
if(legatomodevalid) {
partnote[posb].status = KEY_PLAYING;
partnote[posb].note = note;
}
verifyKeyMode();
assert_kit_sanity(kit);

//this computes the velocity sensing of the part
float vel = VelF(velocity / 127.0f, Pvelsns);
//Preserve Note Stack
if(isMonoMode() || isLegatoMode()) {
monomemPush(note);
monomem[note].velocity = velocity;
monomem[note].mkeyshift = masterkeyshift;

//compute the velocity offset
vel = limit(vel + (Pveloffs - 64.0f) / 64.0f, 0.0f, 1.0f);
} else if(!monomemEmpty())
monomemClear();

//compute the keyshift
int partkeyshift = (int)Pkeyshift - 64;
int keyshift = masterkeyshift + partkeyshift;
//Mono/Legato Release old notes
if(isMonoMode() || (isLegatoMode() && !doingLegato))
notePool.releasePlayingNotes();

//initialise note frequency
float notebasefreq;
if(Pdrummode == 0) {
notebasefreq = microtonal->getnotefreq(note, keyshift);
if(notebasefreq < 0.0f)
return;//the key is no mapped
}
else
notebasefreq = 440.0f * powf(2.0f, (note - 69.0f) / 12.0f);

//Portamento
if(oldfreq < 1.0f)
oldfreq = notebasefreq;//this is only the first note is played

// For Mono/Legato: Force Portamento Off on first
// notes. That means it is required that the previous note is
// still held down or sustained for the Portamento to activate
// (that's like Legato).
bool portamento = false;
if(Ppolymode || !ismonofirstnote)
// I added a third argument to the
// ctl.initportamento(...) function to be able
// to tell it if we're doing a legato note.
portamento = ctl.initportamento(oldfreq, notebasefreq, doinglegato);

if(portamento)
ctl.portamento.noteusing = pos;
oldfreq = notebasefreq;

lastpos = pos; // Keep a trace of used pos.

if(doinglegato) {
// Do Legato note
if(Pkitmode == 0) { // "normal mode" legato note

auto note1 = partnote[pos].kititem[0];
auto note2 = partnote[posb].kititem[0];
LegatoParams pars = {notebasefreq, vel, portamento, note, true};
if(kit[0].Padenabled && note1.adnote && note2.adnote) {
note1.adnote->legatonote(pars);
note2.adnote->legatonote(pars);
}
lastlegatomodevalid = isLegatoMode();

if(kit[0].Psubenabled && note1.subnote && note2.subnote) {
note1.subnote->legatonote(pars);
note2.subnote->legatonote(pars);
}
//Compute Note Parameters
const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
const int partkeyshift = (int)Pkeyshift - 64;
const int keyshift = masterkeyshift + partkeyshift;
const float notebasefreq = getBaseFreq(note, keyshift);

if(kit[0].Ppadenabled && note1.padnote && note2.padnote) {
note1.padnote->legatonote(pars);
note2.padnote->legatonote(pars);
}
}
else { // "kit mode" legato note
int ci = 0;
for(int item = 0; item < NUM_KIT_ITEMS; ++item) {

//Make sure the key is valid and not across multiple ranges
if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey)
|| !inRange((unsigned char)lastnotecopy, kit[item].Pminkey, kit[item].Pmaxkey))
continue;

auto note1 = partnote[pos].kititem[ci];
auto note2 = partnote[posb].kititem[ci];
LegatoParams pars = {notebasefreq, vel, portamento, note, true};
note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);
note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);

if(kit[item].Padenabled && kit[item].adpars && note1.adnote && note2.adnote) {
note1.adnote->legatonote(pars);
note2.adnote->legatonote(pars);
}
if(kit[item].Psubenabled && kit[item].subpars && note1.subnote && note2.subnote) {
note1.subnote->legatonote(pars);
note2.subnote->legatonote(pars);
}
if(kit[item].Ppadenabled && kit[item].padpars && note1.padnote && note2.padnote) {
note1.padnote->legatonote(pars);
note2.padnote->legatonote(pars);
}

if(kit[item].adpars || kit[item].subpars || kit[item].padpars) {
ci++;
if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2))
break;
}
}
if(ci == 0) {
// No legato were performed at all, so pretend nothing happened:
monomemPop(monomemBack()); // Remove last note from the list.
lastnote = lastnotecopy; // Set lastnote back to previous value.
}
}
return; // Ok, Legato note done, return.
}
if(notebasefreq < 0)
return;

partnote[pos].itemsplaying = 0;
if(legatomodevalid)
partnote[posb].itemsplaying = 0;

if(Pkitmode == 0) { //init the notes for the "normal mode"
partnote[pos].kititem[0].sendtoparteffect = 0;
SynthParams pars{memory, ctl, synth, notebasefreq, vel, (bool) portamento, note, false};

if(kit[0].Padenabled)
partnote[pos].kititem[0].adnote =
memory.alloc<ADnote>(kit[0].adpars, pars);
if(kit[0].Psubenabled)
partnote[pos].kititem[0].subnote =
memory.alloc<SUBnote>(kit[0].subpars, pars);
if(kit[0].Ppadenabled)
partnote[pos].kititem[0].padnote =
memory.alloc<PADnote>(kit[0].padpars, pars,
interpolation);


if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled)
partnote[pos].itemsplaying++;

// Spawn another note (but silent) if legatomodevalid==true
if(legatomodevalid) {
partnote[posb].kititem[0].sendtoparteffect = 0;
pars.quiet = true;

if(kit[0].Padenabled)
partnote[posb].kititem[0].adnote =
memory.alloc<ADnote>(kit[0].adpars, pars);
if(kit[0].Psubenabled)
partnote[posb].kititem[0].subnote =
memory.alloc<SUBnote>(kit[0].subpars, pars);
if(kit[0].Ppadenabled)
partnote[posb].kititem[0].padnote =
memory.alloc<PADnote>(kit[0].padpars, pars,
interpolation);

if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled)
partnote[posb].itemsplaying++;
}
}
else //init the notes for the "kit mode"
for(int item = 0; item < NUM_KIT_ITEMS; ++item) {
if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey))
continue;
//Portamento
lastnote = note;
if(oldfreq < 1.0f)
oldfreq = notebasefreq;//this is only the first note is played

// For Mono/Legato: Force Portamento Off on first
// notes. That means it is required that the previous note is
// still held down or sustained for the Portamento to activate
// (that's like Legato).
bool portamento = false;
if(Ppolymode || isRunningNote)
portamento = ctl.initportamento(oldfreq, notebasefreq, doingLegato);

oldfreq = notebasefreq;

//Adjust Existing Notes
if(doingLegato) {
LegatoParams pars = {notebasefreq, vel, portamento, note, true};
notePool.applyLegato(pars);
return;
}

int ci = partnote[pos].itemsplaying; //ci=current item
auto &note1 = partnote[pos].kititem[ci];

//if this parameter is 127 for "unprocessed"
note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);

SynthParams pars{memory, ctl, synth, notebasefreq, vel, (bool) portamento, note, false};

if(kit[item].adpars && kit[item].Padenabled)
note1.adnote =
memory.alloc<ADnote>(kit[item].adpars, pars);

if(kit[item].subpars && kit[item].Psubenabled)
note1.subnote =
memory.alloc<SUBnote>(kit[item].subpars, pars);

if(kit[item].padpars && kit[item].Ppadenabled)
note1.padnote =
memory.alloc<PADnote>(kit[item].padpars, pars,
interpolation);

// Spawn another note (but silent) if legatomodevalid==true
if(legatomodevalid) {
auto &note2 = partnote[posb].kititem[ci];
note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);

pars.quiet = true;
if(kit[item].adpars && kit[item].Padenabled)
note2.adnote =
memory.alloc<ADnote>(kit[item].adpars, pars);
if(kit[item].subpars && kit[item].Psubenabled)
note2.subnote =
memory.alloc<SUBnote>(kit[item].subpars, pars);
if(kit[item].padpars && kit[item].Ppadenabled)
note2.padnote =
memory.alloc<PADnote>(kit[item].padpars, pars,
interpolation);

if(kit[item].adpars || kit[item].subpars || kit[item].padpars)
partnote[posb].itemsplaying++;
}
//Create New Notes
for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) {
auto &item = kit[i];
if(Pkitmode != 0 && !item.validNote(note))
continue;

if(kit[item].adpars || kit[item].subpars) {
partnote[pos].itemsplaying++;
if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2))
break;
}
}
SynthParams pars{memory, ctl, synth, time, notebasefreq, vel,
portamento, note, false};
const int sendto = Pkitmode ? item.sendto() : 0;

if(item.Padenabled)
notePool.insertNote(note, sendto,
{memory.alloc<ADnote>(kit[i].adpars, pars), 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});

//Partial Kit Use
if(isNonKit() || (isSingleKit() && item.active()))
break;
}

//this only release the keys if there is maximum number of keys allowed
if(isLegatoMode())
notePool.upgradeToLegato();

//Enforce the key limit
setkeylimit(Pkeylimit);
}

@@ -683,17 +485,18 @@ void Part::NoteOff(unsigned char note) //release the key
if(!monomemEmpty())
monomemPop(note);

for(int i = POLYPHONY - 1; i >= 0; i--) //first note in, is first out if there are same note multiple times
if((partnote[i].status == KEY_PLAYING) && (partnote[i].note == note)) {
if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
if(!Ppolymode && !monomemEmpty())
MonoMemRenote();//Play most recent still active note
else
ReleaseNotePos(i);
}
else //the sustain pedal is pushed
partnote[i].status = KEY_RELEASED_AND_SUSTAINED;
for(auto &desc:notePool.activeDesc()) {
if(desc.note != note)
continue;
if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
if((isMonoMode() || isLegatoMode()) && !monomemEmpty())
MonoMemRenote();//Play most recent still active note
else
notePool.release(desc);
}
else //the sustain pedal is pushed
desc.status = KEY_RELEASED_AND_SUSTAINED;
}
}

void Part::PolyphonicAftertouch(unsigned char note,
@@ -709,36 +512,12 @@ void Part::PolyphonicAftertouch(unsigned char note,
if(!Ppolymode) // if Poly is off
monomem[note].velocity = velocity; // Store this note's velocity.


for(int i = 0; i < POLYPHONY; ++i)
if((partnote[i].note == note) && (partnote[i].status == KEY_PLAYING)) {
/* update velocity */
// compute the velocity offset
float vel = VelF(velocity / 127.0f, Pvelsns) + (Pveloffs - 64.0f) / 64.0f;
vel = limit(vel, 0.0f, 1.0f);

if(!Pkitmode) { // "normal mode"
if(kit[0].Padenabled && partnote[i].kititem[0].adnote)
partnote[i].kititem[0].adnote->setVelocity(vel);
if(kit[0].Psubenabled && partnote[i].kititem[0].subnote)
partnote[i].kititem[0].subnote->setVelocity(vel);
if(kit[0].Ppadenabled && partnote[i].kititem[0].padnote)
partnote[i].kititem[0].padnote->setVelocity(vel);
}
else // "kit mode"
for(int item = 0; item < NUM_KIT_ITEMS; ++item) {
if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey))
continue;

if(kit[item].Padenabled && partnote[i].kititem[item].adnote)
partnote[i].kititem[item].adnote->setVelocity(vel);
if(kit[item].Psubenabled && partnote[i].kititem[item].subnote)
partnote[i].kititem[item].subnote->setVelocity(vel);
if(kit[item].Ppadenabled && partnote[i].kititem[item].padnote)
partnote[i].kititem[item].padnote->setVelocity(vel);
}
}

const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
for(auto &d:notePool.activeDesc()) {
if(d.note == note && d.status == KEY_PLAYING)
for(auto &s:notePool.activeNotes(d))
s.note->setVelocity(vel);
}
}

/*
@@ -839,13 +618,14 @@ void Part::SetController(unsigned int type, int par)
void Part::ReleaseSustainedKeys()
{
// Let's call MonoMemRenote() on some conditions:
if(Ppolymode == 0 && !monomemEmpty())
if((isMonoMode() || isLegatoMode()) && !monomemEmpty())
if(monomemBack() != lastnote) // Sustain controller manipulation would cause repeated same note respawn without this check.
MonoMemRenote(); // To play most recent still held note.

for(int i = 0; i < POLYPHONY; ++i)
if(partnote[i].status == KEY_RELEASED_AND_SUSTAINED)
ReleaseNotePos(i);
for(auto &d:notePool.activeDesc())
if(d.status == KEY_RELEASED_AND_SUSTAINED)
for(auto &s:notePool.activeNotes(d))
s.note->releasekey();
}

/*
@@ -854,10 +634,10 @@ void Part::ReleaseSustainedKeys()

void Part::ReleaseAllKeys()
{
for(int i = 0; i < POLYPHONY; ++i)
if((partnote[i].status != KEY_RELEASED)
&& (partnote[i].status != KEY_OFF)) //thanks to Frank Neumann
ReleaseNotePos(i);
for(auto &d:notePool.activeDesc())
if(d.status != KEY_RELEASED)
for(auto &s:notePool.activeNotes(d))
s.note->releasekey();
}

// Call NoteOn(...) with the most recent still held key as new note
@@ -866,50 +646,36 @@ void Part::MonoMemRenote()
{
unsigned char mmrtempnote = monomemBack(); // Last list element.
monomemPop(mmrtempnote); // We remove it, will be added again in NoteOn(...).
if(Pnoteon == 0)
ReleaseNotePos(lastpos);
else
NoteOn(mmrtempnote, monomem[mmrtempnote].velocity,
monomem[mmrtempnote].mkeyshift);
NoteOn(mmrtempnote, monomem[mmrtempnote].velocity,
monomem[mmrtempnote].mkeyshift);
}

/*
* Release note at position
*/
void Part::ReleaseNotePos(int pos)
float Part::getBaseFreq(int note, int keyshift) const
{
for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
if(partnote[pos].kititem[j].adnote)
partnote[pos].kititem[j].adnote->releasekey();
if(Pdrummode)
return 440.0f * powf(2.0f, (note - 69.0f) / 12.0f);
else
return microtonal->getnotefreq(note, keyshift);
}

if(partnote[pos].kititem[j].subnote)
partnote[pos].kititem[j].subnote->releasekey();
float Part::getVelocity(uint8_t velocity, uint8_t velocity_sense,
uint8_t velocity_offset) const
{
//compute sense function
const float vel = VelF(velocity / 127.0f, velocity_sense);

if(partnote[pos].kititem[j].padnote)
partnote[pos].kititem[j].padnote->releasekey();
}
partnote[pos].status = KEY_RELEASED;
//compute the velocity offset
return limit(vel + (velocity_offset - 64.0f) / 64.0f, 0.0f, 1.0f);
}


/*
* Kill note at position
*/
void Part::KillNotePos(int pos)
void Part::verifyKeyMode(void)
{
partnote[pos].status = KEY_OFF;
partnote[pos].note = -1;
partnote[pos].time = 0;
partnote[pos].itemsplaying = 0;

for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
memory.dealloc(partnote[pos].kititem[j].adnote);
memory.dealloc(partnote[pos].kititem[j].subnote);
memory.dealloc(partnote[pos].kititem[j].padnote);
}
if(pos == ctl.portamento.noteusing) {
ctl.portamento.noteusing = -1;
ctl.portamento.used = 0;
if(Plegatomode && !Pdrummode && Ppolymode) {
fprintf(stderr,
"WARNING: Poly & Legato modes are On, that shouldn't happen\n"
"Disabling Legato mode...\n"
"(Part.cpp::NoteOn(..))\n");
Plegatomode = 0;
}
}

@@ -917,32 +683,15 @@ void Part::KillNotePos(int pos)
/*
* Set Part's key limit
*/
void Part::setkeylimit(unsigned char Pkeylimit)
void Part::setkeylimit(unsigned char Pkeylimit_)
{
this->Pkeylimit = Pkeylimit;
Pkeylimit = Pkeylimit_;
int keylimit = Pkeylimit;
if(keylimit == 0)
keylimit = POLYPHONY - 5;

//release old keys if the number of notes>keylimit
if(Ppolymode != 0) {
int notecount = 0;
for(int i = 0; i < POLYPHONY; ++i)
if((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED))
notecount++;

int oldestnotepos = -1;
if(notecount > keylimit) //find out the oldest note
for(int i = 0; i < POLYPHONY; ++i) {
int maxtime = 0;
if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
maxtime = partnote[i].time;
oldestnotepos = i;
}
}
if(oldestnotepos != -1)
ReleaseNotePos(oldestnotepos);
}
if(notePool.getRunningNotes() > keylimit)
notePool.enforceKeyLimit(keylimit);
}


@@ -954,65 +703,35 @@ void Part::AllNotesOff()
killallnotes = true;
}

void Part::RunNote(unsigned int k)
/*
* Compute Part samples and store them in the partoutl[] and partoutr[]
*/
void Part::ComputePartSmps()
{
unsigned noteplay = 0;
for(int item = 0; item < partnote[k].itemsplaying; ++item) {
int sendcurrenttofx = partnote[k].kititem[item].sendtoparteffect;

for(unsigned type = 0; type < 3; ++type) {
//Select a note
SynthNote **note = NULL;
if(type == 0)
note = &partnote[k].kititem[item].adnote;
else if(type == 1)
note = &partnote[k].kititem[item].subnote;
else if(type == 2)
note = &partnote[k].kititem[item].padnote;

//Process if it exists
if(!(*note))
continue;
noteplay++;
assert(partefx[0]);
for(unsigned nefx = 0; nefx < NUM_PART_EFX + 1; ++nefx) {
memset(partfxinputl[nefx], 0, synth.bufferbytes);
memset(partfxinputr[nefx], 0, synth.bufferbytes);
}

for(auto &d:notePool.activeDesc()) {
d.age++;
for(auto &s:notePool.activeNotes(d)) {
float tmpoutr[synth.buffersize];
float tmpoutl[synth.buffersize];
(*note)->noteout(&tmpoutl[0], &tmpoutr[0]);
auto &note = *s.note;
note.noteout(&tmpoutl[0], &tmpoutr[0]);

if((*note)->finished())
memory.dealloc(*note);
for(int i = 0; i < synth.buffersize; ++i) { //add the note to part(mix)
partfxinputl[sendcurrenttofx][i] += tmpoutl[i];
partfxinputr[sendcurrenttofx][i] += tmpoutr[i];
partfxinputl[d.sendto][i] += tmpoutl[i];
partfxinputr[d.sendto][i] += tmpoutr[i];
}
}
}

//Kill note if there is no synth on that note
if(!noteplay)
KillNotePos(k);
}

/*
* Compute Part samples and store them in the partoutl[] and partoutr[]
*/
void Part::ComputePartSmps()
{
for(unsigned nefx = 0; nefx < NUM_PART_EFX + 1; ++nefx)
for(int i = 0; i < synth.buffersize; ++i) {
partfxinputl[nefx][i] = 0.0f;
partfxinputr[nefx][i] = 0.0f;
if(note.finished())
notePool.kill(s);
}

for(unsigned k = 0; k < POLYPHONY; ++k) {
if(partnote[k].status == KEY_OFF)
continue;
partnote[k].time++;
//get the sampledata of the note and kill it if it's finished
RunNote(k);
}


//Apply part's effects and mix them
for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) {
if(!Pefxbypass[nefx]) {
@@ -1040,8 +759,8 @@ void Part::ComputePartSmps()
partoutl[i] *= tmp;
partoutr[i] *= tmp;
}
for(int k = 0; k < POLYPHONY; ++k)
KillNotePos(k);
notePool.killAllNotes();
monomemClear();
killallnotes = false;
for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx)
partefx[nefx]->cleanup();
@@ -1087,9 +806,7 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_)
delete kkit.padpars;
kkit.Pname[0] = '\0';

//Reset notes s.t. stale buffers will not get read
for(int k = 0; k < POLYPHONY; ++k)
KillNotePos(k);
notePool.killAllNotes();
}
else {
//All parameters must be NULL in this case
@@ -1247,8 +964,7 @@ void Part::kill_rt(void)
{
for(int i=0; i<NUM_PART_EFX; ++i)
partefx[i]->kill();
for(int k = 0; k < POLYPHONY; ++k)
KillNotePos(k);
notePool.killAllNotes();
}

void Part::monomemPush(char note)
@@ -1414,3 +1130,19 @@ void Part::getfromXML(XMLwrapper *xml)
xml->exitbranch();
}
}

bool Part::Kit::active(void) const
{
return Padenabled || Psubenabled || Ppadenabled;
}

uint8_t Part::Kit::sendto(void) const
{
return limit((int)Psendtoparteffect, 0, NUM_PART_EFX);

}

bool Part::Kit::validNote(char note) const
{
return !Pmuted && inRange((uint8_t)note, Pminkey, Pmaxkey);
}

+ 22
- 19
source/native-plugins/zynaddsubfx/Misc/Part.h View File

@@ -27,6 +27,7 @@

#include "../globals.h"
#include "../Params/Controller.h"
#include "../Containers/NotePool.h"

#include <functional>

@@ -37,7 +38,7 @@ class Part
/**Constructor
* @param microtonal_ Pointer to the microtonal object
* @param fft_ Pointer to the FFTwrapper*/
Part(Allocator &alloc, const SYNTH_T &synth,
Part(Allocator &alloc, const SYNTH_T &synth, const AbsTime &time,
const int& gzip_compression, const int& interpolation,
Microtonal *microtonal_, FFTwrapper *fft_);
/**Destructor*/
@@ -97,6 +98,10 @@ class Part
SUBnoteParameters *subpars;
PADnoteParameters *padpars;

bool active(void) const;
uint8_t sendto(void) const;
bool validNote(char note) const;

const static rtosc::Ports &ports;
} kit[NUM_KIT_ITEMS];

@@ -118,6 +123,8 @@ class Part
unsigned char Pveloffs; //velocity offset
bool Pnoteon; //if the part receives NoteOn messages
int Pkitmode; //if the kitmode is enabled

//XXX consider deprecating drum mode
bool Pdrummode; //if all keys are mapped and the system is 12tET (used for drums)

bool Ppolymode; //Part mode - 0=monophonic , 1=polyphonic
@@ -156,25 +163,22 @@ class Part
const static rtosc::Ports &ports;

private:
void RunNote(unsigned k);
void KillNotePos(int pos);
void ReleaseNotePos(int pos);
void MonoMemRenote(); // MonoMem stuff.
float getBaseFreq(int note, int keyshift) const;
float getVelocity(uint8_t velocity, uint8_t velocity_sense,
uint8_t velocity_offset) const;
void verifyKeyMode(void);
bool isPolyMode(void) const {return Ppolymode;}
bool isMonoMode(void) const {return !Ppolymode && !Plegatomode;};
bool isLegatoMode(void) const {return Plegatomode && !Pdrummode;}
bool isNonKit(void) const {return Pkitmode == 0;}
bool isMultiKit(void) const {return Pkitmode == 1;}
bool isSingleKit(void) const {return Pkitmode == 2;}

int killallnotes; //is set to 1 if I want to kill all notes

struct PartNotes {
NoteStatus status;
int note; //if there is no note playing, the "note"=-1
int itemsplaying;
struct {
SynthNote *adnote, *subnote, *padnote;
int sendtoparteffect;
} kititem[NUM_KIT_ITEMS];
int time;
};
bool killallnotes;

NotePool notePool;

int lastpos, lastposb; // To keep track of previously used pos and posb.
bool lastlegatomodevalid; // To keep track of previous legatomodevalid.

// MonoMem stuff
@@ -194,13 +198,12 @@ class Part
store the velocity and masterkeyshift values of a given note (the list only store note values).
For example 'monomem[note].velocity' would be the velocity value of the note 'note'.*/

PartNotes partnote[POLYPHONY];

float oldfreq; //this is used for portamento
Microtonal *microtonal;
FFTwrapper *fft;
Allocator &memory;
const SYNTH_T &synth;
const AbsTime &time;
const int &gzip_compression, &interpolation;
};



+ 4
- 12
source/native-plugins/zynaddsubfx/Misc/PresetExtractor.cpp View File

@@ -30,7 +30,7 @@ static void dummy(const char *, rtosc::RtData&) {}
const rtosc::Ports real_preset_ports =
{
{"scan-for-presets:", 0, 0,
[](const char *msg, rtosc::RtData &d) {
[](const char *, rtosc::RtData &d) {
MiddleWare &mw = *(MiddleWare*)d.obj;
mw.getPresetsStore().scanforpresets();
auto &pre = mw.getPresetsStore().presets;
@@ -83,7 +83,7 @@ const rtosc::Ports real_preset_ports =
assert(false && "bad arguments");
}},
{"clipboard-type:", 0, 0,
[](const char *msg, rtosc::RtData &d) {
[](const char *, rtosc::RtData &d) {
const MiddleWare &mw = *(MiddleWare*)d.obj;
d.reply(d.loc, "s", mw.getPresetsStore().clipboard.type.c_str());
}},
@@ -99,8 +99,8 @@ const rtosc::Ports real_preset_ports =
const rtosc::Ports preset_ports
{
{"scan-for-presets:", rDoc("Scan For Presets"), 0, dummy},
{"copy:s:ss:si:ssi", rDoc("Copy <s> URL to <s> Name/Clipboard from subfield <i>"), 0, dummy},
{"paste:s:ss:si:ssi", rDoc("Paste <s> URL to <s> File-Name/Clipboard from subfield <i>"), 0, dummy},
{"copy:s:ss:si:ssi", rDoc("Copy (s)URL to (s) Name/Clipboard from subfield (i)"), 0, dummy},
{"paste:s:ss:si:ssi", rDoc("Paste (s) URL to (s) File-Name/Clipboard from subfield (i)"), 0, dummy},
{"clipboard-type:", rDoc("Type Stored In Clipboard"), 0, dummy},
{"delete:s", rDoc("Delete the given preset file"), 0, dummy},
};
@@ -123,14 +123,6 @@ const rtosc::Ports preset_ports
//Synth/Resonance.cpp: setpresettype("Presonance");


//Translate newer symbols to old preset types
std::vector<string> translate_preset_types(std::string metatype)
{
std::vector<string> results;
return results;
}


/*****************************************************************************
* Implementation Methods *
*****************************************************************************/


+ 42
- 0
source/native-plugins/zynaddsubfx/Misc/Time.h View File

@@ -0,0 +1,42 @@
#pragma once
#include <stdint.h>
#include "../globals.h"

class AbsTime
{
public:
AbsTime(const SYNTH_T &synth)
:frames(0),
s(synth){};
void operator++(){++frames;};
void operator++(int){frames++;};
int64_t time() const {return frames;};
float dt() const { return s.dt(); }
float framesPerSec() const { return 1/s.dt();}
int samplesPerFrame() const {return s.buffersize;}
private:
int64_t frames;
const SYNTH_T &s;
};

//Marker for an event relative to some position of the absolute timer
class RelTime
{
public:
RelTime(const AbsTime &t_, float sec)
:t(t_)
{
//Calculate time of event
double deltaFrames = sec*t.framesPerSec();
int64_t tmp = (int64_t)deltaFrames;
frame = t.time() + tmp;
sample = t.samplesPerFrame()*(deltaFrames-tmp);
}
bool inThisFrame() {return t.time() == frame;};
bool inPast() {return t.time() > frame;}
bool inFuture() {return t.time() < frame;}
private:
int64_t frame;
int32_t sample;
const AbsTime &t;
};

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

@@ -157,12 +157,12 @@ char *rtosc_splat(const char *path, std::set<std::string>);
{STRINGIFY(name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, rParamICb(name)}

#define rSelf(type) \
{"self", rProp(internal) rMap(class, type) rDoc("port metadata"), 0, \
{"self:", rProp(internal) rMap(class, type) rDoc("port metadata"), 0, \
[](const char *, rtosc::RtData &d){ \
d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\

#define rPaste \
{"preset-type", rProp(internal), 0, \
{"preset-type:", rProp(internal) rDoc("clipboard type of object"), 0, \
[](const char *, rtosc::RtData &d){ \
rObject *obj = (rObject*)d.obj; \
d.reply(d.loc, "s", obj->type);}},\


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

@@ -10,7 +10,7 @@
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) for more details.
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,


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

@@ -13,7 +13,7 @@
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) for more details.
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,


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

@@ -9,7 +9,7 @@
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) for more details.
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,


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

@@ -13,7 +13,7 @@
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) for more details.
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,


+ 33
- 50
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp View File

@@ -62,11 +62,11 @@ static const Ports voicePorts = {
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,Noise), "Type of Sound"),
rOption(Type, rOptions(Sound,White,Pink), "Type of Sound"),
rParamZyn(PDelay, "Voice Startup Delay"),
rToggle(Presonance, "Resonance Enable"),
rParamZyn(Pextoscil, "External Oscilator Selection"),
rParamZyn(PextFMoscil, "External FM Oscilator Selection"),
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"),
@@ -108,14 +108,19 @@ static const Ports voicePorts = {

//weird stuff for PCoarseDetune
{"detunevalue:", NULL, NULL, [](const char *, RtData &d)
{"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL,
[](const char *, RtData &d)
{
rObject *obj = (rObject *)d.obj;
unsigned detuneType =
obj->PDetuneType == 0 ? *(obj->GlobalPDetuneType)
: obj->PDetuneType;
//TODO check if this is accurate or if PCoarseDetune is utilized
//TODO do the same for the other engines
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
d.reply(d.loc, "f", getdetune(detuneType, 0, obj->PDetune));
}},
{"octave::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -128,7 +133,8 @@ static const Ports voicePorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -143,14 +149,18 @@ static const Ports voicePorts = {
}},
//weird stuff for PCoarseDetune
{"FMdetunevalue:", NULL, NULL, [](const char *, RtData &d)
{"FMdetunevalue:", rMap(unit,cents) rDoc("Get modulator detune"), NULL, [](const char *, RtData &d)
{
rObject *obj = (rObject *)d.obj;
unsigned detuneType =
obj->PFMDetuneType == 0 ? *(obj->GlobalPDetuneType)
: obj->PFMDetuneType;
//TODO check if this is accurate or if PCoarseDetune is utilized
//TODO do the same for the other engines
d.reply(d.loc, "f", getdetune(obj->PFMDetuneType, 0, obj->PFMDetune));
d.reply(d.loc, "f", getdetune(detuneType, 0, obj->PFMDetune));
}},
{"FMoctave::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"FMoctave::c:i", rProp(parameter) rDoc("Octave note offset for modulator"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -163,7 +173,8 @@ static const Ports voicePorts = {
obj->PFMCoarseDetune = k*1024 + obj->PFMCoarseDetune%1024;
}
}},
{"FMcoarsedetune::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"FMcoarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune for modulator"),
NULL, [](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -178,7 +189,8 @@ static const Ports voicePorts = {
}},

//Reader
{"unisonFrequencySpreadCents:", NULL, NULL, [](const char *, RtData &d)
{"unisonFrequencySpreadCents:", rMap(unit,cents) rDoc("Unison Frequency Spread"),
NULL, [](const char *, RtData &d)
{
rObject *obj = (rObject *)d.obj;
d.reply(d.loc, "f", obj->getUnisonFrequencySpreadCents());
@@ -224,12 +236,14 @@ static const Ports globalPorts = {
rParamZyn(Hrandgrouping, "How randomness is applied to multiple voices using the same oscil"),

//weird stuff for PCoarseDetune
{"detunevalue:", NULL, NULL, [](const char *, RtData &d)
{"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL,
[](const char *, RtData &d)
{
rObject *obj = (rObject *)d.obj;
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
}},
{"octave::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -242,7 +256,8 @@ static const Ports globalPorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
rObject *obj = (rObject *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -279,8 +294,10 @@ ADnoteParameters::ADnoteParameters(const SYNTH_T &synth, FFTwrapper *fft_)
fft = fft_;


for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice)
for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
VoicePar[nvoice].GlobalPDetuneType = &GlobalPar.PDetuneType;
EnableVoice(synth, nvoice);
}

defaults();
}
@@ -524,40 +541,6 @@ ADnoteParameters::~ADnoteParameters()
KillVoice(nvoice);
}

int ADnoteParameters::get_unison_size_index(int nvoice) const
{
int index = 0;
if(nvoice >= NUM_VOICES)
return 0;
int unison = VoicePar[nvoice].Unison_size;

while(1) {
if(ADnote_unison_sizes[index] >= unison)
return index;

if(ADnote_unison_sizes[index] == 0)
return index - 1;

index++;
}
return 0;
}

void ADnoteParameters::set_unison_size_index(int nvoice, int index) {
int unison = 1;
for(int i = 0; i <= index; ++i) {
unison = ADnote_unison_sizes[i];
if(unison == 0) {
unison = ADnote_unison_sizes[i - 1];
break;
}
}

VoicePar[nvoice].Unison_size = unison;
}



void ADnoteParameters::add2XMLsection(XMLwrapper *xml, int n)
{
int nvoice = n;


+ 2
- 4
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h View File

@@ -29,8 +29,6 @@
enum FMTYPE {
NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PITCH_MOD
};
static const int ADnote_unison_sizes[] =
{1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0};

/*****************************************************************/
/* GLOBAL PARAMETERS */
@@ -284,6 +282,8 @@ struct ADnoteVoiceParam {
unsigned char PFMAmpEnvelopeEnabled;
EnvelopeParams *FMAmpEnvelope;

unsigned char *GlobalPDetuneType;

static const rtosc::Ports &ports;
};

@@ -306,8 +306,6 @@ class ADnoteParameters:public PresetsArray

float getBandwidthDetuneMultiplier() const;
float getUnisonFrequencySpreadCents(int nvoice) const;
int get_unison_size_index(int nvoice) const;
void set_unison_size_index(int nvoice, int index);
static const rtosc::Ports &ports;
void defaults(int n); //n is the nvoice
void add2XMLsection(XMLwrapper *xml, int n);


+ 8
- 1
source/native-plugins/zynaddsubfx/Params/EnvelopeParams.cpp View File

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

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

@@ -131,7 +132,13 @@ void EnvelopeParams::paste(const EnvelopeParams &ep)
//Avoid undefined behavior
if(&ep == this)
return;
memcpy((char*)this, (const char*)&ep, sizeof(*this));


char *base = (char*)&this->Pfreemode;
char *end = (char*)&this->DR_val;
assert(end-base > 0);
memcpy((char*)&this->Pfreemode, (const char*)&ep.Pfreemode, 1+end-base);
}

float EnvelopeParams::getdt(char i) const


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

@@ -105,13 +105,14 @@ const rtosc::Ports FilterParams::ports = {
if(rtosc_narguments(msg))
rChangeCb;
}},
{"centerfreq:", NULL, NULL,
[](const char *, RtData &d) {
{"centerfreq:", rDoc("Get the center frequency of the formant's graph"),
NULL, [](const char *, RtData &d) {
FilterParams *obj = (FilterParams *) d.obj;
d.reply(d.loc, "f", obj->getcenterfreq());
}},
{"octavesfreq:", NULL, NULL,
[](const char *, RtData &d) {
{"octavesfreq:",
rDoc("Get the number of octave that the formant functions applies to"),
NULL, [](const char *, RtData &d) {
FilterParams *obj = (FilterParams *) d.obj;
d.reply(d.loc, "f", obj->getoctavesfreq());
}},


+ 0
- 4
source/native-plugins/zynaddsubfx/Params/LFOParams.cpp View File

@@ -49,8 +49,6 @@ static const rtosc::Ports _ports = {

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

int LFOParams::time;

LFOParams::LFOParams()
{
Dfreq = 64;
@@ -61,7 +59,6 @@ LFOParams::LFOParams()
Ddelay = 0;
Dcontinous = 0;
fel = 0;
time = 0;

defaults();
}
@@ -94,7 +91,6 @@ LFOParams::LFOParams(char Pfreq_,
Ddelay = Pdelay_;
Dcontinous = Pcontinous_;
fel = fel_;
time = 0;

defaults();
}


+ 8
- 1
source/native-plugins/zynaddsubfx/Params/LFOParams.h View File

@@ -28,6 +28,14 @@

class XMLwrapper;

#define LFO_SINE 0
#define LFO_TRIANGLE 1
#define LFO_SQUARE 2
#define LFO_RAMPUP 3
#define LFO_RAMPDOWN 4
#define LFO_EXP_DOWN1 5
#define LFO_EXP_DOWN2 6

class LFOParams:public Presets
{
public:
@@ -60,7 +68,6 @@ class LFOParams:public Presets
unsigned char Pstretch; /**<how the LFO is "stretched" according the note frequency (64=no stretch)*/

int fel; //what kind is the LFO (0 - frequency, 1 - amplitude, 2 - filter)
static int time; //is used by Pcontinous parameter

static const rtosc::Ports &ports;
private:


+ 8
- 7
source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp View File

@@ -90,8 +90,6 @@ static const rtosc::Ports PADnotePorts =

PC(fixedfreq),
PC(fixedfreqET),
//TODO detune, coarse detune
PC(DetuneType),
PC(Stereo),
PC(Panning),
PC(AmpVelocityScaleFunction),
@@ -115,7 +113,7 @@ static const rtosc::Ports PADnotePorts =
d.reply(d.loc, "i", p->Pbandwidth);
}}},
{"bandwidthvalue:", NULL, NULL,
{"bandwidthvalue:", rMap(unit, cents) rDoc("Get Bandwidth"), NULL,
[](const char *, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
d.reply(d.loc, "f", p->setPbandwidth(p->Pbandwidth));
@@ -143,7 +141,7 @@ static const rtosc::Ports PADnotePorts =
d.reply(d.loc, "b", n*sizeof(float), tmp);
d.reply(d.loc, "i", realbw);
delete[] tmp;}},
{"sample#64:ifb", rDoc("Nothing to see here"), 0,
{"sample#64:ifb", rProp(internal) rDoc("Nothing to see here"), 0,
[](const char *m, rtosc::RtData &d)
{
PADnoteParameters *p = (PADnoteParameters*)d.obj;
@@ -157,12 +155,14 @@ static const rtosc::Ports PADnotePorts =
//XXX TODO memory managment (deallocation of smp buffer)
}},
//weird stuff for PCoarseDetune
{"detunevalue:", NULL, NULL, [](const char *, RtData &d)
{"detunevalue:", rMap(unit,cents) rDoc("Get detune value"), NULL,
[](const char *, RtData &d)
{
PADnoteParameters *obj = (PADnoteParameters *)d.obj;
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
}},
{"octave::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"octave::c:i", rProp(parameter) rDoc("Octave note offset"), NULL,
[](const char *msg, RtData &d)
{
PADnoteParameters *obj = (PADnoteParameters *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -175,7 +175,8 @@ static const rtosc::Ports PADnotePorts =
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", NULL, NULL, [](const char *msg, RtData &d)
{"coarsedetune::c:i", rProp(parameter) rDoc("Coarse note detune"), NULL,
[](const char *msg, RtData &d)
{
PADnoteParameters *obj = (PADnoteParameters *)d.obj;
if(!rtosc_narguments(msg)) {


+ 4
- 2
source/native-plugins/zynaddsubfx/Params/SUBnoteParameters.cpp View File

@@ -93,7 +93,8 @@ static const rtosc::Ports SUBnotePorts = {
d.reply(d.loc, "f", getdetune(obj->PDetuneType, 0, obj->PDetune));
}},
//weird stuff for PCoarseDetune
{"octave::c:i", rDoc("Note octave shift"), NULL, [](const char *msg, RtData &d)
{"octave::c:i", rProp(parameter) rDoc("Note octave shift"), NULL,
[](const char *msg, RtData &d)
{
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj;
if(!rtosc_narguments(msg)) {
@@ -106,7 +107,8 @@ static const rtosc::Ports SUBnotePorts = {
obj->PCoarseDetune = k*1024 + obj->PCoarseDetune%1024;
}
}},
{"coarsedetune::c:i", rDoc("Note coarse detune"), NULL, [](const char *msg, RtData &d)
{"coarsedetune::c:i", rProp(parameter) rDoc("Note coarse detune"), NULL,
[](const char *msg, RtData &d)
{
SUBnoteParameters *obj = (SUBnoteParameters *)d.obj;
if(!rtosc_narguments(msg)) {


+ 70
- 30
source/native-plugins/zynaddsubfx/Synth/ADnote.cpp View File

@@ -49,7 +49,6 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
NoteEnabled = ON;
basefreq = spars.frequency;
velocity = spars.velocity;
time = 0.0f;
stereo = pars.GlobalPar.PStereo;

NoteGlobalPar.Detune = getdetune(pars.GlobalPar.PDetuneType,
@@ -87,6 +86,9 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
NoteGlobalPar.Punch.Enabled = 0;

for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) {
for (int i = 0; i < 14; i++)
pinking[nvoice][i] = 0.0;

pars.VoicePar[nvoice].OscilSmp->newrandseed(prng());
NoteVoicePar[nvoice].OscilSmp = NULL;
NoteVoicePar[nvoice].FMSmp = NULL;
@@ -106,6 +108,10 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
if(unison < 1)
unison = 1;

// Since noise unison of greater than two is touch goofy...
if (pars.VoicePar[nvoice].Type != 0 && unison > 2)
unison = 2;

//compute unison
unison_size[nvoice] = unison;

@@ -397,6 +403,13 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
initparameters();
}

SynthNote *ADnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
(bool)portamento, legato.param.midinote, true};
return memory.alloc<ADnote>(&pars, sp);
}

// ADlegatonote: This function is (mostly) a copy of ADnote(...) and
// initparameters() stuck together with some lines removed so that it
// only alter the already playing note (to perform legato). It is
@@ -711,6 +724,7 @@ void ADnote::initparameters()

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

@@ -753,7 +767,7 @@ void ADnote::initparameters()
}

if(param.PAmpLfoEnabled) {
vce.AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, synth.dt());
vce.AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time);
newamplitude[nvoice] *= vce.AmpLfo->amplfoout();
}

@@ -762,7 +776,7 @@ void ADnote::initparameters()
vce.FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, synth.dt());

if(param.PFreqLfoEnabled)
vce.FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, synth.dt());
vce.FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time);

/* Voice Filter Parameters Init */
if(param.PFilterEnabled != 0) {
@@ -776,7 +790,7 @@ void ADnote::initparameters()
vce.FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, synth.dt());

if(param.PFilterLfoEnabled)
vce.FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, synth.dt());
vce.FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time);

vce.FilterFreqTracking =
param.VoiceFilter->getfreqtracking(basefreq);
@@ -1071,7 +1085,6 @@ void ADnote::computecurrentparameters()
}
}
}
time += synth.buffersize_f / synth.samplerate_f;
}


@@ -1417,7 +1430,7 @@ inline void ADnote::ComputeVoiceOscillatorPitchModulation(int /*nvoice*/)
/*
* Computes the Noise
*/
inline void ADnote::ComputeVoiceNoise(int nvoice)
inline void ADnote::ComputeVoiceWhiteNoise(int nvoice)
{
for(int k = 0; k < unison_size[nvoice]; ++k) {
float *tw = tmpwave_unison[k];
@@ -1426,6 +1439,25 @@ inline void ADnote::ComputeVoiceNoise(int nvoice)
}
}

inline void ADnote::ComputeVoicePinkNoise(int nvoice)
{
for(int k = 0; k < unison_size[nvoice]; ++k) {
float *tw = tmpwave_unison[k];
float *f = &pinking[nvoice][k > 0 ? 7 : 0];
for(int i = 0; i < synth.buffersize; ++i) {
float white = (RND-0.5)/4.0;
f[0] = 0.99886*f[0]+white*0.0555179;
f[1] = 0.99332*f[1]+white*0.0750759;
f[2] = 0.96900*f[2]+white*0.1538520;
f[3] = 0.86650*f[3]+white*0.3104856;
f[4] = 0.55000*f[4]+white*0.5329522;
f[5] = -0.7616*f[5]-white*0.0168980;
tw[i] = f[0]+f[1]+f[2]+f[3]+f[4]+f[5]+f[6]+white*0.5362;
f[6] = white*0.115926;
}
}
}



/*
@@ -1448,27 +1480,34 @@ int ADnote::noteout(float *outl, float *outr)
if((NoteVoicePar[nvoice].Enabled != ON)
|| (NoteVoicePar[nvoice].DelayTicks > 0))
continue;
if(NoteVoicePar[nvoice].noisetype == 0) //voice mode=sound
switch(NoteVoicePar[nvoice].FMEnabled) {
case MORPH:
ComputeVoiceOscillatorMorph(nvoice);
break;
case RING_MOD:
ComputeVoiceOscillatorRingModulation(nvoice);
break;
case PHASE_MOD:
ComputeVoiceOscillatorFrequencyModulation(nvoice, 0);
break;
case FREQ_MOD:
ComputeVoiceOscillatorFrequencyModulation(nvoice, 1);
break;
//case PITCH_MOD:ComputeVoiceOscillatorPitchModulation(nvoice);break;
default:
ComputeVoiceOscillator_LinearInterpolation(nvoice);
//if (config.cfg.Interpolation) ComputeVoiceOscillator_CubicInterpolation(nvoice);
}
else
ComputeVoiceNoise(nvoice);
switch (NoteVoicePar[nvoice].noisetype) {
case 0: //voice mode=sound
switch(NoteVoicePar[nvoice].FMEnabled) {
case MORPH:
ComputeVoiceOscillatorMorph(nvoice);
break;
case RING_MOD:
ComputeVoiceOscillatorRingModulation(nvoice);
break;
case PHASE_MOD:
ComputeVoiceOscillatorFrequencyModulation(nvoice, 0);
break;
case FREQ_MOD:
ComputeVoiceOscillatorFrequencyModulation(nvoice, 1);
break;
//case PITCH_MOD:ComputeVoiceOscillatorPitchModulation(nvoice);break;
default:
ComputeVoiceOscillator_LinearInterpolation(nvoice);
//if (config.cfg.Interpolation) ComputeVoiceOscillator_CubicInterpolation(nvoice);
}
break;
case 1:
ComputeVoiceWhiteNoise(nvoice);
break;
default:
ComputeVoicePinkNoise(nvoice);
break;
}
// Voice Processing


@@ -1772,15 +1811,16 @@ void ADnote::Global::kill(Allocator &memory)

void ADnote::Global::initparameters(const ADnoteGlobalParam &param,
const SYNTH_T &synth,
const AbsTime &time,
class Allocator &memory,
float basefreq, float velocity,
bool stereo)
{
FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, synth.dt());
FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, synth.dt());
FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time);

AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, synth.dt());
AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, synth.dt());
AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time);

Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB
* VelF(velocity, param.PAmpVelocityScaleFunction); //sensing
@@ -1794,7 +1834,7 @@ void ADnote::Global::initparameters(const ADnoteGlobalParam &param,
GlobalFilterR = NULL;

FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, synth.dt());
FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, synth.dt());
FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time);
FilterQ = param.GlobalFilter->getq();
FilterFreqTracking = param.GlobalFilter->getfreqtracking(basefreq);
}

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

@@ -53,6 +53,8 @@ class ADnote:public SynthNote
int noteout(float *outl, float *outr);
void releasekey();
int finished() const;

virtual SynthNote *cloneLegato(void) override;
private:

/**Changes the frequency of an oscillator.
@@ -97,7 +99,8 @@ class ADnote:public SynthNote
inline void ComputeVoiceOscillatorPitchModulation(int nvoice);

/**Generate Noise Samples for Voice*/
inline void ComputeVoiceNoise(int nvoice);
inline void ComputeVoiceWhiteNoise(int nvoice);
inline void ComputeVoicePinkNoise(int nvoice);

/**Fadein in a way that removes clicks but keep sound "punchy"*/
inline void fadein(float *smps) const;
@@ -119,6 +122,7 @@ class ADnote:public SynthNote
void kill(Allocator &memory);
void initparameters(const ADnoteGlobalParam &param,
const SYNTH_T &synth,
const AbsTime &time,
class Allocator &memory,
float basefreq, float velocity,
bool stereo);
@@ -246,8 +250,8 @@ class ADnote:public SynthNote
/* INTERNAL VALUES OF THE NOTE AND OF THE VOICES */
/********************************************************/

//time from the start of the note
float time;
//pinking filter (Paul Kellet)
float pinking[NUM_VOICES][14];

//the size of unison for a single voice
int unison_size[NUM_VOICES];


+ 58
- 72
source/native-plugins/zynaddsubfx/Synth/LFO.cpp View File

@@ -28,8 +28,10 @@
#include <cstdio>
#include <cmath>

LFO::LFO(const LFOParams &lfopars, float basefreq, float dt_)
:dt(dt_)
LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t)
:delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec
waveShape(lfopars.PLFOtype),
deterministic(!lfopars.Pfreqrand)
{
int stretch = lfopars.Pstretch;
if(stretch == 0)
@@ -38,24 +40,24 @@ LFO::LFO(const LFOParams &lfopars, float basefreq, float dt_)
//max 2x/octave
const float lfostretch = powf(basefreq / 440.0f, (stretch - 64.0f) / 63.0f);

float lfofreq =
const float lfofreq =
(powf(2, lfopars.Pfreq * 10.0f) - 1.0f) / 12.0f * lfostretch;
incx = fabs(lfofreq) * dt;
phaseInc = fabs(lfofreq) * t.dt();

if(!lfopars.Pcontinous) {
if(lfopars.Pstartphase == 0)
x = RND;
phase = RND;
else
x = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f, 1.0f);
phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f, 1.0f);
}
else {
const float tmp = fmod(lfopars.time * incx, 1.0f);
x = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f + tmp, 1.0f);
const float tmp = fmod(t.time() * phaseInc, 1.0f);
phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f + tmp, 1.0f);
}

//Limit the Frequency(or else...)
if(incx > 0.49999999f)
incx = 0.499999999f;
if(phaseInc > 0.49999999f)
phaseInc = 0.499999999f;


lfornd = limit(lfopars.Prandomness / 127.0f, 0.0f, 1.0f);
@@ -70,88 +72,72 @@ LFO::LFO(const LFOParams &lfopars, float basefreq, float dt_)
break; //in octave
default:
lfointensity = powf(2, lfopars.Pintensity / 127.0f * 11.0f) - 1.0f; //in centi
x -= 0.25f; //chance the starting phase
phase -= 0.25f; //chance the starting phase
break;
}

amp1 = (1 - lfornd) + lfornd * RND;
amp2 = (1 - lfornd) + lfornd * RND;
lfotype = lfopars.PLFOtype;
lfodelay = lfopars.Pdelay / 127.0f * 4.0f; //0..4 sec
incrnd = nextincrnd = 1.0f;
freqrndenabled = (lfopars.Pfreqrand != 0);
computenextincrnd();
computenextincrnd(); //twice because I want incrnd & nextincrnd to be random
computeNextFreqRnd();
computeNextFreqRnd(); //twice because I want incrnd & nextincrnd to be random
}

LFO::~LFO()
{}

/*
* LFO out
*/
float LFO::lfoout()
float LFO::baseOut(const char waveShape, const float phase) const
{
float out;
switch(lfotype) {
case 1: //LFO_TRIANGLE
if((x >= 0.0f) && (x < 0.25f))
out = 4.0f * x;
switch(waveShape) {
case LFO_TRIANGLE:
if(phase >= 0.0f && phase < 0.25f)
return 4.0f * phase;
else if(phase > 0.25f && phase < 0.75f)
return 2 - 4 * phase;
else
if((x > 0.25f) && (x < 0.75f))
out = 2 - 4 * x;
else
out = 4.0f * x - 4.0f;
return 4.0f * phase - 4.0f;
break;
case 2: //LFO_SQUARE
if(x < 0.5f)
out = -1;
case LFO_SQUARE:
if(phase < 0.5f)
return -1;
else
out = 1;
break;
case 3: //LFO_RAMPUP
out = (x - 0.5f) * 2.0f;
return 1;
break;
case 4: //LFO_RAMPDOWN
out = (0.5f - x) * 2.0f;
break;
case 5: //LFO_EXP_DOWN 1
out = powf(0.05f, x) * 2.0f - 1.0f;
break;
case 6: //LFO_EXP_DOWN 2
out = powf(0.001f, x) * 2.0f - 1.0f;
break;
default:
out = cosf(x * 2.0f * PI); //LFO_SINE
case LFO_RAMPUP: return (phase - 0.5f) * 2.0f;
case LFO_RAMPDOWN: return (0.5f - phase) * 2.0f;
case LFO_EXP_DOWN1: return powf(0.05f, phase) * 2.0f - 1.0f;
case LFO_EXP_DOWN2: return powf(0.001f, phase) * 2.0f - 1.0f;
default: return cosf(phase * 2.0f * PI); //LFO_SINE
}
}


if((lfotype == 0) || (lfotype == 1))
out *= lfointensity * (amp1 + x * (amp2 - amp1));
float LFO::lfoout()
{
float out = baseOut(waveShape, phase);

if(waveShape == LFO_SINE || waveShape == LFO_TRIANGLE)
out *= lfointensity * (amp1 + phase * (amp2 - amp1));
else
out *= lfointensity * amp2;
if(lfodelay < 0.00001f) {
if(freqrndenabled == 0)
x += incx;
else {
float tmp = (incrnd * (1.0f - x) + nextincrnd * x);
if(tmp > 1.0f)
tmp = 1.0f;
else
if(tmp < 0.0f)
tmp = 0.0f;
x += incx * tmp;
}
if(x >= 1) {
x = fmod(x, 1.0f);
amp1 = amp2;
amp2 = (1 - lfornd) + lfornd * RND;

computenextincrnd();
}

if(delayTime.inFuture())
return out;

//Start oscillating
if(deterministic)
phase += phaseInc;
else {
const float tmp = (incrnd * (1.0f - phase) + nextincrnd * phase);
phase += phaseInc * limit(tmp, 0.0f, 1.0f);
}
if(phase >= 1) {
phase = fmod(phase, 1.0f);
amp1 = amp2;
amp2 = (1 - lfornd) + lfornd * RND;

computeNextFreqRnd();
}
else
lfodelay -= dt;
return out;
}

@@ -164,9 +150,9 @@ float LFO::amplfoout()
}


void LFO::computenextincrnd()
void LFO::computeNextFreqRnd()
{
if(freqrndenabled == 0)
if(deterministic)
return;
incrnd = nextincrnd;
nextincrnd = powf(0.5f, lfofreqrnd) + RND * (powf(2.0f, lfofreqrnd) - 1.0f);


+ 25
- 12
source/native-plugins/zynaddsubfx/Synth/LFO.h View File

@@ -24,8 +24,9 @@
#define LFO_H

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

/**Class for creating Low Frequency Ocillators*/
/**Class for creating Low Frequency Oscillators*/
class LFO
{
public:
@@ -34,24 +35,36 @@ class LFO
* @param lfopars pointer to a LFOParams object
* @param basefreq base frequency of LFO
*/
LFO(const LFOParams &lfopars, float basefreq, float dt);
/**Deconstructor*/
LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t);
~LFO();

float lfoout();
float amplfoout();
private:
float x;
float incx, incrnd, nextincrnd;
float amp1, amp2; // used for randomness
float baseOut(const char waveShape, const float phase) const;
//Phase of Oscillator
float phase;
//Phase Increment Per Frame
float phaseInc;
//Frequency Randomness
float incrnd, nextincrnd;
//Amplitude Randomness
float amp1, amp2;

//Intensity of the wave
float lfointensity;
//Amount Randomness
float lfornd, lfofreqrnd;
float lfodelay;
const float dt;
/**\todo see if an enum would be better here*/
char lfotype;
int freqrndenabled;

void computenextincrnd();
//Delay before starting
RelTime delayTime;

char waveShape;

//If After initialization there are no calls to random number gen.
bool deterministic;

void computeNextFreqRnd(void);
};

#endif

+ 112
- 71
source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp View File

@@ -44,38 +44,96 @@ pthread_t main_thread;
const rtosc::Ports OscilGen::ports = {
rSelf(OscilGen),
rPaste,
PC(hmagtype),
PC(currentbasefunc),
PC(basefuncpar),
PC(basefuncmodulation),
PC(basefuncmodulationpar1),
PC(basefuncmodulationpar2),
PC(basefuncmodulationpar3),
PC(waveshaping),
PC(waveshapingfunction),
PC(filtertype),
//TODO ensure min/max
rOption(Phmagtype,
rOptions(linear,dB scale (-40),
dB scale (-60), dB scale (-80),
dB scale (-100)),
"Type of magnitude for harmonics"),
rOption(Pcurrentbasefunc,
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,
"Morph between possible base function shapes "
"(e.g. rising sawtooth vs a falling sawtooth)"),
rOption(Pbasefuncmodulation,
rOptions(None, Rev, Sine, Power),
"Modulation applied to Base function spectra"),
rParamZyn(Pbasefuncmodulationpar1,
"Base function modulation parameter"),
rParamZyn(Pbasefuncmodulationpar2,
"Base function modulation parameter"),
rParamZyn(Pbasefuncmodulationpar3,
"Base function modulation parameter"),
rParamZyn(Pwaveshaping, "Degree Of Waveshaping"),
rOption(Pwaveshapingfunction,
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,
lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2,
cos, sin, low_shelf, s), "Harmonic Filter"),
PC(filterpar1),
PC(filterpar2),
PC(filterbeforews),
rToggle(Pfilterbeforews, "Filter before waveshaping spectra;"
"When enabled oscilfilter(freqs); then waveshape(freqs);, "
"otherwise waveshape(freqs); then oscilfilter(freqs);"),
PC(satype),
PC(sapar),
rParamZyn(Psapar, "Spectral Adjustment Parameter"),
rParamI(Pharmonicshift, "Amount of shift on harmonics"),
rToggle(Pharmonicshiftfirst, "If harmonics are shifted before waveshaping/filtering"),
PC(modulation),
PC(modulationpar1),
PC(modulationpar2),
PC(modulationpar3),
rOption(Pmodulation, rOptions(None, Rev, Sine, Power),
"Frequency Modulation To Combined Spectra"),
rParamZyn(Pmodulationpar1,
"modulation parameter"),
rParamZyn(Pmodulationpar2,
"modulation parameter"),
rParamZyn(Pmodulationpar3,
"modulation parameter"),
//FIXME realtime parameters lurking below
PC(rand),
PC(amprandpower),
PC(amprandtype),
PC(adaptiveharmonics),
PC(adaptiveharmonicsbasefreq),
PC(adaptiveharmonicspower),
PC(adaptiveharmonicspar),
rParamZyn(Pamprandpower,
"Variance of harmonic randomness"),
rOption(Pamprandtype, rOptions(None, Pow, Sin),
"Harmonic random distribution to select from"),
rOption(Padaptiveharmonics,
rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd),
"Adaptive Harmonics Mode"),
rParamI(Padaptiveharmonicsbasefreq, rLinear(0,255),
"Base frequency of adaptive harmonic (30..3000Hz)"),
rParamI(Padaptiveharmonicspower,rLinear(0,200),
"Adaptive Harmonic Strength"),
rParamZyn(Padaptiveharmonicspar,
"Adaptive Harmonics Postprocessing Power"),

//TODO update to rArray and test
{"phase#128::c", rDoc("Sets harmonic phase"),
{"phase#128::c", rProp(parameter) rDoc("Sets harmonic phase"),
NULL, [](const char *m, rtosc::RtData &d) {
const char *mm = m;
while(*mm && !isdigit(*mm)) ++mm;
@@ -86,7 +144,7 @@ const rtosc::Ports OscilGen::ports = {
phase = rtosc_argument(m,0).i;
}},
//TODO update to rArray and test
{"magnitude#128::c", rDoc("Sets harmonic magnitude"),
{"magnitude#128::c", rProp(parameter) rDoc("Sets harmonic magnitude"),
NULL, [](const char *m, rtosc::RtData &d) {
//printf("I'm at '%s'\n", d.loc);
const char *mm = m;
@@ -153,6 +211,10 @@ const rtosc::Ports OscilGen::ports = {
NULL, [](const char *, rtosc::RtData &d) {
((OscilGen*)d.obj)->convert2sine();
}},
{"use-as-base:", rProp(non-realtime) rDoc("Translates current waveform into base"),
NULL, [](const char *, rtosc::RtData &d) {
((OscilGen*)d.obj)->useasbase();
}},
{"prepare:b", rProp(internal) rProp(non-realtime) rProp(pointer) rDoc("Sets prepared fft data"),
NULL, [](const char *m, rtosc::RtData &d) {
//fprintf(stderr, "prepare:b got a message from '%s'\n", m);
@@ -385,64 +447,45 @@ void OscilGen::convert2sine()
*/
void OscilGen::getbasefunction(float *smps)
{
int i;
float par = (Pbasefuncpar + 0.5f) / 128.0f;
if(Pbasefuncpar == 64)
par = 0.5f;

float basefuncmodulationpar1 = Pbasefuncmodulationpar1 / 127.0f,
basefuncmodulationpar2 = Pbasefuncmodulationpar2 / 127.0f,
basefuncmodulationpar3 = Pbasefuncmodulationpar3 / 127.0f;
float p1 = Pbasefuncmodulationpar1 / 127.0f,
p2 = Pbasefuncmodulationpar2 / 127.0f,
p3 = Pbasefuncmodulationpar3 / 127.0f;

switch(Pbasefuncmodulation) {
case 1:
basefuncmodulationpar1 =
(powf(2, basefuncmodulationpar1 * 5.0f) - 1.0f) / 10.0f;
basefuncmodulationpar3 =
floor((powf(2, basefuncmodulationpar3 * 5.0f) - 1.0f));
if(basefuncmodulationpar3 < 0.9999f)
basefuncmodulationpar3 = -1.0f;
p1 = (powf(2, p1 * 5.0f) - 1.0f) / 10.0f;
p3 = floor(powf(2, p3 * 5.0f) - 1.0f);
if(p3 < 0.9999f)
p3 = -1.0f;
break;
case 2:
basefuncmodulationpar1 =
(powf(2, basefuncmodulationpar1 * 5.0f) - 1.0f) / 10.0f;
basefuncmodulationpar3 = 1.0f
+ floor((powf(2, basefuncmodulationpar3
* 5.0f) - 1.0f));
p1 = (powf(2, p1 * 5.0f) - 1.0f) / 10.0f;
p3 = 1.0f + floor(powf(2, p3 * 5.0f) - 1.0f);
break;
case 3:
basefuncmodulationpar1 =
(powf(2, basefuncmodulationpar1 * 7.0f) - 1.0f) / 10.0f;
basefuncmodulationpar3 = 0.01f
+ (powf(2, basefuncmodulationpar3
* 16.0f) - 1.0f) / 10.0f;
p1 = (powf(2, p1 * 7.0f) - 1.0f) / 10.0f;
p3 = 0.01f + (powf(2, p3 * 16.0f) - 1.0f) / 10.0f;
break;
}

base_func func = getBaseFunction(Pcurrentbasefunc);

for(i = 0; i < synth.oscilsize; ++i) {
for(int i = 0; i < synth.oscilsize; ++i) {
float t = i * 1.0f / synth.oscilsize;

switch(Pbasefuncmodulation) {
case 1:
t = t * basefuncmodulationpar3 + sinf(
(t
+ basefuncmodulationpar2) * 2.0f
* PI) * basefuncmodulationpar1; //rev
case 1: //rev
t = t * p3 + sinf((t + p2) * 2.0f * PI) * p1;
break;
case 2:
t = t + sinf(
(t * basefuncmodulationpar3
+ basefuncmodulationpar2) * 2.0f
* PI) * basefuncmodulationpar1; //sine
case 2: //sine
t += sinf( (t * p3 + p2) * 2.0f * PI) * p1;
break;
case 3:
t = t + powf((1.0f - cosf(
(t
+ basefuncmodulationpar2) * 2.0f
* PI)) * 0.5f,
basefuncmodulationpar3) * basefuncmodulationpar1; //power
case 3: //power
t += powf((1.0f - cosf((t + p2) * 2.0f * PI)) * 0.5f, p3) * p1;
break;
}

@@ -652,12 +695,11 @@ void OscilGen::spectrumadjust(fft_t *freqs)
break;
}


normalize(freqs, synth.oscilsize);

for(int i = 0; i < synth.oscilsize / 2; ++i) {
float mag = abs(oscilFFTfreqs, i);
float phase = M_PI_2 - arg(oscilFFTfreqs, i);
float mag = abs(freqs, i);
float phase = M_PI_2 - arg(freqs, i);

switch(Psatype) {
case 1:
@@ -783,13 +825,12 @@ void OscilGen::prepare(fft_t *freqs)
if(Pharmonicshiftfirst != 0)
shiftharmonics(freqs);

if(Pfilterbeforews == 0) {
waveshape(freqs);
oscilfilter(freqs);
}
else {
if(Pfilterbeforews) {
oscilfilter(freqs);
waveshape(freqs);
} else {
waveshape(freqs);
oscilfilter(freqs);
}

modulation(freqs);
@@ -876,9 +917,9 @@ void OscilGen::adaptiveharmonicpostprocess(fft_t *f, int size)
if(Padaptiveharmonics == 2) { //2n+1
for(int i = 0; i < size; ++i)
if((i % 2) == 0)
f[i] += inf[i]; //i=0 pt prima armonica,etc.
f[i] += inf[i]; //i=0 first harmonic,etc.
}
else { //celelalte moduri
else { //other ways
int nh = (Padaptiveharmonics - 3) / 2 + 2;
int sub_vs_add = (Padaptiveharmonics - 3) % 2;
if(sub_vs_add == 0) {


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

@@ -84,7 +84,7 @@ class OscilGen:public Presets

unsigned char Pwaveshaping, Pwaveshapingfunction;
unsigned char Pfiltertype, Pfilterpar1, Pfilterpar2;
unsigned char Pfilterbeforews;
bool Pfilterbeforews;
unsigned char Psatype, Psapar; //spectrum adjust

int Pharmonicshift; //how the harmonics are shifted


+ 13
- 6
source/native-plugins/zynaddsubfx/Synth/PADnote.cpp View File

@@ -28,7 +28,7 @@
#include "../Params/FilterParams.h"
#include "../Misc/Util.h"

PADnote::PADnote(PADnoteParameters *parameters,
PADnote::PADnote(const PADnoteParameters *parameters,
SynthParams pars, const int& interpolation)
:SynthNote(pars), pars(*parameters), interpolation(interpolation)
{
@@ -121,9 +121,9 @@ void PADnote::setup(float freq,
((powf(10, 1.5f * pars.PPunchStrength / 127.0f) - 1.0f)
* VelF(velocity,
pars.PPunchVelocitySensing));
float time =
const float time =
powf(10, 3.0f * pars.PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms
float stretch = powf(440.0f / freq, pars.PPunchStretch / 64.0f);
const float stretch = powf(440.0f / freq, pars.PPunchStretch / 64.0f);
NoteGlobalPar.Punch.dt = 1.0f
/ (time * synth.samplerate_f * stretch);
}
@@ -131,10 +131,10 @@ void PADnote::setup(float freq,
NoteGlobalPar.Punch.Enabled = 0;

NoteGlobalPar.FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, basefreq, synth.dt());
NoteGlobalPar.FreqLfo = memory.alloc<LFO>(*pars.FreqLfo, 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, synth.dt());
NoteGlobalPar.AmpLfo = memory.alloc<LFO>(*pars.AmpLfo, basefreq, time);
}

NoteGlobalPar.Volume = 4.0f
@@ -154,7 +154,7 @@ void PADnote::setup(float freq,
synth.samplerate, synth.buffersize);

NoteGlobalPar.FilterEnvelope = memory.alloc<Envelope>(*pars.FilterEnvelope, basefreq, synth.dt());
NoteGlobalPar.FilterLfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, synth.dt());
NoteGlobalPar.FilterLfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, time);
}
NoteGlobalPar.FilterQ = pars.GlobalFilter->getq();
NoteGlobalPar.FilterFreqTracking = pars.GlobalFilter->getfreqtracking(
@@ -166,6 +166,13 @@ void PADnote::setup(float freq,
}
}

SynthNote *PADnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
(bool)portamento, legato.param.midinote, true};
return memory.alloc<PADnote>(&pars, sp, interpolation);
}

void PADnote::legatonote(LegatoParams pars)
{
// Manage legato stuff


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

@@ -30,10 +30,11 @@
class PADnote:public SynthNote
{
public:
PADnote(PADnoteParameters *parameters, SynthParams pars,
PADnote(const PADnoteParameters *parameters, SynthParams pars,
const int &interpolation);
~PADnote();

SynthNote *cloneLegato(void);
void legatonote(LegatoParams pars);

int noteout(float *outl, float *outr);


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

@@ -44,7 +44,7 @@ const rtosc::Ports Resonance::ports = {
rAction(smooth, "Smooth out frequency response"),
rAction(zero, "Reset frequency response"),
//UI Value listeners
{"centerfreq:", rDoc("Get center frequency"), NULL,
{"centerfreq:", rDoc("Get center frequency") rMap(unit, Hz), NULL,
[](const char *, RtData &d)
{d.reply(d.loc, "f", ((rObject*)d.obj)->getcenterfreq());}},
{"octavesfreq:", rDoc("Get center freq of graph"), NULL,


+ 9
- 1
source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp View File

@@ -33,7 +33,7 @@
#include "../Misc/Util.h"
#include "../Misc/Allocator.h"

SUBnote::SUBnote(SUBnoteParameters *parameters, SynthParams &spars)
SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
:SynthNote(spars), pars(*parameters)
{
NoteEnabled = ON;
@@ -46,6 +46,7 @@ void SUBnote::setup(float freq,
int midinote,
bool legato)
{
this->velocity = velocity;
portamento = portamento_;
NoteEnabled = ON;
volume = powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)); //-60 dB .. 0 dB
@@ -210,6 +211,13 @@ void SUBnote::setup(float freq,
oldamplitude = newamplitude;
}

SynthNote *SUBnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
(bool)portamento, legato.param.midinote, true};
return memory.alloc<SUBnote>(&pars, sp);
}

void SUBnote::legatonote(LegatoParams pars)
{
// Manage legato stuff


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

@@ -30,9 +30,10 @@
class SUBnote:public SynthNote
{
public:
SUBnote(SUBnoteParameters *parameters, SynthParams &pars);
SUBnote(const SUBnoteParameters *parameters, SynthParams &pars);
~SUBnote();

SynthNote *cloneLegato(void);
void legatonote(LegatoParams pars);

int noteout(float *outl, float *outr); //note output,return 0 if the note is finished
@@ -100,6 +101,7 @@ class SUBnote:public SynthNote

int oldpitchwheel, oldbandwidth;
float globalfiltercenterq;
float velocity;
};

#endif

+ 3
- 3
source/native-plugins/zynaddsubfx/Synth/SynthNote.cpp View File

@@ -3,9 +3,9 @@
#include <cstring>

SynthNote::SynthNote(SynthParams &pars)
:legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
pars.note, pars.quiet),
memory(pars.memory), ctl(pars.ctl), synth(pars.synth)
:memory(pars.memory),
legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
pars.note, pars.quiet), ctl(pars.ctl), synth(pars.synth), time(pars.time)
{}

SynthNote::Legato::Legato(const SYNTH_T &synth_, float freq, float vel, int port,


+ 10
- 3
source/native-plugins/zynaddsubfx/Synth/SynthNote.h View File

@@ -28,8 +28,9 @@ class Controller;
struct SynthParams
{
Allocator &memory; //Memory Allocator for the Note to use
Controller &ctl;
const Controller &ctl;
const SYNTH_T &synth;
const AbsTime &time;
float frequency; //Note base frequency
float velocity; //Velocity of the Note
bool portamento;//True if portamento is used for this note
@@ -65,8 +66,14 @@ class SynthNote
virtual int finished() const = 0;

virtual void legatonote(LegatoParams pars) = 0;

virtual SynthNote *cloneLegato(void) = 0;

/* For polyphonic aftertouch needed */
void setVelocity(float velocity_);

//Realtime Safe Memory Allocator For notes
class Allocator &memory;
protected:
// Legato transitions
class Legato
@@ -87,6 +94,7 @@ class SynthNote
int length;
float m, step;
} fade;
public:
struct { // Note parameters
float freq, vel;
bool portamento;
@@ -103,10 +111,9 @@ class SynthNote
void setDecounter(int decounter_) {decounter = decounter_; }
} legato;

//Realtime Safe Memory Allocator For notes
class Allocator &memory;
const Controller &ctl;
const SYNTH_T &synth;
const AbsTime &time;
};

#endif

+ 120
- 59
source/native-plugins/zynaddsubfx/UI/ADnoteUI.fl View File

@@ -70,12 +70,21 @@ decl {\#include "OscilGenUI.h"} {public local
decl {\#include "PresetsUI.h"} {public local
}

decl {\#include "PartUI.h"} {private local
}

decl {\#include "MasterUI.h"} {private local
}

decl {extern class MasterUI *ui;} {private local
}

class ADvoicelistitem {open : {public Fl_Osc_Group}
} {
Function {make_window()} {open private
} {
Fl_Window ADnoteVoiceListItem {open
private xywh {346 881 615 100} type Double box UP_FRAME
private xywh {117 90 670 100} type Double box NO_BOX
class Fl_Osc_Group visible
} {
Fl_Box {} {
@@ -83,61 +92,61 @@ class ADvoicelistitem {open : {public Fl_Osc_Group}
code0 {ADnoteVoiceListItem->base = loc;}
}
Fl_Group voicelistitemgroup {open
private xywh {50 0 570 25}
private xywh {0 0 670 25}
class Fl_Osc_Group
} {
Fl_Value_Slider voicevolume {
tooltip Volume xywh {90 5 115 20} type {Horz Knob} box NO_BOX labelsize 8 align 5 maximum 127 step 1
tooltip Volume xywh {132 5 115 20} type {Horz Knob} box NO_BOX labelsize 8 align 5 maximum 127 step 1
code1 {o->init("PVolume");}
class Fl_Osc_VSlider
}
Fl_Check_Button voiceresonanceenabled {
tooltip {Resonance On/Off} xywh {245 7 15 17} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 11 align 4
tooltip {Resonance On/Off} xywh {287 7 15 17} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 11 align 4
code0 {o->init("Presonance");}
class Fl_Osc_Check
}
Fl_Value_Slider voicelfofreq {
tooltip {Frequency LFO amount} xywh {500 5 115 20} type {Horz Knob} box NO_BOX labelsize 8 align 5 maximum 127 step 1
tooltip {Frequency LFO amount} xywh {542 5 115 20} type {Horz Knob} box NO_BOX labelsize 8 align 5 maximum 127 step 1
code0 {o->init("FreqLfo/Pintensity", 'i');}
class Fl_Osc_Slider
class Fl_Osc_VSlider
}
Fl_Dial voicepanning {
tooltip {Panning (leftmost is Random)} xywh {215 5 20 20} box ROUND_UP_BOX labelsize 10 align 4 maximum 127 step 1
tooltip {Panning (leftmost is Random)} xywh {257 5 20 20} box ROUND_UP_BOX labelsize 10 align 4 maximum 127 step 1
code0 {o->init("PPanning");}
class Fl_Osc_Dial
}
Fl_Group voiceoscil {open
xywh {60 5 30 20} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179
xywh {102 5 30 20} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179
code0 {voiceoscil->ext = "OscilSmp/";}
code1 {oscil=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");}
code2 {oscil->init(false);}
class Fl_Osc_Group
} {}
Fl_Value_Output detunevalueoutput {
xywh {265 5 45 20} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10
xywh {307 5 45 20} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10
code0 {o->init("detunevalue");}
class Fl_Osc_Output
}
Fl_Slider voicedetune {
callback {detunevalueoutput->update();}
tooltip {Fine Detune (cents)} xywh {315 5 185 20} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1
tooltip {Fine Detune (cents)} xywh {357 5 185 20} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1
code0 {o->init("PDetune",'i');}
class Fl_Osc_Slider
}
Fl_Box noiselabel {
Fl_Box whitenoiselabel {
label N
xywh {65 5 20 20} labelfont 1 labelsize 13 labelcolor 7
xywh {107 5 20 20} labelfont 1 labelsize 13 labelcolor 7
}
Fl_Check_Button noisehack {
callback {if (o->value()==0) {
noiselabel->hide();
whitenoiselabel->hide();
voiceresonanceenabled->activate();
detunevalueoutput->activate();
voicedetune->activate();
voicelfofreq->activate();
voiceoscil->activate();
} else {
noiselabel->show();
whitenoiselabel->show();
voiceresonanceenabled->deactivate();
detunevalueoutput->deactivate();
voicedetune->deactivate();
@@ -159,6 +168,21 @@ o->redraw();}
code1 {o->init("Enabled");}
class Fl_Osc_Check
}
Fl_Button {} {
label edit
callback {
class ADnoteUI *adnoteui = ui->partui->adnoteui;
adnoteui->ADnoteVoice->show();
adnoteui->currentvoicecounter->value(nvoice+1);
adnoteui->currentvoicecounter->do_callback();
class ADvoiceUI *advoice = adnoteui->advoice;
if (advoice->mod_type->value() == 0)
advoice->voiceFMparametersgroup->deactivate();
else
advoice->voiceFMparametersgroup->activate();
}
xywh {53 6 40 15} box THIN_UP_BOX labelsize 11
}
}
}
Function {ADvoicelistitem(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h,label)} {open
@@ -281,7 +305,7 @@ o->redraw();}
label Vol
tooltip Volume xywh {540 80 160 15} type {Horz Knob} box NO_BOX labelsize 11 align 8 maximum 127 step 1
code0 {o->init("PFMVolume", 'i');}
class Fl_Osc_Slider
class Fl_Osc_VSlider
}
Fl_Value_Slider {} {
label {V.Sns}
@@ -309,7 +333,7 @@ o->redraw();}
label {F.Damp}
tooltip {Modulator Damp at Higher frequency} xywh {540 120 160 15} type {Horz Knob} box NO_BOX labelsize 11 align 8 minimum -64 maximum 63 step 1
code0 {o->init("PFMVolumeDamp",'i');}
class Fl_Osc_Slider
class Fl_Osc_VSlider
}
}
Fl_Group modoscil {open
@@ -361,11 +385,11 @@ voiceFMparametersgroup->redraw();} open
xywh {560 410 75 20} down_box BORDER_BOX labelsize 10 textfont 1 textsize 10
code0 {o->add("Internal");}
code1 {char tmp[50]; for (int i=0;i<nvoice;i++) {sprintf(tmp,"ExtM.%2d",i+1);o->add(tmp);};}
code3 {o->init("PextFMoscil",1);}
code3 {o->init("PextFMoscil",-1);}
class Fl_Osc_Choice
} {}
}
Fl_Choice {} {
Fl_Choice extMod {
label {External Mod.}
callback {if ((int) o->value() != 0) {
modoscil->deactivate();
@@ -383,7 +407,7 @@ voiceFMparametersgroup->redraw();} open
class Fl_Osc_Choice
} {}
}
Fl_Choice {} {
Fl_Choice mod_type {
label {Type:}
callback {if (o->value()==0) voiceFMparametersgroup->deactivate();
else voiceFMparametersgroup->activate();
@@ -551,25 +575,12 @@ voiceonbutton->redraw();} open
xywh {5 470 65 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10
code0 {o->add("Internal");}
code1 {char tmp[50]; for (int i=0;i<nvoice;i++) {sprintf(tmp,"Ext.%2d",i+1);o->add(tmp);};}
code3 {o->init("Pextoscil",1);}
code3 {o->init("Pextoscil",-1);}
class Fl_Osc_Choice
} {}
Fl_Group {} {open
xywh {5 540 520 50} box UP_FRAME
} {
Fl_Dial {} {
label Stereo
tooltip {Stereo Spread} xywh {322 555 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("Unison_stereo_spread");}
class Fl_Osc_Dial
}
Fl_Choice {} {
label Unison
tooltip {Unison size} xywh {10 560 75 20} down_box BORDER_BOX labelfont 1 align 5 textfont 1 textsize 10
code0 {o->add("OFF");char tmp[100];for (int i=1;ADnote_unison_sizes[i];i++){snprintf(tmp,100,"size %d",ADnote_unison_sizes[i]);o->add(tmp);};}
code1 {o->init("Unison_size");}
class Fl_Osc_Choice
} {}
Fl_Dial {} {
label Vibrato
tooltip Vibrato xywh {364 555 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
@@ -718,8 +729,11 @@ o->redraw();}
code0 {char tmp[10];snprintf(tmp,10,"%d",nvoice+1);o->label(strdup(tmp));}
} {}
Fl_Choice {} {
callback {if (o->value()==0){ voicemodegroup->activate(); noiselabel->hide();}
else{ voicemodegroup->deactivate(); noiselabel->show();}}
callback {switch (o->value()) {
case 0: voicemodegroup->activate(); whitenoiselabel->hide(); pinknoiselabel->hide(); break;
case 1: voicemodegroup->deactivate(); whitenoiselabel->show(); pinknoiselabel->hide(); break;
default: voicemodegroup->deactivate(); whitenoiselabel->hide(); pinknoiselabel->show(); break;
}} open
tooltip {Oscillator Type (sound/noise)} xywh {5 515 65 20} down_box BORDER_BOX labelsize 10 textfont 1 textsize 10
code0 {o->init("Type");}
class Fl_Osc_Choice
@@ -729,8 +743,12 @@ o->redraw();}
xywh {5 5 100 20} labelfont 1 labelsize 11
}
MenuItem {} {
label NOISE
xywh {15 15 100 20} labelfont 1 labelsize 11 labelcolor 1
label White
xywh {15 15 100 20} labelfont 1 labelsize 11 labelcolor 55
}
MenuItem {} {
label Pink
xywh {25 25 100 20} labelfont 1 labelsize 11 labelcolor 211
}
}
Fl_Check_Button bypassfiltercheckbutton {
@@ -759,10 +777,27 @@ bypassfiltercheckbutton->redraw();}
code0 {o->init("PFilterEnabled");}
class Fl_Osc_Check
}
Fl_Box noiselabel {
Fl_Box whitenoiselabel {
label {White Noise}
xywh {150 430 300 65} labelfont 1 labelsize 50 labelcolor 53 hide
}
Fl_Box pinknoiselabel {
label {Pink Noise}
xywh {150 430 300 65} labelfont 1 labelsize 50 labelcolor 212 hide
}
Fl_Dial {} {
label Stereo
tooltip {Stereo Spread} xywh {327 560 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("Unison_stereo_spread");}
class Fl_Osc_Dial
}
Fl_Counter {} {
label Unison selected
tooltip {Unison size} xywh {20 568 65 18} labelfont 1 align 5 minimum 1 maximum 64 step 1 value 1 textfont 1 textsize 11
code0 {o->init("Unison_size", 1);}
code1 {o->lstep(5);}
class Fl_Osc_Counter
}
}
Fl_Check_Button voiceonbutton {
label On
@@ -802,9 +837,29 @@ delete(oscedit);
} {
code {nvoice = nvoice_;
loc = base+"VoicePar"+to_s(nvoice)+"/";
char tmp[10];snprintf(tmp,10,"%d",nvoice+1);
char tmp[50];snprintf(tmp,10,"%d",nvoice+1);
activeVoiceID->label(strdup(tmp));
ADnoteVoiceParameters->rebase(base+"VoicePar"+to_s(nvoice)+"/");} {selected
extoscil->clear();
extoscil->add("Internal");
for (int i=0;i<nvoice;i++) {
sprintf(tmp,"Ext.%2d",i+1);
extoscil->add(tmp);
};

extFMoscil->clear();
extFMoscil->add("Internal");
for (int i=0;i<nvoice;i++) {
sprintf(tmp,"ExtM.%2d",i+1);
extFMoscil->add(tmp);
}
extMod->clear();
extMod->add("OFF");
for (int i=0;i<nvoice;i++) {
sprintf(tmp,"ExtMod.%2d",i+1);
extMod->add(tmp);
}
ADnoteVoiceParameters->rebase(base+"VoicePar"+to_s(nvoice)+"/");} {selected
}
}
decl {int nvoice;} {private local
@@ -834,7 +889,7 @@ class ADnoteUI {open : {public PresetsUI_}
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {ADnoteGlobalParameters->base = loc + "GlobalPar/"; ADnoteGlobalParameters->osc = osc;}
code0 {ADnoteGlobalParameters->init(osc, loc + "GlobalPar/");}
}
Fl_Group {} {
label FREQUENCY open
@@ -879,7 +934,10 @@ class ADnoteUI {open : {public PresetsUI_}
}
Fl_Choice detunetype {
label {Detune Type}
callback {detunevalueoutput->update();} open
callback {detunevalueoutput->update();
ui->partui->adnoteui->advoice->detunevalueoutput->update();
ui->partui->adnoteui->advoice->fmdetunevalueoutput->update();
} open
xywh {455 340 75 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10
code0 {o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");}
code1 {o->init("PDetuneType",1);}
@@ -1000,7 +1058,12 @@ ADnoteVoiceList->show();}
}
Fl_Button {} {
label {Show Voice Parameters}
callback {ADnoteVoice->show();}
callback {
if (advoice->mod_type->value() == 0)
advoice->voiceFMparametersgroup->deactivate();
else
advoice->voiceFMparametersgroup->activate();
ADnoteVoice->show();}
xywh {5 400 170 25} labelsize 12
}
Fl_Button {} {
@@ -1032,8 +1095,7 @@ resui->resonancewindow->show();}
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {ADnoteVoice->base = loc;}
code1 {ADnoteVoice->osc = osc;}
code0 {ADnoteVoice->init(osc,loc);}
}
Fl_Group advoice {open
xywh {0 0 765 595}
@@ -1066,49 +1128,48 @@ advoice->change_voice(nvoice);}
}
Fl_Window ADnoteVoiceList {
label {ADsynth Voices list} open
xywh {32 266 650 260} type Double hide
xywh {6 263 670 260} type Double hide
class Fl_Osc_Window
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {ADnoteVoiceList->base = loc;}
code1 {ADnoteVoiceList->osc = osc;}
code0 {ADnoteVoiceList->init(osc, loc);}
}
Fl_Text_Display {} {
label {No.}
xywh {10 15 30 10} box NO_BOX labelfont 1 labelsize 11
xywh {17 15 30 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Text_Display {} {
label Vol
xywh {145 15 30 10} box NO_BOX labelfont 1 labelsize 11
xywh {190 15 30 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Text_Display {} {
label Detune
xywh {384 15 25 10} box NO_BOX labelfont 1 labelsize 11
xywh {431 15 25 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Text_Display {} {
label Pan
xywh {210 15 30 10} box NO_BOX labelfont 1 labelsize 11
xywh {253 15 30 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Text_Display {} {
label {Vib. Depth}
xywh {560 15 30 10} box NO_BOX labelfont 1 labelsize 11
label {Vib. Depth} selected
xywh {600 15 30 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Text_Display {} {
label {R.}
xywh {245 15 25 10} box NO_BOX labelfont 1 labelsize 11
xywh {285 15 25 10} box NO_BOX labelfont 1 labelsize 11
}
Fl_Button {} {
label {Hide Voice List}
callback {ADnoteVoiceList->hide();}
xywh {255 237 125 20}
xywh {271 237 125 20}
}
Fl_Scroll {} {open
xywh {0 15 640 220} type VERTICAL box THIN_UP_BOX
xywh {0 15 670 220} type VERTICAL box THIN_UP_BOX
} {
Fl_Pack {} {open
xywh {0 20 620 210}
code0 {o->begin();for (int i=0;i<NUM_VOICES;i++){voicelistitem[i]=new ADvoicelistitem(0,0,620,25,"");voicelistitem[i]->init(i,loc+"VoicePar"+to_s(i)+"/",osc);}o->end();}
xywh {0 20 670 210}
code0 {o->begin();for (int i=0;i<NUM_VOICES;i++){voicelistitem[i]=new ADvoicelistitem(0,0,670,25,"");voicelistitem[i]->init(i,loc+"VoicePar"+to_s(i)+"/",osc);}o->end();}
} {}
}
}


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

@@ -29,6 +29,9 @@ decl {\#include "Fl_Osc_Interface.h"} {public local
decl {\#include "Fl_Osc_Check.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include "../Misc/Util.h"} {public local
}

@@ -46,8 +49,7 @@ class BankUI {open
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {bankuiwindow->osc = osc;}
code1 {bankuiwindow->base = "/";}
code0 {bankuiwindow->init(osc, "/");}
}
Fl_Button {} {
label Close


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

@@ -21,7 +21,7 @@ void BankList::init(std::string path)

void BankList::OSC_raw(const char *msg)
{
if(!strcmp(msg, "/bank-list")) {
if(!strcmp(msg, "/bank-list") && !strcmp(rtosc_argument_string(msg),"iss")) {

const int pos = rtosc_argument(msg, 0).i;
const char *path = rtosc_argument(msg, 1).s;
@@ -33,7 +33,7 @@ void BankList::OSC_raw(const char *msg)
this->add(path);
osc->write("/loadbank");
}
if(!strcmp(msg, "/loadbank")) {
if(!strcmp(msg, "/loadbank")&& !strcmp(rtosc_argument_string(msg),"i")) {
value(rtosc_argument(msg, 0).i);
}
}


+ 5
- 3
source/native-plugins/zynaddsubfx/UI/ConfigUI.fl View File

@@ -44,6 +44,9 @@ decl {\#include "Fl_Osc_Numeric_Input.H"} {public local
decl {\#include "Fl_Osc_ListView.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include "../globals.h"} {public local
}

@@ -60,8 +63,7 @@ class ConfigUI {} {
} {
Fl_Box dummy {
xywh {25 25 25 25}
code0 {configwindow->osc = osc;}
code1 {configwindow->base = "/config/";}
code0 {configwindow->init(osc, "/config/");}
}
Fl_Tabs {} {
xywh {5 5 500 330}
@@ -291,7 +293,7 @@ activatebutton_presetdir(true);}
oscilsize->callback = [this](int i){
oscilsize_widget->value(i-7);
};
oscilsize->update("/config/cfg.OscilPower");
oscilsize->doUpdate("/config/cfg.OscilPower");
} {}
}


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

@@ -345,14 +345,18 @@ class UI_Interface:public Fl_Osc_Interface
{
#ifndef NO_UI
printf("\n\nDamage(\"%s\")\n", path);
std::set<Fl_Osc_Widget*> to_update;
for(auto pair:map) {
if(strstr(pair.first.c_str(), path)) {
auto *tmp = dynamic_cast<Fl_Widget*>(pair.second);
if(!tmp || tmp->visible_r()) {
pair.second->update();
to_update.insert(pair.second);
}
}
}

for(auto elm:to_update)
elm->update();
#endif
}



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

@@ -1,7 +1,7 @@
#include "Connection.h"
#include <unistd.h>
namespace GUI {
ui_handle_t createUi(Fl_Osc_Interface*, void *exit)
ui_handle_t createUi(Fl_Osc_Interface*, void *)
{
return 0;
}


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

@@ -29,6 +29,9 @@ decl {\#include "Fl_Osc_Check.H"} {public local
decl {\#include "Fl_EQGraph.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include "EnvelopeUI.h"} {public local
}

@@ -150,7 +153,7 @@ if (filterwindow!=NULL){
label Type
callback {if(o->value()==2) revp12->activate();
else revp12->deactivate();}
xywh {110 15 85 15} down_box BORDER_BOX color 14 selection_color 7 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10
xywh {110 15 85 15} box UP_BOX down_box BORDER_BOX color 14 selection_color 7 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10
code0 {o->init("parameter10");}
class Fl_Osc_Choice
} {


+ 117
- 47
source/native-plugins/zynaddsubfx/UI/EnvelopeFreeEdit.cpp View File

@@ -21,6 +21,12 @@ void EnvelopeFreeEdit::init(void)
oscRegister("Penvdt");
oscRegister("Penvval");
oscRegister("Penvsustain");

//register for non-bulk types
for(int i=0; i<MAX_ENVELOPE_POINTS; ++i) {
osc->createLink(loc+string("Penvdt") + to_s(i), this);
osc->createLink(loc+string("Penvval") + to_s(i), this);
}
}

void EnvelopeFreeEdit::OSC_raw(const char *msg)
@@ -36,6 +42,16 @@ void EnvelopeFreeEdit::OSC_raw(const char *msg)
rtosc_blob_t b = rtosc_argument(msg, 0).b;
assert(b.len == MAX_ENVELOPE_POINTS);
memcpy(Penvval, b.data, MAX_ENVELOPE_POINTS);
} else if(strstr(msg, "Penvval") && !strcmp(args, "c")) {
const char *str = strstr(msg, "Penvval");
int id = atoi(str+7);
assert(0 <= id && id < MAX_ENVELOPE_POINTS);
Penvval[id] = rtosc_argument(msg, 0).i;
} else if(strstr(msg, "Penvdt") && !strcmp(args, "c")) {
const char *str = strstr(msg, "Penvdt");
int id = atoi(str+6);
assert(0 <= id && id < MAX_ENVELOPE_POINTS);
Penvdt[id] = rtosc_argument(msg, 0).i;
} else if(strstr(msg,"Penvsustain") && !strcmp(args, "i")) {
Penvsustain = rtosc_argument(msg, 0).i;
}
@@ -98,6 +114,8 @@ float EnvelopeFreeEdit::getdt(int i) const
return dt(Penvdt[i]);
}

static bool ctrldown;

void EnvelopeFreeEdit::draw(void)
{
int ox=x(),oy=y(),lx=w(),ly=h();
@@ -129,8 +147,10 @@ void EnvelopeFreeEdit::draw(void)
for (int i=1; i<npoints; ++i){
oldxx=xx;oldyy=yy;
xx=getpointx(i);yy=getpointy(i);
if (i==currentpoint) fl_color(FL_RED);
else fl_color(alb);
if (i==currentpoint || (ctrldown && i==lastpoint))
fl_color(FL_RED);
else
fl_color(alb);
fl_line(ox+oldxx,oy+oldyy,ox+xx,oy+yy);
fl_rectf(ox+xx-3,oy+yy-3,6,6);
}
@@ -151,13 +171,13 @@ void EnvelopeFreeEdit::draw(void)
//Show the envelope duration and the current line duration
fl_font(FL_HELVETICA|FL_BOLD,10);
float time=0.0;
if (currentpoint<=0){
if (currentpoint<=0 && (!ctrldown||lastpoint <= 0)){
fl_color(alb);
for(int i=1; i<npoints; ++i)
time+=getdt(i);
} else {
fl_color(255,0,0);
time=getdt(currentpoint);
fl_color(FL_RED);
time=getdt(lastpoint);
}
char tmpstr[20];
if (time<1000.0)
@@ -165,55 +185,99 @@ void EnvelopeFreeEdit::draw(void)
else
snprintf((char *)&tmpstr,20,"%.2fs",time/1000.0);
fl_draw(tmpstr,ox+lx-20,oy+ly-10,20,10,FL_ALIGN_RIGHT,NULL,0);
if (lastpoint>=0){
snprintf((char *)&tmpstr,20,"%d", Penvval[lastpoint]);
fl_draw(tmpstr,ox+lx-20,oy+ly-23,20,10,FL_ALIGN_RIGHT,NULL,0);
}
}

int EnvelopeFreeEdit::handle(int event)
{
const int x_=Fl::event_x()-x();
const int y_=Fl::event_y()-y();

if (event==FL_PUSH) {
currentpoint=getnearest(x_,y_);
cpx=x_;
cpdt=Penvdt[currentpoint];
lastpoint=currentpoint;
redraw();
if (pair)
pair->redraw();
}

if (event==FL_RELEASE){
currentpoint=-1;
redraw();
if (pair)
pair->redraw();
}

if (event==FL_DRAG && currentpoint>=0){
int ny=limit(127-(int) (y_*127.0/h()), 0, 127);

Penvval[currentpoint]=ny;

const int dx=(int)((x_-cpx)*0.1);
const int newdt=limit(cpdt+dx,0,127);

if(currentpoint!=0)
Penvdt[currentpoint]=newdt;
else
Penvdt[currentpoint]=0;

oscWrite(to_s("Penvval")+to_s(currentpoint), "c", ny);
oscWrite(to_s("Penvdt")+to_s(currentpoint), "c", newdt);
oscWrite("Penvdt","");
oscWrite("Penvval","");
redraw();

if(pair)
pair->redraw();
static Fl_Widget *old_focus;
int key;

switch(event) {
case FL_ENTER:
old_focus=Fl::focus();
Fl::focus(this);
// Otherwise the underlying window seems to regrab focus,
// and I can't see the KEYDOWN action.
return 1;
case FL_LEAVE:
Fl::focus(old_focus);
break;
case FL_KEYDOWN:
case FL_KEYUP:
key = Fl::event_key();
if (key==FL_Control_L || key==FL_Control_R){
ctrldown = (event==FL_KEYDOWN);
redraw();
if (pair!=NULL) pair->redraw();
}
break;
case FL_PUSH:
currentpoint=getnearest(x_,y_);
cpx=x_;
cpdt=Penvdt[currentpoint];
lastpoint=currentpoint;
redraw();
if (pair)
pair->redraw();
return 1;
case FL_RELEASE:
currentpoint=-1;
redraw();
if (pair)
pair->redraw();
return 1;
case FL_MOUSEWHEEL:
if (lastpoint>=0) {
if (!ctrldown) {
int ny = Penvval[lastpoint] - Fl::event_dy();
ny = ny < 0 ? 0 : ny > 127 ? 127 : ny;
Penvval[lastpoint] = ny;
oscWrite(to_s("Penvval")+to_s(lastpoint), "c", ny);
oscWrite("Penvval","");
} else if (lastpoint > 0) {
int newdt = Fl::event_dy() + Penvdt[lastpoint];
newdt = newdt < 0 ? 0 : newdt > 127 ? 127 : newdt;
Penvdt[lastpoint] = newdt;
oscWrite(to_s("Penvdt")+to_s(lastpoint), "c", newdt);
oscWrite("Penvdt","");
}
redraw();
if (pair!=NULL) pair->redraw();
return 1;
}
case FL_DRAG:
if (currentpoint>=0){
int ny=limit(127-(int) (y_*127.0/h()), 0, 127);

Penvval[currentpoint]=ny;

const int dx=(int)((x_-cpx)*0.1);
const int newdt=limit(cpdt+dx,0,127);

if(currentpoint!=0)
Penvdt[currentpoint]=newdt;
else
Penvdt[currentpoint]=0;

oscWrite(to_s("Penvval")+to_s(currentpoint), "c", ny);
oscWrite(to_s("Penvdt")+to_s(currentpoint), "c", newdt);
oscWrite("Penvdt","");
oscWrite("Penvval","");
redraw();

if(pair)
pair->redraw();
return 1;
}
}


return 1;
// Needed to propagate undo/redo keys.
return 0;
}

void EnvelopeFreeEdit::update(void)
@@ -230,6 +294,12 @@ void EnvelopeFreeEdit::rebase(std::string new_base)
osc->renameLink(loc+"Penvdt", new_base+"Penvdt", this);
osc->renameLink(loc+"Penvval", new_base+"Penvval", this);
osc->renameLink(loc+"Penvsustain", new_base+"Penvsustain", this);
for(int i=0; i<MAX_ENVELOPE_POINTS; ++i) {
string dt = string("Penvdt") + to_s(i);
string val = string("Penvval") + to_s(i);
osc->renameLink(loc+dt, new_base+dt, this);
osc->renameLink(loc+val, new_base+val, this);
}
loc = new_base;
update();
}

+ 94
- 106
source/native-plugins/zynaddsubfx/UI/EnvelopeUI.fl View File

@@ -20,6 +20,9 @@ decl {\#include "Fl_Osc_Button.H"} {public local
decl {\#include "Fl_Osc_Counter.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include <stdio.h>} {public local
}

@@ -53,6 +56,21 @@ decl {\#include "common.H"} {public local
decl {\#include "EnvelopeFreeEdit.h"} {public local
}

class PointButton {open : {public Fl_Button, public Fl_Osc_Widget}}
{
Function {PointButton(int x,int y, int w, int h, const char *label=0):Fl_Button(x,y,w,h,label),Fl_Osc_Widget(this)} {open
} {
code {} {}
}
Function {rebase(std::string new_base)} {open
} {
code {loc = new_base;} {}
}
Function {init(std::string path_)} {open
} {
code {ext = path_;} {}
}
}
class EnvelopeUI {open : {public Fl_Osc_Group,PresetsUI_}
} {
Function {EnvelopeUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h,label)} {} {
@@ -79,13 +97,13 @@ delete (freemodeeditwindow);} {}
Fl_Button {} {
label C
callback {presetsui->copy(freemodeeditwindow->loc());}
xywh {465 160 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
code0 {freemodeeditwindow->osc = osc; freemodeeditwindow->base = loc();}
xywh {465 160 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
code0 {freemodeeditwindow->init(osc, loc());}
}
Fl_Button {} {
label P
callback {presetsui->paste(freemodeeditwindow->loc(),this);}
xywh {482 160 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {482 160 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Button addpoint {
label {Add point}
@@ -101,8 +119,8 @@ sustaincounter->update();
//sustaincounter->value(Penvsustain);
//sustaincounter->maximum(Penvpoints-2);}
xywh {115 155 80 20} box THIN_UP_BOX labelsize 11
code0 {(void)o;//if (Pfreemode==0) o->hide();}
class Fl_Osc_Button
code0 {(void)o->init("addPoint");}
class PointButton
}
Fl_Box freeedit {
label Envelope
@@ -121,20 +139,8 @@ sustaincounter->update();
//sustaincounter->value(Penvsustain);
//sustaincounter->maximum(Penvpoints-2);}
xywh {200 155 80 20} box THIN_UP_BOX labelsize 11
code0 {(void)o;//if (Pfreemode==0) o->hide();}
class Fl_Osc_Button
}
Fl_Check_Button freemodebutton {
label FreeMode
callback {
o->oscWrite("Pfreemode", o->value() ? "T" : "F");
reinit(o->value());

freeedit->lastpoint=-1;
freeedit->redraw();}
tooltip {Enable or disable the freemode} xywh {10 155 95 20} labelsize 11
code0{o->init("Pfreemode");}
class Fl_Osc_Check
code0 {(void)o->init("delPoint");}
class PointButton
}
Fl_Check_Button forcedreleasecheck {
label frcR
@@ -170,6 +176,18 @@ envfree->redraw();}
code3 {o->init("Penvsustain");}
class Fl_Osc_Counter
}
Fl_Check_Button freemodehack {
xywh {0 0 0 0} down_box DOWN_BOX
callback{refresh_display();}
code0 {o->init("Pfreemode");o->hide();}
class Fl_Osc_Check
}
Fl_Button {} {
label {Cancel Freemode}
callback {disable_freemode();}
xywh {5 155 105 20} box THIN_UP_BOX labelsize 11 labelcolor 1
class Fl_Osc_Button
}
}
}
Function {make_ADSR_window()} {} {
@@ -185,12 +203,12 @@ envfree->redraw();}
Fl_Button {} {
label C
callback {presetsui->copy(envADSR->loc());}
xywh {150 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {150 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Button {} {
label P
callback {presetsui->paste(envADSR->loc(),this);}
xywh {167 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {167 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Dial e1adt {
label {A.dt}
@@ -234,8 +252,9 @@ envfree->redraw();}
}
Fl_Button {} {
label E
callback {freemodeeditwindow->show();}
callback {open_as_freemode();}
tooltip {Envelope window} xywh {185 5 15 15} labelfont 1 labelsize 10
class Fl_Osc_Button
}
Fl_Check_Button e1linearenvelope {
label L
@@ -259,12 +278,12 @@ envfree->redraw();}
Fl_Button {} {
label C
callback {presetsui->copy(envASR->loc());}
xywh {155 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {155 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Button {} {
label P
callback {presetsui->paste(envASR->loc(),this);}
xywh {172 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {172 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Dial e2aval {
label {A.val}
@@ -309,8 +328,9 @@ envfree->redraw();}
}
Fl_Button {} {
label E
callback {freemodeeditwindow->show();}
callback {open_as_freemode();}
tooltip {Envelope window} xywh {190 5 15 15} labelfont 1 labelsize 10
class Fl_Osc_Button
}
}
}
@@ -327,12 +347,12 @@ envfree->redraw();}
Fl_Button {} {
label C
callback {presetsui->copy(envADSRfilter->loc());}
xywh {220 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {220 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Button {} {
label P
callback {presetsui->paste(envADSRfilter->loc(),this);}
xywh {237 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {237 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Dial e3aval {
label {A.val}
@@ -390,8 +410,9 @@ envfree->redraw();}
}
Fl_Button {} {
label E
callback {freemodeeditwindow->show();}
callback {open_as_freemode();}
xywh {255 5 15 15} labelfont 1 labelsize 10
class Fl_Osc_Button
}
}
}
@@ -410,12 +431,12 @@ envfree->redraw();}
Fl_Button {} {
label C
callback {presetsui->copy(envASRbw->loc());}
xywh {155 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {155 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Button {} {
label P
callback {presetsui->paste(envASRbw->loc(),this);}
xywh {172 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 7
xywh {172 5 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 55
}
Fl_Dial e4aval {
label {A.val}
@@ -460,8 +481,9 @@ envfree->redraw();}
}
Fl_Button {} {
label E
callback {freemodeeditwindow->show();}
callback {open_as_freemode();}
xywh {190 5 15 15} labelfont 1 labelsize 10
class Fl_Osc_Button
}
}
}
@@ -478,8 +500,9 @@ envfree->redraw();}
} {
Fl_Button {} {
label E
callback {freemodeeditwindow->show();}
callback {open_as_freemode();}
xywh {185 5 15 15} labelfont 1 labelsize 10
class Fl_Osc_Button
}
Fl_Box freeeditsmall {
label Envelope
@@ -501,6 +524,18 @@ envfree->redraw();}
}
}
}
Function {open_as_freemode()} {open
} {
code {
if (!freemodehack->value() &&
fl_choice("Convert envelope to free mode data?","No","Yes",NULL)==0)
return;
freemodehack->oscWrite("Pfreemode", "T");
freeedit->update();
freemodeeditwindow->show();
freemodeeditwindow->position(Fl::event_x_root()-20, Fl::event_y_root()+20);
} {}
}
Function {init(int env_type, Fl_Osc_Interface *osc_, std::string base_, std::string ext_)} {open
} {
code {osc = osc_;
@@ -533,113 +568,68 @@ freeeditsmall->setpair(freeedit);
freeedit->setpair(freeeditsmall);


refresh();} {}
refresh_display();} {}
}
Function {rebase(std::string new_base)} {open
} {
code {Fl_Osc_Group::rebase(new_base);
freemodeeditwindow->rebase(new_base+ext);} {}
}
Function {reinit(bool Pfreemode)} {open
Function {disable_freemode()} {open
} {
code {
//if(!Pfreemode){
// int answer=fl_choice("Disable the free mode of the Envelope?","No","Yes",NULL);
// freemodebutton->value(Pfreemode);
// if (answer==0)
// return;
//};
freeedit->update();
code {if (fl_choice("Discard free mode data?","No","Yes",NULL)==0)
return;

hide();
const int winx=freemodeeditwindow->x();
const int winy=freemodeeditwindow->y();
bool reshow = freemodeeditwindow->visible();
int winx = Fl::event_x_root()-10;
int winy = Fl::event_y_root()-155;
winx = winx < 1 ? 1 : winx;
winy = winy < 1 ? 1 : winy;
freemodeeditwindow->hide();

envwindow->hide();
Fl_Group *par=envwindow->parent();
par->hide();

refresh();
freemodehack->oscWrite("Pfreemode", "F");
freeedit->update();
envwindow->show();
par->redraw();

par->show();
show();
freemodeeditwindow->position(winx,winy);
if(reshow)
freemodeeditwindow->show();

if (Pfreemode) {
freemodebutton->value(1);
addpoint->show();
deletepoint->show();
forcedreleasecheck->show();
sustaincounter->show();
envstretchdial->show();
} else{
freemodebutton->value(0);
addpoint->hide();
deletepoint->hide();
forcedreleasecheck->hide();
sustaincounter->hide();
envstretchdial->hide();
};
} {selected
}
freemodeeditwindow->position(winx,winy);} {}
}
Function {refresh()} { open }
{ code {
freemodehack->oscWrite("Pfreemode");
} {}
}
Function {refresh()} {open
Function {refresh_display()} {open
} {
code {

sustaincounter->value(Penvsustain);
sustaincounter->maximum(Penvpoints-2);

envstretchdial->value(Penvstretch);

linearenvelopecheck->value(Plinearenvelope);

//Conditionally display widgets
if(freemodebutton->value()) {
freemodebutton->value(1);
addpoint->show();
deletepoint->show();
forcedreleasecheck->show();
sustaincounter->show();
envstretchdial->show();
} else {
freemodebutton->value(0);
addpoint->hide();
deletepoint->hide();
forcedreleasecheck->hide();
sustaincounter->hide();
envstretchdial->hide();
}

if(freemodebutton->value() || Envmode>2)
linearenvelopecheck->hide();
else
linearenvelopecheck->show();
linearenvelopecheck->value(Plinearenvelope);
linearenvelopecheck->show();

forcedreleasecheck->value(Pforcedrelease);

if (freemodebutton->value()==0){
addpoint->hide();
deletepoint->hide();
} else {
addpoint->show();
deletepoint->show();
}

envADSR->hide();
envASR->hide();
envADSRfilter->hide();
envASRbw->hide();
envfree->hide();

if (freemodebutton->value()==0){
if (freemodehack->value()) {
envwindow=envfree;
freeedit->update();
} else {
freemodeeditwindow->hide();
switch(Envmode){
case 1:
case 2:
@@ -656,10 +646,8 @@ if (freemodebutton->value()==0){
break;
default:
break;
};
}else{
envwindow=envfree;
};
}
}

assert(envwindow);
envwindow->resize(this->x(),this->y(),this->w(),this->h());


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

@@ -26,6 +26,9 @@ decl {\#include "Fl_Osc_Output.H"} {public local
decl {\#include "Fl_Osc_Slider.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include <cmath>} {private local
}



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

@@ -39,6 +39,7 @@ void Fl_Osc_DialF::init(const char *path)
ext = path;
loc = pane->base;
oscRegister(path);
integer_step = false;
};

Fl_Osc_DialF::~Fl_Osc_DialF(void)


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

@@ -1,4 +1,5 @@
#include "Fl_Osc_ListView.H"
#include "Fl_Osc_Pane.H"
#include <cstdio>
#include <rtosc/rtosc.h>

@@ -21,7 +22,7 @@ void Fl_Osc_ListView::init(const char *path_)
path = path_;
data = new Osc_SimpleListModel(osc);
data->callback = [this](Osc_SimpleListModel::list_t l){this->doUpdate(l);};
data->update(loc+path_);
data->doUpdate(loc+path_);
}

void Fl_Osc_ListView::doUpdate(Osc_SimpleListModel::list_t l)
@@ -33,7 +34,7 @@ void Fl_Osc_ListView::doUpdate(Osc_SimpleListModel::list_t l)
}
void Fl_Osc_ListView::update(void)
{
data->update(loc+path);
data->doUpdate(loc+path);
}

void Fl_Osc_ListView::insert(std::string s, int offset)


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

@@ -1,3 +1,4 @@
#include <stdlib.h>
#include "Fl_Osc_Numeric_Input.H"

Fl_Osc_Numeric_Input::Fl_Osc_Numeric_Input(int X, int Y, int W, int H, const char *label)


+ 5
- 0
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Pane.H View File

@@ -3,6 +3,7 @@
#include <FL/Fl_Group.H>
#include <FL/Fl_Double_Window.H>
#include <string>
#include "Osc_DataModel.h"

class Fl_Osc_Pane
{
@@ -16,8 +17,12 @@ class Fl_Osc_Pane

class Fl_Osc_Window:public Fl_Double_Window, public Fl_Osc_Pane
{
Osc_DataModel *title_ext;
std::string title_orig;
std::string title_new;
public:
Fl_Osc_Window(int w, int h, const char *L=0);
~Fl_Osc_Window(void);

void init(Fl_Osc_Interface *osc_, std::string loc_);
virtual std::string loc(void) const;


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

@@ -9,15 +9,42 @@ Fl_Osc_Pane::Fl_Osc_Pane(void)


Fl_Osc_Window::Fl_Osc_Window(int w, int h, const char *L)
:Fl_Double_Window(w,h,L)
:Fl_Double_Window(w,h,L), title_ext(NULL)
{}
void Fl_Osc_Window::init(Fl_Osc_Interface *osc_, std::string loc_)
{
title_ext = new Osc_DataModel(osc_);
title_ext->doUpdate("/ui/title");
title_ext->callback = [this](string next) {
//printf("old: %s\n", title_orig.c_str());
const char *orig = title_orig.c_str();
// 12345678901
const char *sub = strstr(orig, "zynaddsubfx");
if(!sub)
sub = strstr(orig, "ZynAddSubFX");
title_new = "";
while(*orig) {
if(orig == sub) {
title_new += next;
orig += 11;
} else
title_new += *orig++;
}
//title_new = title_orig + next;
this->label(title_new.c_str());
};
title_orig = label();

osc = osc_;
base = loc_;
}

Fl_Osc_Window::~Fl_Osc_Window(void)
{
delete title_ext;
}

std::string Fl_Osc_Window::loc(void) const
{
return base;


+ 3
- 2
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Slider.H View File

@@ -5,7 +5,6 @@

class Fl_Osc_Slider:public Fl_Slider, public Fl_Osc_Widget
{

public:
Fl_Osc_Slider(int X, int Y, int W, int H, const char *label = NULL);
// string name,
@@ -22,10 +21,12 @@ class Fl_Osc_Slider:public Fl_Slider, public Fl_Osc_Widget
void callback(Fl_Callback *cb, void *p = NULL);
//MIDI Learn
int handle(int);
int handle(int ev, int X, int Y, int W, int H);
int handle(int ev);

void cb(void);
static void _cb(Fl_Widget *w, void *);
float reset_value;
private:
char osc_type;
std::pair<Fl_Callback*, void*> cb_data;


+ 68
- 3
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Slider.cpp View File

@@ -7,6 +7,7 @@
#include <cmath>
#include <cassert>
#include <sstream>
#include "../Misc/Util.h"

static double min__(double a, double b)
{
@@ -14,7 +15,8 @@ static double min__(double a, double b)
}

Fl_Osc_Slider::Fl_Osc_Slider(int X, int Y, int W, int H, const char *label)
:Fl_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), cb_data(NULL, NULL)
:Fl_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), reset_value(0),
cb_data(NULL, NULL)
{
//bounds(0.0f,1.0f);
Fl_Slider::callback(Fl_Osc_Slider::_cb);
@@ -72,7 +74,7 @@ void Fl_Osc_Slider::callback(Fl_Callback *cb, void *p)
cb_data.second = p;
}

int Fl_Osc_Slider::handle(int ev)
int Fl_Osc_Slider::handle(int ev, int X, int Y, int W, int H)
{
bool middle_mouse = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift());
bool ctl_click = (ev == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl());
@@ -85,7 +87,70 @@ int Fl_Osc_Slider::handle(int ev)
osc->write("/unlearn", "s", (loc+ext).c_str());
return 1;
}
return Fl_Slider::handle(ev);

int handled, rounded;
bool reset_requested = false;
switch (ev) {
case FL_MOUSEWHEEL:
if (this == Fl::belowmouse() && Fl::e_dy != 0) {
int step = 1, divisor = 16;
switch (Fl::event_state() & ( FL_CTRL | FL_SHIFT)) {
case FL_SHIFT:
step = 8;
case FL_SHIFT | FL_CTRL:
break;
case FL_CTRL:
divisor = 128;
default:
step = (fabs(maximum() - minimum()) + 1) / divisor;
if (step < 1)
step = 1;
}
int dy = minimum() <= maximum() ? Fl::e_dy : -Fl::e_dy;
handle_drag(clamp(value() + step * dy));
}
return 1;
case FL_RELEASE:
rounded = value() + 0.5;
value(clamp((double)rounded));
if (Fl::event_clicks() == 1) {
Fl::event_clicks(0);
reset_requested = true;
}
}
if (!Fl::event_shift()) {
handled = Fl_Slider::handle(ev, X, Y, W, H);
if (reset_requested) {
value(reset_value);
value_damage();
if (this->when() != 0)
do_callback();
}
return handled;
}

// Slow down the drag.
// Handy if the slider has a large delta bigger than a mouse quantum.
// Somewhat tricky to use with OSC feedback.
// To change direction of movement, one must reclick the handle.
int old_value = value();
handled = Fl_Slider::handle(ev, X, Y, W, H);
int delta = value() - old_value;
if (ev == FL_DRAG && (delta < -1 || delta > 1)) {
value(clamp((old_value + (delta > 0 ? 1 : -1))));
value_damage();
do_callback();
}
return handled;
}

int Fl_Osc_Slider::handle(int ev) {
return handle(ev,
x()+Fl::box_dx(box()),
y()+Fl::box_dy(box()),
w()-Fl::box_dw(box()),
h()-Fl::box_dh(box()));
}

void Fl_Osc_Slider::update(void)


+ 21
- 0
source/native-plugins/zynaddsubfx/UI/Fl_Osc_TSlider.H View File

@@ -0,0 +1,21 @@
#ifndef FL_OSC_TSLIDER_H
#define FL_OSC_TSLIDER_H
#include "Fl_Osc_Slider.H"
#include "TipWin.h"


class Fl_Osc_TSlider:public Fl_Osc_Slider
{
public:
Fl_Osc_TSlider(int x, int y, int w, int h, const char *label = 0);
~Fl_Osc_TSlider();
int handle(int event);
void set_transform(float scale = 1.0, float offset = 0.0);
float transform(float x);
void setRounding(unsigned int digits = 0);
private:
class TipWin * tipwin;
float value_offset;
float value_scale;
};
#endif

+ 65
- 0
source/native-plugins/zynaddsubfx/UI/Fl_Osc_TSlider.cpp View File

@@ -0,0 +1,65 @@
#include <cmath>
#include "Fl_Osc_TSlider.H"
//Copyright (c) 2015 Christopher Oliver
//License: GNU GPL version 2 or later


Fl_Osc_TSlider::Fl_Osc_TSlider(int x, int y, int w, int h, const char *label)
:Fl_Osc_Slider(x, y, w, h, label), value_offset(0.0), value_scale(1.0)
{
Fl_Group *save = Fl_Group::current();
tipwin = new TipWin();
tipwin->hide();
Fl_Group::current(save);
tipwin->setRounding();
}

Fl_Osc_TSlider::~Fl_Osc_TSlider()
{
if (tipwin)
delete tipwin;
}

void Fl_Osc_TSlider::setRounding(unsigned int digits)
{
tipwin->setRounding(digits);
}


int Fl_Osc_TSlider::handle(int event)
{
int super = 1;

super = Fl_Osc_Slider::handle(event);

switch(event) {
case FL_PUSH:
case FL_MOUSEWHEEL:
if (!Fl::event_inside(x(),y(),w(),h()))
return(1);
tipwin->position(Fl::event_x_root()-Fl::event_x()+x(),
Fl::event_y_root()-Fl::event_y()+h()+y()+5);
case FL_DRAG:
tipwin->showValue(transform(value()));
break;
case FL_RELEASE:
case FL_HIDE:
case FL_LEAVE:
if (tipwin)
tipwin->hide();
return 1;
}
return super;
}

void Fl_Osc_TSlider::set_transform(float scale, float offset)
{
value_offset = offset;
value_scale = scale;
}

float Fl_Osc_TSlider::transform(float x)
{
return value_scale * x + value_offset;
}

+ 16
- 10
source/native-plugins/zynaddsubfx/UI/Fl_Osc_VSlider.H View File

@@ -1,29 +1,35 @@
#pragma once
#include <FL/Fl_Value_Slider.H>
#include "Fl_Osc_Widget.H"
#include "Fl_Osc_Slider.H"
#include <string>

class Fl_Osc_VSlider:public Fl_Value_Slider, public Fl_Osc_Widget
class Fl_Osc_VSlider:public Fl_Osc_Slider
{

public:
Fl_Osc_VSlider(int X, int Y, int W, int H, const char *label = NULL);

virtual ~Fl_Osc_VSlider(void);
void OSC_value(char);
void OSC_value(int);
void OSC_value(float);
void init(std::string, char type = 'i');
Fl_Font textfont_;
Fl_Fontsize textsize_;
Fl_Color textcolor_;

void init(std::string, char type = 'i');
//Refetch parameter information
void update(void);
void callback(Fl_Callback *cb, void *p = NULL);
//MIDI Learn
int handle(int);

void cb(void);
static void _cb(Fl_Widget *w, void *);
// Value Slider add-ins.
Fl_Font textfont() const {return textfont_;}
void textfont(Fl_Font s) {textfont_ = s;}
Fl_Fontsize textsize() const {return textsize_;}
void textsize(Fl_Fontsize s) {textsize_ = s;}
Fl_Color textcolor() const {return textcolor_;}
void textcolor(Fl_Color s) {textcolor_ = s;}

protected:
void draw(void);
private:
char osc_type;
std::pair<Fl_Callback*, void*> cb_data;


+ 40
- 61
source/native-plugins/zynaddsubfx/UI/Fl_Osc_VSlider.cpp View File

@@ -1,4 +1,5 @@
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include "Fl_Osc_VSlider.H"
#include "Fl_Osc_Interface.h"
#include "Fl_Osc_Pane.H"
@@ -9,82 +10,60 @@
#include <sstream>

Fl_Osc_VSlider::Fl_Osc_VSlider(int X, int Y, int W, int H, const char *label)
:Fl_Value_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), cb_data(NULL, NULL)
:Fl_Osc_Slider(X,Y,W,H,label), cb_data(NULL, NULL)
{
//bounds(0.0f,1.0f);
Fl_Slider::callback(Fl_Osc_VSlider::_cb);
}

void Fl_Osc_VSlider::init(std::string path_, char type_)
{
osc_type = type_;
ext = path_;
oscRegister(ext.c_str());
Fl_Slider::callback(Fl_Osc_Slider::_cb);
textfont_ = FL_HELVETICA;
textsize_ = 10;
textcolor_ = FL_FOREGROUND_COLOR;
}

Fl_Osc_VSlider::~Fl_Osc_VSlider(void)
{}

void Fl_Osc_VSlider::OSC_value(char v)
{
Fl_Slider::value(v+minimum()+fmodf(value(), 1.0f));
}
void Fl_Osc_VSlider::OSC_value(int v)
{
Fl_Slider::value(v+minimum()+fmodf(value(), 1.0f));
}

void Fl_Osc_VSlider::OSC_value(float v)
void Fl_Osc_VSlider::init(std::string path_, char type_)
{
Fl_Slider::value(v+minimum());
Fl_Osc_Slider::init(path_, type_);
}

void Fl_Osc_VSlider::cb(void)
{
const float val = Fl_Slider::value();
if(osc_type == 'f')
oscWrite(ext, "f", val-minimum());
else if(osc_type == 'i')
oscWrite(ext, "i", (int)(val-minimum()));
else {
fprintf(stderr, "invalid `c' from vslider %s%s, using `i'\n", loc.c_str(), ext.c_str());
oscWrite(ext, "i", (int)(val-minimum()));
void Fl_Osc_VSlider::draw() {
int sxx = x(), syy = y(), sww = w(), shh = h();
int bxx = x(), byy = y(), bww = w(), bhh = h();
if (horizontal()) {
bww = 35; sxx += 35; sww -= 35;
} else {
syy += 25; bhh = 25; shh -= 25;
}
//OSC_value(val);
if(cb_data.first)
cb_data.first(this, cb_data.second);
}

void Fl_Osc_VSlider::callback(Fl_Callback *cb, void *p)
{
cb_data.first = cb;
cb_data.second = p;
if (damage()&FL_DAMAGE_ALL) draw_box(box(),sxx,syy,sww,shh,color());
Fl_Osc_Slider::draw(sxx+Fl::box_dx(box()),
syy+Fl::box_dy(box()),
sww-Fl::box_dw(box()),
shh-Fl::box_dh(box()));
draw_box(box(),bxx,byy,bww,bhh,color());
char buf[128];
format(buf);
fl_font(textfont(), textsize());
fl_color(active_r() ? textcolor() : fl_inactive(textcolor()));
fl_draw(buf, bxx, byy, bww, bhh, FL_ALIGN_CLIP);
}

int Fl_Osc_VSlider::handle(int ev)
{
bool middle_mouse = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift());
bool ctl_click = (ev == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl());
bool shift_middle = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && Fl::event_shift());
if(middle_mouse || ctl_click) {
printf("Trying to learn...\n");
osc->write("/learn", "s", (loc+ext).c_str());
return 1;
} else if(shift_middle) {
osc->write("/unlearn", "s", (loc+ext).c_str());
return 1;
if (ev == FL_PUSH && Fl::visible_focus()) {
Fl::focus(this);
redraw();
}
int sxx = x(), syy = y(), sww = w(), shh = h();
if (horizontal()) {
sxx += 35; sww -= 35;
} else {
syy += 25; shh -= 25;
}
return Fl_Value_Slider::handle(ev);
}

void Fl_Osc_VSlider::update(void)
{
oscWrite(ext, "");
}

void Fl_Osc_VSlider::_cb(Fl_Widget *w, void *)
{
static_cast<Fl_Osc_VSlider*>(w)->cb();
return Fl_Osc_Slider::handle(ev,
sxx+Fl::box_dx(box()),
syy+Fl::box_dy(box()),
sww-Fl::box_dw(box()),
shh-Fl::box_dh(box()));
}

+ 1
- 2
source/native-plugins/zynaddsubfx/UI/Fl_Osc_Widget.H View File

@@ -4,7 +4,6 @@
#include <cassert>
#include <cmath>
#include "Fl_Osc_Interface.h"
#include "Fl_Osc_Pane.H"
#include <FL/Fl_Group.H>

class Fl_Osc_Widget
@@ -54,5 +53,5 @@ class Fl_Osc_Widget
std::string ext;
Fl_Osc_Interface *osc;
protected:
Fl_Osc_Pane *fetch_osc_pane(Fl_Widget *w);
class Fl_Osc_Pane *fetch_osc_pane(Fl_Widget *w);
};

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

@@ -1,4 +1,5 @@
#include "Fl_Osc_Widget.H"
#include "Fl_Osc_Pane.H"
#include <rtosc/rtosc.h>

Fl_Osc_Widget::Fl_Osc_Widget(void) //Deprecated


+ 3
- 0
source/native-plugins/zynaddsubfx/UI/LFOUI.fl View File

@@ -20,6 +20,9 @@ decl {\#include "Fl_Osc_Choice.H"} {public local
decl {\#include "Fl_Osc_Check.H"} {public local
}

decl {\#include "Fl_Osc_Pane.H"} {public local
}

decl {\#include "../globals.h"} {private global
}



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

@@ -61,6 +61,9 @@ decl {\#include "VuPartMeter.h"} {public local
decl {\#include "Fl_Osc_Dial.H"} {private local
}

decl {\#include "Osc_DataModel.h"} {private local
}

decl {\#include "VuMasterMeter.h"} {public local
}

@@ -241,7 +244,13 @@ class MasterUI {open
close();
};} open
xywh {330 365 390 525} type Double xclass zynaddsubfx visible
class Fl_Osc_Window
} {
Fl_Box dummy_again {
xywh {25 25 25 25}
code0 {masterwindow->init(osc, "");}
}

Fl_Group win_root {open
xywh {0 0 390 525}
class Fl_Osc_Group
@@ -258,6 +267,11 @@ class MasterUI {open
callback {do_new_master();}
xywh {25 25 100 20}
}
MenuItem {} {
label {&Revert changes...}
callback {do_revert_changes();}
xywh {25 25 100 20}
}
MenuItem {} {
label {&Open Parameters...}
callback {\#if USE_NSM
@@ -568,7 +582,7 @@ syseffectui->refresh();}
Fl_Button {} {
label C
callback {presetsui->copy("/sysefx"+to_s(nsyseff)+"/");}
xywh {180 187 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7
xywh {180 187 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 55
}
Fl_Button {} {
label P
@@ -855,8 +869,7 @@ GNU General Public License for details.}
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {syseffsendwindow->osc = osc; assert(osc);}
code1 {syseffsendwindow->base = "";}
code0 {syseffsendwindow->init(osc,"");}
}
Fl_Scroll syseffscroll {open
xywh {0 45 120 170} box FLAT_BOX resizable
@@ -880,8 +893,7 @@ GNU General Public License for details.}
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {panelwindow->osc = osc;}
code1 {panelwindow->base = "/";}
code0 {panelwindow->init(osc,"/");}
}
Fl_Scroll {} {open
xywh {0 5 570 310} type HORIZONTAL box THIN_UP_BOX
@@ -924,8 +936,7 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL))
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {simplemasterwindow->osc = osc;}
code1 {simplemasterwindow->base = "/";}
code0 {simplemasterwindow->init(osc, "/");}
}
Fl_Menu_Bar simplemastermenu {
xywh {0 0 600 25}
@@ -939,6 +950,11 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL))
callback {do_new_master();}
xywh {30 30 100 20}
}
MenuItem {} {
label {&Revert changes...}
callback {do_revert_changes();}
xywh {30 30 100 20}
}
MenuItem {} {
label {&Open Parameters...}
callback {do_load_master();}
@@ -1427,6 +1443,7 @@ virkeys->take_focus();}
label {User Interface mode}
callback {*exitprogram=1;}
xywh {342 246 430 250} type Double hide non_modal
class Fl_Osc_Window
} {
Fl_Box {} {
label {Welcome to ZynAddSubFX}
@@ -1489,6 +1506,25 @@ osc=osc_;
ninseff=0;
nsyseff=0;
npart=0;
last_loaded[0]=0;
loading_next[0]=0;
last_xmz = new Osc_DataModel(osc);
last_xmz->callback = [this](std::string filestr) {
const char *filename = filestr.c_str();
if (filename[0] != 0)
strncpy(last_loaded, filename, XMZ_PATH_MAX);
else if (loading_next[0] != 0) {
strncpy(last_loaded, loading_next, XMZ_PATH_MAX);
loading_next[0] = 0;
} else
last_loaded[0] = 0;
last_loaded[XMZ_PATH_MAX - 1] = 0;
char *label = last_loaded[0] == 0 ? NULL
: ((label = strrchr(last_loaded, '/'))) ? label+1
: last_loaded;
setfilelabel(label);
};
last_xmz->doUpdate("/last_xmz");

for (int i=0;i<NUM_SYS_EFX;i++)
for (int j=0;j<NUM_SYS_EFX;j++)
@@ -1556,6 +1592,7 @@ simplelistitemgroup->redraw();} {}
microtonalui=new MicrotonalUI(osc, "/microtonal/");

osc->write("/reset_master");
osc->write("/last_xmz");
npartcounter->value(1);
refresh_master_ui();
updatepanel();} {}
@@ -1565,9 +1602,29 @@ microtonalui=new MicrotonalUI(osc, "/microtonal/");
do_new_master_unconditional();
}} {}
}
Function {do_revert_changes_unconditional()} {return_type int
} {
code {strncpy(loading_next, last_loaded, XMZ_PATH_MAX);
osc->write("/load_xmz", "s", last_loaded);
osc->write("/last_xmz");
refresh_master_ui();
updatepanel();

return 1;} {}
}
Function {do_revert_changes()} {} {
code {if (last_loaded[0] == 0)
do_new_master();
else
if (fl_choice("Revert *ALL* the parameters ?","No","Yes",NULL)){
do_revert_changes_unconditional();
}} {}
}
Function {do_load_master_unconditional(const char *filename, const char *display_name)} {return_type int
} {
code {osc->write("/load_xmz", "s", filename);
code {strncpy(loading_next, filename, XMZ_PATH_MAX);
osc->write("/load_xmz", "s", filename);
osc->write("/last_xmz");
refresh_master_ui();
updatepanel();

@@ -1648,6 +1705,8 @@ simpleinseffnocounter->do_callback();

simplerefresh();
bankui->hide();} {}
}
decl {class Osc_DataModel *last_xmz;} {public local
}
decl {MicrotonalUI *microtonalui;} {private local
}
@@ -1675,6 +1734,10 @@ bankui->hide();} {}
}
decl {class Fl_Osc_Interface *osc;} {public local
}
decl {char last_loaded[XMZ_PATH_MAX];} {public local
}
decl {char loading_next[XMZ_PATH_MAX];} {public local
}
Function {close()} {open return_type void
} {
code {*exitprogram=1;} {}


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

@@ -51,8 +51,7 @@ class MicrotonalUI {} {
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {microtonaluiwindow->osc = osc;}
code1 {microtonaluiwindow->base = base;}
code0 {microtonaluiwindow->init(osc, base);}
}
Fl_Group {} {
tooltip {Center where the note's freqs. are turned upside-down} xywh {249 2 155 45} box ENGRAVED_FRAME


+ 9
- 9
source/native-plugins/zynaddsubfx/UI/NioUI.cpp View File

@@ -11,6 +11,7 @@
#include <FL/Fl_Group.H>
#include <FL/Fl_Text_Display.H>
#include "Osc_SimpleListModel.h"
#include "Fl_Osc_Pane.H"

using namespace std;

@@ -56,7 +57,7 @@ class Fl_Osc_StrChoice:public Fl_Choice, public Fl_Osc_Widget
cb_data.first = cb;
cb_data.second = p;
}
void cb(void)
{
assert(osc);
@@ -66,7 +67,6 @@ class Fl_Osc_StrChoice:public Fl_Choice, public Fl_Osc_Widget
cb_data.first(this, cb_data.second);
}
private:
int min;
std::pair<Fl_Callback*, void*> cb_data;
};
static void callback_fn_choice_nio(Fl_Widget *w, void *)
@@ -110,9 +110,9 @@ NioUI::NioUI(Fl_Osc_Interface *osc)
for(auto io:list)
audio->add(io.c_str());
};
midi_opt->update("/io/source-list");
audio_opt->update("/io/sink-list");
midi_opt->doUpdate("/io/source-list");
audio_opt->doUpdate("/io/sink-list");

resizable(this);
size_range(400, 300);
@@ -123,19 +123,19 @@ NioUI::~NioUI()

void NioUI::refresh()
{
midi_opt->update("/io/source-list");
audio_opt->update("/io/sink-list");
midi_opt->doUpdate("/io/source-list");
audio_opt->doUpdate("/io/sink-list");
midi->update();
audio->update();
}

void NioUI::midiCallback(Fl_Widget *c)
void NioUI::midiCallback(Fl_Widget *)
{
//bool good = Nio::setSource(static_cast<Fl_Choice *>(c)->text());
//static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));
}

void NioUI::audioCallback(Fl_Widget *c)
void NioUI::audioCallback(Fl_Widget *)
{
//bool good = Nio::setSink(static_cast<Fl_Choice *>(c)->text());
//static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));


+ 2
- 2
source/native-plugins/zynaddsubfx/UI/Osc_DataModel.h View File

@@ -17,7 +17,7 @@ class Osc_DataModel:public Fl_Osc_Widget
value_t value;
std::function<void(value_t)> callback;

void update(std::string url)
void doUpdate(std::string url)
{
if(!ext.empty())
osc->removeLink(this);
@@ -26,7 +26,7 @@ class Osc_DataModel:public Fl_Osc_Widget

oscRegister(ext.c_str());
}
//Raw messages
virtual void OSC_raw(const char *msg)
{


+ 2
- 2
source/native-plugins/zynaddsubfx/UI/Osc_IntModel.h View File

@@ -23,7 +23,7 @@ class Osc_IntModel:public Fl_Osc_Widget
oscWrite(ext, "i", v);
}

void update(std::string url)
void doUpdate(std::string url)
{
if(!ext.empty())
osc->removeLink(this);
@@ -31,7 +31,7 @@ class Osc_IntModel:public Fl_Osc_Widget

oscRegister(ext.c_str());
}
//Raw messages
virtual void OSC_raw(const char *msg)
{


+ 2
- 2
source/native-plugins/zynaddsubfx/UI/Osc_ListModel.h View File

@@ -18,7 +18,7 @@ class Osc_ListModel:public Fl_Osc_Widget
std::function<void(list_t)> callback;
unsigned list_size;

void update(std::string url)
void doUpdate(std::string url)
{
if(!ext.empty())
osc->removeLink(this);
@@ -26,7 +26,7 @@ class Osc_ListModel:public Fl_Osc_Widget

oscRegister(ext.c_str());
}
//Raw messages
virtual void OSC_raw(const char *msg)
{


+ 2
- 2
source/native-plugins/zynaddsubfx/UI/Osc_SimpleListModel.h View File

@@ -18,7 +18,7 @@ class Osc_SimpleListModel:public Fl_Osc_Widget
std::function<void(list_t)> callback;
unsigned list_size;

void update(std::string url)
void doUpdate(std::string url)
{
if(!ext.empty())
osc->removeLink(this);
@@ -47,7 +47,7 @@ class Osc_SimpleListModel:public Fl_Osc_Widget
rtosc_amessage(buffer, sizeof(buffer), ext.c_str(), types, args);
osc->writeRaw(buffer);
}
//Raw messages
virtual void OSC_raw(const char *msg)
{


+ 10
- 10
source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl View File

@@ -346,7 +346,7 @@ oscildisplaygroup->redraw();}
code1 {oscilo_base->parent(o);oscilo_base->init(true);}
} {}
Fl_Dial bfslider {
callback {redrawoscil();}
callback {redrawoscil(); bfparval->value(o->value());}
tooltip {Base Function Parameter} xywh {525 285 20 20} minimum -64 maximum 63 step 1
code0 {o->init("Pbasefuncpar");}
class Fl_Osc_Dial
@@ -492,9 +492,9 @@ redrawoscil();}
}
Fl_Button {} {
label {Use as base}
callback {//oscil->useasbase();
callback {osc->requestValue(loc+"use-as-base");
if (autoclearbutton->value()){
for (int i=0;i<MAX_AD_HARMONICS;i++){
for (int i=0;i<(MAX_AD_HARMONICS - 1);i++){
h[i]->mag->value(64);
h[i]->mag->do_callback();
h[i]->phase->value(64);
@@ -528,7 +528,7 @@ redrawoscil();}
label Clear
callback {if (!fl_choice("Clear the harmonics settings?","No","Yes",NULL)) return;

for (int i=0;i<MAX_AD_HARMONICS;i++){
for (int i=0;i<(MAX_AD_HARMONICS - 1);i++){
h[i]->mag->value(64);
h[i]->mag->do_callback();
h[i]->phase->value(64);
@@ -537,7 +537,7 @@ for (int i=0;i<MAX_AD_HARMONICS;i++){
h[0]->mag->value(0);
h[0]->mag->do_callback();

//for (int i=0;i<MAX_AD_HARMONICS;i++){
//for (int i=0;i<(MAX_AD_HARMONICS - 1);i++){
// if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0);
// else h[i]->mag->selection_color(222);
//};
@@ -620,7 +620,7 @@ redrawoscil();}
}
}
Fl_Dial wshpar {
callback {redrawoscil();}
callback {redrawoscil(); wsparval->value(o->value());}
tooltip {Waveshaping Parameter} xywh {265 318 20 20} minimum -64 maximum 63 step 1
code0 {o->init("Pwaveshaping");}
class Fl_Osc_Dial
@@ -916,7 +916,7 @@ refresh();}
} {
Fl_Pack harmonics {open
xywh {15 350 650 225} type HORIZONTAL
code0 {for (int i=0;i<MAX_AD_HARMONICS;i++){h[i]=new Oscilharmonic(0,0,20,o->h(),"");h[i]->init(i,oscildisplaygroup,loc,osc);}}
code0 {for (int i=0;i<(MAX_AD_HARMONICS - 1);i++){h[i]=new Oscilharmonic(0,0,20,o->h(),"");h[i]->init(i,oscildisplaygroup,loc,osc);}}
} {}
}
}
@@ -958,7 +958,7 @@ osceditUI->show();} {}
Function {~OscilEditor()} {open
} {
code {osceditUI->hide();
for (int i=0; i<MAX_AD_HARMONICS; ++i)
for (int i=0; i<(MAX_AD_HARMONICS - 1); ++i)
delete h[i];

delete oscilo;
@@ -970,7 +970,7 @@ delete osceditUI;} {}
Function {refresh()} {} {
code {magtype->update();

for (int i=0;i<MAX_AD_HARMONICS;i++) h[i]->refresh();
for (int i=0;i<(MAX_AD_HARMONICS - 1);i++) h[i]->refresh();

osc->requestValue(loc+"prepare");

@@ -989,7 +989,7 @@ oscils->update();
oscilo_base->update();
oscils_base->update();} {}
}
decl {Oscilharmonic *h[MAX_AD_HARMONICS];} {private local
decl {Oscilharmonic *h[(MAX_AD_HARMONICS - 1)];} {private local
}
decl {std::string loc;} {private local
}


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

@@ -84,8 +84,7 @@ initialized = true;} {selected
} {

Fl_Box dummy {
code0 {padnotewindow->osc = osc_i; padnotewindow->base = location;}
code1 {puts("dummy setup done...");}
code0 {padnotewindow->init(osc_i, location);}
}
Fl_Tabs {} {
callback {if (o->value()!=harmonicstructuregroup) applybutton->hide();


+ 7
- 11
source/native-plugins/zynaddsubfx/UI/PartUI.fl View File

@@ -418,8 +418,7 @@ if (event==FL_RIGHT_MOUSE){
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {ctlwindow->osc = osc;}
code1 {ctlwindow->base = "/part"+to_s(npart)+"/ctl/";}
code0 {ctlwindow->init(osc,"/part"+to_s(npart)+"/ctl/");}
}
Fl_Check_Button {} {
label Expr
@@ -610,8 +609,7 @@ else {propta->deactivate();proptb->deactivate();}}
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {partfx->osc = osc;}
code1 {partfx->base = part_path;}
code0 {partfx->init(osc, part_path);}
}
Fl_Counter inseffnocounter {
label {FX No.}
@@ -726,12 +724,12 @@ if (x==2) part->partefx[ninseff]->setdryonly(true);
}
Fl_Button {} {
label C
callback {presetsui->copy(partfx->loc());}
callback {presetsui->copy(partfx->loc()+"partefx"+to_s(ninseff)+"/");}
xywh {90 127 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 55
}
Fl_Button {} {
label P
callback {presetsui->paste(partfx->loc(),inseffectui);}
callback {presetsui->paste(partfx->loc()+"partefx"+to_s(ninseff)+"/",inseffectui);}
xywh {120 127 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 55
}
}
@@ -742,8 +740,7 @@ if (x==2) part->partefx[ninseff]->setdryonly(true);
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {instrumentkitlist->osc = osc;}
code1 {instrumentkitlist->base = "/part"+to_s(npart)+"/";}
code0 {instrumentkitlist->init(osc, "/part"+to_s(npart)+"/");}
}
Fl_Button {} {
label {Close Window}
@@ -824,8 +821,7 @@ if (x==2) part->partefx[ninseff]->setdryonly(true);
} {
Fl_Box {} {
xywh {0 0 0 0}
code0 {instrumenteditwindow->osc = osc;}
code1 {instrumenteditwindow->base = "/part"+to_s(npart)+"/";}
code0 {instrumenteditwindow->init(osc, "/part"+to_s(npart)+"/");}
}
Fl_Group editgroup {
xywh {0 220 395 110} box UP_FRAME
@@ -1093,7 +1089,7 @@ delete(instrumenteditwindow);} {}
}
decl {BankUI *bankui;} {private local
}
decl {ADnoteUI *adnoteui;} {private local
decl {ADnoteUI *adnoteui;} {selected public local
}
decl {SUBnoteUI *subnoteui;} {private local
}


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

@@ -60,7 +60,7 @@ class PresetsUI {} {
printf("Value = %s\\n", val.c_str());
copytypetext->label(val.c_str());
pastetypetext->label(val.c_str());
listmodel.update("/presets/scan-for-presets");
listmodel.doUpdate("/presets/scan-for-presets");
};
} {}
@@ -268,7 +268,7 @@ class PresetsUI {} {
pastebrowse->clear();

printf("Datamodel Update...");
datamodel.update(url+"preset-type");
datamodel.doUpdate(url+"preset-type");
} {}
}
decl {std::string url;} {public local


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

@@ -184,7 +184,7 @@ class SUBnoteUI {open : {public PresetsUI_}
} {
Fl_Box {} {
xywh {0 0 0 0} box FLAT_BOX color 45
code0 {SUBparameters->osc = osc; SUBparameters->base = loc;}
code0 {SUBparameters->init(osc, loc);}
}
Fl_Scroll {} {
label scroll open


+ 75
- 0
source/native-plugins/zynaddsubfx/UI/TipWin.cpp View File

@@ -0,0 +1,75 @@
#include <cstdio>
#include <cmath>
#include <FL/Fl_Tooltip.H>
#include <FL/fl_draw.H>
#include "TipWin.h"

TipWin::TipWin(void):Fl_Menu_Window(1, 1)
{
strcpy(format, "%0.2f");
set_override();
end();
}

void TipWin::setRounding(unsigned int digits)
{
format[3] = "0123456789"[digits < 9 ? digits : 9];
}

void TipWin::draw()
{
//setup window
draw_box(FL_BORDER_BOX, 0, 0, w(), h(), Fl_Color(175));
fl_color(Fl_Tooltip::textcolor());
fl_font(labelfont(), labelsize());

//Draw the current string
fl_draw(getStr(), 3, 3, w() - 6, h() - 6,
Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_WRAP));
}

void TipWin::showValue(float f)
{
//convert the value to a string
char tmp[10];
snprintf(tmp, 9, format, f);
tip = tmp;

textmode = false;
redraw();
show();
}

void TipWin::setText(const char *c)
{
text = c;
textmode = true;
redraw();
}

void TipWin::showText()
{
if(!text.empty()) {
textmode = true;
redraw();
show();
}
}

void TipWin::redraw()
{
// Recalc size of window
fl_font(labelfont(), labelsize());
int W = 0, H = 0;
fl_measure(getStr(), W, H, 0);
//provide a bit of extra space
W += 8;
H += 4;
size(W, H);
Fl_Menu_Window::redraw();
}

const char *TipWin::getStr() const
{
return (textmode ? text : tip).c_str();
}

+ 25
- 0
source/native-plugins/zynaddsubfx/UI/TipWin.h View File

@@ -0,0 +1,25 @@
#ifndef TIPWIN_H
#include <string>
#include <FL/Fl_Menu_Window.H>
#include <FL/Fl_Tooltip.H>
#define TIPWIN_H
using namespace std;

class TipWin:public Fl_Menu_Window
{
public:
TipWin();
void draw();
void showValue(float f);
void setText(const char *c);
void showText();
void setRounding(unsigned int digits = 0);
private:
void redraw();
const char *getStr() const;
string tip;
string text;
bool textmode;
char format[6];
};
#endif

+ 71
- 108
source/native-plugins/zynaddsubfx/UI/WidgetPDial.cpp View File

@@ -1,104 +1,19 @@
// generated by Fast Light User Interface Designer (fluid) version 1.0107f

#include "WidgetPDial.h"
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <FL/Fl_Tooltip.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Menu_Window.H>
#include "../Misc/Util.h"
#include "WidgetPDial.h"
//Copyright (c) 2003-2005 Nasca Octavian Paul
//License: GNU GPL version 2 or later

using namespace std;

class TipWin:public Fl_Menu_Window
{
public:
TipWin();
void draw();
void showValue(float f);
void setText(const char *c);
void showText();
private:
void redraw();
const char *getStr() const;
string tip;
string text;
bool textmode;
};

TipWin::TipWin():Fl_Menu_Window(1, 1)
{
set_override();
end();
}

void TipWin::draw()
{
//setup window
draw_box(FL_BORDER_BOX, 0, 0, w(), h(), Fl_Color(175));
fl_color(Fl_Tooltip::textcolor());
fl_font(labelfont(), labelsize());

//Draw the current string
fl_draw(getStr(), 3, 3, w() - 6, h() - 6,
Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_WRAP));
}

void TipWin::showValue(float f)
{
//convert the value to a string
char tmp[10];
snprintf(tmp, 9, "%.2f", f);
tip = tmp;

textmode = false;
redraw();
show();
}

void TipWin::setText(const char *c)
{
text = c;
textmode = true;
redraw();
}

void TipWin::showText()
{
if(!text.empty()) {
textmode = true;
redraw();
show();
}
}

void TipWin::redraw()
{
// Recalc size of window
fl_font(labelfont(), labelsize());
int W = 0, H = 0;
fl_measure(getStr(), W, H, 0);
//provide a bit of extra space
W += 8;
H += 4;
size(W, H);
Fl_Menu_Window::redraw();
}

const char *TipWin::getStr() const
{
return (textmode ? text : tip).c_str();
}

//static int numobj = 0;

WidgetPDial::WidgetPDial(int x, int y, int w, int h, const char *label)
:Fl_Dial(x, y, w, h, label), oldvalue(0.0f), pos(false), textset(false)
:Fl_Dial(x, y, w, h, label), reset_value(0), integer_step(true),
oldvalue(0.0f), pos(false), textset(false), value_offset(0.0),
value_scale(1.0)
{
//cout << "[" << label << "] There are now " << ++numobj << endl;
Fl_Group *save = Fl_Group::current();
@@ -113,27 +28,46 @@ WidgetPDial::~WidgetPDial()
delete tipwin;
}

void WidgetPDial::setRounding(unsigned int digits)
{
tipwin->setRounding(digits);
}

int WidgetPDial::handle(int event)
{
//#ifdef NTK_GUI
// return Fl_Dial::handle( event );
//#else
double dragsize, min = minimum(), max = maximum();
int my;
double dragsize, min = minimum(), max = maximum(), result;
int dy;

if (event == FL_RELEASE && Fl::event_clicks() == 1) {
Fl::event_clicks(0);
value(reset_value);
value_damage();
if (this->when() != 0)
do_callback();
return 1;
}
switch(event) {
case FL_PUSH:
if (integer_step)
setRounding(0);
else if (Fl::event_shift())
setRounding(4);
else
setRounding(Fl::event_button1() ? 2 : 3);
oldvalue = value();
old_y = Fl::event_y();
case FL_DRAG:
getPos();
my = -(Fl::event_y() - y() - h() / 2);
dy = old_y - Fl::event_y();

dragsize = 200.0f;
if(Fl::event_state(FL_BUTTON1) == 0)
dragsize *= 10;
if (Fl::event_shift())
dragsize = 20000.0f;
else
dragsize = Fl::event_button1() ? 200.0f : 2000.0f;

value(limit(oldvalue + my / dragsize * (max - min), min, max));
tipwin->showValue(value());
value(clamp(oldvalue + dy / dragsize * (max - min)));
tipwin->showValue(transform(value()));
value_damage();
if(this->when() != 0)
do_callback();
@@ -141,14 +75,28 @@ int WidgetPDial::handle(int event)
case FL_MOUSEWHEEL:
if (Fl::belowmouse() != this)
return 1;
my = - Fl::event_dy();

dragsize = 200.0f;
if(Fl::event_state(FL_CTRL) != 0)
dragsize *= 10;

value(limit(value() + my / dragsize * (max - min), min, max));
tipwin->showValue(value());
dy = - Fl::event_dy();

if (integer_step) {
setRounding(0);
result = (int)(value() + dy * (Fl::event_ctrl() ? 1 : 8));
} else {
float dragsize;
if (Fl::event_shift()) {
dragsize = 10000.0;
setRounding(4);
} else if (Fl::event_ctrl()) {
dragsize = 1000.0;
setRounding(3);
} else {
dragsize = 100.0;
setRounding(2);
}
result = value() + dy / dragsize * (max - min);
}
value(clamp(result));

tipwin->showValue(transform(value()));
value_damage();
if(this->when() != 0)
do_callback();
@@ -163,6 +111,10 @@ int WidgetPDial::handle(int event)
resetPos();
break;
case FL_RELEASE:
if (integer_step) {
int rounded = value() + 0.5;
value(clamp(rounded));
}
tipwin->hide();
resetPos();
if(this->when() == 0)
@@ -262,3 +214,14 @@ void WidgetPDial::resetPos()
{
pos = false;
}

void WidgetPDial::set_transform(float scale, float offset)
{
value_offset = offset;
value_scale = scale;
}

float WidgetPDial::transform(float x)
{
return value_scale * x + value_offset;
}

+ 10
- 0
source/native-plugins/zynaddsubfx/UI/WidgetPDial.h View File

@@ -3,6 +3,7 @@
#ifndef WIDGETPDIAL_h
#define WIDGETPDIAL_h
#include <FL/Fl_Dial.H>
#include "TipWin.h"


class WidgetPDial:public Fl_Dial
@@ -14,12 +15,21 @@ class WidgetPDial:public Fl_Dial
void draw();
void pdialcolor(int r, int g, int b);
void tooltip(const char *c);
void set_transform(float scale = 1.0, float offset = 0.0);
float transform(float x);
void setRounding(unsigned int digits = 0);
float reset_value;
protected:
bool integer_step;
private:
void getPos();
void resetPos();
double oldvalue;
int old_y;
bool pos;
bool textset;
class TipWin * tipwin;
float value_offset;
float value_scale;
};
#endif

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

@@ -541,6 +541,7 @@ int main(int argc, char *argv[])
lo_server_add_method(server, NULL, NULL, handler_function, 0);
sendtourl = argv[1];
}
fprintf(stderr, "ext client running on %d\n", lo_server_get_port(server));
gui = GUI::createUi(new UI_Interface(), &Pexitprogram);



+ 5
- 2
source/native-plugins/zynaddsubfx/globals.cpp View File

@@ -24,7 +24,7 @@
#include "Misc/Util.h"
#include "globals.h"

void SYNTH_T::alias()
void SYNTH_T::alias(bool randomize)
{
halfsamplerate_f = (samplerate_f = samplerate) / 2.0f;
buffersize_f = buffersize;
@@ -36,5 +36,8 @@ void SYNTH_T::alias()
// for deleting the buffers and also call it in the dtor
denormalkillbuf.resize(buffersize);
for(int i = 0; i < buffersize; ++i)
denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
if(randomize)
denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
else
denormalkillbuf[i] = 0;
}

+ 14
- 4
source/native-plugins/zynaddsubfx/globals.h View File

@@ -43,6 +43,8 @@ class PADnoteParameters;
class SynthNote;

class Allocator;
class AbsTime;
class RelTime;

class Microtonal;
class XMLwrapper;
@@ -142,6 +144,14 @@ typedef std::complex<fftw_real> fft_t;
*/
#define PART_MAX_NAME_LEN 30

/*
* The maximum we allow for an XMZ path
*
* Note that this is an ugly hack. Finding a compile time path
* max portably is painful.
*/
#define XMZ_PATH_MAX 1024

/*
* The maximum number of bands of the equaliser
*/
@@ -270,8 +280,8 @@ public:

operator T*() { return ptr; }
operator const T*() const { return ptr; }
T& operator[](unsigned idx) { return ptr[idx]; }
const T& operator[](unsigned idx) const { return ptr[idx]; }
//T& operator[](unsigned idx) { return ptr[idx]; }
//const T& operator[](unsigned idx) const { return ptr[idx]; }
};

//temporary include for synth->{samplerate/buffersize} members
@@ -280,7 +290,7 @@ struct SYNTH_T {
SYNTH_T(void)
:samplerate(44100), buffersize(256), oscilsize(1024)
{
alias();
alias(false);
}

SYNTH_T(const SYNTH_T& ) = delete;
@@ -320,7 +330,7 @@ struct SYNTH_T {
{
return buffersize_f / samplerate_f;
}
void alias(void);
void alias(bool randomize=true);
static float numRandom(void); //defined in Util.cpp for now
};
#endif

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

@@ -138,7 +138,7 @@ int main(int argc, char *argv[])
<< " Copyright (c) 2009-2014 Mark McCurry [active maintainer]"
<< endl;
cerr << "Compiled: " << __DATE__ << " " << __TIME__ << endl;
cerr << "This program is free software (GNU GPL v.2 or later) and \n";
cerr << "This program is free software (GNU GPL v2 or later) and \n";
cerr << "it comes with ABSOLUTELY NO WARRANTY.\n" << endl;
if(argc == 1)
cerr << "Try 'zynaddsubfx --help' for command-line options." << endl;
@@ -211,6 +211,9 @@ int main(int argc, char *argv[])
{
"dump-oscdoc", 2, NULL, 'd'
},
{
"ui-title", 1, NULL, 'u'
},
{
0, 0, 0, 0
}
@@ -219,7 +222,7 @@ int main(int argc, char *argv[])
int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
int prefered_port = -1;

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

while(1) {
int tmp = 0;
@@ -227,7 +230,7 @@ int main(int argc, char *argv[])
/**\todo check this process for a small memory leak*/
opt = getopt_long(argc,
argv,
"l:L:r:b:o:I:O:N:e:P:hvapSDUY",
"l:L:r:b:o:I:O:N:e:P:u:hvapSDUY",
opts,
&option_index);
char *optarguments = optarg;
@@ -335,6 +338,10 @@ int main(int argc, char *argv[])
outfile << s;
}
break;
case 'u':
if(optarguments)
ui_title = optarguments;
break;
case '?':
cerr << "ERROR:Bad option or parameter.\n" << endl;
exitwithhelp = 1;
@@ -370,6 +377,7 @@ int main(int argc, char *argv[])
<< " -I , --input\t\t\t\t Set Input Engine\n"
<< " -e , --exec-after-init\t\t Run post-initialization script\n"
<< " -d , --dump-oscdoc=FILE\t\t Dump oscdoc xml to file\n"
<< " -u , --ui-title=TITLE\t\t Extend UI Window Titles\n"
<< endl;

return 0;
@@ -384,20 +392,26 @@ int main(int argc, char *argv[])

initprogram(std::move(synth), &config, prefered_port);

bool altered_master = false;
if(!loadfile.empty()) {
int tmp = master->loadXML(loadfile.c_str());
altered_master = true;
const char *filename = loadfile.c_str();
int tmp = master->loadXML(filename);
if(tmp < 0) {
cerr << "ERROR: Could not load master file " << loadfile
<< "." << endl;
exit(1);
}
else {
strncpy(master->last_xmz, filename, XMZ_PATH_MAX);
master->last_xmz[XMZ_PATH_MAX-1] = 0;
master->applyparameters();
cout << "Master file loaded." << endl;
}
}

if(!loadinstrument.empty()) {
altered_master = true;
int loadtopart = 0;
int tmp = master->part[loadtopart]->loadXMLinstrument(
loadinstrument.c_str());
@@ -413,6 +427,9 @@ int main(int argc, char *argv[])
}
}

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

//Run the Nio system
bool ioGood = Nio::start();

@@ -447,6 +464,10 @@ int main(int argc, char *argv[])
delete [] msg;
}

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

if(!noui)
{
GUI::raiseUi(gui, "/show", "i", config.cfg.UserInterfaceMode);


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

@@ -1,5 +1,5 @@

#include "ports.h"
#include <rtosc/ports.h>
#include <cstring>
#include <algorithm>
#include <map>
@@ -8,7 +8,7 @@
#include <utility>

#include <cassert>
#include "miditable.h"
#include <rtosc/miditable.h>

using namespace rtosc;
using std::string;


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

@@ -1,5 +1,5 @@
#include <math.h>
#include "miditable.h"
#include <rtosc/miditable.h>

using namespace rtosc;



+ 184
- 57
source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp View File

@@ -1,4 +1,4 @@
#include "ports.h"
#include "../ports.h"
#include <ostream>
#include <cassert>
#include <climits>
@@ -255,15 +255,15 @@ bool has(T &t, Z&z)
return false;
}

int rtosc_max(int a, int b) { return a<b?b:a;}
static int int_max(int a, int b) { return a<b?b:a;}

ivec_t find_pos(words_t &strs)
static ivec_t find_pos(words_t &strs)
{
ivec_t pos;
int current_dups = strs.size();
int N = 0;
for(auto w:strs)
N = rtosc_max(N,w.length());
N = int_max(N,w.length());

int pos_best = -1;
int pos_best_val = INT_MAX;
@@ -294,7 +294,7 @@ ivec_t find_pos(words_t &strs)
return pos;
}

ivec_t do_hash(const words_t &strs, const ivec_t &pos, const ivec_t &assoc)
static ivec_t do_hash(const words_t &strs, const ivec_t &pos, const ivec_t &assoc)
{
ivec_t ivec;
ivec.reserve(strs.size());
@@ -308,7 +308,7 @@ ivec_t do_hash(const words_t &strs, const ivec_t &pos, const ivec_t &assoc)
return ivec;
}

ivec_t find_assoc(const words_t &strs, const ivec_t &pos)
static ivec_t find_assoc(const words_t &strs, const ivec_t &pos)
{
ivec_t assoc;
int current_dups = strs.size();
@@ -354,7 +354,7 @@ ivec_t find_assoc(const words_t &strs, const ivec_t &pos)
return assoc;
}

ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
static ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
{
ivec_t remap;
auto hashed = do_hash(strs, pos, assoc);
@@ -362,7 +362,7 @@ ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
// printf("%d) '%s'\n", hashed[i], strs[i].c_str());
int N = 0;
for(auto h:hashed)
N = rtosc_max(N,h+1);
N = int_max(N,h+1);
for(int i=0; i<N; ++i)
remap.push_back(0);
for(int i=0; i<(int)hashed.size(); ++i)
@@ -371,7 +371,7 @@ ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
return remap;
}

void generate_minimal_hash(std::vector<std::string> str, Port_Matcher &pm)
static void generate_minimal_hash(std::vector<std::string> str, Port_Matcher &pm)
{
pm.pos = find_pos(str);
if(pm.pos.empty()) {
@@ -382,7 +382,7 @@ void generate_minimal_hash(std::vector<std::string> str, Port_Matcher &pm)
pm.remap = find_remap(str, pm.pos, pm.assoc);
}

void generate_minimal_hash(Ports &p, Port_Matcher &pm)
static void generate_minimal_hash(Ports &p, Port_Matcher &pm)
{
svec_t keys;
cvec_t args;
@@ -575,6 +575,71 @@ const Port *Ports::apropos(const char *path) const
return NULL;
}

static bool parent_path_p(char *read, char *start)
{
if(read-start<2)
return false;
return read[0]=='.' && read[-1]=='.' && read[-2]=='/';
}

static void read_path(char *&r, char *start)
{
while(1)
{
if(r<start)
break;
bool doBreak = *r=='/';
r--;
if(doBreak)
break;
}
}

static void move_path(char *&r, char *&w, char *start)
{
while(1)
{
if(r<start)
break;
bool doBreak = *r=='/';
*w-- = *r--;
if(doBreak)
break;
}
}


char *Ports::collapsePath(char *p)
{
//obtain the pointer to the last non-null char
char *p_end = p;
while(*p_end) p_end++;
p_end--;

//number of subpaths to consume
int consuming = 0;

char *write_pos = p_end;
char *read_pos = p_end;
while(read_pos >= p) {
//per path chunk either
//(1) find a parent ref and inc consuming
//(2) find a normal ref and consume
//(3) find a normal ref and write through
bool ppath = parent_path_p(read_pos, p);
if(ppath) {
read_path(read_pos, p);
consuming++;
} else if(consuming) {
read_path(read_pos, p);
consuming--;
} else
move_path(read_pos, write_pos, p);
}
//return last written location, not next to write
return write_pos+1;
};

void rtosc::walk_ports(const Ports *base,
char *name_buffer,
size_t buffer_size,
@@ -670,7 +735,7 @@ void walk_ports2(const rtosc::Ports *base,

//for(unsigned i=0; i<max; ++i)
{
sprintf(pos,"[0,%d]",max);
sprintf(pos,"[0,%d]",max-1);

//Ensure the result is a path
if(strrchr(name_buffer, '/')[1] != '/')
@@ -697,7 +762,7 @@ void walk_ports2(const rtosc::Ports *base,

//for(unsigned i=0; i<max; ++i)
{
sprintf(pos,"[0,%d]",max);
sprintf(pos,"[0,%d]",max-1);

//Apply walker function
walker(&p, name_buffer, data);
@@ -724,54 +789,110 @@ static void units(std::ostream &o, const char *u)
o << " units=\"" << u << "\"";
}

using std::ostream;
using std::string;
static ostream &dump_t_f_port(ostream &o, string name, string doc)
{
o << " <message_in pattern=\"" << name << "\" typetag=\"T\">\n";
o << " <desc>Enable " << doc << "</desc>\n";
o << " <param_T symbol=\"x\"/>\n";
o << " </message_in>\n";
o << " <message_in pattern=\"" << name << "\" typetag=\"F\">\n";
o << " <desc>Disable " << doc << "</desc>\n";
o << " <param_F symbol=\"x\"/>\n";
o << " </message_in>\n";
o << " <message_in pattern=\"" << name << "\" typetag=\"\">\n";
o << " <desc>Get state of " << doc << "</desc>\n";
o << " </message_in>\n";
o << " <message_out pattern=\"" << name << "\" typetag=\"T\">\n";
o << " <desc>Value of " << doc << "</desc>\n";
o << " <param_T symbol=\"x\"/>";
o << " </message_out>\n";
o << " <message_out pattern=\"" << name << "\" typetag=\"F\">\n";
o << " <desc>Value of " << doc << "</desc>\n";
o << " <param_F symbol=\"x\"/>";
o << " </message_out>\n";
return o;
}
static ostream &dump_any_port(ostream &o, string name, string doc)
{
o << " <message_in pattern=\"" << name << "\" typetag=\"*\">\n";
o << " <desc>" << doc << "</desc>\n";
o << " </message_in>\n";
return o;
}

static ostream &dump_generic_port(ostream &o, string name, string doc, string type)
{
const char *t = type.c_str();
string arg_names = "xyzabcdefghijklmnopqrstuvw";

//start out with argument separator
if(*t++ != ':')
return o;
//now real arguments (assume [] don't exist)
string args;
while(*t && *t != ':')
args += *t++;

o << " <message_in pattern=\"" << name << "\" typetag=\"" << args << "\">\n";
o << " <desc>" << doc << "</desc>\n";

assert(args.length()<arg_names.length());
for(unsigned i=0; i<args.length(); ++i)
o << " <param_" << args[i] << " symbol=\"" << arg_names[i] << "\"/>\n";
o << " </message_in>\n";

if(*t == ':')
return dump_generic_port(o, name, doc, t);
else
return o;
}

void dump_ports_cb(const rtosc::Port *p, const char *name, void *v)
{
std::ostream &o = *(std::ostream*)v;
auto meta = p->meta();
if(meta.find("parameter") != p->meta().end()) {
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");
string doc;

if(mdoc != p->meta().end())
doc = mdoc.value;
if(meta.find("internal") != meta.end()) {
doc += "[INTERNAL]";
}

if(mparameter != p->meta().end()) {
char type = 0;
const char *foo = strchr(p->name, ':');
if(strchr(foo, 'f'))
type = 'f';
else if(strchr(foo, 'i'))
type = 'i';
else if(strchr(foo, 'c'))
type = 'c';
else if(strchr(foo, 'T'))
type = 't';
if(args) {
if(strchr(args, 'f'))
type = 'f';
else if(strchr(args, 'i'))
type = 'i';
else if(strchr(args, 'c'))
type = 'c';
else if(strchr(args, 'T'))
type = 't';
else if(strchr(args, 's'))
type = 's';
}

if(!type) {
fprintf(stderr, "rtosc port dumper: Cannot handle '%s'\n", p->name);
fprintf(stderr, "rtosc port dumper: Cannot handle '%s'\n", name);
fprintf(stderr, " args = <%s>\n", args);
return;
}

if(type == 't')
{
o << " <message_in pattern=\"" << name << "\" typetag=\"T\">\n";
o << " <desc>Enable " << p->meta()["documentation"] << "</desc>\n";
o << " <param_T symbol=\"x\"/>\n";
o << " </message_in>\n";
o << " <message_in pattern=\"" << name << "\" typetag=\"F\">\n";
o << " <desc>Disable " << p->meta()["documentation"] << "</desc>\n";
o << " <param_F symbol=\"x\"/>\n";
o << " </message_in>\n";
o << " <message_in pattern=\"" << name << "\" typetag=\"\">\n";
o << " <desc>Get state of " << p->meta()["documentation"] << "</desc>\n";
o << " </message_in>\n";
o << " <message_out pattern=\"" << name << "\" typetag=\"T\">\n";
o << " <desc>Value of " << p->meta()["documentation"] << "</desc>\n";
o << " <param_T symbol=\"x\"/>";
o << " </message_out>\n";
o << " <message_out pattern=\"" << name << "\" typetag=\"F\">\n";
o << " <desc>Value of %s</desc>\n", p->meta()["documentation"];
o << " <param_F symbol=\"x\"/>";
o << " </message_out>\n";
if(type == 't') {
dump_t_f_port(o, name, doc);
return;
}

o << " <message_in pattern=\"" << name << "\" typetag=\"" << type << "\">\n";
o << " <desc>Set Value of " << p->meta()["documentation"] << "</desc>\n";
if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c')
{
o << " <desc>Set Value of " << doc << "</desc>\n";
if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c') {
o << " <param_" << type << " symbol=\"x\"";
units(o, meta["unit"]);
o << ">\n";
@@ -785,12 +906,11 @@ void dump_ports_cb(const rtosc::Port *p, const char *name, void *v)
}
o << " </message_in>\n";
o << " <message_in pattern=\"" << name << "\" typetag=\"\">\n";
o << " <desc>Get Value of " << p->meta()["documentation"] << "</desc>\n";
o << " <desc>Get Value of " << doc << "</desc>\n";
o << " </message_in>\n";
o << " <message_out pattern=\"" << name << "\" typetag=\"" << type << "\">\n";
o << " <desc>Value of " << p->meta()["documentation"] << "</desc>\n";
if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c')
{
o << " <desc>Value of " << doc << "</desc>\n";
if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c') {
o << " <param_" << type << " symbol=\"x\"";
units(o, meta["unit"]);
o << ">\n";
@@ -803,10 +923,17 @@ void dump_ports_cb(const rtosc::Port *p, const char *name, void *v)
o << "/>\n";
}
o << " </message_out>\n";
}// else if(meta.find("documentation") != meta.end())
// fprintf(stderr, "Skipping \"%s\"\n", name);
//else
// fprintf(stderr, "Skipping [UNDOCUMENTED] \"%s\"\n", name);
} else if(mdoc != meta.end() && (!args || args == std::string(""))) {
dump_any_port(o, name, doc);
} else if(mdoc != meta.end() && args) {
dump_generic_port(o, name, doc, args);
} else if(mdoc != meta.end()) {
fprintf(stderr, "Skipping \"%s\"\n", name);
if(args) {
fprintf(stderr, " type = %s\n", args);
}
} else
fprintf(stderr, "Skipping [UNDOCUMENTED] \"%s\"\n", name);
}

std::ostream &rtosc::operator<<(std::ostream &o, rtosc::OscDocFormatter &formatter)


+ 12
- 4
source/native-plugins/zynaddsubfx/rtosc/cpp/subtree-serialize.cpp View File

@@ -1,12 +1,20 @@
#include "subtree-serialize.h"
#include "ports.h"
#include "rtosc.h"
#include <rtosc/subtree-serialize.h>
#include <rtosc/ports.h>
#include <rtosc/rtosc.h>
#include <cstring>
#include <cassert>


using namespace rtosc;

static void emplace_uint32_cpp(uint8_t *buffer, uint32_t d)
{
buffer[0] = ((d>>24) & 0xff);
buffer[1] = ((d>>16) & 0xff);
buffer[2] = ((d>>8) & 0xff);
buffer[3] = ((d>>0) & 0xff);
}

/*
* Append another message onto a bundle if the space permits it.
* If insufficient space is available, then zero is returned and the buffer is
@@ -26,7 +34,7 @@ static size_t append_bundle(char *dst, const char *src,

if(max_len < dst_len + src_len + 4 || dst_len == 0 || src_len == 0)
return 0;
*(int32_t*)(dst+dst_len) = (int32_t)src_len;
emplace_uint32_cpp((uint8_t*)(dst+dst_len), src_len);

memcpy(dst+dst_len+4, src, src_len);



+ 1
- 4
source/native-plugins/zynaddsubfx/rtosc/cpp/thread-link.cpp View File

@@ -1,4 +1,4 @@
#include "thread-link.h"
#include "../thread-link.h"

namespace rtosc {
#ifdef off_t
@@ -17,7 +17,6 @@ struct internal_ringbuffer_t {
};

typedef internal_ringbuffer_t ringbuffer_t;
#define static

static size_t ring_read_size(ringbuffer_t *ring)
{
@@ -178,5 +177,3 @@ char *ThreadLink::buffer(void) {return write_buffer;}
size_t ThreadLink::buffer_size(void) const {return BufferSize;}

};

#undef static

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

@@ -3,8 +3,8 @@
#include <cstdio>
#include <cassert>
#include <ctime>
#include "rtosc.h"
#include "undo-history.h"
#include <rtosc/rtosc.h>
#include <rtosc/undo-history.h>

using std::pair;
using std::make_pair;


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

@@ -1,7 +1,13 @@
#include "rtosc.h"
#include <rtosc/rtosc.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>


#include <stdio.h>

static bool rtosc_match_number(const char **pattern, const char **msg)
{
//Verify both hold digits
@@ -74,3 +80,207 @@ bool rtosc_match(const char *pattern, const char *msg)
return rtosc_match_args(arg_pattern, msg);
return true;
}



/*
* Special characters from the specification:
* ' ' space 32
* # number sign 35
* * asterisk 42
* , comma 44
* / forward slash 47
* ? question mark 63
* [ open bracket 91
* ] close bracket 93
* { open curly brace 123
* } close curly brace 125
*/

#if 0
QUOTE FROM OSC 1.0 SPEC

'?' in the OSC Address Pattern matches any single character
'*' in the OSC Address Pattern matches any sequence of zero or more characters
A string of characters in square brackets (e.g., "[string]") in the OSC Address Pattern matches any character in the string.
Inside square brackets, the minus sign (-) and exclamation point (!) have special meanings:
two characters separated by a minus sign indicate the range of characters between the given two
in ASCII collating sequence. (A minus sign at the end of the string has no special meaning.)
An exclamation point at the beginning of a bracketed string negates the sense of the list,
meaning that the list matches any character not in the list.
(An exclamation point anywhere besides the first character after the open bracket has no special meaning.)
A comma-separated list of strings enclosed in curly braces (e.g., "{foo,bar}") in the OSC Address Pattern
matches any of the strings in the list.
#endif




//for literal string X
//for X+?+[] Y
//for Y+single{} Z
//for numeric string N
//assume a is of the form X
//assume b is a pattern of the form:
//* (1)
//Y (2)
//Y* (3)
//*X* (4)
//Z (5)
//Z* (6)
//Y#N (7)
#define RTOSC_MATCH_ALL 1
#define RTOSC_MATCH_CHAR 2
#define RTOSC_MATCH_PARTIAL_CHAR 3
#define RTOSC_MATCH_SUBSTRING 4
#define RTOSC_MATCH_OPTIONS 5
#define RTOSC_MATCH_PARTIAL_OPTIONS 6
#define RTOSC_MATCH_ENUMERATED 7
static bool is_charwise(char c)
{
return (c>=0 && c<=0x7f) && c != ' ' && c != '#' &&
c != '/' && c != '{' && c != '}';
}

int rtosc_subpath_pat_type(const char *pattern)
{
int charwise_only = 1;
const char *last_star = rindex(pattern, '*');
const char *pound = index(pattern, '#');
if(!strcmp("*", pattern))
return RTOSC_MATCH_ALL;

for(const char *p = pattern;*p;++p)
charwise_only &= is_charwise(*p);
if(charwise_only && !last_star)
return RTOSC_MATCH_CHAR;
if(pound)
return RTOSC_MATCH_ENUMERATED;


return 2;
}

static bool rtosc_match_char(const char **path, const char **pattern)
{
//printf("rtosc_match_char('%s','%s')\n", *path, *pattern);
if(**path == **pattern && **path) {
++*path;
++*pattern;
return true;
} else if(**pattern == '?' && *path) {
++*path;
++*pattern;
return true;
} else if(**pattern == '[') {
bool matched = false;
bool negation = false;
char last_range = '\0';
char to_match = **path;
++*pattern;
if(**pattern == '!') {
negation = true;
++*pattern;
}
while(**pattern && **pattern != ']') {
last_range = **pattern;
if(**pattern == to_match) {
matched = true;
} else if(**pattern == '-') {//range
++*pattern;
char range_high = **pattern;
if(range_high == ']' || !range_high)
break;
if(to_match <= range_high && to_match >= last_range)
matched = true;
}
++*pattern;
}
if(**pattern == ']')
++*pattern;
++*path;
return negation ^ matched;
}
return false;
}

bool rtosc_match_partial(const char *a, const char *b)
{
//assume a is of the form X
//assume b is a pattern of the form: (1..6)
//This is done to avoid backtracking of any kind
//This is an OSC serialization library, not a regex
//implementation

char patternbuf[256];
(void) patternbuf;
int type = rtosc_subpath_pat_type(b);

if(type == RTOSC_MATCH_ALL)
return true;
else if(type == RTOSC_MATCH_CHAR || type == RTOSC_MATCH_PARTIAL_CHAR) {
while(rtosc_match_char(&a,&b));
if(!*a && !*b)
return true;
else if(*a && *b=='*' && b[1] == '\0')
return true;
else
return false;
} else if(type == 4) {
//extract substring
const char *sub=NULL;
return strstr(a,sub);
} else if(type == RTOSC_MATCH_OPTIONS || type == 6) {
} else if(type == RTOSC_MATCH_ENUMERATED) {
while(rtosc_match_char(&a,&b));
if(*a && *b=='#' && b[1] != '\0')
return atoi(a) < atoi(b+1);
return false;
} else
return 0;
assert(false);
}

int rtosc_matchable_path(const char *pattern)
{
(void) pattern;
return 0;

}

int chunk_path(const char *a, int b, const char *c)
{
(void) a;
(void) b;
(void) c;
return 0;
}
void advance_path(const char **a)
{
(void) a;
}

bool rtosc_match_full_path(const char *pattern, const char *message)
{
assert(false && "This API is a WIP");
char subpattern[256];
char submessage[256];
const char *p = pattern;
const char *m = message;

step:
if(*p != *m)
return 0;
if(chunk_path(subpattern, sizeof(subpattern), p))
return 0;
if(chunk_path(submessage, sizeof(submessage), m))
return 0;

advance_path(&p);
advance_path(&m);

if(*p == 0 && *m == 0)
return 1;
else
goto step;
}

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

@@ -21,9 +21,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef RTOSC_MIDITABLE_H
#define RTOSC_MIDITABLE_H

#pragma once
#include "ports.h"
#include <rtosc/ports.h>
#include <string.h>
#include <algorithm>
#include <map>
@@ -276,3 +277,4 @@ class MidiTable
};

};
#endif

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

@@ -43,8 +43,8 @@ struct rtosc_hack_decltype_t
#define STRINGIFY(a) STRINGIFY2(a)

//Helper for documenting varargs
#define IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...) N
#define LAST_IMP(...) IMPL(__VA_ARGS__,9,8,7,6,5,4,3,2,1,0,0,0,0)
#define IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,N, ...) N
#define LAST_IMP(...) IMPL(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0,0,0)
#define DOC_IMP9(a,b,c,d,e,f,g,h,i) a b c d e f g h rDoc(i)
#define DOC_IMP8(a,b,c,d,e,f,g,h) a b c d e f g rDoc(h)
#define DOC_IMP7(a,b,c,d,e,f,g) a b c d e f rDoc(g)
@@ -75,6 +75,30 @@ struct rtosc_hack_decltype_t
#define MAC_EACH_I(mac, count, ...) MAC_EACH_IMP(mac, count, __VA_ARGS__)
#define MAC_EACH(mac, ...) MAC_EACH_I(mac, LAST_IMP(__VA_ARGS__), __VA_ARGS__)

// 1 2 3 4 5 6 7 8 910111213141516
#define OPTIONS_IMP16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)\
rOpt(14,o)rOpt(15,p)
#define OPTIONS_IMP15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)\
rOpt(14,o)
#define OPTIONS_IMP14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)
#define OPTIONS_IMP13(a,b,c,d,e,f,g,h,i,j,k,l,m) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)
#define OPTIONS_IMP12(a,b,c,d,e,f,g,h,i,j,k,l) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)
#define OPTIONS_IMP11(a,b,c,d,e,f,g,h,i,j,k) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)
#define OPTIONS_IMP10(a,b,c,d,e,f,g,h,i,j) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i) rOpt(9,j)
#define OPTIONS_IMP9(a,b,c,d,e,f,g,h,i) \
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
rOpt(7,h) rOpt(8,i)
@@ -137,7 +161,7 @@ struct rtosc_hack_decltype_t
//Alias operators
#define rParams(name, length, ...) \
rArray(name, length, __VA_ARGS__), \
{STRINGIFY(name) ":", rProp(alias), NULL, rParamsCb(name, length)}
{STRINGIFY(name) ":", rProp(alias) rDoc("get all data from aliased array"), NULL, rParamsCb(name, length)}


template<class T> constexpr T spice(T*t) {return *t;}
@@ -145,7 +169,7 @@ template<class T> constexpr T spice(T*t) {return *t;}
//Recursion [two ports in one for pointer manipulation]
#define rRecur(name, ...) \
{STRINGIFY(name) "/", DOC(__VA_ARGS__), &decltype(rObject::name)::ports, rRecurCb(name)}, \
{STRINGIFY(name) ":", rProp(internal), NULL, rRecurPtrCb(name)}
{STRINGIFY(name) ":", rProp(internal) rDoc("get obj pointer"), NULL, rRecurPtrCb(name)}

#define rRecurp(name, ...) \
{STRINGIFY(name) "/", DOC(__VA_ARGS__), \
@@ -168,7 +192,7 @@ template<class T> constexpr T spice(T*t) {return *t;}
//Misc
#define rDummy(name, ...) {STRINIFY(name), rProp(dummy), NULL, [](msg_t, rtosc::RtData &){}}
#define rString(name, len, ...) \
{STRINGIFY(name) "::s", rMap(length, len) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}
{STRINGIFY(name) "::s", rMap(length, len) rProp(parameter) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}

//General property operators
#define rMap(name, value) ":" STRINGIFY(name) "\0=" STRINGIFY(value) "\0"


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

@@ -28,7 +28,7 @@
#include <vector>
#include <functional>
#include <initializer_list>
#include "rtosc.h"
#include <rtosc/rtosc.h>
#include <cstring>
#include <cctype>
#include <cstdlib>
@@ -180,6 +180,13 @@ struct Ports
*/
const Port *apropos(const char *path) const;

/**
* Collapse path with parent path identifiers "/.."
*
* e.g. /foo/bar/../baz => /foo/baz
*/
static char *collapsePath(char *p);

private:
//Performance hacks
class Port_Matcher *impl;


+ 166
- 58
source/native-plugins/zynaddsubfx/rtosc/rtosc.c View File

@@ -6,7 +6,7 @@
#include <ctype.h>
#include <assert.h>

#include "rtosc.h"
#include <rtosc/rtosc.h>

const char *rtosc_argument_string(const char *msg)
{
@@ -78,6 +78,58 @@ char rtosc_type(const char *msg, unsigned nargument)
}
}

static unsigned arg_start(const char *msg_)
{
const uint8_t *msg = (const uint8_t*)msg_;
//Iterate to the right position
const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg_);
const uint8_t *aligned_ptr = args-1;
const uint8_t *arg_pos = args;

while(*++arg_pos);
//Alignment
arg_pos += 4-(arg_pos-aligned_ptr)%4;
return arg_pos-msg;
}

static unsigned arg_size(const uint8_t *arg_mem, char type)
{
if(!has_reserved(type))
return 0;
const uint8_t *arg_pos=arg_mem;
uint32_t blob_length = 0;
switch(type)
{
case 'h':
case 't':
case 'd':
return 8;
case 'm':
case 'r':
case 'f':
case 'c':
case 'i':
return 4;
case 'S':
case 's':
while(*++arg_pos);
arg_pos += 4-(arg_pos-arg_mem)%4;
return arg_pos-arg_mem;
case 'b':
blob_length |= (*arg_pos++ << 24);
blob_length |= (*arg_pos++ << 16);
blob_length |= (*arg_pos++ << 8);
blob_length |= (*arg_pos++);
if(blob_length%4)
blob_length += 4-blob_length%4;
arg_pos += blob_length;
return arg_pos-arg_mem;
default:
assert("Invalid Type");
}
return -1;
}

static unsigned arg_off(const char *msg, unsigned idx)
{
if(!has_reserved(rtosc_type(msg,idx)))
@@ -97,45 +149,11 @@ static unsigned arg_off(const char *msg, unsigned idx)
++args;

while(idx--) {
uint32_t bundle_length = 0;
switch(*args++)
{
case 'h':
case 't':
case 'd':
arg_pos +=8;
break;
case 'm':
case 'r':
case 'f':
case 'c':
case 'i':
arg_pos += 4;
break;
case 'S':
case 's':
while(*++arg_pos);
arg_pos += 4-(arg_pos-((uint8_t*)aligned_ptr))%4;
break;
case 'b':
bundle_length |= (*arg_pos++ << 24);
bundle_length |= (*arg_pos++ << 16);
bundle_length |= (*arg_pos++ << 8);
bundle_length |= (*arg_pos++);
if(bundle_length%4)
bundle_length += 4-bundle_length%4;
arg_pos += bundle_length;
break;
case '[':
case ']':
//completely ignore array chars
++idx;
break;
case 'T':
case 'F':
case 'I':
;
}
char type = *args++;
if(type == '[' || type == ']')
idx++;//not a valid arg idx
else
arg_pos += arg_size(arg_pos, type);
}
return arg_pos-(uint8_t*)msg;
}
@@ -385,10 +403,9 @@ size_t rtosc_amessage(char *buffer,
return pos;
}

rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
static rtosc_arg_t extract_arg(const uint8_t *arg_pos, char type)
{
rtosc_arg_t result = {0};
char type = rtosc_type(msg, idx);
//trivial case
if(!has_reserved(type)) {
switch(type)
@@ -403,7 +420,6 @@ rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
;
}
} else {
const unsigned char *arg_pos = (const unsigned char*)msg+arg_off(msg,idx);
switch(type)
{
case 'h':
@@ -450,6 +466,52 @@ rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
return result;
}

static const char *advance_past_dummy_args(const char *args)
{
while(*args == '[' || *args == ']')
args++;
return args;
}

rtosc_arg_itr_t rtosc_itr_begin(const char *msg)
{
rtosc_arg_itr_t itr;
itr.type_pos = advance_past_dummy_args(rtosc_argument_string(msg));
itr.value_pos = (uint8_t*)(msg+arg_start(msg));

return itr;
}

rtosc_arg_val_t rtosc_itr_next(rtosc_arg_itr_t *itr)
{
//current position provides the value
rtosc_arg_val_t result = {0};
result.type = *itr->type_pos;
if(result.type)
result.val = extract_arg(itr->value_pos, result.type);

//advance
itr->type_pos = advance_past_dummy_args(itr->type_pos+1);
char type = result.type;
int size = arg_size(itr->value_pos, type);
itr->value_pos += size;


return result;
}

int rtosc_itr_end(rtosc_arg_itr_t itr)
{
return !itr.type_pos || !*itr.type_pos;
}

rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
{
char type = rtosc_type(msg, idx);
uint8_t *arg_mem = (uint8_t*)msg + arg_off(msg, idx);
return extract_arg(arg_mem, type);
}

static unsigned char deref(unsigned pos, ring_t *ring)
{
return pos<ring[0].len ? ring[0].data[pos] :
@@ -461,10 +523,10 @@ static size_t bundle_ring_length(ring_t *ring)
unsigned pos = 8+8;//goto first length field
uint32_t advance = 0;
do {
advance = deref(pos+0, ring) << (8*0) |
deref(pos+1, ring) << (8*1) |
deref(pos+2, ring) << (8*2) |
deref(pos+3, ring) << (8*3);
advance = deref(pos+0, ring) << (8*3) |
deref(pos+1, ring) << (8*2) |
deref(pos+2, ring) << (8*1) |
deref(pos+3, ring) << (8*0);
if(advance)
pos += 4+advance;
} while(advance);
@@ -598,6 +660,49 @@ bool rtosc_valid_message_p(const char *msg, size_t len)
size_t observed_length = rtosc_message_length(msg, len);
return observed_length == len;
}
static uint64_t extract_uint64(const uint8_t *arg_pos)
{
uint64_t arg = 0;
arg |= (((uint64_t)*arg_pos++) << 56);
arg |= (((uint64_t)*arg_pos++) << 48);
arg |= (((uint64_t)*arg_pos++) << 40);
arg |= (((uint64_t)*arg_pos++) << 32);
arg |= (((uint64_t)*arg_pos++) << 24);
arg |= (((uint64_t)*arg_pos++) << 16);
arg |= (((uint64_t)*arg_pos++) << 8);
arg |= (((uint64_t)*arg_pos++));
return arg;
}

static uint32_t extract_uint32(const uint8_t *arg_pos)
{
uint32_t arg = 0;
arg |= (((uint32_t)*arg_pos++) << 24);
arg |= (((uint32_t)*arg_pos++) << 16);
arg |= (((uint32_t)*arg_pos++) << 8);
arg |= (((uint32_t)*arg_pos++));
return arg;
}

static void emplace_uint64(uint8_t *buffer, uint64_t d)
{
buffer[0] = ((d>>56) & 0xff);
buffer[1] = ((d>>48) & 0xff);
buffer[2] = ((d>>40) & 0xff);
buffer[3] = ((d>>32) & 0xff);
buffer[4] = ((d>>24) & 0xff);
buffer[5] = ((d>>16) & 0xff);
buffer[6] = ((d>>8) & 0xff);
buffer[7] = ((d>>0) & 0xff);
}

static void emplace_uint32(uint8_t *buffer, uint32_t d)
{
buffer[0] = ((d>>24) & 0xff);
buffer[1] = ((d>>16) & 0xff);
buffer[2] = ((d>>8) & 0xff);
buffer[3] = ((d>>0) & 0xff);
}

size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
{
@@ -605,15 +710,15 @@ size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
memset(buffer, 0, len);
strcpy(buffer, "#bundle");
buffer += 8;
(*(uint64_t*)buffer) = tt;
buffer +=8;
emplace_uint64((uint8_t*)buffer, tt);
buffer += 8;
va_list va;
va_start(va, elms);
for(int i=0; i<elms; ++i) {
const char *msg = va_arg(va, const char*);
//It is assumed that any passed message/bundle is valid
size_t size = rtosc_message_length(msg, -1);
*(uint32_t*)buffer = size;
emplace_uint32((uint8_t*)buffer, size);
buffer += 4;
memcpy(buffer, msg, size);
buffer+=size;
@@ -623,14 +728,14 @@ size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
return buffer-_buffer;
}


#define POS ((size_t)(((const char *)lengths) - buffer))
size_t rtosc_bundle_elements(const char *buffer, size_t len)
{
const uint32_t *lengths = (const uint32_t*) (buffer+16);
size_t elms = 0;
//TODO
while(POS < len && *lengths) {
lengths += *lengths/4+1;
while(POS < len && extract_uint32((const uint8_t*)lengths)) {
lengths += extract_uint32((const uint8_t*)lengths)/4+1;

if(POS > len)
break;
@@ -644,7 +749,10 @@ const char *rtosc_bundle_fetch(const char *buffer, unsigned elm)
{
const uint32_t *lengths = (const uint32_t*) (buffer+16);
size_t elm_pos = 0;
while(elm_pos!=elm && *lengths) ++elm_pos, lengths+=*lengths/4+1;
while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
++elm_pos;
lengths += extract_uint32((const uint8_t*)lengths)/4+1;
}

return (const char*) (elm==elm_pos?lengths+1:NULL);
}
@@ -654,9 +762,9 @@ size_t rtosc_bundle_size(const char *buffer, unsigned elm)
const uint32_t *lengths = (const uint32_t*) (buffer+16);
size_t elm_pos = 0;
size_t last_len = 0;
while(elm_pos!=elm && *lengths) {
last_len = *lengths;
++elm_pos, lengths+=*lengths/4+1;
while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
last_len = extract_uint32((const uint8_t*)lengths);
++elm_pos, lengths+=extract_uint32((const uint8_t*)lengths)/4+1;
}

return last_len;
@@ -669,5 +777,5 @@ int rtosc_bundle_p(const char *msg)

uint64_t rtosc_bundle_timetag(const char *msg)
{
return *(uint64_t*)(msg+8);
return extract_uint64((const uint8_t*)msg+8);
}

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

@@ -115,6 +115,37 @@ unsigned rtosc_narguments(const char *msg);
*/
char rtosc_type(const char *msg, unsigned i);

typedef struct {
const char *type_pos;
const uint8_t *value_pos;
} rtosc_arg_itr_t;

typedef struct {
char type;
rtosc_arg_t val;
} rtosc_arg_val_t;

/**
* Create an argument iterator for a message
* @param msg OSC message
* @returns an initialized iterator
*/
rtosc_arg_itr_t rtosc_itr_begin(const char *msg);

/**
* Gets the next argument in a message
* @param itr OSC message iterator
* @returns a type value pair from the message
*/
rtosc_arg_val_t rtosc_itr_next(rtosc_arg_itr_t *itr);

/**
* Determines if the iterator is at the end of the argument list
* @param itr OSC message iterator
* @returns 1 if there are no more elements, 0 otherwise
*/
int rtosc_itr_end(rtosc_arg_itr_t itr);

/**
* Blob data may be safely written to
* @param msg OSC message


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save