1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * This file is part of gmidimonitor
6 * Copyright (C) 2005,2006,2007,2008 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>
33 /* TODO: this must be detected at configure stage */
36 snd_seq_t
* g_seq_ptr
;
37 pthread_t g_alsa_midi_tid
; /* alsa_midi_thread id */
39 /* The ALSA MIDI input handling thread */
41 alsa_midi_thread(void * context_ptr
)
44 snd_seq_event_t
* event_ptr
;
45 GtkListStore
* list_store_ptr
;
46 GtkWidget
* child_ptr
;
47 GString
* time_str_ptr
;
48 GString
* msg_str_ptr
;
49 GString
* channel_str_ptr
;
50 const char * note_name
;
52 const char * drum_name
;
55 child_ptr
= get_glade_widget_child(g_main_window_ptr
, "list");
57 list_store_ptr
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr
)));
59 while (snd_seq_event_input(g_seq_ptr
, &event_ptr
) >= 0)
64 time_str_ptr
= g_string_new("");
68 (unsigned int)event_ptr
->time
.time
.tv_sec
,
69 (unsigned int)event_ptr
->time
.time
.tv_nsec
);
70 channel_str_ptr
= g_string_new("");
72 /* Workaround for compiler warnings... */
77 if (event_ptr
->type
== SND_SEQ_EVENT_NOTE
||
78 event_ptr
->type
== SND_SEQ_EVENT_NOTEON
||
79 event_ptr
->type
== SND_SEQ_EVENT_NOTEOFF
||
80 event_ptr
->type
== SND_SEQ_EVENT_KEYPRESS
)
85 (unsigned int)event_ptr
->data
.note
.channel
+1);
86 if (event_ptr
->data
.note
.channel
+ 1 == 10)
88 drum_name
= gm_get_drum_name(event_ptr
->data
.note
.note
);
95 note_name
= g_note_names
[event_ptr
->data
.note
.note
% 12];
96 octave
= event_ptr
->data
.note
.note
/ 12 - 1;
99 if (event_ptr
->type
== SND_SEQ_EVENT_CONTROLLER
||
100 event_ptr
->type
== SND_SEQ_EVENT_PGMCHANGE
||
101 event_ptr
->type
== SND_SEQ_EVENT_PITCHBEND
)
106 (unsigned int)event_ptr
->data
.control
.channel
+1);
109 msg_str_ptr
= g_string_new("unknown event");
111 switch (event_ptr
->type
)
113 case SND_SEQ_EVENT_SYSTEM
:
114 g_string_sprintf(msg_str_ptr
, "System event");
116 case SND_SEQ_EVENT_RESULT
:
117 g_string_sprintf(msg_str_ptr
, "Result status event");
119 case SND_SEQ_EVENT_NOTE
:
120 g_string_sprintf(msg_str_ptr
, "Note");
122 case SND_SEQ_EVENT_NOTEON
:
123 if (event_ptr
->data
.note
.velocity
!= 0)
125 if (drum_name
!= NULL
)
129 "Drum: %s (%s, octave %d, velocity %u)",
133 event_ptr
->data
.note
.velocity
);
139 "Note on, %s, octave %d, velocity %u",
142 event_ptr
->data
.note
.velocity
);
146 case SND_SEQ_EVENT_NOTEOFF
:
147 if (drum_name
!= NULL
) /* ignore note off for drums */
152 "Note off, %s, octave %d",
157 case SND_SEQ_EVENT_KEYPRESS
:
158 g_string_sprintf(msg_str_ptr
, "Key pressure change (aftertouch)");
160 case SND_SEQ_EVENT_CONTROLLER
:
162 switch (event_ptr
->data
.control
.param
)
164 case MIDI_CTL_MSB_BANK
:
165 cc_name
= "Bank selection";
167 case MIDI_CTL_MSB_MODWHEEL
:
168 cc_name
= "Modulation";
170 case MIDI_CTL_MSB_BREATH
:
173 case MIDI_CTL_MSB_FOOT
:
176 case MIDI_CTL_MSB_PORTAMENTO_TIME
:
177 cc_name
= "Portamento time";
179 case MIDI_CTL_MSB_DATA_ENTRY
:
180 cc_name
= "Data entry";
182 case MIDI_CTL_MSB_MAIN_VOLUME
:
183 cc_name
= "Main volume";
185 case MIDI_CTL_MSB_BALANCE
:
188 case MIDI_CTL_MSB_PAN
:
191 case MIDI_CTL_MSB_EXPRESSION
:
192 cc_name
= "Expression";
194 case MIDI_CTL_MSB_EFFECT1
:
197 case MIDI_CTL_MSB_EFFECT2
:
200 case MIDI_CTL_MSB_GENERAL_PURPOSE1
:
201 cc_name
= "General purpose 1";
203 case MIDI_CTL_MSB_GENERAL_PURPOSE2
:
204 cc_name
= "General purpose 2";
206 case MIDI_CTL_MSB_GENERAL_PURPOSE3
:
207 cc_name
= "General purpose 3";
209 case MIDI_CTL_MSB_GENERAL_PURPOSE4
:
210 cc_name
= "General purpose 4";
212 case MIDI_CTL_LSB_BANK
:
213 cc_name
= "Bank selection";
215 case MIDI_CTL_LSB_MODWHEEL
:
216 cc_name
= "Modulation";
218 case MIDI_CTL_LSB_BREATH
:
221 case MIDI_CTL_LSB_FOOT
:
224 case MIDI_CTL_LSB_PORTAMENTO_TIME
:
225 cc_name
= "Portamento time";
227 case MIDI_CTL_LSB_DATA_ENTRY
:
228 cc_name
= "Data entry";
230 case MIDI_CTL_LSB_MAIN_VOLUME
:
231 cc_name
= "Main volume";
233 case MIDI_CTL_LSB_BALANCE
:
236 case MIDI_CTL_LSB_PAN
:
239 case MIDI_CTL_LSB_EXPRESSION
:
240 cc_name
= "Expression";
242 case MIDI_CTL_LSB_EFFECT1
:
245 case MIDI_CTL_LSB_EFFECT2
:
248 case MIDI_CTL_LSB_GENERAL_PURPOSE1
:
249 cc_name
= "General purpose 1";
251 case MIDI_CTL_LSB_GENERAL_PURPOSE2
:
252 cc_name
= "General purpose 2";
254 case MIDI_CTL_LSB_GENERAL_PURPOSE3
:
255 cc_name
= "General purpose 3";
257 case MIDI_CTL_LSB_GENERAL_PURPOSE4
:
258 cc_name
= "General purpose 4";
260 case MIDI_CTL_SUSTAIN
:
261 cc_name
= "Sustain pedal";
263 case MIDI_CTL_PORTAMENTO
:
264 cc_name
= "Portamento";
266 case MIDI_CTL_SOSTENUTO
:
267 cc_name
= "Sostenuto";
269 case MIDI_CTL_SOFT_PEDAL
:
270 cc_name
= "Soft pedal";
272 case MIDI_CTL_LEGATO_FOOTSWITCH
:
273 cc_name
= "Legato foot switch";
278 case MIDI_CTL_SC1_SOUND_VARIATION
:
279 cc_name
= "SC1 Sound Variation";
281 case MIDI_CTL_SC2_TIMBRE
:
282 cc_name
= "SC2 Timbre";
284 case MIDI_CTL_SC3_RELEASE_TIME
:
285 cc_name
= "SC3 Release Time";
287 case MIDI_CTL_SC4_ATTACK_TIME
:
288 cc_name
= "SC4 Attack Time";
290 case MIDI_CTL_SC5_BRIGHTNESS
:
291 cc_name
= "SC5 Brightness";
308 case MIDI_CTL_GENERAL_PURPOSE5
:
309 cc_name
= "General purpose 5";
311 case MIDI_CTL_GENERAL_PURPOSE6
:
312 cc_name
= "General purpose 6";
314 case MIDI_CTL_GENERAL_PURPOSE7
:
315 cc_name
= "General purpose 7";
317 case MIDI_CTL_GENERAL_PURPOSE8
:
318 cc_name
= "General purpose 8";
320 case MIDI_CTL_PORTAMENTO_CONTROL
:
321 cc_name
= "Portamento control";
323 case MIDI_CTL_E1_REVERB_DEPTH
:
324 cc_name
= "E1 Reverb Depth";
326 case MIDI_CTL_E2_TREMOLO_DEPTH
:
327 cc_name
= "E2 Tremolo Depth";
329 case MIDI_CTL_E3_CHORUS_DEPTH
:
330 cc_name
= "E3 Chorus Depth";
332 case MIDI_CTL_E4_DETUNE_DEPTH
:
333 cc_name
= "E4 Detune Depth";
335 case MIDI_CTL_E5_PHASER_DEPTH
:
336 cc_name
= "E5 Phaser Depth";
338 case MIDI_CTL_DATA_INCREMENT
:
339 cc_name
= "Data Increment";
341 case MIDI_CTL_DATA_DECREMENT
:
342 cc_name
= "Data Decrement";
344 case MIDI_CTL_NONREG_PARM_NUM_LSB
:
345 cc_name
= "Non-registered parameter number";
347 case MIDI_CTL_NONREG_PARM_NUM_MSB
:
348 cc_name
= "Non-registered parameter number";
350 case MIDI_CTL_REGIST_PARM_NUM_LSB
:
351 cc_name
= "Registered parameter number";
353 case MIDI_CTL_REGIST_PARM_NUM_MSB
:
354 cc_name
= "Registered parameter number";
356 case MIDI_CTL_ALL_SOUNDS_OFF
:
357 cc_name
= "All sounds off";
359 case MIDI_CTL_RESET_CONTROLLERS
:
360 cc_name
= "Reset Controllers";
362 case MIDI_CTL_LOCAL_CONTROL_SWITCH
:
363 cc_name
= "Local control switch";
365 case MIDI_CTL_ALL_NOTES_OFF
:
366 cc_name
= "All notes off";
368 case MIDI_CTL_OMNI_OFF
:
369 cc_name
= "Omni off";
371 case MIDI_CTL_OMNI_ON
:
386 "CC %s (%u), value %u",
388 (unsigned int)event_ptr
->data
.control
.param
,
389 (unsigned int)event_ptr
->data
.control
.value
);
396 (unsigned int)event_ptr
->data
.control
.param
,
397 (unsigned int)event_ptr
->data
.control
.value
);
400 case SND_SEQ_EVENT_PGMCHANGE
:
403 "Program change, %d (%s)",
404 (unsigned int)event_ptr
->data
.control
.value
,
405 event_ptr
->data
.control
.value
> 127 || event_ptr
->data
.control
.value
< 0 ? "???": gm_get_instrument_name(event_ptr
->data
.control
.value
));
407 case SND_SEQ_EVENT_CHANPRESS
:
408 g_string_sprintf(msg_str_ptr
, "Channel pressure");
410 case SND_SEQ_EVENT_PITCHBEND
:
414 (signed int)event_ptr
->data
.control
.value
);
416 case SND_SEQ_EVENT_CONTROL14
:
417 g_string_sprintf(msg_str_ptr
, "14 bit controller value");
419 case SND_SEQ_EVENT_NONREGPARAM
:
420 g_string_sprintf(msg_str_ptr
, "NRPN");
422 case SND_SEQ_EVENT_REGPARAM
:
423 g_string_sprintf(msg_str_ptr
, "RPN");
425 case SND_SEQ_EVENT_SONGPOS
:
426 g_string_sprintf(msg_str_ptr
, "Song position");
428 case SND_SEQ_EVENT_SONGSEL
:
429 g_string_sprintf(msg_str_ptr
, "Song select");
431 case SND_SEQ_EVENT_QFRAME
:
432 g_string_sprintf(msg_str_ptr
, "midi time code quarter frame");
434 case SND_SEQ_EVENT_TIMESIGN
:
435 g_string_sprintf(msg_str_ptr
, "SMF Time Signature event");
437 case SND_SEQ_EVENT_KEYSIGN
:
438 g_string_sprintf(msg_str_ptr
, "SMF Key Signature event");
440 case SND_SEQ_EVENT_START
:
441 g_string_sprintf(msg_str_ptr
, "MIDI Real Time Start message");
443 case SND_SEQ_EVENT_CONTINUE
:
444 g_string_sprintf(msg_str_ptr
, "MIDI Real Time Continue message");
446 case SND_SEQ_EVENT_STOP
:
447 g_string_sprintf(msg_str_ptr
, "MIDI Real Time Stop message");
449 case SND_SEQ_EVENT_SETPOS_TICK
:
450 g_string_sprintf(msg_str_ptr
, "Set tick queue position");
452 case SND_SEQ_EVENT_SETPOS_TIME
:
453 g_string_sprintf(msg_str_ptr
, "Set real-time queue position");
455 case SND_SEQ_EVENT_TEMPO
:
456 g_string_sprintf(msg_str_ptr
, "(SMF) Tempo event");
458 case SND_SEQ_EVENT_CLOCK
:
459 g_string_sprintf(msg_str_ptr
, "MIDI Real Time Clock message");
461 case SND_SEQ_EVENT_TICK
:
462 g_string_sprintf(msg_str_ptr
, "MIDI Real Time Tick message");
464 case SND_SEQ_EVENT_QUEUE_SKEW
:
465 g_string_sprintf(msg_str_ptr
, "Queue timer skew");
467 case SND_SEQ_EVENT_SYNC_POS
:
468 g_string_sprintf(msg_str_ptr
, "Sync position changed");
470 case SND_SEQ_EVENT_TUNE_REQUEST
:
471 g_string_sprintf(msg_str_ptr
, "Tune request");
473 case SND_SEQ_EVENT_RESET
:
474 g_string_sprintf(msg_str_ptr
, "Reset");
476 case SND_SEQ_EVENT_SENSING
:
477 continue; /* disable */
478 g_string_sprintf(msg_str_ptr
, "Active sensing");
480 case SND_SEQ_EVENT_ECHO
:
481 g_string_sprintf(msg_str_ptr
, "Echo-back event");
483 case SND_SEQ_EVENT_OSS
:
484 g_string_sprintf(msg_str_ptr
, "OSS emulation raw event");
486 case SND_SEQ_EVENT_CLIENT_START
:
487 g_string_sprintf(msg_str_ptr
, "New client has connected");
489 case SND_SEQ_EVENT_CLIENT_EXIT
:
490 g_string_sprintf(msg_str_ptr
, "Client has left the system");
492 case SND_SEQ_EVENT_CLIENT_CHANGE
:
493 g_string_sprintf(msg_str_ptr
, "Client status/info has changed");
495 case SND_SEQ_EVENT_PORT_START
:
496 g_string_sprintf(msg_str_ptr
, "New port was created");
498 case SND_SEQ_EVENT_PORT_EXIT
:
499 g_string_sprintf(msg_str_ptr
, "Port was deleted from system");
501 case SND_SEQ_EVENT_PORT_CHANGE
:
502 g_string_sprintf(msg_str_ptr
, "Port status/info has changed");
504 case SND_SEQ_EVENT_PORT_SUBSCRIBED
:
505 g_string_sprintf(msg_str_ptr
, "Port connected");
507 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED
:
508 g_string_sprintf(msg_str_ptr
, "Port disconnected");
511 case SND_SEQ_EVENT_SAMPLE
:
512 g_string_sprintf(msg_str_ptr
, "Sample select");
514 case SND_SEQ_EVENT_SAMPLE_CLUSTER
:
515 g_string_sprintf(msg_str_ptr
, "Sample cluster select");
517 case SND_SEQ_EVENT_SAMPLE_START
:
518 g_string_sprintf(msg_str_ptr
, "voice start");
520 case SND_SEQ_EVENT_SAMPLE_STOP
:
521 g_string_sprintf(msg_str_ptr
, "voice stop");
523 case SND_SEQ_EVENT_SAMPLE_FREQ
:
524 g_string_sprintf(msg_str_ptr
, "playback frequency");
526 case SND_SEQ_EVENT_SAMPLE_VOLUME
:
527 g_string_sprintf(msg_str_ptr
, "volume and balance");
529 case SND_SEQ_EVENT_SAMPLE_LOOP
:
530 g_string_sprintf(msg_str_ptr
, "sample loop");
532 case SND_SEQ_EVENT_SAMPLE_POSITION
:
533 g_string_sprintf(msg_str_ptr
, "sample position");
535 case SND_SEQ_EVENT_SAMPLE_PRIVATE1
:
536 g_string_sprintf(msg_str_ptr
, "private (hardware dependent) event");
539 case SND_SEQ_EVENT_USR0
:
540 g_string_sprintf(msg_str_ptr
, "user-defined event");
542 case SND_SEQ_EVENT_USR1
:
543 g_string_sprintf(msg_str_ptr
, "user-defined event");
545 case SND_SEQ_EVENT_USR2
:
546 g_string_sprintf(msg_str_ptr
, "user-defined event");
548 case SND_SEQ_EVENT_USR3
:
549 g_string_sprintf(msg_str_ptr
, "user-defined event");
551 case SND_SEQ_EVENT_USR4
:
552 g_string_sprintf(msg_str_ptr
, "user-defined event");
554 case SND_SEQ_EVENT_USR5
:
555 g_string_sprintf(msg_str_ptr
, "user-defined event");
557 case SND_SEQ_EVENT_USR6
:
558 g_string_sprintf(msg_str_ptr
, "user-defined event");
560 case SND_SEQ_EVENT_USR7
:
561 g_string_sprintf(msg_str_ptr
, "user-defined event");
563 case SND_SEQ_EVENT_USR8
:
564 g_string_sprintf(msg_str_ptr
, "user-defined event");
566 case SND_SEQ_EVENT_USR9
:
567 g_string_sprintf(msg_str_ptr
, "user-defined event");
570 case SND_SEQ_EVENT_INSTR_BEGIN
:
571 g_string_sprintf(msg_str_ptr
, "begin of instrument management");
573 case SND_SEQ_EVENT_INSTR_END
:
574 g_string_sprintf(msg_str_ptr
, "end of instrument management");
576 case SND_SEQ_EVENT_INSTR_INFO
:
577 g_string_sprintf(msg_str_ptr
, "query instrument interface info");
579 case SND_SEQ_EVENT_INSTR_INFO_RESULT
:
580 g_string_sprintf(msg_str_ptr
, "result of instrument interface info");
582 case SND_SEQ_EVENT_INSTR_FINFO
:
583 g_string_sprintf(msg_str_ptr
, "query instrument format info");
585 case SND_SEQ_EVENT_INSTR_FINFO_RESULT
:
586 g_string_sprintf(msg_str_ptr
, "result of instrument format info");
588 case SND_SEQ_EVENT_INSTR_RESET
:
589 g_string_sprintf(msg_str_ptr
, "reset instrument instrument memory");
591 case SND_SEQ_EVENT_INSTR_STATUS
:
592 g_string_sprintf(msg_str_ptr
, "get instrument interface status");
594 case SND_SEQ_EVENT_INSTR_STATUS_RESULT
:
595 g_string_sprintf(msg_str_ptr
, "result of instrument interface status");
597 case SND_SEQ_EVENT_INSTR_PUT
:
598 g_string_sprintf(msg_str_ptr
, "put an instrument to port");
600 case SND_SEQ_EVENT_INSTR_GET
:
601 g_string_sprintf(msg_str_ptr
, "get an instrument from port");
603 case SND_SEQ_EVENT_INSTR_GET_RESULT
:
604 g_string_sprintf(msg_str_ptr
, "result of instrument query");
606 case SND_SEQ_EVENT_INSTR_FREE
:
607 g_string_sprintf(msg_str_ptr
, "free instrument(s)");
609 case SND_SEQ_EVENT_INSTR_LIST
:
610 g_string_sprintf(msg_str_ptr
, "get instrument list");
612 case SND_SEQ_EVENT_INSTR_LIST_RESULT
:
613 g_string_sprintf(msg_str_ptr
, "result of instrument list");
615 case SND_SEQ_EVENT_INSTR_CLUSTER
:
616 g_string_sprintf(msg_str_ptr
, "set cluster parameters");
618 case SND_SEQ_EVENT_INSTR_CLUSTER_GET
:
619 g_string_sprintf(msg_str_ptr
, "get cluster parameters");
621 case SND_SEQ_EVENT_INSTR_CLUSTER_RESULT
:
622 g_string_sprintf(msg_str_ptr
, "result of cluster parameters");
624 case SND_SEQ_EVENT_INSTR_CHANGE
:
625 g_string_sprintf(msg_str_ptr
, "instrument change");
628 case SND_SEQ_EVENT_SYSEX
:
630 (guint8
*)event_ptr
->data
.ext
.ptr
,
631 event_ptr
->data
.ext
.len
,
634 case SND_SEQ_EVENT_BOUNCE
:
635 g_string_sprintf(msg_str_ptr
, "error event");
637 case SND_SEQ_EVENT_USR_VAR0
:
638 g_string_sprintf(msg_str_ptr
, "reserved for user apps");
640 case SND_SEQ_EVENT_USR_VAR1
:
641 g_string_sprintf(msg_str_ptr
, "reserved for user apps");
643 case SND_SEQ_EVENT_USR_VAR2
:
644 g_string_sprintf(msg_str_ptr
, "reserved for user apps");
646 case SND_SEQ_EVENT_USR_VAR3
:
647 g_string_sprintf(msg_str_ptr
, "reserved for user apps");
649 case SND_SEQ_EVENT_USR_VAR4
:
650 g_string_sprintf(msg_str_ptr
, "reserved for user apps");
654 /* get GTK thread lock */
657 if (g_row_count
>= MAX_LIST_SIZE
)
659 gtk_tree_model_get_iter_first(
660 GTK_TREE_MODEL(list_store_ptr
),
663 gtk_list_store_remove(
668 /* Append an empty row to the list store. Iter will point to the new row */
669 gtk_list_store_append(list_store_ptr
, &iter
);
674 COL_TIME
, time_str_ptr
->str
,
675 COL_CHANNEL
, channel_str_ptr
->str
,
676 COL_MESSAGE
, msg_str_ptr
->str
,
679 gtk_tree_view_scroll_to_cell(
680 GTK_TREE_VIEW(child_ptr
),
681 gtk_tree_model_get_path(
682 gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr
)),
689 /* Force update of scroll position. */
690 /* Is it a bug that it does not update automagically ? */
691 gtk_container_check_resize(GTK_CONTAINER(child_ptr
));
695 /* release GTK thread lock */
698 g_string_free(channel_str_ptr
, TRUE
);
699 g_string_free(msg_str_ptr
, TRUE
);
700 g_string_free(time_str_ptr
, TRUE
);
707 alsa_init(const char * name
)
710 snd_seq_port_info_t
* port_info
= NULL
;
719 g_warning("Cannot open sequncer, %s\n", snd_strerror(ret
));
723 snd_seq_set_client_name(g_seq_ptr
, name
);
726 lash_alsa_client_id(g_lashc
, snd_seq_client_id(g_seq_ptr
));
729 snd_seq_port_info_alloca(&port_info
);
731 snd_seq_port_info_set_capability(
733 SND_SEQ_PORT_CAP_WRITE
|
734 SND_SEQ_PORT_CAP_SUBS_WRITE
);
735 snd_seq_port_info_set_type(
737 SND_SEQ_PORT_TYPE_APPLICATION
);
738 snd_seq_port_info_set_midi_channels(port_info
, 16);
739 snd_seq_port_info_set_port_specified(port_info
, 1);
741 snd_seq_port_info_set_name(port_info
, "midi in");
742 snd_seq_port_info_set_port(port_info
, 0);
744 ret
= snd_seq_create_port(g_seq_ptr
, port_info
);
747 g_warning("Error creating ALSA sequencer port, %s\n", snd_strerror(ret
));
751 /* Start midi thread */
752 ret
= pthread_create(&g_alsa_midi_tid
, NULL
, alsa_midi_thread
, NULL
);
757 ret
= snd_seq_close(g_seq_ptr
);
760 g_warning("Cannot close sequncer, %s\n", snd_strerror(ret
));
772 /* Cancel the thread. Don't know better way.
773 Poll or unblock mechanisms seem to not be
774 available for alsa sequencer */
775 pthread_cancel(g_alsa_midi_tid
);
777 /* Wait midi thread to finish */
778 ret
= pthread_join(g_alsa_midi_tid
, NULL
);
780 ret
= snd_seq_close(g_seq_ptr
);
783 g_warning("Cannot close sequncer, %s\n", snd_strerror(ret
));