1 /* $OpenBSD: opt.c,v 1.8 2021/03/03 10:19:06 ratchov Exp $ */ 2 /* 3 * Copyright (c) 2008-2011 Alexandre Ratchov <alex@caoua.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <string.h> 18 19 #include "dev.h" 20 #include "midi.h" 21 #include "opt.h" 22 #include "sysex.h" 23 #include "utils.h" 24 25 struct opt *opt_list; 26 27 void opt_midi_imsg(void *, unsigned char *, int); 28 void opt_midi_omsg(void *, unsigned char *, int); 29 void opt_midi_fill(void *, int); 30 void opt_midi_exit(void *); 31 32 struct midiops opt_midiops = { 33 opt_midi_imsg, 34 opt_midi_omsg, 35 opt_midi_fill, 36 opt_midi_exit 37 }; 38 39 void 40 opt_midi_imsg(void *arg, unsigned char *msg, int len) 41 { 42 #ifdef DEBUG 43 struct opt *o = arg; 44 45 log_puts(o->name); 46 log_puts(": can't receive midi messages\n"); 47 panic(); 48 #endif 49 } 50 51 void 52 opt_midi_omsg(void *arg, unsigned char *msg, int len) 53 { 54 struct opt *o = arg; 55 struct sysex *x; 56 unsigned int fps, chan; 57 58 if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) { 59 chan = msg[0] & MIDI_CHANMASK; 60 if (chan >= DEV_NSLOT) 61 return; 62 if (slot_array[chan].opt == NULL || 63 slot_array[chan].opt->dev != o->dev) 64 return; 65 slot_setvol(slot_array + chan, msg[2]); 66 ctl_onval(CTL_SLOT_LEVEL, slot_array + chan, NULL, msg[2]); 67 return; 68 } 69 x = (struct sysex *)msg; 70 if (x->start != SYSEX_START) 71 return; 72 if (len < SYSEX_SIZE(empty)) 73 return; 74 switch (x->type) { 75 case SYSEX_TYPE_RT: 76 if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) { 77 if (len == SYSEX_SIZE(master)) { 78 dev_master(o->dev, x->u.master.coarse); 79 if (o->dev->master_enabled) { 80 ctl_onval(CTL_DEV_MASTER, o->dev, NULL, 81 x->u.master.coarse); 82 } 83 } 84 return; 85 } 86 if (x->id0 != SYSEX_MMC) 87 return; 88 switch (x->id1) { 89 case SYSEX_MMC_STOP: 90 if (len != SYSEX_SIZE(stop)) 91 return; 92 if (o->mtc == NULL) 93 return; 94 if (log_level >= 2) { 95 log_puts(o->name); 96 log_puts(": mmc stop\n"); 97 } 98 mtc_stop(o->mtc); 99 break; 100 case SYSEX_MMC_START: 101 if (len != SYSEX_SIZE(start)) 102 return; 103 if (o->mtc == NULL) 104 return; 105 if (log_level >= 2) { 106 log_puts(o->name); 107 log_puts(": mmc start\n"); 108 } 109 mtc_start(o->mtc); 110 break; 111 case SYSEX_MMC_LOC: 112 if (len != SYSEX_SIZE(loc) || 113 x->u.loc.len != SYSEX_MMC_LOC_LEN || 114 x->u.loc.cmd != SYSEX_MMC_LOC_CMD) 115 return; 116 if (o->mtc == NULL) 117 return; 118 switch (x->u.loc.hr >> 5) { 119 case MTC_FPS_24: 120 fps = 24; 121 break; 122 case MTC_FPS_25: 123 fps = 25; 124 break; 125 case MTC_FPS_30: 126 fps = 30; 127 break; 128 default: 129 mtc_stop(o->mtc); 130 return; 131 } 132 mtc_loc(o->mtc, 133 (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC + 134 x->u.loc.min * 60 * MTC_SEC + 135 x->u.loc.sec * MTC_SEC + 136 x->u.loc.fr * (MTC_SEC / fps)); 137 break; 138 } 139 break; 140 case SYSEX_TYPE_EDU: 141 if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ) 142 return; 143 if (len != SYSEX_SIZE(dumpreq)) 144 return; 145 dev_midi_dump(o->dev); 146 break; 147 } 148 } 149 150 void 151 opt_midi_fill(void *arg, int count) 152 { 153 /* nothing to do */ 154 } 155 156 void 157 opt_midi_exit(void *arg) 158 { 159 struct opt *o = arg; 160 161 if (log_level >= 1) { 162 log_puts(o->name); 163 log_puts(": midi end point died\n"); 164 panic(); 165 } 166 } 167 168 /* 169 * create a new audio sub-device "configuration" 170 */ 171 struct opt * 172 opt_new(struct dev *d, char *name, 173 int pmin, int pmax, int rmin, int rmax, 174 int maxweight, int mmc, int dup, unsigned int mode) 175 { 176 struct opt *o, **po; 177 unsigned int len, num; 178 char c; 179 180 for (len = 0; name[len] != '\0'; len++) { 181 if (len == OPT_NAMEMAX) { 182 log_puts(name); 183 log_puts(": too long\n"); 184 return NULL; 185 } 186 c = name[len]; 187 if ((c < 'a' || c > 'z') && 188 (c < 'A' || c > 'Z')) { 189 log_puts(name); 190 log_puts(": only alphabetic chars allowed\n"); 191 return NULL; 192 } 193 } 194 num = 0; 195 for (po = &opt_list; *po != NULL; po = &(*po)->next) 196 num++; 197 if (num >= OPT_NMAX) { 198 log_puts(name); 199 log_puts(": too many opts\n"); 200 return NULL; 201 } 202 if (opt_byname(d, name)) { 203 dev_log(d); 204 log_puts("."); 205 log_puts(name); 206 log_puts(": already defined\n"); 207 return NULL; 208 } 209 210 if (mmc) { 211 if (mtc_array[0].dev != NULL && mtc_array[0].dev != d) { 212 log_puts(name); 213 log_puts(": MTC already setup for another device\n"); 214 return NULL; 215 } 216 mtc_array[0].dev = d; 217 if (log_level >= 2) { 218 dev_log(d); 219 log_puts(": initial MTC source, controlled by MMC\n"); 220 } 221 } 222 223 o = xmalloc(sizeof(struct opt)); 224 o->num = num; 225 o->dev = d; 226 227 /* 228 * XXX: below, we allocate a midi input buffer, since we don't 229 * receive raw midi data, so no need to allocate a input 230 * ibuf. Possibly set imsg & fill callbacks to NULL and 231 * use this to in midi_new() to check if buffers need to be 232 * allocated 233 */ 234 o->midi = midi_new(&opt_midiops, o, MODE_MIDIIN | MODE_MIDIOUT); 235 midi_tag(o->midi, o->num); 236 237 if (mode & MODE_PLAY) { 238 o->pmin = pmin; 239 o->pmax = pmax; 240 } 241 if (mode & MODE_RECMASK) { 242 o->rmin = rmin; 243 o->rmax = rmax; 244 } 245 o->maxweight = maxweight; 246 o->mtc = mmc ? &mtc_array[0] : NULL; 247 o->dup = dup; 248 o->mode = mode; 249 memcpy(o->name, name, len + 1); 250 o->next = *po; 251 *po = o; 252 if (log_level >= 2) { 253 dev_log(d); 254 log_puts("."); 255 log_puts(o->name); 256 log_puts(":"); 257 if (o->mode & MODE_REC) { 258 log_puts(" rec="); 259 log_putu(o->rmin); 260 log_puts(":"); 261 log_putu(o->rmax); 262 } 263 if (o->mode & MODE_PLAY) { 264 log_puts(" play="); 265 log_putu(o->pmin); 266 log_puts(":"); 267 log_putu(o->pmax); 268 log_puts(" vol="); 269 log_putu(o->maxweight); 270 } 271 if (o->mode & MODE_MON) { 272 log_puts(" mon="); 273 log_putu(o->rmin); 274 log_puts(":"); 275 log_putu(o->rmax); 276 } 277 if (o->mode & (MODE_RECMASK | MODE_PLAY)) { 278 if (o->mtc) 279 log_puts(" mtc"); 280 if (o->dup) 281 log_puts(" dup"); 282 } 283 log_puts("\n"); 284 } 285 return o; 286 } 287 288 struct opt * 289 opt_byname(struct dev *d, char *name) 290 { 291 struct opt *o; 292 293 for (o = opt_list; o != NULL; o = o->next) { 294 if (d != NULL && o->dev != d) 295 continue; 296 if (strcmp(name, o->name) == 0) 297 return o; 298 } 299 return NULL; 300 } 301 302 void 303 opt_del(struct opt *o) 304 { 305 struct opt **po; 306 307 for (po = &opt_list; *po != o; po = &(*po)->next) { 308 #ifdef DEBUG 309 if (*po == NULL) { 310 log_puts("opt_del: not on list\n"); 311 panic(); 312 } 313 #endif 314 } 315 midi_del(o->midi); 316 *po = o->next; 317 xfree(o); 318 } 319