More autotools work; allow disabling of lash
[gmidimonitor.git] / main.c
blobd2c525111455c96163cbe401b011c02e0e42f8d7
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * DESCRIPTION:
5 * gmidimonitor main code.
7 * LICENSE:
8 * GNU GENERAL PUBLIC LICENSE version 2
10 *****************************************************************************/
12 #include "config.h"
14 #include <gtk/gtk.h>
15 #include <alsa/asoundlib.h>
16 #include <pthread.h>
17 #include <signal.h>
19 #ifdef HAVE_LASH
20 #include <lash/lash.h>
21 #endif
23 #include "path.h"
24 #include "glade.h"
26 GtkWidget * g_main_window_ptr;
28 snd_seq_t * g_seq_ptr;
30 gboolean g_midi_ignore = FALSE;
32 int g_row_count;
34 #ifdef HAVE_LASH
35 lash_client_t * g_lashc;
36 #endif
38 static const char * g_note_names[12] =
40 "C",
41 "C#",
42 "D",
43 "D#",
44 "E",
45 "F",
46 "F#",
47 "G",
48 "G#",
49 "A",
50 "A#",
51 "B",
54 static const char * g_gm_instrument_names[] =
56 "Acoustic Grand Piano", /* 1 */
57 "Bright Acoustic Piano", /* 2 */
58 "Electric Grand Piano", /* 3 */
59 "Honky-tonk Piano", /* 4 */
60 "Electric Piano 1", /* 5 */
61 "Electric Piano 2", /* 6 */
62 "Harpsichord", /* 7 */
63 "Clavi", /* 8 */
64 "Celesta", /* 9 */
65 "Glockenspiel", /* 10 */
66 "Music Box", /* 11 */
67 "Vibraphone", /* 12 */
68 "Marimba", /* 13 */
69 "Xylophone", /* 14 */
70 "Tubular Bells", /* 15 */
71 "Dulcimer", /* 16 */
72 "Drawbar Organ", /* 17 */
73 "Percussive Organ", /* 18 */
74 "Rock Organ", /* 19 */
75 "Church Organ", /* 20 */
76 "Reed Organ", /* 21 */
77 "Accordion", /* 22 */
78 "Harmonica", /* 23 */
79 "Tango Accordion", /* 24 */
80 "Acoustic Guitar (nylon)", /* 25 */
81 "Acoustic Guitar (steel)", /* 26 */
82 "Electric Guitar (jazz)", /* 27 */
83 "Electric Guitar (clean)", /* 28 */
84 "Electric Guitar (muted)", /* 29 */
85 "Overdriven Guitar", /* 30 */
86 "Distortion Guitar", /* 31 */
87 "Guitar harmonics", /* 32 */
88 "Acoustic Bass", /* 33 */
89 "Electric Bass (finger)", /* 34 */
90 "Electric Bass (pick)", /* 35 */
91 "Fretless Bass", /* 36 */
92 "Slap Bass 1", /* 37 */
93 "Slap Bass 2", /* 38 */
94 "Synth Bass 1", /* 39 */
95 "Synth Bass 2", /* 40 */
96 "Violin", /* 41 */
97 "Viola", /* 42 */
98 "Cello", /* 43 */
99 "Contrabass", /* 44 */
100 "Tremolo Strings", /* 45 */
101 "Pizzicato Strings", /* 46 */
102 "Orchestral Harp", /* 47 */
103 "Timpani", /* 48 */
104 "String Ensemble 1", /* 49 */
105 "String Ensemble 2", /* 50 */
106 "SynthStrings 1", /* 51 */
107 "SynthStrings 2", /* 52 */
108 "Choir Aahs", /* 53 */
109 "Voice Oohs", /* 54 */
110 "Synth Voice", /* 55 */
111 "Orchestra Hit", /* 56 */
112 "Trumpet", /* 57 */
113 "Trombone", /* 58 */
114 "Tuba", /* 59 */
115 "Muted Trumpet", /* 60 */
116 "French Horn", /* 61 */
117 "Brass Section", /* 62 */
118 "SynthBrass 1", /* 63 */
119 "SynthBrass 2", /* 64 */
120 "Soprano Sax", /* 65 */
121 "Alto Sax", /* 66 */
122 "Tenor Sax", /* 67 */
123 "Baritone Sax", /* 68 */
124 "Oboe", /* 69 */
125 "English Horn", /* 70 */
126 "Bassoon", /* 71 */
127 "Clarinet", /* 72 */
128 "Piccolo", /* 73 */
129 "Flute", /* 74 */
130 "Recorder", /* 75 */
131 "Pan Flute", /* 76 */
132 "Blown Bottle", /* 77 */
133 "Shakuhachi", /* 78 */
134 "Whistle", /* 79 */
135 "Ocarina", /* 80 */
136 "Lead 1 (square)", /* 81 */
137 "Lead 2 (sawtooth)", /* 82 */
138 "Lead 3 (calliope)", /* 83 */
139 "Lead 4 (chiff)", /* 84 */
140 "Lead 5 (charang)", /* 85 */
141 "Lead 6 (voice)", /* 86 */
142 "Lead 7 (fifths)", /* 87 */
143 "Lead 8 (bass + lead)", /* 88 */
144 "Pad 1 (new age)", /* 89 */
145 "Pad 2 (warm)", /* 90 */
146 "Pad 3 (polysynth)", /* 91 */
147 "Pad 4 (choir)", /* 92 */
148 "Pad 5 (bowed)", /* 93 */
149 "Pad 6 (metallic)", /* 94 */
150 "Pad 7 (halo)", /* 95 */
151 "Pad 8 (sweep)", /* 96 */
152 "FX 1 (rain)", /* 97 */
153 "FX 2 (soundtrack)", /* 98 */
154 "FX 3 (crystal)", /* 99 */
155 "FX 4 (atmosphere)", /* 100 */
156 "FX 5 (brightness)", /* 101 */
157 "FX 6 (goblins)", /* 102 */
158 "FX 7 (echoes)", /* 103 */
159 "FX 8 (sci-fi)", /* 104 */
160 "Sitar", /* 105 */
161 "Banjo", /* 106 */
162 "Shamisen", /* 107 */
163 "Koto", /* 108 */
164 "Kalimba", /* 109 */
165 "Bag pipe", /* 110 */
166 "Fiddle", /* 111 */
167 "Shanai", /* 112 */
168 "Tinkle Bell", /* 113 */
169 "Agogo", /* 114 */
170 "Steel Drums", /* 115 */
171 "Woodblock", /* 116 */
172 "Taiko Drum", /* 117 */
173 "Melodic Tom", /* 118 */
174 "Synth Drum", /* 119 */
175 "Reverse Cymbal", /* 120 */
176 "Guitar Fret Noise", /* 121 */
177 "Breath Noise", /* 122 */
178 "Seashore", /* 123 */
179 "Bird Tweet", /* 124 */
180 "Telephone Ring", /* 125 */
181 "Helicopter", /* 126 */
182 "Applause", /* 127 */
183 "Gunshot", /* 128 */
186 static const char * g_gm_drum_names[] =
188 "Acoustic Bass Drum", /* 35 */
189 "Bass Drum 1", /* 36 */
190 "Side Stick", /* 37 */
191 "Acoustic Snare", /* 38 */
192 "Hand Clap", /* 39 */
193 "Electric Snare", /* 40 */
194 "Low Floor Tom", /* 41 */
195 "Closed Hi-Hat", /* 42 */
196 "High Floor Tom", /* 43 */
197 "Pedal Hi-Hat", /* 44 */
198 "Low Tom", /* 45 */
199 "Open Hi-Hat", /* 46 */
200 "Low-Mid Tom", /* 47 */
201 "Hi-Mid Tom", /* 48 */
202 "Crash Cymbal 1", /* 49 */
203 "High Tom", /* 50 */
204 "Ride Cymbal 1", /* 51 */
205 "Chinese Cymbal", /* 52 */
206 "Ride Bell", /* 53 */
207 "Tambourine", /* 54 */
208 "Splash Cymbal", /* 55 */
209 "Cowbell", /* 56 */
210 "Crash Cymbal 2", /* 57 */
211 "Vibraslap", /* 58 */
212 "Ride Cymbal 2", /* 59 */
213 "Hi Bongo", /* 60 */
214 "Low Bongo", /* 61 */
215 "Mute Hi Conga", /* 62 */
216 "Open Hi Conga", /* 63 */
217 "Low Conga", /* 64 */
218 "High Timbale", /* 65 */
219 "Low Timbale", /* 66 */
220 "High Agogo", /* 67 */
221 "Low Agogo", /* 68 */
222 "Cabasa", /* 69 */
223 "Maracas", /* 70 */
224 "Short Whistle", /* 71 */
225 "Long Whistle", /* 72 */
226 "Short Guiro", /* 73 */
227 "Long Guiro", /* 74 */
228 "Claves", /* 75 */
229 "Hi Wood Block", /* 76 */
230 "Low Wood Block", /* 77 */
231 "Mute Cuica", /* 78 */
232 "Open Cuica", /* 79 */
233 "Mute Triangle", /* 80 */
234 "Open Triangle", /* 81 */
237 enum
239 COL_TIME,
240 COL_CHANNEL,
241 COL_MESSAGE,
242 NUM_COLS
245 #define MAX_LIST_SIZE 2000
247 void
248 create_mainwindow()
250 GtkWidget * child_ptr;
251 GtkListStore * list_store_ptr;
252 GtkTreeViewColumn * column_ptr;
253 GtkCellRenderer * text_renderer_ptr;
255 g_main_window_ptr = construct_glade_widget("main_window");
257 child_ptr = get_glade_widget_child(g_main_window_ptr, "list");
259 text_renderer_ptr = gtk_cell_renderer_text_new();
261 g_object_set(
262 G_OBJECT(text_renderer_ptr),
263 "family",
264 "Monospace",
265 NULL);
267 /* column_ptr = gtk_tree_view_column_new_with_attributes( */
268 /* "Time", */
269 /* text_renderer_ptr, */
270 /* "text", COL_TIME, */
271 /* NULL); */
273 /* gtk_tree_view_append_column( */
274 /* GTK_TREE_VIEW(child_ptr), */
275 /* column_ptr); */
277 column_ptr = gtk_tree_view_column_new_with_attributes(
278 "Channel",
279 text_renderer_ptr,
280 "text", COL_CHANNEL,
281 NULL);
283 gtk_tree_view_append_column(
284 GTK_TREE_VIEW(child_ptr),
285 column_ptr);
287 column_ptr = gtk_tree_view_column_new_with_attributes(
288 "Message",
289 text_renderer_ptr,
290 "text", COL_MESSAGE,
291 NULL);
293 gtk_tree_view_append_column(
294 GTK_TREE_VIEW(child_ptr),
295 column_ptr);
297 gtk_widget_show_all(g_main_window_ptr);
299 list_store_ptr = gtk_list_store_new(
300 NUM_COLS,
301 G_TYPE_STRING,
302 G_TYPE_STRING,
303 G_TYPE_STRING);
305 gtk_tree_view_set_model(GTK_TREE_VIEW(child_ptr), GTK_TREE_MODEL(list_store_ptr));
308 /* stop button toggle */
309 void on_button_stop_toggled(
310 GtkAction * action_ptr,
311 GtkWidget * widget_ptr)
313 GtkWidget * child_ptr;
315 child_ptr = get_glade_widget_child(widget_ptr, "button_stop");
317 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(child_ptr)))
319 g_midi_ignore = TRUE;
321 else
323 g_midi_ignore = FALSE;
327 void on_clear_clicked
328 (GtkButton *button, gpointer user_data)
330 gtk_list_store_clear(
331 GTK_LIST_STORE(
332 gtk_tree_view_get_model(
333 GTK_TREE_VIEW(
334 get_glade_widget_child(
335 g_main_window_ptr,
336 "list")))));
337 g_row_count = 0;
340 /* The midi input handling thread */
341 void *
342 midi_thread(void * context_ptr)
344 GtkTreeIter iter;
345 snd_seq_event_t * event_ptr;
346 GtkListStore * list_store_ptr;
347 GtkWidget * child_ptr;
348 GString * time_str_ptr;
349 GString * msg_str_ptr;
350 GString * channel_str_ptr;
351 const char * note_name;
352 int octave;
353 const char * drum_name;
354 const char * cc_name;
355 int i;
356 const char * mmc_command_name;
358 child_ptr = get_glade_widget_child(g_main_window_ptr, "list");
360 list_store_ptr = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)));
362 g_row_count = 0;
364 while (snd_seq_event_input(g_seq_ptr, &event_ptr) >= 0)
366 if (g_midi_ignore)
367 continue;
369 time_str_ptr = g_string_new("");
370 g_string_sprintf(
371 time_str_ptr,
372 "%u:%u",
373 (unsigned int)event_ptr->time.time.tv_sec,
374 (unsigned int)event_ptr->time.time.tv_nsec);
375 channel_str_ptr = g_string_new("");
377 /* Workaround for compiler warnings... */
378 drum_name = NULL;
379 note_name = NULL;
380 octave = 0;
382 if (event_ptr->type == SND_SEQ_EVENT_NOTE ||
383 event_ptr->type == SND_SEQ_EVENT_NOTEON ||
384 event_ptr->type == SND_SEQ_EVENT_NOTEOFF ||
385 event_ptr->type == SND_SEQ_EVENT_KEYPRESS)
387 g_string_sprintf(
388 channel_str_ptr,
389 "%u",
390 (unsigned int)event_ptr->data.note.channel+1);
391 if (event_ptr->data.note.channel+1 == 10 &&
392 event_ptr->data.note.note >= 35 &&
393 event_ptr->data.note.note < 35 + sizeof(g_gm_drum_names)/sizeof(g_gm_drum_names[0]))
395 drum_name = g_gm_drum_names[event_ptr->data.note.note - 35];
397 else
399 drum_name = NULL;
402 note_name = g_note_names[event_ptr->data.note.note % 12];
403 octave = event_ptr->data.note.note / 12 - 1;
406 if (event_ptr->type == SND_SEQ_EVENT_CONTROLLER ||
407 event_ptr->type == SND_SEQ_EVENT_PGMCHANGE ||
408 event_ptr->type == SND_SEQ_EVENT_PITCHBEND)
410 g_string_sprintf(
411 channel_str_ptr,
412 "%u",
413 (unsigned int)event_ptr->data.control.channel+1);
416 msg_str_ptr = g_string_new("unknown event");
418 switch (event_ptr->type)
420 case SND_SEQ_EVENT_SYSTEM:
421 g_string_sprintf(msg_str_ptr, "System event");
422 break;
423 case SND_SEQ_EVENT_RESULT:
424 g_string_sprintf(msg_str_ptr, "Result status event");
425 break;
426 case SND_SEQ_EVENT_NOTE:
427 g_string_sprintf(msg_str_ptr, "Note");
428 break;
429 case SND_SEQ_EVENT_NOTEON:
430 if (event_ptr->data.note.velocity != 0)
432 if (drum_name != NULL)
434 g_string_sprintf(
435 msg_str_ptr,
436 "Drum: %s (%s, octave %d, velocity %u)",
437 drum_name,
438 note_name,
439 octave,
440 event_ptr->data.note.velocity);
442 else
444 g_string_sprintf(
445 msg_str_ptr,
446 "Note on , %s, octave %d, velocity %u",
447 note_name,
448 octave,
449 event_ptr->data.note.velocity);
451 break;
453 case SND_SEQ_EVENT_NOTEOFF:
454 if (drum_name != NULL) /* ignore note off for drums */
455 continue;
457 g_string_sprintf(
458 msg_str_ptr,
459 "Note off, %s, octave %d",
460 note_name,
461 octave);
463 break;
464 case SND_SEQ_EVENT_KEYPRESS:
465 g_string_sprintf(msg_str_ptr, "Key pressure change (aftertouch)");
466 break;
467 case SND_SEQ_EVENT_CONTROLLER:
468 cc_name = NULL;
469 switch (event_ptr->data.control.param)
471 case MIDI_CTL_MSB_BANK:
472 cc_name = "Bank selection";
473 break;
474 case MIDI_CTL_MSB_MODWHEEL:
475 cc_name = "Modulation";
476 break;
477 case MIDI_CTL_MSB_BREATH:
478 cc_name = "Breath";
479 break;
480 case MIDI_CTL_MSB_FOOT:
481 cc_name = "Foot";
482 break;
483 case MIDI_CTL_MSB_PORTAMENTO_TIME:
484 cc_name = "Portamento time";
485 break;
486 case MIDI_CTL_MSB_DATA_ENTRY:
487 cc_name = "Data entry";
488 break;
489 case MIDI_CTL_MSB_MAIN_VOLUME:
490 cc_name = "Main volume";
491 break;
492 case MIDI_CTL_MSB_BALANCE:
493 cc_name = "Balance";
494 break;
495 case MIDI_CTL_MSB_PAN:
496 cc_name = "Panpot";
497 break;
498 case MIDI_CTL_MSB_EXPRESSION:
499 cc_name = "Expression";
500 break;
501 case MIDI_CTL_MSB_EFFECT1:
502 cc_name = "Effect1";
503 break;
504 case MIDI_CTL_MSB_EFFECT2:
505 cc_name = "Effect2";
506 break;
507 case MIDI_CTL_MSB_GENERAL_PURPOSE1:
508 cc_name = "General purpose 1";
509 break;
510 case MIDI_CTL_MSB_GENERAL_PURPOSE2:
511 cc_name = "General purpose 2";
512 break;
513 case MIDI_CTL_MSB_GENERAL_PURPOSE3:
514 cc_name = "General purpose 3";
515 break;
516 case MIDI_CTL_MSB_GENERAL_PURPOSE4:
517 cc_name = "General purpose 4";
518 break;
519 case MIDI_CTL_LSB_BANK:
520 cc_name = "Bank selection";
521 break;
522 case MIDI_CTL_LSB_MODWHEEL:
523 cc_name = "Modulation";
524 break;
525 case MIDI_CTL_LSB_BREATH:
526 cc_name = "Breath";
527 break;
528 case MIDI_CTL_LSB_FOOT:
529 cc_name = "Foot";
530 break;
531 case MIDI_CTL_LSB_PORTAMENTO_TIME:
532 cc_name = "Portamento time";
533 break;
534 case MIDI_CTL_LSB_DATA_ENTRY:
535 cc_name = "Data entry";
536 break;
537 case MIDI_CTL_LSB_MAIN_VOLUME:
538 cc_name = "Main volume";
539 break;
540 case MIDI_CTL_LSB_BALANCE:
541 cc_name = "Balance";
542 break;
543 case MIDI_CTL_LSB_PAN:
544 cc_name = "Panpot";
545 break;
546 case MIDI_CTL_LSB_EXPRESSION:
547 cc_name = "Expression";
548 break;
549 case MIDI_CTL_LSB_EFFECT1:
550 cc_name = "Effect1";
551 break;
552 case MIDI_CTL_LSB_EFFECT2:
553 cc_name = "Effect2";
554 break;
555 case MIDI_CTL_LSB_GENERAL_PURPOSE1:
556 cc_name = "General purpose 1";
557 break;
558 case MIDI_CTL_LSB_GENERAL_PURPOSE2:
559 cc_name = "General purpose 2";
560 break;
561 case MIDI_CTL_LSB_GENERAL_PURPOSE3:
562 cc_name = "General purpose 3";
563 break;
564 case MIDI_CTL_LSB_GENERAL_PURPOSE4:
565 cc_name = "General purpose 4";
566 break;
567 case MIDI_CTL_SUSTAIN:
568 cc_name = "Sustain pedal";
569 break;
570 case MIDI_CTL_PORTAMENTO:
571 cc_name = "Portamento";
572 break;
573 case MIDI_CTL_SOSTENUTO:
574 cc_name = "Sostenuto";
575 break;
576 case MIDI_CTL_SOFT_PEDAL:
577 cc_name = "Soft pedal";
578 break;
579 case MIDI_CTL_LEGATO_FOOTSWITCH:
580 cc_name = "Legato foot switch";
581 break;
582 case MIDI_CTL_HOLD2:
583 cc_name = "Hold2";
584 break;
585 case MIDI_CTL_SC1_SOUND_VARIATION:
586 cc_name = "SC1 Sound Variation";
587 break;
588 case MIDI_CTL_SC2_TIMBRE:
589 cc_name = "SC2 Timbre";
590 break;
591 case MIDI_CTL_SC3_RELEASE_TIME:
592 cc_name = "SC3 Release Time";
593 break;
594 case MIDI_CTL_SC4_ATTACK_TIME:
595 cc_name = "SC4 Attack Time";
596 break;
597 case MIDI_CTL_SC5_BRIGHTNESS:
598 cc_name = "SC5 Brightness";
599 break;
600 case MIDI_CTL_SC6:
601 cc_name = "SC6";
602 break;
603 case MIDI_CTL_SC7:
604 cc_name = "SC7";
605 break;
606 case MIDI_CTL_SC8:
607 cc_name = "SC8";
608 break;
609 case MIDI_CTL_SC9:
610 cc_name = "SC9";
611 break;
612 case MIDI_CTL_SC10:
613 cc_name = "SC10";
614 break;
615 case MIDI_CTL_GENERAL_PURPOSE5:
616 cc_name = "General purpose 5";
617 break;
618 case MIDI_CTL_GENERAL_PURPOSE6:
619 cc_name = "General purpose 6";
620 break;
621 case MIDI_CTL_GENERAL_PURPOSE7:
622 cc_name = "General purpose 7";
623 break;
624 case MIDI_CTL_GENERAL_PURPOSE8:
625 cc_name = "General purpose 8";
626 break;
627 case MIDI_CTL_PORTAMENTO_CONTROL:
628 cc_name = "Portamento control";
629 break;
630 case MIDI_CTL_E1_REVERB_DEPTH:
631 cc_name = "E1 Reverb Depth";
632 break;
633 case MIDI_CTL_E2_TREMOLO_DEPTH:
634 cc_name = "E2 Tremolo Depth";
635 break;
636 case MIDI_CTL_E3_CHORUS_DEPTH:
637 cc_name = "E3 Chorus Depth";
638 break;
639 case MIDI_CTL_E4_DETUNE_DEPTH:
640 cc_name = "E4 Detune Depth";
641 break;
642 case MIDI_CTL_E5_PHASER_DEPTH:
643 cc_name = "E5 Phaser Depth";
644 break;
645 case MIDI_CTL_DATA_INCREMENT:
646 cc_name = "Data Increment";
647 break;
648 case MIDI_CTL_DATA_DECREMENT:
649 cc_name = "Data Decrement";
650 break;
651 case MIDI_CTL_NONREG_PARM_NUM_LSB:
652 cc_name = "Non-registered parameter number";
653 break;
654 case MIDI_CTL_NONREG_PARM_NUM_MSB:
655 cc_name = "Non-registered parameter number";
656 break;
657 case MIDI_CTL_REGIST_PARM_NUM_LSB:
658 cc_name = "Registered parameter number";
659 break;
660 case MIDI_CTL_REGIST_PARM_NUM_MSB:
661 cc_name = "Registered parameter number";
662 break;
663 case MIDI_CTL_ALL_SOUNDS_OFF:
664 cc_name = "All sounds off";
665 break;
666 case MIDI_CTL_RESET_CONTROLLERS:
667 cc_name = "Reset Controllers";
668 break;
669 case MIDI_CTL_LOCAL_CONTROL_SWITCH:
670 cc_name = "Local control switch";
671 break;
672 case MIDI_CTL_ALL_NOTES_OFF:
673 cc_name = "All notes off";
674 break;
675 case MIDI_CTL_OMNI_OFF:
676 cc_name = "Omni off";
677 break;
678 case MIDI_CTL_OMNI_ON:
679 cc_name = "Omni on";
680 break;
681 case MIDI_CTL_MONO1:
682 cc_name = "Mono1";
683 break;
684 case MIDI_CTL_MONO2:
685 cc_name = "Mono2";
686 break;
689 if (cc_name != NULL)
691 g_string_sprintf(
692 msg_str_ptr,
693 "CC %s (%u), value %u",
694 cc_name,
695 (unsigned int)event_ptr->data.control.param,
696 (unsigned int)event_ptr->data.control.value);
698 else
700 g_string_sprintf(
701 msg_str_ptr,
702 "CC %u, value %u",
703 (unsigned int)event_ptr->data.control.param,
704 (unsigned int)event_ptr->data.control.value);
706 break;
707 case SND_SEQ_EVENT_PGMCHANGE:
708 g_string_sprintf(
709 msg_str_ptr,
710 "Program change, %d (%s)",
711 (unsigned int)event_ptr->data.control.value,
712 event_ptr->data.control.value >= sizeof(g_gm_instrument_names)/sizeof(g_gm_instrument_names[0])?
713 "???":
714 g_gm_instrument_names[event_ptr->data.control.value]);
715 break;
716 case SND_SEQ_EVENT_CHANPRESS:
717 g_string_sprintf(msg_str_ptr, "Channel pressure");
718 break;
719 case SND_SEQ_EVENT_PITCHBEND:
720 g_string_sprintf(
721 msg_str_ptr,
722 "Pitchwheel, %d",
723 (unsigned int)event_ptr->data.control.value);
724 break;
725 case SND_SEQ_EVENT_CONTROL14:
726 g_string_sprintf(msg_str_ptr, "14 bit controller value");
727 break;
728 case SND_SEQ_EVENT_NONREGPARAM:
729 g_string_sprintf(msg_str_ptr, "NRPN");
730 break;
731 case SND_SEQ_EVENT_REGPARAM:
732 g_string_sprintf(msg_str_ptr, "RPN");
733 break;
734 case SND_SEQ_EVENT_SONGPOS:
735 g_string_sprintf(msg_str_ptr, "Song position");
736 break;
737 case SND_SEQ_EVENT_SONGSEL:
738 g_string_sprintf(msg_str_ptr, "Song select");
739 break;
740 case SND_SEQ_EVENT_QFRAME:
741 g_string_sprintf(msg_str_ptr, "midi time code quarter frame");
742 break;
743 case SND_SEQ_EVENT_TIMESIGN:
744 g_string_sprintf(msg_str_ptr, "SMF Time Signature event");
745 break;
746 case SND_SEQ_EVENT_KEYSIGN:
747 g_string_sprintf(msg_str_ptr, "SMF Key Signature event");
748 break;
749 case SND_SEQ_EVENT_START:
750 g_string_sprintf(msg_str_ptr, "MIDI Real Time Start message");
751 break;
752 case SND_SEQ_EVENT_CONTINUE:
753 g_string_sprintf(msg_str_ptr, "MIDI Real Time Continue message");
754 break;
755 case SND_SEQ_EVENT_STOP:
756 g_string_sprintf(msg_str_ptr, "MIDI Real Time Stop message");
757 break;
758 case SND_SEQ_EVENT_SETPOS_TICK:
759 g_string_sprintf(msg_str_ptr, "Set tick queue position");
760 break;
761 case SND_SEQ_EVENT_SETPOS_TIME:
762 g_string_sprintf(msg_str_ptr, "Set real-time queue position");
763 break;
764 case SND_SEQ_EVENT_TEMPO:
765 g_string_sprintf(msg_str_ptr, "(SMF) Tempo event");
766 break;
767 case SND_SEQ_EVENT_CLOCK:
768 g_string_sprintf(msg_str_ptr, "MIDI Real Time Clock message");
769 break;
770 case SND_SEQ_EVENT_TICK:
771 g_string_sprintf(msg_str_ptr, "MIDI Real Time Tick message");
772 break;
773 case SND_SEQ_EVENT_QUEUE_SKEW:
774 g_string_sprintf(msg_str_ptr, "Queue timer skew");
775 break;
776 case SND_SEQ_EVENT_SYNC_POS:
777 g_string_sprintf(msg_str_ptr, "Sync position changed");
778 break;
779 case SND_SEQ_EVENT_TUNE_REQUEST:
780 g_string_sprintf(msg_str_ptr, "Tune request");
781 break;
782 case SND_SEQ_EVENT_RESET:
783 g_string_sprintf(msg_str_ptr, "Reset");
784 break;
785 case SND_SEQ_EVENT_SENSING:
786 continue; /* disable */
787 g_string_sprintf(msg_str_ptr, "Active sensing");
788 break;
789 case SND_SEQ_EVENT_ECHO:
790 g_string_sprintf(msg_str_ptr, "Echo-back event");
791 break;
792 case SND_SEQ_EVENT_OSS:
793 g_string_sprintf(msg_str_ptr, "OSS emulation raw event");
794 break;
795 case SND_SEQ_EVENT_CLIENT_START:
796 g_string_sprintf(msg_str_ptr, "New client has connected");
797 break;
798 case SND_SEQ_EVENT_CLIENT_EXIT:
799 g_string_sprintf(msg_str_ptr, "Client has left the system");
800 break;
801 case SND_SEQ_EVENT_CLIENT_CHANGE:
802 g_string_sprintf(msg_str_ptr, "Client status/info has changed");
803 break;
804 case SND_SEQ_EVENT_PORT_START:
805 g_string_sprintf(msg_str_ptr, "New port was created");
806 break;
807 case SND_SEQ_EVENT_PORT_EXIT:
808 g_string_sprintf(msg_str_ptr, "Port was deleted from system");
809 break;
810 case SND_SEQ_EVENT_PORT_CHANGE:
811 g_string_sprintf(msg_str_ptr, "Port status/info has changed");
812 break;
813 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
814 g_string_sprintf(msg_str_ptr, "Port connected");
815 break;
816 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
817 g_string_sprintf(msg_str_ptr, "Port disconnected");
818 break;
819 case SND_SEQ_EVENT_SAMPLE:
820 g_string_sprintf(msg_str_ptr, "Sample select");
821 break;
822 case SND_SEQ_EVENT_SAMPLE_CLUSTER:
823 g_string_sprintf(msg_str_ptr, "Sample cluster select");
824 break;
825 case SND_SEQ_EVENT_SAMPLE_START:
826 g_string_sprintf(msg_str_ptr, "voice start");
827 break;
828 case SND_SEQ_EVENT_SAMPLE_STOP:
829 g_string_sprintf(msg_str_ptr, "voice stop");
830 break;
831 case SND_SEQ_EVENT_SAMPLE_FREQ:
832 g_string_sprintf(msg_str_ptr, "playback frequency");
833 break;
834 case SND_SEQ_EVENT_SAMPLE_VOLUME:
835 g_string_sprintf(msg_str_ptr, "volume and balance");
836 break;
837 case SND_SEQ_EVENT_SAMPLE_LOOP:
838 g_string_sprintf(msg_str_ptr, "sample loop");
839 break;
840 case SND_SEQ_EVENT_SAMPLE_POSITION:
841 g_string_sprintf(msg_str_ptr, "sample position");
842 break;
843 case SND_SEQ_EVENT_SAMPLE_PRIVATE1:
844 g_string_sprintf(msg_str_ptr, "private (hardware dependent) event");
845 break;
846 case SND_SEQ_EVENT_USR0:
847 g_string_sprintf(msg_str_ptr, "user-defined event");
848 break;
849 case SND_SEQ_EVENT_USR1:
850 g_string_sprintf(msg_str_ptr, "user-defined event");
851 break;
852 case SND_SEQ_EVENT_USR2:
853 g_string_sprintf(msg_str_ptr, "user-defined event");
854 break;
855 case SND_SEQ_EVENT_USR3:
856 g_string_sprintf(msg_str_ptr, "user-defined event");
857 break;
858 case SND_SEQ_EVENT_USR4:
859 g_string_sprintf(msg_str_ptr, "user-defined event");
860 break;
861 case SND_SEQ_EVENT_USR5:
862 g_string_sprintf(msg_str_ptr, "user-defined event");
863 break;
864 case SND_SEQ_EVENT_USR6:
865 g_string_sprintf(msg_str_ptr, "user-defined event");
866 break;
867 case SND_SEQ_EVENT_USR7:
868 g_string_sprintf(msg_str_ptr, "user-defined event");
869 break;
870 case SND_SEQ_EVENT_USR8:
871 g_string_sprintf(msg_str_ptr, "user-defined event");
872 break;
873 case SND_SEQ_EVENT_USR9:
874 g_string_sprintf(msg_str_ptr, "user-defined event");
875 break;
876 case SND_SEQ_EVENT_INSTR_BEGIN:
877 g_string_sprintf(msg_str_ptr, "begin of instrument management");
878 break;
879 case SND_SEQ_EVENT_INSTR_END:
880 g_string_sprintf(msg_str_ptr, "end of instrument management");
881 break;
882 case SND_SEQ_EVENT_INSTR_INFO:
883 g_string_sprintf(msg_str_ptr, "query instrument interface info");
884 break;
885 case SND_SEQ_EVENT_INSTR_INFO_RESULT:
886 g_string_sprintf(msg_str_ptr, "result of instrument interface info");
887 break;
888 case SND_SEQ_EVENT_INSTR_FINFO:
889 g_string_sprintf(msg_str_ptr, "query instrument format info");
890 break;
891 case SND_SEQ_EVENT_INSTR_FINFO_RESULT:
892 g_string_sprintf(msg_str_ptr, "result of instrument format info");
893 break;
894 case SND_SEQ_EVENT_INSTR_RESET:
895 g_string_sprintf(msg_str_ptr, "reset instrument instrument memory");
896 break;
897 case SND_SEQ_EVENT_INSTR_STATUS:
898 g_string_sprintf(msg_str_ptr, "get instrument interface status");
899 break;
900 case SND_SEQ_EVENT_INSTR_STATUS_RESULT:
901 g_string_sprintf(msg_str_ptr, "result of instrument interface status");
902 break;
903 case SND_SEQ_EVENT_INSTR_PUT:
904 g_string_sprintf(msg_str_ptr, "put an instrument to port");
905 break;
906 case SND_SEQ_EVENT_INSTR_GET:
907 g_string_sprintf(msg_str_ptr, "get an instrument from port");
908 break;
909 case SND_SEQ_EVENT_INSTR_GET_RESULT:
910 g_string_sprintf(msg_str_ptr, "result of instrument query");
911 break;
912 case SND_SEQ_EVENT_INSTR_FREE:
913 g_string_sprintf(msg_str_ptr, "free instrument(s)");
914 break;
915 case SND_SEQ_EVENT_INSTR_LIST:
916 g_string_sprintf(msg_str_ptr, "get instrument list");
917 break;
918 case SND_SEQ_EVENT_INSTR_LIST_RESULT:
919 g_string_sprintf(msg_str_ptr, "result of instrument list");
920 break;
921 case SND_SEQ_EVENT_INSTR_CLUSTER:
922 g_string_sprintf(msg_str_ptr, "set cluster parameters");
923 break;
924 case SND_SEQ_EVENT_INSTR_CLUSTER_GET:
925 g_string_sprintf(msg_str_ptr, "get cluster parameters");
926 break;
927 case SND_SEQ_EVENT_INSTR_CLUSTER_RESULT:
928 g_string_sprintf(msg_str_ptr, "result of cluster parameters");
929 break;
930 case SND_SEQ_EVENT_INSTR_CHANGE:
931 g_string_sprintf(msg_str_ptr, "instrument change");
932 break;
933 case SND_SEQ_EVENT_SYSEX:
934 /* General MMC decoding, as seen at http://www.borg.com/~jglatt/tech/mmc.htm and
935 extended from "Advanced User Guide for MK-449C MIDI keyboard" info */
936 if (event_ptr->data.ext.len == 6 &&
937 ((guint8 *)event_ptr->data.ext.ptr)[0] == 0xF0 &&
938 ((guint8 *)event_ptr->data.ext.ptr)[1] == 0x7F &&
939 ((guint8 *)event_ptr->data.ext.ptr)[3] == 0x06 &&
940 ((guint8 *)event_ptr->data.ext.ptr)[5] == 0xF7)
942 switch (((guint8 *)event_ptr->data.ext.ptr)[4])
944 case 1:
945 mmc_command_name = "Stop";
946 break;
947 case 2:
948 mmc_command_name = "Play";
949 break;
950 case 3:
951 mmc_command_name = "Deferred Play";
952 break;
953 case 4:
954 mmc_command_name = "Fast Forward";
955 break;
956 case 5:
957 mmc_command_name = "Rewind";
958 break;
959 case 6:
960 mmc_command_name = "Record Strobe (Punch In)";
961 break;
962 case 7:
963 mmc_command_name = "Record Exit (Punch Out)";
964 break;
965 case 8:
966 mmc_command_name = "Record Pause";
967 break;
968 case 9:
969 mmc_command_name = "Pause";
970 break;
971 case 10:
972 mmc_command_name = "Eject";
973 break;
974 case 11:
975 mmc_command_name = "Chase";
976 break;
977 case 12:
978 mmc_command_name = "Command Error Reset";
979 break;
980 case 13:
981 mmc_command_name = "Reset";
982 break;
983 default:
984 goto generic_sysex;
986 g_string_sprintf(
987 msg_str_ptr,
988 "MMC %s, for ",
989 mmc_command_name);
991 if (((guint8 *)event_ptr->data.ext.ptr)[2] == 127)
993 g_string_append(
994 msg_str_ptr,
995 "all devices");
997 else
999 g_string_append_printf(
1000 msg_str_ptr,
1001 "device %u",
1002 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[2]));
1005 /* The goto MMC message, as seen at http://www.borg.com/~jglatt/tech/mmc.htm*/
1006 else if (event_ptr->data.ext.len == 13 &&
1007 ((guint8 *)event_ptr->data.ext.ptr)[0] == 0xF0 &&
1008 ((guint8 *)event_ptr->data.ext.ptr)[1] == 0x7F &&
1009 ((guint8 *)event_ptr->data.ext.ptr)[3] == 0x06 &&
1010 ((guint8 *)event_ptr->data.ext.ptr)[4] == 0x44 &&
1011 ((guint8 *)event_ptr->data.ext.ptr)[5] == 0x06 &&
1012 ((guint8 *)event_ptr->data.ext.ptr)[6] == 0x01 &&
1013 ((guint8 *)event_ptr->data.ext.ptr)[12] == 0xF7)
1015 g_string_sprintf(
1016 msg_str_ptr,
1017 "MMC goto %u:%u:%u/%u:%u",
1018 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[7] & 0x1F), /* fps encoding */
1019 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[8]),
1020 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[9]),
1021 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[10] & 0x1F), /* no fps > 32, but bit 5 looks
1022 used for something */
1023 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[11]));
1025 switch (((guint8 *)event_ptr->data.ext.ptr)[7] & 0x60)
1027 case 0:
1028 g_string_append(
1029 msg_str_ptr,
1030 ", 24 fps");
1031 break;
1032 case 1:
1033 g_string_append(
1034 msg_str_ptr,
1035 ", 25 fps");
1036 break;
1037 case 2:
1038 g_string_append(
1039 msg_str_ptr,
1040 ", 29.97 fps");
1041 break;
1042 case 3:
1043 g_string_append(
1044 msg_str_ptr,
1045 ", 30 fps");
1046 break;
1049 if (((guint8 *)event_ptr->data.ext.ptr)[2] == 127)
1051 g_string_append(
1052 msg_str_ptr,
1053 ", for all devices");
1055 else
1057 g_string_append_printf(
1058 msg_str_ptr,
1059 ", for device %u",
1060 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[2]));
1063 else
1065 generic_sysex:
1066 g_string_sprintf(
1067 msg_str_ptr,
1068 "SYSEX with size %u:",
1069 (unsigned int)event_ptr->data.ext.len);
1070 for (i = 0 ; i < event_ptr->data.ext.len ; i++)
1072 g_string_append_printf(
1073 msg_str_ptr,
1074 " %02X",
1075 (unsigned int)(((guint8 *)event_ptr->data.ext.ptr)[i]));
1078 break;
1079 case SND_SEQ_EVENT_BOUNCE:
1080 g_string_sprintf(msg_str_ptr, "error event");
1081 break;
1082 case SND_SEQ_EVENT_USR_VAR0:
1083 g_string_sprintf(msg_str_ptr, "reserved for user apps");
1084 break;
1085 case SND_SEQ_EVENT_USR_VAR1:
1086 g_string_sprintf(msg_str_ptr, "reserved for user apps");
1087 break;
1088 case SND_SEQ_EVENT_USR_VAR2:
1089 g_string_sprintf(msg_str_ptr, "reserved for user apps");
1090 break;
1091 case SND_SEQ_EVENT_USR_VAR3:
1092 g_string_sprintf(msg_str_ptr, "reserved for user apps");
1093 break;
1094 case SND_SEQ_EVENT_USR_VAR4:
1095 g_string_sprintf(msg_str_ptr, "reserved for user apps");
1096 break;
1099 /* get GTK thread lock */
1100 gdk_threads_enter();
1102 if (g_row_count >= MAX_LIST_SIZE)
1104 gtk_tree_model_get_iter_first(
1105 GTK_TREE_MODEL(list_store_ptr),
1106 &iter);
1108 gtk_list_store_remove(
1109 list_store_ptr,
1110 &iter);
1113 /* Append an empty row to the list store. Iter will point to the new row */
1114 gtk_list_store_append(list_store_ptr, &iter);
1116 gtk_list_store_set(
1117 list_store_ptr,
1118 &iter,
1119 COL_TIME, time_str_ptr->str,
1120 COL_CHANNEL, channel_str_ptr->str,
1121 COL_MESSAGE, msg_str_ptr->str,
1122 -1);
1124 g_string_free(channel_str_ptr, TRUE);
1125 g_string_free(msg_str_ptr, TRUE);
1127 gtk_tree_view_scroll_to_cell(
1128 GTK_TREE_VIEW(child_ptr),
1129 gtk_tree_model_get_path(
1130 gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)),
1131 &iter),
1132 NULL,
1133 TRUE,
1134 0.0,
1135 1.0);
1137 /* Force update of scroll position. */
1138 /* Is it a bug that it does not update automagically ? */
1139 gtk_container_check_resize(GTK_CONTAINER(child_ptr));
1141 /* release GTK thread lock */
1142 gdk_threads_leave();
1144 g_row_count++;
1147 return NULL;
1150 #ifdef HAVE_LASH
1152 void
1153 process_lash_event(lash_event_t * event_ptr)
1155 enum LASH_Event_Type type;
1156 const char * str;
1158 type = lash_event_get_type(event_ptr);
1159 str = lash_event_get_string(event_ptr);
1161 switch (type)
1163 case LASH_Quit:
1164 g_warning("LASH_Quit received.\n");
1165 g_lashc = NULL;
1166 gtk_main_quit();
1167 break;
1168 case LASH_Save_File:
1169 case LASH_Restore_File:
1170 case LASH_Save_Data_Set:
1171 default:
1172 g_warning("LASH Event. Type = %u, string = \"%s\"\n",
1173 (unsigned int)type,
1174 (str == NULL)?"":str);
1178 void
1179 process_lash_config(lash_config_t * config_ptr)
1181 const char * key;
1182 const void * data;
1183 size_t data_size;
1185 key = lash_config_get_key(config_ptr);
1186 data = lash_config_get_value(config_ptr);
1187 data_size = lash_config_get_value_size(config_ptr);
1189 g_warning("LASH Config. Key = \"%s\"\n", key);
1192 /* process lash events callback */
1193 gboolean
1194 process_lash_events(gpointer data)
1196 lash_event_t * event_ptr;
1197 lash_config_t * config_ptr;
1199 /* Process events */
1200 while ((event_ptr = lash_get_event(g_lashc)) != NULL)
1202 process_lash_event(event_ptr);
1203 lash_event_destroy(event_ptr);
1206 /* Process configs */
1207 while ((config_ptr = lash_get_config(g_lashc)) != NULL)
1209 process_lash_config(config_ptr);
1210 lash_config_destroy(config_ptr);
1213 return TRUE;
1216 #endif /* #ifdef HAVE_LASH */
1219 main(int argc, char *argv[])
1221 int ret;
1222 snd_seq_port_info_t * port_info = NULL;
1223 pthread_t midi_tid;
1224 #ifdef HAVE_LASH
1225 lash_event_t * lash_event_ptr;
1226 #endif
1227 GString * seq_client_name_str_ptr;
1229 /* init threads */
1230 g_thread_init(NULL);
1231 gdk_threads_init();
1232 gdk_threads_enter();
1234 gtk_init(&argc, &argv);
1236 path_init(argv[0]);
1238 #ifdef HAVE_LASH
1239 g_lashc = lash_init(
1240 lash_extract_args(&argc, &argv),
1241 "gmidimonitor",
1243 LASH_PROTOCOL_VERSION);
1245 if (g_lashc == NULL)
1247 g_warning("Failed to connect to LASH. Session management will not occur.\n");
1249 else
1251 lash_event_ptr = lash_event_new_with_type(LASH_Client_Name);
1252 lash_event_set_string(lash_event_ptr, "GMIDImonitor");
1253 lash_send_event(g_lashc, lash_event_ptr);
1254 g_timeout_add(250, process_lash_events, NULL);
1256 #endif
1258 /* interface creation */
1259 create_mainwindow();
1261 /* initialisation */
1262 ret = snd_seq_open(
1263 &g_seq_ptr,
1264 "default",
1265 SND_SEQ_OPEN_INPUT,
1267 if (ret < 0)
1269 g_warning("Cannot open sequncer, %s\n", snd_strerror(ret));
1270 goto path_uninit;
1273 seq_client_name_str_ptr = g_string_new("");
1274 g_string_sprintf(seq_client_name_str_ptr, "MIDI monitor (%u)", (unsigned int)getpid());
1275 snd_seq_set_client_name(g_seq_ptr, seq_client_name_str_ptr->str);
1277 #ifdef HAVE_LASH
1278 lash_alsa_client_id(g_lashc, snd_seq_client_id(g_seq_ptr));
1279 #endif
1281 snd_seq_port_info_alloca(&port_info);
1283 snd_seq_port_info_set_capability(
1284 port_info,
1285 SND_SEQ_PORT_CAP_WRITE |
1286 SND_SEQ_PORT_CAP_SUBS_WRITE);
1287 snd_seq_port_info_set_type(
1288 port_info,
1289 SND_SEQ_PORT_TYPE_APPLICATION);
1290 snd_seq_port_info_set_midi_channels(port_info, 16);
1291 snd_seq_port_info_set_port_specified(port_info, 1);
1293 snd_seq_port_info_set_name(port_info, "midi in");
1294 snd_seq_port_info_set_port(port_info, 0);
1296 ret = snd_seq_create_port(g_seq_ptr, port_info);
1297 if (ret < 0)
1299 g_warning("Error creating ALSA sequencer port, %s\n", snd_strerror(ret));
1300 goto close_seq;
1303 /* Start midi thread */
1304 ret = pthread_create(&midi_tid, NULL, midi_thread, NULL);
1306 /* main loop */
1307 gtk_main();
1309 /* Cancel the thread. Don't know better way.
1310 Poll or unblock mechanisms seem to not be
1311 available for alsa sequencer */
1312 pthread_cancel(midi_tid);
1314 /* Wait midi thread to finish */
1315 ret = pthread_join(midi_tid, NULL);
1317 gdk_threads_leave();
1319 close_seq:
1320 ret = snd_seq_close(g_seq_ptr);
1321 if (ret < 0)
1323 g_warning("Cannot close sequncer, %s\n", snd_strerror(ret));
1326 path_uninit:
1327 path_init(argv[0]);
1329 return 0;