1 /*
2 * Simple event decoder
3 */
4
5 static char *event_names[256] = {
6 [SND_SEQ_EVENT_SYSTEM]= "System",
7 [SND_SEQ_EVENT_RESULT]= "Result",
8 [SND_SEQ_EVENT_NOTE]= "Note",
9 [SND_SEQ_EVENT_NOTEON]= "Note On",
10 [SND_SEQ_EVENT_NOTEOFF]= "Note Off",
11 [SND_SEQ_EVENT_KEYPRESS]= "Key Pressure",
12 [SND_SEQ_EVENT_CONTROLLER]= "Controller",
13 [SND_SEQ_EVENT_PGMCHANGE]= "Program Change",
14 [SND_SEQ_EVENT_CHANPRESS]= "Channel Pressure",
15 [SND_SEQ_EVENT_PITCHBEND]= "Pitchbend",
16 [SND_SEQ_EVENT_CONTROL14]= "Control14",
17 [SND_SEQ_EVENT_NONREGPARAM]= "Nonregparam",
18 [SND_SEQ_EVENT_REGPARAM]= "Regparam",
19 [SND_SEQ_EVENT_SONGPOS]= "Song Position",
20 [SND_SEQ_EVENT_SONGSEL]= "Song Select",
21 [SND_SEQ_EVENT_QFRAME]= "Qframe",
22 [SND_SEQ_EVENT_TIMESIGN]= "SMF Time Signature",
23 [SND_SEQ_EVENT_KEYSIGN]= "SMF Key Signature",
24 [SND_SEQ_EVENT_START]= "Start",
25 [SND_SEQ_EVENT_CONTINUE]= "Continue",
26 [SND_SEQ_EVENT_STOP]= "Stop",
27 [SND_SEQ_EVENT_SETPOS_TICK]= "Set Position Tick",
28 [SND_SEQ_EVENT_SETPOS_TIME]= "Set Position Time",
29 [SND_SEQ_EVENT_TEMPO]= "Tempo",
30 [SND_SEQ_EVENT_CLOCK]= "Clock",
31 [SND_SEQ_EVENT_TICK]= "Tick",
32 [SND_SEQ_EVENT_TUNE_REQUEST]= "Tune Request",
33 [SND_SEQ_EVENT_RESET]= "Reset",
34 [SND_SEQ_EVENT_SENSING]= "Active Sensing",
35 [SND_SEQ_EVENT_ECHO]= "Echo",
36 [SND_SEQ_EVENT_OSS]= "OSS",
37 [SND_SEQ_EVENT_CLIENT_START]= "Client Start",
38 [SND_SEQ_EVENT_CLIENT_EXIT]= "Client Exit",
39 [SND_SEQ_EVENT_CLIENT_CHANGE]= "Client Change",
40 [SND_SEQ_EVENT_PORT_START]= "Port Start",
41 [SND_SEQ_EVENT_PORT_EXIT]= "Port Exit",
42 [SND_SEQ_EVENT_PORT_CHANGE]= "Port Change",
43 [SND_SEQ_EVENT_PORT_SUBSCRIBED]= "Port Subscribed",
44 [SND_SEQ_EVENT_PORT_UNSUBSCRIBED]= "Port Unsubscribed",
45 #if 0
46 [SND_SEQ_EVENT_SAMPLE]= "Sample",
47 [SND_SEQ_EVENT_SAMPLE_CLUSTER]= "Sample Cluster",
48 [SND_SEQ_EVENT_SAMPLE_START]= "Sample Start",
49 [SND_SEQ_EVENT_SAMPLE_STOP]= "Sample Stop",
50 [SND_SEQ_EVENT_SAMPLE_FREQ]= "Sample Freq",
51 [SND_SEQ_EVENT_SAMPLE_VOLUME]= "Sample Volume",
52 [SND_SEQ_EVENT_SAMPLE_LOOP]= "Sample Loop",
53 [SND_SEQ_EVENT_SAMPLE_POSITION]= "Sample Position",
54 [SND_SEQ_EVENT_SAMPLE_PRIVATE1]= "Sample Private1",
55 #endif
56 [SND_SEQ_EVENT_USR0]= "User 0",
57 [SND_SEQ_EVENT_USR1]= "User 1",
58 [SND_SEQ_EVENT_USR2]= "User 2",
59 [SND_SEQ_EVENT_USR3]= "User 3",
60 [SND_SEQ_EVENT_USR4]= "User 4",
61 [SND_SEQ_EVENT_USR5]= "User 5",
62 [SND_SEQ_EVENT_USR6]= "User 6",
63 [SND_SEQ_EVENT_USR7]= "User 7",
64 [SND_SEQ_EVENT_USR8]= "User 8",
65 [SND_SEQ_EVENT_USR9]= "User 9",
66 #if 0
67 [SND_SEQ_EVENT_INSTR_BEGIN]= "Instr Begin",
68 [SND_SEQ_EVENT_INSTR_END]= "Instr End",
69 [SND_SEQ_EVENT_INSTR_INFO]= "Instr Info",
70 [SND_SEQ_EVENT_INSTR_INFO_RESULT]= "Instr Info Result",
71 [SND_SEQ_EVENT_INSTR_FINFO]= "Instr Font Info",
72 [SND_SEQ_EVENT_INSTR_FINFO_RESULT]= "Instr Font Info Result",
73 [SND_SEQ_EVENT_INSTR_RESET]= "Instr Reset",
74 [SND_SEQ_EVENT_INSTR_STATUS]= "Instr Status",
75 [SND_SEQ_EVENT_INSTR_STATUS_RESULT]= "Instr Status Result",
76 [SND_SEQ_EVENT_INSTR_PUT]= "Instr Put",
77 [SND_SEQ_EVENT_INSTR_GET]= "Instr Get",
78 [SND_SEQ_EVENT_INSTR_GET_RESULT]= "Instr Get Result",
79 [SND_SEQ_EVENT_INSTR_FREE]= "Instr Free",
80 [SND_SEQ_EVENT_INSTR_LIST]= "Instr List",
81 [SND_SEQ_EVENT_INSTR_LIST_RESULT]= "Instr List Result",
82 [SND_SEQ_EVENT_INSTR_CLUSTER]= "Instr Cluster",
83 [SND_SEQ_EVENT_INSTR_CLUSTER_GET]= "Instr Cluster Get",
84 [SND_SEQ_EVENT_INSTR_CLUSTER_RESULT]= "Instr Cluster Result",
85 [SND_SEQ_EVENT_INSTR_CHANGE]= "Instr Change",
86 #endif
87 [SND_SEQ_EVENT_SYSEX]= "Sysex",
88 [SND_SEQ_EVENT_BOUNCE]= "Bounce",
89 [SND_SEQ_EVENT_USR_VAR0]= "User Var0",
90 [SND_SEQ_EVENT_USR_VAR1]= "User Var1",
91 [SND_SEQ_EVENT_USR_VAR2]= "User Var2",
92 [SND_SEQ_EVENT_USR_VAR3]= "User Var3",
93 [SND_SEQ_EVENT_USR_VAR4]= "User Var4",
94 #if 0
95 [SND_SEQ_EVENT_IPCSHM]= "IPC Shm",
96 [SND_SEQ_EVENT_USR_VARIPC0]= "User IPC0",
97 [SND_SEQ_EVENT_USR_VARIPC1]= "User IPC1",
98 [SND_SEQ_EVENT_USR_VARIPC2]= "User IPC2",
99 [SND_SEQ_EVENT_USR_VARIPC3]= "User IPC3",
100 [SND_SEQ_EVENT_USR_VARIPC4]= "User IPC4",
101 #endif
102 [SND_SEQ_EVENT_NONE]= "None",
103 };
104
decode_event(snd_seq_event_t * ev)105 int decode_event(snd_seq_event_t * ev)
106 {
107 char *space = " ";
108
109 printf("EVENT>>> Type = %d, flags = 0x%x", ev->type, ev->flags);
110 switch (ev->flags & SND_SEQ_TIME_STAMP_MASK) {
111 case SND_SEQ_TIME_STAMP_TICK:
112 printf(", time = %d ticks",
113 ev->time.tick);
114 break;
115 case SND_SEQ_TIME_STAMP_REAL:
116 printf(", time = %d.%09d",
117 (int)ev->time.time.tv_sec,
118 (int)ev->time.time.tv_nsec);
119 break;
120 }
121 printf("\n%sSource = %d.%d, dest = %d.%d, queue = %d\n",
122 space,
123 ev->source.client,
124 ev->source.port,
125 ev->dest.client,
126 ev->dest.port,
127 ev->queue);
128
129 if (event_names[ev->type])
130 printf("%sEvent = %s", space, event_names[ev->type]);
131 else
132 printf("%sEvent = Reserved %d\n", space, ev->type);
133 /* decode the actual event data... */
134 switch (ev->type) {
135 case SND_SEQ_EVENT_NOTE:
136 printf("; ch=%d, note=%d, velocity=%d, off_velocity=%d, duration=%d\n",
137 ev->data.note.channel,
138 ev->data.note.note,
139 ev->data.note.velocity,
140 ev->data.note.off_velocity,
141 ev->data.note.duration);
142 break;
143
144 case SND_SEQ_EVENT_NOTEON:
145 case SND_SEQ_EVENT_NOTEOFF:
146 case SND_SEQ_EVENT_KEYPRESS:
147 printf("; ch=%d, note=%d, velocity=%d\n",
148 ev->data.note.channel,
149 ev->data.note.note,
150 ev->data.note.velocity);
151 break;
152
153 case SND_SEQ_EVENT_CONTROLLER:
154 printf("; ch=%d, param=%i, value=%i\n",
155 ev->data.control.channel,
156 ev->data.control.param,
157 ev->data.control.value);
158 break;
159
160 case SND_SEQ_EVENT_PGMCHANGE:
161 printf("; ch=%d, program=%i\n",
162 ev->data.control.channel,
163 ev->data.control.value);
164 break;
165
166 case SND_SEQ_EVENT_CHANPRESS:
167 case SND_SEQ_EVENT_PITCHBEND:
168 printf("; ch=%d, value=%i\n",
169 ev->data.control.channel,
170 ev->data.control.value);
171 break;
172
173 case SND_SEQ_EVENT_SYSEX:
174 {
175 unsigned char *sysex = (unsigned char *) ev + sizeof(snd_seq_event_t);
176 unsigned int c;
177
178 printf("; len=%d [", ev->data.ext.len);
179
180 for (c = 0; c < ev->data.ext.len; c++) {
181 printf("%02x%s", sysex[c], c < ev->data.ext.len - 1 ? ":" : "");
182 }
183 printf("]\n");
184 }
185 break;
186
187 case SND_SEQ_EVENT_QFRAME:
188 printf("; frame=0x%02x\n", ev->data.control.value);
189 break;
190
191 case SND_SEQ_EVENT_CLOCK:
192 case SND_SEQ_EVENT_START:
193 case SND_SEQ_EVENT_CONTINUE:
194 case SND_SEQ_EVENT_STOP:
195 printf("; queue = %i\n", ev->data.queue.queue);
196 break;
197
198 case SND_SEQ_EVENT_SENSING:
199 printf("\n");
200 break;
201
202 case SND_SEQ_EVENT_ECHO:
203 {
204 int i;
205
206 printf("; ");
207 for (i = 0; i < 8; i++) {
208 printf("%02i%s", ev->data.raw8.d[i], i < 7 ? ":" : "\n");
209 }
210 }
211 break;
212
213 case SND_SEQ_EVENT_CLIENT_START:
214 case SND_SEQ_EVENT_CLIENT_EXIT:
215 case SND_SEQ_EVENT_CLIENT_CHANGE:
216 printf("; client=%i\n", ev->data.addr.client);
217 break;
218
219 case SND_SEQ_EVENT_PORT_START:
220 case SND_SEQ_EVENT_PORT_EXIT:
221 case SND_SEQ_EVENT_PORT_CHANGE:
222 printf("; client=%i, port = %i\n", ev->data.addr.client, ev->data.addr.port);
223 break;
224
225 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
226 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
227 printf("; %i:%i -> %i:%i\n",
228 ev->data.connect.sender.client, ev->data.connect.sender.port,
229 ev->data.connect.dest.client, ev->data.connect.dest.port);
230 break;
231
232 default:
233 printf("; not implemented\n");
234 }
235
236
237 switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
238 case SND_SEQ_EVENT_LENGTH_FIXED:
239 return sizeof(snd_seq_event_t);
240
241 case SND_SEQ_EVENT_LENGTH_VARIABLE:
242 return sizeof(snd_seq_event_t) + ev->data.ext.len;
243 }
244
245 return 0;
246 }
247
event_decoder_start_timer(snd_seq_t * handle,int queue,int client ATTRIBUTE_UNUSED,int port ATTRIBUTE_UNUSED)248 void event_decoder_start_timer(snd_seq_t *handle, int queue,
249 int client ATTRIBUTE_UNUSED,
250 int port ATTRIBUTE_UNUSED)
251 {
252 int err;
253
254 if ((err = snd_seq_start_queue(handle, queue, NULL))<0)
255 fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
256 while (snd_seq_drain_output(handle)>0)
257 sleep(1);
258 }
259
event_decoder(snd_seq_t * handle,int argc,char * argv[])260 void event_decoder(snd_seq_t *handle, int argc, char *argv[])
261 {
262 snd_seq_event_t *ev;
263 snd_seq_port_info_t *pinfo;
264 snd_seq_port_subscribe_t *sub;
265 snd_seq_addr_t addr;
266 int client, port, queue, max, err, v1, v2;
267 char *ptr;
268 struct pollfd *pfds;
269
270 if ((client = snd_seq_client_id(handle))<0) {
271 fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client));
272 return;
273 }
274 printf("Client ID = %i\n", client);
275 if ((queue = snd_seq_alloc_queue(handle))<0) {
276 fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue));
277 return;
278 }
279 printf("Queue ID = %i\n", queue);
280 if ((err = snd_seq_nonblock(handle, 1))<0)
281 fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
282 snd_seq_port_info_alloca(&pinfo);
283 snd_seq_port_info_set_name(pinfo, "Input");
284 snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
285 snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE);
286
287 /* Enable timestamping for events sent by external subscribers. */
288 snd_seq_port_info_set_timestamping(pinfo, 1);
289 snd_seq_port_info_set_timestamp_real(pinfo, 1);
290 snd_seq_port_info_set_timestamp_queue(pinfo, queue);
291
292 if ((err = snd_seq_create_port(handle, pinfo)) < 0) {
293 fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err));
294 return;
295 }
296 port = snd_seq_port_info_get_port(pinfo);
297 event_decoder_start_timer(handle, queue, client, port);
298
299 snd_seq_port_subscribe_alloca(&sub);
300 addr.client = SND_SEQ_CLIENT_SYSTEM;
301 addr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
302 snd_seq_port_subscribe_set_sender(sub, &addr);
303 addr.client = client;
304 addr.port = port;
305 snd_seq_port_subscribe_set_dest(sub, &addr);
306 snd_seq_port_subscribe_set_queue(sub, queue);
307 snd_seq_port_subscribe_set_time_update(sub, 1);
308 snd_seq_port_subscribe_set_time_real(sub, 1);
309 if ((err = snd_seq_subscribe_port(handle, sub))<0) {
310 fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err));
311 return;
312 }
313
314 addr.client = SND_SEQ_CLIENT_SYSTEM;
315 addr.port = SND_SEQ_PORT_SYSTEM_TIMER;
316 snd_seq_port_subscribe_set_sender(sub, &addr);
317 if ((err = snd_seq_subscribe_port(handle, sub))<0) {
318 fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err));
319 return;
320 }
321
322 for (max = 0; max < argc; max++) {
323 ptr = argv[max];
324 if (!ptr)
325 continue;
326 snd_seq_port_subscribe_set_time_real(sub, 0);
327 if (tolower(*ptr) == 'r') {
328 snd_seq_port_subscribe_set_time_real(sub, 1);
329 ptr++;
330 }
331 if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
332 fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
333 return;
334 }
335 addr.client = v1;
336 addr.port = v2;
337 snd_seq_port_subscribe_set_sender(sub, &addr);
338 if ((err = snd_seq_subscribe_port(handle, sub))<0) {
339 fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err));
340 return;
341 }
342 }
343
344 max = snd_seq_poll_descriptors_count(handle, POLLIN);
345 pfds = alloca(sizeof(*pfds) * max);
346 while (1) {
347 snd_seq_poll_descriptors(handle, pfds, max, POLLIN);
348 if (poll(pfds, max, -1) < 0)
349 break;
350 do {
351 if ((err = snd_seq_event_input(handle, &ev))<0)
352 break;
353 if (!ev)
354 continue;
355 decode_event(ev);
356 snd_seq_free_event(ev);
357 } while (err > 0);
358 }
359 }
360