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