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