diff options
| author | cbdev <cb@cbcdn.com> | 2019-12-31 10:58:34 +0100 | 
|---|---|---|
| committer | cbdev <cb@cbcdn.com> | 2019-12-31 10:58:34 +0100 | 
| commit | 3b4a2f9f3bbe97c5b77eb74ba9c0163b52d33206 (patch) | |
| tree | 1defeeb5b081b8c951d920298fa10858191d6beb /backends | |
| parent | 7360766777a7969b76fa306f7381d2d51efa1ebe (diff) | |
| parent | 87fe68ef7d929b2f79e695df649b374fe0e2c572 (diff) | |
| download | midimonster-3b4a2f9f3bbe97c5b77eb74ba9c0163b52d33206.tar.gz midimonster-3b4a2f9f3bbe97c5b77eb74ba9c0163b52d33206.tar.bz2 midimonster-3b4a2f9f3bbe97c5b77eb74ba9c0163b52d33206.zip | |
Merge branch 'master' into debian/master
Diffstat (limited to 'backends')
| -rw-r--r-- | backends/Makefile | 19 | ||||
| -rw-r--r-- | backends/artnet.c | 109 | ||||
| -rw-r--r-- | backends/artnet.h | 6 | ||||
| -rw-r--r-- | backends/evdev.c | 114 | ||||
| -rw-r--r-- | backends/evdev.h | 6 | ||||
| -rw-r--r-- | backends/jack.c | 143 | ||||
| -rw-r--r-- | backends/jack.h | 6 | ||||
| -rw-r--r-- | backends/libmmbackend.c | 33 | ||||
| -rw-r--r-- | backends/libmmbackend.h | 8 | ||||
| -rw-r--r-- | backends/loopback.c | 30 | ||||
| -rw-r--r-- | backends/loopback.h | 6 | ||||
| -rw-r--r-- | backends/lua.c | 69 | ||||
| -rw-r--r-- | backends/lua.h | 6 | ||||
| -rw-r--r-- | backends/maweb.c | 134 | ||||
| -rw-r--r-- | backends/maweb.h | 6 | ||||
| -rw-r--r-- | backends/midi.c | 82 | ||||
| -rw-r--r-- | backends/midi.h | 6 | ||||
| -rw-r--r-- | backends/ola.cpp | 66 | ||||
| -rw-r--r-- | backends/ola.h | 6 | ||||
| -rw-r--r-- | backends/osc.c | 148 | ||||
| -rw-r--r-- | backends/osc.h | 6 | ||||
| -rw-r--r-- | backends/sacn.c | 142 | ||||
| -rw-r--r-- | backends/sacn.h | 7 | ||||
| -rw-r--r-- | backends/sacn.md | 6 | ||||
| -rw-r--r-- | backends/winmidi.c | 206 | ||||
| -rw-r--r-- | backends/winmidi.h | 16 | 
26 files changed, 596 insertions, 790 deletions
| diff --git a/backends/Makefile b/backends/Makefile index feefd7b..656e6b6 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -7,8 +7,12 @@ BACKEND_LIB = libmmbackend.o  SYSTEM := $(shell uname -s) -CFLAGS += -g -fPIC -I../ -Wall -Wpedantic -CPPFLAGS += -g -fPIC -I../ +# Generate debug symbols unless overridden +CFLAGS ?= -g +CPPFLAGS ?= -g + +CFLAGS += -fPIC -I../ -Wall -Wpedantic +CPPFLAGS += -fPIC -I../  LDFLAGS += -shared  # Build Linux backends if possible @@ -47,10 +51,13 @@ evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev || echo "-DBUILD_ERROR=  evdev.so: LDLIBS = $(shell pkg-config --libs libevdev || echo "-DBUILD_ERROR=\"Missing pkg-config data for libevdev\"")  ola.so: LDLIBS = -lola  ola.so: CPPFLAGS += -Wno-write-strings +  # The pkg-config name for liblua5.3 is subject to discussion. I prefer 'lua5.3' (which works on Debian and OSX),  # but Arch requires 'lua53' which works on Debian, too, but breaks on OSX.  lua.so: CFLAGS += $(shell pkg-config --cflags lua53 || pkg-config --cflags lua5.3 || echo "-DBUILD_ERROR=\"Missing pkg-config data for lua53\"")  lua.so: LDLIBS += $(shell pkg-config --libs lua53 || pkg-config --libs lua5.3 || echo "-DBUILD_ERROR=\"Missing pkg-config data for lua53\"") +lua.dll: CFLAGS += $(shell pkg-config --cflags lua53 || pkg-config --cflags lua5.3 || echo "-DBUILD_ERROR=\"Missing pkg-config data for lua53\"") +lua.dll: LDLIBS += -L../libs -llua53  %.so :: %.c %.h $(BACKEND_LIB)  	$(CC) $(CFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) @@ -66,10 +73,12 @@ all: $(BACKEND_LIB) $(BACKENDS)  ../libmmapi.a:  	$(MAKE) -C ../ midimonster.exe -windows: export CC = x86_64-w64-mingw32-gcc -windows: LDLIBS += -lmmapi -windows: LDFLAGS += -L../ +%.dll: export CC = x86_64-w64-mingw32-gcc +%.dll: LDLIBS += -lmmapi +%.dll: LDFLAGS += -L../ +%.dll: CFLAGS += -Wno-format -Wno-pointer-sign  windows: CFLAGS += -Wno-format -Wno-pointer-sign +windows: export CC = x86_64-w64-mingw32-gcc  windows: ../libmmapi.a $(BACKEND_LIB) $(WINDOWS_BACKENDS)  full: $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) diff --git a/backends/artnet.c b/backends/artnet.c index 8a62a43..0bd1a32 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "artnet" +  #include <string.h>  #include <ctype.h>  #include <errno.h> @@ -6,7 +8,6 @@  #include "artnet.h"  #define MAX_FDS 255 -#define BACKEND_NAME "artnet"  static uint8_t default_net = 0;  static size_t artnet_fds = 0; @@ -15,7 +16,7 @@ static artnet_descriptor* artnet_fd = NULL;  static int artnet_listener(char* host, char* port){  	int fd;  	if(artnet_fds >= MAX_FDS){ -		fprintf(stderr, "ArtNet backend descriptor limit reached\n"); +		LOG("Backend descriptor limit reached");  		return -1;  	} @@ -28,11 +29,11 @@ static int artnet_listener(char* host, char* port){  	artnet_fd = realloc(artnet_fd, (artnet_fds + 1) * sizeof(artnet_descriptor));  	if(!artnet_fd){  		close(fd); -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return -1;  	} -	fprintf(stderr, "ArtNet backend interface %" PRIsize_t " bound to %s port %s\n", artnet_fds, host, port); +	LOGPF("Interface %" PRIsize_t " bound to %s port %s", artnet_fds, host, port);  	artnet_fd[artnet_fds].fd = fd;  	artnet_fd[artnet_fds].output_instances = 0;  	artnet_fd[artnet_fds].output_instance = NULL; @@ -55,45 +56,41 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(artnet_instance_id) != sizeof(uint64_t)){ -		fprintf(stderr, "ArtNet instance identification union out of bounds\n"); +		LOG("Instance identification union out of bounds");  		return 1;  	}  	//register backend  	if(mm_backend_register(artnet)){ -		fprintf(stderr, "Failed to register ArtNet backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0;  }  static int artnet_configure(char* option, char* value){ -	char* host = NULL, *port = NULL; +	char* host = NULL, *port = NULL, *fd_opts = NULL;  	if(!strcmp(option, "net")){  		//configure default net  		default_net = strtoul(value, NULL, 0);  		return 0;  	}  	else if(!strcmp(option, "bind")){ -		mmbackend_parse_hostspec(value, &host, &port); - -		if(!port){ -			port = ARTNET_PORT; -		} +		mmbackend_parse_hostspec(value, &host, &port, &fd_opts);  		if(!host){ -			fprintf(stderr, "Not valid ArtNet bind address given\n"); +			LOGPF("%s is not a valid bind address", value);  			return 1;  		} -		if(artnet_listener(host, port)){ -			fprintf(stderr, "Failed to bind ArtNet descriptor: %s\n", value); +		if(artnet_listener(host, (port ? port : ARTNET_PORT))){ +			LOGPF("Failed to bind descriptor: %s", value);  			return 1;  		}  		return 0;  	} -	fprintf(stderr, "Unknown ArtNet backend option %s\n", option); +	LOGPF("Unknown backend option %s", option);  	return 1;  } @@ -106,7 +103,7 @@ static instance* artnet_instance(){  	data = calloc(1, sizeof(artnet_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -132,31 +129,27 @@ static int artnet_configure_instance(instance* inst, char* option, char* value){  		data->fd_index = strtoul(value, NULL, 0);  		if(data->fd_index >= artnet_fds){ -			fprintf(stderr, "Invalid interface configured for ArtNet instance %s\n", inst->name); +			LOGPF("Invalid interface configured for instance %s", inst->name);  			return 1;  		}  		return 0;  	}  	else if(!strcmp(option, "dest") || !strcmp(option, "destination")){ -		mmbackend_parse_hostspec(value, &host, &port); - -		if(!port){ -			port = ARTNET_PORT; -		} +		mmbackend_parse_hostspec(value, &host, &port, NULL);  		if(!host){ -			fprintf(stderr, "Not a valid ArtNet destination for instance %s\n", inst->name); +			LOGPF("Not a valid destination for instance %s: %s", inst->name, value);  			return 1;  		} -		return mmbackend_parse_sockaddr(host, port, &data->dest_addr, &data->dest_len); +		return mmbackend_parse_sockaddr(host, port ? port : ARTNET_PORT, &data->dest_addr, &data->dest_len);  	} -	fprintf(stderr, "Unknown ArtNet option %s for instance %s\n", option, inst->name); +	LOGPF("Unknown instance option %s for instance %s", option, inst->name);  	return 1;  } -static channel* artnet_channel(instance* inst, char* spec){ +static channel* artnet_channel(instance* inst, char* spec, uint8_t flags){  	artnet_instance_data* data = (artnet_instance_data*) inst->impl;  	char* spec_next = spec;  	unsigned chan_a = strtoul(spec, &spec_next, 10); @@ -164,7 +157,7 @@ static channel* artnet_channel(instance* inst, char* spec){  	//primary channel sanity check  	if(!chan_a || chan_a > 512){ -		fprintf(stderr, "Invalid ArtNet channel specification %s\n", spec); +		LOGPF("Invalid channel specification %s", spec);  		return NULL;  	}  	chan_a--; @@ -173,14 +166,14 @@ static channel* artnet_channel(instance* inst, char* spec){  	if(*spec_next == '+'){  		chan_b = strtoul(spec_next + 1, NULL, 10);  		if(!chan_b || chan_b > 512){ -			fprintf(stderr, "Invalid wide-channel spec %s\n", spec); +			LOGPF("Invalid wide-channel specification %s", spec);  			return NULL;  		}  		chan_b--;  		//if mapped mode differs, bail  		if(IS_ACTIVE(data->data.map[chan_b]) && data->data.map[chan_b] != (MAP_FINE | chan_a)){ -			fprintf(stderr, "Fine channel already mapped for ArtNet spec %s\n", spec); +			LOGPF("Fine channel already mapped for spec %s", spec);  			return NULL;  		} @@ -191,7 +184,7 @@ static channel* artnet_channel(instance* inst, char* spec){  	if(IS_ACTIVE(data->data.map[chan_a])){  		if((*spec_next == '+' && data->data.map[chan_a] != (MAP_COARSE | chan_b))  				|| (*spec_next != '+' && data->data.map[chan_a] != (MAP_SINGLE | chan_a))){ -			fprintf(stderr, "Primary ArtNet channel already mapped at differing mode: %s\n", spec); +			LOGPF("Primary channel already mapped at differing mode: %s", spec);  			return NULL;  		}  	} @@ -218,7 +211,7 @@ static int artnet_transmit(instance* inst){  	memcpy(frame.data, data->data.out, 512);  	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)); +		LOGPF("Failed to output frame for instance %s: %s", inst->name, strerror(errno));  	}  	//update last frame timestamp @@ -235,7 +228,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 (%" PRIsize_t " channel events)\n", inst->name, num); +		LOGPF("Instance %s not enabled for output (%" PRIsize_t " channel events)", inst->name, num);  		return 0;  	} @@ -275,7 +268,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){  	artnet_instance_data* data = (artnet_instance_data*) inst->impl;  	if(be16toh(frame->length) > 512){ -		fprintf(stderr, "Invalid ArtNet frame channel count\n"); +		LOGPF("Invalid frame channel count: %d", be16toh(frame->length));  		return 1;  	} @@ -300,7 +293,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){  			}  			if(!chan){ -				fprintf(stderr, "Active channel %" PRIsize_t " on %s not known to core\n", p, inst->name); +				LOGPF("Active channel %" PRIsize_t " on %s not known to core", p, inst->name);  				return 1;  			} @@ -319,7 +312,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){  			}  			if(mm_channel_event(chan, val)){ -				fprintf(stderr, "Failed to push ArtNet channel event to core\n"); +				LOG("Failed to push channel event to core");  				return 1;  			}  		} @@ -366,7 +359,7 @@ static int artnet_handle(size_t num, managed_fd* fds){  					inst_id.fields.uni = frame->universe;  					inst = mm_instance_find(BACKEND_NAME, inst_id.label);  					if(inst && artnet_process_frame(inst, frame)){ -						fprintf(stderr, "Failed to process ArtNet frame\n"); +						LOG("Failed to process frame");  					}  				}  			} @@ -377,11 +370,11 @@ static int artnet_handle(size_t num, managed_fd* fds){  		#else  		if(bytes_read < 0 && errno != EAGAIN){  		#endif -			fprintf(stderr, "ArtNet failed to receive data: %s\n", strerror(errno)); +			LOGPF("Failed to receive data: %s", strerror(errno));  		}  		if(bytes_read == 0){ -			fprintf(stderr, "ArtNet listener closed\n"); +			LOG("Listener closed");  			return 1;  		}  	} @@ -389,29 +382,16 @@ static int artnet_handle(size_t num, managed_fd* fds){  	return 0;  } -static int artnet_start(){ -	size_t n, u, p; +static int artnet_start(size_t n, instance** inst){ +	size_t u, p;  	int rv = 1; -	instance** inst = NULL;  	artnet_instance_data* data = NULL;  	artnet_instance_id id = {  		.label = 0  	}; -	//fetch all defined instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	if(!n){ -		free(inst); -		return 0; -	} -  	if(!artnet_fds){ -		free(inst); -		fprintf(stderr, "Failed to start ArtNet backend: no descriptors bound\n"); +		LOG("Failed to start backend: no descriptors bound");  		return 1;  	} @@ -426,7 +406,7 @@ static int artnet_start(){  		//check for duplicates  		for(p = 0; p < u; p++){  			if(inst[u]->ident == inst[p]->ident){ -				fprintf(stderr, "Universe specified multiple times, use one instance: %s - %s\n", inst[u]->name, inst[p]->name); +				LOGPF("Universe specified multiple times, use one instance: %s - %s", inst[u]->name, inst[p]->name);  				goto bail;  			}  		} @@ -437,7 +417,7 @@ static int artnet_start(){  			artnet_fd[data->fd_index].last_frame = realloc(artnet_fd[data->fd_index].last_frame, (artnet_fd[data->fd_index].output_instances + 1) * sizeof(uint64_t));  			if(!artnet_fd[data->fd_index].output_instance || !artnet_fd[data->fd_index].last_frame){ -				fprintf(stderr, "Failed to allocate memory\n"); +				LOG("Failed to allocate memory");  				goto bail;  			}  			artnet_fd[data->fd_index].output_instance[artnet_fd[data->fd_index].output_instances] = id; @@ -447,7 +427,7 @@ static int artnet_start(){  		}  	} -	fprintf(stderr, "ArtNet backend registering %" PRIsize_t " descriptors to core\n", artnet_fds); +	LOGPF("Registering %" PRIsize_t " descriptors to core", artnet_fds);  	for(u = 0; u < artnet_fds; u++){  		if(mm_manage_fd(artnet_fd[u].fd, BACKEND_NAME, 1, (void*) u)){  			goto bail; @@ -456,22 +436,15 @@ static int artnet_start(){  	rv = 0;  bail: -	free(inst);  	return rv;  } -static int artnet_shutdown(){ -	size_t n, p; -	instance** inst = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} +static int artnet_shutdown(size_t n, instance** inst){ +	size_t p;  	for(p = 0; p < n; p++){  		free(inst[p]->impl);  	} -	free(inst);  	for(p = 0; p < artnet_fds; p++){  		close(artnet_fd[p].fd); @@ -480,6 +453,6 @@ static int artnet_shutdown(){  	}  	free(artnet_fd); -	fprintf(stderr, "ArtNet backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/artnet.h b/backends/artnet.h index cce11d1..59bd53f 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -7,11 +7,11 @@ MM_PLUGIN_API int init();  static int artnet_configure(char* option, char* value);  static int artnet_configure_instance(instance* instance, char* option, char* value);  static instance* artnet_instance(); -static channel* artnet_channel(instance* instance, char* spec); +static channel* artnet_channel(instance* instance, char* spec, uint8_t flags);  static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v);  static int artnet_handle(size_t num, managed_fd* fds); -static int artnet_start(); -static int artnet_shutdown(); +static int artnet_start(size_t n, instance** inst); +static int artnet_shutdown(size_t n, instance** inst);  #define ARTNET_PORT "6454"  #define ARTNET_VERSION 14 diff --git a/backends/evdev.c b/backends/evdev.c index dd2231b..4725ef7 100644 --- a/backends/evdev.c +++ b/backends/evdev.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "evdev" +  #include <fcntl.h>  #include <stdio.h>  #include <errno.h> @@ -16,8 +18,6 @@  #include "midimonster.h"  #include "evdev.h" -#define BACKEND_NAME "evdev" -  static struct {  	uint8_t detect;  } evdev_config = { @@ -38,12 +38,12 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(evdev_channel_ident) != sizeof(uint64_t)){ -		fprintf(stderr, "evdev channel identification union out of bounds\n"); +		LOG("Channel identification union out of bounds");  		return 1;  	}  	if(mm_backend_register(evdev)){ -		fprintf(stderr, "Failed to register evdev backend\n"); +		LOG("Failed to register backend");  		return 1;  	} @@ -59,7 +59,7 @@ static int evdev_configure(char* option, char* value) {  		return 0;  	} -	fprintf(stderr, "Unknown configuration option %s for evdev backend\n", option); +	LOGPF("Unknown backend configuration option %s", option);  	return 1;  } @@ -71,7 +71,7 @@ static instance* evdev_instance(){  	evdev_instance_data* data = calloc(1, sizeof(evdev_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -79,7 +79,7 @@ static instance* evdev_instance(){  #ifndef EVDEV_NO_UINPUT  	data->output_proto = libevdev_new();  	if(!data->output_proto){ -		fprintf(stderr, "Failed to initialize libevdev output prototype device\n"); +		LOG("Failed to initialize libevdev output prototype device");  		free(data);  		return NULL;  	} @@ -91,25 +91,25 @@ static instance* evdev_instance(){  static int evdev_attach(instance* inst, evdev_instance_data* data, char* node){  	if(data->input_fd >= 0){ -		fprintf(stderr, "Instance %s already was assigned an input device\n", inst->name); +		LOGPF("Instance %s already assigned an input device", inst->name);  		return 1;  	}  	data->input_fd = open(node, O_RDONLY | O_NONBLOCK);  	if(data->input_fd < 0){ -		fprintf(stderr, "Failed to open evdev input device node %s: %s\n", node, strerror(errno)); +		LOGPF("Failed to open input device node %s: %s", node, strerror(errno));  		return 1;  	}  	if(libevdev_new_from_fd(data->input_fd, &data->input_ev)){ -		fprintf(stderr, "Failed to initialize libevdev for %s\n", node); +		LOGPF("Failed to initialize libevdev for %s", node);  		close(data->input_fd);  		data->input_fd = -1;  		return 1;  	}  	if(data->exclusive && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){ -		fprintf(stderr, "Failed to obtain exclusive device access on %s\n", node); +		LOGPF("Failed to obtain exclusive device access on %s", node);  	}  	return 0; @@ -123,7 +123,7 @@ static char* evdev_find(char* name){  	char device_name[UINPUT_MAX_NAME_SIZE], *result = NULL;  	if(!nodes){ -		fprintf(stderr, "Failed to query input device nodes in %s: %s", INPUT_NODES, strerror(errno)); +		LOGPF("Failed to query input device nodes in %s: %s", INPUT_NODES, strerror(errno));  		return NULL;  	} @@ -133,12 +133,12 @@ static char* evdev_find(char* name){  			fd = open(file_path, O_RDONLY);  			if(fd < 0){ -				fprintf(stderr, "Failed to access %s: %s\n", file_path, strerror(errno)); +				LOGPF("Failed to access %s: %s", file_path, strerror(errno));  				continue;  			}  			if(ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0){ -				fprintf(stderr, "Failed to read name for %s: %s\n", file_path, strerror(errno)); +				LOGPF("Failed to read name for %s: %s", file_path, strerror(errno));  				close(fd);  				continue;  			} @@ -146,7 +146,7 @@ static char* evdev_find(char* name){  			close(fd);  			if(!strncmp(device_name, name, strlen(name))){ -				fprintf(stderr, "Matched name %s for %s: %s\n", device_name, name, file_path); +				LOGPF("Matched name %s for %s: %s", device_name, name, file_path);  				break;  			}  		} @@ -178,7 +178,7 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {  	else if(!strcmp(option, "input")){  		next_token = evdev_find(value);  		if(!next_token){ -			fprintf(stderr, "Failed to find evdev input device with name %s for instance %s\n", value, inst->name); +			LOGPF("Failed to match input device with name %s for instance %s", value, inst->name);  			return 1;  		}  		if(evdev_attach(inst, data, next_token)){ @@ -190,7 +190,7 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {  	}  	else if(!strcmp(option, "exclusive")){  		if(data->input_fd >= 0 && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){ -			fprintf(stderr, "Failed to obtain exclusive device access on %s\n", inst->name); +			LOGPF("Failed to obtain exclusive device access on %s", inst->name);  		}  		data->exclusive = 1;  		return 0; @@ -198,7 +198,7 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {  	else if(!strncmp(option, "relaxis.", 8)){  		data->relative_axis = realloc(data->relative_axis, (data->relative_axes + 1) * sizeof(evdev_relaxis_config));  		if(!data->relative_axis){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return 1;  		}  		data->relative_axis[data->relative_axes].inverted = 0; @@ -208,9 +208,12 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {  			data->relative_axis[data->relative_axes].max *= -1;  			data->relative_axis[data->relative_axes].inverted = 1;  		} +		else if(data->relative_axis[data->relative_axes].max == 0){ +			LOGPF("Relative axis configuration for %s.%s has invalid range", inst->name, option + 8); +		}  		data->relative_axis[data->relative_axes].current = strtoul(next_token, NULL, 0);  		if(data->relative_axis[data->relative_axes].code < 0){ -			fprintf(stderr, "Failed to configure relative axis extents for %s.%s\n", inst->name, option + 8); +			LOGPF("Failed to configure relative axis extents for %s.%s", inst->name, option + 8);  			return 1;  		}  		data->relative_axes++; @@ -239,17 +242,17 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {  		abs_info.flat = strtol(next_token, &next_token, 0);  		abs_info.resolution = strtol(next_token, &next_token, 0);  		if(libevdev_enable_event_code(data->output_proto, EV_ABS, libevdev_event_code_from_name(EV_ABS, option + 5), &abs_info)){ -			fprintf(stderr, "Failed to enable absolute axis %s for output\n", option + 5); +			LOGPF("Failed to enable absolute axis %s.%s for output", inst->name, option + 5);  			return 1;  		}  		return 0;  	}  #endif -	fprintf(stderr, "Unknown instance configuration parameter %s for evdev instance %s\n", option, inst->name); +	LOGPF("Unknown instance configuration parameter %s for instance %s", option, inst->name);  	return 1;  } -static channel* evdev_channel(instance* inst, char* spec){ +static channel* evdev_channel(instance* inst, char* spec, uint8_t flags){  #ifndef EVDEV_NO_UINPUT  	evdev_instance_data* data = (evdev_instance_data*) inst->impl;  #endif @@ -259,14 +262,14 @@ static channel* evdev_channel(instance* inst, char* spec){  	};  	if(!separator){ -		fprintf(stderr, "Invalid evdev channel specification %s\n", spec); +		LOGPF("Invalid channel specification %s", spec);  		return NULL;  	}  	*(separator++) = 0;  	if(libevdev_event_type_from_name(spec) < 0){ -		fprintf(stderr, "Invalid evdev type specification: %s", spec); +		LOGPF("Invalid type specification: %s", spec);  		return NULL;  	}  	ident.fields.type = libevdev_event_type_from_name(spec); @@ -275,7 +278,7 @@ static channel* evdev_channel(instance* inst, char* spec){  		ident.fields.code = libevdev_event_code_from_name(ident.fields.type, separator);  	}  	else{ -		fprintf(stderr, "evdev Code name not recognized, using as number: %s\n", separator); +		LOGPF("Code name not recognized, using as number: %s.%s", inst->name, separator);  		ident.fields.code = strtoul(separator, NULL, 10);  	} @@ -285,7 +288,7 @@ static channel* evdev_channel(instance* inst, char* spec){  			//enable the event on the device  			//the previous check is necessary to not fail while enabling axes, which require additional information  			if(libevdev_enable_event_code(data->output_proto, ident.fields.type, ident.fields.code, NULL)){ -				fprintf(stderr, "Failed to enable output event %s.%s%s\n", +				LOGPF("Failed to enable output event %s.%s%s",  						libevdev_event_type_get_name(ident.fields.type),  						libevdev_event_code_get_name(ident.fields.type, ident.fields.code),  						(ident.fields.type == EV_ABS) ? ": To output absolute axes, specify their details in the configuration":""); @@ -339,13 +342,13 @@ static int evdev_push_event(instance* inst, evdev_instance_data* data, struct in  		}  		if(mm_channel_event(chan, val)){ -			fprintf(stderr, "Failed to push evdev channel event to core\n"); +			LOG("Failed to push channel event to core");  			return 1;  		}  	}  	if(evdev_config.detect){ -		fprintf(stderr, "Incoming evdev data for channel %s.%s.%s\n", inst->name, libevdev_event_type_get_name(event.type), libevdev_event_code_get_name(event.type, event.code)); +		LOGPF("Incoming data for channel %s.%s.%s", inst->name, libevdev_event_type_get_name(event.type), libevdev_event_code_get_name(event.type, event.code));  	}  	return 0; @@ -366,7 +369,7 @@ static int evdev_handle(size_t num, managed_fd* fds){  	for(fd = 0; fd < num; fd++){  		inst = (instance*) fds[fd].impl;  		if(!inst){ -			fprintf(stderr, "evdev backend signaled for unknown fd\n"); +			LOG("Signaled for unknown FD");  			continue;  		} @@ -393,53 +396,39 @@ static int evdev_handle(size_t num, managed_fd* fds){  	return 0;  } -static int evdev_start(){ -	size_t n, u, fds = 0; -	instance** inst = NULL; +static int evdev_start(size_t n, instance** inst){ +	size_t u, fds = 0;  	evdev_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	if(!n){ -		free(inst); -		return 0; -	} -  	for(u = 0; u < n; u++){  		data = (evdev_instance_data*) inst[u]->impl;  #ifndef EVDEV_NO_UINPUT  		if(data->output_enabled){  			if(libevdev_uinput_create_from_device(data->output_proto, LIBEVDEV_UINPUT_OPEN_MANAGED, &data->output_ev)){ -				fprintf(stderr, "Failed to create evdev output device: %s\n", strerror(errno)); -				free(inst); +				LOGPF("Failed to create output device: %s", strerror(errno));  				return 1;  			} -			fprintf(stderr, "Created device node %s for instance %s\n", libevdev_uinput_get_devnode(data->output_ev), inst[u]->name); +			LOGPF("Created device node %s for instance %s", libevdev_uinput_get_devnode(data->output_ev), inst[u]->name);  		}  #endif  		inst[u]->ident = data->input_fd;  		if(data->input_fd >= 0){  			if(mm_manage_fd(data->input_fd, BACKEND_NAME, 1, inst[u])){ -				fprintf(stderr, "Failed to register event input descriptor for instance %s\n", inst[u]->name); -				free(inst); +				LOGPF("Failed to register input descriptor for instance %s", inst[u]->name);  				return 1;  			}  			fds++;  		}  		if(data->input_fd <= 0 && !data->output_ev){ -			fprintf(stderr, "Instance %s has neither input nor output device set up\n", inst[u]->name); +			LOGPF("Instance %s has neither input nor output device set up", inst[u]->name);  		}  	} -	fprintf(stderr, "evdev backend registered %zu descriptors to core\n", fds); -	free(inst); +	LOGPF("Registered %zu descriptors to core", fds);  	return 0;  } @@ -458,7 +447,7 @@ static int evdev_set(instance* inst, size_t num, channel** c, channel_value* v)  	}  	if(!data->output_enabled){ -		fprintf(stderr, "Instance %s not enabled for output\n", inst->name); +		LOGPF("Instance %s not enabled for output (%" PRIsize_t " channel events)", inst->name, num);  		return 0;  	} @@ -494,36 +483,30 @@ static int evdev_set(instance* inst, size_t num, channel** c, channel_value* v)  		}  		if(libevdev_uinput_write_event(data->output_ev, ident.fields.type, ident.fields.code, value)){ -			fprintf(stderr, "Failed to output event on instance %s\n", inst->name); +			LOGPF("Failed to output event on instance %s", inst->name);  			return 1;  		}  	}  	//send syn event to publish all events  	if(libevdev_uinput_write_event(data->output_ev, EV_SYN, SYN_REPORT, 0)){ -		fprintf(stderr, "Failed to output sync event on instance %s\n", inst->name); +		LOGPF("Failed to output sync event on instance %s", inst->name);  		return 1;  	}  	return 0;  #else -	fprintf(stderr, "The evdev backend does not support output on this platform\n"); +	LOG("No output support on this platform");  	return 1;  #endif  } -static int evdev_shutdown(){ +static int evdev_shutdown(size_t n, instance** inst){  	evdev_instance_data* data = NULL; -	instance** instances = NULL; -	size_t n, u; - -	if(mm_backend_instances(BACKEND_NAME, &n, &instances)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} +	size_t u;  	for(u = 0; u < n; u++){ -		data = (evdev_instance_data*) instances[u]->impl; +		data = (evdev_instance_data*) inst[u]->impl;  		if(data->input_fd >= 0){  			libevdev_free(data->input_ev); @@ -539,10 +522,9 @@ static int evdev_shutdown(){  #endif  		data->relative_axes = 0;  		free(data->relative_axis); -		free(data); +		free(inst[u]->impl);  	} -	free(instances); -	fprintf(stderr, "evdev backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/evdev.h b/backends/evdev.h index 30ce892..0c877fc 100644 --- a/backends/evdev.h +++ b/backends/evdev.h @@ -12,11 +12,11 @@ MM_PLUGIN_API int init();  static int evdev_configure(char* option, char* value);  static int evdev_configure_instance(instance* instance, char* option, char* value);  static instance* evdev_instance(); -static channel* evdev_channel(instance* instance, char* spec); +static channel* evdev_channel(instance* instance, char* spec, uint8_t flags);  static int evdev_set(instance* inst, size_t num, channel** c, channel_value* v);  static int evdev_handle(size_t num, managed_fd* fds); -static int evdev_start(); -static int evdev_shutdown(); +static int evdev_start(size_t n, instance** inst); +static int evdev_shutdown(size_t n, instance** inst);  #define INPUT_NODES "/dev/input"  #define INPUT_PREFIX "event" diff --git a/backends/jack.c b/backends/jack.c index 192aab2..d7f68c4 100644 --- a/backends/jack.c +++ b/backends/jack.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "jack" +  #include <string.h>  #include <signal.h>  #include <sys/types.h> @@ -8,7 +10,6 @@  #include <jack/midiport.h>  #include <jack/metadata.h> -#define BACKEND_NAME "jack"  #define JACKEY_SIGNAL_TYPE "http://jackaudio.org/metadata/signal-type"  #ifdef __APPLE__ @@ -41,20 +42,20 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(mmjack_channel_ident) != sizeof(uint64_t)){ -		fprintf(stderr, "jack channel identification union out of bounds\n"); +		LOG("Channel identification union out of bounds");  		return 1;  	}  	//register backend  	if(mm_backend_register(mmjack)){ -		fprintf(stderr, "Failed to register jack backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0;  }  static void mmjack_message_print(const char* msg){ -	fprintf(stderr, "JACK message: %s\n", msg); +	LOGPF("JACK message: %s", msg);  }  static void mmjack_message_ignore(const char* msg){ @@ -66,7 +67,7 @@ static int mmjack_midiqueue_append(mmjack_port* port, mmjack_channel_ident ident  		//extend the queue  		port->queue = realloc(port->queue, (port->queue_len + JACK_MIDIQUEUE_CHUNK) * sizeof(mmjack_midiqueue));  		if(!port->queue){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return 1;  		}  		port->queue_alloc += JACK_MIDIQUEUE_CHUNK; @@ -75,7 +76,7 @@ static int mmjack_midiqueue_append(mmjack_port* port, mmjack_channel_ident ident  	port->queue[port->queue_len].ident.label = ident.label;  	port->queue[port->queue_len].raw = value;  	port->queue_len++; -	DBGPF("Appended event to queue for %s, now at %" PRIsize_t " entries\n", port->name, port->queue_len); +	DBGPF("Appended event to queue for %s, now at %" PRIsize_t " entries", port->name, port->queue_len);  	return 0;  } @@ -90,7 +91,7 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes  	if(port->input){  		if(event_count){ -			DBGPF("Reading %u MIDI events from jack port %s\n", event_count, port->name); +			DBGPF("Reading %u MIDI events from port %s", event_count, port->name);  			for(u = 0; u < event_count; u++){  				ident.label = 0;  				//read midi data from stream @@ -98,20 +99,20 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes  				//ident.fields.port set on output in mmjack_handle_midi  				ident.fields.sub_channel = event.buffer[0] & 0x0F;  				ident.fields.sub_type = event.buffer[0] & 0xF0; +				ident.fields.sub_control = event.buffer[1]; +				value = event.buffer[2];  				if(ident.fields.sub_type == 0x80){  					ident.fields.sub_type = midi_note;  					value = 0;  				}  				else if(ident.fields.sub_type == midi_pitchbend){ +					ident.fields.sub_control = 0;  					value = event.buffer[1] | (event.buffer[2] << 7);  				}  				else if(ident.fields.sub_type == midi_aftertouch){ +					ident.fields.sub_control = 0;  					value = event.buffer[1];  				} -				else{ -					ident.fields.sub_control = event.buffer[1]; -					value = event.buffer[2]; -				}  				//append midi data  				mmjack_midiqueue_append(port, ident, value);  			} @@ -128,7 +129,7 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes  			ident.label = port->queue[u].ident.label;  			event_data = jack_midi_event_reserve(buffer, u, (ident.fields.sub_type == midi_aftertouch) ? 2 : 3);  			if(!event_data){ -				fprintf(stderr, "Failed to reserve MIDI stream data\n"); +				LOG("Failed to reserve MIDI stream data");  				return 1;  			}  			event_data[0] = ident.fields.sub_channel | ident.fields.sub_type; @@ -146,7 +147,7 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes  		}  		if(port->queue_len){ -			DBGPF("Wrote %" PRIsize_t " MIDI events to jack port %s\n", port->queue_len, port->name); +			DBGPF("Wrote %" PRIsize_t " MIDI events to port %s", port->queue_len, port->name);  		}  		port->queue_len = 0;  	} @@ -180,21 +181,21 @@ static int mmjack_process(jack_nframes_t nframes, void* instp){  	size_t p, mark = 0;  	int rv = 0; -	//DBGPF("jack callback for %d frames on %s\n", nframes, inst->name); +	//DBGPF("jack callback for %d frames on %s", nframes, inst->name);  	for(p = 0; p < data->ports; p++){  		pthread_mutex_lock(&data->port[p].lock);  		switch(data->port[p].type){  			case port_midi: -				//DBGPF("Handling MIDI port %s.%s\n", inst->name, data->port[p].name); +				//DBGPF("Handling MIDI port %s.%s", inst->name, data->port[p].name);  				rv |= mmjack_process_midi(inst, data->port + p, nframes, &mark);  				break;  			case port_cv: -				//DBGPF("Handling CV port %s.%s\n", inst->name, data->port[p].name); +				//DBGPF("Handling CV port %s.%s", inst->name, data->port[p].name);  				rv |= mmjack_process_cv(inst, data->port + p, nframes, &mark);  				break;  			default: -				fprintf(stderr, "Unhandled jack port type in processing callback\n"); +				LOG("Unhandled port type in processing callback");  				pthread_mutex_unlock(&data->port[p].lock);  				return 1;  		} @@ -203,14 +204,14 @@ static int mmjack_process(jack_nframes_t nframes, void* instp){  	//notify the main thread  	if(mark){ -		DBGPF("Notifying handler thread for jack instance %s\n", inst->name); +		DBGPF("Notifying handler thread for instance %s", inst->name);  		send(data->fd, "c", 1, 0);  	}  	return rv;  }  static void mmjack_server_shutdown(void* inst){ -	fprintf(stderr, "jack server shutdown notification\n"); +	LOG("Server shut down");  	config.jack_shutdown = 1;  } @@ -232,7 +233,7 @@ static int mmjack_configure(char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown jack backend option %s\n", option); +	LOGPF("Unknown backend option %s", option);  	return 1;  } @@ -258,7 +259,7 @@ static int mmjack_parse_portconfig(mmjack_port* port, char* spec){  		else if(!strcmp(token, "max")){  			token = strtok(NULL, " ");  			if(!token){ -				fprintf(stderr, "jack port %s configuration missing argument\n", port->name); +				LOGPF("Port %s configuration missing argument", port->name);  				return 1;  			}  			port->max = strtod(token, NULL); @@ -266,19 +267,19 @@ static int mmjack_parse_portconfig(mmjack_port* port, char* spec){  		else if(!strcmp(token, "min")){  			token = strtok(NULL, " ");  			if(!token){ -				fprintf(stderr, "jack port %s configuration missing argument\n", port->name); +				LOGPF("Port %s configuration missing argument", port->name);  				return 1;  			}  			port->min = strtod(token, NULL);  		}  		else{ -			fprintf(stderr, "Unknown jack channel configuration token %s on port %s\n", token, port->name); +			LOGPF("Unknown channel configuration token %s on port %s", token, port->name);  			return 1;  		}  	}  	if(port->type == port_none){ -		fprintf(stderr, "jack channel %s assigned no port type\n", port->name); +		LOGPF("Channel %s assigned no port type", port->name);  		return 1;  	}  	return 0; @@ -306,24 +307,24 @@ static int mmjack_configure_instance(instance* inst, char* option, char* value){  	//register new port, first check for unique name  	for(p = 0; p < data->ports; p++){  		if(!strcmp(data->port[p].name, option)){ -			fprintf(stderr, "jack instance %s has duplicate port %s\n", inst->name, option); +			LOGPF("Instance %s has duplicate port %s", inst->name, option);  			return 1;  		}  	}  	if(strchr(option, '.')){ -		fprintf(stderr, "Invalid jack channel spec %s.%s\n", inst->name, option); +		LOGPF("Invalid channel spec %s.%s", inst->name, option);  	}  	//add port to registry  	//TODO for OSC ports we need to configure subchannels for each message  	data->port = realloc(data->port, (data->ports + 1) * sizeof(mmjack_port));  	if(!data->port){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return 1;  	}  	data->port[data->ports].name = strdup(option);  	if(!data->port[data->ports].name){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return 1;  	}  	if(mmjack_parse_portconfig(data->port + p, value)){ @@ -341,7 +342,7 @@ static instance* mmjack_instance(){  	inst->impl = calloc(1, sizeof(mmjack_instance_data));  	if(!inst->impl){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -359,18 +360,18 @@ static int mmjack_parse_midispec(mmjack_channel_ident* ident, char* spec){  	}  	if(!next_token){ -		fprintf(stderr, "Invalid jack MIDI spec %s\n", spec); +		LOGPF("Invalid MIDI spec %s", spec);  		return 1;  	}  	ident->fields.sub_channel = strtoul(next_token, &next_token, 10);  	if(ident->fields.sub_channel > 15){ -		fprintf(stderr, "Invalid jack MIDI spec %s, channel out of range\n", spec); +		LOGPF("Invalid MIDI spec %s, channel out of range", spec);  		return 1;  	}  	if(*next_token != '.'){ -		fprintf(stderr, "Invalid jack MIDI spec %s\n", spec); +		LOGPF("Invalid MIDI spec %s", spec);  		return 1;  	} @@ -395,7 +396,7 @@ static int mmjack_parse_midispec(mmjack_channel_ident* ident, char* spec){  		ident->fields.sub_type = midi_aftertouch;  	}  	else{ -		fprintf(stderr, "Unknown jack MIDI control type in spec %s\n", spec); +		LOGPF("Unknown MIDI control type in spec %s", spec);  		return 1;  	} @@ -403,13 +404,13 @@ static int mmjack_parse_midispec(mmjack_channel_ident* ident, char* spec){  	if(ident->fields.sub_type == midi_none  			|| ident->fields.sub_control > 127){ -		fprintf(stderr, "Invalid jack MIDI spec %s\n", spec); +		LOGPF("Invalid MIDI spec %s", spec);  		return 1;  	}  	return 0;  } -static channel* mmjack_channel(instance* inst, char* spec){ +static channel* mmjack_channel(instance* inst, char* spec, uint8_t flags){  	mmjack_instance_data* data = (mmjack_instance_data*) inst->impl;  	mmjack_channel_ident ident = {  		.label = 0 @@ -425,7 +426,7 @@ static channel* mmjack_channel(instance* inst, char* spec){  	}  	if(u == data->ports){ -		fprintf(stderr, "jack port %s.%s not found\n", inst->name, spec); +		LOGPF("Tried to map unknown port %s.%s", inst->name, spec);  		return NULL;  	} @@ -456,7 +457,7 @@ static int mmjack_set(instance* inst, size_t num, channel** c, channel_value* v)  		ident.label = c[u]->ident;  		if(data->port[ident.fields.port].input){ -			fprintf(stderr, "jack port %s.%s is an input port, no output is possible\n", inst->name, data->port[ident.fields.port].name); +			LOGPF("Port %s.%s is an input port, no output is possible", inst->name, data->port[ident.fields.port].name);  			continue;  		}  		range = data->port[ident.fields.port].max - data->port[ident.fields.port].min; @@ -466,7 +467,7 @@ static int mmjack_set(instance* inst, size_t num, channel** c, channel_value* v)  			case port_cv:  				//scale value to given range  				data->port[ident.fields.port].last = (range * v[u].normalised) + data->port[ident.fields.port].min; -				DBGPF("CV port %s updated to %f\n", data->port[ident.fields.port].name, data->port[ident.fields.port].last); +				DBGPF("CV port %s updated to %f", data->port[ident.fields.port].name, data->port[ident.fields.port].last);  				break;  			case port_midi:  				value = v[u].normalised * 127.0; @@ -479,7 +480,7 @@ static int mmjack_set(instance* inst, size_t num, channel** c, channel_value* v)  				}  				break;  			default: -				fprintf(stderr, "No handler implemented for jack port type %s.%s\n", inst->name, data->port[ident.fields.port].name); +				LOGPF("No handler implemented for port type %s.%s", inst->name, data->port[ident.fields.port].name);  				break;  		}  		pthread_mutex_unlock(&data->port[ident.fields.port].lock); @@ -503,7 +504,7 @@ static void mmjack_handle_midi(instance* inst, size_t index, mmjack_port* port){  			else{  				val.normalised = ((double)port->queue[u].raw) / 127.0;  			} -			DBGPF("Pushing MIDI channel %d type %02X control %d value %f raw %d label %" PRIu64 "\n", +			DBGPF("Pushing MIDI channel %d type %02X control %d value %f raw %d label %" PRIu64,  					port->queue[u].ident.fields.sub_channel,  					port->queue[u].ident.fields.sub_type,  					port->queue[u].ident.fields.sub_control, @@ -511,13 +512,13 @@ static void mmjack_handle_midi(instance* inst, size_t index, mmjack_port* port){  					port->queue[u].raw,  					port->queue[u].ident.label);  			if(mm_channel_event(chan, val)){ -				fprintf(stderr, "Failed to push MIDI event to core on jack port %s.%s\n", inst->name, port->name); +				LOGPF("Failed to push MIDI event to core on port %s.%s", inst->name, port->name);  			}  		}  	}  	if(port->queue_len){ -		DBGPF("Pushed %" PRIsize_t " MIDI events to core for jack port %s.%s\n", port->queue_len, inst->name, port->name); +		DBGPF("Pushed %" PRIsize_t " MIDI events to core for port %s.%s", port->queue_len, inst->name, port->name);  	}  	port->queue_len = 0;  } @@ -532,7 +533,7 @@ static void mmjack_handle_cv(instance* inst, size_t index, mmjack_port* port){  	channel* chan = mm_channel(inst, ident.label, 0);  	if(!chan){  		//this might happen if a channel is registered but not mapped -		DBGPF("Failed to match jack CV channel %s.%s to core channel\n", inst->name, port->name); +		DBGPF("Failed to match CV channel %s.%s to core channel", inst->name, port->name);  		return;  	} @@ -541,9 +542,9 @@ static void mmjack_handle_cv(instance* inst, size_t index, mmjack_port* port){  	val.normalised = port->last - port->min;  	val.normalised /= range;  	val.normalised = clamp(val.normalised, 1.0, 0.0); -	DBGPF("Pushing CV channel %s value %f raw %f min %f max %f\n", port->name, val.normalised, port->last, port->min, port->max); +	DBGPF("Pushing CV channel %s value %f raw %f min %f max %f", port->name, val.normalised, port->last, port->min, port->max);  	if(mm_channel_event(chan, val)){ -		fprintf(stderr, "Failed to push CV event to core for %s.%s\n", inst->name, port->name); +		LOGPF("Failed to push CV event to core for %s.%s", inst->name, port->name);  	}  } @@ -560,7 +561,7 @@ static int mmjack_handle(size_t num, managed_fd* fds){  			data = (mmjack_instance_data*) inst->impl;  			bytes = recv(fds[u].fd, recv_buf, sizeof(recv_buf), 0);  			if(bytes < 0){ -				fprintf(stderr, "Failed to receive on feedback socket for instance %s\n", inst->name); +				LOGPF("Failed to receive on feedback socket for instance %s", inst->name);  				return 1;  			} @@ -575,7 +576,7 @@ static int mmjack_handle(size_t num, managed_fd* fds){  							mmjack_handle_midi(inst, p, data->port + p);  							break;  						default: -							fprintf(stderr, "Output handler not implemented for unknown jack channel type on %s.%s\n", inst->name, data->port[p].name); +							LOGPF("Output handler not implemented for unknown channel type on %s.%s", inst->name, data->port[p].name);  							break;  					} @@ -587,16 +588,15 @@ static int mmjack_handle(size_t num, managed_fd* fds){  	}  	if(config.jack_shutdown){ -		fprintf(stderr, "JACK server disconnected\n"); +		LOG("Server disconnected");  		return 1;  	}  	return 0;  } -static int mmjack_start(){ +static int mmjack_start(size_t n, instance** inst){  	int rv = 1, feedback_fd[2]; -	size_t n, u, p; -	instance** inst = NULL; +	size_t u, p;  	pthread_mutexattr_t mutex_attr;  	mmjack_instance_data* data = NULL;  	jack_status_t error; @@ -614,13 +614,7 @@ static int mmjack_start(){  	//prepare mutex attributes because the initializer macro for adaptive mutexes is a GNU extension...  	if(pthread_mutexattr_init(&mutex_attr)  			|| pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP)){ -		fprintf(stderr, "Failed to initialize mutex attributes\n"); -		goto bail; -	} - -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); +		LOG("Failed to initialize mutex attributes");  		goto bail;  	} @@ -635,19 +629,19 @@ static int mmjack_start(){  		if(!data->client){  			//TODO pretty-print failures -			fprintf(stderr, "jack backend failed to connect to server, return status %u\n", error); +			LOGPF("Failed to connect to server, return status %u", error);  			goto bail;  		}  		//set up the feedback fd  		if(socketpair(AF_LOCAL, SOCK_DGRAM, 0, feedback_fd)){ -			fprintf(stderr, "Failed to create feedback socket pair\n"); +			LOG("Failed to create feedback socket pair");  			goto bail;  		}  		data->fd = feedback_fd[0];  		if(mm_manage_fd(feedback_fd[1], BACKEND_NAME, 1, inst[u])){ -			fprintf(stderr, "jack backend failed to register feedback fd with core\n"); +			LOG("Failed to register feedback FD with core");  			goto bail;  		} @@ -655,12 +649,12 @@ static int mmjack_start(){  		jack_set_process_callback(data->client, mmjack_process, inst[u]);  		jack_on_shutdown(data->client, mmjack_server_shutdown, inst[u]); -		fprintf(stderr, "jack instance %s assigned client name %s\n", inst[u]->name, jack_get_client_name(data->client)); +		LOGPF("Instance %s assigned client name %s", inst[u]->name, jack_get_client_name(data->client));  		//create and initialize jack ports  		for(p = 0; p < data->ports; p++){  			if(pthread_mutex_init(&(data->port[p].lock), &mutex_attr)){ -				fprintf(stderr, "Failed to create port mutex\n"); +				LOG("Failed to create port mutex");  				goto bail;  			} @@ -673,36 +667,29 @@ static int mmjack_start(){  			jack_set_property(data->client, jack_port_uuid(data->port[p].port), JACKEY_SIGNAL_TYPE, "CV", "text/plain");  			if(!data->port[p].port){ -				fprintf(stderr, "Failed to create jack port %s.%s\n", inst[u]->name, data->port[p].name); +				LOGPF("Failed to create port %s.%s", inst[u]->name, data->port[p].name);  				goto bail;  			}  		}  		//do the thing  		if(jack_activate(data->client)){ -			fprintf(stderr, "Failed to activate jack client for instance %s\n", inst[u]->name); +			LOGPF("Failed to activate client for instance %s", inst[u]->name);  			goto bail;  		}  	} -	fprintf(stderr, "jack backend registered %" PRIsize_t " descriptors to core\n", n); +	LOGPF("Registered %" PRIsize_t " descriptors to core", n);  	rv = 0;  bail:  	pthread_mutexattr_destroy(&mutex_attr); -	free(inst);  	return rv;  } -static int mmjack_shutdown(){ -	size_t n, u, p; -	instance** inst = NULL; +static int mmjack_shutdown(size_t n, instance** inst){ +	size_t u, p;  	mmjack_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (mmjack_instance_data*) inst[u]->impl; @@ -739,10 +726,10 @@ static int mmjack_shutdown(){  		data->client_name = NULL;  		close(data->fd);  		data->fd = -1; -	} -	free(inst); +		free(inst[u]->impl); +	} -	fprintf(stderr, "jack backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/jack.h b/backends/jack.h index 5598042..66c66db 100644 --- a/backends/jack.h +++ b/backends/jack.h @@ -6,11 +6,11 @@ MM_PLUGIN_API int init();  static int mmjack_configure(char* option, char* value);  static int mmjack_configure_instance(instance* inst, char* option, char* value);  static instance* mmjack_instance(); -static channel* mmjack_channel(instance* inst, char* spec); +static channel* mmjack_channel(instance* inst, char* spec, uint8_t flags);  static int mmjack_set(instance* inst, size_t num, channel** c, channel_value* v);  static int mmjack_handle(size_t num, managed_fd* fds); -static int mmjack_start(); -static int mmjack_shutdown(); +static int mmjack_start(size_t n, instance** inst); +static int mmjack_shutdown(size_t n, instance** inst);  #define JACK_DEFAULT_CLIENT_NAME "MIDIMonster"  #define JACK_DEFAULT_SERVER_NAME "default" diff --git a/backends/libmmbackend.c b/backends/libmmbackend.c index ccbeb52..ffa403b 100644 --- a/backends/libmmbackend.c +++ b/backends/libmmbackend.c @@ -1,6 +1,8 @@  #include "libmmbackend.h" -void mmbackend_parse_hostspec(char* spec, char** host, char** port){ +#define LOGPF(format, ...) fprintf(stderr, "libmmbe\t" format "\n", __VA_ARGS__) + +void mmbackend_parse_hostspec(char* spec, char** host, char** port, char** options){  	size_t u = 0;  	if(!spec || !host || !port){ @@ -29,6 +31,19 @@ void mmbackend_parse_hostspec(char* spec, char** host, char** port){  		spec[u] = 0;  		*port = spec + u + 1;  	} + +	if(options){ +		*options = NULL; +		if(*port){ +			//scan for space after port +			for(u = 0; (*port)[u] && !isspace((*port)[u]); u++){ +			} +			if(isspace((*port)[u])){ +				(*port)[u] = 0; +				*options = (*port) + u + 1; +			} +		} +	}  }  int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){ @@ -39,7 +54,7 @@ int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* ad  	int error = getaddrinfo(host, port, &hints, &head);  	if(error || !head){ -		fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error)); +		LOGPF("Failed to parse address %s port %s: %s", host, port, gai_strerror(error));  		return 1;  	} @@ -63,7 +78,7 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin  	status = getaddrinfo(host, port, &hints, &info);  	if(status){ -		fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(status)); +		LOGPF("Failed to parse address %s port %s: %s", host, port, gai_strerror(status));  		return -1;  	} @@ -77,18 +92,18 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin  		//set required socket options  		yes = 1;  		if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){ -			fprintf(stderr, "Failed to enable SO_REUSEADDR on socket\n"); +			LOGPF("Failed to enable SO_REUSEADDR on socket: %s", strerror(errno));  		}  		if(mcast){  			yes = 1;  			if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){ -				fprintf(stderr, "Failed to enable SO_BROADCAST on socket\n"); +				LOGPF("Failed to enable SO_BROADCAST on socket: %s", strerror(errno));  			}  			yes = 0;  			if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){ -				fprintf(stderr, "Failed to disable IP_MULTICAST_LOOP on socket: %s\n", strerror(errno)); +				LOGPF("Failed to disable IP_MULTICAST_LOOP on socket: %s", strerror(errno));  			}  		} @@ -112,7 +127,7 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin  	freeaddrinfo(info);  	if(!addr_it){ -		fprintf(stderr, "Failed to create socket for %s port %s\n", host, port); +		LOGPF("Failed to create socket for %s port %s", host, port);  		return -1;  	} @@ -126,7 +141,7 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin  	#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"); +		LOGPF("Failed to set socket nonblocking: %s", strerror(errno));  		close(fd);  		return -1;  	} @@ -140,7 +155,7 @@ int mmbackend_send(int fd, uint8_t* data, size_t length){  	while(total < length){  		sent = send(fd, data + total, length - total, 0);  		if(sent < 0){ -			fprintf(stderr, "Failed to send: %s\n", strerror(errno)); +			LOGPF("Failed to send: %s", strerror(errno));  			return 1;  		}  		total += sent; diff --git a/backends/libmmbackend.h b/backends/libmmbackend.h index 5749119..aa0d0f0 100644 --- a/backends/libmmbackend.h +++ b/backends/libmmbackend.h @@ -22,13 +22,15 @@  /*    * Parse spec as host specification in the form - *	host port + *	host port [options]   * into its constituent parts.   * Returns offsets into the original string and modifies it.   * Returns NULL in *port if none given.   * Returns NULL in both *port and *host if spec was an empty string. + * Returns a pointer after the port in *options if options is non-NULL + * and the port was not followed by \0   */ -void mmbackend_parse_hostspec(char* spec, char** host, char** port); +void mmbackend_parse_hostspec(char* spec, char** host, char** port, char** options);  /*    * Parse a given host / port combination into a sockaddr_storage @@ -92,7 +94,7 @@ size_t json_obj_offset(char* json, char* key);  size_t json_array_offset(char* json, uint64_t key);  /* - * Check for for a key within a JSON object / index within an array + * Check for a key within a JSON object / index within an array   * Assumes a zero-terminated, validated JSON object / array as input   * Returns type of value   */ diff --git a/backends/loopback.c b/backends/loopback.c index 0a45bde..085d1df 100644 --- a/backends/loopback.c +++ b/backends/loopback.c @@ -1,8 +1,8 @@ +#define BACKEND_NAME "loopback" +  #include <string.h>  #include "loopback.h" -#define BACKEND_NAME "loopback" -  MM_PLUGIN_API int init(){  	backend loopback = {  		.name = BACKEND_NAME, @@ -18,7 +18,7 @@ MM_PLUGIN_API int init(){  	//register backend  	if(mm_backend_register(loopback)){ -		fprintf(stderr, "Failed to register loopback backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0; @@ -42,14 +42,14 @@ static instance* loopback_instance(){  	i->impl = calloc(1, sizeof(loopback_instance_data));  	if(!i->impl){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	}  	return i;  } -static channel* loopback_channel(instance* inst, char* spec){ +static channel* loopback_channel(instance* inst, char* spec, uint8_t flags){  	size_t u;  	loopback_instance_data* data = (loopback_instance_data*) inst->impl; @@ -64,13 +64,13 @@ static channel* loopback_channel(instance* inst, char* spec){  	if(u == data->n){  		data->name = realloc(data->name, (u + 1) * sizeof(char*));  		if(!data->name){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		}  		data->name[u] = strdup(spec);  		if(!data->name[u]){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		}  		data->n++; @@ -92,20 +92,14 @@ static int loopback_handle(size_t num, managed_fd* fds){  	return 0;  } -static int loopback_start(){ +static int loopback_start(size_t n, instance** inst){  	return 0;  } -static int loopback_shutdown(){ -	size_t n, u, p; -	instance** inst = NULL; +static int loopback_shutdown(size_t n, instance** inst){ +	size_t u, p;  	loopback_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (loopback_instance_data*) inst[u]->impl;  		for(p = 0; p < data->n; p++){ @@ -115,8 +109,6 @@ static int loopback_shutdown(){  		free(inst[u]->impl);  	} -	free(inst); - -	fprintf(stderr, "Loopback backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/loopback.h b/backends/loopback.h index a08417b..c508d72 100644 --- a/backends/loopback.h +++ b/backends/loopback.h @@ -4,11 +4,11 @@ MM_PLUGIN_API int init();  static int loopback_configure(char* option, char* value);  static int loopback_configure_instance(instance* inst, char* option, char* value);  static instance* loopback_instance(); -static channel* loopback_channel(instance* inst, char* spec); +static channel* loopback_channel(instance* inst, char* spec, uint8_t flags);  static int loopback_set(instance* inst, size_t num, channel** c, channel_value* v);  static int loopback_handle(size_t num, managed_fd* fds); -static int loopback_start(); -static int loopback_shutdown(); +static int loopback_start(size_t n, instance** inst); +static int loopback_shutdown(size_t n, instance** inst);  typedef struct /*_loopback_instance_data*/ {  	size_t n; diff --git a/backends/lua.c b/backends/lua.c index 0b47b2c..ee9e03f 100644 --- a/backends/lua.c +++ b/backends/lua.c @@ -1,5 +1,6 @@ -#include "lua.h" +#define BACKEND_NAME "lua" +#include "lua.h"  #include <string.h>  #include <unistd.h>  #include <errno.h> @@ -7,7 +8,6 @@  #include <sys/timerfd.h>  #endif -#define BACKEND_NAME "lua"  #define LUA_REGISTRY_KEY "_midimonster_lua_instance"  static size_t timers = 0; @@ -37,7 +37,7 @@ MM_PLUGIN_API int init(){  	//register backend  	if(mm_backend_register(lua)){ -		fprintf(stderr, "Failed to register lua backend\n"); +		LOG("Failed to register backend");  		return 1;  	} @@ -45,7 +45,7 @@ MM_PLUGIN_API int init(){  	//create the timer to expire intervals  	timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);  	if(timer_fd < 0){ -		fprintf(stderr, "Failed to create timer for Lua backend\n"); +		LOG("Failed to create timer");  		return 1;  	}  	#endif @@ -130,7 +130,7 @@ static int lua_callback_output(lua_State* interpreter){  	lua_instance_data* data = NULL;  	if(lua_gettop(interpreter) != 2){ -		fprintf(stderr, "Lua output function called with %d arguments, expected 2 (string, number)\n", lua_gettop(interpreter)); +		LOGPF("Output function called with %d arguments, expected 2 (string, number)", lua_gettop(interpreter));  		return 0;  	} @@ -157,7 +157,7 @@ static int lua_callback_output(lua_State* interpreter){  		}  	} -	fprintf(stderr, "Tried to set unknown channel %s.%s\n", inst->name, channel_name); +	LOGPF("Tried to set unknown channel %s.%s", inst->name, channel_name);  	return 0;  } @@ -167,7 +167,7 @@ static int lua_callback_interval(lua_State* interpreter){  	int reference = LUA_NOREF;  	if(lua_gettop(interpreter) != 2){ -		fprintf(stderr, "Lua output function called with %d arguments, expected 2 (string, number)\n", lua_gettop(interpreter)); +		LOGPF("Interval function called with %d arguments, expected 2 (function, number)", lua_gettop(interpreter));  		return 0;  	} @@ -217,7 +217,7 @@ static int lua_callback_interval(lua_State* interpreter){  		//append new timer  		timer = realloc(timer, (timers + 1) * sizeof(lua_timer));  		if(!timer){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			timers = 0;  			return 0;  		} @@ -240,7 +240,7 @@ static int lua_callback_value(lua_State* interpreter, uint8_t input){  	const char* channel_name = NULL;  	if(lua_gettop(interpreter) != 1){ -		fprintf(stderr, "Lua get_value function called with %d arguments, expected 1 (string)\n", lua_gettop(interpreter)); +		LOGPF("get_value function called with %d arguments, expected 1 (string)", lua_gettop(interpreter));  		return 0;  	} @@ -261,7 +261,7 @@ static int lua_callback_value(lua_State* interpreter, uint8_t input){  		}  	} -	fprintf(stderr, "Tried to get unknown channel %s.%s\n", inst->name, channel_name); +	LOGPF("Tried to get unknown channel %s.%s", inst->name, channel_name);  	return 0;  } @@ -274,7 +274,7 @@ static int lua_callback_output_value(lua_State* interpreter){  }  static int lua_configure(char* option, char* value){ -	fprintf(stderr, "The lua backend does not take any global configuration\n"); +	LOG("No backend configuration possible");  	return 1;  } @@ -284,13 +284,13 @@ static int lua_configure_instance(instance* inst, char* option, char* value){  	//load a lua file into the interpreter  	if(!strcmp(option, "script") || !strcmp(option, "source")){  		if(luaL_dofile(data->interpreter, value)){ -			fprintf(stderr, "Failed to load lua source file %s for instance %s: %s\n", value, inst->name, lua_tostring(data->interpreter, -1)); +			LOGPF("Failed to load source file %s for instance %s: %s", value, inst->name, lua_tostring(data->interpreter, -1));  			return 1;  		}  		return 0;  	} -	fprintf(stderr, "Unknown configuration parameter %s for lua instance %s\n", option, inst->name); +	LOGPF("Unknown instance configuration parameter %s for instance %s", option, inst->name);  	return 1;  } @@ -302,14 +302,14 @@ static instance* lua_instance(){  	lua_instance_data* data = calloc(1, sizeof(lua_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	}  	//load the interpreter  	data->interpreter = luaL_newstate();  	if(!data->interpreter){ -		fprintf(stderr, "Failed to initialize LUA\n"); +		LOG("Failed to initialize interpreter");  		free(data);  		return NULL;  	} @@ -330,7 +330,7 @@ static instance* lua_instance(){  	return inst;  } -static channel* lua_channel(instance* inst, char* spec){ +static channel* lua_channel(instance* inst, char* spec, uint8_t flags){  	size_t u;  	lua_instance_data* data = (lua_instance_data*) inst->impl; @@ -348,7 +348,7 @@ static channel* lua_channel(instance* inst, char* spec){  		data->input = realloc(data->input, (u + 1) * sizeof(double));  		data->output = realloc(data->output, (u + 1) * sizeof(double));  		if(!data->channel_name || !data->reference || !data->input || !data->output){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		} @@ -356,7 +356,7 @@ static channel* lua_channel(instance* inst, char* spec){  		data->input[u] = data->output[u] = 0.0;  		data->channel_name[u] = strdup(spec);  		if(!data->channel_name[u]){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		}  		data->channels++; @@ -377,7 +377,7 @@ static int lua_set(instance* inst, size_t num, channel** c, channel_value* v){  			lua_rawgeti(data->interpreter, LUA_REGISTRYINDEX, data->reference[c[n]->ident]);  			lua_pushnumber(data->interpreter, v[n].normalised);  			if(lua_pcall(data->interpreter, 1, 0, 0) != LUA_OK){ -				fprintf(stderr, "Failed to call handler for %s.%s: %s\n", inst->name, data->channel_name[c[n]->ident], lua_tostring(data->interpreter, -1)); +				LOGPF("Failed to call handler for %s.%s: %s", inst->name, data->channel_name[c[n]->ident], lua_tostring(data->interpreter, -1));  				lua_pop(data->interpreter, 1);  			}  		} @@ -397,7 +397,7 @@ static int lua_handle(size_t num, managed_fd* fds){  	//read the timer iteration to acknowledge the fd  	if(read(timer_fd, read_buffer, sizeof(read_buffer)) < 0){ -		fprintf(stderr, "Failed to read from Lua timer: %s\n", strerror(errno)); +		LOGPF("Failed to read timer: %s", strerror(errno));  		return 1;  	}  	#else @@ -428,17 +428,10 @@ static int lua_handle(size_t num, managed_fd* fds){  	return 0;  } -static int lua_start(){ -	size_t n, u, p; -	instance** inst = NULL; +static int lua_start(size_t n, instance** inst){ +	size_t u, p;  	lua_instance_data* data = NULL; -	//fetch all defined instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	//resolve channels to their handler functions  	for(u = 0; u < n; u++){  		data = (lua_instance_data*) inst[u]->impl; @@ -457,11 +450,9 @@ static int lua_start(){  		}  	} -	free(inst); -  	#ifdef MMBACKEND_LUA_TIMERFD  	//register the timer with the core -	fprintf(stderr, "Lua backend registering 1 descriptor to core\n"); +	LOG("Registering 1 descriptor to core");  	if(mm_manage_fd(timer_fd, BACKEND_NAME, 1, NULL)){  		return 1;  	} @@ -469,17 +460,10 @@ static int lua_start(){  	return 0;  } -static int lua_shutdown(){ -	size_t n, u, p; -	instance** inst = NULL; +static int lua_shutdown(size_t n, instance** inst){ +	size_t u, p;  	lua_instance_data* data = NULL; -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (lua_instance_data*) inst[u]->impl;  		//stop the interpreter @@ -495,7 +479,6 @@ static int lua_shutdown(){  		free(inst[u]->impl);  	} -	free(inst);  	//free module-global data  	free(timer);  	timer = NULL; @@ -505,6 +488,6 @@ static int lua_shutdown(){  	timer_fd = -1;  	#endif -	fprintf(stderr, "Lua backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/lua.h b/backends/lua.h index e187a8e..75f03c4 100644 --- a/backends/lua.h +++ b/backends/lua.h @@ -13,11 +13,11 @@ MM_PLUGIN_API int init();  static int lua_configure(char* option, char* value);  static int lua_configure_instance(instance* inst, char* option, char* value);  static instance* lua_instance(); -static channel* lua_channel(instance* inst, char* spec); +static channel* lua_channel(instance* inst, char* spec, uint8_t flags);  static int lua_set(instance* inst, size_t num, channel** c, channel_value* v);  static int lua_handle(size_t num, managed_fd* fds); -static int lua_start(); -static int lua_shutdown(); +static int lua_start(size_t n, instance** inst); +static int lua_shutdown(size_t n, instance** inst);  #ifndef MMBACKEND_LUA_TIMERFD  static uint32_t lua_interval();  #endif diff --git a/backends/maweb.c b/backends/maweb.c index 08156f2..f81ab46 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "maweb" +  #include <string.h>  #include <unistd.h>  #include <errno.h> @@ -8,7 +10,6 @@  #include "libmmbackend.h"  #include "maweb.h" -#define BACKEND_NAME "maweb"  #define WS_LEN(a) ((a) & 0x7F)  #define WS_OP(a) ((a) & 0x0F)  #define WS_FLAG_FIN 0x80 @@ -88,7 +89,7 @@ MM_PLUGIN_API int init(){  	//register backend  	if(mm_backend_register(maweb)){ -		fprintf(stderr, "Failed to register maweb backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0; @@ -139,18 +140,18 @@ static int maweb_configure(char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown maweb backend configuration option %s\n", option); +	LOGPF("Unknown backend configuration option %s", option);  	return 1;  }  static int maweb_configure_instance(instance* inst, char* option, char* value){  	maweb_instance_data* data = (maweb_instance_data*) inst->impl; -	char* host = NULL, *port = NULL; +	char* host = NULL, *port = NULL, *fd_opts = NULL;  	if(!strcmp(option, "host")){ -		mmbackend_parse_hostspec(value, &host, &port); +		mmbackend_parse_hostspec(value, &host, &port, &fd_opts);  		if(!host){ -			fprintf(stderr, "Invalid host specified for maweb instance %s\n", inst->name); +			LOGPF("Invalid host specified for instance %s", inst->name);  			return 1;  		}  		free(data->host); @@ -179,7 +180,7 @@ static int maweb_configure_instance(instance* inst, char* option, char* value){  		}  		return 0;  		#else -		fprintf(stderr, "This build of the maweb backend only supports the default password\n"); +		LOG("This build only supports the default password");  		return 1;  		#endif  	} @@ -194,13 +195,13 @@ static int maweb_configure_instance(instance* inst, char* option, char* value){  			data->cmdline = cmd_downgrade;  		}  		else{ -			fprintf(stderr, "Unknown maweb commandline mode %s for instance %s\n", value, inst->name); +			LOGPF("Unknown commandline mode %s for instance %s", value, inst->name);  			return 1;  		}  		return 0;  	} -	fprintf(stderr, "Unknown configuration parameter %s for maweb instance %s\n", option, inst->name); +	LOGPF("Unknown instance configuration parameter %s for instance %s", option, inst->name);  	return 1;  } @@ -212,14 +213,14 @@ static instance* maweb_instance(){  	maweb_instance_data* data = calloc(1, sizeof(maweb_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	}  	data->fd = -1;  	data->buffer = calloc(MAWEB_RECV_CHUNK, sizeof(uint8_t));  	if(!data->buffer){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		free(data);  		return NULL;  	} @@ -229,7 +230,7 @@ static instance* maweb_instance(){  	return inst;  } -static channel* maweb_channel(instance* inst, char* spec){ +static channel* maweb_channel(instance* inst, char* spec, uint8_t flags){  	maweb_instance_data* data = (maweb_instance_data*) inst->impl;  	maweb_channel_data chan = {  		0 @@ -241,7 +242,7 @@ static channel* maweb_channel(instance* inst, char* spec){  	if(!strncmp(spec, "page", 4)){  		chan.page = strtoul(spec + 4, &next_token, 10);  		if(*next_token != '.'){ -			fprintf(stderr, "Failed to parse maweb channel spec %s: Missing separator\n", spec); +			LOGPF("Failed to parse channel spec %s: Missing separator", spec);  			return NULL;  		} @@ -273,7 +274,7 @@ static channel* maweb_channel(instance* inst, char* spec){  			if(!strcmp(spec, cmdline_keys[n].name)){  				if((data->cmdline == cmd_remote && !cmdline_keys[n].press && !cmdline_keys[n].release)  							|| (data->cmdline == cmd_console && !cmdline_keys[n].lua)){ -					fprintf(stderr, "maweb cmdline key %s does not work with the current commandline mode for instance %s\n", spec, inst->name); +					LOGPF("Key %s does not work with the current commandline mode for instance %s", spec, inst->name);  					return NULL;  				} @@ -293,7 +294,7 @@ static channel* maweb_channel(instance* inst, char* spec){  		if(maweb_channel_index(data, chan.type, chan.page, chan.index) == -1){  			data->channel = realloc(data->channel, (data->channels + 1) * sizeof(maweb_channel_data));  			if(!data->channel){ -				fprintf(stderr, "Failed to allocate memory\n"); +				LOG("Failed to allocate memory");  				return NULL;  			}  			data->channel[data->channels] = chan; @@ -305,7 +306,7 @@ static channel* maweb_channel(instance* inst, char* spec){  		return channel_ref;  	} -	fprintf(stderr, "Failed to parse maweb channel spec %s\n", spec); +	LOGPF("Failed to parse channel spec %s", spec);  	return NULL;  } @@ -353,7 +354,7 @@ 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 %" PRIu64 ".%" PRIu64 "\n", page, exec_index); +		LOGPF("Missing exec block data on exec %" PRIu64 ".%" PRIu64, page, exec_index);  		return 1;  	} @@ -395,7 +396,7 @@ static int maweb_process_playback(instance* inst, int64_t page, maweb_channel_ty  			}  		} -		DBGPF("maweb page %" PRIu64 " exec %" PRIu64 " value %f running %" PRIu64 "\n", page, exec_index, json_obj_double(payload + control, "v", 0.0), json_obj_int(payload, "isRun", 0)); +		DBGPF("Page %" PRIu64 " exec %" PRIu64 " value %f running %" PRIu64, page, exec_index, json_obj_double(payload + control, "v", 0.0), json_obj_int(payload, "isRun", 0));  		exec_index++;  		block++;  	} @@ -408,12 +409,12 @@ static int maweb_process_playbacks(instance* inst, int64_t page, char* payload,  	uint64_t group = 0, subgroup, item, metatype;  	if(!page){ -		fprintf(stderr, "maweb received playbacks for invalid page\n"); +		LOG("Received playbacks for invalid page");  		return 0;  	}  	if(!base_offset){ -		fprintf(stderr, "maweb playback data missing item key\n"); +		LOG("Playback data missing item key");  		return 0;  	} @@ -448,7 +449,7 @@ static int maweb_process_playbacks(instance* inst, int64_t page, char* payload,  		group++;  	}  	updates_inflight--; -	DBGPF("maweb playback message processing done, %" PRIu64 " updates inflight\n", updates_inflight); +	DBGPF("Playback message processing done, %" PRIu64 " updates inflight", updates_inflight);  	return 0;  } @@ -461,7 +462,7 @@ static int maweb_request_playbacks(instance* inst){  	size_t page_index = 0, view = 3, channel = 0, offsets[3], channel_offset, channels;  	if(updates_inflight){ -		fprintf(stderr, "maweb skipping update request, %" PRIu64 " updates still inflight\n", updates_inflight); +		LOGPF("Skipping update request, %" PRIu64 " updates still inflight", updates_inflight);  		return 0;  	} @@ -522,7 +523,7 @@ static int maweb_request_playbacks(instance* inst){  			snprintf(item_counts, sizeof(item_indices), "[%" PRIsize_t "]", ((channels / 5) * 5 + 5));  		} -		DBGPF("maweb poll range first %d: %d.%d last %d: %d.%d next %d: %d.%d\n", +		DBGPF("Poll range first %d: %d.%d last %d: %d.%d next %d: %d.%d",  				data->channel[channel].type, data->channel[channel].page, data->channel[channel].index,  				data->channel[channel + channel_offset - 1].type, data->channel[channel + channel_offset - 1].page, data->channel[channel + channel_offset - 1].index,  				data->channel[channel + channel_offset].type, data->channel[channel + channel_offset].page, data->channel[channel + channel_offset].index); @@ -550,11 +551,11 @@ static int maweb_request_playbacks(instance* inst){  				view,  				data->session);  		rv |= maweb_send_frame(inst, ws_text, (uint8_t*) xmit_buffer, strlen(xmit_buffer)); -		DBGPF("maweb poll request: %s\n", xmit_buffer); +		DBGPF("Poll request: %s", xmit_buffer);  		updates_inflight++;  	} -	DBGPF("maweb poll request handling done, %" PRIu64 " updates requested\n", updates_inflight); +	DBGPF("Poll request handling done, %" PRIu64 " updates requested", updates_inflight);  	return rv;  } @@ -568,42 +569,42 @@ static int maweb_handle_message(instance* inst, char* payload, size_t payload_le  		field = json_obj_str(payload, "responseType", NULL);  		if(!strncmp(field, "login", 5)){  			if(json_obj_bool(payload, "result", 0)){ -				fprintf(stderr, "maweb login successful\n"); +				LOG("Login successful");  				data->login = 1;  			}  			else{ -				fprintf(stderr, "maweb login failed\n"); +				LOG("Login failed");  				data->login = 0;  			}  		}  		if(!strncmp(field, "playbacks", 9)){  			if(maweb_process_playbacks(inst, json_obj_int(payload, "iPage", 0), payload, payload_length)){ -				fprintf(stderr, "maweb failed to handle/request input data\n"); +				LOG("Failed to handle/request input data");  			}  			return 0;  		}  	} -	DBGPF("maweb message (%" PRIsize_t "): %s\n", payload_length, payload); +	DBGPF("Incoming message (%" PRIsize_t "): %s", payload_length, payload);  	if(json_obj(payload, "session") == JSON_NUMBER){  		data->session = json_obj_int(payload, "session", data->session);  		if(data->session < 0){ -				fprintf(stderr, "maweb login failed\n"); +				LOG("Login failed");  				data->login = 0;  				return 0;  		} -		fprintf(stderr, "maweb session id is now %" PRId64 "\n", data->session); +		LOGPF("Session id is now %" PRId64, data->session);  	}  	if(json_obj_bool(payload, "forceLogin", 0)){ -		fprintf(stderr, "maweb sending user credentials\n"); +		LOG("Sending user credentials");  		snprintf(xmit_buffer, sizeof(xmit_buffer),  				"{\"requestType\":\"login\",\"username\":\"%s\",\"password\":\"%s\",\"session\":%" PRIu64 "}",  				(data->peer_type == peer_dot2) ? "remote" : data->user, data->pass ? data->pass : MAWEB_DEFAULT_PASSWORD, data->session);  		maweb_send_frame(inst, ws_text, (uint8_t*) xmit_buffer, strlen(xmit_buffer));  	}  	if(json_obj(payload, "status") && json_obj(payload, "appType")){ -		fprintf(stderr, "maweb connection established\n"); +		LOG("Connection established");  		field = json_obj_str(payload, "appType", NULL);  		if(!strncmp(field, "dot2", 4)){  			data->peer_type = peer_dot2; @@ -644,13 +645,13 @@ static int maweb_connect(instance* inst){  			//and the whole websocket 'accept key' dance is plenty stupid as it is  			|| mmbackend_send_str(data->fd, "Sec-WebSocket-Key: rbEQrXMEvCm4ZUjkj6juBQ==\r\n")  			|| mmbackend_send_str(data->fd, "\r\n")){ -		fprintf(stderr, "maweb backend failed to communicate with peer\n"); +		LOG("Failed to communicate with peer");  		return 1;  	}  	//register new fd  	if(mm_manage_fd(data->fd, BACKEND_NAME, 1, (void*) inst)){ -		fprintf(stderr, "maweb backend failed to register fd\n"); +		LOG("Failed to register FD");  		return 1;  	}  	return 0; @@ -667,7 +668,7 @@ static ssize_t maweb_handle_lines(instance* inst, ssize_t bytes_read){  					data->state = ws_http;  				}  				else{ -					fprintf(stderr, "maweb received invalid HTTP response for instance %s\n", inst->name); +					LOGPF("Invalid HTTP response for instance %s", inst->name);  					return -1;  				}  			} @@ -737,11 +738,11 @@ static ssize_t maweb_handle_ws(instance* inst, ssize_t bytes_read){  		case ws_ping:  			//answer server ping with a pong  			if(maweb_send_frame(inst, ws_pong, payload, payload_length)){ -				fprintf(stderr, "maweb failed to send pong\n"); +				LOG("Failed to send pong");  			}  			return header_length + payload_length;  		default: -			fprintf(stderr, "maweb encountered unhandled frame type %02X\n", WS_OP(data->buffer[0])); +			LOGPF("Unhandled frame type %02X", WS_OP(data->buffer[0]));  			//this is somewhat dicey, it might be better to handle only header + payload length for known but unhandled types  			return data->offset + bytes_read;  	} @@ -751,12 +752,12 @@ static ssize_t maweb_handle_ws(instance* inst, ssize_t bytes_read){  static int maweb_handle_fd(instance* inst){  	maweb_instance_data* data = (maweb_instance_data*) inst->impl; -	ssize_t bytes_read, bytes_left = data->allocated - data->offset, bytes_handled; +	ssize_t bytes_read, bytes_left = data->allocated - data->offset, bytes_handled = 0;  	if(bytes_left < 3){  		data->buffer = realloc(data->buffer, (data->allocated + MAWEB_RECV_CHUNK) * sizeof(uint8_t));  		if(!data->buffer){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return 1;  		}  		data->allocated += MAWEB_RECV_CHUNK; @@ -765,7 +766,7 @@ static int maweb_handle_fd(instance* inst){  	bytes_read = recv(data->fd, data->buffer + data->offset, bytes_left - 1, 0);  	if(bytes_read < 0){ -		fprintf(stderr, "maweb backend failed to receive: %s\n", strerror(errno)); +		LOGPF("Failed to receive: %s", strerror(errno));  		//TODO close, reopen  		return 1;  	} @@ -793,7 +794,7 @@ static int maweb_handle_fd(instance* inst){  			bytes_handled = data->offset + bytes_read;  			data->offset = 0;  			//TODO close, reopen -			fprintf(stderr, "maweb failed to handle incoming data\n"); +			LOG("Failed to handle incoming data");  			return 1;  		}  		else if(bytes_handled == 0){ @@ -818,7 +819,7 @@ static int maweb_set(instance* inst, size_t num, channel** c, channel_value* v){  	size_t n;  	if(num && !data->login){ -		fprintf(stderr, "maweb instance %s can not send output, not logged in\n", inst->name); +		LOGPF("Instance %s can not send output, not logged in", inst->name);  		return 0;  	} @@ -904,16 +905,16 @@ static int maweb_set(instance* inst, size_t num, channel** c, channel_value* v){  					}  				}  				else{ -					fprintf(stderr, "maweb commandline key %s not executed on %s due to mode mismatch\n", +					LOGPF("Key %s not executed on %s due to mode mismatch",  							cmdline_keys[chan->index].name, inst->name);  					continue;  				}  				break;  			default: -				fprintf(stderr, "maweb control not yet implemented\n"); +				LOG("Control not yet implemented");  				return 1;  		} -		DBGPF("maweb command out %s\n", xmit_buffer); +		DBGPF("Command out %s", xmit_buffer);  		maweb_send_frame(inst, ws_text, (uint8_t*) xmit_buffer, strlen(xmit_buffer));  	}  	return 0; @@ -927,7 +928,7 @@ static int maweb_keepalive(){  	//fetch all defined instances  	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); +		LOG("Failed to fetch instance list");  		return 1;  	} @@ -951,7 +952,7 @@ static int maweb_poll(){  	//fetch all defined instances  	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); +		LOG( "Failed to fetch instance list");  		return 1;  	} @@ -989,17 +990,10 @@ static int maweb_handle(size_t num, managed_fd* fds){  	return rv;  } -static int maweb_start(){ -	size_t n, u, p; -	instance** inst = NULL; +static int maweb_start(size_t n, instance** inst){ +	size_t u, p;  	maweb_instance_data* data = NULL; -	//fetch all defined instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		//sort channels  		data = (maweb_instance_data*) inst[u]->impl; @@ -1011,35 +1005,23 @@ static int maweb_start(){  		}  		if(maweb_connect(inst[u])){ -			fprintf(stderr, "Failed to open connection to MA Web Remote for instance %s\n", inst[u]->name); +			LOGPF("Failed to open connection for instance %s", inst[u]->name);  			free(inst);  			return 1;  		}  	} -	free(inst); -	if(!n){ -		return 0; -	} - -	fprintf(stderr, "maweb backend registering %" PRIsize_t " descriptors to core\n", n); +	LOGPF("Registering %" PRIsize_t " descriptors to core", n);  	//initialize timeouts  	last_keepalive = last_update = mm_timestamp();  	return 0;  } -static int maweb_shutdown(){ -	size_t n, u; -	instance** inst = NULL; +static int maweb_shutdown(size_t n, instance** inst){ +	size_t u;  	maweb_instance_data* data = NULL; -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (maweb_instance_data*) inst[u]->impl;  		free(data->host); @@ -1063,10 +1045,10 @@ static int maweb_shutdown(){  		free(data->channel);  		data->channel = NULL;  		data->channels = 0; -	} -	free(inst); +		free(inst[u]->impl); +	} -	fprintf(stderr, "maweb backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/maweb.h b/backends/maweb.h index 9091cda..50b777a 100644 --- a/backends/maweb.h +++ b/backends/maweb.h @@ -4,11 +4,11 @@ MM_PLUGIN_API int init();  static int maweb_configure(char* option, char* value);  static int maweb_configure_instance(instance* inst, char* option, char* value);  static instance* maweb_instance(); -static channel* maweb_channel(instance* inst, char* spec); +static channel* maweb_channel(instance* inst, char* spec, uint8_t flags);  static int maweb_set(instance* inst, size_t num, channel** c, channel_value* v);  static int maweb_handle(size_t num, managed_fd* fds); -static int maweb_start(); -static int maweb_shutdown(); +static int maweb_start(size_t n, instance** inst); +static int maweb_shutdown(size_t n, instance** inst);  static uint32_t maweb_interval();  //Default login password: MD5("midimonster") diff --git a/backends/midi.c b/backends/midi.c index f380f59..11d759d 100644 --- a/backends/midi.c +++ b/backends/midi.c @@ -1,8 +1,9 @@ +#define BACKEND_NAME "midi" +  #include <string.h>  #include <alsa/asoundlib.h>  #include "midi.h" -#define BACKEND_NAME "midi"  static char* sequencer_name = NULL;  static snd_seq_t* sequencer = NULL; @@ -37,13 +38,13 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(midi_channel_ident) != sizeof(uint64_t)){ -		fprintf(stderr, "MIDI channel identification union out of bounds\n"); +		LOG("Channel identification union out of bounds");  		return 1;  	}  	//register backend  	if(mm_backend_register(midi)){ -		fprintf(stderr, "Failed to register MIDI backend\n"); +		LOG("Failed to register backend");  		return 1;  	} @@ -64,7 +65,7 @@ static int midi_configure(char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown MIDI backend option %s\n", option); +	LOGPF("Unknown backend option %s", option);  	return 1;  } @@ -76,7 +77,7 @@ static instance* midi_instance(){  	inst->impl = calloc(1, sizeof(midi_instance_data));  	if(!inst->impl){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -90,7 +91,7 @@ static int midi_configure_instance(instance* inst, char* option, char* value){  	if(!strcmp(option, "read")){  		//connect input device  		if(data->read){ -			fprintf(stderr, "MIDI instance %s was already connected to an input device\n", inst->name); +			LOGPF("Instance %s was already connected to an input device", inst->name);  			return 1;  		}  		data->read = strdup(value); @@ -99,18 +100,18 @@ static int midi_configure_instance(instance* inst, char* option, char* value){  	else if(!strcmp(option, "write")){  		//connect output device  		if(data->write){ -			fprintf(stderr, "MIDI instance %s was already connected to an output device\n", inst->name); +			LOGPF("Instance %s was already connected to an output device", inst->name);  			return 1;  		}  		data->write = strdup(value);  		return 0;  	} -	fprintf(stderr, "Unknown MIDI instance option %s\n", option); +	LOGPF("Unknown instance option %s", option);  	return 1;  } -static channel* midi_channel(instance* inst, char* spec){ +static channel* midi_channel(instance* inst, char* spec, uint8_t flags){  	midi_channel_ident ident = {  		.label = 0  	}; @@ -141,18 +142,18 @@ static channel* midi_channel(instance* inst, char* spec){  		old_syntax = 1;  	}  	else{ -		fprintf(stderr, "Unknown MIDI channel control type in %s\n", spec); +		LOGPF("Unknown control type in %s", spec);  		return NULL;  	}  	ident.fields.channel = strtoul(channel, &channel, 10);  	if(ident.fields.channel > 15){ -		fprintf(stderr, "MIDI channel out of range in midi channel spec %s\n", spec); +		LOGPF("Channel out of range in spec %s", spec);  		return NULL;  	}  	if(*channel != '.'){ -		fprintf(stderr, "Need MIDI channel specification of form channel<X>.<control><Y>, had %s\n", spec); +		LOGPF("Need specification of form channel<X>.<control><Y>, had %s", spec);  		return NULL;  	}  	//skip the period @@ -182,7 +183,7 @@ static channel* midi_channel(instance* inst, char* spec){  			ident.fields.type = aftertouch;  		}  		else{ -			fprintf(stderr, "Unknown MIDI channel control type in %s\n", spec); +			LOGPF("Unknown control type in %s", spec);  			return NULL;  		}  	} @@ -306,14 +307,14 @@ static int midi_handle(size_t num, managed_fd* fds){  				ident.fields.control = ev->data.control.param;  				break;  			default: -				fprintf(stderr, "Ignored MIDI event of unsupported type\n"); +				LOG("Ignored event of unsupported type");  				continue;  		}  		inst = mm_instance_find(BACKEND_NAME, ev->dest.port);  		if(!inst){  			//FIXME might want to return failure -			fprintf(stderr, "Delivered MIDI event did not match any instance\n"); +			LOG("Delivered event did not match any instance");  			continue;  		} @@ -327,10 +328,10 @@ static int midi_handle(size_t num, managed_fd* fds){  		if(midi_config.detect && event_type){  			if(ident.fields.type == pitchbend || ident.fields.type == aftertouch){ -				fprintf(stderr, "Incoming MIDI data on channel %s.ch%d.%s\n", inst->name, ident.fields.channel, event_type); +				LOGPF("Incoming data on channel %s.ch%d.%s", inst->name, ident.fields.channel, event_type);  			}  			else{ -				fprintf(stderr, "Incoming MIDI data on channel %s.ch%d.%s%d\n", inst->name, ident.fields.channel, event_type, ident.fields.control); +				LOGPF("Incoming data on channel %s.ch%d.%s%d", inst->name, ident.fields.channel, event_type, ident.fields.control);  			}  		}  	} @@ -338,37 +339,25 @@ static int midi_handle(size_t num, managed_fd* fds){  	return 0;  } -static int midi_start(){ -	size_t n = 0, p; +static int midi_start(size_t n, instance** inst){ +	size_t p;  	int nfds, rv = 1;  	struct pollfd* pfds = NULL; -	instance** inst = NULL;  	midi_instance_data* data = NULL;  	snd_seq_addr_t addr; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	//if there are no ports, do nothing -	if(!n){ -		free(inst); -		return 0; -	} -  	//connect to the sequencer  	if(snd_seq_open(&sequencer, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0){ -		fprintf(stderr, "Failed to open ALSA sequencer\n"); +		LOG("Failed to open ALSA sequencer");  		goto bail;  	}  	snd_seq_nonblock(sequencer, 1); -	fprintf(stderr, "MIDI client ID is %d\n", snd_seq_client_id(sequencer)); +	LOGPF("Client ID is %d", snd_seq_client_id(sequencer));  	//update the sequencer client name  	if(snd_seq_set_client_name(sequencer, sequencer_name ? sequencer_name : "MIDIMonster") < 0){ -		fprintf(stderr, "Failed to set MIDI client name to %s\n", sequencer_name); +		LOGPF("Failed to set client name to %s", sequencer_name);  		goto bail;  	} @@ -381,11 +370,11 @@ static int midi_start(){  		//make connections  		if(data->write){  			if(snd_seq_parse_address(sequencer, &addr, data->write) == 0){ -				fprintf(stderr, "Connecting output of instance %s to MIDI device %s (%d:%d)\n", inst[p]->name, data->write, addr.client, addr.port); +				LOGPF("Connecting output of instance %s to device %s (%d:%d)", inst[p]->name, data->write, addr.client, addr.port);  				snd_seq_connect_to(sequencer, data->port, addr.client, addr.port);  			}  			else{ -				fprintf(stderr, "Failed to get destination MIDI device address: %s\n", data->write); +				LOGPF("Failed to get destination device address: %s", data->write);  			}  			free(data->write);  			data->write = NULL; @@ -393,11 +382,11 @@ static int midi_start(){  		if(data->read){  			if(snd_seq_parse_address(sequencer, &addr, data->read) == 0){ -				fprintf(stderr, "Connecting input from MIDI device %s to instance %s (%d:%d)\n", data->read, inst[p]->name, addr.client, addr.port); +				LOGPF("Connecting input from device %s to instance %s (%d:%d)", data->read, inst[p]->name, addr.client, addr.port);  				snd_seq_connect_from(sequencer, data->port, addr.client, addr.port);  			}  			else{ -				fprintf(stderr, "Failed to get source MIDI device address: %s\n", data->read); +				LOGPF("Failed to get source device address: %s", data->read);  			}  			free(data->read);  			data->read = NULL; @@ -408,12 +397,12 @@ static int midi_start(){  	nfds = snd_seq_poll_descriptors_count(sequencer, POLLIN | POLLOUT);  	pfds = calloc(nfds, sizeof(struct pollfd));  	if(!pfds){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		goto bail;  	}  	nfds = snd_seq_poll_descriptors(sequencer, pfds, nfds, POLLIN | POLLOUT); -	fprintf(stderr, "MIDI backend registering %d descriptors to core\n", nfds); +	LOGPF("Registering %d descriptors to core", nfds);  	for(p = 0; p < nfds; p++){  		if(mm_manage_fd(pfds[p].fd, BACKEND_NAME, 1, NULL)){  			goto bail; @@ -424,18 +413,12 @@ static int midi_start(){  bail:  	free(pfds); -	free(inst);  	return rv;  } -static int midi_shutdown(){ -	size_t n, p; -	instance** inst = NULL; +static int midi_shutdown(size_t n, instance** inst){ +	size_t p;  	midi_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	}  	for(p = 0; p < n; p++){  		data = (midi_instance_data*) inst[p]->impl; @@ -445,7 +428,6 @@ static int midi_shutdown(){  		data->write = NULL;  		free(inst[p]->impl);  	} -	free(inst);  	//close midi  	if(sequencer){ @@ -459,6 +441,6 @@ static int midi_shutdown(){  	free(sequencer_name);  	sequencer_name = NULL; -	fprintf(stderr, "MIDI backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/midi.h b/backends/midi.h index b9934f1..66a02bc 100644 --- a/backends/midi.h +++ b/backends/midi.h @@ -4,11 +4,11 @@ MM_PLUGIN_API int init();  static int midi_configure(char* option, char* value);  static int midi_configure_instance(instance* instance, char* option, char* value);  static instance* midi_instance(); -static channel* midi_channel(instance* instance, char* spec); +static channel* midi_channel(instance* instance, char* spec, uint8_t flags);  static int midi_set(instance* inst, size_t num, channel** c, channel_value* v);  static int midi_handle(size_t num, managed_fd* fds); -static int midi_start(); -static int midi_shutdown(); +static int midi_start(size_t n, instance** inst); +static int midi_shutdown(size_t n, instance** inst);  typedef struct /*_midi_instance_data*/ {  	int port; diff --git a/backends/ola.cpp b/backends/ola.cpp index d069a8c..09d68c9 100644 --- a/backends/ola.cpp +++ b/backends/ola.cpp @@ -1,3 +1,5 @@ +#define BACKEND_NAME "ola" +  #include "ola.h"  #include <cstring>  #include <ola/DmxBuffer.h> @@ -7,7 +9,6 @@  #include <ola/io/SelectServer.h>  #include <ola/network/Socket.h> -#define BACKEND_NAME "ola"  static ola::io::SelectServer* ola_select = NULL;  static ola::OlaCallbackClient* ola_client = NULL; @@ -26,7 +27,7 @@ MM_PLUGIN_API int init(){  	//register backend  	if(mm_backend_register(ola)){ -		fprintf(stderr, "Failed to register OLA backend\n"); +		LOG("Failed to register backend");  		return 1;  	} @@ -35,7 +36,7 @@ MM_PLUGIN_API int init(){  }  static int ola_configure(char* option, char* value){ -	fprintf(stderr, "Unknown OLA backend option %s\n", option); +	LOGPF("Unknown backend option %s", option);  	return 1;  } @@ -48,7 +49,7 @@ static instance* ola_instance(){  	data = (ola_instance_data*)calloc(1, sizeof(ola_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -64,11 +65,11 @@ static int ola_configure_instance(instance* inst, char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown OLA option %s for instance %s\n", option, inst->name); +	LOGPF("Unknown instance configuration option %s for instance %s", option, inst->name);  	return 1;  } -static channel* ola_channel(instance* inst, char* spec){ +static channel* ola_channel(instance* inst, char* spec, uint8_t flags){  	ola_instance_data* data = (ola_instance_data*) inst->impl;  	char* spec_next = spec;  	unsigned chan_a = strtoul(spec, &spec_next, 10); @@ -76,7 +77,7 @@ static channel* ola_channel(instance* inst, char* spec){  	//primary channel sanity check  	if(!chan_a || chan_a > 512){ -		fprintf(stderr, "Invalid OLA channel specification %s\n", spec); +		LOGPF("Invalid channel specification %s", spec);  		return NULL;  	}  	chan_a--; @@ -85,14 +86,14 @@ static channel* ola_channel(instance* inst, char* spec){  	if(*spec_next == '+'){  		chan_b = strtoul(spec_next + 1, NULL, 10);  		if(!chan_b || chan_b > 512){ -			fprintf(stderr, "Invalid wide-channel spec %s\n", spec); +			LOGPF("Invalid wide-channel spec %s", spec);  			return NULL;  		}  		chan_b--;  		//if mapped mode differs, bail  		if(IS_ACTIVE(data->data.map[chan_b]) && data->data.map[chan_b] != (MAP_FINE | chan_a)){ -			fprintf(stderr, "Fine channel already mapped for OLA spec %s\n", spec); +			LOGPF("Fine channel already mapped for spec %s", spec);  			return NULL;  		} @@ -103,7 +104,7 @@ static channel* ola_channel(instance* inst, char* spec){  	if(IS_ACTIVE(data->data.map[chan_a])){  		if((*spec_next == '+' && data->data.map[chan_a] != (MAP_COARSE | chan_b))  				|| (*spec_next != '+' && data->data.map[chan_a] != (MAP_SINGLE | chan_a))){ -			fprintf(stderr, "Primary OLA channel already mapped at differing mode: %s\n", spec); +			LOGPF("Primary channel already mapped at differing mode: %s", spec);  			return NULL;  		}  	} @@ -189,7 +190,7 @@ static void ola_data_receive(unsigned int universe, const ola::DmxBuffer& ola_dm  			}  			if(!chan){ -				fprintf(stderr, "Active channel %zu on %s not known to core\n", p, inst->name); +				LOGPF("Active channel %" PRIsize_t " on %s not known to core", p, inst->name);  				return;  			} @@ -207,7 +208,7 @@ static void ola_data_receive(unsigned int universe, const ola::DmxBuffer& ola_dm  			}  			if(mm_channel_event(chan, val)){ -				fprintf(stderr, "Failed to push OLA channel event to core\n"); +				LOG("Failed to push event to core");  				return;  			}  		} @@ -216,51 +217,38 @@ static void ola_data_receive(unsigned int universe, const ola::DmxBuffer& ola_dm  static void ola_register_callback(const std::string &error) {  	if(!error.empty()){ -		fprintf(stderr, "OLA backend failed to register for universe: %s\n", error.c_str()); +		LOGPF("Failed to register for universe: %s", error.c_str());  	}  } -static int ola_start(){ -	size_t n, u, p; -	instance** inst = NULL; +static int ola_start(size_t n, instance** inst){ +	size_t u, p;  	ola_instance_data* data = NULL;  	ola_select = new ola::io::SelectServer();  	ola::network::IPV4SocketAddress ola_server(ola::network::IPV4Address::Loopback(), ola::OLA_DEFAULT_PORT);  	ola::network::TCPSocket* ola_socket = ola::network::TCPSocket::Connect(ola_server);  	if(!ola_socket){ -		fprintf(stderr, "Failed to connect to OLA server\n"); +		LOG("Failed to connect to server");  		return 1;  	}  	ola_client = new ola::OlaCallbackClient(ola_socket);  	if(!ola_client->Setup()){ -		fprintf(stderr, "Failed to start OLA client\n"); +		LOG("Failed to start client");  		goto bail;  	}  	ola_select->AddReadDescriptor(ola_socket); -	fprintf(stderr, "OLA backend registering connection descriptor to core\n"); +	LOG("Registering connection descriptor to core");  	if(mm_manage_fd(ola_socket->ReadDescriptor(), BACKEND_NAME, 1, NULL)){  		goto bail;  	}  	ola_client->SetDmxCallback(ola::NewCallback(&ola_data_receive)); -	//fetch all defined instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		goto bail; -	} - -	//this should not happen anymore (backends without instances are not started anymore) -	if(!n){ -		free(inst); -		return 0; -	} -  	for(u = 0; u < n; u++){  		data = (ola_instance_data*) inst[u]->impl;  		inst[u]->ident = data->universe_id; @@ -268,7 +256,7 @@ static int ola_start(){  		//check for duplicate instances (using the same universe)  		for(p = 0; p < u; p++){  			if(inst[u]->ident == inst[p]->ident){ -				fprintf(stderr, "OLA universe used in multiple instances, use one instance: %s - %s\n", inst[u]->name, inst[p]->name); +				LOGPF("Universe used in multiple instances, use one instance: %s - %s", inst[u]->name, inst[p]->name);  				goto bail;  			}  		} @@ -277,10 +265,8 @@ static int ola_start(){  	//run the ola select implementation to run all commands  	ola_select->RunOnce(); -	free(inst);  	return 0;  bail: -	free(inst);  	delete ola_client;  	ola_client = NULL;  	delete ola_select; @@ -288,18 +274,12 @@ bail:  	return 1;  } -static int ola_shutdown(){ -	size_t n, p; -	instance** inst = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} +static int ola_shutdown(size_t n, instance** inst){ +	size_t p;  	for(p = 0; p < n; p++){  		free(inst[p]->impl);  	} -	free(inst);  	if(ola_client){  		ola_client->Stop(); @@ -313,6 +293,6 @@ static int ola_shutdown(){  		ola_select = NULL;  	} -	fprintf(stderr, "OLA backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/ola.h b/backends/ola.h index 1637495..083e971 100644 --- a/backends/ola.h +++ b/backends/ola.h @@ -8,11 +8,11 @@ extern "C" {  	static int ola_configure(char* option, char* value);  	static int ola_configure_instance(instance* instance, char* option, char* value);  	static instance* ola_instance(); -	static channel* ola_channel(instance* instance, char* spec); +	static channel* ola_channel(instance* instance, char* spec, uint8_t flags);  	static int ola_set(instance* inst, size_t num, channel** c, channel_value* v);  	static int ola_handle(size_t num, managed_fd* fds); -	static int ola_start(); -	static int ola_shutdown(); +	static int ola_start(size_t n, instance** inst); +	static int ola_shutdown(size_t n, instance** inst);  }  #define MAP_COARSE 0x0200 diff --git a/backends/osc.c b/backends/osc.c index d9f9139..7b9a5a5 100644 --- a/backends/osc.c +++ b/backends/osc.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "osc" +  #include <string.h>  #include <ctype.h>  #include <errno.h> @@ -11,7 +13,6 @@   */  #define osc_align(a) ((((a) / 4) + (((a) % 4) ? 1 : 0)) * 4) -#define BACKEND_NAME "osc"  static struct {  	uint8_t detect; @@ -33,13 +34,13 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(osc_channel_ident) != sizeof(uint64_t)){ -		fprintf(stderr, "OSC channel identification union out of bounds\n"); +		LOG("Channel identification union out of bounds");  		return 1;  	}  	//register backend  	if(mm_backend_register(osc)){ -		fprintf(stderr, "Failed to register OSC backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0; @@ -55,7 +56,7 @@ static size_t osc_data_length(osc_parameter_type t){  		case double64:  			return 8;  		default: -			fprintf(stderr, "Invalid OSC format specified %c\n", t); +			LOGPF("Invalid OSC format specifier %c", t);  			return 0;  	}  } @@ -78,7 +79,7 @@ static inline void osc_defaults(osc_parameter_type t, osc_parameter_value* max,  			max->d = 1.0;  			return;  		default: -			fprintf(stderr, "Invalid OSC type, not setting any sane defaults\n"); +			LOG("Invalid OSC type, not setting any sane defaults");  			return;  	}  } @@ -96,7 +97,7 @@ static inline osc_parameter_value osc_parse(osc_parameter_type t, uint8_t* data)  			v.i64 = be64toh(*((int64_t*) data));  			break;  		default: -			fprintf(stderr, "Invalid OSC type passed to parsing routine\n"); +			LOG("Invalid OSC type passed to parsing routine");  	}  	return v;  } @@ -117,7 +118,7 @@ static inline int osc_deparse(osc_parameter_type t, osc_parameter_value v, uint8  			memcpy(data, &u64, sizeof(u64));  			break;  		default: -			fprintf(stderr, "Invalid OSC type passed to parsing routine\n"); +			LOG("Invalid OSC type passed to parsing routine");  			return 1;  	}  	return 0; @@ -140,7 +141,7 @@ static inline osc_parameter_value osc_parse_value_spec(osc_parameter_type t, cha  			v.d = strtod(value, NULL);  			break;  		default: -			fprintf(stderr, "Invalid OSC type passed to value parser\n"); +			LOG("Invalid OSC type passed to value parser");  	}  	return v;  } @@ -181,7 +182,7 @@ static inline channel_value osc_parameter_normalise(osc_parameter_type t, osc_pa  			v.normalised = v.raw.dbl / range.d64;  			break;  		default: -			fprintf(stderr, "Invalid OSC type passed to interpolation routine\n"); +			LOG("Invalid OSC type passed to interpolation routine (normalise)");  	}  	//clamp to range @@ -218,7 +219,7 @@ static inline osc_parameter_value osc_parameter_denormalise(osc_parameter_type t  			v.d = (range.d64 * cur.normalised) + min.d;  			break;  		default: -			fprintf(stderr, "Invalid OSC type passed to interpolation routine\n"); +			LOG("Invalid OSC type passed to interpolation routine (denormalise)");  	}  	return v; @@ -232,27 +233,27 @@ static int osc_path_validate(char* path, uint8_t allow_patterns){  	uint8_t square_open = 0, curly_open = 0;  	if(path[0] != '/'){ -		fprintf(stderr, "%s is not a valid OSC path: Missing root /\n", path); +		LOGPF("%s is not a valid OSC path: Missing root /", path);  		return 1;  	}  	for(u = 0; u < strlen(path); u++){  		for(c = 0; c < sizeof(illegal_chars); c++){  			if(path[u] == illegal_chars[c]){ -				fprintf(stderr, "%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t "\n", path, illegal_chars[c], u); +				LOGPF("%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t, path, illegal_chars[c], u);  				return 1;  			}  		}  		if(!isgraph(path[u])){ -			fprintf(stderr, "%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t "\n", path, pattern_chars[c], u); +			LOGPF("%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t, path, pattern_chars[c], u);  			return 1;  		}  		if(!allow_patterns){  			for(c = 0; c < sizeof(pattern_chars); c++){  				if(path[u] == pattern_chars[c]){ -					fprintf(stderr, "%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t "\n", path, pattern_chars[c], u); +					LOGPF("%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t, path, pattern_chars[c], u);  					return 1;  				}  			} @@ -261,14 +262,14 @@ static int osc_path_validate(char* path, uint8_t allow_patterns){  		switch(path[u]){  			case '{':  				if(square_open || curly_open){ -					fprintf(stderr, "%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t "\n", path, pattern_chars[c], u); +					LOGPF("%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t, path, pattern_chars[c], u);  					return 1;  				}  				curly_open = 1;  				break;  			case '[':  				if(square_open || curly_open){ -					fprintf(stderr, "%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t "\n", path, pattern_chars[c], u); +					LOGPF("%s is not a valid OSC path: Illegal '%c' at %" PRIsize_t, path, pattern_chars[c], u);  					return 1;  				}  				square_open = 1; @@ -281,14 +282,14 @@ static int osc_path_validate(char* path, uint8_t allow_patterns){  				break;  			case '/':  				if(square_open || curly_open){ -					fprintf(stderr, "%s is not a valid OSC path: Pattern across part boundaries\n", path); +					LOGPF("%s is not a valid OSC path: Pattern across part boundaries", path);  					return 1;  				}  		}  	}  	if(square_open || curly_open){ -		fprintf(stderr, "%s is not a valid OSC path: Unterminated pattern expression\n", path); +		LOGPF("%s is not a valid OSC path: Unterminated pattern expression", path);  		return 1;  	}  	return 0; @@ -421,7 +422,7 @@ static int osc_configure(char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown configuration parameter %s for OSC backend\n", option); +	LOGPF("Unknown backend configuration parameter %s", option);  	return 1;  } @@ -430,21 +431,21 @@ static int osc_register_pattern(osc_instance_data* data, char* pattern_path, cha  	char* format = NULL, *token = NULL;  	if(osc_path_validate(pattern_path, 1)){ -		fprintf(stderr, "Not a valid OSC pattern: %s\n", pattern_path); +		LOGPF("Not a valid OSC pattern: %s", pattern_path);  		return 1;  	}  	//tokenize configuration  	format = strtok(configuration, " ");  	if(!format || strlen(format) < 1){ -		fprintf(stderr, "Not a valid format specification for OSC pattern %s\n", pattern_path); +		LOGPF("Not a valid format specification for OSC pattern %s", pattern_path);  		return 1;  	}  	//create pattern  	data->pattern = realloc(data->pattern, (data->patterns + 1) * sizeof(osc_channel));  	if(!data->pattern){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return 1;  	}  	pattern = data->patterns; @@ -461,14 +462,14 @@ static int osc_register_pattern(osc_instance_data* data, char* pattern_path, cha  			|| !data->pattern[pattern].min){  		//this should fail config parsing and thus call the shutdown function,  		//which should properly free the rest of the data -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return 1;  	}  	//check format validity and store min/max values  	for(u = 0; u < strlen(format); u++){  		if(!osc_data_length(format[u])){ -			fprintf(stderr, "Invalid format specifier %c for pattern %s\n", format[u], pattern_path); +			LOGPF("Invalid format specifier %c for pattern %s", format[u], pattern_path);  			return 1;  		} @@ -477,14 +478,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 %" PRIsize_t " of OSC pattern %s\n", u, pattern_path); +			LOGPF("Missing minimum specification for parameter %" PRIsize_t " of OSC pattern %s", 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 %" PRIsize_t " of OSC pattern %s\n", u, pattern_path); +			LOGPF("Missing maximum specification for parameter %" PRIsize_t " of OSC pattern %s", u, pattern_path);  			return 1;  		}  		data->pattern[pattern].max[u] = osc_parse_value_spec(format[u], token); @@ -496,11 +497,11 @@ static int osc_register_pattern(osc_instance_data* data, char* pattern_path, cha  static int osc_configure_instance(instance* inst, char* option, char* value){  	osc_instance_data* data = (osc_instance_data*) inst->impl; -	char* host = NULL, *port = NULL; +	char* host = NULL, *port = NULL, *fd_opts = NULL;  	if(!strcmp(option, "root")){  		if(osc_path_validate(value, 0)){ -			fprintf(stderr, "Not a valid OSC root: %s\n", value); +			LOGPF("Not a valid OSC root: %s", value);  			return 1;  		} @@ -510,21 +511,22 @@ static int osc_configure_instance(instance* inst, char* option, char* value){  		data->root = strdup(value);  		if(!data->root){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return 1;  		}  		return 0;  	}  	else if(!strcmp(option, "bind")){ -		mmbackend_parse_hostspec(value, &host, &port); +		mmbackend_parse_hostspec(value, &host, &port, &fd_opts);  		if(!host || !port){ -			fprintf(stderr, "Invalid bind address for instance %s\n", inst->name); +			LOGPF("Invalid bind address for instance %s", inst->name);  			return 1;  		} +		//this requests a socket with SO_BROADCAST set, whether this is useful functionality for OSC is up for debate  		data->fd = mmbackend_socket(host, port, SOCK_DGRAM, 1, 1);  		if(data->fd < 0){ -			fprintf(stderr, "Failed to bind for instance %s\n", inst->name); +			LOGPF("Failed to bind for instance %s", inst->name);  			return 1;  		}  		return 0; @@ -540,14 +542,14 @@ static int osc_configure_instance(instance* inst, char* option, char* value){  			return 0;  		} -		mmbackend_parse_hostspec(value, &host, &port); +		mmbackend_parse_hostspec(value, &host, &port, NULL);  		if(!host || !port){ -			fprintf(stderr, "Invalid destination address for instance %s\n", inst->name); +			LOGPF("Invalid destination address for instance %s", inst->name);  			return 1;  		}  		if(mmbackend_parse_sockaddr(host, port, &data->dest, &data->dest_len)){ -			fprintf(stderr, "Failed to parse destination address for instance %s\n", inst->name); +			LOGPF("Failed to parse destination address for instance %s", inst->name);  			return 1;  		}  		return 0; @@ -556,7 +558,7 @@ static int osc_configure_instance(instance* inst, char* option, char* value){  		return osc_register_pattern(data, option, value);  	} -	fprintf(stderr, "Unknown configuration parameter %s for OSC instance %s\n", option, inst->name); +	LOGPF("Unknown instance configuration parameter %s for instance %s", option, inst->name);  	return 1;  } @@ -568,7 +570,7 @@ static instance* osc_instance(){  	osc_instance_data* data = calloc(1, sizeof(osc_instance_data));  	if(!data){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	} @@ -577,7 +579,7 @@ static instance* osc_instance(){  	return inst;  } -static channel* osc_map_channel(instance* inst, char* spec){ +static channel* osc_map_channel(instance* inst, char* spec, uint8_t flags){  	size_t u, p;  	osc_instance_data* data = (osc_instance_data*) inst->impl;  	osc_channel_ident ident = { @@ -612,14 +614,14 @@ static channel* osc_map_channel(instance* inst, char* spec){  		data->channel = realloc(data->channel, (u + 1) * sizeof(osc_channel));  		if(!data->channel){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		}  		memset(data->channel + u, 0, sizeof(osc_channel));  		data->channel[u].path = strdup(spec);  		if(p != data->patterns){ -			fprintf(stderr, "Matched pattern %s for %s\n", data->pattern[p].path, spec); +			LOGPF("Matched pattern %s for %s", data->pattern[p].path, spec);  			data->channel[u].params = data->pattern[p].params;  			//just reuse the pointers from the pattern  			data->channel[u].type = data->pattern[p].type; @@ -631,12 +633,12 @@ static channel* osc_map_channel(instance* inst, char* spec){  			data->channel[u].out = calloc(data->channel[u].params, sizeof(osc_parameter_value));  		}  		else if(data->patterns){ -			fprintf(stderr, "No pattern match found for %s\n", spec); +			LOGPF("No pattern match found for %s", spec);  		}  		if(!data->channel[u].path  				|| (data->channel[u].params && (!data->channel[u].in || !data->channel[u].out))){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			return NULL;  		}  		data->channels++; @@ -660,7 +662,7 @@ static int osc_output_channel(instance* inst, size_t channel){  	//determine minimum packet size  	if(osc_align((data->root ? strlen(data->root) : 0) + strlen(data->channel[channel].path) + 1) + osc_align(data->channel[channel].params + 2)  >= sizeof(xmit_buf)){ -		fprintf(stderr, "Insufficient buffer size for OSC transmitting channel %s.%s\n", inst->name, data->channel[channel].path); +		LOGPF("Insufficient buffer size for transmitting channel %s.%s", inst->name, data->channel[channel].path);  		return 1;  	} @@ -686,7 +688,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 %" PRIsize_t "\n", inst->name, data->channel[channel].path, p); +			LOGPF("Insufficient buffer size for transmitting channel %s.%s at parameter %" PRIsize_t, inst->name, data->channel[channel].path, p);  			return 1;  		} @@ -698,7 +700,7 @@ static int osc_output_channel(instance* inst, size_t channel){  	//output packet  	if(sendto(data->fd, xmit_buf, offset, 0, (struct sockaddr*) &(data->dest), data->dest_len) < 0){ -		fprintf(stderr, "Failed to transmit OSC packet: %s\n", strerror(errno)); +		LOGPF("Failed to transmit packet: %s", strerror(errno));  	}  	return 0;  } @@ -717,7 +719,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 (%" PRIsize_t " channels)\n", inst->name, num); +		LOGPF("Instance %s does not have a destination, output is disabled (%" PRIsize_t " channels)", inst->name, num);  		return 0;  	} @@ -727,13 +729,13 @@ static int osc_set(instance* inst, size_t num, channel** c, channel_value* v){  		//sanity check  		if(ident.fields.channel >= data->channels  				|| ident.fields.parameter >= data->channel[ident.fields.channel].params){ -			fprintf(stderr, "OSC channel identifier out of range\n"); +			LOG("Channel identifier out of range");  			return 1;  		}  		//if the format is unknown, don't output  		if(!data->channel[ident.fields.channel].params){ -			fprintf(stderr, "OSC channel %s.%s requires format specification for output\n", inst->name, data->channel[ident.fields.channel].path); +			LOGPF("Channel %s.%s requires format specification for output", inst->name, data->channel[ident.fields.channel].path);  			continue;  		} @@ -775,7 +777,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 %" PRIsize_t "\n", payload_len); +		LOGPF("Invalid packet, data length %" PRIsize_t, payload_len);  		return 0;  	} @@ -784,7 +786,7 @@ static int osc_process_packet(instance* inst, char* local_path, char* format, ui  			ident.fields.channel = c;  			//unconfigured input should work without errors (using default limits)  			if(data->channel[c].params && strlen(format) != data->channel[c].params){ -				fprintf(stderr, "OSC message %s.%s had format %s, internal representation has %" PRIsize_t " parameters\n", inst->name, local_path, format, data->channel[c].params); +				LOGPF("Message %s.%s had format %s, internal representation has %" PRIsize_t " parameters", inst->name, local_path, format, data->channel[c].params);  				continue;  			} @@ -829,7 +831,7 @@ static int osc_handle(size_t num, managed_fd* fds){  	for(fd = 0; fd < num; fd++){  		inst = (instance*) fds[fd].impl;  		if(!inst){ -			fprintf(stderr, "OSC backend signaled for unknown fd\n"); +			LOG("Signaled for unknown FD");  			continue;  		} @@ -857,13 +859,13 @@ static int osc_handle(size_t num, managed_fd* fds){  			osc_fmt = recv_buf + osc_align(strlen(recv_buf) + 1);  			if(*osc_fmt != ','){  				//invalid format string -				fprintf(stderr, "Invalid OSC format string in packet\n"); +				LOGPF("Invalid format string in packet for instance %s", inst->name);  				continue;  			}  			osc_fmt++;  			if(osc_global_config.detect){ -				fprintf(stderr, "Incoming OSC data: Path %s.%s Format %s\n", inst->name, osc_local, osc_fmt); +				LOGPF("Incoming data: Path %s.%s Format %s", inst->name, osc_local, osc_fmt);  			}  			//FIXME check supplied data length @@ -879,11 +881,11 @@ static int osc_handle(size_t num, managed_fd* fds){  		#else  		if(bytes_read < 0 && errno != EAGAIN){  		#endif -			fprintf(stderr, "OSC failed to receive data for instance %s: %s\n", inst->name, strerror(errno)); +			LOGPF("Failed to receive data for instance %s: %s", inst->name, strerror(errno));  		}  		if(bytes_read == 0){ -			fprintf(stderr, "OSC descriptor for instance %s closed\n", inst->name); +			LOGPF("Descriptor for instance %s closed", inst->name);  			return 1;  		}  	} @@ -891,22 +893,10 @@ static int osc_handle(size_t num, managed_fd* fds){  	return 0;  } -static int osc_start(){ -	size_t n, u, fds = 0; -	instance** inst = NULL; +static int osc_start(size_t n, instance** inst){ +	size_t u, fds = 0;  	osc_instance_data* data = NULL; -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	if(!n){ -		free(inst); -		return 0; -	} -  	//update instance identifiers  	for(u = 0; u < n; u++){  		data = (osc_instance_data*) inst[u]->impl; @@ -914,8 +904,7 @@ static int osc_start(){  		if(data->fd >= 0){  			inst[u]->ident = data->fd;  			if(mm_manage_fd(data->fd, BACKEND_NAME, 1, inst[u])){ -				fprintf(stderr, "Failed to register OSC descriptor for instance %s\n", inst[u]->name); -				free(inst); +				LOGPF("Failed to register descriptor for instance %s", inst[u]->name);  				return 1;  			}  			fds++; @@ -925,22 +914,14 @@ static int osc_start(){  		}  	} -	fprintf(stderr, "OSC backend registered %" PRIsize_t " descriptors to core\n", fds); - -	free(inst); +	LOGPF("Registered %" PRIsize_t " descriptors to core", fds);  	return 0;  } -static int osc_shutdown(){ -	size_t n, u, c; -	instance** inst = NULL; +static int osc_shutdown(size_t n, instance** inst){ +	size_t u, c;  	osc_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (osc_instance_data*) inst[u]->impl;  		for(c = 0; c < data->channels; c++){ @@ -967,7 +948,6 @@ static int osc_shutdown(){  		free(inst[u]->impl);  	} -	free(inst); -	fprintf(stderr, "OSC backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/osc.h b/backends/osc.h index 86be285..f8ff3ff 100644 --- a/backends/osc.h +++ b/backends/osc.h @@ -11,11 +11,11 @@ MM_PLUGIN_API int init();  static int osc_configure(char* option, char* value);  static int osc_configure_instance(instance* inst, char* option, char* value);  static instance* osc_instance(); -static channel* osc_map_channel(instance* inst, char* spec); +static channel* osc_map_channel(instance* inst, char* spec, uint8_t flags);  static int osc_set(instance* inst, size_t num, channel** c, channel_value* v);  static int osc_handle(size_t num, managed_fd* fds); -static int osc_start(); -static int osc_shutdown(); +static int osc_start(size_t n, instance** inst); +static int osc_shutdown(size_t n, instance** inst);  typedef enum {  	not_set = 0, diff --git a/backends/sacn.c b/backends/sacn.c index d8b3eb3..ff2b61e 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "sacn" +  #include <string.h>  #include <sys/types.h>  #include <unistd.h> @@ -15,7 +17,10 @@  //upper limit imposed by using the fd index as 16-bit part of the instance id  #define MAX_FDS 4096 -#define BACKEND_NAME "sacn" + +enum /*_sacn_fd_flags*/ { +	mcast_loop = 1 +};  static struct /*_sacn_global_config*/ {  	uint8_t source_name[64]; @@ -45,23 +50,23 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(sacn_instance_id) != sizeof(uint64_t)){ -		fprintf(stderr, "sACN instance identification union out of bounds\n"); +		LOG("Instance identification union out of bounds");  		return 1;  	}  	//register the backend  	if(mm_backend_register(sacn)){ -		fprintf(stderr, "Failed to register sACN backend\n"); +		LOG("Failed to register backend");  		return 1;  	}  	return 0;  } -static int sacn_listener(char* host, char* port, uint8_t fd_flags){ -	int fd = -1; +static int sacn_listener(char* host, char* port, uint8_t flags){ +	int fd = -1, yes = 1;  	if(global_cfg.fds >= MAX_FDS){ -		fprintf(stderr, "sACN backend descriptor limit reached\n"); +		LOG("Descriptor limit reached");  		return -1;  	} @@ -74,16 +79,23 @@ static int sacn_listener(char* host, char* port, uint8_t fd_flags){  	global_cfg.fd = realloc(global_cfg.fd, (global_cfg.fds + 1) * sizeof(sacn_fd));  	if(!global_cfg.fd){  		close(fd); -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return -1;  	} -	fprintf(stderr, "sACN backend interface %" PRIsize_t " bound to %s port %s\n", global_cfg.fds, host, port); +	LOGPF("Interface %" PRIsize_t " bound to %s port %s", 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;  	global_cfg.fd[global_cfg.fds].universe = NULL;  	global_cfg.fd[global_cfg.fds].last_frame = NULL; + +	if(flags & mcast_loop){ +		//set IP_MCAST_LOOP to allow local applications to receive output +		if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){ +			LOGPF("Failed to re-enable IP_MULTICAST_LOOP on socket: %s", strerror(errno)); +		} +	} +  	global_cfg.fds++;  	return 0;  } @@ -95,7 +107,7 @@ static int sacn_configure(char* option, char* value){  	if(!strcmp(option, "name")){  		if(strlen(value) > 63){ -			fprintf(stderr, "Invalid sACN source name %s, limit is 63 characters\n", value); +			LOGPF("Invalid source name %s, limit is 63 characters", value);  			return 1;  		} @@ -110,24 +122,26 @@ static int sacn_configure(char* option, char* value){  		}  	}  	else if(!strcmp(option, "bind")){ -		mmbackend_parse_hostspec(value, &host, &port); -		if(!port){ -			port = SACN_PORT; -		} +		mmbackend_parse_hostspec(value, &host, &port, &next);  		if(!host){ -			fprintf(stderr, "No valid sACN bind address provided\n"); +			LOG("No valid bind address provided");  			return 1;  		} -		if(sacn_listener(host, port, flags)){ -			fprintf(stderr, "Failed to bind sACN descriptor: %s\n", value); +		if(next && !strncmp(next, "local", 5)){ +			flags = mcast_loop; +		} + +		if(sacn_listener(host, port ? port : SACN_PORT, flags)){ +			LOGPF("Failed to bind descriptor: %s", value);  			return 1;  		} +  		return 0;  	} -	fprintf(stderr, "Unknown sACN backend option %s\n", option); +	LOGPF("Unknown backend configuration option %s", option);  	return 1;  } @@ -144,7 +158,7 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){  		data->fd_index = strtoul(value, NULL, 10);  		if(data->fd_index >= global_cfg.fds){ -			fprintf(stderr, "Configured sACN interface index is out of range on instance %s\n", inst->name); +			LOGPF("Configured interface index is out of range on instance %s", inst->name);  			return 1;  		}  		return 0; @@ -154,17 +168,14 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){  		return 0;  	}  	else if(!strcmp(option, "destination")){ -		mmbackend_parse_hostspec(value, &host, &port); -		if(!port){ -			port = SACN_PORT; -		} +		mmbackend_parse_hostspec(value, &host, &port, NULL);  		if(!host){ -			fprintf(stderr, "No valid sACN destination for instance %s\n", inst->name); +			LOGPF("No valid destination for instance %s", inst->name);  			return 1;  		} -		return mmbackend_parse_sockaddr(host, port, &data->dest_addr, &data->dest_len); +		return mmbackend_parse_sockaddr(host, port ? port : SACN_PORT, &data->dest_addr, &data->dest_len);  	}  	else if(!strcmp(option, "from")){  		next = value; @@ -172,14 +183,15 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){  		for(u = 0; u < sizeof(data->cid_filter); u++){  			data->cid_filter[u] = (strtoul(next, &next, 0) & 0xFF);  		} -		fprintf(stderr, "Enabled source CID filter for instance %s\n", inst->name); +		LOGPF("Enabled source CID filter for instance %s", inst->name);  		return 0;  	}  	else if(!strcmp(option, "unicast")){  		data->unicast_input = strtoul(value, NULL, 10); +		return 0;  	} -	fprintf(stderr, "Unknown configuration option %s for sACN backend\n", option); +	LOGPF("Unknown instance configuration option %s for instance %s", option, inst->name);  	return 1;  } @@ -191,14 +203,14 @@ static instance* sacn_instance(){  	inst->impl = calloc(1, sizeof(sacn_instance_data));  	if(!inst->impl){ -		fprintf(stderr, "Failed to allocate memory"); +		LOG("Failed to allocate memory");  		return NULL;  	}  	return inst;  } -static channel* sacn_channel(instance* inst, char* spec){ +static channel* sacn_channel(instance* inst, char* spec, uint8_t flags){  	sacn_instance_data* data = (sacn_instance_data*) inst->impl;  	char* spec_next = spec; @@ -206,7 +218,7 @@ static channel* sacn_channel(instance* inst, char* spec){  	//range check  	if(!chan_a || chan_a > 512){ -		fprintf(stderr, "sACN channel out of range on instance %s: %s\n", inst->name, spec); +		LOGPF("Channel out of range on instance %s: %s", inst->name, spec);  		return NULL;  	}  	chan_a--; @@ -215,14 +227,14 @@ static channel* sacn_channel(instance* inst, char* spec){  	if(*spec_next == '+'){  		chan_b = strtoul(spec_next + 1, NULL, 10);  		if(!chan_b || chan_b > 512){ -			fprintf(stderr, "Invalid wide-channel spec on instance %s: %s\n", inst->name, spec); +			LOGPF("Invalid wide-channel spec on instance %s: %s", inst->name, spec);  			return NULL;  		}  		chan_b--;  		//if already mapped, bail  		if(IS_ACTIVE(data->data.map[chan_b]) && data->data.map[chan_b] != (MAP_FINE | chan_a)){ -			fprintf(stderr, "Fine channel %u already mapped on instance %s\n", chan_b, inst->name); +			LOGPF("Fine channel %u already mapped on instance %s", chan_b, inst->name);  			return NULL;  		} @@ -233,7 +245,7 @@ static channel* sacn_channel(instance* inst, char* spec){  	if(IS_ACTIVE(data->data.map[chan_a])){  		if((*spec_next == '+' && data->data.map[chan_a] != (MAP_COARSE | chan_b))  				|| (*spec_next != '+' && data->data.map[chan_a] != (MAP_SINGLE | chan_a))){ -			fprintf(stderr, "Primary sACN channel %u already mapped in another mode on instance %s\n", chan_a, inst->name); +			LOGPF("Primary channel %u already mapped in another mode on instance %s", chan_a, inst->name);  			return NULL;  		}  	} @@ -279,7 +291,7 @@ static int sacn_transmit(instance* inst){  	memcpy((((uint8_t*)pdu.data.data) + 1), data->data.out, 512);  	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)); +		LOGPF("Failed to output frame for instance %s: %s", inst->name, strerror(errno));  	}  	//update last transmit timestamp @@ -300,7 +312,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 (%" PRIsize_t " channel events)\n", inst->name, num); +		LOGPF("Instance %s not enabled for output (%" PRIsize_t " channel events)", inst->name, num);  		return 0;  	} @@ -346,12 +358,12 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame  	if(data->format != 0xa1  			|| data->startcode_offset  			|| be16toh(data->address_increment) != 1){ -		fprintf(stderr, "sACN framing not supported\n"); +		LOGPF("Framing not supported for incoming data on instance %s\n", inst->name);  		return 1;  	}  	if(be16toh(data->channels) > 513){ -		fprintf(stderr, "Invalid sACN frame channel count\n"); +		LOGPF("Invalid frame channel count %d on instance %s", be16toh(data->channels), inst->name);  		return 1;  	} @@ -385,7 +397,7 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame  			}  			if(!chan){ -				fprintf(stderr, "Active channel %" PRIsize_t " on %s not known to core", u, inst->name); +				LOGPF("Active channel %" PRIsize_t " on %s not known to core", u, inst->name);  				return 1;  			} @@ -402,7 +414,7 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame  			}  			if(mm_channel_event(chan, val)){ -				fprintf(stderr, "Failed to push sACN channel event to core\n"); +				LOG("Failed to push event to core");  				return 1;  			}  		} @@ -453,7 +465,7 @@ static void sacn_discovery(size_t fd){  		memcpy(pdu.data.data, global_cfg.fd[fd].universe + page * 512, universes * sizeof(uint16_t));  		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 %" PRIsize_t ": %s\n", fd, strerror(errno)); +			LOGPF("Failed to output universe discovery frame for interface %" PRIsize_t ": %s", fd, strerror(errno));  		}  	}  } @@ -513,7 +525,7 @@ static int sacn_handle(size_t num, managed_fd* fds){  					instance_id.fields.uni = be16toh(data->universe);  					inst = mm_instance_find(BACKEND_NAME, instance_id.label);  					if(inst && sacn_process_frame(inst, frame, data)){ -						fprintf(stderr, "Failed to process sACN frame\n"); +						LOG("Failed to process frame");  					}  				}  			} @@ -524,11 +536,11 @@ static int sacn_handle(size_t num, managed_fd* fds){  		#else  		if(bytes_read < 0 && errno != EAGAIN){  		#endif -			fprintf(stderr, "sACN failed to receive data: %s\n", strerror(errno)); +			LOGPF("Failed to receive data: %s", strerror(errno));  		}  		if(bytes_read == 0){ -			fprintf(stderr, "sACN listener closed\n"); +			LOG("Listener closed");  			return 1;  		}  	} @@ -536,10 +548,9 @@ static int sacn_handle(size_t num, managed_fd* fds){  	return 0;  } -static int sacn_start(){ -	size_t n, u, p; +static int sacn_start(size_t n, instance** inst){ +	size_t u, p;  	int rv = 1; -	instance** inst = NULL;  	sacn_instance_data* data = NULL;  	sacn_instance_id id = {  		.label = 0 @@ -549,19 +560,8 @@ static int sacn_start(){  	};  	struct sockaddr_in* dest_v4 = NULL; -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	if(!n){ -		free(inst); -		return 0; -	} -  	if(!global_cfg.fds){ -		fprintf(stderr, "Failed to start sACN backend: no descriptors bound\n"); +		LOG("Failed to start, no descriptors bound");  		free(inst);  		return 1;  	} @@ -574,14 +574,14 @@ static int sacn_start(){  		inst[u]->ident = id.label;  		if(!data->uni){ -			fprintf(stderr, "Please specify a universe on instance %s\n", inst[u]->name); +			LOGPF("Please specify a universe on instance %s", inst[u]->name);  			goto bail;  		}  		//find duplicates  		for(p = 0; p < u; p++){  			if(inst[u]->ident == inst[p]->ident){ -				fprintf(stderr, "Colliding sACN instances, use one: %s - %s\n", inst[u]->name, inst[p]->name); +				LOGPF("Colliding instances, use one: %s - %s", inst[u]->name, inst[p]->name);  				goto bail;  			}  		} @@ -589,7 +589,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, (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)); +				LOGPF("Failed to join Multicast group for universe %u on instance %s: %s", data->uni, inst[u]->name, strerror(errno));  			}  		} @@ -597,7 +597,7 @@ static int sacn_start(){  			//add to list of advertised universes for this fd  			global_cfg.fd[data->fd_index].universe = realloc(global_cfg.fd[data->fd_index].universe, (global_cfg.fd[data->fd_index].universes + 1) * sizeof(uint16_t));  			if(!global_cfg.fd[data->fd_index].universe){ -				fprintf(stderr, "Failed to allocate memory\n"); +				LOG("Failed to allocate memory");  				goto bail;  			} @@ -615,12 +615,12 @@ static int sacn_start(){  		}  	} -	fprintf(stderr, "sACN backend registering %" PRIsize_t " descriptors to core\n", global_cfg.fds); +	LOGPF("Registering %" PRIsize_t " descriptors to core", 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));  		if(!global_cfg.fd[u].last_frame){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			goto bail;  		}  		if(mm_manage_fd(global_cfg.fd[u].fd, BACKEND_NAME, 1, (void*) u)){ @@ -630,23 +630,15 @@ static int sacn_start(){  	rv = 0;  bail: -	free(inst);  	return rv;  } -static int sacn_shutdown(){ -	size_t n, p; -	instance** inst = NULL; - -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} +static int sacn_shutdown(size_t n, instance** inst){ +	size_t p;  	for(p = 0; p < n; p++){  		free(inst[p]->impl);  	} -	free(inst);  	for(p = 0; p < global_cfg.fds; p++){  		close(global_cfg.fd[p].fd); @@ -654,6 +646,6 @@ static int sacn_shutdown(){  		free(global_cfg.fd[p].last_frame);  	}  	free(global_cfg.fd); -	fprintf(stderr, "sACN backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/sacn.h b/backends/sacn.h index 631d3a4..c8d11e9 100644 --- a/backends/sacn.h +++ b/backends/sacn.h @@ -4,11 +4,11 @@ MM_PLUGIN_API int init();  static int sacn_configure(char* option, char* value);  static int sacn_configure_instance(instance* instance, char* option, char* value);  static instance* sacn_instance(); -static channel* sacn_channel(instance* instance, char* spec); +static channel* sacn_channel(instance* instance, char* spec, uint8_t flags);  static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v);  static int sacn_handle(size_t num, managed_fd* fds); -static int sacn_start(); -static int sacn_shutdown(); +static int sacn_start(size_t n, instance** inst); +static int sacn_shutdown(size_t n, instance** inst);  #define SACN_PORT "5568"  #define SACN_RECV_BUF 8192 @@ -56,7 +56,6 @@ typedef union /*_sacn_instance_id*/ {  typedef struct /*_sacn_socket*/ {  	int fd; -	uint8_t flags;  	size_t universes;  	uint16_t* universe;  	uint64_t* last_frame; diff --git a/backends/sacn.md b/backends/sacn.md index 434beeb..f5f1db4 100644 --- a/backends/sacn.md +++ b/backends/sacn.md @@ -10,7 +10,11 @@ containing all write-enabled universes.  |---------------|-----------------------|-----------------------|-----------------------|  | `name`	| `sACN source`		| `MIDIMonster`		| sACN source name	|  | `cid`		| `0xAA 0xBB 0xCC` ...	| `MIDIMonster`		| Source CID (16 bytes)	| -| `bind`	| `0.0.0.0 5568`	| none			| Binds a network address to listen for data. This option may be set multiple times, with each descriptor being assigned an index starting from 0 to be used with the `interface` instance configuration option. At least one descriptor is required for transmission. | +| `bind`	| `0.0.0.0 5568`	| none			| Binds a network address to listen for data. This option may be set multiple times, with each descriptor being assigned an index starting from 0 to be used with the `interface` instance configuration option. At least one descriptor is required for operation. | + +The `bind` configuration value can be extended by the keyword `local` to allow software on the +local host to process the sACN output frames from the MIDIMonster (e.g. `bind = 0.0.0.0 5568 local`). +This has the side effect of mirroring the output of instances on those descriptors to their input.  #### Instance configuration diff --git a/backends/winmidi.c b/backends/winmidi.c index bda5401..0722ca2 100644 --- a/backends/winmidi.c +++ b/backends/winmidi.c @@ -1,3 +1,5 @@ +#define BACKEND_NAME "winmidi" +  #include <string.h>  #include "libmmbackend.h" @@ -5,8 +7,6 @@  #include "winmidi.h" -#define BACKEND_NAME "winmidi" -  static struct {  	uint8_t list_devices;  	uint8_t detect; @@ -37,13 +37,13 @@ MM_PLUGIN_API int init(){  	};  	if(sizeof(winmidi_channel_ident) != sizeof(uint64_t)){ -		fprintf(stderr, "winmidi channel identification union out of bounds\n"); +		LOG("Channel identification union out of bounds");  		return 1;  	}  	//register backend  	if(mm_backend_register(winmidi)){ -		fprintf(stderr, "Failed to register winmidi backend\n"); +		LOG("Failed to register backend");  		return 1;  	} @@ -68,7 +68,7 @@ static int winmidi_configure(char* option, char* value){  		return 0;  	} -	fprintf(stderr, "Unknown winmidi backend option %s\n", option); +	LOGPF("Unknown backend option %s", option);  	return 1;  } @@ -76,7 +76,7 @@ static int winmidi_configure_instance(instance* inst, char* option, char* value)  	winmidi_instance_data* data = (winmidi_instance_data*) inst->impl;  	if(!strcmp(option, "read")){  		if(data->read){ -			fprintf(stderr, "winmidi instance %s already connected to an input device\n", inst->name); +			LOGPF("Instance %s already connected to an input device", inst->name);  			return 1;  		}  		data->read = strdup(value); @@ -84,14 +84,14 @@ 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 output device\n", inst->name); +			LOGPF("Instance %s already connected to an output device", inst->name);  			return 1;  		}  		data->write = strdup(value);  		return 0;  	} -	fprintf(stderr, "Unknown winmidi instance option %s\n", option); +	LOGPF("Unknown instance configuration option %s on instance %s", option, inst->name);  	return 1;  } @@ -103,14 +103,14 @@ static instance* winmidi_instance(){  	i->impl = calloc(1, sizeof(winmidi_instance_data));  	if(!i->impl){ -		fprintf(stderr, "Failed to allocate memory\n"); +		LOG("Failed to allocate memory");  		return NULL;  	}  	return i;  } -static channel* winmidi_channel(instance* inst, char* spec){ +static channel* winmidi_channel(instance* inst, char* spec, uint8_t flags){  	char* next_token = NULL;  	winmidi_channel_ident ident = {  		.label = 0 @@ -124,18 +124,18 @@ static channel* winmidi_channel(instance* inst, char* spec){  	}  	if(!next_token){ -		fprintf(stderr, "Invalid winmidi channel specification %s\n", spec); +		LOGPF("Invalid channel specification %s", spec);  		return NULL;  	}  	ident.fields.channel = strtoul(next_token, &next_token, 10);  	if(ident.fields.channel > 15){ -		fprintf(stderr, "MIDI channel out of range in winmidi channel spec %s\n", spec); +		LOGPF("MIDI channel out of range in spec %s", spec);  		return NULL;  	}  	if(*next_token != '.'){ -		fprintf(stderr, "winmidi channel specification %s does not conform to channel<X>.<control><Y>\n", spec); +		LOGPF("Channel specification %s does not conform to channel<X>.<control><Y>", spec);  		return NULL;  	} @@ -160,7 +160,7 @@ static channel* winmidi_channel(instance* inst, char* spec){  		ident.fields.type = aftertouch;  	}  	else{ -		fprintf(stderr, "Unknown winmidi channel control type in %s\n", spec); +		LOGPF("Unknown control type in %s", spec);  		return NULL;  	} @@ -196,42 +196,24 @@ static int winmidi_set(instance* inst, size_t num, channel** c, channel_value* v  	}  	if(!data->device_out){ -		fprintf(stderr, "winmidi instance %s has no output device\n", inst->name); +		LOGPF("Instance %s has no output device", inst->name);  		return 0;  	}  	for(u = 0; u < num; u++){  		ident.label = c[u]->ident; -		switch(ident.fields.type){ -			case note: -				output.components.status = 0x90 | ident.fields.channel; -				output.components.data1 = ident.fields.control; -				output.components.data2 = v[u].normalised * 127.0; -				break; -			case cc: -				output.components.status = 0xB0 | ident.fields.channel; -				output.components.data1 = ident.fields.control; -				output.components.data2 = v[u].normalised * 127.0; -				break; -			case pressure: -				output.components.status = 0xA0 | ident.fields.channel; -				output.components.data1 = ident.fields.control; -				output.components.data2 = v[u].normalised * 127.0; -				break; -			case aftertouch: -				output.components.status = 0xD0 | ident.fields.channel; -				output.components.data1 = v[u].normalised * 127.0; -				output.components.data2 = 0; -				break; -			case pitchbend: -				output.components.status = 0xE0 | ident.fields.channel; -				output.components.data1 = ((int)(v[u].normalised * 16384.0)) & 0x7F; -				output.components.data2 = (((int)(v[u].normalised * 16384.0)) >> 7) & 0x7F; -				break; -			default: -				fprintf(stderr, "Unknown winmidi channel type %d\n", ident.fields.type); -				continue; +		//build output message +		output.components.status = ident.fields.type | ident.fields.channel; +		output.components.data1 = ident.fields.control; +		output.components.data2 = v[u].normalised * 127.0; +		if(ident.fields.type == pitchbend){ +			output.components.data1 = ((int)(v[u].normalised * 16384.0)) & 0x7F; +			output.components.data2 = (((int)(v[u].normalised * 16384.0)) >> 7) & 0x7F; +		} +		else if(ident.fields.type == aftertouch){ +			output.components.data1 = v[u].normalised * 127.0; +			output.components.data2 = 0;  		}  		midiOutShortMsg(data->device_out, output.dword); @@ -277,14 +259,14 @@ static int winmidi_handle(size_t num, managed_fd* fds){  			//pretty-print channel-wide events  			if(backend_config.event[u].channel.fields.type == pitchbend  					|| backend_config.event[u].channel.fields.type == aftertouch){ -				fprintf(stderr, "Incoming MIDI data on channel %s.ch%d.%s, value %f\n", +				LOGPF("Incoming data on channel %s.ch%d.%s, value %f",  						backend_config.event[u].inst->name,  						backend_config.event[u].channel.fields.channel,  						winmidi_type_name(backend_config.event[u].channel.fields.type),  						backend_config.event[u].value);  			}  			else{ -				fprintf(stderr, "Incoming MIDI data on channel %s.ch%d.%s%d, value %f\n", +				LOGPF("Incoming data on channel %s.ch%d.%s%d, value %f",  						backend_config.event[u].inst->name,  						backend_config.event[u].channel.fields.channel,  						winmidi_type_name(backend_config.event[u].channel.fields.type), @@ -297,7 +279,7 @@ static int winmidi_handle(size_t num, managed_fd* fds){  			mm_channel_event(chan, backend_config.event[u].value);  		}  	} -	DBGPF("winmidi flushed %" PRIsize_t " wakeups, handled %" PRIsize_t " events\n", bytes, backend_config.events_active); +	DBGPF("Flushed %" PRIsize_t " wakeups, handled %" PRIsize_t " events", bytes, backend_config.events_active);  	backend_config.events_active = 0;  	LeaveCriticalSection(&backend_config.push_events);  	return 0; @@ -321,7 +303,7 @@ static void CALLBACK winmidi_input_callback(HMIDIIN device, unsigned message, DW  	};  	//callbacks may run on different threads, so we queue all events and alert the main thread via the feedback socket -	DBGPF("winmidi input callback on thread %ld\n", GetCurrentThreadId()); +	DBGPF("Input callback on thread %ld", GetCurrentThreadId());  	switch(message){  		case MIM_MOREDATA: @@ -330,40 +312,21 @@ static void CALLBACK winmidi_input_callback(HMIDIIN device, unsigned message, DW  			//param1 has the message  			input.dword = param1;  			ident.fields.channel = input.components.status & 0x0F; -			switch(input.components.status & 0xF0){ -				case 0x80: -					ident.fields.type = note; -					ident.fields.control = input.components.data1; -					val.normalised = 0.0; -					break; -				case 0x90: -					ident.fields.type = note; -					ident.fields.control = input.components.data1; -					val.normalised = (double) input.components.data2 / 127.0; -					break; -				case 0xA0: -					ident.fields.type = pressure; -					ident.fields.control = input.components.data1; -					val.normalised = (double) input.components.data2 / 127.0; -					break; -				case 0xB0: -					ident.fields.type = cc; -					ident.fields.control = input.components.data1; -					val.normalised = (double) input.components.data2 / 127.0; -					break; -				case 0xD0: -					ident.fields.type = aftertouch; -					ident.fields.control = 0; -					val.normalised = (double) input.components.data1 / 127.0; -					break; -				case 0xE0: -					ident.fields.type = pitchbend; -					ident.fields.control = 0; -					val.normalised = (double)((input.components.data2 << 7) | input.components.data1) / 16384.0; -					break; -				default: -					fprintf(stderr, "winmidi unhandled status byte %02X\n", input.components.status); -					return; +			ident.fields.type = input.components.status & 0xF0; +			ident.fields.control = input.components.data1; +			val.normalised = (double) input.components.data2 / 127.0; +			 +			if(ident.fields.type == 0x80){ +				ident.fields.type = note; +				val.normalised = 0; +			} +			else if(ident.fields.type == pitchbend){ +				ident.fields.control = 0; +				val.normalised = (double)((input.components.data2 << 7) | input.components.data1) / 16384.0; +			} +			else if(ident.fields.type == aftertouch){ +				ident.fields.control = 0; +				val.normalised = (double) input.components.data1 / 127.0;  			}  			break;  		case MIM_LONGDATA: @@ -371,7 +334,7 @@ static void CALLBACK winmidi_input_callback(HMIDIIN device, unsigned message, DW  			return;  		case MIM_ERROR:  			//error in input stream -			fprintf(stderr, "winmidi warning: error in input stream\n"); +			LOG("Error in input stream");  			return;  		case MIM_OPEN:  		case MIM_CLOSE: @@ -380,14 +343,14 @@ static void CALLBACK winmidi_input_callback(HMIDIIN device, unsigned message, DW  	} -	DBGPF("winmidi incoming message type %d channel %d control %d value %f\n", +	DBGPF("Incoming message type %d channel %d control %d value %f",  			ident.fields.type, ident.fields.channel, ident.fields.control, val.normalised);  	EnterCriticalSection(&backend_config.push_events);  	if(backend_config.events_alloc <= backend_config.events_active){  		backend_config.event = realloc((void*) backend_config.event, (backend_config.events_alloc + 1) * sizeof(winmidi_event));  		if(!backend_config.event){ -			fprintf(stderr, "Failed to allocate memory\n"); +			LOG("Failed to allocate memory");  			backend_config.events_alloc = 0;  			backend_config.events_active = 0;  			LeaveCriticalSection(&backend_config.push_events); @@ -408,7 +371,7 @@ static void CALLBACK winmidi_input_callback(HMIDIIN device, unsigned message, DW  }  static void CALLBACK winmidi_output_callback(HMIDIOUT device, unsigned message, DWORD_PTR inst, DWORD param1, DWORD param2){ -	DBGPF("winmidi output callback on thread %ld\n", GetCurrentThreadId()); +	DBGPF("Output callback on thread %ld", GetCurrentThreadId());  }  static int winmidi_match_input(char* prefix){ @@ -418,13 +381,13 @@ static int winmidi_match_input(char* prefix){  	size_t n;  	if(!prefix){ -		fprintf(stderr, "winmidi detected %u input devices\n", inputs); +		LOGPF("Detected %u input devices", inputs);  	}  	else{  		n = strtoul(prefix, &next_token, 10);  		if(!(*next_token) && n < inputs){  			midiInGetDevCaps(n, &input_caps, sizeof(MIDIINCAPS)); -			fprintf(stderr, "winmidi selected input device %s for ID %d\n", input_caps.szPname, n); +			LOGPF("Selected input device %s for ID %d", input_caps.szPname, n);  			return n;  		}  	} @@ -433,10 +396,10 @@ static int winmidi_match_input(char* prefix){  	for(n = 0; n < inputs; n++){  		midiInGetDevCaps(n, &input_caps, sizeof(MIDIINCAPS));  		if(!prefix){ -			printf("\tID %d: %s\n", n, input_caps.szPname); +			printf("\tID %d: %s", n, input_caps.szPname);  		}  		else if(!strncmp(input_caps.szPname, prefix, strlen(prefix))){ -			fprintf(stderr, "winmidi selected input device %s (ID %" PRIsize_t ") for name %s\n", input_caps.szPname, n, prefix); +			LOGPF("Selected input device %s (ID %" PRIsize_t ") for name %s", input_caps.szPname, n, prefix);  			return n;  		}  	} @@ -451,13 +414,13 @@ static int winmidi_match_output(char* prefix){  	size_t n;  	if(!prefix){ -		fprintf(stderr, "winmidi detected %u output devices\n", outputs); +		LOGPF("Detected %u output devices", outputs);  	}  	else{  		n = strtoul(prefix, &next_token, 10);  		if(!(*next_token) && n < outputs){  			midiOutGetDevCaps(n, &output_caps, sizeof(MIDIOUTCAPS)); -			fprintf(stderr, "winmidi selected output device %s for ID %d\n", output_caps.szPname, n); +			LOGPF("Selected output device %s for ID %d", output_caps.szPname, n);  			return n;  		}  	} @@ -466,10 +429,10 @@ static int winmidi_match_output(char* prefix){  	for(n = 0; n < outputs; n++){  		midiOutGetDevCaps(n, &output_caps, sizeof(MIDIOUTCAPS));  		if(!prefix){ -			printf("\tID %d: %s\n", n, output_caps.szPname); +			printf("\tID %d: %s", n, output_caps.szPname);  		}  		else if(!strncmp(output_caps.szPname, prefix, strlen(prefix))){ -			fprintf(stderr, "winmidi selected output device %s (ID %" PRIsize_t " for name %s\n", output_caps.szPname, n, prefix); +			LOGPF("Selected output device %s (ID %" PRIsize_t " for name %s", output_caps.szPname, n, prefix);  			return n;  		}  	} @@ -477,10 +440,9 @@ static int winmidi_match_output(char* prefix){  	return -1;  } -static int winmidi_start(){ -	size_t n = 0, p; +static int winmidi_start(size_t n, instance** inst){ +	size_t p;  	int device, rv = -1; -	instance** inst = NULL;  	winmidi_instance_data* data = NULL;  	struct sockaddr_storage sockadd = {  		0 @@ -488,19 +450,7 @@ static int winmidi_start(){  	//this really should be a size_t but getsockname specifies int* for some reason  	int sockadd_len = sizeof(sockadd);  	char* error = NULL; -	DBGPF("winmidi main thread ID is %ld\n", GetCurrentThreadId()); - -	//fetch all instances -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} - -	//no instances, we're done -	if(!n){ -		free(inst); -		return 0; -	} +	DBGPF("Main thread ID is %ld", GetCurrentThreadId());  	//output device list if requested  	if(backend_config.list_devices){ @@ -512,13 +462,13 @@ static int winmidi_start(){  	//for some reason the feedback connection fails to work on 'real' windows with ipv6  	backend_config.socket_pair[0] = mmbackend_socket("127.0.0.1", "0", SOCK_DGRAM, 1, 0);  	if(backend_config.socket_pair[0] < 0){ -		fprintf(stderr, "winmidi failed to open feedback socket\n"); +		LOG("Failed to open feedback socket");  		return 1;  	}  	if(getsockname(backend_config.socket_pair[0], (struct sockaddr*) &sockadd, &sockadd_len)){  		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,  			NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); -		fprintf(stderr, "winmidi failed to query feedback socket information: %s\n", error); +		LOGPF("Failed to query feedback socket information: %s", error);  		LocalFree(error);  		return 1;  	} @@ -534,15 +484,15 @@ static int winmidi_start(){  //			((struct sockaddr_in6*) &sockadd)->sin6_addr = in6addr_any;  //			break;  		default: -			fprintf(stderr, "winmidi invalid feedback socket family\n"); +			LOG("Invalid feedback socket family");  			return 1;  	} -	DBGPF("winmidi feedback socket family %d port %d\n", sockadd.ss_family, be16toh(((struct sockaddr_in*)&sockadd)->sin_port)); +	DBGPF("Feedback socket family %d port %d", sockadd.ss_family, be16toh(((struct sockaddr_in*)&sockadd)->sin_port));  	backend_config.socket_pair[1] = socket(sockadd.ss_family, SOCK_DGRAM, IPPROTO_UDP);  	if(backend_config.socket_pair[1] < 0 || connect(backend_config.socket_pair[1], (struct sockaddr*) &sockadd, sockadd_len)){  		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,  			NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); -		fprintf(stderr, "winmidi failed to connect to feedback socket: %s\n", error); +		LOGPF("Failed to connect to feedback socket: %s", error);  		LocalFree(error);  		return 1;  	} @@ -556,11 +506,11 @@ static int winmidi_start(){  		if(data->read){  			device = winmidi_match_input(data->read);  			if(device < 0){ -				fprintf(stderr, "Failed to match input device %s for instance %s\n", data->read, inst[p]->name); +				LOGPF("Failed to match input device %s for instance %s", data->read, inst[p]->name);  				goto bail;  			}  			if(midiInOpen(&(data->device_in), device, (DWORD_PTR) winmidi_input_callback, (DWORD_PTR) inst[p], CALLBACK_FUNCTION | MIDI_IO_STATUS) != MMSYSERR_NOERROR){ -				fprintf(stderr, "Failed to open input device for instance %s\n", inst[p]->name); +				LOGPF("Failed to open input device for instance %s", inst[p]->name);  				goto bail;  			}  			//start midi input callbacks @@ -571,38 +521,31 @@ static int winmidi_start(){  		if(data->write){  			device = winmidi_match_output(data->write);  			if(device < 0){ -				fprintf(stderr, "Failed to match output device %s for instance %s\n", data->read, inst[p]->name); +				LOGPF("Failed to match output device %s for instance %s", data->read, inst[p]->name);  				goto bail;  			}  			if(midiOutOpen(&(data->device_out), device, (DWORD_PTR) winmidi_output_callback, (DWORD_PTR) inst[p], CALLBACK_FUNCTION) != MMSYSERR_NOERROR){ -				fprintf(stderr, "Failed to open output device for instance %s\n", inst[p]->name); +				LOGPF("Failed to open output device for instance %s", inst[p]->name);  				goto bail;  			}  		}  	}  	//register the feedback socket to the core -	fprintf(stderr, "winmidi backend registering 1 descriptor to core\n"); +	LOG("Registering 1 descriptor to core");  	if(mm_manage_fd(backend_config.socket_pair[0], BACKEND_NAME, 1, NULL)){  		goto bail;  	}  	rv = 0;  bail: -	free(inst);  	return rv;  } -static int winmidi_shutdown(){ -	size_t n, u; -	instance** inst = NULL; +static int winmidi_shutdown(size_t n, instance** inst){ +	size_t u;  	winmidi_instance_data* data = NULL; -	if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ -		fprintf(stderr, "Failed to fetch instance list\n"); -		return 1; -	} -  	for(u = 0; u < n; u++){  		data = (winmidi_instance_data*) inst[u]->impl;  		free(data->read); @@ -621,9 +564,10 @@ static int winmidi_shutdown(){  			midiOutClose(data->device_out);  			data->device_out = NULL;  		} + +		free(inst[u]->impl);  	} -	free(inst);  	closesocket(backend_config.socket_pair[0]);  	closesocket(backend_config.socket_pair[1]); @@ -635,6 +579,6 @@ static int winmidi_shutdown(){  	LeaveCriticalSection(&backend_config.push_events);  	DeleteCriticalSection(&backend_config.push_events); -	fprintf(stderr, "winmidi backend shut down\n"); +	LOG("Backend shut down");  	return 0;  } diff --git a/backends/winmidi.h b/backends/winmidi.h index ffa6a26..81e7439 100644 --- a/backends/winmidi.h +++ b/backends/winmidi.h @@ -4,11 +4,11 @@ MM_PLUGIN_API int init();  static int winmidi_configure(char* option, char* value);  static int winmidi_configure_instance(instance* inst, char* option, char* value);  static instance* winmidi_instance(); -static channel* winmidi_channel(instance* inst, char* spec); +static channel* winmidi_channel(instance* inst, char* spec, uint8_t flags);  static int winmidi_set(instance* inst, size_t num, channel** c, channel_value* v);  static int winmidi_handle(size_t num, managed_fd* fds); -static int winmidi_start(); -static int winmidi_shutdown(); +static int winmidi_start(size_t n, instance** inst); +static int winmidi_shutdown(size_t n, instance** inst);  typedef struct /*_winmidi_instance_data*/ {  	char* read; @@ -19,11 +19,11 @@ typedef struct /*_winmidi_instance_data*/ {  enum /*_winmidi_channel_type*/ {  	none = 0, -	note, -	cc, -	pressure, -	aftertouch, -	pitchbend +	note = 0x90, +	cc = 0xB0, +	pressure = 0xA0, +	aftertouch = 0xD0, +	pitchbend = 0xE0  };  typedef union { | 
