zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

PresetExtractor.cpp (16370B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   PresetExtractor.cpp - Extract Presets from realtime data
      5   Copyright (C) 2015 Mark McCurry
      6 
      7   This program is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU General Public License
      9   as published by the Free Software Foundation; either version 2
     10   of the License, or (at your option) any later version.
     11 */
     12 
     13 #include "../Params/PresetsStore.h"
     14 
     15 #include "../Misc/Master.h"
     16 #include "../Misc/Util.h"
     17 #include "../Misc/Allocator.h"
     18 #include "../Effects/EffectMgr.h"
     19 #include "../Synth/OscilGen.h"
     20 #include "../Synth/Resonance.h"
     21 #include "../Params/ADnoteParameters.h"
     22 #include "../Params/EnvelopeParams.h"
     23 #include "../Params/FilterParams.h"
     24 #include "../Params/LFOParams.h"
     25 #include "../Params/PADnoteParameters.h"
     26 #include "../Params/Presets.h"
     27 #include "../Params/PresetsArray.h"
     28 #include "../Params/SUBnoteParameters.h"
     29 #include "../Misc/MiddleWare.h"
     30 #include "PresetExtractor.h"
     31 #include <rtosc/ports.h>
     32 #include <rtosc/port-sugar.h>
     33 #include <string>
     34 
     35 namespace zyn {
     36 
     37 using std::string;
     38 static void dummy(const char *, rtosc::RtData&) {}
     39 
     40 const rtosc::Ports real_preset_ports =
     41 {
     42     {"scan-for-presets:", 0, 0,
     43         [](const char *, rtosc::RtData &d) {
     44             MiddleWare &mw = *(MiddleWare*)d.obj;
     45             assert(d.obj);
     46             mw.getPresetsStore().scanforpresets();
     47             auto &pre = mw.getPresetsStore().presets;
     48             d.reply(d.loc, "i", pre.size());
     49             for(unsigned i=0; i<pre.size();++i)
     50                 d.reply(d.loc, "isss", i,
     51                         pre[i].file.c_str(),
     52                         pre[i].name.c_str(),
     53                         pre[i].type.c_str());
     54 
     55         }},
     56     {"copy:s:ss:si:ssi", 0, 0,
     57         [](const char *msg, rtosc::RtData &d) {
     58             MiddleWare &mw = *(MiddleWare*)d.obj;
     59             assert(d.obj);
     60             std::string args = rtosc_argument_string(msg);
     61             d.reply(d.loc, "s", "clipboard copy...");
     62             printf("\nClipboard Copy...\n");
     63             if(args == "s")
     64                 presetCopy(mw, rtosc_argument(msg, 0).s, "");
     65             else if(args == "ss")
     66                 presetCopy(mw, rtosc_argument(msg, 0).s,
     67                             rtosc_argument(msg, 1).s);
     68             else if(args == "si")
     69                 presetCopyArray(mw, rtosc_argument(msg, 0).s,
     70                             rtosc_argument(msg, 1).i, "");
     71             else if(args == "ssi")
     72                 presetCopyArray(mw, rtosc_argument(msg, 0).s,
     73                             rtosc_argument(msg, 2).i, rtosc_argument(msg, 1).s);
     74             else
     75                 assert(false && "bad arguments");
     76         }},
     77     {"paste:s:ss:si:ssi", 0, 0,
     78         [](const char *msg, rtosc::RtData &d) {
     79             MiddleWare &mw = *(MiddleWare*)d.obj;
     80             assert(d.obj);
     81             std::string args = rtosc_argument_string(msg);
     82             d.reply(d.loc, "s", "clipboard paste...");
     83             if(args == "s")
     84                 presetPaste(mw, rtosc_argument(msg, 0).s, "");
     85             else if(args == "ss")
     86                 presetPaste(mw, rtosc_argument(msg, 0).s,
     87                             rtosc_argument(msg, 1).s);
     88             else if(args == "si")
     89                 presetPasteArray(mw, rtosc_argument(msg, 0).s,
     90                             rtosc_argument(msg, 1).i, "");
     91             else if(args == "ssi")
     92                 presetPasteArray(mw, rtosc_argument(msg, 0).s,
     93                             rtosc_argument(msg, 2).i, rtosc_argument(msg, 1).s);
     94             else
     95                 assert(false && "bad arguments");
     96         }},
     97     {"clipboard-type:", 0, 0,
     98         [](const char *, rtosc::RtData &d) {
     99             const MiddleWare &mw = *(MiddleWare*)d.obj;
    100             assert(d.obj);
    101             d.reply(d.loc, "s", mw.getPresetsStore().clipboard.type.c_str());
    102         }},
    103     {"delete:s", 0, 0,
    104         [](const char *msg, rtosc::RtData &d) {
    105             MiddleWare &mw = *(MiddleWare*)d.obj;
    106             assert(d.obj);
    107             mw.getPresetsStore().deletepreset(rtosc_argument(msg,0).s);
    108         }},
    109 
    110 };
    111 
    112 // Documentation for real_preset_ports above.
    113 const rtosc::Ports preset_ports
    114 {
    115     {"scan-for-presets:", rDoc("Scan For Presets"), 0, dummy},
    116     {"copy:s:ss:si:ssi",  rDoc("Copy (s)URL to (s) Name/Clipboard from subfield (i)"), 0, dummy},
    117     {"paste:s:ss:si:ssi", rDoc("Paste (s) URL to (s) File-Name/Clipboard from subfield (i)"), 0, dummy},
    118     {"clipboard-type:",   rDoc("Type Stored In Clipboard"), 0, dummy},
    119     {"delete:s", rDoc("Delete the given preset file"), 0, dummy},
    120 };
    121 
    122 //Relevant types to keep in mind
    123 //Effects/EffectMgr.cpp:    setpresettype("Peffect");
    124 //Params/ADnoteParameters.cpp:    setpresettype("Padsynth");
    125 //Params/EnvelopeParams.cpp:    //setpresettype("Penvamplitude");
    126 //Params/EnvelopeParams.cpp:    //setpresettype("Penvamplitude");
    127 //Params/EnvelopeParams.cpp:    //setpresettype("Penvfrequency");
    128 //Params/EnvelopeParams.cpp:    //setpresettype("Penvfilter");
    129 //Params/EnvelopeParams.cpp:    //setpresettype("Penvbandwidth");
    130 //Params/FilterParams.cpp:    //setpresettype("Pfilter");
    131 //Params/LFOParams.cpp:    //        setpresettype("Plfofrequency");
    132 //Params/LFOParams.cpp:    //        setpresettype("Plfoamplitude");
    133 //Params/LFOParams.cpp:    //        setpresettype("Plfofilter");
    134 //Params/PADnoteParameters.cpp:    setpresettype("Ppadsynth");
    135 //Params/SUBnoteParameters.cpp:    setpresettype("Psubsynth");
    136 //Synth/OscilGen.cpp:    setpresettype("Poscilgen");
    137 //Synth/Resonance.cpp:    setpresettype("Presonance");
    138 
    139 
    140 /*****************************************************************************
    141  *                     Implementation Methods                                *
    142  *****************************************************************************/
    143 class Capture:public rtosc::RtData
    144 {
    145     public:
    146         Capture(void *obj_)
    147         {
    148             matches = 0;
    149             memset(locbuf, 0, sizeof(locbuf));
    150             memset(msgbuf, 0, sizeof(msgbuf));
    151             loc      = locbuf;
    152             loc_size = sizeof(locbuf);
    153             obj      = obj_;
    154         }
    155 
    156         virtual void reply(const char *path, const char *args, ...)
    157         {
    158             //printf("reply(%p)(%s)(%s)...\n", msgbuf, path, args);
    159             //printf("size is %d\n", sizeof(msgbuf));
    160             va_list va;
    161             va_start(va,args);
    162             char *buffer = msgbuf;
    163             rtosc_vmessage(buffer,sizeof(msgbuf),path,args,va);
    164             va_end(va);
    165         }
    166         char msgbuf[1024];
    167         char locbuf[1024];
    168 };
    169 
    170 template <class T>
    171 T capture(Master *m, std::string url);
    172 
    173 template <>
    174 std::string capture(Master *m, std::string url)
    175 {
    176     Capture c(m);
    177     char query[1024];
    178     rtosc_message(query, 1024, url.c_str(), "");
    179     Master::ports.dispatch(query+1,c);
    180     if(rtosc_message_length(c.msgbuf, sizeof(c.msgbuf))) {
    181         if(rtosc_type(c.msgbuf, 0) == 's')
    182             return rtosc_argument(c.msgbuf,0).s;
    183     }
    184 
    185     return "";
    186 }
    187 
    188 template <>
    189 void *capture(Master *m, std::string url)
    190 {
    191     Capture c(m);
    192     char query[1024];
    193     rtosc_message(query, 1024, url.c_str(), "");
    194     Master::ports.dispatch(query+1,c);
    195     if(rtosc_message_length(c.msgbuf, sizeof(c.msgbuf))) {
    196         if(rtosc_type(c.msgbuf, 0) == 'b' &&
    197                 rtosc_argument(c.msgbuf, 0).b.len == sizeof(void*))
    198             return *(void**)rtosc_argument(c.msgbuf,0).b.data;
    199     }
    200 
    201     return NULL;
    202 }
    203 
    204 template<class T>
    205 std::string doCopy(MiddleWare &mw, string url, string name)
    206 {
    207     mw.doReadOnlyOp([url, name, &mw](){
    208         Master *m = mw.spawnMaster();
    209         //Get the pointer
    210         T *t = (T*)capture<void*>(m, url+"self");
    211         assert(t);
    212         //Extract Via mxml
    213         t->copy(mw.getPresetsStore(), name.empty()? NULL:name.c_str());
    214     });
    215 
    216     return "";
    217 }
    218 
    219 template<class T, typename... Ts>
    220 void doPaste(MiddleWare &mw, string url, string type, XMLwrapper &xml, Ts&&... args)
    221 {
    222     //Generate a new object
    223     T *t = new T(std::forward<Ts>(args)...);
    224 
    225     //Old workaround for LFO parameters
    226     if(strstr(type.c_str(), "Plfo"))
    227         type = "Plfo";
    228 
    229     if(xml.enterbranch(type) == 0)
    230     {
    231         delete t;
    232         return;
    233     }
    234 
    235     t->getfromXML(xml);
    236 
    237     //Send the pointer
    238     string path = url+"paste";
    239     char buffer[1024];
    240     rtosc_message(buffer, 1024, path.c_str(), "b", sizeof(void*), &t);
    241     if(!Master::ports.apropos(path.c_str()))
    242         fprintf(stderr, "Warning: Missing Paste URL: '%s'\n", path.c_str());
    243     //printf("Sending info to '%s'\n", buffer);
    244     mw.transmitMsg(buffer);
    245 
    246     //Let the pointer be reclaimed later
    247 }
    248 
    249 template<class T>
    250 std::string doArrayCopy(MiddleWare &mw, int field, string url, string name)
    251 {
    252     //printf("Getting info from '%s'<%d>\n", url.c_str(), field);
    253     mw.doReadOnlyOp([url, field, name, &mw](){
    254         Master *m = mw.spawnMaster();
    255         //Get the pointer
    256         T *t = (T*)capture<void*>(m, url+"self");
    257         //Extract Via mxml
    258         t->copy(mw.getPresetsStore(), field, name.empty()?NULL:name.c_str());
    259     });
    260 
    261     return "";
    262 }
    263 
    264 template<class T, typename... Ts>
    265 void doArrayPaste(MiddleWare &mw, int field, string url, string type,
    266         XMLwrapper &xml, Ts&&... args)
    267 {
    268     //Generate a new object
    269     T *t = new T(std::forward<Ts>(args)...);
    270 
    271     if(xml.enterbranch(type+"n") == 0) {
    272         delete t;
    273         return;
    274     }
    275     t->defaults(field);
    276     t->getfromXMLsection(xml, field);
    277     xml.exitbranch();
    278 
    279     //Send the pointer
    280     string path = url+"paste-array";
    281     char buffer[1024];
    282     rtosc_message(buffer, 1024, path.c_str(), "bi", sizeof(void*), &t, field);
    283     if(!Master::ports.apropos(path.c_str()))
    284         fprintf(stderr, "Warning: Missing Paste URL: '%s'\n", path.c_str());
    285     //printf("Sending info to '%s'<%d>\n", buffer, field);
    286     mw.transmitMsg(buffer);
    287 
    288     //Let the pointer be reclaimed later
    289 }
    290 
    291 /*
    292  * Dispatch to class specific operators
    293  *
    294  * Oscilgen and PADnoteParameters have mixed RT/non-RT parameters and require
    295  * extra handling.
    296  * See MiddleWare.cpp for these specifics
    297  */
    298 void doClassPaste(std::string type, std::string type_, MiddleWare &mw, string url, XMLwrapper &data)
    299 {
    300     //printf("Class Paste\n");
    301     if(type == "EnvelopeParams")
    302         doPaste<EnvelopeParams>(mw, url, type_, data);
    303     else if(type == "LFOParams")
    304         doPaste<LFOParams>(mw, url, type_, data);
    305     else if(type == "FilterParams")
    306         doPaste<FilterParams>(mw, url, type_, data);
    307     else if(type == "ADnoteParameters")
    308         doPaste<ADnoteParameters>(mw, url, type_, data, mw.getSynth(), (FFTwrapper*)NULL);
    309     else if(type == "PADnoteParameters")
    310         doPaste<PADnoteParameters>(mw, url, type_, data, mw.getSynth(), (FFTwrapper*)NULL);
    311     else if(type == "SUBnoteParameters")
    312         doPaste<SUBnoteParameters>(mw, url, type_, data);
    313     else if(type == "OscilGen")
    314         doPaste<OscilGen>(mw, url, type_, data, mw.getSynth(), (FFTwrapper*)NULL, (Resonance*)NULL);
    315     else if(type == "Resonance")
    316         doPaste<Resonance>(mw, url, type_, data);
    317     else if(type == "EffectMgr")
    318         doPaste<EffectMgr>(mw, url, type_, data, DummyAlloc, mw.getSynth(), false);
    319     else {
    320         fprintf(stderr, "Warning: Unknown type<%s> from url<%s>\n", type.c_str(), url.c_str());
    321     }
    322 }
    323 
    324 std::string doClassCopy(std::string type, MiddleWare &mw, string url, string name)
    325 {
    326     //printf("doClassCopy(%p)\n", mw.spawnMaster()->uToB);
    327     if(type == "EnvelopeParams")
    328         return doCopy<EnvelopeParams>(mw, url, name);
    329     else if(type == "LFOParams")
    330         return doCopy<LFOParams>(mw, url, name);
    331     else if(type == "FilterParams")
    332         return doCopy<FilterParams>(mw, url, name);
    333     else if(type == "ADnoteParameters")
    334         return doCopy<ADnoteParameters>(mw, url, name);
    335     else if(type == "PADnoteParameters")
    336         return doCopy<PADnoteParameters>(mw, url, name);
    337     else if(type == "SUBnoteParameters")
    338         return doCopy<SUBnoteParameters>(mw, url, name);
    339     else if(type == "OscilGen")
    340         return doCopy<OscilGen>(mw, url, name);
    341     else if(type == "Resonance")
    342         return doCopy<Resonance>(mw, url, name);
    343     else if(type == "EffectMgr")
    344         doCopy<EffectMgr>(mw, url, name);
    345     return "UNDEF";
    346 }
    347 
    348 void doClassArrayPaste(std::string type, std::string type_, int field, MiddleWare &mw, string url,
    349         XMLwrapper &data)
    350 {
    351     if(type == "FilterParams")
    352         doArrayPaste<FilterParams>(mw, field, url, type_, data);
    353     else if(type == "ADnoteParameters")
    354         doArrayPaste<ADnoteParameters>(mw, field, url, type_, data, mw.getSynth(), (FFTwrapper*)NULL);
    355 }
    356 
    357 std::string doClassArrayCopy(std::string type, int field, MiddleWare &mw, string url, string name)
    358 {
    359     if(type == "FilterParams")
    360         return doArrayCopy<FilterParams>(mw, field, url, name);
    361     else if(type == "ADnoteParameters")
    362         return doArrayCopy<ADnoteParameters>(mw, field, url, name);
    363     return "UNDEF";
    364 }
    365 
    366 //This is an abuse of the readonly op, but one that might look reasonable from a
    367 //user perspective...
    368 std::string getUrlPresetType(std::string url, MiddleWare &mw)
    369 {
    370     std::string result;
    371     mw.doReadOnlyOp([url, &result, &mw](){
    372         Master *m = mw.spawnMaster();
    373         //Get the pointer
    374         result = capture<std::string>(m, url+"preset-type");
    375     });
    376     //printf("preset type = %s\n", result.c_str());
    377     return result;
    378 }
    379 
    380 std::string getUrlType(std::string url)
    381 {
    382     assert(!url.empty());
    383     //printf("Searching for '%s'\n", (url+"self").c_str());
    384     auto self = Master::ports.apropos((url+"self").c_str());
    385     if(!self)
    386         fprintf(stderr, "Warning: URL Metadata Not Found For '%s'\n", url.c_str());
    387 
    388     if(self)
    389         return self->meta()["class"];
    390     else
    391         return "";
    392 }
    393 
    394 
    395 /*****************************************************************************
    396  *                            API Stubs                                      *
    397  *****************************************************************************/
    398 
    399 #if 0
    400 Clipboard clipboardCopy(MiddleWare &mw, string url)
    401 {
    402     //Identify The Self Type of the Object
    403     string type = getUrlType(url);
    404     printf("Copying a '%s' object", type.c_str());
    405 
    406     //Copy The Object
    407     string data = doClassCopy(type, mw, url);
    408     printf("Object Information '%s'\n", data.c_str());
    409 
    410     return {type, data};
    411 }
    412 
    413 void clipBoardPaste(const char *url, Clipboard clip)
    414 {
    415     (void) url;
    416     (void) clip;
    417 }
    418 #endif
    419 
    420 void presetCopy(MiddleWare &mw, std::string url, std::string name)
    421 {
    422     (void) name;
    423     doClassCopy(getUrlType(url), mw, url, name);
    424     //printf("PresetCopy()\n");
    425 }
    426 void presetPaste(MiddleWare &mw, std::string url, std::string name)
    427 {
    428     (void) name;
    429     //printf("PresetPaste()\n");
    430     string data = "";
    431     XMLwrapper xml;
    432     if(name.empty()) {
    433         data = mw.getPresetsStore().clipboard.data;
    434         if(data.length() < 20)
    435             return;
    436         if(!xml.putXMLdata(data.c_str()))
    437             return;
    438     } else {
    439         if(xml.loadXMLfile(name))
    440             return;
    441     }
    442 
    443     doClassPaste(getUrlType(url), getUrlPresetType(url, mw), mw, url, xml);
    444 }
    445 void presetCopyArray(MiddleWare &mw, std::string url, int field, std::string name)
    446 {
    447     (void) name;
    448     //printf("PresetArrayCopy()\n");
    449     doClassArrayCopy(getUrlType(url), field, mw, url, name);
    450 }
    451 void presetPasteArray(MiddleWare &mw, std::string url, int field, std::string name)
    452 {
    453     (void) name;
    454     //printf("PresetArrayPaste()\n");
    455     string data = "";
    456     XMLwrapper xml;
    457     if(name.empty()) {
    458         data = mw.getPresetsStore().clipboard.data;
    459         if(data.length() < 20)
    460             return;
    461         if(!xml.putXMLdata(data.c_str()))
    462             return;
    463     } else {
    464         if(xml.loadXMLfile(name))
    465             return;
    466     }
    467     //printf("Performing Paste...\n");
    468     doClassArrayPaste(getUrlType(url), getUrlPresetType(url, mw), field, mw, url, xml);
    469 }
    470 #if 0
    471 void presetPaste(std::string url, int)
    472 {
    473     printf("PresetPaste()\n");
    474     doClassPaste(getUrlType(url), *middlewarepointer, url, presetsstore.clipboard.data);
    475 }
    476 #endif
    477 void presetDelete(int)
    478 {
    479     printf("PresetDelete()<UNIMPLEMENTED>\n");
    480 }
    481 void presetRescan()
    482 {
    483     printf("PresetRescan()<UNIMPLEMENTED>\n");
    484 }
    485 std::string presetClipboardType()
    486 {
    487     printf("PresetClipboardType()<UNIMPLEMENTED>\n");
    488     return "dummy";
    489 }
    490 bool presetCheckClipboardType()
    491 {
    492     printf("PresetCheckClipboardType()<UNIMPLEMENTED>\n");
    493     return true;
    494 }
    495 
    496 }