Annotation of src/usr.bin/sndiod/opt.c, Revision 1.8
1.8 ! ratchov 1: /* $OpenBSD: opt.c,v 1.7 2021/03/03 10:13:06 ratchov Exp $ */
1.1 ratchov 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"
1.7 ratchov 20: #include "midi.h"
1.1 ratchov 21: #include "opt.h"
1.7 ratchov 22: #include "sysex.h"
1.1 ratchov 23: #include "utils.h"
24:
1.5 ratchov 25: struct opt *opt_list;
26:
1.7 ratchov 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;
1.8 ! ratchov 92: if (o->mtc == NULL)
1.7 ratchov 93: return;
94: if (log_level >= 2) {
95: log_puts(o->name);
96: log_puts(": mmc stop\n");
97: }
1.8 ! ratchov 98: mtc_stop(o->mtc);
1.7 ratchov 99: break;
100: case SYSEX_MMC_START:
101: if (len != SYSEX_SIZE(start))
102: return;
1.8 ! ratchov 103: if (o->mtc == NULL)
1.7 ratchov 104: return;
105: if (log_level >= 2) {
106: log_puts(o->name);
107: log_puts(": mmc start\n");
108: }
1.8 ! ratchov 109: mtc_start(o->mtc);
1.7 ratchov 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;
1.8 ! ratchov 116: if (o->mtc == NULL)
1.7 ratchov 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:
1.8 ! ratchov 129: mtc_stop(o->mtc);
1.7 ratchov 130: return;
131: }
1.8 ! ratchov 132: mtc_loc(o->mtc,
1.7 ratchov 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:
1.1 ratchov 168: /*
169: * create a new audio sub-device "configuration"
170: */
171: struct opt *
1.4 ratchov 172: opt_new(struct dev *d, char *name,
1.1 ratchov 173: int pmin, int pmax, int rmin, int rmax,
174: int maxweight, int mmc, int dup, unsigned int mode)
175: {
1.6 ratchov 176: struct opt *o, **po;
177: unsigned int len, num;
1.1 ratchov 178: char c;
179:
180: for (len = 0; name[len] != '\0'; len++) {
181: if (len == OPT_NAMEMAX) {
1.3 ratchov 182: log_puts(name);
183: log_puts(": too long\n");
184: return NULL;
1.1 ratchov 185: }
186: c = name[len];
187: if ((c < 'a' || c > 'z') &&
188: (c < 'A' || c > 'Z')) {
1.3 ratchov 189: log_puts(name);
190: log_puts(": only alphabetic chars allowed\n");
191: return NULL;
1.1 ratchov 192: }
193: }
1.6 ratchov 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: }
1.8 ! ratchov 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:
1.1 ratchov 223: o = xmalloc(sizeof(struct opt));
1.6 ratchov 224: o->num = num;
1.5 ratchov 225: o->dev = d;
1.7 ratchov 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:
1.1 ratchov 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;
1.8 ! ratchov 246: o->mtc = mmc ? &mtc_array[0] : NULL;
1.1 ratchov 247: o->dup = dup;
248: o->mode = mode;
249: memcpy(o->name, name, len + 1);
1.6 ratchov 250: o->next = *po;
251: *po = o;
1.1 ratchov 252: if (log_level >= 2) {
1.4 ratchov 253: dev_log(d);
1.1 ratchov 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)) {
1.8 ! ratchov 278: if (o->mtc)
! 279: log_puts(" mtc");
1.1 ratchov 280: if (o->dup)
281: log_puts(" dup");
282: }
283: log_puts("\n");
284: }
285: return o;
286: }
287:
288: struct opt *
1.4 ratchov 289: opt_byname(struct dev *d, char *name)
1.1 ratchov 290: {
291: struct opt *o;
292:
1.5 ratchov 293: for (o = opt_list; o != NULL; o = o->next) {
294: if (d != NULL && o->dev != d)
295: continue;
1.1 ratchov 296: if (strcmp(name, o->name) == 0)
297: return o;
298: }
299: return NULL;
300: }
301:
302: void
1.5 ratchov 303: opt_del(struct opt *o)
1.1 ratchov 304: {
305: struct opt **po;
306:
1.5 ratchov 307: for (po = &opt_list; *po != o; po = &(*po)->next) {
1.1 ratchov 308: #ifdef DEBUG
309: if (*po == NULL) {
310: log_puts("opt_del: not on list\n");
311: panic();
312: }
313: #endif
314: }
1.7 ratchov 315: midi_del(o->midi);
1.1 ratchov 316: *po = o->next;
317: xfree(o);
318: }