zynaddsubfx

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

commit 2835ac7ce79625d8d661a60a16b83a71e3f58ddf
parent e1a3d3a2e664f600ffa3aac5d1f589a26b0ef3db
Author: fundamental <[email protected]>
Date:   Sat, 17 Aug 2013 00:09:25 -0400

Fix Program Change Instrument Swapping

While the UI is still not quite right on some things parts could
previously be loaded from the BankUI without blocking. This
commit redirects program change events into the same code. Now
where program changes would previously zombify the system, loads
are done in the background. Tested with period sizes 32, 64, &
128 at 48kHz, so this appears to work quite well though one
segfault appears to exist when loading an instrument from the
'Collection' bank.

- Disable Debug Prints
- Add UI Refresh on Part Change
- Add Poly/Mono/Legato Selector On PartUI
- Redirect Program Change Events Through MiddleWare

Diffstat:
Msrc/Misc/Bank.cpp | 4++--
Msrc/Misc/Master.cpp | 11+++++------
Msrc/Misc/MiddleWare.cpp | 112++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/Misc/Part.cpp | 22++++++++++++++++++++++
Msrc/Nio/InMgr.cpp | 5++++-
Msrc/Params/ADnoteParameters.cpp | 2+-
Msrc/UI/Fl_Osc_Check.H | 1-
Msrc/UI/Fl_Osc_Check.cpp | 3---
Msrc/UI/Fl_Osc_Interface.h | 3+++
Msrc/UI/Fl_Osc_Widget.H | 3+++
Msrc/UI/Fl_Osc_Widget.cpp | 5+++++
Msrc/UI/Fl_Oscilloscope.h | 1-
Msrc/UI/PartUI.fl | 18++++++++----------
13 files changed, 116 insertions(+), 74 deletions(-)

diff --git a/src/Misc/Bank.cpp b/src/Misc/Bank.cpp @@ -102,7 +102,7 @@ void Bank::setname(unsigned int ninstrument, const string &newname, int newslot) if(tmpfilename[i] == ' ') tmpfilename[i] = '0'; - newfilename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz"; + newfilename = dirname + legalizeFilename(tmpfilename) + ".xiz"; rename(ins[ninstrument].filename.c_str(), newfilename.c_str()); @@ -427,7 +427,7 @@ int Bank::addtobank(int pos, string filename, string name) deletefrombank(pos); ins[pos].name = name; - ins[pos].filename = dirname + '/' + filename; + ins[pos].filename = dirname + filename; return 0; } diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -129,7 +129,6 @@ class DataObj:public rtosc::RtData va_start(va,args); char *buffer = bToU->buffer(); rtosc_vmessage(buffer,bToU->buffer_size(),path,args,va); - printf("sending reply of '%s'\n", buffer); reply(buffer); } virtual void reply(const char *msg) @@ -141,7 +140,6 @@ class DataObj:public rtosc::RtData va_start(va,args); char *buffer = bToU->buffer(); rtosc_vmessage(buffer,bToU->buffer_size(),path,args,va); - printf("sending reply of '%s'\n\n", buffer); reply(buffer);} virtual void broadcast(const char *msg) override{reply(msg);}; private: @@ -412,7 +410,7 @@ void Master::AudioOut(float *outl, float *outr) DataObj d{loc_buf, 1024, this, bToU}; memset(loc_buf, sizeof(loc_buf), 0); int events = 0; - while(uToB->hasNext()) { + while(uToB->hasNext() && events < 10) { const char *msg = uToB->read(); if(!strcmp(msg, "/load-master")) { @@ -425,7 +423,7 @@ void Master::AudioOut(float *outl, float *outr) } //XXX yes, this is not realtime safe, but it is useful... - if(strcmp(msg, "/get-vu")) { + 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)); @@ -435,14 +433,15 @@ void Master::AudioOut(float *outl, float *outr) //fprintf(stdout, "address '%s'\n", uToB->peak()); ports.dispatch(msg+1, d); events++; - if(!d.matches) { + if(!d.matches && false) { fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); fprintf(stderr, "Unknown address '%s'\n", uToB->peak()); fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } } - if(events>1) + if(events>1 && false) fprintf(stderr, "backend: %d events per cycle\n",events); + //Swaps the Left channel with Right Channel if(swaplr) diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -150,30 +150,6 @@ void deallocate(const char *str, void *v) */ void osc_check(cb_t cb, void *ui) { - lo_server_recv_noblock(server, 0); - while(bToU->hasNext()) { - const char *rtmsg = bToU->read(); - //printf("return: got a '%s'\n", rtmsg); - if(!strcmp(rtmsg, "/echo") - && !strcmp(rtosc_argument_string(rtmsg),"ss") - && !strcmp(rtosc_argument(rtmsg,0).s, "OSC_URL")) - curr_url = rtosc_argument(rtmsg,1).s; - else if(!strcmp(rtmsg, "/free") - && !strcmp(rtosc_argument_string(rtmsg),"sb")) { - deallocate(rtosc_argument(rtmsg, 0).s, *((void**)rtosc_argument(rtmsg, 1).b.data)); - } else if(curr_url == "GUI") { - cb(ui, rtmsg); //GUI::raiseUi(gui, bToU->read()); - } else{ - lo_message msg = lo_message_deserialise((void*)rtmsg, - rtosc_message_length(rtmsg, bToU->buffer_size()), NULL); - - //Send to known url - if(!curr_url.empty()) { - lo_address addr = lo_address_new_from_url(curr_url.c_str()); - lo_send_message(addr, rtmsg, msg); - } - } - } } @@ -352,7 +328,7 @@ struct MiddleWareImpl for(int k=0; k<NUM_VOICES; ++k) { objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = master->part[i]->kit[j].adpars->VoicePar[k].OscilSmp; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil-mod/"] = + objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = master->part[i]->kit[j].adpars->VoicePar[k].FMSmp; } } @@ -369,14 +345,15 @@ struct MiddleWareImpl void warnMemoryLeaks(void); - void loadPart(const char *msg, Master *master) + void loadPart(int npart, const char *filename, Master *master, Fl_Osc_Interface *osc) { - fprintf(stderr, "loading a part!!\n"); + //fprintf(stderr, "loading a part!!\n"); //Load the part Part *p = new Part(&master->microtonal, master->fft); - unsigned npart = rtosc_argument(msg, 0).i; - fprintf(stderr, "Part is stored in '%s'\n", rtosc_argument(msg, 1).s); - p->loadXMLinstrument(rtosc_argument(msg, 1).s); + //fprintf(stderr, "Part[%d] is stored in '%s'\n", npart, filename); + if(p->loadXMLinstrument(filename)) + fprintf(stderr, "FAILED TO LOAD PART!!\n"); + p->applyparameters(); //Update the resource locators @@ -389,7 +366,7 @@ struct MiddleWareImpl for(int k=0; k<NUM_VOICES; ++k) { objmap[base+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = p->kit[j].adpars->VoicePar[k].OscilSmp; - objmap[base+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil-mod/"] = + objmap[base+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = p->kit[j].adpars->VoicePar[k].FMSmp; } } @@ -398,6 +375,7 @@ struct MiddleWareImpl //deallocation //printf("writing something to the location called '%s'\n", msg); uToB->write("/load-part", "ib", npart, sizeof(Part*), &p); + osc->damage(("/part"+to_s(npart)+"/").c_str()); } //Well, you don't get much crazier than changing out all of your RT @@ -419,7 +397,7 @@ struct MiddleWareImpl for(int k=0; k<NUM_VOICES; ++k) { objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = m->part[i]->kit[j].adpars->VoicePar[k].OscilSmp; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil-mod/"] = + objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = m->part[i]->kit[j].adpars->VoicePar[k].FMSmp; } } @@ -435,7 +413,33 @@ struct MiddleWareImpl void tick(void) { - osc_check(cb, ui); + lo_server_recv_noblock(server, 0); + while(bToU->hasNext()) { + const char *rtmsg = bToU->read(); + //printf("return: got a '%s'\n", rtmsg); + if(!strcmp(rtmsg, "/echo") + && !strcmp(rtosc_argument_string(rtmsg),"ss") + && !strcmp(rtosc_argument(rtmsg,0).s, "OSC_URL")) + curr_url = rtosc_argument(rtmsg,1).s; + else if(!strcmp(rtmsg, "/free") + && !strcmp(rtosc_argument_string(rtmsg),"sb")) { + deallocate(rtosc_argument(rtmsg, 0).s, *((void**)rtosc_argument(rtmsg, 1).b.data)); + } 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); + } else if(curr_url == "GUI") { + cb(ui, rtmsg); //GUI::raiseUi(gui, bToU->read()); + } else{ + lo_message msg = lo_message_deserialise((void*)rtmsg, + rtosc_message_length(rtmsg, bToU->buffer_size()), NULL); + + //Send to known url + if(!curr_url.empty()) { + lo_address addr = lo_address_new_from_url(curr_url.c_str()); + lo_send_message(addr, rtmsg, msg); + } + } + } } bool handlePAD(string path, const char *msg, void *v) @@ -455,10 +459,10 @@ struct MiddleWareImpl PADnoteParameters::ports.dispatch(msg, d); if(!d.matches) { - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); - fprintf(stderr, "Unknown location '%s%s'<%s>\n", - path.c_str(), msg, rtosc_argument_string(msg)); - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); + //fprintf(stderr, "Unknown location '%s%s'<%s>\n", + // path.c_str(), msg, rtosc_argument_string(msg)); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } return true; @@ -481,10 +485,10 @@ struct MiddleWareImpl OscilGen::ports.dispatch(msg, d); if(!d.matches) { - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); - fprintf(stderr, "Unknown location '%s%s'<%s>\n", - path.c_str(), msg, rtosc_argument_string(msg)); - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); + //fprintf(stderr, "Unknown location '%s%s'<%s>\n", + // path.c_str(), msg, rtosc_argument_string(msg)); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } return true; @@ -538,10 +542,10 @@ struct MiddleWareImpl uToB->raw_write(msg); } else //just forward the message uToB->raw_write(msg); - } else if(strstr(msg, "load_xmz")) { + } else if(strstr(msg, "load_xmz") && !strcmp(rtosc_argument_string(msg), "s")) { loadMaster(rtosc_argument(msg,0).s); - } else if(strstr(msg, "load-part")) - loadPart(msg, master); + } else if(strstr(msg, "load-part") && !strcmp(rtosc_argument_string(msg), "is")) + loadPart(rtosc_argument(msg,0).i, rtosc_argument(msg,1).s, master, osc); else uToB->raw_write(msg); } @@ -698,12 +702,22 @@ class UI_Interface:public Fl_Osc_Interface } } + //A very simplistic implementation of a UI agnostic refresh method + virtual void damage(const char *path) + { + for(auto pair:map) { + if(strstr(pair.first.c_str(), path)) { + pair.second->update(); + } + } + } + void tryLink(const char *msg) override { //DEBUG - //if(strcmp(msg, "/vu-meter"))//Ignore repeated message - // printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); + if(strcmp(msg, "/vu-meter"))//Ignore repeated message + printf("trying the link for a '%s'<%s>\n", msg, rtosc_argument_string(msg)); const char *handle = rindex(msg,'/'); if(handle) ++handle; @@ -745,9 +759,9 @@ class UI_Interface:public Fl_Osc_Interface && strcmp(msg, "undo_change") && !strstr(msg, "parameter") && !strstr(msg, "Prespoint")) { - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); - fprintf(stderr, "Unknown widget '%s'\n", msg); - fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); + //fprintf(stderr, "Unknown widget '%s'\n", msg); + //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } }; diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -69,6 +69,28 @@ static Ports partPorts = { {Part *p = (Part*)r.obj; p->Pminkey = p->lastnote;}}, {"captureMax:", NULL, NULL, [](const char *, RtData &r) {Part *p = (Part*)r.obj; p->Pmaxkey = p->lastnote;}}, + {"polyType::c:i", NULL, NULL, [](const char *msg, RtData &d) + { + Part *p = (Part*)d.obj; + if(!rtosc_narguments(msg)) { + int res = 0; + if(!p->Ppolymode) + res = p->Plegatomode ? 2 : 1; + d.reply(d.loc, "c", res); + return; + } + + int i = rtosc_argument(msg, 0).i; + if(i == 0) { + p->Ppolymode = 1; + p->Plegatomode = 0; + } else if(i==1) { + p->Ppolymode = 0; + p->Plegatomode = 0; + } else { + p->Ppolymode = 0; + p->Plegatomode = 1; + }}}, //{"kit#16::T:F", "::Enables or disables kit item", 0, // [](const char *m, RtData &d) { diff --git a/src/Nio/InMgr.cpp b/src/Nio/InMgr.cpp @@ -2,6 +2,7 @@ #include "MidiIn.h" #include "EngineMgr.h" #include "../Misc/Master.h" +#include <rtosc/thread-link.h> #include <iostream> using namespace std; @@ -84,8 +85,10 @@ void InMgr::flush() break; case M_PGMCHANGE: - master->setProgram(ev.channel, ev.num); + //FIXME channel is only interpreted as part number here + bToU->write("/setprogram", "cc", ev.channel, ev.num); break; + case M_PRESSURE: master->polyphonicAftertouch(ev.channel, ev.num, ev.value); break; diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -94,7 +94,7 @@ static Ports voicePorts = { //Modulator Stuff - rToggle(PFMEnabled, "Modulator Enable"), + rParam(PFMEnabled, "Modulator Enable/Type"), rParamI(PFMVoice, "Modulator Oscillator Selection"), rParam(PFMVolume, "Modulator Magnitude"), rParam(PFMVolumeDamp, "Modulator HF dampening"), diff --git a/src/UI/Fl_Osc_Check.H b/src/UI/Fl_Osc_Check.H @@ -18,7 +18,6 @@ class Fl_Osc_Check:public Fl_Check_Button, public Fl_Osc_Widget using Fl_Osc_Widget::OSC_value; void init(std::string loc, char type = 'T'); - void update(void); void callback(Fl_Callback *cb, void *p = NULL); void cb(void); static void _cb(Fl_Widget *w, void *); diff --git a/src/UI/Fl_Osc_Check.cpp b/src/UI/Fl_Osc_Check.cpp @@ -46,9 +46,6 @@ void Fl_Osc_Check::cb(void) oscWrite(ext, "c", value()); } -void Fl_Osc_Check::update(void) -{} - void Fl_Osc_Check::callback(Fl_Callback *cb, void *p) { cb_data.first = cb; diff --git a/src/UI/Fl_Osc_Interface.h b/src/UI/Fl_Osc_Interface.h @@ -17,6 +17,9 @@ class Fl_Osc_Interface //and to be able to give them events virtual void tryLink(const char *){}; + //Damage the values of a collection of widgets + virtual void damage(const char*){}; + //Communication link virtual void requestValue(string s) { printf("request: '%s'...\n", s.c_str()); }; virtual void writeValue(string s, float f){printf("%s -> %f\n",s.c_str(), f); }; diff --git a/src/UI/Fl_Osc_Widget.H b/src/UI/Fl_Osc_Widget.H @@ -38,6 +38,9 @@ class Fl_Osc_Widget void oscWrite(std::string path); void oscRegister(const char *path); + //Forces an update of parameters as they have become stale somehow + virtual void update(void); + //Smoothly change the base path virtual void rebase(std::string new_base); void oscMove(std::string new_ext); diff --git a/src/UI/Fl_Osc_Widget.cpp b/src/UI/Fl_Osc_Widget.cpp @@ -76,6 +76,11 @@ void Fl_Osc_Widget::oscRegister(const char *path) osc->requestValue(loc+path); } +void Fl_Osc_Widget::update(void) +{ + osc->requestValue(loc+ext); +} + Fl_Osc_Pane *Fl_Osc_Widget::fetch_osc_pane(Fl_Widget *w) { if(!w) diff --git a/src/UI/Fl_Oscilloscope.h b/src/UI/Fl_Oscilloscope.h @@ -32,7 +32,6 @@ class Fl_Oscilloscope : public Fl_Box, Fl_Osc_Widget void init(bool base_waveform_p) { - fprintf(stderr, "PARENT BASE LEADS TO '%s'\n", loc.c_str()); ext = (base_waveform_p ? "base-waveform": "waveform"); assert(osc); oscRegister(ext.c_str()); diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl @@ -823,8 +823,10 @@ if (x==2) part->partefx[ninseff]->setdryonly(true); } Fl_Check_Button padsynenabledcheck { label Enabled - callback {if (o->value()==0) padeditbutton->deactivate(); - else padeditbutton->activate();} + callback {if (o->value()==0){ delete padnoteui; padnoteui = NULL; padeditbutton->deactivate();} +else { + padnoteui=new PADnoteUI(loc+"kit0/padpars/", osc); + padeditbutton->activate();}} tooltip {enable/disable PADsynth} xywh {215 255 80 20} box UP_BOX down_box DOWN_BOX color 51 selection_color 51 labelfont 1 labelsize 11 code1 {o->init("Ppadenabled");} class Fl_Osc_Check @@ -1034,8 +1036,7 @@ keylimitlist->value(val);} {} if (kititem!=lastkititem){ delete adnoteui; delete subnoteui; - delete padnoteui; - adnoteui=NULL;subnoteui=NULL;padnoteui=NULL; + adnoteui=NULL;subnoteui=NULL; lastkititem=kititem; if(kititem>=NUM_KIT_ITEMS) return;//bad kit item @@ -1046,16 +1047,13 @@ if (kititem!=lastkititem){ if(subsynenabledcheck->value()) subnoteui=new SUBnoteUI(osc, loc+"kit"+to_s(kititem)+"/subpars/"); - - if(padsynenabledcheck->value()) - padnoteui=new PADnoteUI(loc+"kit"+to_s(kititem)+"/padpars/", osc); }; -if ((engine==0)&&(adnoteui!=NULL)) adnoteui->ADnoteGlobalParameters->show(); -if ((engine==1)&&(subnoteui!=NULL)) subnoteui->SUBparameters->show(); -if ((engine==2)&&(adnoteui!=NULL)) padnoteui->padnotewindow->show();} {} +if ((engine==0)&&adnoteui) adnoteui->ADnoteGlobalParameters->show(); +if ((engine==1)&&subnoteui) subnoteui->SUBparameters->show(); +if ((engine==2)&&padnoteui) padnoteui->padnotewindow->show();} {} } Function {~PartUI()} {} { code {delete adnoteui;