1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * This file is part of gmidimonitor
6 * Copyright (C) 2005,2006,2007,2008,2011 Nedko Arnaudov <nedko@arnaudov.name>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *****************************************************************************/
23 #include <alsa/asoundlib.h>
32 /* TODO: this must be detected at configure stage */
35 extern GtkBuilder
* g_builder
;
37 snd_seq_t
* g_seq_ptr
;
38 pthread_t g_alsa_midi_tid
; /* alsa_midi_thread id */
40 /* The ALSA MIDI input handling thread */
42 alsa_midi_thread(void * context_ptr
)
45 snd_seq_event_t
* event_ptr
;
46 GtkListStore
* list_store_ptr
;
47 GtkWidget
* child_ptr
;
48 GString
* time_str_ptr
;
49 GString
* msg_str_ptr
;
50 GString
* channel_str_ptr
;
51 const char * note_name
;
53 const char * drum_name
;
56 child_ptr
= GTK_WIDGET (gtk_builder_get_object (g_builder
, "list"));
58 list_store_ptr
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr
)));
60 while (snd_seq_event_input(g_seq_ptr
, &event_ptr
) >= 0)
65 time_str_ptr
= g_string_new("");
69 (unsigned int)event_ptr
->time
.time
.tv_sec
,
70 (unsigned int)event_ptr
->time
.time
.tv_nsec
);
71 channel_str_ptr
= g_string_new("");
73 /* Workaround for compiler warnings... */
78 if (event_ptr
->type
== SND_SEQ_EVENT_NOTE
||
79 event_ptr
->type
== SND_SEQ_EVENT_NOTEON
||
80 event_ptr
->type
== SND_SEQ_EVENT_NOTEOFF
||
81 event_ptr
->type
== SND_SEQ_EVENT_KEYPRESS
)
86 (unsigned int)event_ptr
->data
.note
.channel
+1);
87 if (event_ptr
->data
.note
.channel
+ 1 == 10)
89 drum_name
= gm_get_drum_name(event_ptr
->data
.note
.note
);
96 note_name
= g_note_names
[event_ptr
->data
.note
.note
% 12];
97 octave
= event_ptr
->data
.note
.note
/ 12 - 1;
100 if (event_ptr
->type
== SND_SEQ_EVENT_CONTROLLER
||
101 event_ptr
->type
== SND_SEQ_EVENT_PGMCHANGE
||
102 event_ptr
->type
== SND_SEQ_EVENT_PITCHBEND
)
107 (unsigned int)event_ptr
->data
.control
.channel
+1);
110 msg_str_ptr
= g_string_new("unknown event");
112 switch (event_ptr
->type
)
114 case SND_SEQ_EVENT_SYSTEM
:
115 g_string_printf(msg_str_ptr
, "System event");
117 case SND_SEQ_EVENT_RESULT
:
118 g_string_printf(msg_str_ptr
, "Result status event");
120 case SND_SEQ_EVENT_NOTE
:
121 g_string_printf(msg_str_ptr
, "Note");
123 case SND_SEQ_EVENT_NOTEON
:
124 if (event_ptr
->data
.note
.velocity
!= 0)
126 if (drum_name
!= NULL
)
130 "Drum: %s (%s, octave %d, velocity %u)",
134 event_ptr
->data
.note
.velocity
);
140 "Note on, %s, octave %d, velocity %u",
143 event_ptr
->data
.note
.velocity
);
147 case SND_SEQ_EVENT_NOTEOFF
:
148 if (drum_name
!= NULL
) /* ignore note off for drums */
153 "Note off, %s, octave %d",
158 case SND_SEQ_EVENT_KEYPRESS
:
159 g_string_printf(msg_str_ptr
, "Key pressure change (aftertouch)");
161 case SND_SEQ_EVENT_CONTROLLER
:
163 switch (event_ptr
->data
.control
.param
)
165 case MIDI_CTL_MSB_BANK
:
166 cc_name
= "Bank selection";
168 case MIDI_CTL_MSB_MODWHEEL
:
169 cc_name
= "Modulation";
171 case MIDI_CTL_MSB_BREATH
:
174 case MIDI_CTL_MSB_FOOT
:
177 case MIDI_CTL_MSB_PORTAMENTO_TIME
:
178 cc_name
= "Portamento time";
180 case MIDI_CTL_MSB_DATA_ENTRY
:
181 cc_name
= "Data entry";
183 case MIDI_CTL_MSB_MAIN_VOLUME
:
184 cc_name
= "Main volume";
186 case MIDI_CTL_MSB_BALANCE
:
189 case MIDI_CTL_MSB_PAN
:
192 case MIDI_CTL_MSB_EXPRESSION
:
193 cc_name
= "Expression";
195 case MIDI_CTL_MSB_EFFECT1
:
198 case MIDI_CTL_MSB_EFFECT2
:
201 case MIDI_CTL_MSB_GENERAL_PURPOSE1
:
202 cc_name
= "General purpose 1";
204 case MIDI_CTL_MSB_GENERAL_PURPOSE2
:
205 cc_name
= "General purpose 2";
207 case MIDI_CTL_MSB_GENERAL_PURPOSE3
:
208 cc_name
= "General purpose 3";
210 case MIDI_CTL_MSB_GENERAL_PURPOSE4
:
211 cc_name
= "General purpose 4";
213 case MIDI_CTL_LSB_BANK
:
214 cc_name
= "Bank selection";
216 case MIDI_CTL_LSB_MODWHEEL
:
217 cc_name
= "Modulation";
219 case MIDI_CTL_LSB_BREATH
:
222 case MIDI_CTL_LSB_FOOT
:
225 case MIDI_CTL_LSB_PORTAMENTO_TIME
:
226 cc_name
= "Portamento time";
228 case MIDI_CTL_LSB_DATA_ENTRY
:
229 cc_name
= "Data entry";
231 case MIDI_CTL_LSB_MAIN_VOLUME
:
232 cc_name
= "Main volume";
234 case MIDI_CTL_LSB_BALANCE
:
237 case MIDI_CTL_LSB_PAN
:
240 case MIDI_CTL_LSB_EXPRESSION
:
241 cc_name
= "Expression";
243 case MIDI_CTL_LSB_EFFECT1
:
246 case MIDI_CTL_LSB_EFFECT2
:
249 case MIDI_CTL_LSB_GENERAL_PURPOSE1
:
250 cc_name
= "General purpose 1";
252 case MIDI_CTL_LSB_GENERAL_PURPOSE2
:
253 cc_name
= "General purpose 2";
255 case MIDI_CTL_LSB_GENERAL_PURPOSE3
:
256 cc_name
= "General purpose 3";
258 case MIDI_CTL_LSB_GENERAL_PURPOSE4
:
259 cc_name
= "General purpose 4";
261 case MIDI_CTL_SUSTAIN
:
262 cc_name
= "Sustain pedal";
264 case MIDI_CTL_PORTAMENTO
:
265 cc_name
= "Portamento";
267 case MIDI_CTL_SOSTENUTO
:
268 cc_name
= "Sostenuto";
270 case MIDI_CTL_SOFT_PEDAL
:
271 cc_name
= "Soft pedal";
273 case MIDI_CTL_LEGATO_FOOTSWITCH
:
274 cc_name
= "Legato foot switch";
279 case MIDI_CTL_SC1_SOUND_VARIATION
:
280 cc_name
= "SC1 Sound Variation";
282 case MIDI_CTL_SC2_TIMBRE
:
283 cc_name
= "SC2 Timbre";
285 case MIDI_CTL_SC3_RELEASE_TIME
:
286 cc_name
= "SC3 Release Time";
288 case MIDI_CTL_SC4_ATTACK_TIME
:
289 cc_name
= "SC4 Attack Time";
291 case MIDI_CTL_SC5_BRIGHTNESS
:
292 cc_name
= "SC5 Brightness";
309 case MIDI_CTL_GENERAL_PURPOSE5
:
310 cc_name
= "General purpose 5";
312 case MIDI_CTL_GENERAL_PURPOSE6
:
313 cc_name
= "General purpose 6";
315 case MIDI_CTL_GENERAL_PURPOSE7
:
316 cc_name
= "General purpose 7";
318 case MIDI_CTL_GENERAL_PURPOSE8
:
319 cc_name
= "General purpose 8";
321 case MIDI_CTL_PORTAMENTO_CONTROL
:
322 cc_name
= "Portamento control";
324 case MIDI_CTL_E1_REVERB_DEPTH
:
325 cc_name
= "E1 Reverb Depth";
327 case MIDI_CTL_E2_TREMOLO_DEPTH
:
328 cc_name
= "E2 Tremolo Depth";
330 case MIDI_CTL_E3_CHORUS_DEPTH
:
331 cc_name
= "E3 Chorus Depth";
333 case MIDI_CTL_E4_DETUNE_DEPTH
:
334 cc_name
= "E4 Detune Depth";
336 case MIDI_CTL_E5_PHASER_DEPTH
:
337 cc_name
= "E5 Phaser Depth";
339 case MIDI_CTL_DATA_INCREMENT
:
340 cc_name
= "Data Increment";
342 case MIDI_CTL_DATA_DECREMENT
:
343 cc_name
= "Data Decrement";
345 case MIDI_CTL_NONREG_PARM_NUM_LSB
:
346 cc_name
= "Non-registered parameter number";
348 case MIDI_CTL_NONREG_PARM_NUM_MSB
:
349 cc_name
= "Non-registered parameter number";
351 case MIDI_CTL_REGIST_PARM_NUM_LSB
:
352 cc_name
= "Registered parameter number";
354 case MIDI_CTL_REGIST_PARM_NUM_MSB
:
355 cc_name
= "Registered parameter number";
357 case MIDI_CTL_ALL_SOUNDS_OFF
:
358 cc_name
= "All sounds off";
360 case MIDI_CTL_RESET_CONTROLLERS
:
361 cc_name
= "Reset Controllers";
363 case MIDI_CTL_LOCAL_CONTROL_SWITCH
:
364 cc_name
= "Local control switch";
366 case MIDI_CTL_ALL_NOTES_OFF
:
367 cc_name
= "All notes off";
369 case MIDI_CTL_OMNI_OFF
:
370 cc_name
= "Omni off";
372 case MIDI_CTL_OMNI_ON
:
387 "CC %s (%u), value %u",
389 (unsigned int)event_ptr
->data
.control
.param
,
390 (unsigned int)event_ptr
->data
.control
.value
);
397 (unsigned int)event_ptr
->data
.control
.param
,
398 (unsigned int)event_ptr
->data
.control
.value
);
401 case SND_SEQ_EVENT_PGMCHANGE
:
404 "Program change, %d (%s)",
405 (unsigned int)event_ptr
->data
.control
.value
,
406 event_ptr
->data
.control
.value
> 127 || event_ptr
->data
.control
.value
< 0 ? "???": gm_get_instrument_name(event_ptr
->data
.control
.value
));
408 case SND_SEQ_EVENT_CHANPRESS
:
409 g_string_printf(msg_str_ptr
, "Channel pressure");
411 case SND_SEQ_EVENT_PITCHBEND
:
415 (signed int)event_ptr
->data
.control
.value
);
417 case SND_SEQ_EVENT_CONTROL14
:
418 g_string_printf(msg_str_ptr
, "14 bit controller value");
420 case SND_SEQ_EVENT_NONREGPARAM
:
421 g_string_printf(msg_str_ptr
, "NRPN");
423 case SND_SEQ_EVENT_REGPARAM
:
424 g_string_printf(msg_str_ptr
, "RPN");
426 case SND_SEQ_EVENT_SONGPOS
:
427 g_string_printf(msg_str_ptr
, "Song position");
429 case SND_SEQ_EVENT_SONGSEL
:
430 g_string_printf(msg_str_ptr
, "Song select");
432 case SND_SEQ_EVENT_QFRAME
:
433 g_string_printf(msg_str_ptr
, "midi time code quarter frame");
435 case SND_SEQ_EVENT_TIMESIGN
:
436 g_string_printf(msg_str_ptr
, "SMF Time Signature event");
438 case SND_SEQ_EVENT_KEYSIGN
:
439 g_string_printf(msg_str_ptr
, "SMF Key Signature event");
441 case SND_SEQ_EVENT_START
:
442 g_string_printf(msg_str_ptr
, "MIDI Real Time Start message");
444 case SND_SEQ_EVENT_CONTINUE
:
445 g_string_printf(msg_str_ptr
, "MIDI Real Time Continue message");
447 case SND_SEQ_EVENT_STOP
:
448 g_string_printf(msg_str_ptr
, "MIDI Real Time Stop message");
450 case SND_SEQ_EVENT_SETPOS_TICK
:
451 g_string_printf(msg_str_ptr
, "Set tick queue position");
453 case SND_SEQ_EVENT_SETPOS_TIME
:
454 g_string_printf(msg_str_ptr
, "Set real-time queue position");
456 case SND_SEQ_EVENT_TEMPO
:
457 g_string_printf(msg_str_ptr
, "(SMF) Tempo event");
459 case SND_SEQ_EVENT_CLOCK
:
460 g_string_printf(msg_str_ptr
, "MIDI Real Time Clock message");
462 case SND_SEQ_EVENT_TICK
:
463 g_string_printf(msg_str_ptr
, "MIDI Real Time Tick message");
465 case SND_SEQ_EVENT_QUEUE_SKEW
:
466 g_string_printf(msg_str_ptr
, "Queue timer skew");
468 case SND_SEQ_EVENT_SYNC_POS
:
469 g_string_printf(msg_str_ptr
, "Sync position changed");
471 case SND_SEQ_EVENT_TUNE_REQUEST
:
472 g_string_printf(msg_str_ptr
, "Tune request");
474 case SND_SEQ_EVENT_RESET
:
475 g_string_printf(msg_str_ptr
, "Reset");
477 case SND_SEQ_EVENT_SENSING
:
478 continue; /* disable */
479 g_string_printf(msg_str_ptr
, "Active sensing");
481 case SND_SEQ_EVENT_ECHO
:
482 g_string_printf(msg_str_ptr
, "Echo-back event");
484 case SND_SEQ_EVENT_OSS
:
485 g_string_printf(msg_str_ptr
, "OSS emulation raw event");
487 case SND_SEQ_EVENT_CLIENT_START
:
488 g_string_printf(msg_str_ptr
, "New client has connected");
490 case SND_SEQ_EVENT_CLIENT_EXIT
:
491 g_string_printf(msg_str_ptr
, "Client has left the system");
493 case SND_SEQ_EVENT_CLIENT_CHANGE
:
494 g_string_printf(msg_str_ptr
, "Client status/info has changed");
496 case SND_SEQ_EVENT_PORT_START
:
497 g_string_printf(msg_str_ptr
, "New port was created");
499 case SND_SEQ_EVENT_PORT_EXIT
:
500 g_string_printf(msg_str_ptr
, "Port was deleted from system");
502 case SND_SEQ_EVENT_PORT_CHANGE
:
503 g_string_printf(msg_str_ptr
, "Port status/info has changed");
505 case SND_SEQ_EVENT_PORT_SUBSCRIBED
:
506 g_string_printf(msg_str_ptr
, "Port connected");
508 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED
:
509 g_string_printf(msg_str_ptr
, "Port disconnected");
512 case SND_SEQ_EVENT_SAMPLE
:
513 g_string_printf(msg_str_ptr
, "Sample select");
515 case SND_SEQ_EVENT_SAMPLE_CLUSTER
:
516 g_string_printf(msg_str_ptr
, "Sample cluster select");
518 case SND_SEQ_EVENT_SAMPLE_START
:
519 g_string_printf(msg_str_ptr
, "voice start");
521 case SND_SEQ_EVENT_SAMPLE_STOP
:
522 g_string_printf(msg_str_ptr
, "voice stop");
524 case SND_SEQ_EVENT_SAMPLE_FREQ
:
525 g_string_printf(msg_str_ptr
, "playback frequency");
527 case SND_SEQ_EVENT_SAMPLE_VOLUME
:
528 g_string_printf(msg_str_ptr
, "volume and balance");
530 case SND_SEQ_EVENT_SAMPLE_LOOP
:
531 g_string_printf(msg_str_ptr
, "sample loop");
533 case SND_SEQ_EVENT_SAMPLE_POSITION
:
534 g_string_printf(msg_str_ptr
, "sample position");
536 case SND_SEQ_EVENT_SAMPLE_PRIVATE1
:
537 g_string_printf(msg_str_ptr
, "private (hardware dependent) event");
540 case SND_SEQ_EVENT_USR0
:
541 g_string_printf(msg_str_ptr
, "user-defined event");
543 case SND_SEQ_EVENT_USR1
:
544 g_string_printf(msg_str_ptr
, "user-defined event");
546 case SND_SEQ_EVENT_USR2
:
547 g_string_printf(msg_str_ptr
, "user-defined event");
549 case SND_SEQ_EVENT_USR3
:
550 g_string_printf(msg_str_ptr
, "user-defined event");
552 case SND_SEQ_EVENT_USR4
:
553 g_string_printf(msg_str_ptr
, "user-defined event");
555 case SND_SEQ_EVENT_USR5
:
556 g_string_printf(msg_str_ptr
, "user-defined event");
558 case SND_SEQ_EVENT_USR6
:
559 g_string_printf(msg_str_ptr
, "user-defined event");
561 case SND_SEQ_EVENT_USR7
:
562 g_string_printf(msg_str_ptr
, "user-defined event");
564 case SND_SEQ_EVENT_USR8
:
565 g_string_printf(msg_str_ptr
, "user-defined event");
567 case SND_SEQ_EVENT_USR9
:
568 g_string_printf(msg_str_ptr
, "user-defined event");
571 case SND_SEQ_EVENT_INSTR_BEGIN
:
572 g_string_printf(msg_str_ptr
, "begin of instrument management");
574 case SND_SEQ_EVENT_INSTR_END
:
575 g_string_printf(msg_str_ptr
, "end of instrument management");
577 case SND_SEQ_EVENT_INSTR_INFO
:
578 g_string_printf(msg_str_ptr
, "query instrument interface info");
580 case SND_SEQ_EVENT_INSTR_INFO_RESULT
:
581 g_string_printf(msg_str_ptr
, "result of instrument interface info");
583 case SND_SEQ_EVENT_INSTR_FINFO
:
584 g_string_printf(msg_str_ptr
, "query instrument format info");
586 case SND_SEQ_EVENT_INSTR_FINFO_RESULT
:
587 g_string_printf(msg_str_ptr
, "result of instrument format info");
589 case SND_SEQ_EVENT_INSTR_RESET
:
590 g_string_printf(msg_str_ptr
, "reset instrument instrument memory");
592 case SND_SEQ_EVENT_INSTR_STATUS
:
593 g_string_printf(msg_str_ptr
, "get instrument interface status");
595 case SND_SEQ_EVENT_INSTR_STATUS_RESULT
:
596 g_string_printf(msg_str_ptr
, "result of instrument interface status");
598 case SND_SEQ_EVENT_INSTR_PUT
:
599 g_string_printf(msg_str_ptr
, "put an instrument to port");
601 case SND_SEQ_EVENT_INSTR_GET
:
602 g_string_printf(msg_str_ptr
, "get an instrument from port");
604 case SND_SEQ_EVENT_INSTR_GET_RESULT
:
605 g_string_printf(msg_str_ptr
, "result of instrument query");
607 case SND_SEQ_EVENT_INSTR_FREE
:
608 g_string_printf(msg_str_ptr
, "free instrument(s)");
610 case SND_SEQ_EVENT_INSTR_LIST
:
611 g_string_printf(msg_str_ptr
, "get instrument list");
613 case SND_SEQ_EVENT_INSTR_LIST_RESULT
:
614 g_string_printf(msg_str_ptr
, "result of instrument list");
616 case SND_SEQ_EVENT_INSTR_CLUSTER
:
617 g_string_printf(msg_str_ptr
, "set cluster parameters");
619 case SND_SEQ_EVENT_INSTR_CLUSTER_GET
:
620 g_string_printf(msg_str_ptr
, "get cluster parameters");
622 case SND_SEQ_EVENT_INSTR_CLUSTER_RESULT
:
623 g_string_printf(msg_str_ptr
, "result of cluster parameters");
625 case SND_SEQ_EVENT_INSTR_CHANGE
:
626 g_string_printf(msg_str_ptr
, "instrument change");
629 case SND_SEQ_EVENT_SYSEX
:
631 (guint8
*)event_ptr
->data
.ext
.ptr
,
632 event_ptr
->data
.ext
.len
,
635 case SND_SEQ_EVENT_BOUNCE
:
636 g_string_printf(msg_str_ptr
, "error event");
638 case SND_SEQ_EVENT_USR_VAR0
:
639 g_string_printf(msg_str_ptr
, "reserved for user apps");
641 case SND_SEQ_EVENT_USR_VAR1
:
642 g_string_printf(msg_str_ptr
, "reserved for user apps");
644 case SND_SEQ_EVENT_USR_VAR2
:
645 g_string_printf(msg_str_ptr
, "reserved for user apps");
647 case SND_SEQ_EVENT_USR_VAR3
:
648 g_string_printf(msg_str_ptr
, "reserved for user apps");
650 case SND_SEQ_EVENT_USR_VAR4
:
651 g_string_printf(msg_str_ptr
, "reserved for user apps");
655 /* get GTK thread lock */
658 if (g_row_count
>= MAX_LIST_SIZE
)
660 gtk_tree_model_get_iter_first(
661 GTK_TREE_MODEL(list_store_ptr
),
664 gtk_list_store_remove(
669 /* Append an empty row to the list store. Iter will point to the new row */
670 gtk_list_store_append(list_store_ptr
, &iter
);
675 COL_TIME
, time_str_ptr
->str
,
676 COL_CHANNEL
, channel_str_ptr
->str
,
677 COL_MESSAGE
, msg_str_ptr
->str
,
680 gtk_tree_view_scroll_to_cell(
681 GTK_TREE_VIEW(child_ptr
),
682 gtk_tree_model_get_path(
683 gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr
)),
690 /* Force update of scroll position. */
691 /* Is it a bug that it does not update automagically ? */
692 gtk_container_check_resize(GTK_CONTAINER(child_ptr
));
696 /* release GTK thread lock */
699 g_string_free(channel_str_ptr
, TRUE
);
700 g_string_free(msg_str_ptr
, TRUE
);
701 g_string_free(time_str_ptr
, TRUE
);
708 alsa_init(const char * name
)
711 snd_seq_port_info_t
* port_info
= NULL
;
720 g_warning("Cannot open sequncer, %s\n", snd_strerror(ret
));
724 snd_seq_set_client_name(g_seq_ptr
, name
);
727 lash_alsa_client_id(g_lashc
, snd_seq_client_id(g_seq_ptr
));
730 snd_seq_port_info_alloca(&port_info
);
732 snd_seq_port_info_set_capability(
734 SND_SEQ_PORT_CAP_WRITE
|
735 SND_SEQ_PORT_CAP_SUBS_WRITE
);
736 snd_seq_port_info_set_type(
738 SND_SEQ_PORT_TYPE_APPLICATION
);
739 snd_seq_port_info_set_midi_channels(port_info
, 16);
740 snd_seq_port_info_set_port_specified(port_info
, 1);
742 snd_seq_port_info_set_name(port_info
, "midi in");
743 snd_seq_port_info_set_port(port_info
, 0);
745 ret
= snd_seq_create_port(g_seq_ptr
, port_info
);
748 g_warning("Error creating ALSA sequencer port, %s\n", snd_strerror(ret
));
752 /* Start midi thread */
753 ret
= pthread_create(&g_alsa_midi_tid
, NULL
, alsa_midi_thread
, NULL
);
758 ret
= snd_seq_close(g_seq_ptr
);
761 g_warning("Cannot close sequncer, %s\n", snd_strerror(ret
));
773 /* Cancel the thread. Don't know better way.
774 Poll or unblock mechanisms seem to not be
775 available for alsa sequencer */
776 pthread_cancel(g_alsa_midi_tid
);
778 /* Wait midi thread to finish */
779 ret
= pthread_join(g_alsa_midi_tid
, NULL
);
781 ret
= snd_seq_close(g_seq_ptr
);
784 g_warning("Cannot close sequncer, %s\n", snd_strerror(ret
));