1
2 /*
3 * Diverse Bristol midi routines.
4 * Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 /*
23 * This code should open the midi device (working with ALSA raw midi only for
24 * the moment (9/11/01)), and read data from it. Not sure how it will be read,
25 * either buffers, events, or perhaps just raw data. At some point in the
26 * development this will become a separate thread in the synth code.
27 */
28 #include <sys/poll.h>
29 #include <sys/select.h>
30 #include <stdlib.h>
31
32 #include "bristol.h"
33 #include "bristolmidi.h"
34
35 /* #define DEBUG */
36
37 extern bristolMidiMain bmidi;
38 extern int bristolFreeHandle();
39 extern int bristolFreeDevice();
40 extern int bristolMidiRawToMsg();
41
42 /*
43 * This is the ALSA code. Should separate it out already.
44 */
45 int
bristolMidiALSAOpen(char * devname,int flags,int chan,int messages,int (* callback)(),void * param,int dev,int handle)46 bristolMidiALSAOpen(char *devname, int flags, int chan, int messages,
47 int (*callback)(), void *param, int dev, int handle)
48 {
49 #if (BRISTOL_HAS_ALSA == 1)
50 #if (SND_LIB_MAJOR == 1)
51 int nfds;
52 snd_seq_port_info_t *port_info;
53
54 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
55 printf("bristolMidiALSAOpen(%s)\n", devname);
56
57 bmidi.dev[dev].flags = SND_SEQ_OPEN_INPUT;
58 if (snd_rawmidi_open(&bmidi.dev[dev].driver.alsa.handle, NULL,
59 devname, bmidi.dev[dev].flags) != 0)
60 {
61 /*
62 * Print a debug message, this is problematic.
63 */
64 printf("Could not open the MIDI interface.\n");
65 return(BRISTOL_MIDI_DRIVER);
66 }
67
68 snd_seq_port_info_alloca (&port_info);
69 snd_seq_port_info_set_name (port_info, "bristol input port");
70 snd_seq_port_info_set_capability (port_info,
71 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE);
72 snd_seq_port_info_set_type (port_info,
73 SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_SYNTHESIZER);
74 /*|SND_SEQ_PORT_TYPE_SPECIFIC); */
75
76 if (snd_seq_create_port (bmidi.dev[dev].driver.seq.handle, port_info))
77 printf ("error creating alsa port\n");
78 else if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
79 printf ("created alsa port\n");
80
81 /*
82 * We need to get a file descriptor for this interface, since we are going
83 * to use it with select() over several interfaces.
84 if ((bmidi.dev[dev].fd = open("/dev/midi", O_RDONLY)) < 0)
85 printf("Issue getting MIDI fd\n");
86 */
87 if ((nfds =
88 snd_rawmidi_poll_descriptors_count(bmidi.dev[dev].driver.alsa.handle))
89 < 1)
90 printf("issue getting descriptors: %i\n", nfds);
91 else {
92 struct pollfd *pfds;
93
94 pfds = (struct pollfd *) malloc(sizeof (struct pollfd) * nfds);
95 snd_rawmidi_poll_descriptors(bmidi.dev[dev].driver.alsa.handle,
96 pfds, nfds);
97
98 bmidi.dev[dev].fd = pfds[0].fd;
99 }
100 #endif
101
102 bmidi.dev[dev].flags |= BRISTOL_CONN_MIDI;
103
104 return(handle);
105 #else
106 return(0);
107 #endif /* ADLIB */
108 }
109
110 int
bristolMidiALSAClose(int handle)111 bristolMidiALSAClose(int handle)
112 {
113 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
114 printf("bristolMidiALSAClose()\n");
115
116 #if (BRISTOL_HAS_ALSA == 1)
117 #if (SND_LIB_MAJOR == 1)
118 /*
119 * Check to see if the associated device has multiple handles associated
120 */
121 if (bmidi.dev[bmidi.handle[handle].dev].handleCount > 1)
122 {
123 bmidi.dev[bmidi.handle[handle].dev].handleCount--;
124 bristolFreeHandle(handle);
125
126 return(BRISTOL_MIDI_OK);
127 }
128
129 snd_rawmidi_close(bmidi.dev[bmidi.handle[handle].dev].driver.alsa.handle);
130
131 bristolFreeDevice(bmidi.handle[handle].dev);
132 bristolFreeHandle(handle);
133 #endif /* ADLIB */
134 #endif /* ADLIB */
135 return(BRISTOL_MIDI_OK);
136 }
137
138 /*
139 * Check callbacks has two functions, firstly it looks to see if there are any
140 * handles registered for this message, then whilst scanning the whole list of
141 * handles it will decide if the message also needs redistributing.
142 *
143 * The decision to redistribute should only be taken if the message came from
144 * a midi device that is not a TCP connection. The destination will be selected
145 * if it the device is a TCP connection.
146 */
147 void
checkcallbacks(bristolMidiMsg * msg)148 checkcallbacks(bristolMidiMsg *msg)
149 {
150 int i = 0, message = 1 << ((msg->command & 0x70) >> 4);
151
152 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
153 printf("msg from %i, chan %i, %i bytes\n", msg->params.bristol.from,
154 msg->params.bristol.channel, msg->params.bristol.msgLen);
155
156 for (i = 0; i < BRISTOL_MIDI_HANDLES; i++)
157 {
158 if ((bmidi.dev[bmidi.handle[i].dev].flags & BRISTOL_ACCEPT_SOCKET)
159 || (bmidi.dev[i].flags & BRISTOL_CONN_JACK)
160 || (bmidi.handle[i].state < 0))
161 continue;
162
163 if ((bmidi.dev[bmidi.handle[i].dev].fd > 0)
164 && (bmidi.flags & BRISTOL_MIDI_FORWARD)
165 && (bmidi.flags & BRISTOL_MIDI_GO)
166 //&& (~bmidi.dev[i].flags & BRISTOL_CONN_JACK)
167 && (~bmidi.dev[msg->params.bristol.from].flags & BRISTOL_CONN_TCP)
168 && (bmidi.dev[bmidi.handle[i].dev].flags & BRISTOL_CONN_TCP)
169 && (bmidi.dev[bmidi.handle[i].dev].flags & BRISTOL_CONN_FORWARD)
170 && (bmidi.handle[i].dev >= 0)
171 && (msg->params.bristol.msgLen != 0))
172 {
173 if (bmidi.dev[bmidi.handle[i].dev].flags & _BRISTOL_MIDI_DEBUG)
174 printf(
175 "candidate for forwarding: %i: %i -> %i (%x %x: %i %i)\n",
176 i,
177 msg->params.bristol.from,
178 bmidi.handle[i].dev,
179 bmidi.dev[msg->params.bristol.from].flags,
180 bmidi.dev[bmidi.handle[i].dev].flags,
181 bmidi.dev[bmidi.handle[i].dev].fd,
182 msg->params.bristol.msgLen);
183 if (bmidi.msgforwarder != NULL) {
184 msg->mychannel = bmidi.handle[i].dev;
185 bmidi.msgforwarder(msg);
186 } else if (bristolMidiRawWrite(bmidi.handle[i].dev, msg,
187 msg->params.bristol.msgLen) != 0)
188 printf("forward failed\n");
189 }
190 /*
191 printf("Not a forwarding candidate\n%i %x: %x %x %x %x %x %i\n",
192 i, //7
193 bmidi.flags,
194 bmidi.flags & BRISTOL_MIDI_FORWARD, //20000000
195 bmidi.flags & BRISTOL_MIDI_GO, //80000000
196 ~bmidi.dev[msg->params.bristol.from].flags & BRISTOL_CONN_TCP,
197 bmidi.dev[bmidi.handle[i].dev].flags & BRISTOL_CONN_TCP,
198 bmidi.dev[bmidi.handle[i].dev].flags & BRISTOL_CONN_FORWARD,
199 msg->params.bristol.msgLen);
200 */
201
202 if (bmidi.handle[i].callback == NULL)
203 {
204 if (bmidi.dev[bmidi.handle[i].dev].flags & _BRISTOL_MIDI_DEBUG)
205 printf("null callback\n");
206 /*
207 * We should not really have null callbacks. The only use for it
208 * was for blocking read operations for the GUI to get acks back
209 * from the engine.
210 *
211 * Registrations with null callback should be given a default
212 * handler which flags the message as 'new' for the reader thread
213 * to take it and return.
214 */
215 continue;
216 }
217
218 if (bmidi.handle[i].messagemask & message)
219 {
220 if (msg->command == (MIDI_SYSEX & MIDI_COMMAND_MASK))
221 {
222 /*
223 * SYSEX should only be sent on a single channel, the one on
224 * which it arrived.
225 */
226 if (msg->params.bristol.from == bmidi.handle[i].dev)
227 {
228 msg->params.bristol.from = i;
229 bmidi.handle[i].callback(msg, bmidi.handle[i].param);
230 return;
231 }
232 } else {
233 unsigned char hold = msg->params.bristol.from;
234
235 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
236 printf("callback non sysex: %i %x\n",
237 i, bmidi.handle[i].flags);
238
239 if (((~bmidi.flags & BRISTOL_MIDI_GO)
240 && (((msg->command & ~MIDI_STATUS_MASK) >> 4) < 2))
241 || (bmidi.handle[i].flags & BRISTOL_CONN_SYSEX))
242 continue;
243 msg->params.bristol.from = i;
244 bmidi.handle[i].callback(msg, bmidi.handle[i].param);
245 msg->params.bristol.from = hold;
246 }
247 }
248 }
249 }
250
251 /*
252 * Note that we should not read on a handle - we should read on a device, and
253 * then forward to all the handles.
254 */
255 int
bristolMidiALSARead(int dev,bristolMidiMsg * msg)256 bristolMidiALSARead(int dev, bristolMidiMsg *msg)
257 {
258 int parsed, space;
259
260 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
261 printf("bristolMidiALSARead(%i)\n", dev);
262
263 /*
264 * See if we can read more data from the midi device. We need to make sure
265 * we have buffer capacity, and if so attempt to read as many bytes as we
266 * have space for. We need to treat the buffer as endless, ie, rotary. It
267 * does make it pretty ugly if we come to large sysex messages.
268 */
269 if ((space = BRISTOL_MIDI_BUFSIZE - bmidi.dev[dev].bufcount) > 0)
270 {
271 int offset, count = 0;
272
273 /*
274 * We have space in our buffer, but we may have a wrap condition. If
275 * this is the case, only partially read to the end of the buffer, then
276 * read further into the buffer. Requires two read ops. Bummer.
277 */
278 /*
279 * Generate offset for new data, with buffer size corrections.
280 */
281 if ((offset = bmidi.dev[dev].bufindex + bmidi.dev[dev].bufcount)
282 >= BRISTOL_MIDI_BUFSIZE)
283 offset -= BRISTOL_MIDI_BUFSIZE;
284
285 /*
286 * Read new data, if we have any
287 */
288 if (bmidi.dev[dev].flags & BRISTOL_CONTROL_SOCKET) {
289 count = read(bmidi.dev[dev].fd, &bmidi.dev[dev].buffer[offset], 1);
290 /*
291 * We are going to treat a count of zero as an error.
292 */
293 if (count == 0)
294 return(BRISTOL_MIDI_DEV);
295 } else {
296 #if (BRISTOL_HAS_ALSA == 1)
297 #if (SND_LIB_MAJOR == 1)
298 if (bmidi.dev[dev].flags & BRISTOL_CONN_MIDI)
299 count = snd_rawmidi_read(bmidi.dev[dev].driver.alsa.handle,
300 &bmidi.dev[dev].buffer[offset], 1);
301 else
302 #endif
303 #endif
304 {
305 #define B_SEL /* Decide whether to use the select() code or just read() */
306 #ifdef B_SEL
307 int iterations = 3;
308 struct timeval timeout;
309 fd_set read_set[256];
310
311 /*
312 * We need to poll the FD here to prevent lockouts.
313 */
314 while (iterations-- > 0)
315 {
316 FD_ZERO(read_set);
317 FD_SET(bmidi.dev[dev].fd, read_set);
318
319 //#warning LINK AN OSC FD REQUEST IN HERE
320 /*
321 * OSC will give perhaps another FD to be included. If the
322 * request for the OSC fd > 0 put it in the list
323 */
324
325 if (bmidi.dev[dev].flags & BRISTOL_CONN_NBLOCK)
326 timeout.tv_sec = 0;
327 else
328 timeout.tv_sec = 1;
329 timeout.tv_sec = 0;
330 timeout.tv_usec = 100000;
331 timeout.tv_usec = 10000;
332
333 if (select(bmidi.dev[dev].fd + 1, read_set,
334 NULL, NULL, &timeout) == 1)
335 {
336 count = read(bmidi.dev[dev].fd,
337 &bmidi.dev[dev].buffer[offset], 1);
338 break;
339 }
340
341 if (bmidi.dev[dev].flags & BRISTOL_CONN_NBLOCK)
342 return(BRISTOL_MIDI_DEV);
343
344 return(BRISTOL_MIDI_DEV);
345
346 printf("Midi read retry (%i)\n", getpid());
347 }
348 #else
349 count = read(bmidi.dev[dev].fd,
350 &bmidi.dev[dev].buffer[offset], 1);
351 #endif
352 }
353 }
354
355 /*
356 * MIDI byte debugging. This should be under a compilation flag
357 */
358 if ((count == 1) && (bmidi.dev[dev].flags & _BRISTOL_MIDI_DEBUG))
359 printf("%i-%02x ", dev, bmidi.dev[dev].buffer[offset]);
360
361 if (count < 1)
362 {
363 if (bmidi.dev[dev].bufcount == 0)
364 {
365 /*
366 * MARK
367 */
368 printf("no data in alsa buffer for %i (close)\n", dev);
369 msg->command = -1;
370 /*
371 * We should consider closing whatever synth was listening
372 * here. This would require build an EXIT message.
373 */
374 return(BRISTOL_MIDI_CHANNEL);
375 } else
376 count = 0;
377 }
378
379 bmidi.dev[dev].bufcount++;
380 } else {
381 printf("Device buffer exhausted\n");
382 bmidi.dev[dev].bufindex = bmidi.dev[dev].bufcount = 0;
383 return(BRISTOL_MIDI_DEV);
384 }
385
386 /*
387 * I really want to parse these, and then forward the messages to callback
388 * routines registered by the bristolMidiOpen() command.
389 if ((parsed = bristolMidiRawToMsg(&bmidi.dev[dev].buffer[0],
390 */
391 while ((parsed = bristolMidiRawToMsg(&bmidi.dev[dev].buffer[0],
392 bmidi.dev[dev].bufcount, bmidi.dev[dev].bufindex, dev, msg)) > 0)
393 {
394 if (bmidi.flags & BRISTOL_BMIDI_DEBUG)
395 printf("parsed %i\n", parsed);
396
397 if ((bmidi.dev[dev].bufcount -= parsed) < 0)
398 {
399 /*
400 * We have an issue here, count has gone negative. Reset all buffer
401 * pointers, and just write an error for now.
402 */
403 bmidi.dev[dev].bufcount = 0;
404 bmidi.dev[dev].bufindex = 0;
405 printf("Issue with buffer capacity going negative\n");
406 }
407 /*
408 * Wrap index as necessary.
409 */
410 if ((bmidi.dev[dev].bufindex += parsed) >= BRISTOL_MIDI_BUFSIZE)
411 bmidi.dev[dev].bufindex -= BRISTOL_MIDI_BUFSIZE;
412
413 /*
414 * We should now go through all the handles, and find out who has
415 * registered for these events - then forward them the event via the
416 * callback. For now we are just going to send it to the one existing
417 * callback.
418 */
419 msg->params.bristol.from = dev;
420 /* bristolMidiToGM2(msg); */
421
422 if (msg->params.bristol.msgLen == 0)
423 msg->params.bristol.msgLen = parsed;
424
425 if (msg->command != 0x0ff)
426 checkcallbacks(msg);
427 }
428
429 msg->command = -1;
430
431 return(BRISTOL_MIDI_OK);
432 }
433
434