/********************* a simple virtual fan-out box for midi $Id: fanout.c,v 1.14 2007-10-13 09:05:04 ken Exp $ fans out one incoming midi stream onto virtual ALSA ports, by channel i.e. any data received on channel 0 goes to port 0, any data on channel 16 goes to port 16 i force it to channel 0 upon output build with: gcc -Wall -o fanout fanout.c -lasound Copyright (C) 2007 ken restivo most of the working code, is lifted from qmidiroute, midirgui, and alsaseq2jackmidi Program Author: Matthais Nagorni Copyright: 2002-2004 SuSE AG Nuremberg Copyright (c)2005 Sean Bolton. This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***********************/ #define _GNU_SOURCE #include #include #include #include #define FANOUT_CLIENT_NAME "Fan Out Box" #define FANOUT_PORT_NAME "fanout" #define MAXBYTESLINE 16 #undef FANOUT_DEBUG int portid_in; snd_seq_t *seq_handle; int portCount = 16; int clientid; int default_chan = 0; int main(int argc, char ** argv) { if (snd_seq_open(&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) { fprintf(stderr, "Error opening ALSA sequencer.\n"); exit(1); } snd_seq_set_client_name(seq_handle, FANOUT_CLIENT_NAME); clientid = snd_seq_client_id(seq_handle); if ((portid_in = snd_seq_create_simple_port(seq_handle, FANOUT_PORT_NAME, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { fprintf(stderr, "Error creating sequencer port.\n"); exit(1); } int l1; int portid_out[portCount]; char * portname; for (l1 = 0; l1 < portCount; l1++) { //XXX yeah, it's a memory leak. so what. asprintf(&portname, "%s output %d", FANOUT_PORT_NAME, l1); if ((portid_out[l1] = snd_seq_create_simple_port(seq_handle, portname, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { fprintf(stderr, "Error creating sequencer port.\n"); exit(1); } } //set up listener snd_seq_event_t *ev; unsigned int cmdchan = 0; // te loop! // now go get! while( snd_seq_event_input(seq_handle, &ev)){ if(ev == NULL) { fprintf(stderr, "fanout: shooting blanks??\n"); continue; } if ((ev->type == SND_SEQ_EVENT_NOTEON) || (ev->type == SND_SEQ_EVENT_NOTEOFF)) { cmdchan = ev->data.note.channel; //force ev->data.note.channel = default_chan; } else if ((ev->type == SND_SEQ_EVENT_CHANPRESS) || (ev->type == SND_SEQ_EVENT_PITCHBEND) || (ev->type == SND_SEQ_EVENT_CONTROLLER) || (ev->type == SND_SEQ_EVENT_PGMCHANGE)) { cmdchan = ev->data.control.channel; //force ev->data.control.channel = default_chan; } else { //WTF? fprintf(stderr, "fanout: event type %d isn't handled. sysex?\n", ev->type); continue; } snd_seq_ev_set_subs (ev); snd_seq_ev_set_direct (ev); if(cmdchan > portCount - 1){ fprintf(stderr, "fanout: channel %d doesn't have a port. you got trouble\n", cmdchan); continue; } snd_seq_ev_set_source(ev, portid_out[cmdchan]); snd_seq_event_output_direct(seq_handle, ev); snd_seq_free_event(ev); } // END LOOP return(0); } // TO DO: cleanup, signals