1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * controller_midi.c
5  * Copyright (C) 2004-2007 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #define _GNU_SOURCE  /* the ALSA headers need this */
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <time.h>
31 
32 #include <glib/gstdio.h>
33 
34 #ifdef HAVE_ALSA
35 #include <alsa/asoundlib.h>
36 #endif
37 
38 #include <gegl.h>
39 #include <gtk/gtk.h>
40 
41 #include "libgimpconfig/gimpconfig.h"
42 #include "libgimpmodule/gimpmodule.h"
43 #include "libgimpwidgets/gimpwidgets.h"
44 
45 #define GIMP_ENABLE_CONTROLLER_UNDER_CONSTRUCTION
46 #include "libgimpwidgets/gimpcontroller.h"
47 
48 #include "libgimp/libgimp-intl.h"
49 
50 
51 typedef struct
52 {
53   gchar *name;
54   gchar *blurb;
55 } MidiEvent;
56 
57 
58 enum
59 {
60   PROP_0,
61   PROP_DEVICE,
62   PROP_CHANNEL
63 };
64 
65 
66 #define CONTROLLER_TYPE_MIDI            (controller_midi_get_type ())
67 #define CONTROLLER_MIDI(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CONTROLLER_TYPE_MIDI, ControllerMidi))
68 #define CONTROLLER_MIDI_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CONTROLLER_TYPE_MIDI, ControllerMidiClass))
69 #define CONTROLLER_IS_MIDI(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CONTROLLER_TYPE_MIDI))
70 #define CONTROLLER_IS_MIDI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CONTROLLER_TYPE_MIDI))
71 
72 
73 typedef struct _ControllerMidi      ControllerMidi;
74 typedef struct _ControllerMidiClass ControllerMidiClass;
75 
76 struct _ControllerMidi
77 {
78   GimpController  parent_instance;
79 
80   gchar          *device;
81   gint            midi_channel;
82 
83   GIOChannel     *io;
84   guint           io_id;
85 
86 #ifdef HAVE_ALSA
87   snd_seq_t      *sequencer;
88   guint           seq_id;
89 #endif
90 
91   /* midi status */
92   gboolean        swallow;
93   gint            command;
94   gint            channel;
95   gint            key;
96   gint            velocity;
97   gint            msb;
98   gint            lsb;
99 };
100 
101 struct _ControllerMidiClass
102 {
103   GimpControllerClass  parent_class;
104 };
105 
106 
107 static GType         controller_midi_get_type (void);
108 
109 static void          midi_dispose             (GObject        *object);
110 static void          midi_set_property        (GObject        *object,
111                                                guint           property_id,
112                                                const GValue   *value,
113                                                GParamSpec     *pspec);
114 static void          midi_get_property        (GObject        *object,
115                                                guint           property_id,
116                                                GValue         *value,
117                                                GParamSpec     *pspec);
118 
119 static gint          midi_get_n_events        (GimpController *controller);
120 static const gchar * midi_get_event_name      (GimpController *controller,
121                                                gint            event_id);
122 static const gchar * midi_get_event_blurb     (GimpController *controller,
123                                                gint            event_id);
124 
125 static gboolean      midi_set_device          (ControllerMidi *controller,
126                                                const gchar    *device);
127 static void          midi_event               (ControllerMidi *midi,
128                                                gint            channel,
129                                                gint            event_id,
130                                                gdouble         value);
131 
132 static gboolean      midi_read_event          (GIOChannel     *io,
133                                                GIOCondition    cond,
134                                                gpointer        data);
135 
136 #ifdef HAVE_ALSA
137 static gboolean      midi_alsa_prepare        (GSource        *source,
138                                                gint           *timeout);
139 static gboolean      midi_alsa_check          (GSource        *source);
140 static gboolean      midi_alsa_dispatch       (GSource        *source,
141                                                GSourceFunc     callback,
142                                                gpointer        user_data);
143 
144 static GSourceFuncs alsa_source_funcs =
145 {
146   midi_alsa_prepare,
147   midi_alsa_check,
148   midi_alsa_dispatch,
149   NULL
150 };
151 
152 typedef struct _GAlsaSource GAlsaSource;
153 
154 struct _GAlsaSource
155 {
156   GSource         source;
157   ControllerMidi *controller;
158 };
159 #endif /* HAVE_ALSA */
160 
161 static const GimpModuleInfo midi_info =
162 {
163   GIMP_MODULE_ABI_VERSION,
164   N_("MIDI event controller"),
165   "Michael Natterer <mitch@gimp.org>",
166   "v0.2",
167   "(c) 2004-2007, released under the GPL",
168   "2004-2007"
169 };
170 
171 
G_DEFINE_DYNAMIC_TYPE(ControllerMidi,controller_midi,GIMP_TYPE_CONTROLLER)172 G_DEFINE_DYNAMIC_TYPE (ControllerMidi, controller_midi,
173                        GIMP_TYPE_CONTROLLER)
174 
175 static MidiEvent midi_events[128 + 128 + 128];
176 
177 
178 G_MODULE_EXPORT const GimpModuleInfo *
179 gimp_module_query (GTypeModule *module)
180 {
181   return &midi_info;
182 }
183 
184 G_MODULE_EXPORT gboolean
gimp_module_register(GTypeModule * module)185 gimp_module_register (GTypeModule *module)
186 {
187   controller_midi_register_type (module);
188 
189   return TRUE;
190 }
191 
192 static void
controller_midi_class_init(ControllerMidiClass * klass)193 controller_midi_class_init (ControllerMidiClass *klass)
194 {
195   GimpControllerClass *controller_class = GIMP_CONTROLLER_CLASS (klass);
196   GObjectClass        *object_class     = G_OBJECT_CLASS (klass);
197   gchar               *blurb;
198 
199   object_class->dispose            = midi_dispose;
200   object_class->get_property       = midi_get_property;
201   object_class->set_property       = midi_set_property;
202 
203   blurb = g_strconcat (_("The name of the device to read MIDI events from."),
204 #ifdef HAVE_ALSA
205                        "\n",
206                        _("Enter 'alsa' to use the ALSA sequencer."),
207 #endif
208                        NULL);
209 
210   g_object_class_install_property (object_class, PROP_DEVICE,
211                                    g_param_spec_string ("device",
212                                                         _("Device:"),
213                                                         blurb,
214                                                         NULL,
215                                                         GIMP_CONFIG_PARAM_FLAGS));
216 
217   g_free (blurb);
218 
219   g_object_class_install_property (object_class, PROP_CHANNEL,
220                                    g_param_spec_int ("channel",
221                                                      _("Channel:"),
222                                                      _("The MIDI channel to read events from. Set to -1 for reading from all MIDI channels."),
223                                                      -1, 15, -1,
224                                                      GIMP_CONFIG_PARAM_FLAGS));
225 
226   controller_class->name            = _("MIDI");
227   controller_class->help_id         = "gimp-controller-midi";
228   controller_class->icon_name       = GIMP_ICON_CONTROLLER_MIDI;
229 
230   controller_class->get_n_events    = midi_get_n_events;
231   controller_class->get_event_name  = midi_get_event_name;
232   controller_class->get_event_blurb = midi_get_event_blurb;
233 }
234 
235 static void
controller_midi_class_finalize(ControllerMidiClass * klass)236 controller_midi_class_finalize (ControllerMidiClass *klass)
237 {
238 }
239 
240 static void
controller_midi_init(ControllerMidi * midi)241 controller_midi_init (ControllerMidi *midi)
242 {
243   midi->device       = NULL;
244   midi->midi_channel = -1;
245   midi->io           = NULL;
246   midi->io_id        = 0;
247 #ifdef HAVE_ALSA
248   midi->sequencer    = NULL;
249   midi->seq_id       = 0;
250 #endif
251 
252   midi->swallow      = TRUE; /* get rid of data bytes at start of stream */
253   midi->command      = 0x0;
254   midi->channel      = 0x0;
255   midi->key          = -1;
256   midi->velocity     = -1;
257   midi->msb          = -1;
258   midi->lsb          = -1;
259 }
260 
261 static void
midi_dispose(GObject * object)262 midi_dispose (GObject *object)
263 {
264   ControllerMidi *midi = CONTROLLER_MIDI (object);
265 
266   midi_set_device (midi, NULL);
267 
268   G_OBJECT_CLASS (controller_midi_parent_class)->dispose (object);
269 }
270 
271 static void
midi_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)272 midi_set_property (GObject      *object,
273                    guint         property_id,
274                    const GValue *value,
275                    GParamSpec   *pspec)
276 {
277   ControllerMidi *midi = CONTROLLER_MIDI (object);
278 
279   switch (property_id)
280     {
281     case PROP_DEVICE:
282       midi_set_device (midi, g_value_get_string (value));
283       break;
284     case PROP_CHANNEL:
285       midi->midi_channel = g_value_get_int (value);
286       break;
287     default:
288       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
289       break;
290     }
291 }
292 
293 static void
midi_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)294 midi_get_property (GObject    *object,
295                    guint       property_id,
296                    GValue     *value,
297                    GParamSpec *pspec)
298 {
299   ControllerMidi *midi = CONTROLLER_MIDI (object);
300 
301   switch (property_id)
302     {
303     case PROP_DEVICE:
304       g_value_set_string (value, midi->device);
305       break;
306     case PROP_CHANNEL:
307       g_value_set_int (value, midi->midi_channel);
308       break;
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
311       break;
312     }
313 }
314 
315 static gint
midi_get_n_events(GimpController * controller)316 midi_get_n_events (GimpController *controller)
317 {
318   return 128 + 128 + 128;
319 }
320 
321 static const gchar *
midi_get_event_name(GimpController * controller,gint event_id)322 midi_get_event_name (GimpController *controller,
323                      gint            event_id)
324 {
325   if (event_id < (128 + 128 + 128))
326     {
327       if (! midi_events[event_id].name)
328         {
329           if (event_id < 128)
330             midi_events[event_id].name = g_strdup_printf ("note-on-%02x",
331                                                           event_id);
332           else if (event_id < (128 + 128))
333             midi_events[event_id].name = g_strdup_printf ("note-off-%02x",
334                                                           event_id - 128);
335           else if (event_id < (128 + 128 + 128))
336             midi_events[event_id].name = g_strdup_printf ("controller-%03d",
337                                                           event_id - 256);
338         }
339 
340       return midi_events[event_id].name;
341     }
342 
343   return NULL;
344 }
345 
346 static const gchar *
midi_get_event_blurb(GimpController * controller,gint event_id)347 midi_get_event_blurb (GimpController *controller,
348                       gint            event_id)
349 {
350   if (event_id <= 383)
351     {
352       if (! midi_events[event_id].blurb)
353         {
354           if (event_id <= 127)
355             midi_events[event_id].blurb = g_strdup_printf (_("Note %02x on"),
356                                                            event_id);
357           else if (event_id <= 255)
358             midi_events[event_id].blurb = g_strdup_printf (_("Note %02x off"),
359                                                            event_id - 128);
360           else if (event_id <= 383)
361             midi_events[event_id].blurb = g_strdup_printf (_("Controller %03d"),
362                                                            event_id - 256);
363         }
364 
365       return midi_events[event_id].blurb;
366     }
367 
368   return NULL;
369 }
370 
371 static gboolean
midi_set_device(ControllerMidi * midi,const gchar * device)372 midi_set_device (ControllerMidi *midi,
373                  const gchar    *device)
374 {
375   midi->swallow  = TRUE;
376   midi->command  = 0x0;
377   midi->channel  = 0x0;
378   midi->key      = -1;
379   midi->velocity = -1;
380   midi->msb      = -1;
381   midi->lsb      = -1;
382 
383   if (midi->io)
384     {
385       g_source_remove (midi->io_id);
386       midi->io_id = 0;
387 
388       g_io_channel_unref (midi->io);
389       midi->io = NULL;
390     }
391 
392 #ifdef HAVE_ALSA
393   if (midi->seq_id)
394     {
395       g_source_remove (midi->seq_id);
396       midi->seq_id = 0;
397 
398       snd_seq_close (midi->sequencer);
399       midi->sequencer = NULL;
400     }
401 #endif /* HAVE_ALSA */
402 
403   if (midi->device)
404     g_free (midi->device);
405 
406   midi->device = g_strdup (device);
407 
408   g_object_set (midi, "name", _("MIDI Events"), NULL);
409 
410   if (midi->device && strlen (midi->device))
411     {
412       gint fd;
413 
414 #ifdef HAVE_ALSA
415       if (! g_ascii_strcasecmp (midi->device, "alsa"))
416         {
417           GSource *event_source;
418           gchar   *alsa;
419           gchar   *state;
420           gint     ret;
421 
422           ret = snd_seq_open (&midi->sequencer, "default",
423                               SND_SEQ_OPEN_INPUT, 0);
424           if (ret >= 0)
425             {
426               snd_seq_set_client_name (midi->sequencer, _("GIMP"));
427               ret = snd_seq_create_simple_port (midi->sequencer,
428                                                 _("GIMP MIDI Input Controller"),
429                                                 SND_SEQ_PORT_CAP_WRITE |
430                                                 SND_SEQ_PORT_CAP_SUBS_WRITE,
431                                                 SND_SEQ_PORT_TYPE_APPLICATION);
432             }
433 
434           if (ret < 0)
435             {
436               state = g_strdup_printf (_("Device not available: %s"),
437                                        snd_strerror (ret));
438               g_object_set (midi, "state", state, NULL);
439               g_free (state);
440 
441               if (midi->sequencer)
442                 {
443                   snd_seq_close (midi->sequencer);
444                   midi->sequencer = NULL;
445                 }
446 
447               return FALSE;
448             }
449 
450           /* hack to avoid new message to translate */
451           alsa = g_strdup_printf ("ALSA (%d:%d)",
452                                   snd_seq_client_id (midi->sequencer),
453                                   ret);
454           state = g_strdup_printf (_("Reading from %s"), alsa);
455           g_free (alsa);
456 
457           g_object_set (midi, "state", state, NULL);
458           g_free (state);
459 
460           event_source = g_source_new (&alsa_source_funcs,
461                                        sizeof (GAlsaSource));
462 
463           ((GAlsaSource *) event_source)->controller = midi;
464 
465           midi->seq_id = g_source_attach (event_source, NULL);
466           g_source_unref (event_source);
467 
468           return TRUE;
469         }
470 #endif /* HAVE_ALSA */
471 
472 #ifdef G_OS_WIN32
473       fd = g_open (midi->device, O_RDONLY, 0);
474 #else
475       fd = g_open (midi->device, O_RDONLY | O_NONBLOCK, 0);
476 #endif
477 
478       if (fd >= 0)
479         {
480           gchar *state = g_strdup_printf (_("Reading from %s"), midi->device);
481           g_object_set (midi, "state", state, NULL);
482           g_free (state);
483 
484           midi->io = g_io_channel_unix_new (fd);
485           g_io_channel_set_close_on_unref (midi->io, TRUE);
486           g_io_channel_set_encoding (midi->io, NULL, NULL);
487 
488           midi->io_id = g_io_add_watch (midi->io,
489                                         G_IO_IN  | G_IO_ERR |
490                                         G_IO_HUP | G_IO_NVAL,
491                                         midi_read_event,
492                                         midi);
493           return TRUE;
494         }
495       else
496         {
497           gchar *state = g_strdup_printf (_("Device not available: %s"),
498                                           g_strerror (errno));
499           g_object_set (midi, "state", state, NULL);
500           g_free (state);
501         }
502     }
503   else
504     {
505       g_object_set (midi, "state", _("No device configured"), NULL);
506     }
507 
508   return FALSE;
509 }
510 
511 static void
midi_event(ControllerMidi * midi,gint channel,gint event_id,gdouble value)512 midi_event (ControllerMidi *midi,
513             gint            channel,
514             gint            event_id,
515             gdouble         value)
516 {
517   if (channel == -1            ||
518       midi->midi_channel == -1 ||
519       channel == midi->midi_channel)
520     {
521       GimpControllerEvent event = { 0, };
522 
523       event.any.type     = GIMP_CONTROLLER_EVENT_VALUE;
524       event.any.source   = GIMP_CONTROLLER (midi);
525       event.any.event_id = event_id;
526 
527       g_value_init (&event.value.value, G_TYPE_DOUBLE);
528       g_value_set_double (&event.value.value, value);
529 
530       gimp_controller_event (GIMP_CONTROLLER (midi), &event);
531 
532       g_value_unset (&event.value.value);
533     }
534 }
535 
536 
537 #define D(stmnt) stmnt;
538 
539 gboolean
midi_read_event(GIOChannel * io,GIOCondition cond,gpointer data)540 midi_read_event (GIOChannel   *io,
541                  GIOCondition  cond,
542                  gpointer      data)
543 {
544   ControllerMidi *midi = CONTROLLER_MIDI (data);
545   GIOStatus       status;
546   GError         *error = NULL;
547   guchar          buf[0xf];
548   gsize           size;
549   gint            pos = 0;
550 
551   status = g_io_channel_read_chars (io,
552                                     (gchar *) buf,
553                                     sizeof (buf), &size,
554                                     &error);
555 
556   switch (status)
557     {
558     case G_IO_STATUS_ERROR:
559     case G_IO_STATUS_EOF:
560       g_source_remove (midi->io_id);
561       midi->io_id = 0;
562 
563       g_io_channel_unref (midi->io);
564       midi->io = NULL;
565 
566       if (error)
567         {
568           gchar *state = g_strdup_printf (_("Device not available: %s"),
569                                           error->message);
570           g_object_set (midi, "state", state, NULL);
571           g_free (state);
572 
573           g_clear_error (&error);
574         }
575       else
576         {
577           g_object_set (midi, "state", _("End of file"), NULL);
578         }
579       return FALSE;
580       break;
581 
582     case G_IO_STATUS_AGAIN:
583       return TRUE;
584 
585     default:
586       break;
587     }
588 
589   while (pos < size)
590     {
591 #if 0
592       gint i;
593 
594       g_print ("MIDI IN (%d bytes), command 0x%02x: ", size, midi->command);
595 
596       for (i = 0; i < size; i++)
597         g_print ("%02x ", buf[i]);
598       g_print ("\n");
599 #endif
600 
601       if (buf[pos] & 0x80)  /* status byte */
602         {
603           if (buf[pos] >= 0xf8)  /* realtime messages */
604             {
605               switch (buf[pos])
606                 {
607                 case 0xf8:  /* timing clock   */
608                 case 0xf9:  /* (undefined)    */
609                 case 0xfa:  /* start          */
610                 case 0xfb:  /* continue       */
611                 case 0xfc:  /* stop           */
612                 case 0xfd:  /* (undefined)    */
613                 case 0xfe:  /* active sensing */
614                 case 0xff:  /* system reset   */
615                   /* nop */
616 #if 0
617                   g_print ("MIDI: realtime message (%02x)\n", buf[pos]);
618 #endif
619                   break;
620                 }
621             }
622           else
623             {
624               midi->swallow = FALSE;  /* any status bytes ends swallowing */
625 
626               if (buf[pos] >= 0xf0)  /* system messages */
627                 {
628                   switch (buf[pos])
629                     {
630                     case 0xf0:  /* sysex start */
631                       midi->swallow = TRUE;
632 
633                       D (g_print ("MIDI: sysex start\n"));
634                       break;
635 
636                     case 0xf1:              /* time code   */
637                       midi->swallow = TRUE; /* type + data */
638 
639                       D (g_print ("MIDI: time code\n"));
640                       break;
641 
642                     case 0xf2:              /* song position */
643                       midi->swallow = TRUE; /* lsb + msb     */
644 
645                       D (g_print ("MIDI: song position\n"));
646                       break;
647 
648                     case 0xf3:              /* song select */
649                       midi->swallow = TRUE; /* song number */
650 
651                       D (g_print ("MIDI: song select\n"));
652                       break;
653 
654                     case 0xf4:  /* (undefined) */
655                     case 0xf5:  /* (undefined) */
656                       D (g_print ("MIDI: undefined system message\n"));
657                       break;
658 
659                     case 0xf6:  /* tune request */
660                       D (g_print ("MIDI: tune request\n"));
661                       break;
662 
663                     case 0xf7:  /* sysex end */
664                       D (g_print ("MIDI: sysex end\n"));
665                       break;
666                     }
667                 }
668               else  /* channel messages */
669                 {
670                   midi->command = buf[pos] >> 4;
671                   midi->channel = buf[pos] & 0xf;
672 
673                   /* reset running status */
674                   midi->key      = -1;
675                   midi->velocity = -1;
676                   midi->msb      = -1;
677                   midi->lsb      = -1;
678                 }
679             }
680 
681           pos++;  /* status byte consumed */
682           continue;
683         }
684 
685       if (midi->swallow)
686         {
687           pos++;  /* consume any data byte */
688           continue;
689         }
690 
691       switch (midi->command)
692         {
693         case 0x8:  /* note off   */
694         case 0x9:  /* note on    */
695         case 0xa:  /* aftertouch */
696 
697           if (midi->key == -1)
698             {
699               midi->key = buf[pos++];  /* key byte consumed */
700               continue;
701             }
702 
703           if (midi->velocity == -1)
704             midi->velocity = buf[pos++];  /* velocity byte consumed */
705 
706           /* note on with velocity = 0 means note off */
707           if (midi->command == 0x9 && midi->velocity == 0x0)
708             midi->command = 0x8;
709 
710           if (midi->command == 0x9)
711             {
712               D (g_print ("MIDI (ch %02d): note on  (%02x vel %02x)\n",
713                           midi->channel,
714                           midi->key, midi->velocity));
715 
716               midi_event (midi, midi->channel, midi->key,
717                           (gdouble) midi->velocity / 127.0);
718             }
719           else if (midi->command == 0x8)
720             {
721               D (g_print ("MIDI (ch %02d): note off (%02x vel %02x)\n",
722                           midi->channel, midi->key, midi->velocity));
723 
724               midi_event (midi, midi->channel, midi->key + 128,
725                           (gdouble) midi->velocity / 127.0);
726             }
727           else
728             {
729               D (g_print ("MIDI (ch %02d): polyphonic aftertouch (%02x pressure %02x)\n",
730                           midi->channel, midi->key, midi->velocity));
731             }
732 
733           midi->key      = -1;
734           midi->velocity = -1;
735           break;
736 
737         case 0xb:  /* controllers, sustain */
738 
739           if (midi->key == -1)
740             {
741               midi->key = buf[pos++];
742               continue;
743             }
744 
745           if (midi->velocity == -1)
746             midi->velocity = buf[pos++];
747 
748           D (g_print ("MIDI (ch %02d): controller %d (value %d)\n",
749                       midi->channel, midi->key, midi->velocity));
750 
751           midi_event (midi, midi->channel, midi->key + 128 + 128,
752                       (gdouble) midi->velocity / 127.0);
753 
754           midi->key      = -1;
755           midi->velocity = -1;
756           break;
757 
758         case 0xc:  /* program change */
759           midi->key = buf[pos++];
760 
761           D (g_print ("MIDI (ch %02d): program change (%d)\n",
762                       midi->channel, midi->key));
763 
764           midi->key = -1;
765           break;
766 
767         case 0xd:  /* channel key pressure */
768           midi->velocity = buf[pos++];
769 
770           D (g_print ("MIDI (ch %02d): channel aftertouch (%d)\n",
771                       midi->channel, midi->velocity));
772 
773           midi->velocity = -1;
774           break;
775 
776         case 0xe:  /* pitch bend */
777           if (midi->lsb == -1)
778             {
779               midi->lsb = buf[pos++];
780               continue;
781             }
782 
783           if (midi->msb == -1)
784             midi->msb = buf[pos++];
785 
786           midi->velocity = midi->lsb | (midi->msb << 7);
787 
788           D (g_print ("MIDI (ch %02d): pitch (%d)\n",
789                       midi->channel, midi->velocity));
790 
791           midi->msb      = -1;
792           midi->lsb      = -1;
793           midi->velocity = -1;
794           break;
795         }
796     }
797 
798   return TRUE;
799 }
800 
801 #ifdef HAVE_ALSA
802 static gboolean
midi_alsa_prepare(GSource * source,gint * timeout)803 midi_alsa_prepare (GSource *source,
804                    gint    *timeout)
805 {
806   ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
807   gboolean        ready;
808 
809   ready = snd_seq_event_input_pending (midi->sequencer, 1) > 0;
810   *timeout = ready ? 1 : 10;
811 
812   return ready;
813 }
814 
815 static gboolean
midi_alsa_check(GSource * source)816 midi_alsa_check (GSource *source)
817 {
818   ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
819 
820   return snd_seq_event_input_pending (midi->sequencer, 1) > 0;
821 }
822 
823 static gboolean
midi_alsa_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)824 midi_alsa_dispatch (GSource     *source,
825                     GSourceFunc  callback,
826                     gpointer     user_data)
827 {
828   ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller);
829 
830   snd_seq_event_t       *event;
831   snd_seq_client_info_t *client_info;
832   snd_seq_port_info_t   *port_info;
833 
834   if (snd_seq_event_input_pending (midi->sequencer, 1) > 0)
835     {
836       snd_seq_event_input (midi->sequencer, &event);
837 
838       if (event->type == SND_SEQ_EVENT_NOTEON &&
839           event->data.note.velocity == 0)
840         event->type = SND_SEQ_EVENT_NOTEOFF;
841 
842       switch (event->type)
843         {
844         case SND_SEQ_EVENT_NOTEON:
845           midi_event (midi, event->data.note.channel,
846                       event->data.note.note,
847                       (gdouble) event->data.note.velocity / 127.0);
848           break;
849 
850         case SND_SEQ_EVENT_NOTEOFF:
851           midi_event (midi, event->data.note.channel,
852                       event->data.note.note + 128,
853                       (gdouble) event->data.note.velocity / 127.0);
854           break;
855 
856         case SND_SEQ_EVENT_CONTROLLER:
857           midi_event (midi, event->data.control.channel,
858                       event->data.control.param + 256,
859                       (gdouble) event->data.control.value / 127.0);
860           break;
861 
862         case SND_SEQ_EVENT_PORT_SUBSCRIBED:
863           snd_seq_client_info_alloca (&client_info);
864           snd_seq_port_info_alloca (&port_info);
865           snd_seq_get_any_client_info (midi->sequencer,
866                                        event->data.connect.sender.client,
867                                        client_info);
868           snd_seq_get_any_port_info (midi->sequencer,
869                                      event->data.connect.sender.client,
870                                      event->data.connect.sender.port,
871                                      port_info);
872           /*
873            * g_printerr ("subscribed to \"%s:%s\"\n",
874            *             snd_seq_client_info_get_name (client_info),
875            *             snd_seq_port_info_get_name (port_info));
876            */
877           break;
878 
879         case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
880           /* g_printerr ("unsubscribed\n");
881            */
882           break;
883 
884         default:
885           break;
886         }
887 
888       return TRUE;
889     }
890 
891   return FALSE;
892 }
893 #endif /* HAVE_ALSA */
894