/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler, * Winfried Ritsch, Karl MacMillan, and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* MIDI I/O for Linux using ALSA */ #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include "m_pd.h" #include "s_stuff.h" //the maximum length of input messages #ifndef ALSA_MAX_EVENT_SIZE #define ALSA_MAX_EVENT_SIZE 512 #endif static int alsa_nmidiin; static int alsa_midiinfd[MAXMIDIINDEV]; static int alsa_nmidiout; static int alsa_midioutfd[MAXMIDIOUTDEV]; static snd_seq_t *midi_handle; static snd_midi_event_t *midiev; void midi_alsa_setndevs(int in, int out); void sys_alsa_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) { char portname[50]; int err = 0; int client; int i; snd_seq_client_info_t *alsainfo; alsa_nmidiin = 0; alsa_nmidiout = 0; midi_alsa_setndevs(alsa_nmidiin, alsa_nmidiout); if (nmidiout == 0 && nmidiin == 0) return; if(nmidiin>MAXMIDIINDEV ) { post("midi input ports reduced to maximum %d", MAXMIDIINDEV); nmidiin=MAXMIDIINDEV; } if(nmidiout>MAXMIDIOUTDEV) { post("midi output ports reduced to maximum %d", MAXMIDIOUTDEV); nmidiout=MAXMIDIOUTDEV; } if (nmidiin>0 && nmidiout>0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_DUPLEX,0); else if (nmidiin > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0); else if (nmidiout > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_OUTPUT,0); if (err!=0) { sys_setalarm(1000000); post("couldn't open alsa sequencer"); return; } for (i=0;i= 0 && portno < alsa_nmidiout) { if (a >= 224) // pitchbend { channel = a-224; snd_seq_ev_set_pitchbend(&ev, channel, (((c<<7)|b)-8192)); /* b and c are already correct but alsa needs to recalculate them */ } else if (a >= 208) // touch { channel = a-208; snd_seq_ev_set_chanpress(&ev,channel,b); } else if (a >= 192) // program { channel = a-192; snd_seq_ev_set_pgmchange(&ev,channel,b); } else if (a >= 176) // controller { channel = a-176; snd_seq_ev_set_controller(&ev,channel,b,c); } else if (a >= 160) // polytouch { channel = a-160; snd_seq_ev_set_keypress(&ev,channel,b,c); } else if (a >= 144) // note { channel = a-144; if (c) snd_seq_ev_set_noteon(&ev,channel,b,c); else snd_seq_ev_set_noteoff(&ev,channel,b,c); } snd_seq_ev_set_direct(&ev); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]); snd_seq_event_output_direct(midi_handle,&ev); } //post("%d %d %d\n",a,b,c); } void sys_alsa_putmidibyte(int portno, int byte) { static snd_midi_event_t *dev = NULL; int res; snd_seq_event_t ev; if (!dev) { snd_midi_event_new(ALSA_MAX_EVENT_SIZE, &dev); //assert(dev); snd_midi_event_init(dev); } snd_seq_ev_clear(&ev); res = snd_midi_event_encode_byte(dev, byte, &ev); if (res > 0 && ev.type != SND_SEQ_EVENT_NONE) { // got a complete event, output it snd_seq_ev_set_direct(&ev); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_source(&ev, alsa_midioutfd[portno]); snd_seq_event_output_direct(midi_handle, &ev); } if (res != 0) // reinitialize the parser snd_midi_event_init(dev); } /* this version uses the asynchronous "read()" ... */ void sys_alsa_poll_midi(void) { unsigned char buf[ALSA_MAX_EVENT_SIZE]; int count, alsa_source; int i; snd_seq_event_t *midievent = NULL; if (alsa_nmidiout == 0 && alsa_nmidiin == 0) return; snd_midi_event_init(midiev); if (!alsa_nmidiout && !alsa_nmidiin) return; count = snd_seq_event_input_pending(midi_handle,1); if (count != 0) count = snd_seq_event_input(midi_handle,&midievent); if (midievent != NULL) { count = snd_midi_event_decode(midiev,buf,sizeof(buf),midievent); alsa_source = midievent->dest.port; for(i=0;i maxndev) ndev = maxndev; for (i = 0; i < ndev; i++) sprintf(indevlist + i * devdescsize, "ALSA MIDI device #%d", i+1); *nindevs = ndev; if ((ndev = alsa_nmidioutdevs) > maxndev) ndev = maxndev; for (i = 0; i < ndev; i++) sprintf(outdevlist + i * devdescsize, "ALSA MIDI device #%d", i+1); *noutdevs = ndev; }