commit 1d6349314c26c044c09fde756d04bbaab6857a8a
parent ca158d3535d383309ad733534a91607ed6f34b30
Author: fundamental <mark.d.mccurry@gmail.com>
Date: Wed, 29 Apr 2015 16:19:26 -0400
Enable External UI Support
This adds support for an external UI with zero access to the core access.
All access is done through OSC messages which can be either on a local or remote
machine, though there may be some minor cases where they depend on struct
packing due to shoving stuff into blobs.
There doesn't seem to be any lag given that both sides consume all events when
they check for them and when running with a large amount of latency elements
still appear to be correct in the end.
This does add some regressions in the controls which did depend upon direct
access, such as the ConfigUI, PresetUI, and NioUI, however those should be fixed
to use the OSC API anyhow. Some new widget types will be made for these cases
and the vision of everything over OSC will be obtained.
Diffstat:
23 files changed, 811 insertions(+), 237 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -312,8 +312,7 @@ if(NOT FltkGui AND NOT NtkGui)
if(LibloEnable)
set(NSM_WORKAROUND UI/NSM.C UI/NSM/Client.C)
endif()
- add_library(zynaddsubfx_gui_dummy STATIC UI/ConnectionDummy.cpp ${NSM_WORKAROUND})
- set(GUI_LIBRARIES zynaddsubfx_gui_dummy)
+ add_library(zynaddsubfx_gui_bridge STATIC UI/ConnectionDummy.cpp ${NSM_WORKAROUND})
add_definitions(-DNO_UI=1)
endif()
@@ -375,6 +374,7 @@ add_executable(zynaddsubfx main.cpp)
target_link_libraries(zynaddsubfx
zynaddsubfx_core
zynaddsubfx_nio
+ zynaddsubfx_gui_bridge
${GUI_LIBRARIES}
${NIO_LIBRARIES}
${AUDIO_LIBRARIES}
diff --git a/src/Misc/Config.cpp b/src/Misc/Config.cpp
@@ -19,19 +19,58 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <rtosc/ports.h>
+#include <rtosc/port-sugar.h>
#include "Config.h"
#include "XMLwrapper.h"
-using namespace std;
+#define rStdString(name, len, ...) \
+ {STRINGIFY(name) "::s", rMap(length, len) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}
+#define rStdStringCb(name, length) rBOIL_BEGIN \
+ if(!strcmp("", args)) {\
+ data.reply(loc, "s", obj->name); \
+ } else { \
+ strncpy(obj->name, rtosc_argument(msg, 0).s, length); \
+ data.broadcast(loc, "s", obj->name);\
+ rChangeCb \
+ } rBOIL_END
+
+
+
+
+#if 0
+#define rObject Config
+rtosc::Ports port = {
+ rString(cfg.LinuxOSSWaveOutDev),
+ rString(cfg.LinuxOSSSeqInDev),
+ rParamI(cfg.SampleRate),
+ rParamI(cfg.SoundBufferSize),
+ rParamI(cfg.OscilSize),
+ rToggle(cfg.SwapStereo),
+ rToggle(cfg.BankUIAutoClose),
+ rParamI(cfg.GzipCompression),
+ rParamI(cfg.Interpolation),
+ rArrayS(cfg.bankRootDirList,MAX_BANK_ROOT_DIRS),
+ rString(cfg.currentBankDir),
+ rArrayS(cfg.presetsDirList,MAX_BANK_ROOT_DIRS),
+ rToggle(cfg.CheckPADsynth),
+ rToggle(cfg.IgnoreProgramChange),
+ rParamI(cfg.UserInterfaceMode),
+ rParamI(cfg.VirKeybLayout),
+ rParamS(cfg.LinuxALSAaudioDev),
+ rParamS(cfg.nameTag)
+};
+#endif
Config::Config()
{}
+
void Config::init()
{
maxstringsize = MAX_STRING_SIZE; //for ui
diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp
@@ -607,7 +607,7 @@ void Master::AudioOut(float *outl, float *outr)
}
//XXX yes, this is not realtime safe, but it is useful...
- if(strcmp(msg, "/get-vu") && false) {
+ if(strcmp(msg, "/get-vu") && true) {
fprintf(stdout, "%c[%d;%d;%dm", 0x1B, 0, 5 + 30, 0 + 40);
fprintf(stdout, "backend[%d]: '%s'<%s>\n", msg_id++, msg,
rtosc_argument_string(msg));
diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp
@@ -126,6 +126,7 @@ static int handler_function(const char *path, const char *types, lo_arg **argv,
memset(buffer, 0, sizeof(buffer));
size_t size = 2048;
lo_message_serialise(msg, path, buffer, &size);
+ printf("Liblo<%s>\n", buffer);
if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) {
path_search(buffer, mw->activeUrl().c_str());
} else
@@ -686,7 +687,7 @@ public:
void tick(void)
{
- lo_server_recv_noblock(server, 0);
+ while(lo_server_recv_noblock(server, 0));
while(bToU->hasNext()) {
const char *rtmsg = bToU->read();
bToUhandle(rtmsg);
@@ -789,6 +790,11 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw)
//Grab objects of interest from master
obj_store.extractMaster(master);
+ //Load Part Status
+ for(int i=0; i < NUM_MIDI_PARTS; ++i) {
+ kits.extractPart(master->part[i], i);
+ }
+
//Null out Load IDs
for(int i=0; i < NUM_MIDI_PARTS; ++i) {
pending_load[i] = 0;
@@ -993,11 +999,13 @@ void MiddleWareImpl::kitEnable(const char *msg)
type = 1;
else if(strstr(msg, "Psubenabled"))
type = 2;
+ printf("type='%d'\n", type);
if(type == -1)
return;
const char *tmp = strstr(msg, "part");
+ printf("part='%s'\n", tmp);
if(tmp == NULL)
return;
@@ -1005,6 +1013,7 @@ void MiddleWareImpl::kitEnable(const char *msg)
const int part = atoi(tmp+4);
tmp = strstr(msg, "kit");
+ printf("kit='%s'\n", tmp);
if(tmp == NULL)
return;
@@ -1016,7 +1025,7 @@ void MiddleWareImpl::kitEnable(const char *msg)
void MiddleWareImpl::kitEnable(int part, int kit, int type)
{
- // printf("attempting a kit enable\n");
+ printf("attempting a kit enable<%d,%d,%d>\n", part, kit, type);
string url = "/part"+to_s(part)+"/kit"+to_s(kit)+"/";
void *ptr = NULL;
if(type == 0 && kits.add[part][kit] == NULL) {
diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt
@@ -33,6 +33,7 @@ target_link_libraries(XMLwrapperTest ${test_lib})
target_link_libraries(RandTest ${test_lib})
target_link_libraries(PADnoteTest ${test_lib})
target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio
+ zynaddsubfx_gui_bridge
${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES})
target_link_libraries(UnisonTest ${test_lib})
#target_link_libraries(RtAllocTest ${test_lib})
diff --git a/src/UI/BankUI.fl b/src/UI/BankUI.fl
@@ -26,6 +26,9 @@ decl {\#include <FL/Fl_File_Chooser.H>} {public local
decl {\#include "Fl_Osc_Interface.h"} {public local
}
+decl {\#include "Fl_Osc_Check.H"} {public local
+}
+
decl {\#include "../Misc/Util.h"} {public local
}
@@ -76,9 +79,9 @@ refreshmainwindow();}
}
Fl_Check_Button {} {
label {auto close}
- callback {config.cfg.BankUIAutoClose=(int) o->value();}
tooltip {automatically close the bank window if the instrument is loaded} xywh {705 529 60 15} down_box DOWN_BOX labelsize 10
- code0 {o->value(config.cfg.BankUIAutoClose);}
+ code0 {o->init("cfg.BankUIAutoClose");}
+ class Fl_Osc_Check
}
Fl_Choice banklist {
callback {refreshmainwindow();}
@@ -109,8 +112,7 @@ delete bankuiwindow;} {}
}
Function {show()} {open
} {
- code {bankuiwindow->show();
-simplesetmode(config.cfg.UserInterfaceMode==2);} {}
+ code {bankuiwindow->show();} {}
}
Function {hide()} {open
} {
@@ -128,27 +130,16 @@ rescan_for_banks();} {}
}
Function {refreshmainwindow()} {open
} {
- code {/*bankuiwindow->label(bank->bankfiletitle.c_str());*/
+ code {
bankview->refresh();} {}
}
Function {rescan_for_banks()} {open
} {
code {banklist->clear();
osc->write("/rescanforbanks");
-
-/*
-for (unsigned int i=0;i<bank->banks.size();i++) {
- banklist->add(bank->banks[i].name.c_str());
-}
-*/
if (banklist->size() == 0)
banklist->add(" ");} {}
}
- Function {simplesetmode(bool beginnerui)} {open
- } {
- code {if (beginnerui) modeselect->hide();
- else modeselect->show();} {}
- }
decl {Fl_Osc_Interface *osc;} {private local
}
decl {Fl_Valuator *cbwig;} {public local
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
@@ -30,6 +30,12 @@ if(NtkGui)
add_definitions(-DSOURCE_DIR="${CMAKE_SOURCE_DIR}")
endif()
+if(FltkGui)
+ add_executable(zynaddsubfx_ext_gui guimain.cpp)
+ target_link_libraries(zynaddsubfx_ext_gui zynaddsubfx_gui ${FLTK_LIBRARIES}
+ ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${LIBLO_LIBRARIES} rtosc rtosc-cpp)
+endif()
+
add_library(zynaddsubfx_gui STATIC
${UI_objs}
${zynaddsubfx_gui_FLTK_UI_SRCS}
@@ -55,8 +61,9 @@ add_library(zynaddsubfx_gui STATIC
FormantFilterGraph.cpp
EnvelopeFreeEdit.cpp
BankView.cpp
- Connection.cpp
)
+add_library(zynaddsubfx_gui_bridge STATIC
+ Connection.cpp)
if(NtkGui)
target_link_libraries(zynaddsubfx_gui ${NTK_LIBRARIES} ${NTK_IMAGES_LIBRARIES})
diff --git a/src/UI/ConfigUI.fl b/src/UI/ConfigUI.fl
@@ -20,6 +20,21 @@ decl {\#include <stdlib.h>} {public local
decl {\#include <FL/Fl_File_Chooser.H>} {public local
}
+decl {\#include "Fl_Osc_Button.H"} {public local
+}
+
+decl {\#include "Fl_Osc_Counter.H"} {public local
+}
+
+decl {\#include "Fl_Osc_Choice.H"} {public local
+}
+
+decl {\#include "Fl_Osc_Check.H"} {public local
+}
+
+decl {\#include "Fl_Osc_Input.H"} {public local
+}
+
decl {\#include "../globals.h"} {public local
}
@@ -33,7 +48,13 @@ class ConfigUI {} {
callback {writebankcfg();
o->hide();}
xywh {554 443 510 370} type Double visible
+ class Fl_Osc_Window
} {
+ Fl_Box dummy {
+ xywh {25 25 25 25}
+ code0 {configwindow->osc = osc;}
+ code1 {configwindow->base = "/";}
+ }
Fl_Tabs {} {
xywh {5 5 500 330}
} {
@@ -45,78 +66,29 @@ o->hide();}
label {Sample Rate}
xywh {15 45 165 30} box ENGRAVED_FRAME
} {
- Fl_Choice {} {
- callback {if ((int)o->value()==0) samplerateinput->activate();
- else samplerateinput->deactivate();
-
-int samplerates[8]={44100,16000,22050,32000,44100,48000,88200,96000};
-config.cfg.SampleRate=samplerates[(int)o->value()];
-
-setsamplerateinput();}
- xywh {20 50 85 20} down_box BORDER_BOX textsize 10
- code0 {o->value(getsamplerateorder());}
- } {
- MenuItem {} {
- label Custom
- xywh {10 10 100 20} labelfont 1
- }
- MenuItem {} {
- label 16000Hz
- xywh {30 30 100 20} labelfont 1
- }
- MenuItem {} {
- label 22050Hz
- xywh {20 20 100 20} labelfont 1
- }
- MenuItem {} {
- label 32000Hz
- xywh {30 30 100 20} labelfont 1
- }
- MenuItem {} {
- label 44100Hz
- xywh {40 40 100 20} labelfont 1
- }
- MenuItem {} {
- label 48000Hz
- xywh {50 50 100 20} labelfont 1
- }
- MenuItem {} {
- label 88200Hz
- xywh {60 60 100 20} labelfont 1
- }
- MenuItem {} {
- label 96000Hz
- xywh {70 70 100 20} labelfont 1
- }
- }
Fl_Input samplerateinput {
- callback {char *tmp;
-config.cfg.SampleRate=strtoul(o->value(),&tmp,10);}
xywh {115 50 60 20} type Int textfont 1
- code0 {setsamplerateinput();}
- code1 {if (getsamplerateorder()!=0) o->deactivate();}
+ code0 {o->init("cfg.SampleRate");}
+ class Fl_Osc_Input
}
}
Fl_Input {} {
label {Buffer Size}
- callback {char *tmp;
-config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);}
tooltip {Internal Sound Buffer Size (samples)} xywh {190 45 60 20} type Int labelsize 11 align 129 textfont 1
- code0 {char *tmpbuf=new char[100];o->cut(0,o->maximum_size());}
- code1 {snprintf(tmpbuf,100,"%d",config.cfg.SoundBufferSize);o->insert(tmpbuf);}
- code2 {delete []tmpbuf;}
+ code0 {o->init("cfg.SoundBufferSize");}
+ class Fl_Osc_Input
}
Fl_Check_Button {} {
label {Swap Stereo }
- callback {config.cfg.SwapStereo=(int) o->value();}
xywh {15 80 95 20} box NO_BOX labelsize 11
- code0 {o->value(config.cfg.SwapStereo);}
+ code0 {o->init("cfg.SwapStereo");}
+ class Fl_Osc_Check
}
Fl_Choice {} {
label OscilSize
- callback {config.cfg.OscilSize=128<<o->value();}
tooltip {ADSynth Oscillator Size (samples)} xywh {175 80 75 20} down_box BORDER_BOX labelfont 1 labelsize 11 textsize 10
- code0 {o->value( (int) (log(config.cfg.OscilSize/128.0-1.0)/log(2)) +1);}
+ code0 {o->init("cfg.OscilPower");}
+ class Fl_Osc_Choice
} {
MenuItem {} {
label 128
@@ -155,21 +127,17 @@ config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);}
label {Most settings has effect only after ZynAddSubFX is restarted.}
xywh {10 300 235 30} labelfont 1 labelsize 11 align 128
}
- Fl_Box {} {
- label {Read the Readme.txt for other settings}
- xywh {10 280 240 15} labelfont 1 labelsize 11 align 128
- }
Fl_Counter {} {
label {XML compression level}
- callback {config.cfg.GzipCompression=(int) o->value();}
tooltip {gzip compression level (0 - uncompressed)} xywh {20 215 65 15} type Simple labelsize 11 align 8 minimum 0 maximum 9 step 1
- code0 {o->value(config.cfg.GzipCompression);}
+ code0 {o->init("cfg.GzipCompression");}
+ class Fl_Osc_Counter
}
Fl_Choice {} {
label {PADsynth Interpolation}
- callback {config.cfg.Interpolation=(int) o->value();}
xywh {175 105 75 15} down_box BORDER_BOX labelsize 10 textsize 11
- code0 {o->value(config.cfg.Interpolation);}
+ code0 {o->init("cfg.Interpolation");}
+ class Fl_Osc_Choice
} {
MenuItem {} {
label {Linear(fast)}
@@ -182,9 +150,9 @@ config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);}
}
Fl_Choice {} {
label {Virtual Keyboard Layout}
- callback {config.cfg.VirKeybLayout=(int) o->value();;}
xywh {155 235 85 20} down_box BORDER_BOX labelsize 12 textfont 1 textsize 11
- code0 {o->value(config.cfg.VirKeybLayout);}
+ code0 {o->init("cfg.VirKeybLayout");}
+ class Fl_Osc_Choice
} {
MenuItem {} {
label { }
@@ -209,9 +177,9 @@ config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);}
}
Fl_Check_Button {} {
label {Ignore MIDI Program Change}
- callback {config.cfg.IgnoreProgramChange=(int) o->value();}
xywh {10 255 220 20} down_box DOWN_BOX
- code0 {o->value(config.cfg.IgnoreProgramChange);}
+ code0 {o->init("cfg.IgnoreProgramChange");}
+ class Fl_Osc_Check
}
}
Fl_Group {} {
@@ -304,8 +272,10 @@ writepresetcfg();}
}
}
}
- Function {ConfigUI()} {} {
- code {make_window();
+ Function {ConfigUI(Fl_Osc_Interface *osc_)} {} {
+ code {
+ osc = osc_;
+ make_window();
readbankcfg();
readpresetcfg();} {}
}
@@ -330,57 +300,40 @@ readpresetcfg();} {}
Function {readbankcfg()} {} {
code {rootsbrowse->clear();
-for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){
- if (!config.cfg.bankRootDirList[i].empty())
- rootsbrowse->add(config.cfg.bankRootDirList[i].c_str());
-};} {}
+//for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){
+// if (!config.cfg.bankRootDirList[i].empty())
+// rootsbrowse->add(config.cfg.bankRootDirList[i].c_str());
+//};
+} {}
}
Function {writebankcfg()} {} {
- code {config.clearbankrootdirlist();
-
-for (int n=0;n<rootsbrowse->size();n++){
- config.cfg.bankRootDirList[n] = rootsbrowse->text(n+1);
-};} {}
+ code {
+//config.clearbankrootdirlist();
+//
+//for (int n=0;n<rootsbrowse->size();n++){
+// config.cfg.bankRootDirList[n] = rootsbrowse->text(n+1);
+//};
+} {}
}
Function {readpresetcfg()} {} {
code {presetbrowse->clear();
-for(int i=0;i<MAX_BANK_ROOT_DIRS;i++){
- if(!config.cfg.presetsDirList[i].empty())
- presetbrowse->add(config.cfg.presetsDirList[i].c_str());
-};} {}
+//for(int i=0;i<MAX_BANK_ROOT_DIRS;i++){
+// if(!config.cfg.presetsDirList[i].empty())
+// presetbrowse->add(config.cfg.presetsDirList[i].c_str());
+//};
+} {}
}
Function {writepresetcfg()} {} {
- code {config.clearpresetsdirlist();
-
-for (int n=0;n<presetbrowse->size();n++)
- config.cfg.presetsDirList[n] = presetbrowse->text(n+1);} {}
- }
- Function {getsamplerateorder()} {return_type int
- } {
- code {int smpr=config.cfg.SampleRate;
-int order=0;
-switch(smpr){
- case 16000:order=1;break;
- case 22050:order=2;break;
- case 32000:order=3;break;
- case 44100:order=4;break;
- case 48000:order=5;break;
- case 88200:order=6;break;
- case 96000:order=7;break;
- default:order=0;break;
-};
-return(order);} {}
- }
- Function {setsamplerateinput()} {return_type void
- } {
- code {char *tmpbuf=new char[100];
-samplerateinput->cut(0,samplerateinput->maximum_size());
-snprintf(tmpbuf,100,"%d",config.cfg.SampleRate);
-samplerateinput->insert(tmpbuf);
-delete []tmpbuf;} {}
+ code {
+//config.clearpresetsdirlist();
+//
+//for (int n=0;n<presetbrowse->size();n++)
+// config.cfg.presetsDirList[n] = presetbrowse->text(n+1);} {}
}
Function {show()} {} {
code {configwindow->show();} {}
}
+ decl {class Fl_Osc_Interface *osc;} {public local
+ }
}
diff --git a/src/UI/Connection.cpp b/src/UI/Connection.cpp
@@ -128,8 +128,8 @@ struct uiPorts {
//DSL based ports
rtosc::Ports uiPorts::ports = {
- BEGIN("show:T") {
- ui->showUI();
+ BEGIN("show:i") {
+ ui->showUI(a0.i);
} END
BEGIN("alert:s") {
fl_alert("%s",a0.s);
diff --git a/src/UI/EnvelopeFreeEdit.cpp b/src/UI/EnvelopeFreeEdit.cpp
@@ -88,9 +88,14 @@ int EnvelopeFreeEdit::getnearest(int x,int y) const
return nearestpoint;
}
+static float dt(char val)
+{
+ return (powf(2.0f, val / 127.0f * 12.0f) - 1.0f) * 10.0f; //miliseconds
+}
+
float EnvelopeFreeEdit::getdt(int i) const
{
- return EnvelopeParams::dt(Penvdt[i]);
+ return dt(Penvdt[i]);
}
void EnvelopeFreeEdit::draw(void)
diff --git a/src/UI/Fl_EQGraph.H b/src/UI/Fl_EQGraph.H
@@ -23,6 +23,7 @@ class Fl_EQGraph:public Fl_Box, public Fl_Osc_Widget
float getfreqx(float x) const;
float getfreqpos(float freq) const;
+ float samplerate;
float num[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1];
float dem[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1];
};
diff --git a/src/UI/Fl_EQGraph.cpp b/src/UI/Fl_EQGraph.cpp
@@ -11,13 +11,15 @@
#define MAX_DB 30
Fl_EQGraph::Fl_EQGraph(int x,int y, int w, int h, const char *label)
- :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this)
+ :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this), samplerate(48000)
{
memset(num, 0, sizeof(num));
memset(dem, 0, sizeof(dem));
num[0] = 1;
dem[0] = 1;
ext = "eq-coeffs";
+ osc->createLink("/samplerate", this);
+ osc->requestValue("/samplerate");
oscRegister("eq-coeffs");
}
@@ -26,9 +28,13 @@ Fl_EQGraph::~Fl_EQGraph(void)
void Fl_EQGraph::OSC_raw(const char *msg)
{
- memcpy(dem, rtosc_argument(msg, 0).b.data, sizeof(dem));
- memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(dem));
- redraw();
+ if(strstr(msg, "samplerate") && !strcmp("f", rtosc_argument_string(msg))) {
+ samplerate = rtosc_argument(msg, 0).f;
+ } else {
+ memcpy(dem, rtosc_argument(msg, 0).b.data, sizeof(dem));
+ memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(dem));
+ redraw();
+ }
}
void Fl_EQGraph::update(void)
@@ -114,7 +120,7 @@ void Fl_EQGraph::draw(void)
fl_begin_line();
for (i=1;i<lx;i++){
float frq=getfreqx(i/(float) lx);
- if (frq>synth->samplerate/2) break;
+ if (frq>samplerate/2) break;
iy=getresponse(ly,frq);
if ((oiy>=0) && (oiy<ly) &&
(iy>=0) && (iy<ly) )
@@ -134,7 +140,7 @@ void Fl_EQGraph::draw(void)
*/
double Fl_EQGraph::getresponse(int maxy,float freq) const
{
- const float angle = 2*PI*freq/synth->samplerate_f;
+ const float angle = 2*PI*freq/samplerate;
std::complex<float> num_res = 0;
std::complex<float> dem_res = 0;
diff --git a/src/UI/Fl_Osc_Button.H b/src/UI/Fl_Osc_Button.H
@@ -3,8 +3,6 @@
#include "Fl_Osc_Widget.H"
#include <string>
-using std::string; //yes this is bad form FIXME
-
class Fl_Osc_Button:public Fl_Button, public Fl_Osc_Widget
{
diff --git a/src/UI/Fl_OscilSpectrum.h b/src/UI/Fl_OscilSpectrum.h
@@ -1,4 +1,7 @@
#include <cassert>
+#include <FL/Fl_Box.H>
+#include <FL/Fl.H>
+#include "Fl_Osc_Widget.H"
//consider merging with Fl_Oscilloscope
class Fl_OscilSpectrum : public Fl_Box, Fl_Osc_Widget
@@ -68,8 +71,8 @@ class Fl_OscilSpectrum : public Fl_Box, Fl_Osc_Widget
const int maxdb=60;//must be multiple of 10
const int GX=2;
int n=lx/GX-1;
- if (n>synth->oscilsize/2)
- n=synth->oscilsize/2;
+ if (n>(int)nsamples)
+ n=nsamples;
fl_rectf(ox,oy,lx,ly,0,0,0);
diff --git a/src/UI/Fl_Oscilloscope.h b/src/UI/Fl_Oscilloscope.h
@@ -17,10 +17,8 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget
{
public:
Fl_Oscilloscope(int x,int y, int w, int h, const char *label=0)
- :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this)
+ :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this), smps(0), oscilsize(0)
{
- smps = new float[synth->oscilsize];
- memset(smps, 0, synth->oscilsize*sizeof(float));
phase=64;
box(FL_FLAT_BOX);
}
@@ -33,6 +31,8 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget
void init(bool base_waveform_p)
{
ext = (base_waveform_p ? "base-waveform": "waveform");
+ osc->createLink("/oscilsize", this);
+ osc->requestValue("/oscilsize");
assert(osc);
oscRegister(ext.c_str());
}
@@ -42,21 +42,29 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget
oscWrite(ext);
}
+ virtual void OSC_value(int smp)
+ {
+ oscilsize = smp;
+ delete []smps;
+ smps = new float[oscilsize];
+ memset(smps, 0, oscilsize*sizeof(float));
+ }
+
virtual void OSC_value(unsigned N, void *data) override
{
- assert(N==(unsigned)(synth->oscilsize*4));
+ assert(N==(unsigned)(oscilsize*4));
memcpy(smps, data, N);
//normalize
float max=0;
- for (int i=0;i<synth->oscilsize;i++)
+ for (int i=0;i<oscilsize;i++)
if(max<fabs(smps[i]))
max=fabs(smps[i]);
if (max<0.00001) max=1.0;
max *= -1.05;
- for(int i=0; i < synth->oscilsize; ++i)
+ for(int i=0; i < oscilsize; ++i)
smps[i] /= max;
//Get widget to redraw new data
@@ -100,10 +108,10 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget
int lw=2;
fl_line_style(FL_SOLID,lw);
fl_begin_line();
- double ph=((phase-64.0)/128.0*synth->oscilsize+synth->oscilsize);
+ double ph=((phase-64.0)/128.0*oscilsize+oscilsize);
for (int i=1;i<lx;i++){
- int k2=(synth->oscilsize*i/lx)+ph;
- double y2=smps[k2%synth->oscilsize];
+ int k2=(oscilsize*i/lx)+ph;
+ double y2=smps[k2%oscilsize];
fl_vertex(i+ox,y2*ly/2.0+oy+ly/2);
}
fl_end_line();
@@ -127,4 +135,5 @@ class Fl_Oscilloscope : public Fl_Box, public Fl_Osc_Widget
}
float *smps;
+ int oscilsize;
};
diff --git a/src/UI/Fl_PADnoteOvertonePosition.h b/src/UI/Fl_PADnoteOvertonePosition.h
@@ -10,15 +10,13 @@ class PADnoteOvertonePosition: public Fl_Box, Fl_Osc_Widget
{
public:
PADnoteOvertonePosition(int x,int y, int w, int h, const char *label=0)
- :Fl_Box(x,y,w,h,label), nsamples(synth->oscilsize/2),
- spc(new float[synth->oscilsize/2]),
- nhr(new float[synth->oscilsize/2]),
+ :Fl_Box(x,y,w,h,label), nsamples(0),
+ spc(0),
+ nhr(0),
spectrum(new float[w]),
mode(0), osc(NULL)
{
memset(spectrum, 0, w*sizeof(float));
- memset(spc, 0, synth->oscilsize/2*sizeof(float));
- memset(nhr, 0, synth->oscilsize/2*sizeof(float));
}
~PADnoteOvertonePosition(void)
@@ -42,6 +40,9 @@ class PADnoteOvertonePosition: public Fl_Box, Fl_Osc_Widget
base_path = og->base;
osc = og->osc;
assert(osc);
+
+ osc->createLink("/oscilsize", (Fl_Osc_Widget*) this);
+ osc->requestValue("/oscilsize");
osc->createLink(base_path + "nhr",
(Fl_Osc_Widget*) this);
@@ -76,9 +77,18 @@ class PADnoteOvertonePosition: public Fl_Box, Fl_Osc_Widget
}
virtual void OSC_value(int x, const char *name) override
{
- assert(!strcmp(name, "Pmode"));
- mode = x;
- regenerateOvertones();
+ if(!strcmp(name, "Pmode")) {
+ mode = x;
+ regenerateOvertones();
+ } else if(!strcmp(name, "oscilsize")) {
+ nsamples = x/2;
+ delete [] spc;
+ delete [] nhr;
+ spc = new float[nsamples];
+ nhr = new float[nsamples];
+ memset(spc, 0, nsamples*sizeof(float));
+ memset(nhr, 0, nsamples*sizeof(float));
+ }
}
private:
diff --git a/src/UI/FormantFilterGraph.cpp b/src/UI/FormantFilterGraph.cpp
@@ -243,10 +243,11 @@ void FormantFilterGraph::formantfilterH(int nvowel, int nfreqs, float *freqs)
//printf("NFORMANT %d\n", nformant);
//printf("CHARACTERISTICS: FREQ %f Q %f AMP %f\n", filter_freq, filter_q, filter_amp);
+ const float SampleRate = 48000.0f;
- if(filter_freq <= (synth->samplerate / 2 - 100.0f)) {
- const float omega = 2 * PI * filter_freq / synth->samplerate_f;
+ if(filter_freq <= (SampleRate / 2 - 100.0f)) {
+ const float omega = 2 * PI * filter_freq / SampleRate;
const float sn = sinf(omega);
const float cs = cosf(omega);
const float alpha = sn / (2 * filter_q);
@@ -265,14 +266,14 @@ void FormantFilterGraph::formantfilterH(int nvowel, int nfreqs, float *freqs)
const float freq = getfreqx(i / (float) nfreqs);
//Discard frequencies above nyquist rate
- if(freq > synth->samplerate / 2) {
+ if(freq > SampleRate / 2) {
for(int tmp = i; tmp < nfreqs; ++tmp)
freqs[tmp] = 0.0f;
break;
}
//Convert to normalized frequency
- const float fr = freq / synth->samplerate * PI * 2.0f;
+ const float fr = freq / SampleRate * PI * 2.0f;
//Evaluate Complex domain ratio
float x = c[0], y = 0.0f;
diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl
@@ -436,7 +436,7 @@ if (fl_choice("The file *might* exist. \\nOverwrite it?","No","Yes",NULL)) {
masterwindow->hide();
refresh_master_ui();
simplemasterwindow->show();
- config.cfg.UserInterfaceMode=2;
+ osc->write("/cfg.UserInterfaceMode", "i", 2);
};}
xywh {15 15 100 20}
}
@@ -910,7 +910,6 @@ updatepanel();}
if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL))
\#endif
{
- config.save();
*exitprogram=1;
};} open
xywh {661 384 600 335} type Double
@@ -1002,7 +1001,7 @@ if (result==-10) fl_alert("Error: Could not load the file\\nbecause it is not an
simplemasterwindow->hide();
refresh_master_ui();
masterwindow->show();
- config.cfg.UserInterfaceMode=1;
+ osc->write("/cfg.UserInterfaceMode", "i", 1);
};}
xywh {0 0 100 20}
}
@@ -1432,7 +1431,8 @@ virkeys->take_focus();}
}
Fl_Button {} {
label Advanced
- callback {config.cfg.UserInterfaceMode=1;
+ callback {
+ osc->write("/cfg.UserInterfaceMode", "i", 1);
masterwindow->show();
selectuiwindow->hide();}
xywh {10 165 100 35} color 229 labelfont 1 labelsize 16
@@ -1445,7 +1445,7 @@ selectuiwindow->hide();}
label Beginner
callback {simplemasterwindow->show();
selectuiwindow->hide();
-config.cfg.UserInterfaceMode=2;}
+osc->write("/cfg.UserInterfaceMode", "i", 2);}
xywh {10 80 100 65} color 238 labelfont 1 labelsize 16
}
Fl_Box {} {
@@ -1490,7 +1490,7 @@ for (int i=0;i<NUM_SYS_EFX;i++)
microtonalui=new MicrotonalUI(osc, "/microtonal/");
virkeyboard=new VirKeyboard(osc, "/");
bankui=new BankUI(&npart, osc);
-configui=new ConfigUI();
+configui=new ConfigUI(osc);
make_window();
fl_open_display();
@@ -1524,8 +1524,8 @@ delete presetsui;
delete panelwindow;
delete selectuiwindow;} {}
}
- Function {showUI()} {} {
- code {switch (config.cfg.UserInterfaceMode){
+ Function {showUI(int UIMode)} {} {
+ code {switch (UIMode){
case 0:selectuiwindow->show();
break;
case 1:masterwindow->show();
@@ -1668,7 +1668,6 @@ bankui->hide();} {}
}
Function {close()} {open return_type void
} {
- code {config.save();
-*exitprogram=1;} {}
+ code {*exitprogram=1;} {}
}
}
diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp
@@ -28,30 +28,30 @@ NioUI::NioUI()
//initialize midi list
{
- set<string> midiList = Nio::getSources();
- string source = Nio::getSource();
- int midival = 0;
- for(set<string>::iterator itr = midiList.begin();
- itr != midiList.end(); ++itr) {
- midi->add(itr->c_str());
- if(*itr == source)
- midival = midi->size() - 2;
- }
- midi->value(midival);
+ //set<string> midiList = Nio::getSources();
+ //string source = Nio::getSource();
+ //int midival = 0;
+ //for(set<string>::iterator itr = midiList.begin();
+ // itr != midiList.end(); ++itr) {
+ // midi->add(itr->c_str());
+ // if(*itr == source)
+ // midival = midi->size() - 2;
+ //}
+ //midi->value(midival);
}
//initialize audio list
{
- set<string> audioList = Nio::getSinks();
- string sink = Nio::getSink();
- int audioval = 0;
- for(set<string>::iterator itr = audioList.begin();
- itr != audioList.end(); ++itr) {
- audio->add(itr->c_str());
- if(*itr == sink)
- audioval = audio->size() - 2;
- }
- audio->value(audioval);
+ //set<string> audioList = Nio::getSinks();
+ //string sink = Nio::getSink();
+ //int audioval = 0;
+ //for(set<string>::iterator itr = audioList.begin();
+ // itr != audioList.end(); ++itr) {
+ // audio->add(itr->c_str());
+ // if(*itr == sink)
+ // audioval = audio->size() - 2;
+ //}
+ //audio->value(audioval);
}
resizable(this);
size_range(400, 300);
@@ -65,12 +65,12 @@ void NioUI::refresh()
void NioUI::midiCallback(Fl_Widget *c)
{
- bool good = Nio::setSource(static_cast<Fl_Choice *>(c)->text());
- static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));
+ //bool good = Nio::setSource(static_cast<Fl_Choice *>(c)->text());
+ //static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));
}
void NioUI::audioCallback(Fl_Widget *c)
{
- bool good = Nio::setSink(static_cast<Fl_Choice *>(c)->text());
- static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));
+ //bool good = Nio::setSink(static_cast<Fl_Choice *>(c)->text());
+ //static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255 * !good, 0, 0));
}
diff --git a/src/UI/PresetsUI.fl b/src/UI/PresetsUI.fl
@@ -5,23 +5,15 @@ code_name {.cc}
decl {\#include <FL/fl_ask.H>} {selected public
}
-decl {\#include <stdio.h>} {public
+decl {\#include <cstdio>} {public
}
-decl {\#include <stdlib.h>} {public
+decl {\#include <cstdlib>} {public
}
decl {\#include <string>} {public
}
-decl {\#include "../Params/PresetsArray.h"} {}
-
-decl {\#include "../Params/Presets.h"} {public
-}
-
-decl {\#include "../Misc/PresetExtractor.h"} {public
-}
-
class PresetsUI_ {} {
Function {refresh()} {open return_type {virtual void}
} {
@@ -59,7 +51,7 @@ class PresetsUI {} {
callback {const char *tmp=presetname->value();
if (tmp!=NULL) {
if (strlen(tmp)>0){
- presetCopy(url, tmp);
+ /*presetCopy(url, tmp);*/
copywin->hide();
};
};}
@@ -68,7 +60,7 @@ class PresetsUI {} {
Fl_Button copybutton {
label {Copy to Clipboard}
callback {
- presetCopy(url, "");
+ /*presetCopy(url, "");*/
copywin->hide();}
xywh {25 385 90 35} box THIN_UP_BOX align 192
}
@@ -114,14 +106,14 @@ class PresetsUI {} {
Fl_Button pastepbutton {
label {Paste from Preset}
callback {int n=pastebrowse->value();
- if (n!=0) presetPaste(url, n);
+ if (n!=0){/* presetPaste(url, n);*/}
pastewin->hide();
pui->refresh();}
xywh {10 355 160 20} box THIN_UP_BOX
}
Fl_Button pastebutton {
label {Paste from Clipboard}
- callback {presetPaste(url, 0);
+ callback {/*presetPaste(url, 0);*/
pastewin->hide();
pui->refresh();}
xywh {25 385 90 35} box THIN_UP_BOX align 192
@@ -142,8 +134,9 @@ class PresetsUI {} {
label Delete
callback {int n=pastebrowse->value();
- if (n!=0)
- presetDelete(n);
+ if (n!=0) {
+ /*presetDelete(n);*/
+ }
rescan();
} selected
xywh {180 355 75 20} box THIN_UP_BOX
@@ -166,10 +159,10 @@ class PresetsUI {} {
presetname->cut(0,presetname->maximum_size());
if(but) {
- presetCopy(url_, "");
+ /*presetCopy(url_, "");*/
} else {
rescan();
- copytypetext->label(presetClipboardType().c_str());
+ /*copytypetext->label(presetClipboardType().c_str());*/
copywin->show();
};} {}
}
@@ -182,28 +175,30 @@ class PresetsUI {} {
deletepbutton->deactivate();
if(but) {
- presetPaste(url, 0);
+ /*presetPaste(url, 0);*/
pui->refresh();
} else {
rescan();
- pastetypetext->label(presetClipboardType().c_str());
+ /*pastetypetext->label(presetClipboardType().c_str());
if (presetCheckClipboardType()) pastebutton->activate();
- else pastebutton->deactivate();
+ else pastebutton->deactivate();*/
pastewin->show();
};} {}
}
Function {rescan()} {} {
code {copybrowse->clear();
pastebrowse->clear();
- presetRescan();
+ /*presetRescan();*/
+ /*
for (unsigned int i=0;i<presetsstore.presets.size();i++){
std::string name=presetsstore.presets[i].name;
if(name.empty())
continue;
copybrowse->add(name.c_str());
pastebrowse->add(name.c_str());
- };} {}
+ };*/
+ } {}
}
decl {std::string url;} {public local
}
diff --git a/src/UI/VirKeyboard.fl b/src/UI/VirKeyboard.fl
@@ -26,6 +26,9 @@ decl {\#include "../Misc/Util.h"} {public local
decl {\#include "WidgetPDial.h"} {public local
}
+decl {\#include "Fl_Osc_Counter.H"} {public local
+}
+
decl {\#include "common.H"} {public local
}
@@ -61,7 +64,7 @@ decl {const int keysoct1az[]={'a',233,'z','\\"','e','r','(','t','-','y',232,'u',
decl {const int keysoct2az[]={'w','s','x','d','c','v','g','b','h','n','j',',',';','l',':','m','!',0};} {private local
}
-class VirKeys {open : {public Fl_Box}
+class VirKeys {open : {public Fl_Box, public Fl_Osc_Widget}
} {
decl {static const int N_OCT=6;} {private local
}
@@ -69,14 +72,22 @@ class VirKeys {open : {public Fl_Box}
}
decl {static const int SIZE_BLACK=8;} {private local
}
- Function {VirKeys(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} {
+ Function {VirKeys(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label),Fl_Osc_Widget()} {} {
code {} {}
}
+ Function {OSC_value(int layout)} {} {
+ code {
+ keylayout = layout;
+ } {}
+ }
Function {init(Fl_Osc_Interface *osc_, std::string loc_)} {open
} {
code {osc=osc_;
+ osc->createLink("/cfg.VirKeybLayout", this);
+ osc->requestValue("/cfg.VirKeybLayout");
loc=loc_;
for (int i=0;i<N_OCT*12+1;i++) pressed[i]=0;
+keylayout=0;
midich=0;
midivel=100;
midioct=2;
@@ -232,13 +243,13 @@ if ((event==FL_PUSH)||(event==FL_DRAG)||(event==FL_RELEASE)){
const int *keysoct1=keysoct1qwerty;
const int *keysoct2=keysoct2qwerty;
-if (config.cfg.VirKeybLayout==2) {
+if (keylayout==2) {
keysoct1=keysoct1dw;
keysoct2=keysoct2dw;
-}else if (config.cfg.VirKeybLayout==3) {
+}else if (keylayout==3) {
keysoct1=keysoct1qwertz;
keysoct2=keysoct2qwertz;
-}else if (config.cfg.VirKeybLayout==4) {
+}else if (keylayout==4) {
keysoct1=keysoct1az;
keysoct2=keysoct2az;
};
@@ -277,7 +288,7 @@ pressed[nk]=type;
damage(1);
float vel=midivel;
if (rndvelocity!=0){
- vel=midivel*(127.0-rndvelocity)/127.0+RND*rndvelocity;
+ vel=midivel*(127.0-rndvelocity)/127.0+(rand()/RAND_MAX)*rndvelocity;
};
osc->write(loc+"noteOn", "iii", midich,nk+midioct*12,(int)vel);} {}
@@ -301,6 +312,8 @@ osc->write(loc+"noteOff", "ii", midich,nk+12*midioct);} {}
}
decl {unsigned char midich;} {public local
}
+ decl {int keylayout;} {public local
+ }
decl {unsigned char midivel;} {public local
}
decl {char midioct,keyoct1,keyoct2;} {public local
diff --git a/src/UI/guimain.cpp b/src/UI/guimain.cpp
@@ -0,0 +1,533 @@
+/*
+ ZynAddSubFX - a software synthesizer
+
+ guimain.cpp - Main file of synthesizer GUI
+ Copyright (C) 2015 Mark McCurry
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (version 2 or later) for more details.
+
+ You should have received a copy of the GNU General Public License (version 2)
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include <lo/lo.h>
+#include <string>
+
+//GUI System
+#include "Connection.h"
+#include "NSM.H"
+
+#include <sys/stat.h>
+GUI::ui_handle_t gui = 0;
+#if USE_NSM
+NSM_Client *nsm = 0;
+#endif
+lo_server server;
+std::string sendtourl;
+
+int ADnote_unison_sizes[] =
+{1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0};
+
+/*
+ * Program exit
+ */
+void exitprogram()
+{
+ GUI::destroyUi(gui);
+}
+
+bool fileexists(const char *filename)
+{
+ struct stat tmp;
+ int result = stat(filename, &tmp);
+ if(result >= 0)
+ return true;
+
+ return false;
+}
+
+int Pexitprogram = 0;
+
+
+#include "Connection.h"
+#include "Fl_Osc_Interface.h"
+#include "../globals.h"
+#include <map>
+#include <cassert>
+
+#include <rtosc/rtosc.h>
+#include <rtosc/ports.h>
+
+#include <FL/Fl.H>
+#include "Fl_Osc_Tree.H"
+#include "common.H"
+#include "MasterUI.h"
+
+#ifdef NTK_GUI
+#include <FL/Fl_Shared_Image.H>
+#include <FL/Fl_Tiled_Image.H>
+#include <FL/Fl_Dial.H>
+#include <err.h>
+#endif // NTK_GUI
+
+#ifndef NO_UI
+#include "Fl_Osc_Widget.H"
+#endif
+
+using namespace GUI;
+class MasterUI *ui=0;
+
+#ifdef NTK_GUI
+static Fl_Tiled_Image *module_backdrop;
+#endif
+
+int undo_redo_handler(int)
+{
+ const bool undo_ = Fl::event_ctrl() && Fl::event_key() == 'z';
+ const bool redo = Fl::event_ctrl() && Fl::event_key() == 'r';
+ if(undo_)
+ ui->osc->write("/undo", "");
+ else if(redo)
+ ui->osc->write("/redo", "");
+ return undo_ || redo;
+}
+
+void
+set_module_parameters ( Fl_Widget *o )
+{
+#ifdef NTK_GUI
+ o->box( FL_DOWN_FRAME );
+ o->align( o->align() | FL_ALIGN_IMAGE_BACKDROP );
+ o->color( FL_BLACK );
+ o->image( module_backdrop );
+ o->labeltype( FL_SHADOW_LABEL );
+ if(o->parent()) {
+ o->parent()->labeltype(FL_NO_LABEL);
+ o->parent()->box(FL_NO_BOX);
+ }
+#else
+ o->box( FL_PLASTIC_UP_BOX );
+ o->color( FL_CYAN );
+ o->labeltype( FL_EMBOSSED_LABEL );
+#endif
+}
+
+ui_handle_t GUI::createUi(Fl_Osc_Interface *osc, void *exit)
+{
+#ifdef NTK_GUI
+ fl_register_images();
+
+ Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
+
+ if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/knob.png"))
+ Fl_Dial::default_image(img);
+ else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/knob.png"))
+ Fl_Dial::default_image(img);
+ else
+ errx(1, "ERROR: Cannot find pixmaps/knob.png");
+
+
+ if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/window_backdrop.png"))
+ Fl::scheme_bg(new Fl_Tiled_Image(img));
+ else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/window_backdrop.png"))
+ Fl::scheme_bg(new Fl_Tiled_Image(img));
+ else
+ errx(1, "ERROR: Cannot find pixmaps/window_backdrop.png");
+
+ if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/module_backdrop.png"))
+ module_backdrop = new Fl_Tiled_Image(img);
+ else if(Fl_Shared_Image *img = Fl_Shared_Image::get(SOURCE_DIR "/pixmaps/module_backdrop.png"))
+ module_backdrop = new Fl_Tiled_Image(img);
+ else
+ errx(1, "ERROR: Cannot find pixmaps/module_backdrop");
+
+ Fl::background(50, 50, 50);
+ Fl::background2(70, 70, 70);
+ Fl::foreground(255, 255, 255);
+#endif
+
+ //Fl_Window *midi_win = new Fl_Double_Window(400, 400, "Midi connections");
+ //Fl_Osc_Tree *tree = new Fl_Osc_Tree(0,0,400,400);
+ //midi_win->resizable(tree);
+ //tree->root_ports = &Master::ports;
+ //tree->osc = osc;
+ //midi_win->show();
+
+ Fl::add_handler(undo_redo_handler);
+ return (void*) (ui = new MasterUI((int*)exit, osc));
+}
+void GUI::destroyUi(ui_handle_t ui)
+{
+ delete static_cast<MasterUI*>(ui);
+}
+
+#define BEGIN(x) {x,":non-realtime\0",NULL,[](const char *m, rtosc::RtData d){ \
+ MasterUI *ui = static_cast<MasterUI*>(d.obj); \
+ rtosc_arg_t a0 = {0}, a1 = {0}; \
+ if(rtosc_narguments(m) > 0) \
+ a0 = rtosc_argument(m,0); \
+ if(rtosc_narguments(m) > 1) \
+ a1 = rtosc_argument(m,1); \
+ (void)ui;(void)a1;(void)a0;
+
+#define END }},
+
+struct uiPorts {
+ static rtosc::Ports ports;
+};
+
+//DSL based ports
+rtosc::Ports uiPorts::ports = {
+ BEGIN("show:i") {
+ ui->showUI(a0.i);
+ } END
+ BEGIN("alert:s") {
+ fl_alert("%s",a0.s);
+ } END
+ BEGIN("session-type:s") {
+ if(strcmp(a0.s,"LASH"))
+ return;
+ ui->sm_indicator1->value(1);
+ ui->sm_indicator2->value(1);
+ ui->sm_indicator1->tooltip("LASH");
+ ui->sm_indicator2->tooltip("LASH");
+ } END
+ BEGIN("save-master:s") {
+ ui->do_save_master(a0.s);
+ } END
+ BEGIN("load-master:s") {
+ ui->do_load_master(a0.s);
+ } END
+ BEGIN("vu-meter:bb") {
+ printf("Vu meter handler...\n");
+ if(a0.b.len == sizeof(vuData) &&
+ a1.b.len == sizeof(float)*NUM_MIDI_PARTS) {
+ printf("Normal behavior...\n");
+ //Refresh the primary VU meters
+ ui->simplemastervu->update((vuData*)a0.b.data);
+ ui->mastervu->update((vuData*)a0.b.data);
+
+ float *partvu = (float*)a1.b.data;
+ for(int i=0; i<NUM_MIDI_PARTS; ++i)
+ ui->panellistitem[i]->partvu->update(partvu[i]);
+ }
+ } END
+ BEGIN("close-ui") {
+ ui->close();
+ } END
+};
+
+
+void GUI::raiseUi(ui_handle_t gui, const char *message)
+{
+ if(!gui)
+ return;
+ MasterUI *mui = (MasterUI*)gui;
+ mui->osc->tryLink(message);
+ printf("got message for UI '%s:%s'\n", message, rtosc_argument_string(message));
+ char buffer[1024];
+ memset(buffer, 0, sizeof(buffer));
+ rtosc::RtData d;
+ d.loc = buffer;
+ d.loc_size = 1024;
+ d.obj = gui;
+ uiPorts::ports.dispatch(message+1, d);
+}
+
+void GUI::raiseUi(ui_handle_t gui, const char *dest, const char *args, ...)
+{
+ char buffer[1024];
+ va_list va;
+ va_start(va,args);
+ if(rtosc_vmessage(buffer,1024,dest,args,va))
+ raiseUi(gui, buffer);
+ va_end(va);
+}
+
+void GUI::tickUi(ui_handle_t)
+{
+ Fl::wait(0.02f);
+}
+
+/******************************************************************************
+ * OSC Interface For User Interface *
+ * *
+ * This is a largely out of date section of code *
+ * Most type specific write methods are no longer used *
+ * See UI/Fl_Osc_* to see what is actually used in this interface *
+ ******************************************************************************/
+class UI_Interface:public Fl_Osc_Interface
+{
+ public:
+ UI_Interface()
+ {}
+
+ void transmitMsg(const char *path, const char *args, ...)
+ {
+ char buffer[1024];
+ va_list va;
+ va_start(va,args);
+ if(rtosc_vmessage(buffer,1024,path,args,va))
+ transmitMsg(buffer);
+ else
+ fprintf(stderr, "Error in transmitMsg(...)\n");
+ va_end(va);
+ }
+
+ void transmitMsg(const char *rtmsg)
+ {
+ //Send to known url
+ if(!sendtourl.empty()) {
+ lo_message msg = lo_message_deserialise((void*)rtmsg,
+ rtosc_message_length(rtmsg, rtosc_message_length(rtmsg,-1)), NULL);
+ lo_address addr = lo_address_new_from_url(sendtourl.c_str());
+ lo_send_message(addr, rtmsg, msg);
+ }
+ }
+
+ void requestValue(string s) override
+ {
+ //printf("Request Value '%s'\n", s.c_str());
+ assert(s!="/Psysefxvol-1/part0");
+ //Fl_Osc_Interface::requestValue(s);
+ /*
+ if(impl->activeUrl() != "GUI") {
+ impl->transmitMsg("/echo", "ss", "OSC_URL", "GUI");
+ impl->activeUrl("GUI");
+ }*/
+
+ transmitMsg(s.c_str(),"");
+ }
+
+ void write(string s, const char *args, ...) override
+ {
+ va_list va;
+ va_start(va, args);
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
+ ////fprintf(stderr, ".");
+ //fprintf(stderr, "write(%s:%s)\n", s.c_str(), args);
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
+ transmitMsg(s.c_str(), args, va);
+ va_end(va);
+ }
+
+ void writeRaw(const char *msg) override
+ {
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
+ ////fprintf(stderr, ".");
+ //fprintf(stderr, "rawWrite(%s:%s)\n", msg, rtosc_argument_string(msg));
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
+ transmitMsg(msg);
+ }
+
+ void writeValue(string s, string ss) override
+ {
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
+ //fprintf(stderr, "writevalue<string>(%s,%s)\n", s.c_str(),ss.c_str());
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
+ transmitMsg(s.c_str(), "s", ss.c_str());
+ }
+
+ void writeValue(string s, char c) override
+ {
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
+ //fprintf(stderr, "writevalue<char>(%s,%d)\n", s.c_str(),c);
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
+ transmitMsg(s.c_str(), "c", c);
+ }
+
+ void writeValue(string s, float f) override
+ {
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 4 + 30, 0 + 40);
+ //fprintf(stderr, "writevalue<float>(%s,%f)\n", s.c_str(),f);
+ //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40);
+ transmitMsg(s.c_str(), "f", f);
+ }
+
+ void createLink(string s, class Fl_Osc_Widget*w) override
+ {
+ assert(s.length() != 0);
+ Fl_Osc_Interface::createLink(s,w);
+ assert(!strstr(s.c_str(), "/part0/kit-1"));
+ map.insert(std::pair<string,Fl_Osc_Widget*>(s,w));
+ }
+
+ void renameLink(string old, string newer, Fl_Osc_Widget *w) override
+ {
+ fprintf(stdout, "renameLink('%s','%s',%p)\n",
+ old.c_str(), newer.c_str(), w);
+ removeLink(old, w);
+ createLink(newer, w);
+ }
+
+ void removeLink(string s, class Fl_Osc_Widget*w) override
+ {
+ for(auto i = map.begin(); i != map.end(); ++i) {
+ if(i->first == s && i->second == w) {
+ map.erase(i);
+ break;
+ }
+ }
+ //printf("[%d] removing '%s' (%p)...\n", map.size(), s.c_str(), w);
+ }
+
+ virtual void removeLink(class Fl_Osc_Widget *w) override
+ {
+ bool processing = true;
+ while(processing)
+ {
+ //Verify Iterator invalidation sillyness
+ processing = false;//Exit if no new elements are found
+ for(auto i = map.begin(); i != map.end(); ++i) {
+ if(i->second == w) {
+ //printf("[%d] removing '%s' (%p)...\n", map.size()-1,
+ // i->first.c_str(), w);
+ map.erase(i);
+ processing = true;
+ break;
+ }
+ }
+ }
+ }
+
+ //A very simplistic implementation of a UI agnostic refresh method
+ virtual void damage(const char *path) override
+ {
+ //printf("\n\nDamage(\"%s\")\n", path);
+ for(auto pair:map) {
+ if(strstr(pair.first.c_str(), path)) {
+ auto *tmp = dynamic_cast<Fl_Widget*>(pair.second);
+ //if(tmp)
+ // printf("%x, %d %d [%s]\n", (int)pair.second, tmp->visible_r(), tmp->visible(), pair.first.c_str());
+ //else
+ // printf("%x, (NULL)[%s]\n", (int)pair.second,pair.first.c_str());
+ if(!tmp || tmp->visible_r())
+ 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));
+ const char *handle = rindex(msg,'/');
+ if(handle)
+ ++handle;
+
+ int found_count = 0;
+
+ auto range = map.equal_range(msg);
+ for(auto itr = range.first; itr != range.second; ++itr) {
+ auto widget = itr->second;
+ found_count++;
+ const char *arg_str = rtosc_argument_string(msg);
+
+ //Always provide the raw message
+ widget->OSC_raw(msg);
+
+ if(!strcmp(arg_str, "b")) {
+ widget->OSC_value(rtosc_argument(msg,0).b.len,
+ rtosc_argument(msg,0).b.data,
+ handle);
+ } else if(!strcmp(arg_str, "c")) {
+ widget->OSC_value((char)rtosc_argument(msg,0).i,
+ handle);
+ } else if(!strcmp(arg_str, "s")) {
+ widget->OSC_value((const char*)rtosc_argument(msg,0).s,
+ handle);
+ } else if(!strcmp(arg_str, "i")) {
+ widget->OSC_value((int)rtosc_argument(msg,0).i,
+ handle);
+ } else if(!strcmp(arg_str, "f")) {
+ widget->OSC_value((float)rtosc_argument(msg,0).f,
+ handle);
+ } else if(!strcmp(arg_str, "T") || !strcmp(arg_str, "F")) {
+ widget->OSC_value((bool)rtosc_argument(msg,0).T, handle);
+ }
+ }
+
+ if(found_count == 0
+ && strcmp(msg, "/vu-meter")
+ && 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);
+ }
+ };
+
+ void dumpLookupTable(void)
+ {
+ if(!map.empty()) {
+ printf("Leaked controls:\n");
+ for(auto i = map.begin(); i != map.end(); ++i) {
+ printf("Known control '%s' (%p)...\n", i->first.c_str(), i->second);
+ }
+ }
+ }
+
+
+ private:
+ std::multimap<string,Fl_Osc_Widget*> map;
+};
+
+Fl_Osc_Interface *GUI::genOscInterface(MiddleWare *)
+{
+ return new UI_Interface();
+}
+
+static void liblo_error_cb(int i, const char *m, const char *loc)
+{
+ fprintf(stderr, "liblo :-( %d-%s@%s\n",i,m,loc);
+}
+
+static int handler_function(const char *path, const char *types, lo_arg **argv,
+ int argc, lo_message msg, void *user_data)
+{
+ (void) types;
+ (void) argv;
+ (void) argc;
+ (void) user_data;
+ char buffer[2048];
+ memset(buffer, 0, sizeof(buffer));
+ size_t size = 2048;
+ lo_message_serialise(msg, path, buffer, &size);
+ raiseUi(gui, buffer);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ //Startup Liblo Link
+ if(argc == 2) {
+ server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb);
+ lo_server_add_method(server, NULL, NULL, handler_function, 0);
+ sendtourl = argv[1];
+ }
+
+ gui = GUI::createUi(new UI_Interface(), &Pexitprogram);
+
+ GUI::raiseUi(gui, "/show", "i", 1);
+ while(Pexitprogram == 0) {
+ if(server)
+ while(lo_server_recv_noblock(server, 0));
+ GUI::tickUi(gui);
+ }
+
+ exitprogram();
+ return 0;
+}
diff --git a/src/main.cpp b/src/main.cpp
@@ -111,6 +111,7 @@ void initprogram(void)
void exitprogram()
{
Nio::stop();
+ config.save();
GUI::destroyUi(gui);
delete middleware;
@@ -431,7 +432,7 @@ int main(int argc, char *argv[])
if(!noui)
{
- GUI::raiseUi(gui, "/show", "T");
+ GUI::raiseUi(gui, "/show", "i", config.cfg.UserInterfaceMode);
if(!ioGood)
GUI::raiseUi(gui, "/alert", "s",
"Default IO did not initialize.\nDefaulting to NULL backend.");