1 2 /* 3 # Sfront, a SAOL to C translator 4 # This file: aucontrol control driver for sfront 5 # 6 # Copyright (c) 1999-2006, Regents of the University of California 7 # All rights reserved. 8 # 9 # Redistribution and use in source and binary forms, with or without 10 # modification, are permitted provided that the following conditions are 11 # met: 12 # 13 # Redistributions of source code must retain the above copyright 14 # notice, this list of conditions and the following disclaimer. 15 # 16 # Redistributions in binary form must reproduce the above copyright 17 # notice, this list of conditions and the following disclaimer in the 18 # documentation and/or other materials provided with the distribution. 19 # 20 # Neither the name of the University of California, Berkeley nor the 21 # names of its contributors may be used to endorse or promote products 22 # derived from this software without specific prior written permission. 23 # 24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 # 36 # Maintainer: John Lazzaro, lazzaro@cs.berkeley.edu 37 */ 38 39 /****************************************************************/ 40 /****************************************************************/ 41 /* audiounit control driver for sfront */ 42 /****************************************************************/ 43 44 /*~~~~~~~~~~~~~~~~~*/ 45 /* include headers */ 46 /*_________________*/ 47 48 /* for socket system */ 49 50 #include <sys/types.h> 51 #include <sys/socket.h> 52 #include <unistd.h> 53 #include <sys/uio.h> 54 #include <fcntl.h> 55 56 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 57 /* MIDI event constants */ 58 /* Must match audiounit.c versions */ 59 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 60 61 /* retry limit for socket writing */ 62 63 #define CSYSI_AUCONTROL_RETRY_MAX 256 64 65 /* bitfield constants for MIDIevent flags variable */ 66 67 #define CSYSI_AUCONTROL_MIDIFLAGS_WAITING 0x01u /* queuing flag bit */ 68 69 /* bitfield constants for SASLevent flags variable */ 70 71 #define CSYSI_AUCONTROL_SASLFLAGS_WAITING 0x01u /* queuing flag bit */ 72 73 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 74 /* typedef for MIDI events */ 75 /* Fields & order must match */ 76 /* asysn_audiounit_MIDIevent */ 77 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 78 79 typedef struct csysi_aucontrol_MIDIevent { 80 unsigned char cmd; 81 unsigned char d0; 82 unsigned char d1; 83 unsigned char flags; 84 int kcycleidx; 85 } csysi_aucontrol_MIDIevent; 86 87 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 88 /* typedef for SASL events */ 89 /* Fields & order must match */ 90 /* asysn_audiounit_SASLevent */ 91 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 92 93 typedef struct csysi_aucontrol_SASLevent { 94 int index; 95 Float32 value; 96 unsigned char flags; 97 int kcycleidx; 98 } csysi_aucontrol_SASLevent; 99 100 /*~~~~~~~~~~~~~~~~~*/ 101 /* aucontrol state */ 102 /*~~~~~~~~~~~~~~~~~*/ 103 104 typedef struct csysi_aucontrol_state { 105 int mpipe; 106 csysi_aucontrol_MIDIevent nextMIDIevent; 107 int spipe; 108 csysi_aucontrol_SASLevent nextSASLevent; 109 } csysi_aucontrol_state; 110 111 /*~~~~~~~~~~~~~~~~~~~~~~~~~*/ 112 /* helper function externs */ 113 /*_________________________*/ 114 115 extern int csysi_aucontrol_midievent_read(csysi_aucontrol_state * mystate); 116 extern int csysi_aucontrol_saslevent_read(csysi_aucontrol_state * mystate); 117 118 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 119 /* high-level functions: called by sfront engine */ 120 /*______________________________________________________________*/ 121 122 /****************************************************************/ 123 /* initialization routine for control */ 124 /****************************************************************/ 125 126 int csys_setup(ENGINE_PTR_DECLARE) 127 128 { 129 csysi_aucontrol_state * mystate; 130 int msize; 131 char message[256]; 132 133 msize = sizeof(csysi_aucontrol_state); 134 if (!(mystate = calloc(1, msize))) 135 return CSYS_ERROR; 136 asysn_audiounit_memstatus(mystate, msize, MADV_WILLNEED); 137 138 EV(csys_state) = (void *) mystate; 139 140 if ((EV(csys_argc) == 5) && 141 !strcmp(EV(csys_argv)[1], "-asys_audiounit_mpipe") && 142 !strcmp(EV(csys_argv)[3], "-asys_audiounit_spipe")) 143 { 144 mystate->mpipe = atoi(EV(csys_argv[2])); 145 mystate->spipe = atoi(EV(csys_argv[4])); 146 } 147 148 sprintf(message, "Opening aucontrol driver for %s\n\n", 149 (EV(csys_argc) >= 1) ? EV(csys_argv)[0] : "(unknown)"); 150 151 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING(message); 152 153 return CSYS_DONE; 154 } 155 156 /****************************************************************/ 157 /* polling routine for new data */ 158 /****************************************************************/ 159 160 int csys_newdata(ENGINE_PTR_DECLARE) 161 162 { 163 csysi_aucontrol_state * mystate = (csysi_aucontrol_state *) EV(csys_state); 164 int has_midi, has_sasl; 165 166 #if defined(CSYS_CDRIVER_AUCONTROLM) 167 has_midi = (mystate->nextMIDIevent.flags & CSYSI_AUCONTROL_MIDIFLAGS_WAITING) || 168 (csysi_aucontrol_midievent_read(mystate) == CSYS_MIDIEVENTS); 169 #else 170 has_midi = 0; 171 #endif 172 173 has_sasl = (mystate->nextSASLevent.flags & CSYSI_AUCONTROL_SASLFLAGS_WAITING) || 174 (csysi_aucontrol_saslevent_read(mystate) == CSYS_SASLEVENTS); 175 176 if (!(has_midi || has_sasl)) /* quick exit in common case */ 177 return CSYS_NONE; 178 179 has_midi = has_midi && (mystate->nextMIDIevent.kcycleidx <= EV(kcycleidx)); 180 has_sasl = has_sasl && (mystate->nextSASLevent.kcycleidx <= EV(kcycleidx)); 181 182 if (!(has_midi || has_sasl)) 183 return CSYS_NONE; 184 185 if (has_midi && has_sasl) 186 return CSYS_EVENTS; 187 188 #if defined(CSYS_CDRIVER_AUCONTROLM) 189 if (has_midi) 190 return CSYS_MIDIEVENTS; 191 #endif 192 193 if (has_sasl) 194 return CSYS_SASLEVENTS; 195 } 196 197 198 #if defined(CSYS_CDRIVER_AUCONTROLM) 199 200 /****************************************************************/ 201 /* processes a MIDI event */ 202 /****************************************************************/ 203 204 int csys_midievent(ENGINE_PTR_DECLARE_COMMA unsigned char * cmd, 205 unsigned char * ndata, unsigned char * vdata, 206 unsigned short * extchan, float * fval) 207 208 { 209 csysi_aucontrol_state * mystate = (csysi_aucontrol_state *) EV(csys_state); 210 211 if ((*cmd = mystate->nextMIDIevent.cmd) < CSYS_MIDI_SYSTEM) 212 { 213 *extchan = (*cmd) & 0x0Fu; 214 *ndata = mystate->nextMIDIevent.d0; 215 *vdata = mystate->nextMIDIevent.d1; 216 } 217 else 218 *cmd = CSYS_MIDI_NOOP; /* filter MIDI System commands */ 219 220 if (csysi_aucontrol_midievent_read(mystate) == CSYS_NONE) 221 { 222 mystate->nextMIDIevent.flags &= ~(CSYSI_AUCONTROL_MIDIFLAGS_WAITING); 223 return CSYS_NONE; 224 } 225 226 if (mystate->nextMIDIevent.kcycleidx <= EV(kcycleidx)) 227 return CSYS_MIDIEVENTS; 228 229 return CSYS_NONE; 230 } 231 232 #endif 233 234 /****************************************************************/ 235 /* processes a SASL event */ 236 /****************************************************************/ 237 238 int csys_saslevent(ENGINE_PTR_DECLARE_COMMA unsigned char * cmd, 239 unsigned char * priority, unsigned short * id, 240 unsigned short * label, float * fval, 241 unsigned int * pnum, float ** p) 242 243 { 244 csysi_aucontrol_state * mystate = (csysi_aucontrol_state *) EV(csys_state); 245 246 *cmd = CSYS_SASL_CONTROL; 247 *priority = 1; 248 *id = CSYS_SASL_NOINSTR; 249 *label = CSYS_NOLABEL; 250 *pnum = mystate->nextSASLevent.index; 251 *fval = mystate->nextSASLevent.value; 252 253 if (csysi_aucontrol_saslevent_read(mystate) == CSYS_NONE) 254 { 255 mystate->nextSASLevent.flags &= ~(CSYSI_AUCONTROL_SASLFLAGS_WAITING); 256 return CSYS_NONE; 257 } 258 259 if (mystate->nextSASLevent.kcycleidx <= EV(kcycleidx)) 260 return CSYS_SASLEVENTS; 261 262 return CSYS_NONE; 263 } 264 265 266 /****************************************************************/ 267 /* closing routine for control */ 268 /****************************************************************/ 269 270 void csys_shutdown(ENGINE_PTR_DECLARE) 271 272 { 273 csysi_aucontrol_state * mystate = (csysi_aucontrol_state *) EV(csys_state); 274 int msize; 275 char message[256]; 276 277 /* flush unprocessed events from MIDI and SASL pipes */ 278 279 #if defined(CSYS_CDRIVER_AUCONTROLM) 280 do { } while (csysi_aucontrol_midievent_read(mystate) != CSYS_NONE); 281 #endif 282 do { } while (csysi_aucontrol_saslevent_read(mystate) != CSYS_NONE); 283 284 /* log driver close, and free mystate */ 285 286 sprintf(message, "Closing aucontrol driver for %s\n\n", 287 (EV(csys_argc) >= 1) ? EV(csys_argv)[0] : "(unknown)"); 288 289 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING(message); 290 291 msize = sizeof(csysi_aucontrol_state); 292 asysn_audiounit_memstatus(mystate, msize, MADV_FREE); 293 free(mystate); 294 295 return; 296 } 297 298 299 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 300 /* helper functions */ 301 /*______________________________________________________________*/ 302 303 #if defined(CSYS_CDRIVER_AUCONTROLM) 304 305 /****************************************************************/ 306 /* read a MIDI event from the socket */ 307 /****************************************************************/ 308 309 int csysi_aucontrol_midievent_read(csysi_aucontrol_state * mystate) 310 311 { 312 int retry = 0; 313 int len; 314 315 if (mystate->mpipe == 0) 316 return CSYS_NONE; /* no mpipe, so no MIDIevents */ 317 318 do { 319 320 if (((len = read(mystate->mpipe, &(mystate->nextMIDIevent), 321 sizeof(csysi_aucontrol_MIDIevent))) < 0) && (errno == EAGAIN)) 322 return CSYS_NONE; /* no MIDIevents in mpipe */ 323 324 if (len == sizeof(csysi_aucontrol_MIDIevent)) 325 return CSYS_MIDIEVENTS; /* a MIDIevent was read */ 326 327 if ((len >= 0) || (errno != EINTR) || (++retry > CSYSI_AUCONTROL_RETRY_MAX)) 328 { 329 if (len == 0) 330 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 331 ("\tError in csys_newdata: read() returned a zero-length MIDIevent\n"); 332 333 if (len > 0) 334 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 335 ("\tError in csys_newdata: read() returned an incomplete MIDIevent\n"); 336 337 if ((len < 0) && (errno != EINTR)) 338 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 339 ("\tError in csys_newdata: errno other than EINTR or EAGAIN (MIDI)\n"); 340 341 if ((len < 0) && (retry > ASYS_AUDIOUNIT_RETRY_MAX)) 342 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 343 ("\tError in csys_newdata: Maximum retry for EINTR exceeded (MIDI)\n"); 344 345 return CSYS_NONE; /* to do: clear flag, consider error reporting */ 346 } 347 348 } while(1); /* loop to try again when (errno == EINTR) */ 349 350 return CSYS_NONE; 351 } 352 353 #endif 354 355 /****************************************************************/ 356 /* read a SASL event from the socket */ 357 /****************************************************************/ 358 359 int csysi_aucontrol_saslevent_read(csysi_aucontrol_state * mystate) 360 361 { 362 int retry = 0; 363 int len; 364 365 if (mystate->spipe == 0) 366 return CSYS_NONE; /* no spipe, so no SASLevents */ 367 368 do { 369 370 if (((len = read(mystate->spipe, &(mystate->nextSASLevent), 371 sizeof(csysi_aucontrol_SASLevent))) < 0) && (errno == EAGAIN)) 372 return CSYS_NONE; /* no SASLevents in spipe */ 373 374 if (len == sizeof(csysi_aucontrol_SASLevent)) 375 return CSYS_SASLEVENTS; /* a SASLevent was read */ 376 377 if ((len >= 0) || (errno != EINTR) || (++retry > CSYSI_AUCONTROL_RETRY_MAX)) 378 { 379 if (len == 0) 380 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 381 ("\tError in csys_newdata: read() returned a zero-length SASLevent\n"); 382 383 if (len > 0) 384 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 385 ("\tError in csys_newdata: read() returned an incomplete SASLevent\n"); 386 387 if ((len < 0) && (errno != EINTR)) 388 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 389 ("\tError in csys_newdata: errno other than EINTR or EAGAIN (SASL)\n"); 390 391 if ((len < 0) && (retry > ASYS_AUDIOUNIT_RETRY_MAX)) 392 ASYS_AUDIOUNIT_WIRETAP_PUTSTRING 393 ("\tError in csys_newdata: Maximum retry for EINTR exceeded (SASL)\n"); 394 395 return CSYS_NONE; /* to do: clear flag, consider error reporting */ 396 } 397 398 } while(1); /* loop to try again when (errno == EINTR) */ 399 400 return CSYS_NONE; 401 } 402