From fa8f005a6c97480a671146c483cf1183d5f1b083 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 24 Mar 2019 15:20:25 +0100 Subject: Introduce full build target in root --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index cda8fae..5ee9cd9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all clean run sanitize backends +.PHONY: all clean run sanitize backends full backends-full OBJS = config.o backend.o plugin.o PLUGINDIR = "\"./backends/\"" @@ -19,9 +19,14 @@ endif all: midimonster backends +full: midimonster backends-full + backends: $(MAKE) -C backends +backends-full: + $(MAKE) -C backends full + # This rule can not be the default rule because OSX the target prereqs are not exactly the build prereqs midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ -- cgit v1.2.3 From 20a6882a063404858588596bd3f12bdd9e53460a Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 3 Aug 2019 18:42:39 +0200 Subject: Windows build compatiblity --- .gitignore | 3 +++ Makefile | 23 +++++++++++++++++-- backend.c | 31 ++++++++++++++----------- backend.h | 9 +++++++- backends/Makefile | 26 +++++++++++++++++++-- backends/artnet.c | 16 ++++++++----- backends/artnet.h | 2 ++ backends/libmmbackend.c | 12 ++++++++-- backends/libmmbackend.h | 6 +++++ backends/lua.c | 4 ---- backends/osc.c | 18 +++++++++------ backends/osc.h | 2 ++ backends/sacn.c | 28 ++++++++++++++--------- backends/sacn.h | 1 - config.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ midimonster.c | 39 ++++++++++++++++++++++++++------ midimonster.h | 38 ++++++++++++++++++++++++------- monster.cfg | 12 +++------- plugin.c | 60 +++++++++++++++++++++++++++++++++++++++++++++---- portability.h | 17 ++++++++++++++ 20 files changed, 326 insertions(+), 77 deletions(-) (limited to 'Makefile') diff --git a/.gitignore b/.gitignore index 3afd872..4396a38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ midimonster +midimonster.exe +libmmapi.a *.swp *.o *.so +*.dll diff --git a/Makefile b/Makefile index 5ee9cd9..b82d6d8 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ -.PHONY: all clean run sanitize backends full backends-full +.PHONY: all clean run sanitize backends windows full backends-full OBJS = config.o backend.o plugin.o PLUGINDIR = "\"./backends/\"" +PLUGINDIR_W32 = "\"backends\\\\\"" SYSTEM := $(shell uname -s) -CFLAGS ?= -g -Wall +CFLAGS ?= -g -Wall -Wpedantic +# Hide all non-API symbols for export +CFLAGS += -fvisibility=hidden + #CFLAGS += -DDEBUG midimonster: LDLIBS = -ldl midimonster: CFLAGS += -DPLUGINS=$(PLUGINDIR) @@ -21,6 +25,8 @@ all: midimonster backends full: midimonster backends-full +windows: midimonster.exe + backends: $(MAKE) -C backends @@ -31,8 +37,21 @@ backends-full: midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ +midimonster.exe: export CC = x86_64-w64-mingw32-gcc +#midimonster.exe: CFLAGS += -Wno-format +midimonster.exe: CFLAGS += -DPLUGINS=$(PLUGINDIR_W32) -Wno-format +midimonster.exe: LDLIBS = -lws2_32 +midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a +midimonster.exe: midimonster.c portability.h $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ + # The windows build for backends requires the import library generated with the build, + # so the backends can't be a prerequisite for the executable... + $(MAKE) -C backends windows + clean: $(RM) midimonster + $(RM) midimonster.exe + $(RM) libmmapi.a $(RM) $(OBJS) $(MAKE) -C backends clean diff --git a/backend.c b/backend.c index 5df5d73..4fa7704 100644 --- a/backend.c +++ b/backend.c @@ -1,4 +1,9 @@ #include +#ifndef _WIN32 +#define MM_API __attribute__((visibility ("default"))) +#else +#define MM_API __attribute__((dllexport)) +#endif #include "midimonster.h" #include "backend.h" @@ -26,7 +31,7 @@ int backends_handle(size_t nfds, managed_fd* fds){ } } - DBGPF("Notifying backend %s of %zu waiting FDs\n", backends[u].name, n); + DBGPF("Notifying backend %s of %lu waiting FDs\n", backends[u].name, n); rv |= backends[u].process(n, fds); if(rv){ fprintf(stderr, "Backend %s failed to handle input\n", backends[u].name); @@ -59,28 +64,28 @@ int backends_notify(size_t nev, channel** c, channel_value* v){ } } - DBGPF("Calling handler for instance %s with %zu events\n", instances[u]->name, n); + DBGPF("Calling handler for instance %s with %lu events\n", instances[u]->name, n); rv |= instances[u]->backend->handle(instances[u], n, c, v); } return 0; } -channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ +channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create){ size_t u; for(u = 0; u < nchannels; u++){ - if(channels[u]->instance == i && channels[u]->ident == ident){ - DBGPF("Requested channel %zu on instance %s already exists, reusing\n", ident, i->name); + if(channels[u]->instance == inst && channels[u]->ident == ident){ + DBGPF("Requested channel %lu on instance %s already exists, reusing\n", ident, inst->name); return channels[u]; } } if(!create){ - DBGPF("Requested unknown channel %zu on instance %s\n", ident, i->name); + DBGPF("Requested unknown channel %lu on instance %s\n", ident, inst->name); return NULL; } - DBGPF("Creating previously unknown channel %zu on instance %s\n", ident, i->name); + DBGPF("Creating previously unknown channel %lu on instance %s\n", ident, inst->name); channel** new_chan = realloc(channels, (nchannels + 1) * sizeof(channel*)); if(!new_chan){ fprintf(stderr, "Failed to allocate memory\n"); @@ -95,12 +100,12 @@ channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ return NULL; } - channels[nchannels]->instance = i; + channels[nchannels]->instance = inst; channels[nchannels]->ident = ident; return channels[nchannels++]; } -instance* mm_instance(){ +instance* MM_API mm_instance(){ instance** new_inst = realloc(instances, (ninstances + 1) * sizeof(instance*)); if(!new_inst){ //TODO free @@ -118,7 +123,7 @@ instance* mm_instance(){ return instances[ninstances++]; } -instance* mm_instance_find(char* name, uint64_t ident){ +instance* MM_API mm_instance_find(char* name, uint64_t ident){ size_t u; backend* b = backend_match(name); if(!b){ @@ -134,7 +139,7 @@ instance* mm_instance_find(char* name, uint64_t ident){ return NULL; } -int mm_backend_instances(char* name, size_t* ninst, instance*** inst){ +int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst){ backend* b = backend_match(name); size_t n = 0, u; //count number of affected instances @@ -177,7 +182,7 @@ void instances_free(){ void channels_free(){ size_t u; for(u = 0; u < nchannels; u++){ - DBGPF("Destroying channel %zu on instance %s\n", channels[u]->ident, channels[u]->instance->name); + DBGPF("Destroying channel %lu on instance %s\n", channels[u]->ident, channels[u]->instance->name); if(channels[u]->impl){ channels[u]->instance->backend->channel_free(channels[u]); } @@ -232,7 +237,7 @@ struct timeval backend_timeout(){ return tv; } -int mm_backend_register(backend b){ +int MM_API mm_backend_register(backend b){ if(!backend_match(b.name)){ backends = realloc(backends, (nbackends + 1) * sizeof(backend)); if(!backends){ diff --git a/backend.h b/backend.h index daf96bc..7529154 100644 --- a/backend.h +++ b/backend.h @@ -1,8 +1,8 @@ #include +/* Internal API */ int backends_handle(size_t nfds, managed_fd* fds); int backends_notify(size_t nev, channel** c, channel_value* v); - backend* backend_match(char* name); instance* instance_match(char* name); struct timeval backend_timeout(); @@ -10,3 +10,10 @@ int backends_start(); int backends_stop(); void instances_free(); void channels_free(); + +/* Backend API */ +channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create); +instance* MM_API mm_instance(); +instance* MM_API mm_instance_find(char* name, uint64_t ident); +int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst); +int MM_API mm_backend_register(backend b); diff --git a/backends/Makefile b/backends/Makefile index 22cb95b..2374df0 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -1,12 +1,13 @@ .PHONY: all clean full OPTIONAL_BACKENDS = ola.so +WINDOWS_BACKENDS = loopback.dll artnet.dll osc.dll sacn.dll LINUX_BACKENDS = midi.so evdev.so BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so BACKEND_LIB = libmmbackend.o SYSTEM := $(shell uname -s) -CFLAGS += -g -fPIC -I../ +CFLAGS += -g -fPIC -I../ -Wall -Wpedantic CPPFLAGS += -g -fPIC -I../ LDFLAGS += -shared @@ -20,8 +21,17 @@ LDFLAGS += -undefined dynamic_lookup endif artnet.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +artnet.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +artnet.dll: LDLIBS += -lws2_32 + osc.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +osc.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +osc.dll: LDLIBS += -lws2_32 + sacn.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +sacn.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +sacn.dll: LDLIBS += -lws2_32 + midi.so: LDLIBS = -lasound evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev) evdev.so: LDLIBS = $(shell pkg-config --libs libevdev) @@ -33,12 +43,24 @@ lua.so: LDLIBS += $(shell pkg-config --libs lua5.3) %.so :: %.c %.h $(BACKEND_LIB) $(CC) $(CFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) +%.dll :: %.c %.h $(BACKEND_LIB) + $(CC) $(CFLAGS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) $(LDLIBS) + %.so :: %.cpp %.h $(CXX) $(CPPFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) all: $(BACKEND_LIB) $(BACKENDS) +../libmmapi.a: + $(MAKE) -C ../ midimonster.exe + +windows: export CC = x86_64-w64-mingw32-gcc +windows: LDLIBS += -lmmapi +windows: LDFLAGS += -L../ +windows: CFLAGS += -Wno-format -Wno-pointer-sign +windows: ../libmmapi.a $(BACKEND_LIB) $(WINDOWS_BACKENDS) + full: $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) clean: - $(RM) $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) + $(RM) $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) $(WINDOWS_BACKENDS) diff --git a/backends/artnet.c b/backends/artnet.c index 8b404a6..a6df4ab 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -3,8 +3,8 @@ #include #include "libmmbackend.h" - #include "artnet.h" + #define MAX_FDS 255 #define BACKEND_NAME "artnet" @@ -32,7 +32,7 @@ static int artnet_listener(char* host, char* port){ return -1; } - fprintf(stderr, "ArtNet backend interface %zu bound to %s port %s\n", artnet_fds, host, port); + fprintf(stderr, "ArtNet backend interface %lu bound to %s port %s\n", artnet_fds, host, port); artnet_fd[artnet_fds].fd = fd; artnet_fd[artnet_fds].output_instances = 0; artnet_fd[artnet_fds].output_instance = NULL; @@ -212,7 +212,7 @@ static int artnet_transmit(instance* inst){ }; memcpy(frame.data, data->data.out, 512); - if(sendto(artnet_fd[data->fd_index].fd, &frame, sizeof(frame), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ + if(sendto(artnet_fd[data->fd_index].fd, (uint8_t*) &frame, sizeof(frame), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ fprintf(stderr, "Failed to output ArtNet frame for instance %s: %s\n", inst->name, strerror(errno)); } @@ -230,7 +230,7 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) artnet_instance_data* data = (artnet_instance_data*) inst->impl; if(!data->dest_len){ - fprintf(stderr, "ArtNet instance %s not enabled for output (%zu channel events)\n", inst->name, num); + fprintf(stderr, "ArtNet instance %s not enabled for output (%lu channel events)\n", inst->name, num); return 0; } @@ -295,7 +295,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){ } if(!chan){ - fprintf(stderr, "Active channel %zu on %s not known to core\n", p, inst->name); + fprintf(stderr, "Active channel %lu on %s not known to core\n", p, inst->name); return 1; } @@ -367,7 +367,11 @@ static int artnet_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "ArtNet failed to receive data: %s\n", strerror(errno)); } @@ -438,7 +442,7 @@ static int artnet_start(){ } } - fprintf(stderr, "ArtNet backend registering %zu descriptors to core\n", artnet_fds); + fprintf(stderr, "ArtNet backend registering %lu descriptors to core\n", artnet_fds); for(u = 0; u < artnet_fds; u++){ if(mm_manage_fd(artnet_fd[u].fd, BACKEND_NAME, 1, (void*) u)){ goto bail; diff --git a/backends/artnet.h b/backends/artnet.h index 90aedd5..f5aa745 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -1,4 +1,6 @@ +#ifndef _WIN32 #include +#endif #include "midimonster.h" int init(); diff --git a/backends/libmmbackend.c b/backends/libmmbackend.c index 6320611..b27ebc5 100644 --- a/backends/libmmbackend.c +++ b/backends/libmmbackend.c @@ -53,7 +53,7 @@ int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* ad } int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){ - int fd = -1, status, yes = 1, flags; + int fd = -1, status, yes = 1; struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = socktype, @@ -106,12 +106,20 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){ } //set nonblocking - flags = fcntl(fd, F_GETFL, 0); + #ifdef _WIN32 + u_long mode = 1; + if(ioctlsocket(fd, FIONBIO, &mode) != NO_ERROR){ + closesocket(fd); + return 1; + } + #else + int flags = fcntl(fd, F_GETFL, 0); if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){ fprintf(stderr, "Failed to set socket nonblocking\n"); close(fd); return -1; } + #endif return fd; } diff --git a/backends/libmmbackend.h b/backends/libmmbackend.h index 38bfca0..77cad6a 100644 --- a/backends/libmmbackend.h +++ b/backends/libmmbackend.h @@ -1,14 +1,20 @@ #include #include #include +#ifdef _WIN32 +#include +//#define close closesocket +#else #include #include +#endif #include #include #include #include #include #include +#include "../portability.h" /* Parse spec as host specification in the form * host port diff --git a/backends/lua.c b/backends/lua.c index 4a910a2..ec02575 100644 --- a/backends/lua.c +++ b/backends/lua.c @@ -161,8 +161,6 @@ static int lua_callback_output(lua_State* interpreter){ static int lua_callback_interval(lua_State* interpreter){ size_t n = 0; - instance* inst = NULL; - lua_instance_data* data = NULL; uint64_t interval = 0; int reference = LUA_NOREF; @@ -174,8 +172,6 @@ static int lua_callback_interval(lua_State* interpreter){ //get instance pointer from registry lua_pushstring(interpreter, LUA_REGISTRY_KEY); lua_gettable(interpreter, LUA_REGISTRYINDEX); - inst = (instance*) lua_touserdata(interpreter, -1); - data = (lua_instance_data*) inst->impl; //fetch and round the interval interval = luaL_checkinteger(interpreter, 2); diff --git a/backends/osc.c b/backends/osc.c index 18c8bad..03e431f 100644 --- a/backends/osc.c +++ b/backends/osc.c @@ -1,8 +1,8 @@ #include #include #include -#include "libmmbackend.h" +#include "libmmbackend.h" #include "osc.h" /* @@ -480,14 +480,14 @@ static int osc_register_pattern(osc_instance_data* data, char* pattern_path, cha //parse min/max values token = strtok(NULL, " "); if(!token){ - fprintf(stderr, "Missing minimum specification for parameter %zu of OSC pattern %s\n", u, pattern_path); + fprintf(stderr, "Missing minimum specification for parameter %lu of OSC pattern %s\n", u, pattern_path); return 1; } data->pattern[pattern].min[u] = osc_parse_value_spec(format[u], token); token = strtok(NULL, " "); if(!token){ - fprintf(stderr, "Missing maximum specification for parameter %zu of OSC pattern %s\n", u, pattern_path); + fprintf(stderr, "Missing maximum specification for parameter %lu of OSC pattern %s\n", u, pattern_path); return 1; } data->pattern[pattern].max[u] = osc_parse_value_spec(format[u], token); @@ -689,7 +689,7 @@ static int osc_output_channel(instance* inst, size_t channel){ //write data if(offset + osc_data_length(data->channel[channel].type[p]) >= sizeof(xmit_buf)){ - fprintf(stderr, "Insufficient buffer size for OSC transmitting channel %s.%s at parameter %zu\n", inst->name, data->channel[channel].path, p); + fprintf(stderr, "Insufficient buffer size for OSC transmitting channel %s.%s at parameter %lu\n", inst->name, data->channel[channel].path, p); return 1; } @@ -720,7 +720,7 @@ static int osc_set(instance* inst, size_t num, channel** c, channel_value* v){ osc_instance_data* data = (osc_instance_data*) inst->impl; if(!data->dest_len){ - fprintf(stderr, "OSC instance %s does not have a destination, output is disabled (%zu channels)\n", inst->name, num); + fprintf(stderr, "OSC instance %s does not have a destination, output is disabled (%lu channels)\n", inst->name, num); return 0; } @@ -778,7 +778,7 @@ static int osc_process_packet(instance* inst, char* local_path, char* format, ui channel* chan = NULL; if(payload_len % 4){ - fprintf(stderr, "Invalid OSC packet, data length %zu\n", payload_len); + fprintf(stderr, "Invalid OSC packet, data length %lu\n", payload_len); return 0; } @@ -877,7 +877,11 @@ static int osc_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "OSC failed to receive data for instance %s: %s\n", inst->name, strerror(errno)); } @@ -924,7 +928,7 @@ static int osc_start(){ } } - fprintf(stderr, "OSC backend registered %zu descriptors to core\n", fds); + fprintf(stderr, "OSC backend registered %lu descriptors to core\n", fds); free(inst); return 0; diff --git a/backends/osc.h b/backends/osc.h index 4e9dec5..b2aaea7 100644 --- a/backends/osc.h +++ b/backends/osc.h @@ -1,6 +1,8 @@ #include "midimonster.h" #include +#ifndef _WIN32 #include +#endif #define OSC_RECV_BUF 8192 #define OSC_XMIT_BUF 8192 diff --git a/backends/sacn.c b/backends/sacn.c index 75bb76f..6f7d1a5 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -1,16 +1,18 @@ #include #include -#include -#include #include #include #include #include +#ifndef _WIN32 +#include #include +#include +#endif #include "libmmbackend.h" - #include "sacn.h" + //upper limit imposed by using the fd index as 16-bit part of the instance id #define MAX_FDS 4096 #define BACKEND_NAME "sacn" @@ -71,7 +73,7 @@ static int sacn_listener(char* host, char* port, uint8_t fd_flags){ return -1; } - fprintf(stderr, "sACN backend interface %zu bound to %s port %s\n", global_cfg.fds, host, port); + fprintf(stderr, "sACN backend interface %lu bound to %s port %s\n", global_cfg.fds, host, port); global_cfg.fd[global_cfg.fds].fd = fd; global_cfg.fd[global_cfg.fds].flags = fd_flags; global_cfg.fd[global_cfg.fds].universes = 0; @@ -271,7 +273,7 @@ static int sacn_transmit(instance* inst){ memcpy(pdu.data.source_name, global_cfg.source_name, sizeof(pdu.data.source_name)); memcpy((((uint8_t*)pdu.data.data) + 1), data->data.out, 512); - if(sendto(global_cfg.fd[data->fd_index].fd, &pdu, sizeof(pdu), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ + if(sendto(global_cfg.fd[data->fd_index].fd, (uint8_t*) &pdu, sizeof(pdu), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ fprintf(stderr, "Failed to output sACN frame for instance %s: %s\n", inst->name, strerror(errno)); } @@ -293,7 +295,7 @@ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ } if(!data->xmit_prio){ - fprintf(stderr, "sACN instance %s not enabled for output (%zu channel events)\n", inst->name, num); + fprintf(stderr, "sACN instance %s not enabled for output (%lu channel events)\n", inst->name, num); return 0; } @@ -378,7 +380,7 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame } if(!chan){ - fprintf(stderr, "Active channel %zu on %s not known to core", u, inst->name); + fprintf(stderr, "Active channel %lu on %s not known to core", u, inst->name); return 1; } @@ -445,8 +447,8 @@ static void sacn_discovery(size_t fd){ pdu.data.page = page; memcpy(pdu.data.data, global_cfg.fd[fd].universe + page * 512, universes * sizeof(uint16_t)); - if(sendto(global_cfg.fd[fd].fd, &pdu, sizeof(pdu) - (512 - universes) * sizeof(uint16_t), 0, (struct sockaddr*) &discovery_dest, sizeof(discovery_dest)) < 0){ - fprintf(stderr, "Failed to output sACN universe discovery frame for interface %zu: %s\n", fd, strerror(errno)); + if(sendto(global_cfg.fd[fd].fd, (uint8_t*) &pdu, sizeof(pdu) - (512 - universes) * sizeof(uint16_t), 0, (struct sockaddr*) &discovery_dest, sizeof(discovery_dest)) < 0){ + fprintf(stderr, "Failed to output sACN universe discovery frame for interface %lu: %s\n", fd, strerror(errno)); } } } @@ -512,7 +514,11 @@ static int sacn_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "sACN failed to receive data: %s\n", strerror(errno)); } @@ -577,7 +583,7 @@ static int sacn_start(){ if(!data->unicast_input){ mcast_req.imr_multiaddr.s_addr = htobe32(((uint32_t) 0xefff0000) | ((uint32_t) data->uni)); - if(setsockopt(global_cfg.fd[data->fd_index].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast_req, sizeof(mcast_req))){ + if(setsockopt(global_cfg.fd[data->fd_index].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (uint8_t*) &mcast_req, sizeof(mcast_req))){ fprintf(stderr, "Failed to join Multicast group for sACN universe %u on instance %s: %s\n", data->uni, inst[u]->name, strerror(errno)); } } @@ -604,7 +610,7 @@ static int sacn_start(){ } } - fprintf(stderr, "sACN backend registering %zu descriptors to core\n", global_cfg.fds); + fprintf(stderr, "sACN backend registering %lu descriptors to core\n", global_cfg.fds); for(u = 0; u < global_cfg.fds; u++){ //allocate memory for storing last frame transmission timestamp global_cfg.fd[u].last_frame = calloc(global_cfg.fd[u].universes, sizeof(uint64_t)); diff --git a/backends/sacn.h b/backends/sacn.h index e7106f7..7af2a36 100644 --- a/backends/sacn.h +++ b/backends/sacn.h @@ -1,4 +1,3 @@ -#include #include "midimonster.h" int init(); diff --git a/config.c b/config.c index 6d5fd16..93fb56d 100644 --- a/config.c +++ b/config.c @@ -20,6 +20,62 @@ typedef enum { static backend* current_backend = NULL; static instance* current_instance = NULL; +#ifdef _WIN32 +#define GETLINE_BUFFER 4096 + +static ssize_t getline(char** line, size_t* alloc, FILE* stream){ + size_t bytes_read = 0; + char c; + //sanity checks + if(!line || !alloc || !stream){ + return -1; + } + + //allocate buffer if none provided + if(!*line || !*alloc){ + *alloc = GETLINE_BUFFER; + *line = calloc(GETLINE_BUFFER, sizeof(char)); + if(!*line){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + } + + if(feof(stream)){ + return -1; + } + + for(c = fgetc(stream); 1; c = fgetc(stream)){ + //end of buffer, resize + if(bytes_read == (*alloc) - 1){ + *alloc += GETLINE_BUFFER; + *line = realloc(*line, (*alloc) * sizeof(char)); + if(!*line){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + } + + //store character + (*line)[bytes_read] = c; + + //end of line + if(feof(stream) || c == '\n'){ + //terminate string + (*line)[bytes_read + 1] = 0; + return bytes_read; + } + + //input broken + if(ferror(stream) || c < 0){ + return -1; + } + + bytes_read++; + } +} +#endif + static char* config_trim_line(char* in){ ssize_t n; //trim front diff --git a/midimonster.c b/midimonster.c index fb664a4..df27ca3 100644 --- a/midimonster.c +++ b/midimonster.c @@ -1,9 +1,14 @@ #include #include -#include #include #include #include +#ifndef _WIN32 +#include +#define MM_API __attribute__((visibility("default"))) +#else +#define MM_API __attribute__((dllexport)) +#endif #include "midimonster.h" #include "config.h" #include "backend.h" @@ -35,11 +40,14 @@ static void signal_handler(int signum){ shutdown_requested = 1; } -uint64_t mm_timestamp(){ +uint64_t MM_API mm_timestamp(){ return global_timestamp; } static void update_timestamp(){ + #ifdef _WIN32 + global_timestamp = GetTickCount(); + #else struct timespec current; if(clock_gettime(CLOCK_MONOTONIC_COARSE, ¤t)){ fprintf(stderr, "Failed to update global timestamp, time-based processing for some backends may be impaired: %s\n", strerror(errno)); @@ -47,6 +55,7 @@ static void update_timestamp(){ } global_timestamp = current.tv_sec * 1000 + current.tv_nsec / 1000000; + #endif } int mm_map_channel(channel* from, channel* to){ @@ -99,7 +108,7 @@ void map_free(){ map = NULL; } -int mm_manage_fd(int new_fd, char* back, int manage, void* impl){ +int MM_API mm_manage_fd(int new_fd, char* back, int manage, void* impl){ backend* b = backend_match(back); size_t u; @@ -163,7 +172,7 @@ void fds_free(){ fd = NULL; } -int mm_channel_event(channel* c, channel_value v){ +int MM_API mm_channel_event(channel* c, channel_value v){ size_t u, p; //find mapped channels @@ -229,7 +238,7 @@ static fd_set fds_collect(int* max_fd){ *max_fd = -1; } - DBGPF("Building selector set from %zu FDs registered to core\n", fds); + DBGPF("Building selector set from %lu FDs registered to core\n", fds); FD_ZERO(&rv_fds); for(u = 0; u < fds; u++){ if(fd[u].fd >= 0){ @@ -243,6 +252,17 @@ static fd_set fds_collect(int* max_fd){ return rv_fds; } +int platform_initialize(){ +#ifdef _WIN32 + WSADATA wsa; + WORD version = MAKEWORD(2, 2); + if(WSAStartup(version, &wsa)){ + return 1; + } +#endif + return 0; +} + int main(int argc, char** argv){ fd_set all_fds, read_fds; event_collection* secondary = NULL; @@ -255,6 +275,11 @@ int main(int argc, char** argv){ cfg_file = argv[1]; } + if(platform_initialize()){ + fprintf(stderr, "Failed to perform platform-specific initialization\n"); + return EXIT_FAILURE; + } + FD_ZERO(&all_fds); //initialize backends if(plugins_load(PLUGINS)){ @@ -316,14 +341,14 @@ int main(int argc, char** argv){ update_timestamp(); //run backend processing, collect events - DBGPF("%zu backend FDs signaled\n", n); + DBGPF("%lu backend FDs signaled\n", n); if(backends_handle(n, signaled_fds)){ goto bail; } while(primary->n){ //swap primary and secondary event collectors - DBGPF("Swapping event collectors, %zu events in primary\n", primary->n); + DBGPF("Swapping event collectors, %lu events in primary\n", primary->n); for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){ if(primary != event_pool + u){ secondary = primary; diff --git a/midimonster.h b/midimonster.h index 7f70f5b..eb118c6 100644 --- a/midimonster.h +++ b/midimonster.h @@ -4,6 +4,21 @@ #include #include +#ifndef MM_API + #ifdef _WIN32 + #define MM_API __attribute__((dllimport)) + #else + #define MM_API + #endif +#endif + +/* GCC ignores the visibility attributes on some API functions, so override visibility */ +#if !defined(_WIN32) && defined(__GNUC__) && !defined(__clang__) + #undef MM_API + #define MM_API + #pragma GCC visibility push(default) +#endif + /* Straight-forward min / max macros */ #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) @@ -187,7 +202,7 @@ typedef struct /*_mm_channel_mapping*/ { /* * Register a new backend. */ -int mm_backend_register(backend b); +int MM_API mm_backend_register(backend b); /* * Provides a pointer to a newly (zero-)allocated instance. @@ -201,7 +216,8 @@ int mm_backend_register(backend b); * mmbackend_shutdown procedure of the backend, eg. by querying * all instances for the backend. */ -instance* mm_instance(); +instance* MM_API mm_instance(); + /* * Finds an instance matching the specified backend and identifier. * Since setting an identifier for an instance is optional, @@ -209,7 +225,8 @@ instance* mm_instance(); * Instance identifiers may for example be set in the backends * mmbackend_start call. */ -instance* mm_instance_find(char* backend, uint64_t ident); +instance* MM_API mm_instance_find(char* backend, uint64_t ident); + /* * Provides a pointer to a channel structure, pre-filled with * the provided instance reference and identifier. @@ -224,30 +241,35 @@ instance* mm_instance_find(char* backend, uint64_t ident); * this function, the backend will receive a call to its channel_free * function. */ -channel* mm_channel(instance* i, uint64_t ident, uint8_t create); +channel* MM_API mm_channel(instance* i, uint64_t ident, uint8_t create); //TODO channel* mm_channel_find() + /* * Register (manage = 1) or unregister (manage = 0) a file descriptor * to be selected on. The backend will be notified when the descriptor * becomes ready to read via its registered mmbackend_process_fd call. */ -int mm_manage_fd(int fd, char* backend, int manage, void* impl); +int MM_API mm_manage_fd(int fd, char* backend, int manage, void* impl); + /* * Notifies the core of a channel event. Called by backends to * inject events gathered from their backing implementation. */ -int mm_channel_event(channel* c, channel_value v); +int MM_API mm_channel_event(channel* c, channel_value v); + /* * Query all active instances for a given backend. * *i will need to be freed by the caller. */ -int mm_backend_instances(char* backend, size_t* n, instance*** i); +int MM_API mm_backend_instances(char* backend, size_t* n, instance*** i); + /* * Query an internal timestamp, which is updated every core iteration. * This timestamp should not be used as a performance counter, but can be * used for timeouting. Resolution is milliseconds. */ -uint64_t mm_timestamp(); +uint64_t MM_API mm_timestamp(); + /* * Create a channel-to-channel mapping. This API should not * be used by backends. It is only exported for core modules. diff --git a/monster.cfg b/monster.cfg index 2e6f76f..2413f6d 100644 --- a/monster.cfg +++ b/monster.cfg @@ -1,18 +1,12 @@ [backend artnet] bind = 0.0.0.0 -[backend evdev] +[loopback loop] [artnet art] universe = 0 dest = 255.255.255.255 -[evdev mouse] -input = TPPS - -[loopback loop] - [map] -mouse.EV_REL.REL_X > loop.chan0 -art.{3..4}{4..3} > loop.chan{4..3}{3..4} -art.{1..10} > loop.data{1..10} + +art.1+2 > loop.b diff --git a/plugin.c b/plugin.c index fc642ac..a452559 100644 --- a/plugin.c +++ b/plugin.c @@ -1,11 +1,20 @@ #include #include -#include #include #include #include #include #include +#include "portability.h" +#ifdef _WIN32 +#define dlclose FreeLibrary +#define dlsym GetProcAddress +#define dlerror() "Failed" +#define dlopen(lib,ig) LoadLibrary(lib) +#else +#include +#endif + #include "plugin.h" static size_t plugins = 0; @@ -14,19 +23,29 @@ static void** plugin_handle = NULL; static int plugin_attach(char* path, char* file){ plugin_init init = NULL; void* handle = NULL; + char* lib = NULL; + char* error = NULL; - char* lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); + lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); if(!lib){ fprintf(stderr, "Failed to allocate memory\n"); return 1; } - snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file); handle = dlopen(lib, RTLD_NOW); if(!handle){ - fprintf(stderr, "Failed to load plugin %s: %s\n", lib, dlerror()); + #ifdef _WIN32 + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); + #else + error = dlerror(); + #endif + fprintf(stderr, "Failed to load plugin %s: %s\n", lib, error); free(lib); + #ifdef _WIN32 + LocalFree(error); + #endif return 0; } @@ -62,6 +81,38 @@ static int plugin_attach(char* path, char* file){ int plugins_load(char* path){ int rv = -1; +#ifdef _WIN32 + char* search_expression = calloc(strlen(path) + strlen("*.dll") + 1, sizeof(char)); + if(!search_expression){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + snprintf(search_expression, strlen(path) + strlen("*.dll"), "%s*.dll", path); + + WIN32_FIND_DATA result; + HANDLE hSearch = FindFirstFile(search_expression, &result); + + if(hSearch == INVALID_HANDLE_VALUE){ + LPVOID lpMsgBuf = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); + fprintf(stderr, "Failed to search for backend plugin files in %s: %s\n", path, lpMsgBuf); + LocalFree(lpMsgBuf); + return -1; + } + + do { + if(plugin_attach(path, result.cFileName)){ + goto load_done; + } + } while(FindNextFile(hSearch, &result)); + + rv = 0; +load_done: + free(search_expression); + FindClose(hSearch); + return rv; +#else struct dirent* entry; struct stat file_stat; DIR* directory = opendir(path); @@ -100,6 +151,7 @@ load_done: return -1; } return rv; +#endif } int plugins_close(){ diff --git a/portability.h b/portability.h index 25aee01..903ecd8 100644 --- a/portability.h +++ b/portability.h @@ -19,3 +19,20 @@ #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #endif + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include + #include + + #define htobe16(x) htons(x) + #define be16toh(x) ntohs(x) + + #define htobe32(x) htonl(x) + #define be32toh(x) ntohl(x) + + #define htobe64(x) _byteswap_uint64(x) + #define htole64(x) (x) + #define be64toh(x) _byteswap_uint64(x) + #define le64toh(x) (x) +#endif -- cgit v1.2.3 From 47a5f9a21bd661f9161d6175ebd074962daee255 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 7 Aug 2019 17:25:24 +0200 Subject: Fix export visibilities for GCC --- Makefile | 5 +---- backend.c | 10 +++++----- backend.h | 10 +++++----- backends/Makefile | 10 +++++++--- backends/midi.c | 6 ------ midimonster.c | 16 ++++++++-------- midimonster.h | 23 ++++++++--------------- 7 files changed, 34 insertions(+), 46 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index b82d6d8..57fe089 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ all: midimonster backends full: midimonster backends-full windows: midimonster.exe + $(MAKE) -C backends windows backends: $(MAKE) -C backends @@ -38,15 +39,11 @@ midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ midimonster.exe: export CC = x86_64-w64-mingw32-gcc -#midimonster.exe: CFLAGS += -Wno-format midimonster.exe: CFLAGS += -DPLUGINS=$(PLUGINDIR_W32) -Wno-format midimonster.exe: LDLIBS = -lws2_32 midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a midimonster.exe: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ - # The windows build for backends requires the import library generated with the build, - # so the backends can't be a prerequisite for the executable... - $(MAKE) -C backends windows clean: $(RM) midimonster diff --git a/backend.c b/backend.c index 4fa7704..3a18f41 100644 --- a/backend.c +++ b/backend.c @@ -71,7 +71,7 @@ int backends_notify(size_t nev, channel** c, channel_value* v){ return 0; } -channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create){ +MM_API channel* mm_channel(instance* inst, uint64_t ident, uint8_t create){ size_t u; for(u = 0; u < nchannels; u++){ if(channels[u]->instance == inst && channels[u]->ident == ident){ @@ -105,7 +105,7 @@ channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create){ return channels[nchannels++]; } -instance* MM_API mm_instance(){ +MM_API instance* mm_instance(){ instance** new_inst = realloc(instances, (ninstances + 1) * sizeof(instance*)); if(!new_inst){ //TODO free @@ -123,7 +123,7 @@ instance* MM_API mm_instance(){ return instances[ninstances++]; } -instance* MM_API mm_instance_find(char* name, uint64_t ident){ +MM_API instance* mm_instance_find(char* name, uint64_t ident){ size_t u; backend* b = backend_match(name); if(!b){ @@ -139,7 +139,7 @@ instance* MM_API mm_instance_find(char* name, uint64_t ident){ return NULL; } -int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst){ +MM_API int mm_backend_instances(char* name, size_t* ninst, instance*** inst){ backend* b = backend_match(name); size_t n = 0, u; //count number of affected instances @@ -237,7 +237,7 @@ struct timeval backend_timeout(){ return tv; } -int MM_API mm_backend_register(backend b){ +MM_API int mm_backend_register(backend b){ if(!backend_match(b.name)){ backends = realloc(backends, (nbackends + 1) * sizeof(backend)); if(!backends){ diff --git a/backend.h b/backend.h index 7529154..6573e17 100644 --- a/backend.h +++ b/backend.h @@ -12,8 +12,8 @@ void instances_free(); void channels_free(); /* Backend API */ -channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create); -instance* MM_API mm_instance(); -instance* MM_API mm_instance_find(char* name, uint64_t ident); -int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst); -int MM_API mm_backend_register(backend b); +MM_API channel* mm_channel(instance* inst, uint64_t ident, uint8_t create); +MM_API instance* mm_instance(); +MM_API instance* mm_instance_find(char* name, uint64_t ident); +MM_API int mm_backend_instances(char* name, size_t* ninst, instance*** inst); +MM_API int mm_backend_register(backend b); diff --git a/backends/Makefile b/backends/Makefile index 2374df0..3308ef0 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -1,8 +1,8 @@ .PHONY: all clean full -OPTIONAL_BACKENDS = ola.so -WINDOWS_BACKENDS = loopback.dll artnet.dll osc.dll sacn.dll LINUX_BACKENDS = midi.so evdev.so -BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so +WINDOWS_BACKENDS = artnet.dll osc.dll loopback.dll sacn.dll maweb.dll +BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so maweb.so +OPTIONAL_BACKENDS = ola.so BACKEND_LIB = libmmbackend.o SYSTEM := $(shell uname -s) @@ -32,6 +32,10 @@ sacn.so: ADDITIONAL_OBJS += $(BACKEND_LIB) sacn.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) sacn.dll: LDLIBS += -lws2_32 +maweb.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +maweb.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +maweb.dll: LDLIBS += -lws2_32 + midi.so: LDLIBS = -lasound evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev) evdev.so: LDLIBS = $(shell pkg-config --libs libevdev) diff --git a/backends/midi.c b/backends/midi.c index c1480c0..9c6ba80 100644 --- a/backends/midi.c +++ b/backends/midi.c @@ -14,12 +14,6 @@ typedef union { uint64_t label; } midi_channel_ident; -/* - * TODO - * Optionally send note-off messages - * Optionally send updates as after-touch - */ - enum /*_midi_channel_type*/ { none = 0, note, diff --git a/midimonster.c b/midimonster.c index df27ca3..1e47698 100644 --- a/midimonster.c +++ b/midimonster.c @@ -40,7 +40,7 @@ static void signal_handler(int signum){ shutdown_requested = 1; } -uint64_t MM_API mm_timestamp(){ +MM_API uint64_t mm_timestamp(){ return global_timestamp; } @@ -98,7 +98,7 @@ int mm_map_channel(channel* from, channel* to){ return 0; } -void map_free(){ +static void map_free(){ size_t u; for(u = 0; u < mappings; u++){ free(map[u].to); @@ -108,7 +108,7 @@ void map_free(){ map = NULL; } -int MM_API mm_manage_fd(int new_fd, char* back, int manage, void* impl){ +MM_API int mm_manage_fd(int new_fd, char* back, int manage, void* impl){ backend* b = backend_match(back); size_t u; @@ -158,7 +158,7 @@ int MM_API mm_manage_fd(int new_fd, char* back, int manage, void* impl){ return 0; } -void fds_free(){ +static void fds_free(){ size_t u; for(u = 0; u < fds; u++){ //TODO free impl @@ -172,7 +172,7 @@ void fds_free(){ fd = NULL; } -int MM_API mm_channel_event(channel* c, channel_value v){ +MM_API int mm_channel_event(channel* c, channel_value v){ size_t u, p; //find mapped channels @@ -213,7 +213,7 @@ int MM_API mm_channel_event(channel* c, channel_value v){ return 0; } -void event_free(){ +static void event_free(){ size_t u; for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){ @@ -223,7 +223,7 @@ void event_free(){ } } -int usage(char* fn){ +static int usage(char* fn){ fprintf(stderr, "MIDIMonster v0.1\n"); fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t%s \n", fn); @@ -252,7 +252,7 @@ static fd_set fds_collect(int* max_fd){ return rv_fds; } -int platform_initialize(){ +static int platform_initialize(){ #ifdef _WIN32 WSADATA wsa; WORD version = MAKEWORD(2, 2); diff --git a/midimonster.h b/midimonster.h index eb118c6..270a61f 100644 --- a/midimonster.h +++ b/midimonster.h @@ -12,13 +12,6 @@ #endif #endif -/* GCC ignores the visibility attributes on some API functions, so override visibility */ -#if !defined(_WIN32) && defined(__GNUC__) && !defined(__clang__) - #undef MM_API - #define MM_API - #pragma GCC visibility push(default) -#endif - /* Straight-forward min / max macros */ #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) @@ -202,7 +195,7 @@ typedef struct /*_mm_channel_mapping*/ { /* * Register a new backend. */ -int MM_API mm_backend_register(backend b); +MM_API int mm_backend_register(backend b); /* * Provides a pointer to a newly (zero-)allocated instance. @@ -216,7 +209,7 @@ int MM_API mm_backend_register(backend b); * mmbackend_shutdown procedure of the backend, eg. by querying * all instances for the backend. */ -instance* MM_API mm_instance(); +MM_API instance* mm_instance(); /* * Finds an instance matching the specified backend and identifier. @@ -225,7 +218,7 @@ instance* MM_API mm_instance(); * Instance identifiers may for example be set in the backends * mmbackend_start call. */ -instance* MM_API mm_instance_find(char* backend, uint64_t ident); +MM_API instance* mm_instance_find(char* backend, uint64_t ident); /* * Provides a pointer to a channel structure, pre-filled with @@ -241,7 +234,7 @@ instance* MM_API mm_instance_find(char* backend, uint64_t ident); * this function, the backend will receive a call to its channel_free * function. */ -channel* MM_API mm_channel(instance* i, uint64_t ident, uint8_t create); +MM_API channel* mm_channel(instance* i, uint64_t ident, uint8_t create); //TODO channel* mm_channel_find() /* @@ -249,26 +242,26 @@ channel* MM_API mm_channel(instance* i, uint64_t ident, uint8_t create); * to be selected on. The backend will be notified when the descriptor * becomes ready to read via its registered mmbackend_process_fd call. */ -int MM_API mm_manage_fd(int fd, char* backend, int manage, void* impl); +MM_API int mm_manage_fd(int fd, char* backend, int manage, void* impl); /* * Notifies the core of a channel event. Called by backends to * inject events gathered from their backing implementation. */ -int MM_API mm_channel_event(channel* c, channel_value v); +MM_API int mm_channel_event(channel* c, channel_value v); /* * Query all active instances for a given backend. * *i will need to be freed by the caller. */ -int MM_API mm_backend_instances(char* backend, size_t* n, instance*** i); +MM_API int mm_backend_instances(char* backend, size_t* n, instance*** i); /* * Query an internal timestamp, which is updated every core iteration. * This timestamp should not be used as a performance counter, but can be * used for timeouting. Resolution is milliseconds. */ -uint64_t MM_API mm_timestamp(); +MM_API uint64_t mm_timestamp(); /* * Create a channel-to-channel mapping. This API should not -- cgit v1.2.3 From b4b27aa4a90899d5b025bbef11d444d4c47800d9 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 23 Aug 2019 19:47:53 +0200 Subject: Finalize & publish maweb backend --- Makefile | 2 +- README.md | 2 ++ backends/maweb.c | 92 ++++++++++++++++++++++++++++++++----------------------- backends/maweb.md | 6 +--- 4 files changed, 58 insertions(+), 44 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 57fe089..2d88c49 100644 --- a/Makefile +++ b/Makefile @@ -56,5 +56,5 @@ run: valgrind --leak-check=full --show-leak-kinds=all ./midimonster sanitize: export CC = clang -sanitize: export CFLAGS = -g -Wall -Wpedantic -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer +sanitize: export CFLAGS += -g -Wall -Wpedantic -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer sanitize: midimonster backends diff --git a/README.md b/README.md index 40f8fbb..5c4233f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Currently, the MIDIMonster supports the following protocols: * OpenSoundControl (OSC) * evdev input devices (Linux) * Open Lighting Architecture (OLA) +* MA Lighting Web Remote with additional flexibility provided by a Lua scripting environment. @@ -121,6 +122,7 @@ special information. These documentation files are located in the `backends/` di * [`ola` backend documentation](backends/ola.md) * [`osc` backend documentation](backends/osc.md) * [`lua` backend documentation](backends/lua.md) +* [`maweb` backend documentation](backends/maweb.md) ## Building diff --git a/backends/maweb.c b/backends/maweb.c index 9ba04fa..4e6fad1 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -266,14 +266,17 @@ static channel* maweb_channel(instance* inst, char* spec){ ident.fields.index--; ident.fields.page--; - //check if the channel is already known + //check if the (exec/meta) channel is already known for(n = 0; n < data->input_channels; n++){ - if(data->input_channel[n].label == ident.label){ + if(data->input_channel[n].fields.page == ident.fields.page + && data->input_channel[n].fields.index == ident.fields.index){ break; } } - if(n == data->input_channels){ + //FIXME only register channels that are mapped as outputs + //only register exec channels for updates + if(n == data->input_channels && ident.fields.type != cmdline_button){ data->input_channel = realloc(data->input_channel, (data->input_channels + 1) * sizeof(maweb_channel_ident)); if(!data->input_channel){ fprintf(stderr, "Failed to allocate memory\n"); @@ -324,9 +327,9 @@ static int maweb_send_frame(instance* inst, maweb_operation op, uint8_t* payload static int maweb_process_playback(instance* inst, int64_t page, maweb_channel_type metatype, char* payload, size_t payload_length){ size_t exec_blocks = json_obj_offset(payload, (metatype == 2) ? "executorBlocks" : "bottomButtons"), offset, block = 0, control; channel* chan = NULL; - channel_value evt; + channel_value evt; maweb_channel_ident ident = { - .fields.page = page, + .fields.page = page - 1, .fields.index = json_obj_int(payload, "iExec", 191) }; @@ -335,10 +338,11 @@ static int maweb_process_playback(instance* inst, int64_t page, maweb_channel_ty //ignore unused buttons return 0; } - fprintf(stderr, "maweb missing exec block data on exec %d\n", ident.fields.index); + fprintf(stderr, "maweb missing exec block data on exec %ld.%d\n", page, ident.fields.index); return 1; } + //the bottomButtons key has an additional subentry if(metatype == 3){ exec_blocks += json_obj_offset(payload + exec_blocks, "items"); } @@ -363,7 +367,7 @@ static int maweb_process_playback(instance* inst, int64_t page, maweb_channel_ty mm_channel_event(chan, evt); } - //printf("maweb page %ld exec %d value %f running %lu\n", page, ident.fields.index, json_obj_double(payload + control, "v", 0.0), json_obj_int(payload, "isRun", 0)); + DBGPF("maweb page %ld exec %d value %f running %lu\n", page, ident.fields.index, json_obj_double(payload + control, "v", 0.0), json_obj_int(payload, "isRun", 0)); ident.fields.index++; block++; } @@ -416,7 +420,7 @@ static int maweb_process_playbacks(instance* inst, int64_t page, char* payload, group++; } updates_inflight--; - fprintf(stderr, "maweb playback message processing done, %lu updates inflight\n", updates_inflight); + DBGPF("maweb playback message processing done, %lu updates inflight\n", updates_inflight); return 0; } @@ -425,45 +429,53 @@ static int maweb_request_playbacks(instance* inst){ char xmit_buffer[MAWEB_XMIT_CHUNK]; int rv = 0; - char item_indices[1024] = "[0,100,200]", item_counts[1024] = "[21,21,21]", item_types[1024] = "[2,3,3]"; - //char item_indices[1024] = "[300,400]", item_counts[1024] = "[18,18]", item_types[1024] = "[3,3]"; - size_t page_index = 0, view = 2, channel = 0, offsets[3], channel_offset, channels; + char item_indices[1024] = "[300,400,500]", item_counts[1024] = "[16,16,16]", item_types[1024] = "[3,3,3]"; + size_t page_index = 0, view = 3, channel = 0, offsets[3], channel_offset, channels; if(updates_inflight){ fprintf(stderr, "maweb skipping update request, %lu updates still inflight\n", updates_inflight); return 0; } + //don't quote me on this whole segment for(channel = 0; channel < data->input_channels; channel++){ - offsets[0] = offsets[1] = offsets[2] = 0; + offsets[0] = offsets[1] = offsets[2] = 1; page_index = data->input_channel[channel].fields.page; if(data->peer_type == peer_dot2){ - //TODO implement poll segmentation for dot - //"\"startIndex\":[0,100,200]," - //"\"itemsCount\":[21,21,21]," - //"\"itemsType\":[2,3,3]," - //"\"view\":2," - //view = (data->input_channel[channel].fields.index >= 300) ? 3 : 2; - //observed - //"startIndex":[300,400,500,600,700,800], - //"itemsCount":[13,13,13,13,13,13] - //"itemsType":[3,3,3,3,3,3] - /*fprintf(stderr, "range start at %lu.%lu (%lu/%lu) end at %lu.%lu (%lu/%lu)\n", - page_index, - data->input_channel[channel].fields.index, - channel, - data->input_channels, - page_index, - data->input_channel[channel + channel_offset - 1].fields.index, - channel + channel_offset - 1, - data->input_channels - );*/ - //only send one request currently - channel = data->input_channels; + //blocks 0, 100 & 200 have 21 execs and need to be queried from fader view + view = (data->input_channel[channel].fields.index >= 300) ? 3 : 2; + + for(channel_offset = 1; channel + channel_offset <= data->input_channels; channel_offset++){ + channels = channel + channel_offset - 1; + //find end for this exec block + for(; channel + channel_offset < data->input_channels; channel_offset++){ + if(data->input_channel[channel + channel_offset].fields.page != page_index + || (data->input_channel[channels].fields.index / 100) != (data->input_channel[channel + channel_offset].fields.index / 100)){ + break; + } + } + + //add request block for the exec block + offsets[0] += snprintf(item_indices + offsets[0], sizeof(item_indices) - offsets[0], "%d,", data->input_channel[channels].fields.index); + offsets[1] += snprintf(item_counts + offsets[1], sizeof(item_counts) - offsets[1], "%d,", data->input_channel[channel + channel_offset - 1].fields.index - data->input_channel[channels].fields.index + 1); + offsets[2] += snprintf(item_types + offsets[2], sizeof(item_types) - offsets[2], "%d,", (data->input_channel[channels].fields.index < 100) ? 2 : 3); + + //send on page boundary, metamode boundary, last channel + if(channel + channel_offset >= data->input_channels + || data->input_channel[channel + channel_offset].fields.page != page_index + || (data->input_channel[channel].fields.index < 300) != (data->input_channel[channel + channel_offset].fields.index < 300)){ + break; + } + } + + //terminate arrays (overwriting the last array separator) + offsets[0] += snprintf(item_indices + offsets[0] - 1, sizeof(item_indices) - offsets[0], "]"); + offsets[1] += snprintf(item_counts + offsets[1] - 1, sizeof(item_counts) - offsets[1], "]"); + offsets[2] += snprintf(item_types + offsets[2] - 1, sizeof(item_types) - offsets[2], "]"); } else{ + //for the ma, the view equals the exec type requested (we can query all button execs from button view, all fader execs from fader view) view = (data->input_channel[channel].fields.index >= 100) ? 3 : 2; - //for the ma, the view equals the exec type snprintf(item_types, sizeof(item_types), "[%lu]", view); //this channel must be included, so it must be in range for the first startindex snprintf(item_indices, sizeof(item_indices), "[%d]", (data->input_channel[channel].fields.index / 5) * 5); @@ -476,8 +488,12 @@ static int maweb_request_playbacks(instance* inst){ channels = data->input_channel[channel + channel_offset - 1].fields.index - (data->input_channel[channel].fields.index / 5) * 5; snprintf(item_counts, sizeof(item_indices), "[%lu]", ((channels / 5) * 5 + 5)); - channel += channel_offset - 1; } + + //advance base channel + channel += channel_offset - 1; + + //send current request snprintf(xmit_buffer, sizeof(xmit_buffer), "{" "\"requestType\":\"playbacks\"," @@ -497,7 +513,7 @@ static int maweb_request_playbacks(instance* inst){ view, data->session); rv |= maweb_send_frame(inst, ws_text, (uint8_t*) xmit_buffer, strlen(xmit_buffer)); - //fprintf(stderr, "req: %s\n", xmit_buffer); + DBGPF("maweb poll request: %s\n", xmit_buffer); updates_inflight++; } @@ -530,7 +546,7 @@ static int maweb_handle_message(instance* inst, char* payload, size_t payload_le } } - fprintf(stderr, "maweb message (%lu): %s\n", payload_length, payload); + DBGPF("maweb message (%lu): %s\n", payload_length, payload); if(json_obj(payload, "session") == JSON_NUMBER){ data->session = json_obj_int(payload, "session", data->session); fprintf(stderr, "maweb session id is now %ld\n", data->session); diff --git a/backends/maweb.md b/backends/maweb.md index f3b40b6..9fe4790 100644 --- a/backends/maweb.md +++ b/backends/maweb.md @@ -109,8 +109,4 @@ Data input from the console is done by actively querying the state of all mapped at low latency. A lower input interval value will produce data with lower latency, at the cost of network & CPU usage. Higher values will make the input "step" more, but will not consume as many CPU cycles and network bandwidth. -This backend is currently in active development. It therefore has some limitations: - -* It outputs a lot of debug information -* Command line events are sent, but I'm not sure they're being handled yet -* For the dot2, currently only the Core & F-Wings are supported for input from the console, not the B-Wings +Command line events are sent, but I'm not sure they're being handled yet. -- cgit v1.2.3 From 350f0d2d2eaff5f0d57b09857102e2df1e96d733 Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 7 Nov 2019 18:44:19 +0100 Subject: Makefile install target and packaging instructions (Fixes #28) --- Makefile | 22 +++++++++++++++++----- README.md | 23 +++++++++++++++++++++++ backends/lua.md | 5 +---- backends/maweb.c | 2 +- backends/winmidi.c | 2 +- config.c | 38 +++++++++++++++++++++++++++++++++++--- configs/flying-faders.cfg | 2 +- configs/lua.cfg | 2 +- midimonster.h | 13 ++++++++++++- plugin.c | 12 ++++++++++-- 10 files changed, 102 insertions(+), 19 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 2d88c49..5a83a2d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ -.PHONY: all clean run sanitize backends windows full backends-full +.PHONY: all clean run sanitize backends windows full backends-full install OBJS = config.o backend.o plugin.o -PLUGINDIR = "\"./backends/\"" -PLUGINDIR_W32 = "\"backends\\\\\"" +PREFIX ?= /usr SYSTEM := $(shell uname -s) CFLAGS ?= -g -Wall -Wpedantic @@ -11,7 +10,6 @@ CFLAGS += -fvisibility=hidden #CFLAGS += -DDEBUG midimonster: LDLIBS = -ldl -midimonster: CFLAGS += -DPLUGINS=$(PLUGINDIR) # Work around strange linker passing convention differences in Linux and OSX ifeq ($(SYSTEM),Linux) @@ -21,6 +19,14 @@ ifeq ($(SYSTEM),Darwin) midimonster: LDFLAGS += -Wl,-export_dynamic endif +# Allow overriding the locations for backend plugins and default configuration +ifdef DEFAULT_CFG +midimonster: CFLAGS += -DDEFAULT_CFG=\"$(DEFAULT_CFG)\" +endif +ifdef PLUGINS +midimonster: CFLAGS += -DPLUGINS=\"$(PLUGINS)\" +endif + all: midimonster backends full: midimonster backends-full @@ -39,7 +45,7 @@ midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ midimonster.exe: export CC = x86_64-w64-mingw32-gcc -midimonster.exe: CFLAGS += -DPLUGINS=$(PLUGINDIR_W32) -Wno-format +midimonster.exe: CFLAGS += -Wno-format midimonster.exe: LDLIBS = -lws2_32 midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a midimonster.exe: midimonster.c portability.h $(OBJS) @@ -55,6 +61,12 @@ clean: run: valgrind --leak-check=full --show-leak-kinds=all ./midimonster +install: + install -d "$(DESTDIR)$(PREFIX)/bin" + install -d "$(DESTDIR)$(PREFIX)/lib/midimonster" + install -m 0755 midimonster "$(DESTDIR)$(PREFIX)/bin" + install -m 0755 backends/*.so "$(DESTDIR)$(PREFIX)/lib/midimonster" + sanitize: export CC = clang sanitize: export CFLAGS += -g -Wall -Wpedantic -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer sanitize: midimonster backends diff --git a/README.md b/README.md index 130945a..c31f16c 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,16 @@ be used to build a subset of the backends as well as the core. For Linux and OSX, just running `make` in the source directory should do the trick. +The build process accepts the following parameters, either from the environment or +as arguments to the `make` invocation: + +| Target | Parameter | Default value | Description | +|---------------|-----------------------|-------------------------------|-------------------------------| +| build targets | `DEFAULT_CFG` | `monster.cfg` | Default configuration file | +| build targets | `PLUGINS` | Linux/OSX: `./backends/`, Windows: `backends\` | Backend plugin library path | +| `install` | `DESTDIR` | empty | Destination directory for packaging builds | +| `install` | `PREFIX` | `/usr` | Install prefix for binaries | + Some backends have been marked as optional as they require rather large additional software to be installed, for example the `ola` backend. To create a build including these, run `make full`. @@ -163,6 +173,19 @@ To build for Windows, you still need to compile on a Linux machine. Install the crosscompiler package listed above and run `make windows`. This will build `midimonster.exe` as well as a set of backends as DLL files. +For system-wide install or packaging builds, the following steps are recommended: + +``` +export PREFIX=/usr +export PLUGINS=$PREFIX/lib/midimonster +export DEFAULT_CFG=/etc/midimonster.cfg +make +make install +``` + +Depending on your configuration of `DESTDIR`, the `make install` step may require root privileges to +install the binaries to the appropriate destinations. + ## Development The architecture is split into the `midimonster` core, handling mapping diff --git a/backends/lua.md b/backends/lua.md index 6ad5c2a..f38e189 100644 --- a/backends/lua.md +++ b/backends/lua.md @@ -43,7 +43,7 @@ The `lua` backend does not take any global configuration. | Option | Example value | Default value | Description | |---------------|-----------------------|-----------------------|-----------------------| -| `script` | `script.lua` | none | Lua source file | +| `script` | `script.lua` | none | Lua source file (relative to configuration file)| A single instance may have multiple `source` options specified, which will all be read cumulatively. @@ -64,6 +64,3 @@ Using these names as arguments to the output and value interface functions works Output values will not trigger corresponding input event handlers unless the channel is mapped back in the MIDIMonster configuration. - -The path to the Lua source files is relative to the current working directory. This may lead -to problems when copying configuration between installations. diff --git a/backends/maweb.c b/backends/maweb.c index c98d04b..57d04ae 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -470,7 +470,7 @@ static int maweb_request_playbacks(instance* inst){ offsets[0] = offsets[1] = offsets[2] = 1; page_index = data->channel[channel].page; //poll logic differs between the consoles because reasons - //dont quote me on this section + //don't quote me on this section if(data->peer_type == peer_dot2){ //blocks 0, 100 & 200 have 21 execs and need to be queried from fader view view = (data->channel[channel].index >= 300) ? 3 : 2; diff --git a/backends/winmidi.c b/backends/winmidi.c index de7d867..d6bc0bc 100644 --- a/backends/winmidi.c +++ b/backends/winmidi.c @@ -84,7 +84,7 @@ static int winmidi_configure_instance(instance* inst, char* option, char* value) } if(!strcmp(option, "write")){ if(data->write){ - fprintf(stderr, "winmidi instance %s already connected to an otput device\n", inst->name); + fprintf(stderr, "winmidi instance %s already connected to an output device\n", inst->name); return 1; } data->write = strdup(value); diff --git a/config.c b/config.c index f4d928e..ddee720 100644 --- a/config.c +++ b/config.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "midimonster.h" #include "config.h" #include "backend.h" @@ -310,16 +312,45 @@ done: return rv; } -int config_read(char* cfg_file){ +int config_read(char* cfg_filepath){ int rv = 1; size_t line_alloc = 0; ssize_t status; map_type mapping_type = map_rtl; char* line_raw = NULL, *line, *separator; - FILE* source = fopen(cfg_file, "r"); + + //create heap copy of file name because original might be in readonly memory + char* source_dir = strdup(cfg_filepath), *source_file = NULL; + #ifdef _WIN32 + char path_separator = '\\'; + #else + char path_separator = '/'; + #endif + + if(!source_dir){ + fprintf(stderr, "Failed to allocate memory\n"); + return 1; + } + + //change working directory to the one containing the configuration file so relative paths work as expected + source_file = strrchr(source_dir, path_separator); + if(source_file){ + *source_file = 0; + source_file++; + if(chdir(source_dir)){ + fprintf(stderr, "Failed to change to configuration file directory %s: %s\n", source_dir, strerror(errno)); + goto bail; + } + } + else{ + source_file = source_dir; + } + + FILE* source = fopen(source_file, "r"); + if(!source){ fprintf(stderr, "Failed to open configuration file for reading\n"); - return 1; + goto bail; } for(status = getline(&line_raw, &line_alloc, source); status >= 0; status = getline(&line_raw, &line_alloc, source)){ @@ -459,6 +490,7 @@ int config_read(char* cfg_file){ rv = 0; bail: + free(source_dir); fclose(source); free(line_raw); return rv; diff --git a/configs/flying-faders.cfg b/configs/flying-faders.cfg index 4197581..d331f38 100644 --- a/configs/flying-faders.cfg +++ b/configs/flying-faders.cfg @@ -13,7 +13,7 @@ dest = learn@9000 /1/xy = ff 0.0 1.0 0.0 1.0 [lua generator] -script = configs/flying-faders.lua +script = flying-faders.lua [map] diff --git a/configs/lua.cfg b/configs/lua.cfg index af17496..098c0f1 100644 --- a/configs/lua.cfg +++ b/configs/lua.cfg @@ -13,7 +13,7 @@ axis.ABS_X = 34300 0 65535 255 4095 axis.ABS_Y = 34300 0 65535 255 4095 [lua lua] -script = configs/demo.lua +script = demo.lua [artnet art] universe = 0 diff --git a/midimonster.h b/midimonster.h index 491cc11..b05326c 100644 --- a/midimonster.h +++ b/midimonster.h @@ -33,7 +33,18 @@ #include "portability.h" /* Default configuration file name to read when no other is specified */ -#define DEFAULT_CFG "monster.cfg" +#ifndef DEFAULT_CFG + #define DEFAULT_CFG "monster.cfg" +#endif + +/* Default backend plugin location */ +#ifndef PLUGINS + #ifndef _WIN32 + #define PLUGINS "./backends/" + #else + #define PLUGINS "backends\\" + #endif +#endif /* Forward declare some of the structs so we can use them in each other */ struct _channel_value; diff --git a/plugin.c b/plugin.c index dd99041..a14baff 100644 --- a/plugin.c +++ b/plugin.c @@ -24,13 +24,21 @@ static int plugin_attach(char* path, char* file){ plugin_init init = NULL; void* handle = NULL; char* lib = NULL; + #ifdef _WIN32 + char* path_separator = "\\"; + #else + char* path_separator = "/"; + #endif - lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); + lib = calloc(strlen(path) + strlen(file) + 2, sizeof(char)); if(!lib){ fprintf(stderr, "Failed to allocate memory\n"); return 1; } - snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file); + snprintf(lib, strlen(path) + strlen(file) + 2, "%s%s%s", + path, + (path[strlen(path)] == path_separator[0]) ? "" : path_separator, + file); handle = dlopen(lib, RTLD_NOW); if(!handle){ -- cgit v1.2.3 From aed52ce3e67f35c69ef1295f770a012258167496 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 10 Nov 2019 14:24:51 +0100 Subject: Actually use plugin install path in Makefile --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 5a83a2d..40570c8 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ OBJS = config.o backend.o plugin.o PREFIX ?= /usr +PLUGIN_INSTALL = "$(PREFIX)/lib/midimonster" SYSTEM := $(shell uname -s) CFLAGS ?= -g -Wall -Wpedantic @@ -25,6 +26,7 @@ midimonster: CFLAGS += -DDEFAULT_CFG=\"$(DEFAULT_CFG)\" endif ifdef PLUGINS midimonster: CFLAGS += -DPLUGINS=\"$(PLUGINS)\" +PLUGIN_INSTALL = $(PLUGINS) endif all: midimonster backends @@ -63,7 +65,7 @@ run: install: install -d "$(DESTDIR)$(PREFIX)/bin" - install -d "$(DESTDIR)$(PREFIX)/lib/midimonster" + install -d "$(DESTDIR)$(PLUGIN_INSTALL)" install -m 0755 midimonster "$(DESTDIR)$(PREFIX)/bin" install -m 0755 backends/*.so "$(DESTDIR)$(PREFIX)/lib/midimonster" -- cgit v1.2.3 From 5b840d986ae723656aad4163e12f7d24a88e1da3 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 1 Dec 2019 12:56:22 +0100 Subject: Add configuration files and examples to install target --- Makefile | 11 ++++++++--- monster.cfg | 40 ++++------------------------------------ 2 files changed, 12 insertions(+), 39 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 40570c8..caad174 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ OBJS = config.o backend.o plugin.o PREFIX ?= /usr -PLUGIN_INSTALL = "$(PREFIX)/lib/midimonster" +PLUGIN_INSTALL = $(PREFIX)/lib/midimonster SYSTEM := $(shell uname -s) CFLAGS ?= -g -Wall -Wpedantic @@ -65,9 +65,14 @@ run: install: install -d "$(DESTDIR)$(PREFIX)/bin" - install -d "$(DESTDIR)$(PLUGIN_INSTALL)" install -m 0755 midimonster "$(DESTDIR)$(PREFIX)/bin" - install -m 0755 backends/*.so "$(DESTDIR)$(PREFIX)/lib/midimonster" + install -d "$(DESTDIR)$(PLUGIN_INSTALL)" + install -m 0755 backends/*.so "$(DESTDIR)$(PLUGIN_INSTALL)" + install -d "$(DESTDIR)$(PREFIX)/share/midimonster" + install -m 0644 configs/* "$(DESTDIR)$(PREFIX)/share/midimonster" +ifdef DEFAULT_CFG + install -m 0644 monster.cfg "$(DESTDIR)$(DEFAULT_CFG)" +endif sanitize: export CC = clang sanitize: export CFLAGS += -g -Wall -Wpedantic -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer diff --git a/monster.cfg b/monster.cfg index e6258a7..8e415a3 100644 --- a/monster.cfg +++ b/monster.cfg @@ -1,39 +1,7 @@ -[backend artnet] -bind = 0.0.0.0 - +; This is a useless default configuration +; Replace it with a proper one from the configs/ directory or write your own :) [loopback loop] -[artnet art] -universe = 0 -dest = 255.255.255.255 - -[backend midi] -detect = on - -[backend evdev] -;detect = on - -[midi bcf] -read = BCF -write = BCF - -[evdev mouse] -input = TPPS -relaxis.REL_X = 255 -relaxis.REL_Y = -255 - -[maweb ma] -;host = 10.23.23.248 -host = 127.0.0.1 4040 -user = web -password = web - [map] -bcf.channel{0..7}.pitch > bcf.channel{0..7}.pitch -bcf.channel{0..7}.pitch > art.{1..8} - -bcf.channel{0..7}.pitch > ma.page1.fader{1..8} -bcf.channel0.note{16..23} > ma.page1.upper{1..8} -bcf.channel0.note{24..31} > ma.page1.lower{1..8} -mouse.EV_REL.REL_Y > ma.page1.fader1 -mouse.EV_KEY.BTN_LEFT > ma.page2.button102 +loop.a > loop.b +loop.b < loop.c -- cgit v1.2.3 From bb6e54e99b86a71fcc300890b41b49209245ac61 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 4 Dec 2019 21:48:25 +0100 Subject: Have the configuration file be installed in a separate directory --- LICENSE.txt | 2 +- Makefile | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Makefile') diff --git a/LICENSE.txt b/LICENSE.txt index 3d2ec64..95db371 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2017, cbdev/FJS +Copyright (c) 2017, cbdev/Fabian J. Stumpf All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile b/Makefile index caad174..8b2d7ec 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ install: install -d "$(DESTDIR)$(PREFIX)/share/midimonster" install -m 0644 configs/* "$(DESTDIR)$(PREFIX)/share/midimonster" ifdef DEFAULT_CFG - install -m 0644 monster.cfg "$(DESTDIR)$(DEFAULT_CFG)" + install -Dm 0644 monster.cfg "$(DESTDIR)$(DEFAULT_CFG)" endif sanitize: export CC = clang diff --git a/README.md b/README.md index 83cd06b..bcae9dd 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ For system-wide install or packaging builds, the following steps are recommended ``` export PREFIX=/usr export PLUGINS=$PREFIX/lib/midimonster -export DEFAULT_CFG=/etc/midimonster.cfg +export DEFAULT_CFG=/etc/midimonster/midimonster.cfg make clean make full make install -- cgit v1.2.3 From 96fe966928cd83f22aed388a11013b67c1a374a1 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 6 Dec 2019 18:58:59 +0100 Subject: Make install path for examples configurable --- Makefile | 5 +++-- README.md | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 8b2d7ec..8dab638 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ OBJS = config.o backend.o plugin.o PREFIX ?= /usr PLUGIN_INSTALL = $(PREFIX)/lib/midimonster +EXAMPLES ?= $(PREFIX)/share/midimonster SYSTEM := $(shell uname -s) CFLAGS ?= -g -Wall -Wpedantic @@ -68,8 +69,8 @@ install: install -m 0755 midimonster "$(DESTDIR)$(PREFIX)/bin" install -d "$(DESTDIR)$(PLUGIN_INSTALL)" install -m 0755 backends/*.so "$(DESTDIR)$(PLUGIN_INSTALL)" - install -d "$(DESTDIR)$(PREFIX)/share/midimonster" - install -m 0644 configs/* "$(DESTDIR)$(PREFIX)/share/midimonster" + install -d "$(DESTDIR)$(EXAMPLES)" + install -m 0644 configs/* "$(DESTDIR)$(EXAMPLES)" ifdef DEFAULT_CFG install -Dm 0644 monster.cfg "$(DESTDIR)$(DEFAULT_CFG)" endif diff --git a/README.md b/README.md index bcae9dd..9bcd913 100644 --- a/README.md +++ b/README.md @@ -159,12 +159,13 @@ For Linux and OSX, just running `make` in the source directory should do the tri The build process accepts the following parameters, either from the environment or as arguments to the `make` invocation: -| Target | Parameter | Default value | Description | -|---------------|-----------------------|-------------------------------|-------------------------------| -| build targets | `DEFAULT_CFG` | `monster.cfg` | Default configuration file | -| build targets | `PLUGINS` | Linux/OSX: `./backends/`, Windows: `backends\` | Backend plugin library path | -| `install` | `DESTDIR` | empty | Destination directory for packaging builds | -| `install` | `PREFIX` | `/usr` | Install prefix for binaries | +| Target | Parameter | Default value | Description | +|-------------------------------|-----------------------|-------------------------------|-------------------------------| +| build targets, `install` | `DEFAULT_CFG` | `monster.cfg` | Default configuration file | +| build targets, `install` | `PLUGINS` | Linux/OSX: `./backends/`, Windows: `backends\` | Backend plugin library path | +| `install` | `DESTDIR` | empty | Destination directory for packaging builds | +| `install` | `PREFIX` | `/usr` | Install prefix for binaries | +| `install` | `EXAMPLES` | `$(PREFIX)/share/midimonster` | Install path for example configurations | Some backends have been marked as optional as they require rather large additional software to be installed, for example the `ola` backend. To create a build including these, run `make full`. -- cgit v1.2.3