aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--midimonster.c74
-rw-r--r--midimonster.h49
2 files changed, 99 insertions, 24 deletions
diff --git a/midimonster.c b/midimonster.c
index 03b2699..8f30686 100644
--- a/midimonster.c
+++ b/midimonster.c
@@ -8,14 +8,24 @@
#include "backend.h"
#include "plugin.h"
+typedef struct /*_event_collection*/ {
+ size_t alloc;
+ size_t n;
+ channel** channel;
+ channel_value* value;
+} event_collection;
+
static size_t mappings = 0;
static channel_mapping* map = NULL;
static size_t fds = 0;
static managed_fd* fd = NULL;
-static size_t ev_alloc = 0;
-static size_t evs = 0;
-static channel** ev_channel = NULL;
-static channel_value* ev_value = NULL;
+
+static event_collection event_pool[2] = {
+ {0},
+ {0}
+};
+static event_collection* primary = event_pool;
+
volatile static sig_atomic_t shutdown_requested = 0;
void signal_handler(int signum){
@@ -150,35 +160,39 @@ int mm_channel_event(channel* c, channel_value v){
}
//resize event structures to fit additional events
- if(evs + map[u].destinations >= ev_alloc){
- ev_channel = realloc(ev_channel, (ev_alloc + map[u].destinations) * sizeof(channel*));
- ev_value = realloc(ev_value, (ev_alloc + map[u].destinations) * sizeof(channel_value));
+ if(primary->n + map[u].destinations >= primary->alloc){
+ primary->channel = realloc(primary->channel, (primary->alloc + map[u].destinations) * sizeof(channel*));
+ primary->value = realloc(primary->value, (primary->alloc + map[u].destinations) * sizeof(channel_value));
- if(!ev_channel || !ev_value){
+ if(!primary->channel || !primary->value){
fprintf(stderr, "Failed to allocate memory\n");
- ev_alloc = 0;
- evs = 0;
+ primary->alloc = 0;
+ primary->n = 0;
return 1;
}
- ev_alloc += map[u].destinations;
+ primary->alloc += map[u].destinations;
}
//enqueue channel events
//FIXME this might lead to one channel being mentioned multiple times in an apply call
for(p = 0; p < map[u].destinations; p++){
- ev_channel[evs + p] = map[u].to[p];
- ev_value[evs + p] = v;
+ primary->channel[primary->n + p] = map[u].to[p];
+ primary->value[primary->n + p] = v;
}
- evs += map[u].destinations;
+ primary->n += map[u].destinations;
return 0;
}
void event_free(){
- free(ev_channel);
- free(ev_value);
- ev_alloc = 0;
+ size_t u;
+
+ for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){
+ free(event_pool[u].channel);
+ free(event_pool[u].value);
+ event_pool[u].alloc = 0;
+ }
}
int usage(char* fn){
@@ -190,6 +204,7 @@ int usage(char* fn){
int main(int argc, char** argv){
fd_set all_fds, read_fds;
+ event_collection* secondary = NULL;
struct timeval tv;
size_t u, n;
managed_fd* signaled_fds = NULL;
@@ -267,14 +282,25 @@ int main(int argc, char** argv){
goto bail;
}
- //push collected events to target backends
- if(evs && backends_notify(evs, ev_channel, ev_value)){
- fprintf(stderr, "Backends failed to handle output\n");
- goto bail;
- }
+ while(primary->n){
+ //swap primary and secondary event collectors
+ for(u = 0; u < sizeof(event_pool)/sizeof(event_collection); u++){
+ if(primary != event_pool + u){
+ secondary = primary;
+ primary = event_pool + u;
+ break;
+ }
+ }
- //reset the event count
- evs = 0;
+ //push collected events to target backends
+ if(secondary->n && backends_notify(secondary->n, secondary->channel, secondary->value)){
+ fprintf(stderr, "Backends failed to handle output\n");
+ goto bail;
+ }
+
+ //reset the event count
+ secondary->n = 0;
+ }
}
rv = EXIT_SUCCESS;
diff --git a/midimonster.h b/midimonster.h
index 8d439f5..3cf6771 100644
--- a/midimonster.h
+++ b/midimonster.h
@@ -12,6 +12,55 @@ struct _backend_channel;
struct _backend_instance;
struct _managed_fd;
+/*
+ * Backend module callback defines
+ *
+ * The lifecycle of a backend module is as follows
+ * * int init()
+ * The only function that should be exported by the shared object.
+ * Called when the shared object is attached. Should register
+ * a backend structure with the core.
+ * Returning anything other than zero causes midimonster to fail the
+ * startup checks.
+ * * mmbackend_configure
+ * Parse backend-global configuration options from the user-supplied
+ * configuration file. Returning a non-zero value fails config parsing.
+ * * mmbackend_instance
+ * Allocate space for a backend instance. Returning NULL signals an out-of-memory
+ * condition and terminates the program.
+ * * mmbackend_configure_instance
+ * Parse instance configuration from the user-supplied configuration
+ * file. Returning a non-zero value fails config parsing.
+ * * mmbackend_channel
+ * Parse a channel-spec to be mapped to/from. Returning NULL signals an
+ * out-of-memory condition and terminates the program.
+ * * mmbackend_start
+ * Called after all instances have been created and all mappings
+ * have been set up. May be used to connect to backing hardware
+ * or to update runtime-specific data in the various data structures.
+ * Returning a non-zero value signals an error starting the backend
+ * and stops further progress.
+ * * Normal processing loop starts here
+ * * mmbackend_process_fd
+ * Handle data from signaled fds registered via mm_manage_fd.
+ * Push generated events to the core with mm_channel_event.
+ * All registered fds that are ready to read are pushed at once.
+ * Backends that have not registered any fds are still called with
+ * nfds set to 0 in order to support polling backends.
+ * Returning a non-zero value signals an error and gracefully terminates
+ * the program.
+ * * mmbackend_handle_event
+ * An event resulted in a channel for an instance being set.
+ * Called once per changed instance with all updated channels for that
+ * specific instance.
+ * Returning a non-zero value terminates the program.
+ * * (optional) mmbackend_interval
+ * Return the maximum sleep interval for this backend in milliseconds.
+ * If not implemented, a maximum interval of one second is used.
+ * * mmbackend_shutdown
+ * Clean up all allocations, finalize all hardware connections.
+ * Return value is currently ignored.
+ */
typedef int (*mmbackend_handle_event)(struct _backend_instance* inst, size_t channels, struct _backend_channel** c, struct _channel_value* v);
typedef struct _backend_instance* (*mmbackend_create_instance)();
typedef struct _backend_channel* (*mmbackend_parse_channel)(struct _backend_instance* instance, char* spec);