-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmidi.c
207 lines (175 loc) · 4.6 KB
/
midi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#include <alsa/asoundlib.h>
#define MIDI_DELAY 10000
static snd_seq_t *seq;
static int port_count;
static snd_seq_addr_t *ports;
/* A bunch of crap taken from aseqdump.c */
static void fatal(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
/* memory allocation error handling */
static void check_mem(void *p)
{
if (!p)
fatal("Out of memory");
}
/* error handling for ALSA functions */
static void check_snd(const char *operation, int err)
{
if (err < 0)
fatal("Cannot %s - %s", operation, snd_strerror(err));
}
static void init_seq(void)
{
int err;
/* open sequencer */
err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
check_snd("open sequencer", err);
/* set our client's name */
err = snd_seq_set_client_name(seq, "uniform");
check_snd("set client name", err);
}
static void parse_ports(const char *arg)
{
char *buf, *s, *port_name;
int err;
/* make a copy of the string because we're going to modify it */
buf = strdup(arg);
check_mem(buf);
for (port_name = s = buf; s; port_name = s + 1) {
/* Assume that ports are separated by commas. We don't use
* spaces because those are valid in client names. */
s = strchr(port_name, ',');
if (s)
*s = '\0';
++port_count;
ports = realloc(ports, port_count * sizeof(snd_seq_addr_t));
check_mem(ports);
err = snd_seq_parse_address(seq, &ports[port_count - 1], port_name);
if (err < 0)
fatal("Invalid port %s - %s", port_name, snd_strerror(err));
}
free(buf);
}
static void create_port(void) {
int err;
err = snd_seq_create_simple_port(seq, "uniform",
SND_SEQ_PORT_CAP_WRITE |
SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
SND_SEQ_PORT_TYPE_APPLICATION);
check_snd("create port", err);
}
static void connect_ports(void)
{
int i, err;
for (i = 0; i < port_count; ++i) {
err = snd_seq_connect_from(seq, 0, ports[i].client, ports[i].port);
if (err < 0)
fatal("Cannot connect from port %d:%d - %s",
ports[i].client, ports[i].port, snd_strerror(err));
}
}
/* Now the real workhorse to dump midi to uniforms */
static void dump_event(const snd_seq_event_t *ev)
{
switch (ev->type) {
case SND_SEQ_EVENT_NOTEON:
if (ev->data.note.velocity) {
printf("u_midi_note,%f\n", ev->data.note.note / 2.0);
printf("u_midi_velocity,%f\n", ev->data.note.velocity / 127.0);
} else {
printf("u_midi_note,0.0\n");
printf("u_midi_velocity,0.0\n");
}
break;
case SND_SEQ_EVENT_NOTEOFF:
printf("u_midi_velocity,0.0\n");
break;
case SND_SEQ_EVENT_KEYPRESS:
printf("u_midi_note,%f\n", ev->data.note.note / 2.0);
printf("u_midi_velocity,%f\n", ev->data.note.velocity / 127.0);
break;
case SND_SEQ_EVENT_CONTROLLER:
case SND_SEQ_EVENT_CONTROL14:
printf("u_midi_cc_%i,%f\n", ev->data.control.param, ev->data.control.value / 127.0);
break;
case SND_SEQ_EVENT_PGMCHANGE:
printf("Program change %2d, program %d\n",
ev->data.control.channel, ev->data.control.value);
break;
case SND_SEQ_EVENT_CHANPRESS:
printf("Channel aftertouch %2d, value %d\n",
ev->data.control.channel, ev->data.control.value);
break;
case SND_SEQ_EVENT_PITCHBEND:
printf("u_midi_pitch,%f\n", (ev->data.control.value + 1.0) / 8192.0);
break;
case SND_SEQ_EVENT_SETPOS_TICK:
break;
case SND_SEQ_EVENT_SETPOS_TIME:
break;
case SND_SEQ_EVENT_TEMPO:
break;
case SND_SEQ_EVENT_CLOCK:
break;
case SND_SEQ_EVENT_TICK:
break;
case SND_SEQ_EVENT_QUEUE_SKEW:
break;
case SND_SEQ_EVENT_TUNE_REQUEST:
break;
case SND_SEQ_EVENT_RESET:
break;
case SND_SEQ_EVENT_SYSEX:
{
unsigned int i;
printf("System exclusive ");
for (i = 0; i < ev->data.ext.len; ++i)
printf(" %02X", ((unsigned char*)ev->data.ext.ptr)[i]);
printf("\n");
}
break;
}
}
/* And the startup thread function */
void* midi(void* arg) {
int err;
init_seq();
create_port();
parse_ports("24");
connect_ports();
err = snd_seq_nonblock(seq, 1);
check_snd("set nonblock mode", err);
struct pollfd *pfds;
int npfds;
npfds = snd_seq_poll_descriptors_count(seq, POLLIN);
pfds = alloca(sizeof(*pfds) * npfds);
while(1) {
snd_seq_poll_descriptors(seq, pfds, npfds, POLLIN);
if (poll(pfds, npfds, -1) < 0)
break;
do {
snd_seq_event_t *event;
err = snd_seq_event_input(seq, &event);
//if (err < 0)
// break;
if (event)
dump_event(event);
} while (err > 0);
usleep(MIDI_DELAY);
}
return 0;
}