Index: modules/controller_midi.c
===================================================================
RCS file: /cvs/gnome/gimp/modules/controller_midi.c,v
retrieving revision 1.11
diff -u -p -r1.11 controller_midi.c
--- modules/controller_midi.c	27 Oct 2004 11:08:48 -0000	1.11
+++ modules/controller_midi.c	17 Nov 2004 20:24:22 -0000
@@ -22,12 +22,18 @@
 
 #include "config.h"
 
+#define HAVE_ASOUNDLIB_H
+
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#ifdef HAVE_ASOUNDLIB_H
+#  include <alsa/asoundlib.h>
+#endif
+
 #include <gtk/gtk.h>
 
 #include "libgimpmodule/gimpmodule.h"
@@ -73,6 +79,11 @@ struct _ControllerMidi
   GIOChannel     *io;
   guint           io_id;
 
+#ifdef HAVE_ASOUNDLIB_H
+  snd_seq_t      *sequencer;
+  guint           seq_id;
+#endif
+
   /* midi status */
   gboolean        swallow;
   gint            command;
@@ -121,6 +132,31 @@ static gboolean      midi_read_event    
                                            GIOCondition    cond,
                                            gpointer        data);
 
+#ifdef HAVE_ASOUNDLIB_H
+static gboolean      midi_alsa_prepare    (GSource        *source,
+                                           gint           *timeout);
+static gboolean      midi_alsa_check      (GSource        *source);
+static gboolean      midi_alsa_dispatch   (GSource        *source,
+                                           GSourceFunc     callback,
+                                           gpointer        user_data);
+
+static GSourceFuncs alsa_source_funcs =
+{
+  midi_alsa_prepare,
+  midi_alsa_check,
+  midi_alsa_dispatch,
+  NULL
+};
+
+typedef struct _GAlsaSource GAlsaSource;
+
+struct _GAlsaSource
+{
+  GSource         source;
+  ControllerMidi *controller;
+};
+
+#endif
 
 static const GimpModuleInfo midi_info =
 {
@@ -224,6 +260,10 @@ midi_init (ControllerMidi *midi)
   midi->midi_channel = -1;
   midi->io           = NULL;
   midi->io_id        = 0;
+#ifdef HAVE_ASOUNDLIB_H
+  midi->sequencer    = NULL;
+  midi->seq_id       = 0;
+#endif
 
   midi->swallow      = TRUE; /* get rid of data bytes at start of stream */
   midi->command      = 0x0;
@@ -365,6 +405,17 @@ midi_set_device (ControllerMidi *midi,
       midi->io = NULL;
     }
 
+#ifdef HAVE_ASOUNDLIB_H
+  if (midi->seq_id)
+    {
+      g_source_remove (midi->seq_id);
+      midi->seq_id = 0;
+
+      snd_seq_close (midi->sequencer);
+      midi->sequencer = NULL;
+    }
+#endif
+
   if (midi->device)
     g_free (midi->device);
 
@@ -374,6 +425,58 @@ midi_set_device (ControllerMidi *midi,
     {
       gint fd;
 
+#ifdef HAVE_ASOUNDLIB_H
+      if (! g_ascii_strcasecmp (midi->device, "alsa"))
+        {
+          GAlsaSource *event_source;
+          gchar       *alsa, *name;
+          gint         ret;
+
+          ret = snd_seq_open (&midi->sequencer, "default",
+                              SND_SEQ_OPEN_INPUT, 0);
+          if (ret >= 0)
+            {
+              snd_seq_set_client_name (midi->sequencer, "The GIMP");
+              ret = snd_seq_create_simple_port (midi->sequencer,
+                                                "The GIMP midi controller",
+                                                SND_SEQ_PORT_CAP_WRITE |
+                                                SND_SEQ_PORT_CAP_SUBS_WRITE,
+                                                SND_SEQ_PORT_TYPE_APPLICATION);
+            }
+
+          if (ret < 0)
+            {
+              name = g_strdup_printf (_("Device not available: %s"),
+                                      snd_strerror (ret));
+              g_object_set (midi, "name", name, NULL);
+              g_free (name);
+
+              if (midi->sequencer)
+                {
+                  snd_seq_close (midi->sequencer);
+                  midi->sequencer = NULL;
+                }
+
+              return FALSE;
+            }
+
+          /* hack to avoid new message to translate */
+          alsa = g_strdup_printf ("ALSA: %d:%d",
+                                  snd_seq_client_id (midi->sequencer),
+                                  ret);
+          name = g_strdup_printf (_("Reading from %s"), alsa);
+          g_object_set (midi, "name", name, NULL);
+          g_free (name);
+          g_free (alsa);
+
+          event_source = (GAlsaSource *) g_source_new (&alsa_source_funcs,
+                                                       sizeof (GAlsaSource));
+          event_source->controller = midi;
+          midi->seq_id = g_source_attach ((GSource *) event_source, NULL);
+          return TRUE;
+        }
+#endif
+
 #ifdef G_OS_WIN32
       fd = open (midi->device, O_RDONLY);
 #else
@@ -702,3 +805,68 @@ midi_read_event (GIOChannel   *io,
 
   return TRUE;
 }
+
+#ifdef HAVE_ASOUNDLIB_H
+static gboolean
+midi_alsa_prepare (GSource *source,
+                   gint    *timeout)
+{
+  ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
+  gboolean        ready;
+
+  ready = snd_seq_event_input_pending (midi->sequencer, 1) > 0;
+  *timeout = ready ? 1 : 10;
+
+  return ready;
+}
+
+static gboolean
+midi_alsa_check (GSource *source)
+{
+  ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
+
+  return snd_seq_event_input_pending (midi->sequencer, 1) > 0;
+}
+
+static gboolean
+midi_alsa_dispatch (GSource     *source,
+                    GSourceFunc  callback,
+                    gpointer     user_data)
+{
+  ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
+  snd_seq_event_t *event;
+
+  if (snd_seq_event_input_pending (midi->sequencer, 1) > 0)
+    {
+      snd_seq_event_input (midi->sequencer, &event);
+      if (event->type == SND_SEQ_EVENT_NOTEON &&
+          event->data.note.velocity == 0)
+        event->type = SND_SEQ_EVENT_NOTEOFF;
+
+      switch (event->type)
+        {
+        case SND_SEQ_EVENT_NOTEON:
+          midi_event (midi, midi->channel, event->data.note.note,
+                      (gdouble) event->data.note.velocity / 127.0);
+          break;
+
+        case SND_SEQ_EVENT_NOTEOFF:
+          midi_event (midi, midi->channel, event->data.note.note + 128,
+                      (gdouble) event->data.note.velocity / 127.0);
+          break;
+
+        case SND_SEQ_EVENT_CONTROLLER:
+          midi_event (midi, midi->channel, event->data.control.param + 256,
+                      (gdouble) event->data.control.value / 127.0);
+          break;
+
+        default:
+          break;
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+#endif