zynaddsubfx

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

commit a4ecf324794fc55370f43570fdc5aac29d07ee6d
parent 368e544ca923fcf0246639564070adb07e2f145c
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Thu,  7 Feb 2013 13:10:30 -0500

Minimum librtosc integration

- It's quick, ugly, and spawns more issues than it solves, but it must begin
  somewhere
- Master::volume is now controllable via OSC

Diffstat:
Msrc/CMakeLists.txt | 11++++++-----
Msrc/Misc/Master.cpp | 32++++++++++++++++++++++++++++++++
Msrc/Misc/Master.h | 3++-
Msrc/globals.h | 4++++
Msrc/main.cpp | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 168 insertions(+), 6 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -113,22 +113,22 @@ option (BuildForDebug "Include gdb debugging support" OFF) set(CMAKE_BUILD_TYPE "Release") set (BuildOptions_x86_64AMD - "-O3 -march=athlon64 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" + "-std=c++0x -O3 -march=athlon64 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" CACHE STRING "X86_64 compiler options" ) set (BuildOptions_X86_64Core2 - "-O3 -march=core2 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" + "-std=c++0x -O3 -march=core2 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" CACHE STRING "X86_64 compiler options" ) set (BuildOptionsBasic - "-O3 -msse -msse2 -mfpmath=sse -ffast-math -fomit-frame-pointer" + "-std=c++0x -O3 -msse -msse2 -mfpmath=sse -ffast-math -fomit-frame-pointer" CACHE STRING "basic X86 complier options" ) set (BuildOptionsDebug - "-O0 -g3 -ggdb -Wall -Wpointer-arith" CACHE STRING "Debug build flags") + "-std=c++0x -O0 -g3 -ggdb -Wall -Wpointer-arith" CACHE STRING "Debug build flags") ########### Settings dependant code ########### # From here on, the setting variables have been prepared so concentrate @@ -321,7 +321,8 @@ target_link_libraries(zynaddsubfx_core ${FFTW_LIBRARIES} ${MXML_LIBRARIES} ${OS_LIBRARIES} - pthread) + pthread + rtosc) message(STATUS "using link directories: ${AUDIO_LIBRARY_DIRS} ${ZLIB_LIBRARY_DIRS} ${FFTW_LIBRARY_DIRS} ${MXML_LIBRARY_DIRS} ${FLTK_LIBRARY_DIRS}") diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -29,6 +29,8 @@ #include "../Effects/EffectMgr.h" #include "../DSP/FFTwrapper.h" +#include <rtosc/ports.h> +#include <rtosc/thread-link.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> @@ -39,6 +41,31 @@ #include <unistd.h> using namespace std; +using rtosc::Ports; +using rtosc::RtData; + +template<class T> +T lim(T min, T max, T val) +{ + return val<max?(val>min?val:min):max; +} +//floating point parameter - with lookup code +#define PARAMF(type, var, name, scale, _min, _max, desc) \ +{#name"::f", #scale "," # _min "," #_max ":'parameter':" desc, 0, \ + [](const char *m, RtData d) { \ + if(rtosc_narguments(m)==0) {\ + bToU->write("/display", "sf", d.loc, ((type*)d.obj)->var); \ + } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='f') {\ + ((type*)d.obj)->var = lim<float>(_min,_max,rtosc_argument(m,0).f); \ + bToU->write(d.loc, "f", ((type*)d.obj)->var);}}} + +static Ports localports = { + {"echo", ":'hidden':Hidden port to echo messages", 0, [](const char *m, RtData) { + bToU->raw_write(m-1);}}, + PARAMF(Master, volume, volume, log, 0.01, 4.42, "Master Volume"), +}; + +Ports &Master::ports = localports; vuData::vuData(void) :outpeakl(0.0f), outpeakr(0.0f), maxoutpeakl(0.0f), maxoutpeakr(0.0f), @@ -319,6 +346,11 @@ void Master::partonoff(int npart, int what) */ void Master::AudioOut(float *outl, float *outr) { + //Handle user events TODO move me to a proper location + char loc_buf[1024]; + while(uToB->hasNext()) + ports.dispatch(loc_buf, 1024, uToB->read()+1, this); + //Swaps the Left channel with Right Channel if(swaplr) swap(outl, outr); diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -164,10 +164,11 @@ class Master pthread_mutex_t vumutex; + static rtosc::Ports &ports; + float volume; private: bool nullRun; vuData vu; - float volume; float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; int keyshift; diff --git a/src/globals.h b/src/globals.h @@ -26,6 +26,10 @@ #define GLOBALS_H #include <stdint.h> +//Forward declarations +namespace rtosc{class Ports; class ThreadLink;}; +extern rtosc::ThreadLink *bToU; +extern rtosc::ThreadLink *uToB; /** * The number of harmonics of additive synth diff --git a/src/main.cpp b/src/main.cpp @@ -35,6 +35,10 @@ #include <getopt.h> +#include <lo/lo.h> +#include <rtosc/ports.h> +#include <rtosc/thread-link.h> + #include "DSP/FFTwrapper.h" #include "Misc/Master.h" #include "Misc/Part.h" @@ -96,6 +100,122 @@ void sigterm_exit(int /*sig*/) Pexitprogram = 1; } +void error_cb(int i, const char *m, const char *loc) +{ + fprintf(stderr, "liblo :-( %d-%s@%s\n",i,m,loc); +} + +lo_server server; +rtosc::ThreadLink *bToU = new rtosc::ThreadLink(1024,1024); +rtosc::ThreadLink *uToB = new rtosc::ThreadLink(1024,1024); +string last_url, curr_url; + +void path_search(const char *m) +{ + using rtosc::Ports; + using rtosc::Port; + + //assumed upper bound of 32 ports (may need to be resized) + char types[65]; + rtosc_arg_t args[64]; + size_t pos = 0; + const Ports *ports = NULL; + const Port *port = NULL; + const char *str = rtosc_argument(m,0).s; + const char *needle = rtosc_argument(m,1).s; + + //zero out data + memset(types, 0, sizeof(types)); + memset(args, 0, sizeof(args)); + + if(!*str) { + ports = &Master::ports; + } else { + const Port *port = Master::ports.apropos(rtosc_argument(m,0).s); + if(port) + ports = port->ports; + } + + if(ports) { + //RTness not confirmed here + for(const Port &p:*ports) { + if(strstr(p.name, needle)!=p.name) + continue; + types[pos] = types[pos+1] = 's'; + args[pos++].s = p.name; + args[pos++].s = p.metadata; + } + } + + //Reply to requester + char buffer[1024]; + size_t length = rtosc_amessage(buffer, 1024, "/paths", types, args); + if(length) { + lo_message msg = lo_message_deserialise((void*)buffer, length, NULL); + lo_address addr = lo_address_new_from_url(last_url.c_str()); + if(addr) + lo_send_message(addr, buffer, msg); + } +} + +int handler_function(const char *path, const char *types, lo_arg **argv, + int argc, lo_message msg, void *user_data) +{ + lo_address addr = lo_message_get_source(msg); + if(addr) { + const char *tmp = lo_address_get_url(addr); + if(tmp != last_url) { + uToB->write("/echo", "ss", "OSC_URL", tmp); + last_url = tmp; + } + + } + + char buffer[2048]; + memset(buffer, 0, sizeof(buffer)); + size_t size = 2048; + lo_message_serialise(msg, path, buffer, &size); + if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) { + path_search(buffer); + } else + uToB->raw_write(buffer); + + return 0; +} + +void osc_setup(void) +{ + server = lo_server_new_with_proto(NULL, LO_UDP, error_cb); + lo_server_add_method(server, NULL, NULL, handler_function, NULL); + fprintf(stderr, "lo server running on %d\n", lo_server_get_port(server)); +} + +/** + * - Fetches liblo messages and forward them to the backend + * - Grabs backend messages and distributes them to the frontends + */ +void osc_check(void) +{ + lo_server_recv_noblock(server, 100); + while(bToU->hasNext()) { + const char *rtmsg = bToU->read(); + 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 { + 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); + } + } + } +} + #ifndef DISABLE_GUI @@ -139,6 +259,8 @@ void initprogram(void) signal(SIGINT, sigterm_exit); signal(SIGTERM, sigterm_exit); + + osc_setup(); } /* @@ -537,6 +659,8 @@ int main(int argc, char *argv[]) done: #endif + osc_check(); + Fl::wait(0.02f); #else usleep(100000);