]> git.cworth.org Git - scherzo/commitdiff
Listen for MIDI event through ALSA "virtual" rawmidi interface
authorCarl Worth <cworth@cworth.org>
Wed, 2 Oct 2013 18:10:49 +0000 (11:10 -0700)
committerCarl Worth <cworth@cworth.org>
Thu, 3 Oct 2013 17:50:55 +0000 (10:50 -0700)
This allows for connecting up any MIDI device (hardware or software)
through programs such as aconnect or qjackctl that allow one to
connect MIDI outputs to inputs. This is quite convenient for
connecting a virtual keyboard (such as vkeybd or vmpk) to scherzo.

It can also be used to connect a real, hardware MIDI keyboard to
scherzo, but we keep around the code that does a direct connection to
/dev/midi1 since that simplifies things by reducing one step in the
usage, (the user needn't run aconnect nor qjackctl to make the
connection).

scherzo.c

index bdd1a0fe5c7dbe86e97cf1c2a219e17815b9873e..0ef44ea1b362bba96e6b3edc63160cfdd6e97af0 100644 (file)
--- a/scherzo.c
+++ b/scherzo.c
@@ -66,8 +66,6 @@ typedef struct scherzo
      * keyboard". Any "piano keyboard" key knows its own octave and
      * accidental already. */
     int keyboard_octave;
-
-    int midi_fd;
     snd_midi_event_t *snd_midi_event;
 
     mnemon_t mnemon;
@@ -1182,17 +1180,25 @@ _score_challenge (scherzo_t *scherzo)
 }
 #endif
 
+typedef struct
+{
+    scherzo_t *scherzo;
+    int fd;
+} scherzo_midi_closure_t;
+
 static int
 on_midi_input (unused (GIOChannel *channel),
               unused (GIOCondition condition),
               void *user_data)
 {
+    scherzo_midi_closure_t *closure = user_data;
     unsigned char buf[MIDI_BUF_SIZE], *next;
-    scherzo_t *scherzo = user_data;
+    scherzo_t *scherzo = closure->scherzo;
+    int fd = closure->fd;
     ssize_t remaining;
     snd_seq_event_t event;
 
-    remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
+    remaining = read (fd, buf, MIDI_BUF_SIZE);
 
     next = buf;
     while (remaining) {
@@ -1244,11 +1250,38 @@ on_midi_input (unused (GIOChannel *channel),
     return TRUE;
 }
 
+static void *
+listen_to_alsa_midi (void *data)
+{
+    scherzo_midi_closure_t *closure = data;
+    int out_fd = closure->fd;
+    snd_rawmidi_t *midi_in;
+    unsigned char buf[MIDI_BUF_SIZE];
+    ssize_t bytes;
+    int err;
+
+    err = snd_rawmidi_open (&midi_in, NULL, "virtual", 0);
+    if (err) {
+       fprintf (stderr, "Failed to open virtual MIDI handle.");
+       return NULL;
+    }
+
+    while (1) {
+       bytes = snd_rawmidi_read (midi_in, buf, MIDI_BUF_SIZE);
+       write (out_fd, buf, bytes);
+    }
+
+    return NULL;
+}
+
 int
 main (int argc, char *argv[])
 {
     GtkWidget *drawing_area;
+    GIOChannel *channel;
     scherzo_t scherzo;
+    int alsa_midi_fd[2];
+    scherzo_midi_closure_t midi_out, alsa_midi_in, alsa_midi_out;
     int err;
 
     srand (time (NULL));
@@ -1294,17 +1327,29 @@ main (int argc, char *argv[])
     }
 
 #define MIDI_DEVICE "/dev/midi1"
-    scherzo.midi_fd = open (MIDI_DEVICE, O_RDONLY);
-    if (scherzo.midi_fd < 0) {
-       printf ("failed to open " MIDI_DEVICE ". Midi input will not be available.\n");
-    } else {
-       GIOChannel *channel;
 
-       channel = g_io_channel_unix_new (scherzo.midi_fd);
+    midi_out.scherzo = &scherzo;
+    midi_out.fd = open (MIDI_DEVICE, O_RDONLY);
+    if (midi_out.fd < 0) {
+       printf ("Failed to open " MIDI_DEVICE ". You will need to connect a MIDI device.\n");
+    } else {
+       channel = g_io_channel_unix_new (midi_out.fd);
        g_io_channel_set_encoding (channel, NULL, NULL);
-       g_io_add_watch (channel, G_IO_IN, on_midi_input, &scherzo);
+       g_io_add_watch (channel, G_IO_IN, on_midi_input, &midi_out);
     }
 
+    pipe (alsa_midi_fd);
+
+    alsa_midi_in.scherzo = &scherzo;
+    alsa_midi_in.fd = alsa_midi_fd[1];
+    g_thread_new ("scherzo-vmidi", listen_to_alsa_midi, &alsa_midi_in);
+
+    alsa_midi_out.scherzo = &scherzo;
+    alsa_midi_out.fd = alsa_midi_fd[0];
+    channel = g_io_channel_unix_new (alsa_midi_out.fd);
+    g_io_channel_set_encoding (channel, NULL, NULL);
+    g_io_add_watch (channel, G_IO_IN, on_midi_input, &alsa_midi_out);
+
     scherzo.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
     gtk_window_set_default_size (GTK_WINDOW (scherzo.window), 1000, 600);