Browse Source

Update zynaddsubfx

tags/1.9.7
falkTX 10 years ago
parent
commit
10d4f851be
38 changed files with 1322 additions and 931 deletions
  1. +8
    -0
      source/native-plugins/zynaddsubfx/Containers/NotePool.cpp
  2. +2
    -0
      source/native-plugins/zynaddsubfx/Containers/NotePool.h
  3. +1
    -1
      source/native-plugins/zynaddsubfx/Effects/EffectMgr.cpp
  4. +45
    -50
      source/native-plugins/zynaddsubfx/Misc/Master.cpp
  5. +1
    -1
      source/native-plugins/zynaddsubfx/Misc/Master.h
  6. +552
    -483
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
  7. +5
    -1
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.h
  8. +2
    -2
      source/native-plugins/zynaddsubfx/Misc/Part.cpp
  9. +9
    -0
      source/native-plugins/zynaddsubfx/Misc/PresetExtractor.cpp
  10. +0
    -114
      source/native-plugins/zynaddsubfx/Misc/TmpFileMgr.cpp
  11. +0
    -19
      source/native-plugins/zynaddsubfx/Misc/TmpFileMgr.h
  12. +66
    -3
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp
  13. +24
    -3
      source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h
  14. +28
    -4
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp
  15. +5
    -0
      source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h
  16. +131
    -94
      source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp
  17. +3
    -1
      source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h
  18. +4
    -0
      source/native-plugins/zynaddsubfx/Synth/ADnote.cpp
  19. +1
    -0
      source/native-plugins/zynaddsubfx/Synth/ADnote.h
  20. +67
    -69
      source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp
  21. +3
    -1
      source/native-plugins/zynaddsubfx/Synth/OscilGen.h
  22. +20
    -13
      source/native-plugins/zynaddsubfx/UI/ADnoteUI.fl
  23. +1
    -1
      source/native-plugins/zynaddsubfx/UI/BankUI.fl
  24. +34
    -24
      source/native-plugins/zynaddsubfx/UI/BankView.cpp
  25. +1
    -1
      source/native-plugins/zynaddsubfx/UI/Connection.cpp
  26. +1
    -1
      source/native-plugins/zynaddsubfx/UI/EnvelopeUI.fl
  27. +1
    -1
      source/native-plugins/zynaddsubfx/UI/FilterUI.fl
  28. +2
    -0
      source/native-plugins/zynaddsubfx/UI/Fl_Osc_Slider.cpp
  29. +5
    -3
      source/native-plugins/zynaddsubfx/UI/LFOUI.fl
  30. +39
    -4
      source/native-plugins/zynaddsubfx/UI/MasterUI.fl
  31. +7
    -3
      source/native-plugins/zynaddsubfx/UI/OscilGenUI.fl
  32. +3
    -3
      source/native-plugins/zynaddsubfx/UI/PartUI.fl
  33. +1
    -1
      source/native-plugins/zynaddsubfx/globals.h
  34. +74
    -14
      source/native-plugins/zynaddsubfx/rtosc/cpp/midimapper.cpp
  35. +87
    -10
      source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp
  36. +58
    -3
      source/native-plugins/zynaddsubfx/rtosc/dispatch.c
  37. +5
    -1
      source/native-plugins/zynaddsubfx/rtosc/miditable.h
  38. +26
    -2
      source/native-plugins/zynaddsubfx/rtosc/ports.h

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

@@ -106,6 +106,14 @@ void NotePool::applyLegato(LegatoParams &par)
}
};

bool NotePool::full(void) const
{
for(int i=0; i<POLYPHONY; ++i)
if(ndesc[i].status == Part::KEY_OFF)
return false;
return true;
}

//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
bool NotePool::existsRunningNote(void) const
{


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

@@ -93,6 +93,8 @@ class NotePool
void upgradeToLegato(void);
void applyLegato(LegatoParams &par);

bool full(void) const;

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


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

@@ -45,7 +45,7 @@ static const rtosc::Ports local_ports = {
rSelf(EffectMgr),
rPaste,
rRecurp(filterpars, "Filter Parameter for Dynamic Filter"),
{"parameter#128::i:T:F", rProp(parameter) rProp(alias) rDoc("Parameter Accessor"),
{"parameter#128::i:T:F", rProp(parameter) rProp(alias) rLinear(0,127) rDoc("Parameter Accessor"),
NULL,
[](const char *msg, rtosc::RtData &d)
{


+ 45
- 50
source/native-plugins/zynaddsubfx/Misc/Master.cpp View File

@@ -166,6 +166,10 @@ static const Ports master_ports = {
[](const char *m,RtData &d){
Master *M = (Master*)d.obj;
M->noteOff(rtosc_argument(m,0).i,rtosc_argument(m,1).i);}},
{"virtual_midi_cc:iii", rDoc("MIDI CC Event"), 0,
[](const char *m,RtData &d){
Master *M = (Master*)d.obj;
M->setController(rtosc_argument(m,0).i,rtosc_argument(m,1).i,rtosc_argument(m,2).i);}},

{"setController:iii", rDoc("MIDI CC Event"), 0,
[](const char *m,RtData &d){
@@ -189,19 +193,13 @@ static const Ports master_ports = {
[](const char *,RtData &d) {
Master *M = (Master*)d.obj;
M->frozenState = false;}},
{"register:iis", rDoc("MIDI Mapping Registration"), 0,
[](const char *m,RtData &d){
Master *M = (Master*)d.obj;
M->midi.addElm(rtosc_argument(m,0).i, rtosc_argument(m,1).i,rtosc_argument(m,2).s);}},
{"learn:s", rDoc("Begin Learning for specified address"), 0,
[](const char *m, RtData &d){
Master *M = (Master*)d.obj;
printf("learning '%s'\n", rtosc_argument(m,0).s);
M->midi.learn(rtosc_argument(m,0).s);}},
{"unlearn:s", rDoc("Remove Learning for specified address"), 0,
[](const char *m, RtData &d){
{"midi-learn/", 0, &rtosc::MidiMapperRT::ports,
[](const char *msg, RtData &d) {
Master *M = (Master*)d.obj;
M->midi.clear_entry(rtosc_argument(m,0).s);}},
SNIP;
printf("residue message = <%s>\n", msg);
d.obj = &M->midi;
rtosc::MidiMapperRT::ports.dispatch(msg,d);}},
{"close-ui:", rDoc("Request to close any connection named \"GUI\""), 0,
[](const char *, RtData &d) {
d.reply("/close-ui", "");}},
@@ -228,7 +226,7 @@ static const Ports master_ports = {
{"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 &){}},
[](const char *, rtosc::RtData &d){d.forward();}},
{"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN
SNIP
preset_ports.dispatch(msg, data);
@@ -236,12 +234,6 @@ static const Ports master_ports = {
};
const Ports &Master::ports = master_ports;

#ifndef PLUGINVERSION
//XXX HACKS
Master *the_master;
rtosc::ThreadLink *the_bToU;
#endif

class DataObj:public rtosc::RtData
{
public:
@@ -252,6 +244,7 @@ class DataObj:public rtosc::RtData
loc_size = loc_size_;
obj = obj_;
bToU = bToU_;
forwarded = false;
}

virtual void reply(const char *path, const char *args, ...) override
@@ -280,9 +273,18 @@ class DataObj:public rtosc::RtData
}
virtual void broadcast(const char *msg) override
{
reply("/broadcast");
reply("/broadcast", "");
reply(msg);
};
}

virtual void forward(const char *reason) override
{
assert(message);
reply("/forward", "");
printf("forwarding '%s'\n", message);
forwarded = true;
}
bool forwarded;
private:
rtosc::ThreadLink *bToU;
};
@@ -295,20 +297,22 @@ vuData::vuData(void)
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),
frozenState(false), pendingMemory(false),
synth(synth_), time(synth), gzip_compression(config->cfg.GzipCompression)
{
bToU = NULL;
uToB = NULL;

//Setup MIDI
midi.frontend = [this](const char *msg) {bToU->raw_write(msg);};
midi.backend = [this](const char *msg) {applyOscEvent(msg);};

memory = new AllocatorClass();
swaplr = 0;
off = 0;
smps = 0;
bufl = new float[synth.buffersize];
bufr = new float[synth.buffersize];
#ifndef PLUGINVERSION
the_master = this;
#endif

last_xmz[0] = 0;
fft = new FFTwrapper(synth.oscilsize);
@@ -334,24 +338,6 @@ Master::Master(const SYNTH_T &synth_, Config* config)

defaults();

#ifndef PLUGINVERSION
midi.event_cb = [](const char *m)
{
char loc_buf[1024];
DataObj d{loc_buf, 1024, the_master, the_bToU};
memset(loc_buf, 0, sizeof(loc_buf));
//printf("sending an event to the owner of '%s'\n", m);
Master::ports.dispatch(m+1, d);
};
#else
midi.event_cb = [](const char *) {};
#endif

midi.error_cb = [](const char *a, const char *b)
{
fprintf(stderr, "MIDI- got an error '%s' -- '%s'\n",a,b);
};

mastercb = 0;
mastercb_ptr = 0;
}
@@ -362,9 +348,19 @@ void Master::applyOscEvent(const char *msg)
DataObj d{loc_buf, 1024, this, bToU};
memset(loc_buf, 0, sizeof(loc_buf));
d.matches = 0;
ports.dispatch(msg+1, d);
if(d.matches == 0)
fprintf(stderr, "Unknown path '%s'\n", msg);
if(strcmp(msg, "/get-vu") && false) {
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40);
fprintf(stdout, "backend[*]: '%s'<%s>\n", msg,
rtosc_argument_string(msg));
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
}

ports.dispatch(msg, d, true);
if(d.matches == 0 && !d.forwarded)
fprintf(stderr, "Unknown path '%s:%s'\n", msg, rtosc_argument_string(msg));
if(d.forwarded)
bToU->raw_write(msg);
}

void Master::defaults()
@@ -450,7 +446,8 @@ void Master::setController(char chan, int type, int par)
{
if(frozenState)
return;
midi.process(chan,type,par);
//TODO add chan back
midi.handleCC(type,par);
if((type == C_dataentryhi) || (type == C_dataentrylo)
|| (type == C_nrpnhi) || (type == C_nrpnlo)) { //Process RPN and NRPN by the Master (ignore the chan)
ctl.setparameternumber(type, par);
@@ -658,9 +655,7 @@ void Master::AudioOut(float *outl, float *outr)
rtosc_argument_string(msg));
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
}
d.matches = 0;
//fprintf(stdout, "address '%s'\n", uToB->peak());
ports.dispatch(msg+1, d);
ports.dispatch(msg, d, true);
events++;
if(!d.matches) {// && !ports.apropos(msg)) {
fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40);


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

@@ -166,7 +166,7 @@ class Master
//Statistics on output levels
vuData vu;

rtosc::MidiTable midi;//<1024,64>
rtosc::MidiMapperRT midi;

bool frozenState;//read-only parameters for threadsafe actions
Allocator *memory;


+ 552
- 483
source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
File diff suppressed because it is too large
View File


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

@@ -32,11 +32,15 @@ class MiddleWare
//Handle a rtosc Message uToB
void transmitMsg(const char *, const char *args, ...);
//Handle a rtosc Message uToB
void transmitMsg(const char *, const char *args, va_list va);
void transmitMsg_va(const char *, const char *args, va_list va);

//Indicate that a bank will be loaded
//NOTE: Can only be called by realtime thread
void pendingSetBank(int bank);
//Indicate that a program will be loaded on a known part
//NOTE: Can only be called by realtime thread
void pendingSetProgram(int part, int program);

//Get/Set the active bToU url
std::string activeUrl(void);
void activeUrl(std::string u);


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

@@ -398,7 +398,7 @@ void Part::NoteOn(unsigned char note,
const bool doingLegato = isRunningNote && isLegatoMode() &&
lastlegatomodevalid;

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

verifyKeyMode();
@@ -492,7 +492,7 @@ void Part::NoteOff(unsigned char note) //release the key
monomemPop(note);

for(auto &desc:notePool.activeDesc()) {
if(desc.note != note)
if(desc.note != note || desc.status != KEY_PLAYING)
continue;
if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
if((isMonoMode() || isLegatoMode()) && !monomemEmpty())


+ 9
- 0
source/native-plugins/zynaddsubfx/Misc/PresetExtractor.cpp View File

@@ -32,6 +32,7 @@ const rtosc::Ports real_preset_ports =
{"scan-for-presets:", 0, 0,
[](const char *, rtosc::RtData &d) {
MiddleWare &mw = *(MiddleWare*)d.obj;
assert(d.obj);
mw.getPresetsStore().scanforpresets();
auto &pre = mw.getPresetsStore().presets;
d.reply(d.loc, "i", pre.size());
@@ -45,6 +46,7 @@ const rtosc::Ports real_preset_ports =
{"copy:s:ss:si:ssi", 0, 0,
[](const char *msg, rtosc::RtData &d) {
MiddleWare &mw = *(MiddleWare*)d.obj;
assert(d.obj);
std::string args = rtosc_argument_string(msg);
d.reply(d.loc, "s", "clipboard copy...");
printf("\nClipboard Copy...\n");
@@ -65,6 +67,7 @@ const rtosc::Ports real_preset_ports =
{"paste:s:ss:si:ssi", 0, 0,
[](const char *msg, rtosc::RtData &d) {
MiddleWare &mw = *(MiddleWare*)d.obj;
assert(d.obj);
std::string args = rtosc_argument_string(msg);
d.reply(d.loc, "s", "clipboard paste...");
printf("\nClipboard Paste...\n");
@@ -85,11 +88,13 @@ const rtosc::Ports real_preset_ports =
{"clipboard-type:", 0, 0,
[](const char *, rtosc::RtData &d) {
const MiddleWare &mw = *(MiddleWare*)d.obj;
assert(d.obj);
d.reply(d.loc, "s", mw.getPresetsStore().clipboard.type.c_str());
}},
{"delete:s", 0, 0,
[](const char *msg, rtosc::RtData &d) {
MiddleWare &mw = *(MiddleWare*)d.obj;
assert(d.obj);
mw.getPresetsStore().deletepreset(rtosc_argument(msg,0).s);
}},

@@ -133,6 +138,7 @@ class Capture:public rtosc::RtData
{
matches = 0;
memset(locbuf, 0, sizeof(locbuf));
memset(msgbuf, 0, sizeof(msgbuf));
loc = locbuf;
loc_size = sizeof(locbuf);
obj = obj_;
@@ -193,7 +199,9 @@ std::string doCopy(MiddleWare &mw, string url, string name)
mw.doReadOnlyOp([&xml, url, name, &mw](){
Master *m = mw.spawnMaster();
//Get the pointer
printf("capture at <%s>\n", (url+"self").c_str());
T *t = (T*)capture<void*>(m, url+"self");
assert(t);
//Extract Via mxml
//t->add2XML(&xml);
t->copy(mw.getPresetsStore(), name.empty()? NULL:name.c_str());
@@ -303,6 +311,7 @@ void doClassPaste(std::string type, std::string type_, MiddleWare &mw, string ur

std::string doClassCopy(std::string type, MiddleWare &mw, string url, string name)
{
printf("doClassCopy(%p)\n", mw.spawnMaster()->uToB);
if(type == "EnvelopeParams")
return doCopy<EnvelopeParams>(mw, url, name);
else if(type == "LFOParams")


+ 0
- 114
source/native-plugins/zynaddsubfx/Misc/TmpFileMgr.cpp View File

@@ -1,114 +0,0 @@
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <fstream>
#include <unistd.h>
#include <dirent.h>

#include "Util.h"
#include "TmpFileMgr.h"

std::string TmpFileMgr::get_tmp_nam() const
{
return tmp_nam_prefix + to_s(getpid());
}

void TmpFileMgr::create_tmp_file(unsigned server_port) const
{
std::string tmp_nam = get_tmp_nam();
if(0 == access(tmp_nam.c_str(), F_OK)) {
fprintf(stderr, "Error: Cannot overwrite file %s. "
"You should probably remove it.", tmp_nam.c_str());
exit(EXIT_FAILURE);
}
FILE* tmp_fp = fopen(tmp_nam.c_str(), "w");
if(!tmp_fp)
fprintf(stderr, "Warning: could not create new file %s.\n",
tmp_nam.c_str());
else
fprintf(tmp_fp, "%u", server_port);
fclose(tmp_fp);
}

void TmpFileMgr::clean_up_tmp_nams() const
{
DIR *dir;
struct dirent *entry;
if ((dir = opendir ("/tmp/")) != nullptr)
{
while ((entry = readdir (dir)) != nullptr)
{
std::string name = std::string("/tmp/") + entry->d_name;
if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix))
{
std::string pid = name.substr(strlen(tmp_nam_prefix));
std::string proc_file = "/proc/" + std::move(pid) +
"/comm";

std::ifstream ifs(proc_file);
bool remove = false;

if(!ifs.good())
{
fprintf(stderr, "Note: trying to remove %s - the "
"process does not exist anymore.\n",
name.c_str());
remove = true;
}
else
{
std::string comm_name;
ifs >> comm_name;
if(comm_name == "zynaddsubfx")
fprintf(stderr, "Note: detected running "
"zynaddsubfx with PID %s.\n",
name.c_str() + strlen(tmp_nam_prefix));
else {
fprintf(stderr, "Note: trying to remove %s - the "
"PID is owned by\n another "
"process: %s\n",
name.c_str(), comm_name.c_str());
remove = true;
}
}


if(remove)
{
// make sure this file contains only one unsigned
unsigned udp_port;
std::ifstream ifs2(name);
if(!ifs2.good())
fprintf(stderr, "Warning: could not open %s.\n",
name.c_str());
else
{
ifs2 >> udp_port;
if(ifs.good())
fprintf(stderr, "Warning: could not remove "
"%s, \n it has not been "
"written by zynaddsubfx\n",
name.c_str());
else
{
if(std::remove(name.c_str()) != 0)
fprintf(stderr, "Warning: can not remove "
"%s.\n", name.c_str());
}
}
}

/* one might want to connect to zyn here,
but it is not necessary:
lo_address la = lo_address_new(nullptr, udp_port.c_str());
if(lo_send(la, "/echo", nullptr) <= 0)
fputs("Note: found crashed file %s\n", stderr);
lo_address_free(la);*/
}
}
closedir (dir);
} else {
fputs("Warning: can not read /tmp.\n", stderr);
}
}

+ 0
- 19
source/native-plugins/zynaddsubfx/Misc/TmpFileMgr.h View File

@@ -1,19 +0,0 @@
#pragma once

/**
This file provides routines for using zyn's tmp files.
*/
class TmpFileMgr
{
static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_";

public:
//! returns file name to where UDP port is saved
std::string get_tmp_nam() const;

//! creates a tmp file with given UDP port information
void create_tmp_file(unsigned server_port) const;

//! cleans up as many tmp files as possible
void clean_up_tmp_nams() const;
};

+ 66
- 3
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.cpp View File

@@ -250,8 +250,12 @@ void XMLwrapper::addpar(const string &name, int val)

void XMLwrapper::addparreal(const string &name, float val)
{
addparams("par_real", 2, "name", name.c_str(), "value",
stringFrom<float>(val).c_str());
union { float in; uint32_t out; } convert;
char buf[11];
convert.in = val;
sprintf(buf, "0x%8X", convert.out);
addparams("par_real", 3, "name", name.c_str(), "value",
stringFrom<float>(val).c_str(), "exact_value", buf);
}

void XMLwrapper::addparbool(const string &name, int val)
@@ -571,7 +575,14 @@ float XMLwrapper::getparreal(const char *name, float defaultpar) const
if(tmp == NULL)
return defaultpar;

const char *strval = mxmlElementGetAttr(tmp, "value");
const char *strval = mxmlElementGetAttr(tmp, "exact_value");
if (strval != NULL) {
union { float out; uint32_t in; } convert;
sscanf(strval+2, "%x", &convert.in);
return convert.out;
}

strval = mxmlElementGetAttr(tmp, "value");
if(strval == NULL)
return defaultpar;

@@ -621,3 +632,55 @@ mxml_node_t *XMLwrapper::addparams(const char *name, unsigned int params,
}
return element;
}

XmlNode::XmlNode(std::string name_)
:name(name_)
{}

std::string &XmlNode::operator[](std::string name)
{
//fetch an existing one
for(auto &a:attrs)
if(a.name == name)
return a.value;

//create a new one
attrs.push_back({name, ""});
return attrs[attrs.size()-1].value;
}

bool XmlNode::has(std::string name_)
{
//fetch an existing one
for(auto &a:attrs)
if(a.name == name_)
return true;
return false;
}

void XMLwrapper::add(const XmlNode &node_)
{
mxml_node_t *element = mxmlNewElement(node, node_.name.c_str());
for(auto attr:node_.attrs)
mxmlElementSetAttr(element, attr.name.c_str(),
attr.value.c_str());
}

std::vector<XmlNode> XMLwrapper::getBranch(void) const
{
std::vector<XmlNode> res;
mxml_node_t *current = node->child;
while(current) {
if(current->type == MXML_ELEMENT) {
auto elm = current->value.element;
XmlNode n(elm.name);
for(int i=0; i<elm.num_attrs; ++i) {
auto &attr = elm.attrs[i];
n[attr.name] = attr.value;
}
res.push_back(n);
}
current = mxmlWalkNext(current, node, MXML_NO_DESCEND);
}
return res;
}

+ 24
- 3
source/native-plugins/zynaddsubfx/Misc/XMLwrapper.h View File

@@ -24,13 +24,30 @@

#include <mxml.h>
#include <string>
#ifndef float
#define float float
#endif
#include <vector>

#ifndef XML_WRAPPER_H
#define XML_WRAPPER_H

class XmlAttr
{
public:
std::string name;
std::string value;
};


class XmlNode
{
public:
XmlNode(std::string name_);
std::string name;
std::vector<XmlAttr> attrs;

std::string &operator[](std::string name);
bool has(std::string);
};

/**Mxml wrapper*/
class XMLwrapper
{
@@ -220,6 +237,10 @@ class XMLwrapper
*/
bool hasPadSynth() const;

void add(const XmlNode &node);

std::vector<XmlNode> getBranch(void) const;

private:

/**


+ 28
- 4
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.cpp View File

@@ -42,8 +42,27 @@ using rtosc::RtData;
#define rObject ADnoteVoiceParam

static const Ports voicePorts = {
rRecurp(OscilSmp, "Primary Oscillator"),
rRecurp(FMSmp, "Modulating Oscillator"),
//Send Messages To Oscillator Realtime Table
{"OscilSmp/", rDoc("Primary Oscillator"),
&OscilGen::ports,
rBOIL_BEGIN
if(obj->OscilSmp == NULL) return;
data.obj = obj->OscilSmp;
SNIP
OscilGen::realtime_ports.dispatch(msg, data);
if(data.matches == 0)
data.forward();
rBOIL_END},
{"FMSmp/", rDoc("Modulating Oscillator"),
&OscilGen::ports,
rBOIL_BEGIN
if(obj->FMSmp == NULL) return;
data.obj = obj->FMSmp;
SNIP
OscilGen::realtime_ports.dispatch(msg, data);
if(data.matches == 0)
data.forward();
rBOIL_END},
rRecurp(FreqLfo, "Frequency LFO"),
rRecurp(AmpLfo, "Amplitude LFO"),
rRecurp(FilterLfo, "Filter LFO"),
@@ -107,7 +126,7 @@ static const Ports voicePorts = {
rToggle(PFMFreqEnvelopeEnabled, "Modulator Frequency Envelope"),
rToggle(PFMAmpEnvelopeEnabled, "Modulator Amplitude Envelope"),

//weird stuff for PCoarseDetune
{"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL,
[](const char *, RtData &d)
@@ -148,7 +167,7 @@ static const Ports voicePorts = {
obj->PCoarseDetune = k + (obj->PCoarseDetune/1024)*1024;
}
}},
//weird stuff for PCoarseDetune
{"FMdetunevalue:", rMap(unit,cents) rDoc("Get modulator detune"), NULL, [](const char *, RtData &d)
{
@@ -223,6 +242,7 @@ static const Ports globalPorts = {
rParamZyn(PVolume, "volume control"),
rParamZyn(PAmpVelocityScaleFunction, "Volume Velocity Control"),

rParamZyn(Fadein_adjustment, "Adjustment for anti-pop strategy."),
rParamZyn(PPunchStrength, "Punch Strength"),
rParamZyn(PPunchTime, "UNKNOWN"),
rParamZyn(PPunchStretch, "How Punch changes with note frequency"),
@@ -348,6 +368,7 @@ void ADnoteGlobalParam::defaults()
PAmpVelocityScaleFunction = 64;
AmpEnvelope->defaults();
AmpLfo->defaults();
Fadein_adjustment = FADEIN_ADJUSTMENT_SCALE;
PPunchStrength = 0;
PPunchTime = 60;
PPunchStretch = 64;
@@ -712,6 +733,7 @@ void ADnoteGlobalParam::add2XML(XMLwrapper *xml)
xml->addpar("volume", PVolume);
xml->addpar("panning", PPanning);
xml->addpar("velocity_sensing", PAmpVelocityScaleFunction);
xml->addpar("fadein_adjustment", Fadein_adjustment);
xml->addpar("punch_strength", PPunchStrength);
xml->addpar("punch_time", PPunchTime);
xml->addpar("punch_stretch", PPunchStretch);
@@ -788,6 +810,7 @@ void ADnoteGlobalParam::getfromXML(XMLwrapper *xml)
PAmpVelocityScaleFunction = xml->getpar127("velocity_sensing",
PAmpVelocityScaleFunction);

Fadein_adjustment = xml->getpar127("fadein_adjustment", Fadein_adjustment);
PPunchStrength = xml->getpar127("punch_strength", PPunchStrength);
PPunchTime = xml->getpar127("punch_time", PPunchTime);
PPunchStretch = xml->getpar127("punch_stretch", PPunchStretch);
@@ -982,6 +1005,7 @@ void ADnoteGlobalParam::paste(ADnoteGlobalParam &a)
copy(PPanning);
copy(PAmpVelocityScaleFunction);

copy(Fadein_adjustment);
copy(PPunchStrength);
copy(PPunchTime);
copy(PPunchStretch);


+ 5
- 0
source/native-plugins/zynaddsubfx/Params/ADnoteParameters.h View File

@@ -30,6 +30,8 @@ enum FMTYPE {
NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PITCH_MOD
};

#define FADEIN_ADJUSTMENT_SCALE 20

/*****************************************************************/
/* GLOBAL PARAMETERS */
/*****************************************************************/
@@ -79,6 +81,9 @@ struct ADnoteGlobalParam {

LFOParams *AmpLfo;

/* Adjustment factor for anti-pop fadein */
unsigned char Fadein_adjustment;

unsigned char PPunchStrength, PPunchTime, PPunchStretch,
PPunchVelocitySensing;



+ 131
- 94
source/native-plugins/zynaddsubfx/Params/PADnoteParameters.cpp View File

@@ -34,113 +34,41 @@
using namespace rtosc;


#define PC(x) rParamZyn(P##x, "undocumented padnote parameter")

template<int i>
void simpleset(const char *m, rtosc::RtData &d)
{
unsigned char *addr = ((unsigned char*) d.obj)+i;
if(!rtosc_narguments(m))
d.reply(d.loc, "c", *addr);
else
*addr = rtosc_argument(m, 0).i;
}

#define rObject PADnoteParameters

#define P_C(x) rtosc::Port{#x "::c", "::", NULL, \
simpleset<__builtin_offsetof(class PADnoteParameters, P##x)>}
static const rtosc::Ports PADnotePorts =
static const rtosc::Ports realtime_ports =
{
rRecurp(oscilgen, "Oscillator"),
rRecurp(FreqLfo, "Frequency LFO"),
rRecurp(AmpLfo, "Amplitude LFO"),
rRecurp(FilterLfo, "Filter LFO"),
rRecurp(resonance, "Resonance"),
rRecurp(FreqEnvelope, "Frequency Envelope"),
rRecurp(AmpEnvelope, "Amplitude Envelope"),
rRecurp(FilterEnvelope, "Filter Envelope"),
rRecurp(GlobalFilter, "Post Filter"),
rParamI(Pmode, rMap(min, 0), rMap(max, 2), "0 - bandwidth, 1 - discrete 2 - continious"),
PC(Volume),
PC(hp.base.type),
PC(hp.base.par1),
PC(hp.freqmult),
PC(hp.modulator.par1),
PC(hp.modulator.freq),
PC(hp.width),
PC(hp.amp.mode),
PC(hp.amp.type),
PC(hp.amp.par1),
PC(hp.amp.par2),
rToggle(Php.autoscale, "Autoscaling Harmonics"),
PC(hp.onehalf),

PC(bwscale),

PC(hrpos.type),
PC(hrpos.par1),
PC(hrpos.par2),
PC(hrpos.par3),

PC(quality.samplesize),
PC(quality.basenote),
PC(quality.oct),
PC(quality.smpoct),

PC(fixedfreq),
PC(fixedfreqET),
PC(Stereo),
PC(Panning),
PC(AmpVelocityScaleFunction),
PC(PunchStrength),
PC(PunchTime),
PC(PunchStretch),
PC(PunchVelocitySensing),
PC(FilterVelocityScale),
PC(FilterVelocityScaleFunction),

//Volume
rToggle(PStereo, "Stereo/Mono Mode"),
rParamZyn(PPanning, "Left Right Panning"),
rParamZyn(PVolume, "Synth Volume"),
rParamZyn(PAmpVelocityScaleFunction, "Amplitude Velocity Sensing function"),

//Punch
rParamZyn(PPunchStrength, "Punch Strength"),
rParamZyn(PPunchTime, "UNKNOWN"),
rParamZyn(PPunchStretch, "How Punch changes with note frequency"),
rParamZyn(PPunchVelocitySensing, "Punch Velocity control"),

//Filter
rParamZyn(PFilterVelocityScale, "Filter Velocity Magnitude"),
rParamZyn(PFilterVelocityScaleFunction, "Filter Velocity Function Shape"),

//Freq
rToggle(Pfixedfreq, "Base frequency fixed frequency enable"),
rParamZyn(PfixedfreqET, "Equal temeperate control for fixed frequency operation"),

rParamI(PDetune, "Fine Detune"),
rParamI(PCoarseDetune, "Coarse Detune"),
rParamZyn(PDetuneType, "Magnitude of Detune"),

{"Pbandwidth::i", rProp(parameter) rDoc("Bandwith Of Harmonics"), NULL,
[](const char *msg, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
if(rtosc_narguments(msg)) {
p->setPbandwidth(rtosc_argument(msg, 0).i);
} else {
d.reply(d.loc, "i", p->Pbandwidth);
}}},
{"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));
}},


{"nhr:", rProp(non-realtime) rDoc("Returns the harmonic shifts"),
NULL, [](const char *, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
const unsigned n = p->synth.oscilsize / 2;
float *tmp = new float[n];
*tmp = 0;
for(unsigned i=1; i<n; ++i)
tmp[i] = p->getNhr(i);
d.reply(d.loc, "b", n*sizeof(float), tmp);
delete[] tmp;}},
{"profile:i", rProp(non-realtime) rDoc("UI display of the harmonic profile"),
NULL, [](const char *m, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
const int n = rtosc_argument(m, 0).i;
if(n<=0)
return;
float *tmp = new float[n];
float realbw = p->getprofile(tmp, n);
d.reply(d.loc, "b", n*sizeof(float), tmp);
d.reply(d.loc, "i", realbw);
delete[] tmp;}},
{"sample#64:ifb", rProp(internal) rDoc("Nothing to see here"), 0,
[](const char *m, rtosc::RtData &d)
{
@@ -189,9 +117,118 @@ static const rtosc::Ports PADnotePorts =
obj->PCoarseDetune = k + (obj->PCoarseDetune/1024)*1024;
}
}},

};
static const rtosc::Ports non_realtime_ports =
{
//Harmonic Source Distribution
rRecurp(oscilgen, "Oscillator"),
rRecurp(resonance, "Resonance"),

//Harmonic Shape
rOption(Pmode, rMap(min, 0), rMap(max, 2), rOptions(bandwidth,discrete,continious),
"Harmonic Distribution Model"),
rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential),
"Harmonic profile shape"),
rParamZyn(Php.base.par1, "Harmonic shape distribution parameter"),
rParamZyn(Php.freqmult, "Frequency multiplier on distribution"),
rParamZyn(Php.modulator.par1, "Distribution modulator parameter"),
rParamZyn(Php.modulator.freq, "Frequency of modulator parameter"),
rParamZyn(Php.width, "Width of base harmonic"),
rOption(Php.amp.mode, rOptions(Sum, Mult, Div1, Div2),
"Amplitude harmonic multiplier type"),

//Harmonic Modulation
rOption(Php.amp.type, rOptions(Off, Gauss, Sine, Flat),
"Type of amplitude multipler"),
rParamZyn(Php.amp.par1, "Amplitude multiplier parameter"),
rParamZyn(Php.amp.par2, "Amplitude multiplier parameter"),
rToggle(Php.autoscale, "Autoscaling Harmonics"),
rOption(Php.onehalf,
rOptions(Full, Upper Half, Lower Half),
"Harmonic cutoff model"),

//Harmonic Bandwidth
rOption(Pbwscale,
rOptions(Normal,
EqualHz, Quater,
Half, 75%, 150%,
Double, Inv. Half),
"Bandwidth scaling"),

//Harmonic Position Modulation
rOption(Phrpos.type,
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine,
Power, Shift),
"Harmonic Overtone shifting mode"),
rParamZyn(Phrpos.par1, "Harmonic position parameter"),
rParamZyn(Phrpos.par2, "Harmonic position parameter"),
rParamZyn(Phrpos.par3, "Harmonic position parameter"),

//Quality
rOption(Pquality.samplesize,
rOptions(16k (Tiny), 32k, 64k (Small), 128k,
256k (Normal), 512k, 1M (Big)),
"Size of each wavetable element"),
rOption(Pquality.basenote,
rOptions( C-2, G-2, C-3, G-3, C-4,
G-4, C-5, G-5, G-6,),
"Base note for wavetable"),
rOption(Pquality.smpoct,
rOptions(0.5, 1, 2, 3, 4, 6, 12),
"Samples per octave"),
rParamI(Pquality.oct, rLinear(0,7),
"Number of octaves to sample (above the first sample"),

{"Pbandwidth::i", rProp(parameter) rLinear(0,1000) rDoc("Bandwith Of Harmonics"), NULL,
[](const char *msg, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
if(rtosc_narguments(msg)) {
p->setPbandwidth(rtosc_argument(msg, 0).i);
} else {
d.reply(d.loc, "i", p->Pbandwidth);
}}},

{"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));
}},


{"nhr:", rProp(non-realtime) rDoc("Returns the harmonic shifts"),
NULL, [](const char *, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
const unsigned n = p->synth.oscilsize / 2;
float *tmp = new float[n];
*tmp = 0;
for(unsigned i=1; i<n; ++i)
tmp[i] = p->getNhr(i);
d.reply(d.loc, "b", n*sizeof(float), tmp);
delete[] tmp;}},
{"profile:i", rProp(non-realtime) rDoc("UI display of the harmonic profile"),
NULL, [](const char *m, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
const int n = rtosc_argument(m, 0).i;
if(n<=0)
return;
float *tmp = new float[n];
float realbw = p->getprofile(tmp, n);
d.reply(d.loc, "b", n*sizeof(float), tmp);
d.reply(d.loc, "i", realbw);
delete[] tmp;}},
};

const rtosc::Ports &PADnoteParameters::non_realtime_ports = ::non_realtime_ports;
const rtosc::Ports &PADnoteParameters::realtime_ports = ::realtime_ports;


const rtosc::MergePorts PADnoteParameters::ports =
{
&non_realtime_ports,
&realtime_ports
};

const rtosc::Ports &PADnoteParameters::ports = PADnotePorts;

PADnoteParameters::PADnoteParameters(const SYNTH_T &synth_, FFTwrapper *fft_)
:Presets(), synth(synth_)


+ 3
- 1
source/native-plugins/zynaddsubfx/Params/PADnoteParameters.h View File

@@ -165,7 +165,9 @@ class PADnoteParameters:public Presets
void sampleGenerator(PADnoteParameters::callback cb,
std::function<bool()> do_abort);

static const rtosc::Ports &ports;
static const rtosc::MergePorts ports;
static const rtosc::Ports &non_realtime_ports;
static const rtosc::Ports &realtime_ports;

private:
void generatespectrum_bandwidthMode(float *spectrum,


+ 4
- 0
source/native-plugins/zynaddsubfx/Synth/ADnote.cpp View File

@@ -69,6 +69,9 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
pars.GlobalPar.
PFilterVelocityScaleFunction) - 1);

NoteGlobalPar.Fadein_adjustment =
pars.GlobalPar.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE;
NoteGlobalPar.Fadein_adjustment *= NoteGlobalPar.Fadein_adjustment;
if(pars.GlobalPar.PPunchStrength != 0) {
NoteGlobalPar.Punch.Enabled = 1;
NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f
@@ -1101,6 +1104,7 @@ inline void ADnote::fadein(float *smps) const
float tmp = (synth.buffersize_f - 1.0f) / (zerocrossings + 1) / 3.0f;
if(tmp < 8.0f)
tmp = 8.0f;
tmp *= NoteGlobalPar.Fadein_adjustment;

int n;
F2I(tmp, n); //how many samples is the fade-in


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

@@ -144,6 +144,7 @@ class ADnote:public SynthNote
Envelope *AmpEnvelope;
LFO *AmpLfo;

float Fadein_adjustment;
struct {
int Enabled;
float initialvalue, dt, t;


+ 67
- 69
source/native-plugins/zynaddsubfx/Synth/OscilGen.cpp View File

@@ -38,10 +38,8 @@

pthread_t main_thread;

#define PC(x) rParamZyn(P##x, "undocumented oscilgen parameter")

#define rObject OscilGen
const rtosc::Ports OscilGen::ports = {
const rtosc::Ports OscilGen::non_realtime_ports = {
rSelf(OscilGen),
rPaste,
//TODO ensure min/max
@@ -51,27 +49,16 @@ const rtosc::Ports OscilGen::ports = {
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),
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),
rOptions(None, Rev, Sine, Power, Chop),
"Modulation applied to Base function spectra"),
rParamZyn(Pbasefuncmodulationpar1,
"Base function modulation parameter"),
@@ -82,58 +69,32 @@ const rtosc::Ports OscilGen::ports = {
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"),
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),
rParamZyn(Pfilterpar1, "Filter parameter"),
rParamZyn(Pfilterpar2, "Filter parameter"),
rToggle(Pfilterbeforews, "Filter before waveshaping spectra;"
"When enabled oscilfilter(freqs); then waveshape(freqs);, "
"otherwise waveshape(freqs); then oscilfilter(freqs);"),
PC(satype),
rOption(Psatype, rOptions(None, Pow, ThrsD, ThrsU),
"Spectral Adjustment Type"),
rParamZyn(Psapar, "Spectral Adjustment Parameter"),
rParamI(Pharmonicshift, "Amount of shift on harmonics"),
rToggle(Pharmonicshiftfirst, "If harmonics are shifted before waveshaping/filtering"),
rOption(Pmodulation, rOptions(None, Rev, Sine, Power),
"Frequency Modulation To Combined Spectra"),
rParamZyn(Pmodulationpar1,
"modulation parameter"),
rParamZyn(Pmodulationpar2,
"modulation parameter"),
rParamZyn(Pmodulationpar3,
"modulation parameter"),
//FIXME realtime parameters lurking below
PC(rand),
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"),
rParamZyn(Pmodulationpar1, "modulation parameter"),
rParamZyn(Pmodulationpar2, "modulation parameter"),
rParamZyn(Pmodulationpar3, "modulation parameter"),


//TODO update to rArray and test
{"phase#128::c", rProp(parameter) rDoc("Sets harmonic phase"),
{"phase#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic phase"),
NULL, [](const char *m, rtosc::RtData &d) {
const char *mm = m;
while(*mm && !isdigit(*mm)) ++mm;
@@ -144,7 +105,7 @@ const rtosc::Ports OscilGen::ports = {
phase = rtosc_argument(m,0).i;
}},
//TODO update to rArray and test
{"magnitude#128::c", rProp(parameter) rDoc("Sets harmonic magnitude"),
{"magnitude#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic magnitude"),
NULL, [](const char *m, rtosc::RtData &d) {
//printf("I'm at '%s'\n", d.loc);
const char *mm = m;
@@ -152,8 +113,20 @@ const rtosc::Ports OscilGen::ports = {
unsigned char &mag = ((OscilGen*)d.obj)->Phmag[atoi(mm)];
if(!rtosc_narguments(m))
d.reply(d.loc, "c", mag);
else
else {
mag = rtosc_argument(m,0).i;
printf("setting magnitude\n\n");
//XXX hack hack
char *repath = strdup(d.loc);
char *edit = rindex(repath, '/')+1;
strcpy(edit, "prepare");
OscilGen &o = *((OscilGen*)d.obj);
fft_t *data = new fft_t[o.synth.oscilsize / 2];
o.prepare(data);
// fprintf(stderr, "sending '%p' of fft data\n", data);
d.chain(repath, "b", sizeof(fft_t*), &data);
o.pendingfreqs = data;
}
}},
{"base-spectrum:", rProp(non-realtime) rDoc("Returns spectrum of base waveshape"),
NULL, [](const char *, rtosc::RtData &d) {
@@ -203,8 +176,8 @@ const rtosc::Ports OscilGen::ports = {
OscilGen &o = *(OscilGen*)d.obj;
fft_t *data = new fft_t[o.synth.oscilsize / 2];
o.prepare(data);
//fprintf(stderr, "sending '%p' of fft data\n", data);
d.reply("/forward", "sb", d.loc, sizeof(fft_t*), &data);
// fprintf(stderr, "sending '%p' of fft data\n", data);
d.chain(d.loc, "b", sizeof(fft_t*), &data);
o.pendingfreqs = data;
}},
{"convert2sine:", rProp(non-realtime) rDoc("Translates waveform into FS"),
@@ -214,20 +187,42 @@ const rtosc::Ports OscilGen::ports = {
{"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"),
}}};

#define rForwardCb [](const char *msg, rtosc::RtData &d) {\
printf("fowarding...\n"); d.forward();}
const rtosc::Ports OscilGen::realtime_ports{
rSelf(OscilGen),
rParamZyn(Prand, "Oscilator Phase Randomness: smaller than 0 is \""
"group\", larger than 0 is for each harmonic"),
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"),
{"prepare:b", rProp(internal) rProp(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);
// fprintf(stderr, "prepare:b got a message from '%s'\n", m);
OscilGen &o = *(OscilGen*)d.obj;
assert(rtosc_argument(m,0).b.len == sizeof(void*));
d.reply("/free", "sb", "fft_t", sizeof(void*), &o.oscilFFTfreqs);
//fprintf(stderr, "\n\n");
//fprintf(stderr, "The ID of this of this thread is: %ld\n", (long)pthread_self());
//fprintf(stderr, "o.oscilFFTfreqs = %p\n", o.oscilFFTfreqs);
assert(main_thread != pthread_self());
assert(o.oscilFFTfreqs !=*(fft_t**)rtosc_argument(m,0).b.data);
o.oscilFFTfreqs = *(fft_t**)rtosc_argument(m,0).b.data;
}},

};

const rtosc::MergePorts OscilGen::ports{
&OscilGen::realtime_ports,
&OscilGen::non_realtime_ports
};


@@ -486,6 +481,9 @@ void OscilGen::getbasefunction(float *smps)
case 3: //power
t += powf((1.0f - cosf((t + p2) * 2.0f * PI)) * 0.5f, p3) * p1;
break;
case 4: //chop
t = t * (powf(2.0, Pbasefuncmodulationpar1/32.0 +
Pbasefuncmodulationpar2/2048.0)) + p3;
}

t = t - floor(t);


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

@@ -114,7 +114,9 @@ class OscilGen:public Presets

bool ADvsPAD; //if it is used by ADsynth or by PADsynth

static const rtosc::Ports ports;
static const rtosc::MergePorts ports;
static const rtosc::Ports non_realtime_ports;
static const rtosc::Ports realtime_ports;

/* Oscillator Frequencies -
* this is different than the hamonics set-up by the user,


+ 20
- 13
source/native-plugins/zynaddsubfx/UI/ADnoteUI.fl View File

@@ -690,6 +690,12 @@ voiceonbutton->redraw();} open
code0 {o->init("Unison_phase_randomness");}
class Fl_Osc_Dial
}
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_Group {} {
@@ -717,7 +723,7 @@ voiceonbutton->redraw();} open
} {}
Fl_Dial {} {
label Pan
tooltip {Panning (leftmost is Random)} xywh {210 60 30 30} box ROUND_UP_BOX labelsize 10 maximum 127 step 1
tooltip {Panning (leftmost is Random)} xywh {212 65 30 30} box ROUND_UP_BOX labelsize 10 maximum 127 step 1
code0 {o->init("PPanning");}
class Fl_Osc_Dial
}
@@ -856,12 +862,6 @@ bypassfiltercheckbutton->redraw();}
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
@@ -1046,27 +1046,34 @@ class ADnoteUI {open : {public PresetsUI_}
code0 {o->init("PPanning");}
class Fl_Osc_Dial
}
Fl_Dial {} {
label De-pop selected
tooltip {Pop suppression} xywh {208 228 20 20} type Float labelsize 10 maximum 127 step 1 textfont 1 textsize 11
code0 {o->init("Fadein_adjustment");}
class Fl_Osc_Dial
}

Fl_Dial pstr {
label {P.Str.}
tooltip {Punch Strength} xywh {125 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
tooltip {Punch Strength} xywh {78 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("PPunchStrength");}
class Fl_Osc_Dial
}
Fl_Dial pt {
label {P.t.}
tooltip {Punch Time (duration)} xywh {155 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
tooltip {Punch Time (duration)} xywh {108 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("PPunchTime");}
class Fl_Osc_Dial
}
Fl_Dial pstc {
label {P.Stc.}
tooltip {Punch Stretch} xywh {185 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
tooltip {Punch Stretch} xywh {138 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("PPunchStretch");}
class Fl_Osc_Dial
}
Fl_Dial pvel {
label {P.Vel.}
tooltip {Punch Velocity Sensing} xywh {215 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
tooltip {Punch Velocity Sensing} xywh {168 237 25 25} box ROUND_UP_BOX labelsize 10 align 1 maximum 127 step 1
code0 {o->init("PPunchVelocitySensing");}
class Fl_Osc_Dial
}
@@ -1084,7 +1091,7 @@ class ADnoteUI {open : {public PresetsUI_}
} {}
Fl_Check_Button rndgrp {
label {Rnd Grp}
tooltip {How the Harmonic Amplitude is applied to voices that use the same oscillator} xywh {70 235 40 25} down_box DOWN_BOX labelsize 10 align 148
tooltip {How the Harmonic Amplitude is applied to voices that use the same oscillator} xywh {7 241 65 18} down_box DOWN_BOX labelsize 11
code0 {o->init("Hrandgrouping");}
class Fl_Osc_Check
}
@@ -1115,7 +1122,7 @@ class ADnoteUI {open : {public PresetsUI_}
}
Fl_Check_Button stereo {
label Stereo
xywh {5 230 65 35} down_box DOWN_BOX labelsize 11
xywh {7 223 65 18} down_box DOWN_BOX labelsize 11
code0 {o->init("PStereo");}
class Fl_Osc_Check
}


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

@@ -89,7 +89,7 @@ refreshmainwindow();}
callback {refreshmainwindow();}
xywh {5 8 220 20} down_box BORDER_BOX labelfont 1 align 0 textfont 1 textsize 11
code0 {bankview->init(osc, modeselect, npart);}
code1 {o->init("loadbank");}
code1 {o->init("bank/bank_select");}
class BankList
} {}
Fl_Button {} {


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

@@ -15,13 +15,14 @@ BankList::BankList(int x,int y, int w, int h, const char *label)
void BankList::init(std::string path)
{
ext = path;
oscRegister("bank-list");
oscRegister("bank/bank_select");
oscRegister(path.c_str());
oscWrite("bank/banks", "");
}

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

const int pos = rtosc_argument(msg, 0).i;
const char *path = rtosc_argument(msg, 1).s;
@@ -31,9 +32,8 @@ void BankList::OSC_raw(const char *msg)
this->clear();

this->add(path);
osc->write("/loadbank");
}
if(!strcmp(msg, "/loadbank")&& !strcmp(rtosc_argument_string(msg),"i")) {
if(!strcmp(msg, "/bank/bank_select")&& !strcmp(rtosc_argument_string(msg),"i")) {
value(rtosc_argument(msg, 0).i);
}
}
@@ -246,9 +246,12 @@ void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_)
for(int i=0; i<160; ++i)
slots[i]->init(i, this);

//Create Slot Listeners
for(int i=0; i<160; ++i)
osc->createLink("/bank/slot"+to_s(i), this);
//Request Values
for(int i=0; i<160; ++i)
osc->write("/refresh_bank", "i", i);
osc->write("/bank/slot"+to_s(i), "");
}

/*
@@ -271,8 +274,8 @@ void BankView::react(int event, int nslot)
//Rename slot
if (event==2 && !isempty && mode!=4) {
if(const char *name=fl_input("Slot (instrument) name:", slot.name())) {
osc->write("/bank-rename", "is", nslot, name);
osc->write("/refresh_bank", "i", nslot);
osc->write("/bank/rename_slot", "is", nslot, name);
osc->write("/bank/slot"+to_s(nslot), "");
}
}

@@ -289,8 +292,8 @@ void BankView::react(int event, int nslot)
if(event==1 && mode==2){
if(isempty ||
fl_choice("Overwrite the slot no. %d ?","No","Yes",NULL,nslot+1)) {
osc->write("/save-bank-part", "ii", *npart, nslot);
osc->write("/refresh_bank", "i", nslot);
osc->write("/bank/save_to_slot", "ii", *npart, nslot);
osc->write("/bank/slot"+to_s(nslot), "");
}
bvc->mode(1);
}
@@ -300,8 +303,8 @@ void BankView::react(int event, int nslot)
if(event==1 && mode==3) {
if (!isempty &&
fl_choice("Clear the slot no. %d ?","No","Yes",NULL, nslot+1)) {
osc->write("/clear-bank-slot", "i", nslot);
osc->write("/refresh_bank", "i", nslot);
osc->write("/bank/clear-slot", "i", nslot);
osc->write("/bank/slot"+to_s(nslot), "");
}
bvc->mode(1);
}
@@ -309,9 +312,9 @@ void BankView::react(int event, int nslot)
//Swap
if(mode==4) {
if(event==1 && nselected>=0){
osc->write("/swap-bank-slots", "ii", nselected, nslot);
osc->write("/refresh_bank", "i", nslot);
osc->write("/refresh_bank", "i", nselected);
osc->write("/bank/swap_slots", "ii", nselected, nslot);
osc->write("/bank/slot"+to_s(nslot), "");
osc->write("/bank/slot"+to_s(nselected), "");
nselected=-1;
} else if(nselected<0 || event==2) {
nselected=nslot;
@@ -321,15 +324,22 @@ void BankView::react(int event, int nslot)

void BankView::OSC_raw(const char *msg)
{
if(strcmp(rtosc_argument_string(msg), "iss"))
return;

int nslot = rtosc_argument(msg,0).i;
const char *name = rtosc_argument(msg,1).s;
const char *fname = rtosc_argument(msg,2).s;

if(0 <= nslot && nslot < 160)
slots[nslot]->update(name, fname);
if(!strcmp(rtosc_argument_string(msg), "iss")) {
int nslot = rtosc_argument(msg,0).i;
const char *name = rtosc_argument(msg,1).s;
const char *fname = rtosc_argument(msg,2).s;

if(0 <= nslot && nslot < 160)
slots[nslot]->update(name, fname);
} if(!strcmp(rtosc_argument_string(msg), "ss")) {
while(*msg && !isdigit(*msg)) msg++;
int nslot = atoi(msg);
const char *name = rtosc_argument(msg,0).s;
const char *fname = rtosc_argument(msg,1).s;

if(0 <= nslot && nslot < 160)
slots[nslot]->update(name, fname);
}
}
void BankView::cbwig(Fl_Widget *w)
@@ -345,6 +355,6 @@ void BankView::refresh(void)
return;

for(int i=0; i<160; ++i)
osc->write("/refresh_bank", "i", i);
osc->write("/bank/slot"+to_s(i), "");
}


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

@@ -263,7 +263,7 @@ class UI_Interface:public Fl_Osc_Interface
////fprintf(stderr, ".");
//fprintf(stderr, "write(%s:%s)\n", s.c_str(), args);
//fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
impl->transmitMsg(s.c_str(), args, va);
impl->transmitMsg_va(s.c_str(), args, va);
va_end(va);
}



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

@@ -73,7 +73,7 @@ class PointButton {open : {public Fl_Button, public Fl_Osc_Widget}}
}
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)} {} {
Function {EnvelopeUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h)} {} {
code {freemodeeditwindow=NULL;
envADSR=NULL;
envASR=NULL;


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

@@ -70,7 +70,7 @@ decl {\#include "FormantFilterGraph.H"} {public local

class FilterUI {open : {public Fl_Osc_Group,PresetsUI_}
} {
Function {FilterUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h,label)} {} {
Function {FilterUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h)} {} {
code {nvowel=0;nformant=0;nseqpos=0;} {}
}
Function {~FilterUI()} {} {


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

@@ -107,6 +107,8 @@ int Fl_Osc_Slider::handle(int ev, int X, int Y, int W, int H)
step = 1;
}
int dy = minimum() <= maximum() ? -Fl::e_dy : Fl::e_dy;
// Flip sense for vertical sliders.
dy = (this->type() & 1) ? dy : -dy;
handle_drag(clamp(value() + step * dy));
}
return 1;


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

@@ -46,9 +46,9 @@ decl {\#include "common.H"} {public local

class LFOUI {open : {public Fl_Osc_Group, PresetsUI_}
} {
Function {LFOUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h,label)} {open
Function {LFOUI(int x,int y, int w, int h, const char *label=0):Fl_Osc_Group(x,y,w,h)} {open
} {
code {} {}
code { cached_label = label; } {}
}
Function {~LFOUI()} {open
} {
@@ -188,6 +188,8 @@ refresh();

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

lfoparamswindow->label(this->label());} {}
lfoparamswindow->label(cached_label);} {}
}

decl { const char *cached_label; } { private }
}

+ 39
- 4
source/native-plugins/zynaddsubfx/UI/MasterUI.fl View File

@@ -161,7 +161,12 @@ bankui->show();}
callback {if ((int)bankui->cbwig->value()!=(npart+1)){
bankui->cbwig->value(npart+1);
bankui->cbwig->do_callback();
};}
}
if (Fl::event_shift())
partui->instrumenteditwindow->show();
else if (Fl::event_ctrl())
partui->instrumentkitlist->show();
}
xywh {15 235 40 20} labelsize 10
}
Fl_Choice partrcv {
@@ -196,9 +201,10 @@ o->redraw();}
code {npart=0;
bankui=NULL;} {}
}
Function {init(int npart_,BankUI *bankui_)} {} {
Function {init(int npart_,BankUI *bankui_, PartUI *partui_)} {} {
code {npart=npart_;
bankui=bankui_;
partui=partui_;
ext = "part"+to_s(npart)+"/";

make_window();
@@ -227,6 +233,8 @@ panellistitemgroup->redraw();} {}
}
decl {BankUI *bankui;} {private local
}
decl {PartUI *partui;} {private local
}
}

class MasterUI {open
@@ -304,6 +312,32 @@ class MasterUI {open
}}
xywh {15 15 100 20} divider
}
MenuItem {} {
label {&Load Midi Learn...}
callback {char *filename;
filename=fl_file_chooser("Open:","({*.xlz})",NULL,0);
if (filename==NULL) return;

osc->write("/load_xlz", "s", filename);}
xywh {40 40 100 20}
}
MenuItem {} {
label {Save Midi Learn...}
callback {char *filename;
int result;
filename=fl_file_chooser("Save:","({*.xlz})",NULL,0);
if (filename==NULL) return;
filename=fl_filename_setext(filename,".xlz");

result=fileexists(filename);
if (result) {
result=0;
if (!fl_choice("The file exists. \\nOverwrite it?","No","Yes",NULL)) return;
};

osc->write("/save_xlz", "s", filename);}
xywh {30 30 100 20} divider
}
MenuItem {} {
label {&Load Scale Settings...}
callback {char *filename;
@@ -903,7 +937,7 @@ GNU General Public License for details.}
} {
Fl_Pack {} {open
xywh {5 10 560 285} type HORIZONTAL
code0 {for (int i=0;i<NUM_MIDI_PARTS/2;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(i,bankui);}}
code0 {for (int i=0;i<NUM_MIDI_PARTS/2;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(i,bankui,partui);}}
} {}
}
Fl_Scroll {} {open
@@ -911,7 +945,7 @@ GNU General Public License for details.}
} {
Fl_Pack {} {open
xywh {5 325 560 285} type HORIZONTAL
code0 {for (int i=NUM_MIDI_PARTS/2;i<NUM_MIDI_PARTS;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(i,bankui);}}
code0 {for (int i=NUM_MIDI_PARTS/2;i<NUM_MIDI_PARTS;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(i,bankui,partui);}}
} {}
}
Fl_Button {} {
@@ -1681,6 +1715,7 @@ char *tmp;
if (result<0) fl_alert("Error: Could not save the file.");
else
{
osc->write("/last_xmz", "s", filename);
\#if USE_NSM
if ( nsm && nsm->is_active() )
setfilelabel( nsm->display_name );


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

@@ -121,7 +121,7 @@ class Oscilharmonic {: {public Fl_Group}

display->redraw();}
xywh {0 15 15 115} type {Vert Knob} box NO_BOX selection_color 222 maximum 127 step 1 value 64
code0 {o->phase=false;//o->value(127-oscil->Phmag[n]);}
code0 {o->phase=false;o->ext = "magnitude"+to_s(n);//o->value(127-oscil->Phmag[n]);}
code1 {//if (oscil->Phmag[n]==64) o->selection_color(0);}
class OGSlider
}
@@ -134,7 +134,7 @@ o->osc->requestValue(o->loc+"waveform");

display->redraw();}
xywh {0 135 15 75} type {Vert Knob} box NO_BOX selection_color 222 maximum 127 step 1 value 64
code0 {o->phase=true;//o->value(oscil->Phphase[n]);}
code0 {o->phase=true;o->ext = "phase"+to_s(n);//o->value(oscil->Phphase[n]);}
class OGSlider
}
Fl_Box {} {
@@ -252,7 +252,7 @@ class OscilEditor {open : {public PresetsUI_}
label rnd
callback {}
tooltip {Oscilator Phase Randomness: smaller than 0 is "group", larger than 0 is for each harmonic} xywh {145 290 100 10} type {Horz Knob} box NO_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1
code0 {(void)o->init("Prand");//if (oscil->ADvsPAD) o->hide();}
code0 {(void)o->init("Prand"); if (!adnotep) o->hide();}
class Fl_Osc_VSlider
}
Fl_Group {} {open
@@ -454,6 +454,10 @@ redrawoscil();}
label Pow
xywh {85 85 100 20} labelfont 1 labelsize 10
}
MenuItem {} {
label Chop
xywh {95 95 100 20} labelfont 1 labelsize 10
}
}
Fl_Dial bfmodpar1 {
callback {redrawoscil();}


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

@@ -137,11 +137,11 @@ maxkcounter->do_callback();}
Fl_Button adeditbutton {
label edit
callback {
if (Fl::event_shift()) {
if (Fl::event_shift())
partui->showvoiceparams(n, true);
} else if (Fl::event_ctrl()) {
else if (Fl::event_ctrl())
partui->showvoiceparams(n, false);
} else
else
partui->showparameters(n,0);
}
xywh {420 0 40 15} box THIN_UP_BOX labelsize 11


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

@@ -34,7 +34,7 @@
#endif

//Forward Declarations
namespace rtosc{struct Ports; class ThreadLink;};
namespace rtosc{struct Ports; struct ClonePorts; struct MergePorts; class ThreadLink;};
class EffectMgr;
class ADnoteParameters;
struct ADnoteGlobalParam;


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

@@ -139,20 +139,42 @@ void MidiMappernRT::map(const char *addr, bool coarse)
unMap(addr, coarse);
learnQueue.push_back(std::make_pair(addr,coarse));
char buf[1024];
rtosc_message(buf, 1024, "/midi-add-watch","");
rtosc_message(buf, 1024, "/midi-learn/midi-add-watch","");
rt_cb(buf);
}
MidiMapperStorage *MidiMappernRT::generateNewBijection(const Port &port, std::string addr)
{
MidiBijection bi;
const auto &meta = port.meta();
if(meta.find("min") == meta.end() ||
meta.find("max") == meta.end()) {
printf("Rtosc-MIDI: Cannot Learn address = <%s>\n", addr.c_str());
printf("Rtosc-MIDI: There are no min/max fields\n");
return NULL;
}
bi.mode = 0;
bi.min = atof(port.meta()["min"]);
bi.max = atof(port.meta()["max"]);
auto tmp = [bi,addr](int16_t x, MidiMapperStorage::write_cb cb) {
char type = 'f';
if(strstr(port.name, ":i"))
type = 'i';
std::function<void(int16_t, MidiMapperStorage::write_cb cb)> tmp =
[bi,addr,type](int16_t x, MidiMapperStorage::write_cb cb) {
float out = bi(x);
//printf("in = %d out = %f\n", x, out);
char buf[1024];
rtosc_message(buf, 1024, addr.c_str(), "f", out);
if(type == 'f')
rtosc_message(buf, 1024, addr.c_str(), "f", out);
else
rtosc_message(buf, 1024, addr.c_str(), "i", (int)out);
cb(buf);
};
if(bi.min == 0 && bi.max == 127 && type =='i')
tmp = [bi,addr,type](int16_t x, MidiMapperStorage::write_cb cb) {
//printf("special case in = %x out = %d\n", x, 0x7f&(x>>7));
char buf[1024];
rtosc_message(buf, 1024, addr.c_str(), "i", 0x7f&(x>>7));
cb(buf);
};

@@ -177,10 +199,19 @@ void MidiMappernRT::addNewMapper(int ID, const Port &port, std::string addr)
bi.mode = 0;
bi.min = atof(port.meta()["min"]);
bi.max = atof(port.meta()["max"]);
auto tmp = [bi,addr](int16_t x, MidiMapperStorage::write_cb cb) {
char type = 'f';
if(strstr(port.name, ":i"))
type = 'i';
//printf("ADDING TYPE %c\n", type);
auto tmp = [bi,addr,type](int16_t x, MidiMapperStorage::write_cb cb) {
float out = bi(x);
//printf("in = %d out = %f\n", x, out);
char buf[1024];
rtosc_message(buf, 1024, addr.c_str(), "f", out);
if(type == 'f')
rtosc_message(buf, 1024, addr.c_str(), "f", out);
else
rtosc_message(buf, 1024, addr.c_str(), "i", (int)out);

cb(buf);
};

@@ -197,6 +228,10 @@ void MidiMappernRT::addNewMapper(int ID, const Port &port, std::string addr)
}
storage = nstorage;
inv_map[addr] = std::make_tuple(storage->callbacks.size()-1, ID,-1,bi);

char buf[1024];
rtosc_message(buf, 1024, "/midi-learn/midi-bind", "b", sizeof(storage), &storage);
rt_cb(buf);
}

void MidiMappernRT::addFineMapper(int ID, const Port &port, std::string addr)
@@ -234,7 +269,7 @@ void MidiMappernRT::useFreeID(int ID)
return;
std::string addr = std::get<0>(learnQueue.front());
bool coarse = std::get<1>(learnQueue.front());
learnQueue.pop_front();
assert(base_ports);
const rtosc::Port *p = base_ports->apropos(addr.c_str());
@@ -264,13 +299,13 @@ void MidiMappernRT::useFreeID(int ID)
//TODO clean up unused value and callback objects

char buf[1024];
rtosc_message(buf, 1024, "/midi-bind", "b", sizeof(storage), &storage);
rtosc_message(buf, 1024, "/midi-learn/midi-bind", "b", sizeof(storage), &storage);
rt_cb(buf);
};

void MidiMappernRT::unMap(const char *addr, bool coarse)
{
printf("Unmapping('%s',%d)\n",addr,coarse);
//printf("Unmapping('%s',%d)\n",addr,coarse);
if(inv_map.find(addr) == inv_map.end())
return;
auto imap = inv_map[addr];
@@ -296,7 +331,7 @@ void MidiMappernRT::unMap(const char *addr, bool coarse)
//TODO clean up unused value and callback objects

char buf[1024];
rtosc_message(buf, 1024, "/midi-bind", "b", sizeof(storage), &storage);
rtosc_message(buf, 1024, "/midi-learn/midi-bind", "b", sizeof(storage), &storage);
rt_cb(buf);
}

@@ -386,7 +421,7 @@ void MidiMappernRT::apply_low(int v, int ID) { apply_midi(0x7f&v,ID);}
void MidiMappernRT::apply_midi(int val, int ID)
{
char buf[1024];
rtosc_message(buf,1024,"/virtual_midi_cc","ii",val,ID);
rtosc_message(buf,1024,"/virtual_midi_cc","iii",0,val,ID);
rt_cb(buf);
}

@@ -408,9 +443,9 @@ void MidiMappernRT::setBounds(const char *str, float low, float high)
};

storage = nstorage;
char buf[1024];
rtosc_message(buf, 1024, "/midi-bind", "b", sizeof(storage), &storage);
rtosc_message(buf, 1024, "/midi-learn/midi-bind", "b", sizeof(storage), &storage);
rt_cb(buf);
}

@@ -497,7 +532,8 @@ MidiMapperRT::MidiMapperRT(void)
{}
void MidiMapperRT::setBackendCb(std::function<void(const char*)> cb) {backend = cb;}
void MidiMapperRT::setFrontendCb(std::function<void(const char*)> cb) {frontend = cb;}
void MidiMapperRT::handleCC(int ID, int val) {
void MidiMapperRT::handleCC(int ID, int val) {
//printf("handling CC(%d,%d){%d,%d,%d}\n", ID, val, (int)storage, pending.has(ID), watchSize);
if((!storage || !storage->handleCC(ID, val, backend)) && !pending.has(ID) && watchSize) {
watchSize--;
pending.insert(ID);
@@ -508,6 +544,30 @@ void MidiMapperRT::handleCC(int ID, int val) {
}
void MidiMapperRT::addWatch(void) {watchSize++;}
void MidiMapperRT::remWatch(void) {if(watchSize) watchSize--;}

const rtosc::Ports MidiMapperRT::ports = {
{"midi-add-watch",0,0, [](msg_t, RtData&d)
{
auto midi = (MidiMapperRT*)d.obj;
midi->addWatch();}},
{"midi-remove-watch",0,0, [](msg_t, RtData&d)
{
auto midi = (MidiMapperRT*)d.obj;
midi->remWatch();}},
{"midi-bind:b","",0, [](msg_t msg, RtData&d)
{
auto &midi = *(MidiMapperRT*)d.obj;
midi.pending.pop();
MidiMapperStorage *nstorage =
*(MidiMapperStorage**)rtosc_argument(msg,0).b.data;
if(midi.storage) {
nstorage->cloneValues(*midi.storage);
midi.storage = nstorage;
} else
midi.storage = nstorage;}}
};

//Depricated
Port MidiMapperRT::addWatchPort(void) {
return Port{"midi-add-watch","",0, [this](msg_t, RtData&) {
this->addWatch();


+ 87
- 10
source/native-plugins/zynaddsubfx/rtosc/cpp/ports.cpp View File

@@ -16,7 +16,7 @@ static inline void scat(char *dest, const char *src)
}

RtData::RtData(void)
:loc(NULL), loc_size(0), obj(NULL), matches(0)
:loc(NULL), loc_size(0), obj(NULL), matches(0), message(NULL)
{}

void RtData::reply(const char *path, const char *args, ...)
@@ -42,6 +42,9 @@ void RtData::broadcast(const char *path, const char *args, ...)
void RtData::broadcast(const char *msg)
{reply(msg);};

void RtData::forward(const char *rational)
{}

void metaiterator_advance(const char *&title, const char *&value)
{
if(!title || !*title) {
@@ -373,6 +376,8 @@ static ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)

static void generate_minimal_hash(std::vector<std::string> str, Port_Matcher &pm)
{
if(str.empty())
return;
pm.pos = find_pos(str);
if(pm.pos.empty()) {
fprintf(stderr, "rtosc: Failed to generate minimal hash\n");
@@ -413,14 +418,9 @@ static void generate_minimal_hash(Ports &p, Port_Matcher &pm)
}

Ports::Ports(std::initializer_list<Port> l)
:ports(l), impl(new Port_Matcher)
:ports(l), impl(NULL)
{
generate_minimal_hash(*this, *impl);
impl->enump = new bool[ports.size()];
for(int i=0; i<(int)ports.size(); ++i)
impl->enump[i] = strchr(ports[i].name, '#');

elms = ports.size();
refreshMagic();
}

Ports::~Ports()
@@ -433,9 +433,20 @@ Ports::~Ports()
#define __builtin_expect(a,b) a
#endif

void Ports::dispatch(const char *m, rtosc::RtData &d) const
void Ports::dispatch(const char *m, rtosc::RtData &d, bool base_dispatch) const
{
void *obj = d.obj;

//handle the first dispatch layer
if(base_dispatch) {
d.matches = 0;
d.message = m;
if(m && *m == '/')
m++;
if(d.loc)
d.loc[0] = 0;
}

//simple case
if(!d.loc || !d.loc_size) {
for(const Port &port: ports) {
@@ -501,8 +512,14 @@ void Ports::dispatch(const char *m, rtosc::RtData &d) const
for(auto p:impl->pos)
if(p < (int)len)
t += impl->assoc[m[p]];
if(t >= (int)impl->remap.size())
if(t >= (int)impl->remap.size() && !default_handler)
return;
else if(t >= (int)impl->remap.size() && default_handler) {
d.matches++;
default_handler(m,d), d.obj = obj;
return;
}

int port_num = impl->remap[t];

//Verify the chosen port is correct
@@ -531,6 +548,9 @@ void Ports::dispatch(const char *m, rtosc::RtData &d) const

//Remove the rest of the path
old_end[0] = '\0';
} else if(default_handler) {
d.matches++;
default_handler(m,d), d.obj = obj;
}
}
}
@@ -640,6 +660,63 @@ char *Ports::collapsePath(char *p)
return write_pos+1;
};

void Ports::refreshMagic()
{
delete impl;
impl = new Port_Matcher;
generate_minimal_hash(*this, *impl);
impl->enump = new bool[ports.size()];
for(int i=0; i<(int)ports.size(); ++i)
impl->enump[i] = strchr(ports[i].name, '#');

elms = ports.size();
}

ClonePorts::ClonePorts(const Ports &ports_,
std::initializer_list<ClonePort> c)
:Ports({})
{
for(auto &to_clone:c) {
const Port *clone_port = NULL;
for(auto &p:ports_.ports)
if(!strcmp(p.name, to_clone.name))
clone_port = &p;
if(!clone_port && strcmp("*", to_clone.name)) {
fprintf(stderr, "Cannot find a clone port for '%s'\n",to_clone.name);
assert(false);
}

if(clone_port) {
ports.push_back({clone_port->name, clone_port->metadata,
clone_port->ports, to_clone.cb});
} else {
default_handler = to_clone.cb;
}
}

refreshMagic();
}
MergePorts::MergePorts(std::initializer_list<const rtosc::Ports*> c)
:Ports({})
{
//XXX TODO remove duplicates in some sane and documented way
//e.g. repeated ports override and remove older ones
for(auto *to_clone:c) {
assert(to_clone);
for(auto &p:to_clone->ports) {
bool already_there = false;
for(auto &pp:ports)
if(!strcmp(pp.name, p.name))
already_there = true;

if(!already_there)
ports.push_back(p);
}
}

refreshMagic();
}

void rtosc::walk_ports(const Ports *base,
char *name_buffer,
size_t buffer_size,


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

@@ -26,15 +26,70 @@ static bool rtosc_match_number(const char **pattern, const char **msg)
return val < max;
}

// pattern = /previous/{A,B,C,D,E}/after
// ^
// message = /previous/C/after
// ^
const char *rtosc_match_options(const char *pattern, const char **msg)
{
const char *preserve = *msg;
assert(*pattern == '{');
pattern++;

retry:

while(1) {
//Check for special characters
if(*pattern == ',' || *pattern == '}') {
goto advance_until_end;
} else if((*pattern == **msg)) { //verbatim compare
if(**msg)
++pattern, ++*msg;
else
goto try_next;
} else
goto try_next;
}

advance_until_end:
while(*pattern && *pattern != '}') pattern++;
if(*pattern == '}')
pattern++;
return pattern;
try_next:
*msg = preserve;
while(*pattern && *pattern != '}' && *pattern != ',') pattern++;
if(*pattern == ',') {
pattern++;
goto retry;
}

return NULL;
}

const char *rtosc_match_path(const char *pattern, const char *msg)
{
while(1) {
//Check for special characters
if(*pattern == ':' && !*msg)
return pattern;
else if(*pattern == '/' && *msg == '/')
return ++pattern;
else if(*pattern == '#') {
else if(*pattern == '{') {
pattern = rtosc_match_options(pattern, &msg);
if(!pattern)
return NULL;
} else if(*pattern == '*') {
//advance message and pattern to '/' or ':' and '\0'
while(*pattern && *pattern != '/' && *pattern != ':')
pattern++;
if(*pattern == '/' || *pattern == ':')
while(*msg && *msg != '/')
msg++;
} else if(*pattern == '/' && *msg == '/') {
++pattern;
++msg;
if(*pattern == '\0' || *pattern == ':')
return pattern;
} else if(*pattern == '#') {
++pattern;
if(!rtosc_match_number(&pattern, &msg))
return NULL;


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

@@ -121,7 +121,7 @@ class MidiMappernRT
std::string getMappedString(std::string addr);

MidiBijection getBijection(std::string s);
void snoop(const char *msg);

void apply_high(int v, int ID);
@@ -158,10 +158,14 @@ class MidiMapperRT
void handleCC(int ID, int val);
void addWatch(void);
void remWatch(void);

//Depricated
Port addWatchPort(void);
Port removeWatchPort(void);
Port bindPort(void);

static const Ports ports;

//Fixed upper bounded size set of integer IDs
class PendingQueue
{


+ 26
- 2
source/native-plugins/zynaddsubfx/rtosc/ports.h View File

@@ -52,11 +52,16 @@ struct RtData
void *obj;
int matches;
const Port *port;
const char *message;

virtual void reply(const char *path, const char *args, ...);
virtual void reply(const char *msg);
virtual void chain(const char *path, const char *args, ...){};
virtual void chain(const char *msg){};
virtual void broadcast(const char *path, const char *args, ...);
virtual void broadcast(const char *msg);

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


@@ -123,7 +128,7 @@ struct Port {
struct Ports
{
std::vector<Port> ports;
std::function<void(msg_t, RtData&)> default_handler;

typedef std::vector<Port>::const_iterator itr_t;

@@ -152,7 +157,7 @@ struct Ports
* @param d The RtData object shall contain a path buffer (or null), the length of
* the buffer, a pointer to data.
*/
void dispatch(const char *m, RtData &d) const;
void dispatch(const char *m, RtData &d, bool base_dispatch=false) const;

/**
* Retrieve local port by name
@@ -187,12 +192,31 @@ struct Ports
*/
static char *collapsePath(char *p);

protected:
void refreshMagic(void);
private:
//Performance hacks
class Port_Matcher *impl;
unsigned elms;
};

struct ClonePort
{
const char *name;
std::function<void(msg_t, RtData&)> cb;
};

struct ClonePorts:public Ports
{
ClonePorts(const Ports &p,
std::initializer_list<ClonePort> c);
};

struct MergePorts:public Ports
{
MergePorts(std::initializer_list<const Ports*> c);
};


/*********************
* Port walking code *


Loading…
Cancel
Save