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