]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Added sequencer test program..
authorJaroslav Kysela <perex@perex.cz>
Sun, 27 Dec 1998 01:02:59 +0000 (01:02 +0000)
committerJaroslav Kysela <perex@perex.cz>
Sun, 27 Dec 1998 01:02:59 +0000 (01:02 +0000)
test/Makefile.am
test/seq-decoder.c [new file with mode: 0644]
test/seq-sender.c [new file with mode: 0644]
test/seq.c [new file with mode: 0644]

index dcfa12044f1680464d5bdf94f179d323c323120a..e48bb0d876a130a076e5cba6c0bcd0d69b58ae97 100644 (file)
@@ -1,4 +1,4 @@
-check_PROGRAMS=control mixer switches pause pcm latency
+check_PROGRAMS=control mixer switches pause pcm latency seq
 
 control_LDADD=../src/libasound.la
 mixer_LDADD=../src/libasound.la
@@ -6,6 +6,8 @@ switches_LDADD=../src/libasound.la
 pause_LDADD=../src/libasound.la
 pcm_LDADD=../src/libasound.la
 latency_LDADD=../src/libasound.la
-
+seq_LDADD=../src/libasound.la
 
 INCLUDES=-I$(top_srcdir)/include
+CFLAGS=-static -Wall -pipe -g
+
diff --git a/test/seq-decoder.c b/test/seq-decoder.c
new file mode 100644 (file)
index 0000000..05e5abc
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ *  Simple event decoder
+ */
+
+static char *event_names[256] = {
+       /* 0   */       "System",
+       /* 1   */       "Note",
+       /* 2   */       "Note On",
+       /* 3   */       "Note Off",
+       /* 4   */       "Reserved 4",
+       /* 5   */       "Reserved 5",
+       /* 6   */       "Reserved 6",
+       /* 7   */       "Reserved 7",
+       /* 8   */       "Reserved 8",
+       /* 9   */       "Reserved 9",
+       /* 10   */      "KeyPress",
+       /* 11   */      "Controller",
+       /* 12   */      "Program Change",
+       /* 13   */      "Channel Pressure",
+       /* 14   */      "Pitchbend",
+       /* 15   */      "Control14",
+       /* 16   */      "Nonregparam",
+       /* 17   */      "Regparam",
+       /* 18   */      "Reserved 18",
+       /* 19   */      "Reserved 19",
+       /* 20   */      "Song Position",
+       /* 21   */      "Song Select",
+       /* 22   */      "Clock",
+       /* 23   */      "Start",
+       /* 24   */      "Continue",
+       /* 25   */      "Stop",
+       /* 26   */      "Qframe",
+       /* 27   */      "Reserved 27",
+       /* 28   */      "Reserved 28",
+       /* 29   */      "Reserved 29",
+       /* 30   */      "Tempo",
+       /* 31   */      "SMF Time Signature",
+       /* 32   */      "SMF Key Signature",
+       /* 33   */      "Reserved 33",
+       /* 34   */      "Reserved 34",
+       /* 35   */      "Reserved 35",
+       /* 36   */      "Reserved 36",
+       /* 37   */      "Reserved 37",
+       /* 38   */      "Reserved 38",
+       /* 39   */      "Reserved 39",
+       /* 40   */      "System Exclusive",
+       /* 41   */      "Heart Beat",
+       /* 42   */      "Reserved 42",
+       /* 43   */      "Reserved 43",
+       /* 44   */      "Reserved 44",
+       /* 45   */      "Reserved 45",
+       /* 46   */      "Reserved 46",
+       /* 47   */      "Reserved 47",
+       /* 48   */      "Reserved 48",
+       /* 49   */      "Reserved 49",
+       /* 50   */      "Heart Beat (Active sensing)",
+       /* 51   */      "Echo",
+       /* 52   */      "Reserved 52",
+       /* 53   */      "Reserved 53",
+       /* 54   */      "Reserved 54",
+       /* 55   */      "Reserved 55",
+       /* 56   */      "Reserved 56",
+       /* 57   */      "Reserved 57",
+       /* 58   */      "Reserved 58",
+       /* 59   */      "Reserved 59",
+       /* 60   */      "Client Start",
+       /* 61   */      "Client Exit",
+       /* 62   */      "Client Change",
+       /* 63   */      "Port Start",
+       /* 64   */      "Port Exit",
+       /* 65   */      "Port Change",
+       /* 66   */      "Reserved 66",
+       /* 67   */      "Reserved 67",
+       /* 68   */      "Reserved 68",
+       /* 69   */      "Reserved 69",
+       /* 70   */      "Reserved 70",
+       /* 71   */      "Reserved 71",
+       /* 72   */      "Reserved 72",
+       /* 73   */      "Reserved 73",
+       /* 74   */      "Reserved 74",
+       /* 75   */      "Reserved 75",
+       /* 76   */      "Reserved 76",
+       /* 77   */      "Reserved 77",
+       /* 78   */      "Reserved 78",
+       /* 79   */      "Reserved 79",
+       /* 80   */      "Sample Select",
+       /* 81   */      "Sample Start",
+       /* 82   */      "Sample Stop",
+       /* 83   */      "Sample Frequency",
+       /* 84   */      "Sample Volume",
+       /* 85   */      "Sample Loop",
+       /* 86   */      "Sample Position",
+       /* 87   */      "Reseved 87",
+       /* 88   */      "Reseved 88",
+       /* 89   */      "Reseved 89",
+       /* 90   */      "Reseved 90",
+       /* 91   */      "Reseved 91",
+       /* 92   */      "Reseved 92",
+       /* 93   */      "Reseved 93",
+       /* 94   */      "Reseved 94",
+       /* 95   */      "Reseved 95",
+       /* 96   */      "Reseved 96",
+       /* 97   */      "Reseved 97",
+       /* 98   */      "Reseved 98",
+       /* 99   */      "Reseved 99",
+       /* 100  */      "Reseved 100",
+       /* 101  */      "Reseved 101",
+       /* 102  */      "Reseved 102",
+       /* 103  */      "Reseved 103",
+       /* 104  */      "Reseved 104",
+       /* 105  */      "Reseved 105",
+       /* 106  */      "Reseved 106",
+       /* 107  */      "Reseved 107",
+       /* 108  */      "Reseved 108",
+       /* 109  */      "Reseved 109",
+       /* 100  */      "Reserved 100"
+       /* 101  */      "Reserved 101"
+       /* 102  */      "Reserved 102"
+       /* 103  */      "Reserved 103"
+       /* 104  */      "Reserved 104"
+       /* 105  */      "Reserved 105"
+       /* 106  */      "Reserved 106"
+       /* 107  */      "Reserved 107"
+       /* 108  */      "Reserved 108"
+       /* 109  */      "Reserved 109"
+       /* 110  */      "Reserved 110"
+       /* 111  */      "Reserved 111"
+       /* 112  */      "Reserved 112"
+       /* 113  */      "Reserved 113"
+       /* 114  */      "Reserved 114"
+       /* 115  */      "Reserved 115"
+       /* 116  */      "Reserved 116"
+       /* 117  */      "Reserved 117"
+       /* 118  */      "Reserved 118"
+       /* 119  */      "Reserved 119"
+       /* 120  */      "Reserved 120"
+       /* 121  */      "Reserved 121"
+       /* 122  */      "Reserved 122"
+       /* 123  */      "Reserved 123"
+       /* 124  */      "Reserved 124"
+       /* 125  */      "Reserved 125"
+       /* 126  */      "Reserved 126"
+       /* 127  */      "Reserved 127"
+       /* 128  */      "Reserved 128"
+       /* 129  */      "Reserved 129"
+       /* 130  */      "Reserved 130"
+       /* 131  */      "Reserved 131"
+       /* 132  */      "Reserved 132"
+       /* 133  */      "Reserved 133"
+       /* 134  */      "Reserved 134"
+       /* 135  */      "Reserved 135"
+       /* 136  */      "Reserved 136"
+       /* 137  */      "Reserved 137"
+       /* 138  */      "Reserved 138"
+       /* 139  */      "Reserved 139"
+       /* 140  */      "Reserved 140"
+       /* 141  */      "Reserved 141"
+       /* 142  */      "Reserved 142"
+       /* 143  */      "Reserved 143"
+       /* 144  */      "Reserved 144"
+       /* 145  */      "Reserved 145"
+       /* 146  */      "Reserved 146"
+       /* 147  */      "Reserved 147"
+       /* 148  */      "Reserved 148"
+       /* 149  */      "Reserved 149"
+       /* 150  */      "Reserved 150"
+       /* 151  */      "Reserved 151"
+       /* 152  */      "Reserved 152"
+       /* 153  */      "Reserved 153"
+       /* 154  */      "Reserved 154"
+       /* 155  */      "Reserved 155"
+       /* 156  */      "Reserved 156"
+       /* 157  */      "Reserved 157"
+       /* 158  */      "Reserved 158"
+       /* 159  */      "Reserved 159"
+       /* 160  */      "Reserved 160"
+       /* 161  */      "Reserved 161"
+       /* 162  */      "Reserved 162"
+       /* 163  */      "Reserved 163"
+       /* 164  */      "Reserved 164"
+       /* 165  */      "Reserved 165"
+       /* 166  */      "Reserved 166"
+       /* 167  */      "Reserved 167"
+       /* 168  */      "Reserved 168"
+       /* 169  */      "Reserved 169"
+       /* 170  */      "Reserved 170"
+       /* 171  */      "Reserved 171"
+       /* 172  */      "Reserved 172"
+       /* 173  */      "Reserved 173"
+       /* 174  */      "Reserved 174"
+       /* 175  */      "Reserved 175"
+       /* 176  */      "Reserved 176"
+       /* 177  */      "Reserved 177"
+       /* 178  */      "Reserved 178"
+       /* 179  */      "Reserved 179"
+       /* 180  */      "Reserved 180"
+       /* 181  */      "Reserved 181"
+       /* 182  */      "Reserved 182"
+       /* 183  */      "Reserved 183"
+       /* 184  */      "Reserved 184"
+       /* 185  */      "Reserved 185"
+       /* 186  */      "Reserved 186"
+       /* 187  */      "Reserved 187"
+       /* 188  */      "Reserved 188"
+       /* 189  */      "Reserved 189"
+       /* 190  */      "Reserved 190"
+       /* 191  */      "Reserved 191"
+       /* 192  */      "Reserved 192"
+       /* 193  */      "Reserved 193"
+       /* 194  */      "Reserved 194"
+       /* 195  */      "Reserved 195"
+       /* 196  */      "Reserved 196"
+       /* 197  */      "Reserved 197"
+       /* 198  */      "Reserved 198"
+       /* 199  */      "Reserved 199"
+       /* 200  */      "Reserved 200"
+       /* 201  */      "Reserved 201"
+       /* 202  */      "Reserved 202"
+       /* 203  */      "Reserved 203"
+       /* 204  */      "Reserved 204"
+       /* 205  */      "Reserved 205"
+       /* 206  */      "Reserved 206"
+       /* 207  */      "Reserved 207"
+       /* 208  */      "Reserved 208"
+       /* 209  */      "Reserved 209"
+       /* 210  */      "Reserved 210"
+       /* 211  */      "Reserved 211"
+       /* 212  */      "Reserved 212"
+       /* 213  */      "Reserved 213"
+       /* 214  */      "Reserved 214"
+       /* 215  */      "Reserved 215"
+       /* 216  */      "Reserved 216"
+       /* 217  */      "Reserved 217"
+       /* 218  */      "Reserved 218"
+       /* 219  */      "Reserved 219"
+       /* 220  */      "Reserved 220"
+       /* 221  */      "Reserved 221"
+       /* 222  */      "Reserved 222"
+       /* 223  */      "Reserved 223"
+       /* 224  */      "Reserved 224"
+       /* 225  */      "Reserved 225"
+       /* 226  */      "Reserved 226"
+       /* 227  */      "Reserved 227"
+       /* 228  */      "Reserved 228"
+       /* 229  */      "Reserved 229"
+       /* 230  */      "Reserved 230"
+       /* 231  */      "Reserved 231"
+       /* 232  */      "Reserved 232"
+       /* 233  */      "Reserved 233"
+       /* 234  */      "Reserved 234"
+       /* 235  */      "Reserved 235"
+       /* 236  */      "Reserved 236"
+       /* 237  */      "Reserved 237"
+       /* 238  */      "Reserved 238"
+       /* 239  */      "Reserved 239"
+       /* 240  */      "Reserved 240"
+       /* 241  */      "Reserved 241"
+       /* 242  */      "Reserved 242"
+       /* 243  */      "Reserved 243"
+       /* 244  */      "Reserved 244"
+       /* 245  */      "Reserved 245"
+       /* 246  */      "Reserved 246"
+       /* 247  */      "Reserved 247"
+       /* 248  */      "Reserved 248"
+       /* 249  */      "Reserved 249"
+       /* 250  */      "Reserved 250"
+       /* 251  */      "Reserved 251"
+       /* 252  */      "Reserved 252"
+       /* 253  */      "Reserved 253"
+       /* 254  */      "Reserved 254"
+       /* 255  */      "Reserved 255"
+};
+
+int decode_event(snd_seq_event_t * ev)
+{
+       char *space = "         ";
+
+       printf("EVENT>>> Type = %d, flags = 0x%x", ev->type, ev->flags);
+       switch (ev->flags & SND_SEQ_TIME_STAMP_MASK) {
+               case SND_SEQ_TIME_STAMP_TICK:
+                       printf(", time = %d ticks",
+                              ev->time.tick);
+                       break;
+               case SND_SEQ_TIME_STAMP_REAL:
+                       printf(", time = %d.%09d",
+                              (int)ev->time.real.tv_sec,
+                              (int)ev->time.real.tv_nsec);
+                       break;
+       }
+       printf("\n%sSource = %d.%d.%d.%d, dest = %d.%d.%d.%d\n",
+              space,
+              ev->source.queue,
+              ev->source.client,
+              ev->source.port,
+              ev->source.channel,
+              ev->dest.queue,
+              ev->dest.client,
+              ev->dest.port,
+              ev->dest.channel);
+
+       printf("%sEvent = %s", space, event_names[ev->type]);
+       /* decode actual event data... */
+       switch (ev->type) {
+               case SND_SEQ_EVENT_NOTE:
+                       printf("; note=%d, velocity=%d, duration=%d\n",
+                              ev->data.note.note,
+                              ev->data.note.velocity,
+                              ev->data.note.duration);
+                       break;
+
+               case SND_SEQ_EVENT_NOTEON:
+               case SND_SEQ_EVENT_NOTEOFF:
+                       printf("; note=%d, velocity=%d\n",
+                              ev->data.note.note,
+                              ev->data.note.velocity);
+                       break;
+               
+               case SND_SEQ_EVENT_KEYPRESS:
+               case SND_SEQ_EVENT_CONTROLLER:
+                       printf("; param=%i, value=%i\n",
+                               ev->data.control.param,
+                               ev->data.control.value);
+                       break;
+
+               case SND_SEQ_EVENT_PGMCHANGE:
+                       printf("; program=%i\n", ev->data.control.value);
+                       break;
+                       
+               case SND_SEQ_EVENT_CHANPRESS:
+               case SND_SEQ_EVENT_PITCHBEND:
+                       printf("; value=%i\n", ev->data.control.value);
+                       break;
+                       
+               case SND_SEQ_EVENT_SYSEX:
+                       {
+                               unsigned char *sysex = (unsigned char *) ev + sizeof(snd_seq_event_t);
+                               int c;
+
+                               printf("; len=%d [", ev->data.ext.len);
+
+                               for (c = 0; c < ev->data.ext.len; c++) {
+                                       printf("%02x%s", sysex[c], c < ev->data.ext.len - 1 ? ":" : "");
+                               }
+                               printf("]\n");
+                       }
+                       break;
+                       
+               case SND_SEQ_EVENT_QFRAME:
+                       printf("; frame=%i\n", ev->data.control.value);
+                       break;
+                       
+               case SND_SEQ_EVENT_CLOCK:
+               case SND_SEQ_EVENT_START:
+               case SND_SEQ_EVENT_CONTINUE:
+               case SND_SEQ_EVENT_STOP:
+                       printf("; queue = %i, client = %i\n", ev->data.addr.queue, ev->data.addr.client);
+                       break;
+
+               case SND_SEQ_EVENT_HEARTBEAT:
+                       printf("\n");
+                       break;
+
+               case SND_SEQ_EVENT_ECHO:
+                       {
+                               int i;
+                               
+                               printf("; ");
+                               for (i = 0; i < 8; i++) {
+                                       printf("%02i%s", ev->data.raw8.d[i], i < 7 ? ":" : "\n");
+                               }
+                       }
+                       break;
+                       
+               case SND_SEQ_EVENT_CLIENT_START:
+               case SND_SEQ_EVENT_CLIENT_EXIT:
+               case SND_SEQ_EVENT_CLIENT_CHANGE:
+                       printf("; client=%i\n", ev->data.addr.client);
+                       break;
+
+               case SND_SEQ_EVENT_PORT_START:
+               case SND_SEQ_EVENT_PORT_EXIT:
+               case SND_SEQ_EVENT_PORT_CHANGE:
+                       printf("; client=%i, port = %i\n", ev->data.addr.client, ev->data.addr.port);
+                       break;
+
+               default:
+                       printf("; not implemented\n");
+       }
+
+
+       switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
+               case SND_SEQ_EVENT_LENGTH_FIXED:
+                       return sizeof(snd_seq_event_t);
+
+               case SND_SEQ_EVENT_LENGTH_VARIABLE:
+                       return sizeof(snd_seq_event_t) + ev->data.ext.len;
+       }
+
+       return 0;
+}
+
+void event_decoder_start_timer(void *handle, int queue, int client, int port)
+{
+       int err;
+       snd_seq_event_t ev;
+       
+       bzero(&ev, sizeof(ev));
+       ev.source.queue = queue;
+       ev.source.client = client;
+       ev.source.port = 0;
+       ev.dest.queue = queue;
+       ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
+       ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
+       ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
+       ev.type = SND_SEQ_EVENT_START;
+       if ((err = snd_seq_event_output(handle, &ev))<0)
+               fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
+       while (snd_seq_flush_output(handle)>0)
+               sleep(1);
+}
+
+void event_decoder(void *handle, int argc, char *argv[])
+{
+       snd_seq_event_t *ev;
+       snd_seq_port_info_t port;
+       snd_seq_port_subscribe_t sub;
+       fd_set in;
+       int client, queue, max, err, v1, v2;
+       char *ptr;
+
+       if ((client = snd_seq_client_id(handle))<0) {
+               fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client));
+               return;
+       }
+       printf("Client ID = %i\n", client);
+       if ((queue = snd_seq_alloc_queue(handle, NULL))<0) {
+               fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue));
+               return;
+       }
+       printf("Queue ID = %i\n", queue);
+       if ((err = snd_seq_block_mode(handle, 0))<0)
+               fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
+       bzero(&port, sizeof(port));
+       strcpy(port.name, "Input");
+       if ((err = snd_seq_create_port(handle, &port)) < 0) {
+               fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err));
+               return;
+       }
+       event_decoder_start_timer(handle, queue, client, port.port);
+
+       bzero(&sub, sizeof(sub));
+       sub.sender.queue = queue;
+       sub.sender.client = SND_SEQ_CLIENT_SYSTEM;
+       sub.sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
+       sub.dest.queue = queue;
+       sub.dest.client = client;
+       sub.dest.port = port.port;
+       sub.exclusive = 0;
+       sub.realtime = 1;
+       if ((err = snd_seq_subscribe_port(handle, &sub))<0) {
+               fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err));
+               return;
+       }
+       sub.sender.port = SND_SEQ_PORT_SYSTEM_TIMER;
+       if ((err = snd_seq_subscribe_port(handle, &sub))<0) {
+               fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err));
+               return;
+       }
+
+       for (max = 0; max < argc; max++) {
+               ptr = argv[max];
+               if (!ptr)
+                       continue;
+               sub.realtime = 0;
+               if (tolower(*ptr) == 'r') {
+                       sub.realtime = 1;
+                       ptr++;
+               }
+               if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
+                       fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
+                       return;
+               }
+               sub.sender.client = v1;
+               sub.sender.port = v2;
+               if ((err = snd_seq_subscribe_port(handle, &sub))<0) {
+                       fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err));
+                       return;
+               }
+       }
+       
+       while (1) {
+               FD_ZERO(&in);
+               FD_SET(max = snd_seq_file_descriptor(handle), &in);
+               if (select(max + 1, &in, NULL, NULL, NULL) < 0)
+                       break;
+               do {
+                       if ((err = snd_seq_event_input(handle, &ev))<0)
+                               break;
+                       if (!ev)
+                               continue;
+                       decode_event(ev);
+                       snd_seq_free_event(ev);
+               } while (err > 0);
+       }
+}
diff --git a/test/seq-sender.c b/test/seq-sender.c
new file mode 100644 (file)
index 0000000..e6dbe87
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  Simple event sender
+ */
+
+void event_sender_start_timer(void *handle, int client, int queue)
+{
+       int err;
+       snd_seq_event_t ev;
+       
+       bzero(&ev, sizeof(ev));
+       ev.source.queue = queue;
+       ev.source.client = client;
+       ev.source.port = 0;
+       ev.dest.queue = queue;
+       ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
+       ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
+       ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
+       ev.type = SND_SEQ_EVENT_START;
+       if ((err = snd_seq_event_output(handle, &ev))<0)
+               fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
+       while (snd_seq_flush_output(handle)>0)
+               sleep(1);
+}
+
+void event_sender_filter(void *handle)
+{
+       int err;
+       snd_seq_client_info_t info;
+
+       if ((err = snd_seq_get_client_info(handle, &info)) < 0) {
+               fprintf(stderr, "Unable to get client info: %s\n", snd_strerror(err));
+               return;
+       }
+       info.filter = SND_SEQ_FILTER_USE_EVENT;
+       memset(&info.event_filter, 0, sizeof(info.event_filter));
+       snd_seq_set_bit(SND_SEQ_EVENT_ECHO, info.event_filter);
+       if ((err = snd_seq_set_client_info(handle, &info)) < 0) {
+               fprintf(stderr, "Unable to set client info: %s\n", snd_strerror(err));
+               return;
+       }
+}
+
+void send_event(void *handle, int queue, int client, int port,
+                snd_seq_port_subscribe_t *sub, int *time)
+{
+       int err;
+       snd_seq_event_t ev;
+       
+       bzero(&ev, sizeof(ev));
+       ev.source.queue = ev.dest.queue = queue;
+       ev.source.client = ev.dest.client = client;
+       ev.source.port = ev.dest.port = port;
+       ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
+       ev.time.real.tv_sec = *time; (*time)++;
+       ev.type = SND_SEQ_EVENT_ECHO;
+       if ((err = snd_seq_event_output(handle, &ev))<0)
+               fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
+       ev.dest.client = sub->dest.client;
+       ev.dest.port = sub->dest.port;
+       ev.dest.channel = 0;
+       ev.type = SND_SEQ_EVENT_NOTE;
+       ev.data.note.note = 64 + (queue*2);
+       ev.data.note.velocity = 127;
+       ev.data.note.duration = 500;    /* 0.5sec */
+       if ((err = snd_seq_event_output(handle, &ev))<0)
+               fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
+       if ((err = snd_seq_flush_output(handle))<0)
+               fprintf(stderr, "Event flush error: %s\n", snd_strerror(err));
+}
+
+void event_sender(void *handle, int argc, char *argv[])
+{
+       snd_seq_event_t *ev;
+       snd_seq_port_info_t port;
+       snd_seq_port_subscribe_t sub;
+       fd_set out, in;
+       int client, queue, max, err, v1, v2, time = 0;
+       char *ptr;
+
+       if (argc != 1) {
+               fprintf(stderr, "Invalid destonation...\n");
+               return;
+       }
+
+       if ((client = snd_seq_client_id(handle))<0) {
+               fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client));
+               return;
+       }
+       printf("Client ID = %i\n", client);
+       if ((queue = snd_seq_alloc_queue(handle, NULL))<0) {
+               fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue));
+               return;
+       }
+       printf("Queue ID = %i\n", queue);
+       event_sender_filter(handle);
+       if ((err = snd_seq_block_mode(handle, 0))<0)
+               fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
+       event_sender_start_timer(handle, client, queue);
+       bzero(&port, sizeof(port));
+       strcpy(port.name, "Output");
+       if ((err = snd_seq_create_port(handle, &port)) < 0) {
+               fprintf(stderr, "Cannot create output port: %s\n", snd_strerror(err));
+               return;
+       }
+
+       bzero(&sub, sizeof(sub));
+       sub.sender.queue = queue;
+       sub.sender.client = client;
+       sub.sender.port = port.port;
+       sub.dest.queue = queue;
+       sub.exclusive = 0;
+
+       for (max = 0; max < argc; max++) {
+               ptr = argv[max];
+               if (!ptr)
+                       continue;
+               if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
+                       fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
+                       return;
+               }
+               sub.dest.client = v1;
+               sub.dest.port = v2;
+               if ((err = snd_seq_subscribe_port(handle, &sub))<0) {
+                       fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err));
+                       return;
+               }
+       }
+
+       printf("Destonation client = %i, port = %i\n", sub.dest.client, sub.dest.port);
+       
+       while (1) {
+               FD_ZERO(&out);
+               FD_ZERO(&in);
+               FD_SET(max = snd_seq_file_descriptor(handle), &out);
+               FD_SET(max = snd_seq_file_descriptor(handle), &in);
+               if (select(max + 1, &in, &out, NULL, NULL) < 0)
+                       break;
+               if (FD_ISSET(max, &out)) {
+                       send_event(handle, queue, client, port.port, &sub, &time);
+               }
+               if (FD_ISSET(max, &in)) {
+                       do {
+                               if ((err = snd_seq_event_input(handle, &ev))<0)
+                                       break;
+                               if (!ev)
+                                       continue;
+                               decode_event(ev);
+                               snd_seq_free_event(ev);
+                       } while (err > 0);
+               }
+       }
+}
diff --git a/test/seq.c b/test/seq.c
new file mode 100644 (file)
index 0000000..cc812c7
--- /dev/null
@@ -0,0 +1,223 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <getopt.h>
+#include "../include/asoundlib.h"
+
+#include "seq-decoder.c"
+#include "seq-sender.c"
+
+#define SEQ_VERSION "0.0.1"
+
+#define HELPID_HELP             1000
+#define HELPID_DEBUG            1001
+#define HELPID_VERBOSE         1002
+#define HELPID_VERSION          1003
+
+snd_seq_system_info_t sysinfo;
+int debug = 0;
+int verbose = 0;
+
+void set_name(void *handle)
+{
+       int err;
+       snd_seq_client_info_t info;
+       
+       bzero(&info, sizeof(info));
+       snprintf(info.name, sizeof(info.name), "SeqUtil - %i", getpid());
+       if ((err = snd_seq_set_client_info(handle, &info)) < 0) {
+               fprintf(stderr, "Set client info error: %s\n", snd_strerror(err));
+               exit(0);
+       }
+}
+
+void system_info(void *handle)
+{
+       int err;
+       
+       if ((err = snd_seq_system_info(handle, &sysinfo))<0) {
+               fprintf(stderr, "System info error: %s\n", snd_strerror(err));
+               exit(0);
+       }
+}
+
+void show_system_info(void *handle)
+{
+       printf("System info\n");
+       printf("  Max queues    : %i\n", sysinfo.queues);
+       printf("  Max clients   : %i\n", sysinfo.clients);
+       printf("  Max ports     : %i\n", sysinfo.ports);
+}
+
+void show_queue_info(void *handle, int queue)
+{
+       int err, idx, min, max;
+       snd_seq_queue_info_t info;
+       
+       min = queue < 0 ? 0 : queue;
+       max = queue < 0 ? sysinfo.queues : queue + 1;
+       for (idx = min; idx < max; idx++) {
+               if ((err = snd_seq_get_queue_info(handle, idx, &info))<0) {
+                       if (err == -ENOENT)
+                               continue;
+                       fprintf(stderr, "Client %i info error: %s\n", idx, snd_strerror(err));
+                       exit(0);
+               }
+               printf("Queue %i info\n", info.queue);
+               printf("  Tick          : %u\n", info.tick); 
+               printf("  Realtime      : %i.%i\n", info.time.tv_sec, info.time.tv_nsec);
+               printf("  Running       : %i\n", info.running);
+               printf("  Tempo         : %i\n", info.tempo);
+               printf("  PPQ           : %i\n", info.ppq);
+               printf("  Flags         : 0x%x\n", info.flags);
+               printf("  Owner         : %i\n", info.owner);
+               printf("  Locked        : %i\n", info.locked);
+       }
+}
+
+void show_port_info(void *handle, int client, int port)
+{
+       int err, idx, min, max;
+       snd_seq_port_info_t info;
+
+       min = port < 0 ? 0 : port;
+       max = port < 0 ? sysinfo.ports : port + 1;
+       for (idx = min; idx < max; idx++) {
+               if ((err = snd_seq_get_any_port_info(handle, client, idx, &info))<0) {
+                       if (err == -ENOENT)
+                               continue;
+                       fprintf(stderr, "Port %i/%i info error: %s\n", client, idx, snd_strerror(err));
+                       exit(0);
+               }
+               printf("  Port %i info\n", idx);
+               printf("    Client        : %i\n", info.client);
+               printf("    Port          : %i\n", info.port);
+               printf("    Name          : %s\n", info.name);
+               printf("    Capability    : 0x%x\n", info.capability);
+               printf("    Type          : 0x%x\n", info.type);
+               printf("    Midi channels : %i\n", info.midi_channels);
+               printf("    Synth voices  : %i\n", info.synth_voices);
+               printf("    Subscribers   : %i\n", info.subscribers);
+               printf("    Use           : %i\n", info.use);
+       }
+}
+
+void show_client_info(void *handle, int client)
+{
+       int err, idx, min, max;
+       snd_seq_client_info_t info;
+
+       min = client < 0 ? 0 : client;
+       max = client < 0 ? sysinfo.clients : client + 1;
+       for (idx = min; idx < max; idx++) {
+               if ((err = snd_seq_get_any_client_info(handle, idx, &info))<0) {
+                       if (err == -ENOENT)
+                               continue;
+                       fprintf(stderr, "Client %i info error: %s\n", idx, snd_strerror(err));
+                       exit(0);
+               }
+               printf("Client %i info\n", idx);
+               if (verbose)
+                       printf("  Client        : %i\n", info.client);
+               printf("  Type          : %s\n", info.type == KERNEL_CLIENT ? "kernel" : "user");
+               printf("  Name          : %s\n", info.name);
+       }
+}
+
+static void help(void)
+{
+       printf("Usage: seq <options> command\n");
+       printf("\nAvailable options:\n");
+       printf("  -h,--help       this help\n");
+       printf("  -d,--debug      debug mode\n");
+       printf("  -v,--verbose    verbose mode\n");
+       printf("  -V,--version    print version of this program\n");
+       printf("\nAvailable commands:\n");
+       printf("  system          show basic sequencer info\n");
+       printf("  queue [#]       show all queues or specified queue\n");
+       printf("  client [#]      show all clients or specified client\n");
+       printf("  port <client> [#]  show all ports or specified port for specified client\n");
+       printf("  decoder         event decoder\n");
+}
+
+int main(int argc, char *argv[])
+{
+       int morehelp, err, arg, arg1;
+       void *handle;
+       static struct option long_option[] =
+       {
+               {"help", 0, NULL, HELPID_HELP},
+               {"debug", 0, NULL, HELPID_DEBUG},
+               {"verbose", 0, NULL, HELPID_VERBOSE},
+               {"version", 0, NULL, HELPID_VERSION},
+               {NULL, 0, NULL, 0},
+        };
+       
+       while (1) {
+               int c;
+
+               if ((c = getopt_long(argc, argv, "hdvV", long_option, NULL)) < 0)
+                       break;
+               switch (c) {
+               case 'h':
+               case HELPID_HELP:
+                       morehelp++;
+                       break;
+               case 'd':
+               case HELPID_DEBUG:
+                       debug = 1;
+                       break;
+               case 'v':
+               case HELPID_VERBOSE:
+                       verbose = 1;
+                       break;
+               case 'V':
+               case HELPID_VERSION:
+                       printf("alsactl version " SEQ_VERSION "\n");
+                       return 1;
+               default:
+                       fprintf(stderr, "\07Invalid switch or option needs an argument.\n");
+                       morehelp++;
+               }
+       }
+        if (morehelp) {
+                help();
+                return 1;
+        }
+       if (argc - optind <= 0) {
+               fprintf(stderr, "seq: Specify command...\n");
+               return 0;
+       }
+       if ((err = snd_seq_open(&handle, SND_SEQ_OPEN))<0) {
+               fprintf(stderr, "Open error: %s\n", snd_strerror(err));
+               exit(0);
+       }
+       set_name(handle);
+       system_info(handle);
+        if (!strcmp(argv[optind], "system")) {
+               show_system_info(handle);
+       } else if (!strcmp(argv[optind], "queue")) {
+               arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1;
+               show_queue_info(handle, arg);
+       } else if (!strcmp(argv[optind], "client")) {
+               arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1;
+               show_client_info(handle, arg);
+       } else if (!strcmp(argv[optind], "port")) {
+               arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1;
+               if (arg < 0) {
+                       fprintf(stderr, "Specify port...\n");
+                       exit(0);
+               }
+               arg1 = argc - optind > 2 ? atoi(argv[optind + 2]) : -1;
+               show_port_info(handle, arg, arg1);
+       } else if (!strcmp(argv[optind], "decoder")) {
+               event_decoder(handle, argc - optind - 1, argv + optind + 1);
+       } else if (!strcmp(argv[optind], "sender")) {
+               event_sender(handle, argc - optind - 1, argv + optind + 1);
+       } else {
+               help();
+       }
+       exit(1);
+}