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