1#include <stdio.h>
  2#include <stdlib.h>
  3#include <alloca.h>
  4#include <signal.h>
  5#include <alsa/asoundlib.h>
  6
  7#define CLIENT_NAME "ttdaw"
  8#define MAX_MIDI_PORTS 1
  9
 10static snd_seq_t *seq_handle;
 11static snd_seq_addr_t *ports;
 12static int stop = 0;
 13
 14static void sighandler(int sig ATTRIBUTE_UNUSED) {
 15	stop = 1;
 16}
 17
 18int main(void) {
 19	fprintf(stdout, "Example: Reading MIDI input\n");
 20
 21	if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
 22		fprintf(stderr, "Error opening ALSA sequencer.\n");
 23		exit(1);
 24	}
 25
 26	if (snd_seq_set_client_name(seq_handle, CLIENT_NAME) < 0) {
 27		fprintf(stderr, "Could not set up client name.\n");
 28		exit(1);
 29	}
 30
 31	if (snd_seq_create_simple_port(seq_handle, CLIENT_NAME,
 32				SND_SEQ_PORT_CAP_WRITE |
 33				SND_SEQ_PORT_CAP_SUBS_WRITE,
 34				SND_SEQ_PORT_TYPE_MIDI_GENERIC |
 35				SND_SEQ_PORT_TYPE_APPLICATION) < 0) {
 36		fprintf(stderr, "Error creating sequencer port.\n");
 37		exit(1);
 38	}
 39
 40	// Connecting ports.
 41	char *port_name = "28:0";
 42	ports = realloc(ports, MAX_MIDI_PORTS * sizeof(snd_seq_addr_t));
 43	if (snd_seq_parse_address(seq_handle, &ports[0], port_name) < 0) {
 44		fprintf(stderr, "Invalid port %s.\n", port_name);
 45		exit(1);
 46	}
 47
 48	// Listing assigned ports.
 49	fprintf(stdout, "Ports:\n");
 50	for (int j = 0; j < MAX_MIDI_PORTS; j++) {
 51		fprintf(stdout, " client: %d, port: %d\n", ports[j].client, ports[j].port);
 52	}
 53
 54	// Connecting ports.
 55	for (int i = 0; i < MAX_MIDI_PORTS; ++i) {
 56		int err = snd_seq_connect_from(seq_handle, 0, ports[i].client, ports[i].port);
 57		if (err < 0) {
 58			fprintf(stderr, "Cannot connect from port %d:%d - %s", ports[i].client, ports[i].port, snd_strerror(err));
 59			exit(1);
 60		}
 61	}
 62
 63	if (snd_seq_nonblock(seq_handle, 1) < 0) {
 64		fprintf(stderr, "Set nonblock mode failed.");
 65		exit(1);
 66	}
 67
 68	signal(SIGINT, sighandler);
 69	signal(SIGTERM, sighandler);
 70
 71	// Reading MIDI device.
 72	struct pollfd *pfds;
 73	size_t npfds;
 74
 75	npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
 76	pfds = alloca(sizeof(*pfds) * npfds);
 77
 78	for (;;) {
 79		snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN);
 80		if (poll(pfds, npfds, -1) < 0) {
 81			break;
 82		}
 83
 84		for (;;) {
 85			snd_seq_event_t *ev;
 86
 87			if (snd_seq_event_input(seq_handle, &ev) < 0) {
 88				break;
 89			}
 90
 91			if (ev) {
 92				switch (ev->type) {
 93					case SND_SEQ_EVENT_NOTEON:
 94						printf("%3d:%-3dNote on  %2d, note %d, velocity: %3d\n",
 95								ev->source.client, ev->source.port,
 96								ev->data.note.channel,
 97								ev->data.note.note,
 98								ev->data.note.velocity);
 99						break;
100
101					case SND_SEQ_EVENT_NOTEOFF:
102						printf("%3d:%-3dNote off\t%2d, note %d\n",
103								ev->source.client, ev->source.port,
104								ev->data.note.channel,
105								ev->data.note.note);
106						break;
107
108
109				} 
110			}
111		}
112
113		fflush(stdout);
114
115		if (stop) {
116			break;
117		}
118	}
119
120	fprintf(stdout, "Finishing up\n");
121	snd_seq_close(seq_handle);
122	return 0;
123}
124