1/*
2 *  Simple event decoder
3 */
4
5static 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
105int 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
248void 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
260void 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	if ((err = snd_seq_create_port(handle, pinfo)) < 0) {
287		fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err));
288		return;
289	}
290	port = snd_seq_port_info_get_port(pinfo);
291	event_decoder_start_timer(handle, queue, client, port);
292
293	snd_seq_port_subscribe_alloca(&sub);
294	addr.client = SND_SEQ_CLIENT_SYSTEM;
295	addr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
296	snd_seq_port_subscribe_set_sender(sub, &addr);
297	addr.client = client;
298	addr.port = port;
299	snd_seq_port_subscribe_set_dest(sub, &addr);
300	snd_seq_port_subscribe_set_queue(sub, queue);
301	snd_seq_port_subscribe_set_time_update(sub, 1);
302	snd_seq_port_subscribe_set_time_real(sub, 1);
303	if ((err = snd_seq_subscribe_port(handle, sub))<0) {
304		fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err));
305		return;
306	}
307
308	addr.client = SND_SEQ_CLIENT_SYSTEM;
309	addr.port = SND_SEQ_PORT_SYSTEM_TIMER;
310	snd_seq_port_subscribe_set_sender(sub, &addr);
311	if ((err = snd_seq_subscribe_port(handle, sub))<0) {
312		fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err));
313		return;
314	}
315
316	for (max = 0; max < argc; max++) {
317		ptr = argv[max];
318		if (!ptr)
319			continue;
320		snd_seq_port_subscribe_set_time_real(sub, 0);
321		if (tolower(*ptr) == 'r') {
322			snd_seq_port_subscribe_set_time_real(sub, 1);
323			ptr++;
324		}
325		if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
326			fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
327			return;
328		}
329		addr.client = v1;
330		addr.port = v2;
331		snd_seq_port_subscribe_set_sender(sub, &addr);
332		if ((err = snd_seq_subscribe_port(handle, sub))<0) {
333			fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err));
334			return;
335		}
336	}
337
338	max = snd_seq_poll_descriptors_count(handle, POLLIN);
339	pfds = alloca(sizeof(*pfds) * max);
340	while (1) {
341		snd_seq_poll_descriptors(handle, pfds, max, POLLIN);
342		if (poll(pfds, max, -1) < 0)
343			break;
344		do {
345			if ((err = snd_seq_event_input(handle, &ev))<0)
346				break;
347			if (!ev)
348				continue;
349			decode_event(ev);
350			snd_seq_free_event(ev);
351		} while (err > 0);
352	}
353}
354