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 /*#define DEBUG */
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/select.h>
26 #include <signal.h>
27 #include <unistd.h>
28
29 #include "bristol.h"
30 #include "bristolmidi.h"
31
32 struct sockaddr address;
33
34 extern bristolMidiMain bmidi;
35 extern int bristolMidiTCPPassive();
36 int bristolMidiTCPActive();
37 extern int bristolMidiFindDev();
38 extern int initControlPort();
39 extern int bristolFreeHandle();
40 extern int bristolFreeDevice();
41
42 extern void checkcallbacks(bristolMidiMsg *);
43
44 static char bristol_sockname[128];
45
46 int
bristolMidiTCPClose(int handle)47 bristolMidiTCPClose(int handle)
48 {
49 #ifdef DEBUG
50 printf("bristolMidiTCPClose()\n");
51 #endif
52
53 /*
54 * Check to see if the associated device has multiple handles associated
55 */
56 if (bmidi.dev[bmidi.handle[handle].dev].handleCount > 1)
57 {
58 bmidi.dev[bmidi.handle[handle].dev].handleCount--;
59 bristolFreeHandle(handle);
60
61 return(BRISTOL_MIDI_OK);
62 }
63
64 close(bmidi.dev[bmidi.handle[handle].dev].fd);
65 bmidi.dev[bmidi.handle[handle].dev].fd = -1;
66
67 if (bmidi.dev[bmidi.handle[handle].dev].flags & BRISTOL_ACCEPT_SOCKET)
68 unlink(bristol_sockname);
69
70 bristolFreeDevice(bmidi.handle[handle].dev);
71 bristolFreeHandle(handle);
72
73 return(BRISTOL_MIDI_OK);
74 }
75
76 int
bristolMidiTCPOpen(char * host,int flags,int chan,int msgs,int (* callback)(),void * param,int dev,int handle)77 bristolMidiTCPOpen(char *host, int flags, int chan, int msgs,
78 int (*callback)(), void *param, int dev, int handle)
79 {
80 /* printf("bristolMidiTCPOpen(%s, %i, %i)\n", host, chan, dev); */
81 /*
82 * See if we are active or passive.
83 */
84 bmidi.dev[dev].handleCount = 1;
85 if (flags & BRISTOL_CONN_PASSIVE)
86 {
87 /*
88 * This is the server, or in our case the engine, side of operations.
89 * we need to open a listening socket, and bind it to an address.
90 */
91 return(bristolMidiTCPPassive(host, flags, chan, msgs, callback,
92 param, dev, handle));
93 } else {
94 /*
95 * This is the client side, we should have a station address in "dev"
96 * and we connect to this address.
97 */
98 return(bristolMidiTCPActive(host, flags, chan, msgs, callback,
99 param, dev, handle));
100 }
101 }
102
103 int
bristolMidiTCPActive(char * host,int conntype,int chan,int msgs,int (* callback)(),void * param,int dev,int handle)104 bristolMidiTCPActive(char *host, int conntype, int chan, int msgs,
105 int (*callback)(), void *param, int dev, int handle)
106 {
107 struct linger blinger;
108
109 #ifdef DEBUG
110 printf("bristolMidiTCPActive(%s, %i)\n", host, handle);
111 #endif
112
113 if ((conntype & BRISTOL_CONN_UNIX) ||
114 ((strncmp("unix", host, 4) == 0)
115 && (strlen(host) > 4)
116 && (host[4] == ':')))
117 conntype = 0;
118 else
119 conntype = 1;
120
121 /*
122 * Otherwise try and find a device that is free.
123 if ((dev = bristolMidiFindDev(NULL)) < 0)
124 return(dev);
125 */
126
127 bmidi.dev[dev].flags |= BRISTOL_CONN_TCP;
128
129 if (chan == -1)
130 chan = 5028;
131
132 if (conntype)
133 {
134 if ((bmidi.dev[dev].fd = initControlPort(host, chan)) < 0)
135 {
136 printf("connfailed\n");
137 return(BRISTOL_MIDI_CHANNEL);
138 }
139 bmidi.dev[dev].flags = BRISTOL_CONN_TCP;
140 } else {
141 /*
142 * We need to open a control socket to the bristol engine. For the time
143 * being we will only be concerned with a unix domain socket.
144 */
145 if ((bmidi.dev[dev].fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
146 {
147 printf("Could not get a socket\n");
148 exit(-2);
149 }
150
151 #ifdef DEBUG
152 printf("Opened the bristol control socket: %i\n", bmidi.dev[dev].fd);
153 #endif
154
155 address.sa_family = AF_LOCAL;
156 if ((strlen(host) > 5) && (host[4] == ':'))
157 snprintf(bristol_sockname, 128, "/tmp/br.%s", &host[5]);
158 else
159 snprintf(bristol_sockname, 128, "%s", BRISTOL_SOCKNAME);
160
161 snprintf(&address.sa_data[0], 14, "%s", bristol_sockname);
162
163 if (connect(bmidi.dev[dev].fd, &address, sizeof(struct sockaddr)) < 0)
164 {
165 printf("Could not connect to the bristol control socket\n");
166 return(BRISTOL_MIDI_CHANNEL);
167 }
168 bmidi.dev[dev].flags = BRISTOL_CONN_TCP;
169 }
170
171 printf("Connected to the bristol control socket: %i (dev=%i)\n",
172 bmidi.dev[dev].fd, dev);
173
174 blinger.l_onoff = 1;
175 blinger.l_linger = 2;
176
177 if (setsockopt(bmidi.dev[dev].fd, SOL_SOCKET, SO_LINGER,
178 &blinger, sizeof(struct linger)) < 0)
179 printf("client linger failed\n");
180
181 return(handle);
182 }
183
184 /*
185 * select for data on every TCP connection. Hm, this is problematic for the
186 * monolithic process as it owns all the sockets.
187 */
188 int
bristolMidiTCPRead(bristolMidiMsg * msg)189 bristolMidiTCPRead(bristolMidiMsg *msg)
190 {
191 int parsed, dev, offset, space, dc = 0;
192 struct timeval timeout;
193 fd_set read_set[BRISTOL_MIDI_DEVCOUNT << 1];
194
195 #ifdef DEBUG
196 printf("bristolMidiTCPRead()\n");
197 #endif
198
199 FD_ZERO(read_set);
200
201 /*
202 * Find ports of type TCP, see if they have buffer spaace then schedule them
203 * to be read.
204 */
205 for (dev = 0; dev < BRISTOL_MIDI_DEVCOUNT; dev++)
206 {
207 /* Only want TCP data connections */
208 if ((bmidi.dev[dev].fd > 0)
209 && (BRISTOL_MIDI_BUFSIZE - bmidi.dev[dev].bufcount > 0)
210 && ((bmidi.dev[dev].flags & BRISTOL_CONTROL_SOCKET) == 0)
211 && (bmidi.dev[dev].flags & BRISTOL_CONN_TCP))
212 {
213 FD_SET(bmidi.dev[dev].fd, read_set);
214 dc++;
215 }
216 }
217
218 /* This is really just a poll operation */
219 timeout.tv_sec = 0;
220 timeout.tv_usec = 1000;
221
222 if (dc == 0)
223 return(-1);
224
225 if (select(dev + 1, read_set, NULL, NULL, &timeout) == 0)
226 return(0);
227
228 /* We have data somewhere. Get it */
229 for (dev = 0; dev < BRISTOL_MIDI_DEVCOUNT; dev++)
230 {
231 if (bmidi.dev[dev].fd < 0)
232 continue;
233 if (FD_ISSET(bmidi.dev[dev].fd, read_set))
234 {
235 if ((offset = bmidi.dev[dev].bufindex + bmidi.dev[dev].bufcount)
236 >= BRISTOL_MIDI_BUFSIZE)
237 offset -= BRISTOL_MIDI_BUFSIZE;
238
239 if ((space = BRISTOL_MIDI_BUFSIZE - offset)
240 > sizeof(bristolMidiMsg))
241 space = sizeof(bristolMidiMsg);
242
243 if ((space =
244 read(bmidi.dev[dev].fd, &bmidi.dev[dev].buffer[offset], space))
245 < 0)
246 {
247 printf("no data in tcp buffer for %i (close)\n", dev);
248 msg->command = -1;
249 /*
250 * We should consider closing whatever synth was listening
251 * here. This would require build an EXIT message.
252 */
253 return(BRISTOL_MIDI_DEV);
254 }
255
256 /*
257 int j;
258 printf("read");
259 for (j = 0; j < space; j++)
260 printf(" %x", bmidi.dev[dev].buffer[offset + j]);
261 printf("\n");
262 */
263
264 bmidi.dev[dev].bufcount+=space;
265
266 /*
267 * I really want to parse these, and then forward the messages to
268 * callback routines registered by the bristolMidiOpen() command.
269 */
270 while ((parsed = bristolMidiRawToMsg(&bmidi.dev[dev].buffer[0],
271 bmidi.dev[dev].bufcount, bmidi.dev[dev].bufindex, dev, msg))
272 > 0)
273 {
274 /*
275 * Reduce count of available space.
276 */
277 if ((bmidi.dev[dev].bufcount -= parsed) < 0)
278 {
279 /*
280 * We have an issue here, count has gone negative. Reset
281 * all buffer pointers, and just write an error for now.
282 */
283 bmidi.dev[dev].bufcount = 0;
284 bmidi.dev[dev].bufindex = 0;
285 printf("Issue with buffer capacity going negative\n");
286 }
287 /*
288 * Wrap index as necessary.
289 */
290 if ((bmidi.dev[dev].bufindex += parsed) >= BRISTOL_MIDI_BUFSIZE)
291 bmidi.dev[dev].bufindex -= BRISTOL_MIDI_BUFSIZE;
292
293 /*
294 * We should now go through all the handles, and find out who
295 * has registered for these events - then forward them the event
296 * via the callback. For now we are just going to send it to the
297 * one existing callback.
298 */
299 msg->params.bristol.from = dev;
300 /* bristolMidiToGM2(msg); */
301
302 if (msg->params.bristol.msgLen == 0)
303 msg->params.bristol.msgLen = parsed;
304
305 if (msg->command != 0x0ff)
306 {
307 //if ((msg->command == 0xc0) || (msg->command == 0xc0))
308 //printf("tcp comm %x %i\n", msg->command, msg->params.program.p_id);
309
310 checkcallbacks(msg);
311 }
312
313 msg->command = -1;
314 }
315 }
316 }
317
318 return(1);
319 }
320
321