From ddb185aaa2a5ef6a70c130675826c33f90057591 Mon Sep 17 00:00:00 2001 From: cbdev Date: Mon, 5 Jun 2017 20:53:02 +0200 Subject: MIDI backend start procedure --- artnet.c | 2 +- backend.c | 6 +++- midi.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++------- midi.h | 6 ++++ midimonster.h | 2 +- 5 files changed, 111 insertions(+), 16 deletions(-) diff --git a/artnet.c b/artnet.c index 6eef2fe..598fed8 100644 --- a/artnet.c +++ b/artnet.c @@ -104,7 +104,7 @@ static channel* artnet_channel(instance* instance, char* spec){ fprintf(stderr, "Invalid ArtNet channel %s\n", spec); return NULL; } - return mm_channel(instance, channel); + return mm_channel(instance, channel, 1); } static int artnet_set(size_t num, channel* c, channel_value* v){ diff --git a/backend.c b/backend.c index f49bd91..2eb6fcf 100644 --- a/backend.c +++ b/backend.c @@ -9,7 +9,7 @@ static instance** instances = NULL; static size_t nchannels = 0; static channel** channels = NULL; -channel* mm_channel(instance* i, uint64_t ident){ +channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ size_t u; for(u = 0; u < nchannels; u++){ if(channels[u]->instance == 0 && channels[u]->ident == ident){ @@ -17,6 +17,10 @@ channel* mm_channel(instance* i, uint64_t ident){ } } + if(!create){ + return NULL; + } + channel** new_chan = realloc(channels, (nchannels + 1) * sizeof(channel*)); if(!new_chan){ fprintf(stderr, "Failed to allocate memory\n"); diff --git a/midi.c b/midi.c index 00ff0a4..ca1f66b 100644 --- a/midi.c +++ b/midi.c @@ -40,6 +40,10 @@ int midi_init(){ fprintf(stderr, "Failed to register MIDI backend\n"); return 1; } + + snd_seq_nonblock(sequencer, 1); + + fprintf(stderr, "MIDI client ID is %d\n", snd_seq_client_id(sequencer)); return 0; } @@ -57,24 +61,43 @@ static int midi_configure(char* option, char* value){ } static instance* midi_instance(){ - return mm_instance(); + instance* inst = mm_instance(); + if(!inst){ + return NULL; + } + + inst->impl = calloc(1, sizeof(midi_instance_data)); + if(!inst->impl){ + fprintf(stderr, "Failed to allocate memory\n"); + return NULL; + } + + return inst; } static int midi_configure_instance(instance* instance, char* option, char* value){ - if(!strcmp(option, "device")){ - //open i/o device - return 0; - } - else if(!strcmp(option, "port")){ - //create midi port + midi_instance_data* data = (midi_instance_data*) instance->impl; + + //FIXME maybe allow connecting more than one device + if(!strcmp(option, "read")){ + //connect input device + if(data->read){ + fprintf(stderr, "Port already connected to an input device\n"); + return 1; + } + data->read = strdup(value); return 0; } - else if(!strcmp(option, "mode")){ - //configure open mode - //FIXME needed? + else if(!strcmp(option, "write")){ + //connect output device + if(data->write){ + fprintf(stderr, "Port already connected to an output device\n"); + return 1; + } + data->write = strdup(value); return 0; } - + fprintf(stderr, "Unknown MIDI instance option %s\n", option); return 1; } @@ -124,7 +147,7 @@ static channel* midi_channel(instance* instance, char* spec){ ident.fields.control = strtoul(channel, NULL, 10); if(ident.label){ - return mm_channel(instance, ident.label); + return mm_channel(instance, ident.label, 1); } return NULL; @@ -141,7 +164,69 @@ static int midi_handle(size_t num, int* fd, void** data){ } static int midi_start(){ - return 0; + size_t n, 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; + } + + //create all ports + for(p = 0; p < n; p++){ + data = (midi_instance_data*) inst[p]->impl; + data->port = snd_seq_create_simple_port(sequencer, inst[p]->name, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + + //make connections + if(data->write){ + fprintf(stderr, "Connecting output of instance %s to MIDI device %s\n", inst[p]->name, data->write); + if(snd_seq_parse_address(sequencer, &addr, data->write) == 0){ + snd_seq_connect_to(sequencer, data->port, addr.client, addr.port); + } + else{ + fprintf(stderr, "Failed to get destination device address: %s\n", data->write); + } + free(data->write); + data->write = NULL; + } + + if(data->read){ + fprintf(stderr, "Connecting input from MIDI device %s to instance %s\n", data->read, inst[p]->name); + if(snd_seq_parse_address(sequencer, &addr, data->read) == 0){ + snd_seq_connect_from(sequencer, data->port, addr.client, addr.port); + } + else{ + fprintf(stderr, "Failed to get source device address: %s\n", data->read); + } + free(data->read); + data->read = NULL; + } + } + + //register all fds to core + nfds = snd_seq_poll_descriptors_count(sequencer, POLLIN | POLLOUT); + pfds = calloc(nfds, sizeof(struct pollfd)); + if(!pfds){ + fprintf(stderr, "Failed to allocate memory\n"); + goto bail; + } + nfds = snd_seq_poll_descriptors(sequencer, pfds, nfds, POLLIN | POLLOUT); + + fprintf(stderr, "Registering %d descriptors to core\n", nfds); + for(p = 0; p < nfds; p++){ + mm_manage_fd(pfds[p].fd, BACKEND_NAME, 1, NULL); + } + + rv = 0; + +bail: + free(pfds); + free(inst); + return rv; } static int midi_shutdown(){ diff --git a/midi.h b/midi.h index c83345b..7a13f7c 100644 --- a/midi.h +++ b/midi.h @@ -9,3 +9,9 @@ static int midi_set(size_t num, channel* c, channel_value* v); static int midi_handle(size_t num, int* fd, void** data); static int midi_start(); static int midi_shutdown(); + +typedef struct /*_midi_instance_data*/ { + int port; + char* read; + char* write; +} midi_instance_data; diff --git a/midimonster.h b/midimonster.h index 181f1da..d548528 100644 --- a/midimonster.h +++ b/midimonster.h @@ -98,7 +98,7 @@ instance* mm_instance(); * For each channel with a non-NULL impl field, the backend * will receive a call to its channel_free function. */ -channel* mm_channel(instance* i, uint64_t ident); +channel* mm_channel(instance* i, uint64_t ident, uint8_t create); /* * Register a file descriptor to be selected on. The backend * will be notified via the mmbackend_process_fd call. -- cgit v1.2.3