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