File: | src/usr.bin/sndiod/dev.c |
Warning: | line 2490, column 3 Null pointer passed as 2nd argument to string copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dev.c,v 1.103 2021/11/01 14:43:24 ratchov Exp $ */ | ||||
2 | /* | ||||
3 | * Copyright (c) 2008-2012 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 <stdio.h> | ||||
18 | #include <string.h> | ||||
19 | |||||
20 | #include "abuf.h" | ||||
21 | #include "defs.h" | ||||
22 | #include "dev.h" | ||||
23 | #include "dsp.h" | ||||
24 | #include "siofile.h" | ||||
25 | #include "midi.h" | ||||
26 | #include "opt.h" | ||||
27 | #include "sysex.h" | ||||
28 | #include "utils.h" | ||||
29 | |||||
30 | void zomb_onmove(void *); | ||||
31 | void zomb_onvol(void *); | ||||
32 | void zomb_fill(void *); | ||||
33 | void zomb_flush(void *); | ||||
34 | void zomb_eof(void *); | ||||
35 | void zomb_exit(void *); | ||||
36 | |||||
37 | void dev_mix_badd(struct dev *, struct slot *); | ||||
38 | void dev_mix_adjvol(struct dev *); | ||||
39 | void dev_sub_bcopy(struct dev *, struct slot *); | ||||
40 | |||||
41 | void dev_onmove(struct dev *, int); | ||||
42 | void dev_master(struct dev *, unsigned int); | ||||
43 | void dev_cycle(struct dev *); | ||||
44 | struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, | ||||
45 | unsigned int, unsigned int, unsigned int, unsigned int); | ||||
46 | void dev_adjpar(struct dev *, int, int, int); | ||||
47 | int dev_allocbufs(struct dev *); | ||||
48 | void dev_freebufs(struct dev *); | ||||
49 | int dev_ref(struct dev *); | ||||
50 | void dev_unref(struct dev *); | ||||
51 | int dev_init(struct dev *); | ||||
52 | void dev_done(struct dev *); | ||||
53 | struct dev *dev_bynum(int); | ||||
54 | void dev_del(struct dev *); | ||||
55 | unsigned int dev_roundof(struct dev *, unsigned int); | ||||
56 | void dev_wakeup(struct dev *); | ||||
57 | |||||
58 | void slot_ctlname(struct slot *, char *, size_t); | ||||
59 | void slot_log(struct slot *); | ||||
60 | void slot_del(struct slot *); | ||||
61 | void slot_setvol(struct slot *, unsigned int); | ||||
62 | void slot_ready(struct slot *); | ||||
63 | void slot_allocbufs(struct slot *); | ||||
64 | void slot_freebufs(struct slot *); | ||||
65 | void slot_skip_update(struct slot *); | ||||
66 | void slot_write(struct slot *); | ||||
67 | void slot_read(struct slot *); | ||||
68 | int slot_skip(struct slot *); | ||||
69 | |||||
70 | void ctl_node_log(struct ctl_node *); | ||||
71 | void ctl_log(struct ctl *); | ||||
72 | |||||
73 | struct slotops zomb_slotops = { | ||||
74 | zomb_onmove, | ||||
75 | zomb_onvol, | ||||
76 | zomb_fill, | ||||
77 | zomb_flush, | ||||
78 | zomb_eof, | ||||
79 | zomb_exit | ||||
80 | }; | ||||
81 | |||||
82 | struct ctl *ctl_list = NULL((void*)0); | ||||
83 | struct dev *dev_list = NULL((void*)0); | ||||
84 | unsigned int dev_sndnum = 0; | ||||
85 | |||||
86 | struct ctlslot ctlslot_array[DEV_NCTLSLOT8]; | ||||
87 | struct slot slot_array[DEV_NSLOT8]; | ||||
88 | unsigned int slot_serial; /* for slot allocation */ | ||||
89 | |||||
90 | /* | ||||
91 | * we support/need a single MTC clock source only | ||||
92 | */ | ||||
93 | struct mtc mtc_array[1] = { | ||||
94 | {.dev = NULL((void*)0), .tstate = MTC_STOP1} | ||||
95 | }; | ||||
96 | |||||
97 | void | ||||
98 | slot_array_init(void) | ||||
99 | { | ||||
100 | unsigned int i; | ||||
101 | |||||
102 | for (i = 0; i < DEV_NSLOT8; i++) { | ||||
103 | slot_array[i].unit = i; | ||||
104 | slot_array[i].ops = NULL((void*)0); | ||||
105 | slot_array[i].vol = MIDI_MAXCTL127; | ||||
106 | slot_array[i].opt = NULL((void*)0); | ||||
107 | slot_array[i].serial = slot_serial++; | ||||
108 | memset(slot_array[i].name, 0, SLOT_NAMEMAX8); | ||||
109 | } | ||||
110 | } | ||||
111 | |||||
112 | void | ||||
113 | dev_log(struct dev *d) | ||||
114 | { | ||||
115 | #ifdef DEBUG1 | ||||
116 | static char *pstates[] = { | ||||
117 | "cfg", "ini", "run" | ||||
118 | }; | ||||
119 | #endif | ||||
120 | log_puts("snd"); | ||||
121 | log_putu(d->num); | ||||
122 | #ifdef DEBUG1 | ||||
123 | if (log_level >= 3) { | ||||
124 | log_puts(" pst="); | ||||
125 | log_puts(pstates[d->pstate]); | ||||
126 | } | ||||
127 | #endif | ||||
128 | } | ||||
129 | |||||
130 | void | ||||
131 | slot_ctlname(struct slot *s, char *name, size_t size) | ||||
132 | { | ||||
133 | snprintf(name, size, "%s%u", s->name, s->unit); | ||||
134 | } | ||||
135 | |||||
136 | void | ||||
137 | slot_log(struct slot *s) | ||||
138 | { | ||||
139 | char name[CTL_NAMEMAX16]; | ||||
140 | #ifdef DEBUG1 | ||||
141 | static char *pstates[] = { | ||||
142 | "ini", "sta", "rdy", "run", "stp", "mid" | ||||
143 | }; | ||||
144 | #endif | ||||
145 | slot_ctlname(s, name, CTL_NAMEMAX16); | ||||
146 | log_puts(name); | ||||
147 | #ifdef DEBUG1 | ||||
148 | if (log_level >= 3) { | ||||
149 | log_puts(" vol="); | ||||
150 | log_putu(s->vol); | ||||
151 | if (s->ops) { | ||||
152 | log_puts(",pst="); | ||||
153 | log_puts(pstates[s->pstate]); | ||||
154 | } | ||||
155 | } | ||||
156 | #endif | ||||
157 | } | ||||
158 | |||||
159 | void | ||||
160 | zomb_onmove(void *arg) | ||||
161 | { | ||||
162 | } | ||||
163 | |||||
164 | void | ||||
165 | zomb_onvol(void *arg) | ||||
166 | { | ||||
167 | } | ||||
168 | |||||
169 | void | ||||
170 | zomb_fill(void *arg) | ||||
171 | { | ||||
172 | } | ||||
173 | |||||
174 | void | ||||
175 | zomb_flush(void *arg) | ||||
176 | { | ||||
177 | } | ||||
178 | |||||
179 | void | ||||
180 | zomb_eof(void *arg) | ||||
181 | { | ||||
182 | struct slot *s = arg; | ||||
183 | |||||
184 | #ifdef DEBUG1 | ||||
185 | if (log_level >= 3) { | ||||
186 | slot_log(s); | ||||
187 | log_puts(": zomb_eof\n"); | ||||
188 | } | ||||
189 | #endif | ||||
190 | s->ops = NULL((void*)0); | ||||
191 | } | ||||
192 | |||||
193 | void | ||||
194 | zomb_exit(void *arg) | ||||
195 | { | ||||
196 | #ifdef DEBUG1 | ||||
197 | struct slot *s = arg; | ||||
198 | |||||
199 | if (log_level >= 3) { | ||||
200 | slot_log(s); | ||||
201 | log_puts(": zomb_exit\n"); | ||||
202 | } | ||||
203 | #endif | ||||
204 | } | ||||
205 | |||||
206 | /* | ||||
207 | * Broadcast MIDI data to all opts using this device | ||||
208 | */ | ||||
209 | void | ||||
210 | dev_midi_send(struct dev *d, void *msg, int msglen) | ||||
211 | { | ||||
212 | struct opt *o; | ||||
213 | |||||
214 | for (o = opt_list; o != NULL((void*)0); o = o->next) { | ||||
215 | if (o->dev != d) | ||||
216 | continue; | ||||
217 | midi_send(o->midi, msg, msglen); | ||||
218 | } | ||||
219 | } | ||||
220 | |||||
221 | /* | ||||
222 | * send a quarter frame MTC message | ||||
223 | */ | ||||
224 | void | ||||
225 | mtc_midi_qfr(struct mtc *mtc, int delta) | ||||
226 | { | ||||
227 | unsigned char buf[2]; | ||||
228 | unsigned int data; | ||||
229 | int qfrlen; | ||||
230 | |||||
231 | mtc->delta += delta * MTC_SEC2400; | ||||
232 | qfrlen = mtc->dev->rate * (MTC_SEC2400 / (4 * mtc->fps)); | ||||
233 | while (mtc->delta >= qfrlen) { | ||||
234 | switch (mtc->qfr) { | ||||
235 | case 0: | ||||
236 | data = mtc->fr & 0xf; | ||||
237 | break; | ||||
238 | case 1: | ||||
239 | data = mtc->fr >> 4; | ||||
240 | break; | ||||
241 | case 2: | ||||
242 | data = mtc->sec & 0xf; | ||||
243 | break; | ||||
244 | case 3: | ||||
245 | data = mtc->sec >> 4; | ||||
246 | break; | ||||
247 | case 4: | ||||
248 | data = mtc->min & 0xf; | ||||
249 | break; | ||||
250 | case 5: | ||||
251 | data = mtc->min >> 4; | ||||
252 | break; | ||||
253 | case 6: | ||||
254 | data = mtc->hr & 0xf; | ||||
255 | break; | ||||
256 | case 7: | ||||
257 | data = (mtc->hr >> 4) | (mtc->fps_id << 1); | ||||
258 | /* | ||||
259 | * tick messages are sent 2 frames ahead | ||||
260 | */ | ||||
261 | mtc->fr += 2; | ||||
262 | if (mtc->fr < mtc->fps) | ||||
263 | break; | ||||
264 | mtc->fr -= mtc->fps; | ||||
265 | mtc->sec++; | ||||
266 | if (mtc->sec < 60) | ||||
267 | break; | ||||
268 | mtc->sec = 0; | ||||
269 | mtc->min++; | ||||
270 | if (mtc->min < 60) | ||||
271 | break; | ||||
272 | mtc->min = 0; | ||||
273 | mtc->hr++; | ||||
274 | if (mtc->hr < 24) | ||||
275 | break; | ||||
276 | mtc->hr = 0; | ||||
277 | break; | ||||
278 | default: | ||||
279 | /* NOTREACHED */ | ||||
280 | data = 0; | ||||
281 | } | ||||
282 | buf[0] = 0xf1; | ||||
283 | buf[1] = (mtc->qfr << 4) | data; | ||||
284 | mtc->qfr++; | ||||
285 | mtc->qfr &= 7; | ||||
286 | dev_midi_send(mtc->dev, buf, 2); | ||||
287 | mtc->delta -= qfrlen; | ||||
288 | } | ||||
289 | } | ||||
290 | |||||
291 | /* | ||||
292 | * send a full frame MTC message | ||||
293 | */ | ||||
294 | void | ||||
295 | mtc_midi_full(struct mtc *mtc) | ||||
296 | { | ||||
297 | struct sysex x; | ||||
298 | unsigned int fps; | ||||
299 | |||||
300 | mtc->delta = -MTC_SEC2400 * (int)mtc->dev->bufsz; | ||||
301 | if (mtc->dev->rate % (30 * 4 * mtc->dev->round) == 0) { | ||||
302 | mtc->fps_id = MTC_FPS_303; | ||||
303 | mtc->fps = 30; | ||||
304 | } else if (mtc->dev->rate % (25 * 4 * mtc->dev->round) == 0) { | ||||
305 | mtc->fps_id = MTC_FPS_251; | ||||
306 | mtc->fps = 25; | ||||
307 | } else { | ||||
308 | mtc->fps_id = MTC_FPS_240; | ||||
309 | mtc->fps = 24; | ||||
310 | } | ||||
311 | #ifdef DEBUG1 | ||||
312 | if (log_level >= 3) { | ||||
313 | dev_log(mtc->dev); | ||||
314 | log_puts(": mtc full frame at "); | ||||
315 | log_puti(mtc->delta); | ||||
316 | log_puts(", "); | ||||
317 | log_puti(mtc->fps); | ||||
318 | log_puts(" fps\n"); | ||||
319 | } | ||||
320 | #endif | ||||
321 | fps = mtc->fps; | ||||
322 | mtc->hr = (mtc->origin / (MTC_SEC2400 * 3600)) % 24; | ||||
323 | mtc->min = (mtc->origin / (MTC_SEC2400 * 60)) % 60; | ||||
324 | mtc->sec = (mtc->origin / (MTC_SEC2400)) % 60; | ||||
325 | mtc->fr = (mtc->origin / (MTC_SEC2400 / fps)) % fps; | ||||
326 | |||||
327 | x.start = SYSEX_START0xf0; | ||||
328 | x.type = SYSEX_TYPE_RT0x7f; | ||||
329 | x.dev = SYSEX_DEV_ANY0x7f; | ||||
330 | x.id0 = SYSEX_MTC0x01; | ||||
331 | x.id1 = SYSEX_MTC_FULL0x01; | ||||
332 | x.u.full.hr = mtc->hr | (mtc->fps_id << 5); | ||||
333 | x.u.full.min = mtc->min; | ||||
334 | x.u.full.sec = mtc->sec; | ||||
335 | x.u.full.fr = mtc->fr; | ||||
336 | x.u.full.end = SYSEX_END0xf7; | ||||
337 | mtc->qfr = 0; | ||||
338 | dev_midi_send(mtc->dev, (unsigned char *)&x, SYSEX_SIZE(full)(5 + sizeof(struct sysex_full))); | ||||
339 | } | ||||
340 | |||||
341 | /* | ||||
342 | * send a volume change MIDI message | ||||
343 | */ | ||||
344 | void | ||||
345 | dev_midi_vol(struct dev *d, struct slot *s) | ||||
346 | { | ||||
347 | unsigned char msg[3]; | ||||
348 | |||||
349 | msg[0] = MIDI_CTL0xb0 | (s - slot_array); | ||||
350 | msg[1] = MIDI_CTL_VOL7; | ||||
351 | msg[2] = s->vol; | ||||
352 | dev_midi_send(d, msg, 3); | ||||
353 | } | ||||
354 | |||||
355 | /* | ||||
356 | * send a master volume MIDI message | ||||
357 | */ | ||||
358 | void | ||||
359 | dev_midi_master(struct dev *d) | ||||
360 | { | ||||
361 | struct ctl *c; | ||||
362 | unsigned int master, v; | ||||
363 | struct sysex x; | ||||
364 | |||||
365 | if (d->master_enabled) | ||||
366 | master = d->master; | ||||
367 | else { | ||||
368 | master = 0; | ||||
369 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
370 | if (c->type != CTL_NUM2 || | ||||
371 | strcmp(c->group, d->name) != 0 || | ||||
372 | strcmp(c->node0.name, "output") != 0 || | ||||
373 | strcmp(c->func, "level") != 0) | ||||
374 | continue; | ||||
375 | if (c->u.any.arg0 != d) | ||||
376 | continue; | ||||
377 | v = (c->curval * 127 + c->maxval / 2) / c->maxval; | ||||
378 | if (master < v) | ||||
379 | master = v; | ||||
380 | } | ||||
381 | } | ||||
382 | |||||
383 | memset(&x, 0, sizeof(struct sysex)); | ||||
384 | x.start = SYSEX_START0xf0; | ||||
385 | x.type = SYSEX_TYPE_RT0x7f; | ||||
386 | x.dev = SYSEX_DEV_ANY0x7f; | ||||
387 | x.id0 = SYSEX_CONTROL0x04; | ||||
388 | x.id1 = SYSEX_MASTER0x01; | ||||
389 | x.u.master.fine = 0; | ||||
390 | x.u.master.coarse = master; | ||||
391 | x.u.master.end = SYSEX_END0xf7; | ||||
392 | dev_midi_send(d, (unsigned char *)&x, SYSEX_SIZE(master)(5 + sizeof(struct sysex_master))); | ||||
393 | } | ||||
394 | |||||
395 | /* | ||||
396 | * send a sndiod-specific slot description MIDI message | ||||
397 | */ | ||||
398 | void | ||||
399 | dev_midi_slotdesc(struct dev *d, struct slot *s) | ||||
400 | { | ||||
401 | struct sysex x; | ||||
402 | |||||
403 | memset(&x, 0, sizeof(struct sysex)); | ||||
404 | x.start = SYSEX_START0xf0; | ||||
405 | x.type = SYSEX_TYPE_EDU0x7d; | ||||
406 | x.dev = SYSEX_DEV_ANY0x7f; | ||||
407 | x.id0 = SYSEX_AUCAT0x23; | ||||
408 | x.id1 = SYSEX_AUCAT_SLOTDESC0x01; | ||||
409 | if (s->opt != NULL((void*)0) && s->opt->dev == d) | ||||
410 | slot_ctlname(s, (char *)x.u.slotdesc.name, SYSEX_NAMELEN10); | ||||
411 | x.u.slotdesc.chan = (s - slot_array); | ||||
412 | x.u.slotdesc.end = SYSEX_END0xf7; | ||||
413 | dev_midi_send(d, (unsigned char *)&x, SYSEX_SIZE(slotdesc)(5 + sizeof(struct sysex_slotdesc))); | ||||
414 | } | ||||
415 | |||||
416 | void | ||||
417 | dev_midi_dump(struct dev *d) | ||||
418 | { | ||||
419 | struct sysex x; | ||||
420 | struct slot *s; | ||||
421 | int i; | ||||
422 | |||||
423 | dev_midi_master(d); | ||||
424 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
425 | if (s->opt != NULL((void*)0) && s->opt->dev != d) | ||||
426 | continue; | ||||
427 | dev_midi_slotdesc(d, s); | ||||
428 | dev_midi_vol(d, s); | ||||
429 | } | ||||
430 | x.start = SYSEX_START0xf0; | ||||
431 | x.type = SYSEX_TYPE_EDU0x7d; | ||||
432 | x.dev = SYSEX_DEV_ANY0x7f; | ||||
433 | x.id0 = SYSEX_AUCAT0x23; | ||||
434 | x.id1 = SYSEX_AUCAT_DUMPEND0x03; | ||||
435 | x.u.dumpend.end = SYSEX_END0xf7; | ||||
436 | dev_midi_send(d, (unsigned char *)&x, SYSEX_SIZE(dumpend)(5 + sizeof(struct sysex_dumpend))); | ||||
437 | } | ||||
438 | |||||
439 | int | ||||
440 | slot_skip(struct slot *s) | ||||
441 | { | ||||
442 | unsigned char *data = (unsigned char *)0xdeadbeef; /* please gcc */ | ||||
443 | int max, count; | ||||
444 | |||||
445 | max = s->skip; | ||||
446 | while (s->skip > 0) { | ||||
447 | if (s->pstate != SLOT_STOP4 && (s->mode & MODE_RECMASK(0x02 | 0x10))) { | ||||
448 | data = abuf_wgetblk(&s->sub.buf, &count); | ||||
449 | if (count < s->round * s->sub.bpf) | ||||
450 | break; | ||||
451 | } | ||||
452 | if (s->mode & MODE_PLAY0x01) { | ||||
453 | if (s->mix.buf.used < s->round * s->mix.bpf) | ||||
454 | break; | ||||
455 | } | ||||
456 | #ifdef DEBUG1 | ||||
457 | if (log_level >= 4) { | ||||
458 | slot_log(s); | ||||
459 | log_puts(": skipped a cycle\n"); | ||||
460 | } | ||||
461 | #endif | ||||
462 | if (s->pstate != SLOT_STOP4 && (s->mode & MODE_RECMASK(0x02 | 0x10))) { | ||||
463 | if (s->sub.encbuf) | ||||
464 | enc_sil_do(&s->sub.enc, data, s->round); | ||||
465 | else | ||||
466 | memset(data, 0, s->round * s->sub.bpf); | ||||
467 | abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf); | ||||
468 | } | ||||
469 | if (s->mode & MODE_PLAY0x01) { | ||||
470 | abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); | ||||
471 | } | ||||
472 | s->skip--; | ||||
473 | } | ||||
474 | return max - s->skip; | ||||
475 | } | ||||
476 | |||||
477 | /* | ||||
478 | * Mix the slot input block over the output block | ||||
479 | */ | ||||
480 | void | ||||
481 | dev_mix_badd(struct dev *d, struct slot *s) | ||||
482 | { | ||||
483 | adata_t *idata, *odata, *in; | ||||
484 | int icount, i, offs, vol, nch; | ||||
485 | |||||
486 | odata = DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan); | ||||
487 | idata = (adata_t *)abuf_rgetblk(&s->mix.buf, &icount); | ||||
488 | #ifdef DEBUG1 | ||||
489 | if (icount < s->round * s->mix.bpf) { | ||||
490 | slot_log(s); | ||||
491 | log_puts(": not enough data to mix ("); | ||||
492 | log_putu(icount); | ||||
493 | log_puts("bytes)\n"); | ||||
494 | panic(); | ||||
495 | } | ||||
496 | #endif | ||||
497 | if (!(s->opt->mode & MODE_PLAY0x01)) { | ||||
498 | /* | ||||
499 | * playback not allowed in opt structure, produce silence | ||||
500 | */ | ||||
501 | abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); | ||||
502 | return; | ||||
503 | } | ||||
504 | |||||
505 | |||||
506 | /* | ||||
507 | * Apply the following processing chain: | ||||
508 | * | ||||
509 | * dec -> resamp-> cmap | ||||
510 | * | ||||
511 | * where the first two are optional. | ||||
512 | */ | ||||
513 | |||||
514 | in = idata; | ||||
515 | |||||
516 | if (s->mix.decbuf) { | ||||
517 | dec_do(&s->mix.dec, (void *)in, s->mix.decbuf, s->round); | ||||
518 | in = s->mix.decbuf; | ||||
519 | } | ||||
520 | |||||
521 | if (s->mix.resampbuf) { | ||||
522 | resamp_do(&s->mix.resamp, in, s->mix.resampbuf, s->round); | ||||
523 | in = s->mix.resampbuf; | ||||
524 | } | ||||
525 | |||||
526 | nch = s->mix.cmap.nch; | ||||
527 | vol = ADATA_MUL(s->mix.weight, s->mix.vol)(((int)(s->mix.weight) * (int)(s->mix.vol)) >> (16 - 1)) / s->mix.join; | ||||
528 | cmap_add(&s->mix.cmap, in, odata, vol, d->round); | ||||
529 | |||||
530 | offs = 0; | ||||
531 | for (i = s->mix.join - 1; i > 0; i--) { | ||||
532 | offs += nch; | ||||
533 | cmap_add(&s->mix.cmap, in + offs, odata, vol, d->round); | ||||
534 | } | ||||
535 | |||||
536 | offs = 0; | ||||
537 | for (i = s->mix.expand - 1; i > 0; i--) { | ||||
538 | offs += nch; | ||||
539 | cmap_add(&s->mix.cmap, in, odata + offs, vol, d->round); | ||||
540 | } | ||||
541 | |||||
542 | abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); | ||||
543 | } | ||||
544 | |||||
545 | /* | ||||
546 | * Normalize input levels. | ||||
547 | */ | ||||
548 | void | ||||
549 | dev_mix_adjvol(struct dev *d) | ||||
550 | { | ||||
551 | unsigned int n; | ||||
552 | struct slot *i, *j; | ||||
553 | int jcmax, icmax, weight; | ||||
554 | |||||
555 | for (i = d->slot_list; i != NULL((void*)0); i = i->next) { | ||||
556 | if (!(i->mode & MODE_PLAY0x01)) | ||||
557 | continue; | ||||
558 | icmax = i->opt->pmin + i->mix.nch - 1; | ||||
559 | weight = ADATA_UNIT(1 << (16 - 1)); | ||||
560 | if (d->autovol) { | ||||
561 | /* | ||||
562 | * count the number of inputs that have | ||||
563 | * overlapping channel sets | ||||
564 | */ | ||||
565 | n = 0; | ||||
566 | for (j = d->slot_list; j != NULL((void*)0); j = j->next) { | ||||
567 | if (!(j->mode & MODE_PLAY0x01)) | ||||
568 | continue; | ||||
569 | jcmax = j->opt->pmin + j->mix.nch - 1; | ||||
570 | if (i->opt->pmin <= jcmax && | ||||
571 | icmax >= j->opt->pmin) | ||||
572 | n++; | ||||
573 | } | ||||
574 | weight /= n; | ||||
575 | } | ||||
576 | if (weight > i->opt->maxweight) | ||||
577 | weight = i->opt->maxweight; | ||||
578 | i->mix.weight = d->master_enabled ? | ||||
579 | ADATA_MUL(weight, MIDI_TO_ADATA(d->master))(((int)(weight) * (int)((aparams_ctltovol[d->master] << (16 - 16)))) >> (16 - 1)) : weight; | ||||
580 | #ifdef DEBUG1 | ||||
581 | if (log_level >= 3) { | ||||
582 | slot_log(i); | ||||
583 | log_puts(": set weight: "); | ||||
584 | log_puti(i->mix.weight); | ||||
585 | log_puts("/"); | ||||
586 | log_puti(i->opt->maxweight); | ||||
587 | log_puts("\n"); | ||||
588 | } | ||||
589 | #endif | ||||
590 | } | ||||
591 | } | ||||
592 | |||||
593 | /* | ||||
594 | * Copy data from slot to device | ||||
595 | */ | ||||
596 | void | ||||
597 | dev_sub_bcopy(struct dev *d, struct slot *s) | ||||
598 | { | ||||
599 | adata_t *idata, *enc_out, *resamp_out, *cmap_out; | ||||
600 | void *odata; | ||||
601 | int ocount, moffs; | ||||
602 | |||||
603 | int i, vol, offs, nch; | ||||
604 | |||||
605 | |||||
606 | odata = (adata_t *)abuf_wgetblk(&s->sub.buf, &ocount); | ||||
607 | #ifdef DEBUG1 | ||||
608 | if (ocount < s->round * s->sub.bpf) { | ||||
609 | log_puts("dev_sub_bcopy: not enough space\n"); | ||||
610 | panic(); | ||||
611 | } | ||||
612 | #endif | ||||
613 | if (s->opt->mode & MODE_MON0x10) { | ||||
614 | moffs = d->poffs + d->round; | ||||
615 | if (moffs == d->psize) | ||||
616 | moffs = 0; | ||||
617 | idata = d->pbuf + moffs * d->pchan; | ||||
618 | } else if (s->opt->mode & MODE_REC0x02) { | ||||
619 | idata = d->rbuf; | ||||
620 | } else { | ||||
621 | /* | ||||
622 | * recording not allowed in opt structure, produce silence | ||||
623 | */ | ||||
624 | enc_sil_do(&s->sub.enc, odata, s->round); | ||||
625 | abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf); | ||||
626 | return; | ||||
627 | } | ||||
628 | |||||
629 | /* | ||||
630 | * Apply the following processing chain: | ||||
631 | * | ||||
632 | * cmap -> resamp -> enc | ||||
633 | * | ||||
634 | * where the last two are optional. | ||||
635 | */ | ||||
636 | |||||
637 | enc_out = odata; | ||||
638 | resamp_out = s->sub.encbuf ? s->sub.encbuf : enc_out; | ||||
639 | cmap_out = s->sub.resampbuf ? s->sub.resampbuf : resamp_out; | ||||
640 | |||||
641 | nch = s->sub.cmap.nch; | ||||
642 | vol = ADATA_UNIT(1 << (16 - 1)) / s->sub.join; | ||||
643 | cmap_copy(&s->sub.cmap, idata, cmap_out, vol, d->round); | ||||
644 | |||||
645 | offs = 0; | ||||
646 | for (i = s->sub.join - 1; i > 0; i--) { | ||||
647 | offs += nch; | ||||
648 | cmap_add(&s->sub.cmap, idata + offs, cmap_out, vol, d->round); | ||||
649 | } | ||||
650 | |||||
651 | offs = 0; | ||||
652 | for (i = s->sub.expand - 1; i > 0; i--) { | ||||
653 | offs += nch; | ||||
654 | cmap_copy(&s->sub.cmap, idata, cmap_out + offs, vol, d->round); | ||||
655 | } | ||||
656 | |||||
657 | if (s->sub.resampbuf) { | ||||
658 | resamp_do(&s->sub.resamp, | ||||
659 | s->sub.resampbuf, resamp_out, d->round); | ||||
660 | } | ||||
661 | |||||
662 | if (s->sub.encbuf) | ||||
663 | enc_do(&s->sub.enc, s->sub.encbuf, (void *)enc_out, s->round); | ||||
664 | |||||
665 | abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf); | ||||
666 | } | ||||
667 | |||||
668 | /* | ||||
669 | * run a one block cycle: consume one recorded block from | ||||
670 | * rbuf and produce one play block in pbuf | ||||
671 | */ | ||||
672 | void | ||||
673 | dev_cycle(struct dev *d) | ||||
674 | { | ||||
675 | struct slot *s, **ps; | ||||
676 | unsigned char *base; | ||||
677 | int nsamp; | ||||
678 | |||||
679 | /* | ||||
680 | * check if the device is actually used. If it isn't, | ||||
681 | * then close it | ||||
682 | */ | ||||
683 | if (d->slot_list == NULL((void*)0) && (mtc_array[0].dev != d || | ||||
684 | mtc_array[0].tstate != MTC_RUN3)) { | ||||
685 | if (log_level >= 2) { | ||||
686 | dev_log(d); | ||||
687 | log_puts(": device stopped\n"); | ||||
688 | } | ||||
689 | dev_sio_stop(d); | ||||
690 | d->pstate = DEV_INIT1; | ||||
691 | if (d->refcnt == 0) | ||||
692 | dev_close(d); | ||||
693 | return; | ||||
694 | } | ||||
695 | |||||
696 | if (d->prime > 0) { | ||||
697 | #ifdef DEBUG1 | ||||
698 | if (log_level >= 4) { | ||||
699 | dev_log(d); | ||||
700 | log_puts(": empty cycle, prime = "); | ||||
701 | log_putu(d->prime); | ||||
702 | log_puts("\n"); | ||||
703 | } | ||||
704 | #endif | ||||
705 | base = (unsigned char *)DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan); | ||||
706 | nsamp = d->round * d->pchan; | ||||
707 | memset(base, 0, nsamp * sizeof(adata_t)); | ||||
708 | if (d->encbuf) { | ||||
709 | enc_do(&d->enc, (unsigned char *)DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan), | ||||
710 | d->encbuf, d->round); | ||||
711 | } | ||||
712 | d->prime -= d->round; | ||||
713 | return; | ||||
714 | } | ||||
715 | |||||
716 | d->delta -= d->round; | ||||
717 | #ifdef DEBUG1 | ||||
718 | if (log_level >= 4) { | ||||
719 | dev_log(d); | ||||
720 | log_puts(": full cycle: delta = "); | ||||
721 | log_puti(d->delta); | ||||
722 | if (d->mode & MODE_PLAY0x01) { | ||||
723 | log_puts(", poffs = "); | ||||
724 | log_puti(d->poffs); | ||||
725 | } | ||||
726 | log_puts("\n"); | ||||
727 | } | ||||
728 | #endif | ||||
729 | if (d->mode & MODE_PLAY0x01) { | ||||
730 | base = (unsigned char *)DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan); | ||||
731 | nsamp = d->round * d->pchan; | ||||
732 | memset(base, 0, nsamp * sizeof(adata_t)); | ||||
733 | } | ||||
734 | if ((d->mode & MODE_REC0x02) && d->decbuf) | ||||
735 | dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round); | ||||
736 | ps = &d->slot_list; | ||||
737 | while ((s = *ps) != NULL((void*)0)) { | ||||
738 | #ifdef DEBUG1 | ||||
739 | if (log_level >= 4) { | ||||
740 | slot_log(s); | ||||
741 | log_puts(": running"); | ||||
742 | log_puts(", skip = "); | ||||
743 | log_puti(s->skip); | ||||
744 | log_puts("\n"); | ||||
745 | } | ||||
746 | #endif | ||||
747 | /* | ||||
748 | * skip cycles for XRUN_SYNC correction | ||||
749 | */ | ||||
750 | slot_skip(s); | ||||
751 | if (s->skip < 0) { | ||||
752 | s->skip++; | ||||
753 | ps = &s->next; | ||||
754 | continue; | ||||
755 | } | ||||
756 | |||||
757 | #ifdef DEBUG1 | ||||
758 | if (s->pstate == SLOT_STOP4 && !(s->mode & MODE_PLAY0x01)) { | ||||
759 | slot_log(s); | ||||
760 | log_puts(": rec-only slots can't be drained\n"); | ||||
761 | panic(); | ||||
762 | } | ||||
763 | #endif | ||||
764 | /* | ||||
765 | * check if stopped stream finished draining | ||||
766 | */ | ||||
767 | if (s->pstate == SLOT_STOP4 && | ||||
768 | s->mix.buf.used < s->round * s->mix.bpf) { | ||||
769 | /* | ||||
770 | * partial blocks are zero-filled by socket | ||||
771 | * layer, so s->mix.buf.used == 0 and we can | ||||
772 | * destroy the buffer | ||||
773 | */ | ||||
774 | *ps = s->next; | ||||
775 | s->pstate = SLOT_INIT0; | ||||
776 | s->ops->eof(s->arg); | ||||
777 | slot_freebufs(s); | ||||
778 | dev_mix_adjvol(d); | ||||
779 | #ifdef DEBUG1 | ||||
780 | if (log_level >= 3) { | ||||
781 | slot_log(s); | ||||
782 | log_puts(": drained\n"); | ||||
783 | } | ||||
784 | #endif | ||||
785 | continue; | ||||
786 | } | ||||
787 | |||||
788 | /* | ||||
789 | * check for xruns | ||||
790 | */ | ||||
791 | if (((s->mode & MODE_PLAY0x01) && | ||||
792 | s->mix.buf.used < s->round * s->mix.bpf) || | ||||
793 | ((s->mode & MODE_RECMASK(0x02 | 0x10)) && | ||||
794 | s->sub.buf.len - s->sub.buf.used < | ||||
795 | s->round * s->sub.bpf)) { | ||||
796 | |||||
797 | #ifdef DEBUG1 | ||||
798 | if (log_level >= 3) { | ||||
799 | slot_log(s); | ||||
800 | log_puts(": xrun, pause cycle\n"); | ||||
801 | } | ||||
802 | #endif | ||||
803 | if (s->xrun == XRUN_IGNORE0) { | ||||
804 | s->delta -= s->round; | ||||
805 | ps = &s->next; | ||||
806 | } else if (s->xrun == XRUN_SYNC1) { | ||||
807 | s->skip++; | ||||
808 | ps = &s->next; | ||||
809 | } else if (s->xrun == XRUN_ERROR2) { | ||||
810 | s->ops->exit(s->arg); | ||||
811 | *ps = s->next; | ||||
812 | } else { | ||||
813 | #ifdef DEBUG1 | ||||
814 | slot_log(s); | ||||
815 | log_puts(": bad xrun mode\n"); | ||||
816 | panic(); | ||||
817 | #endif | ||||
818 | } | ||||
819 | continue; | ||||
820 | } | ||||
821 | if ((s->mode & MODE_RECMASK(0x02 | 0x10)) && !(s->pstate == SLOT_STOP4)) { | ||||
822 | if (s->sub.prime == 0) { | ||||
823 | dev_sub_bcopy(d, s); | ||||
824 | s->ops->flush(s->arg); | ||||
825 | } else { | ||||
826 | #ifdef DEBUG1 | ||||
827 | if (log_level >= 3) { | ||||
828 | slot_log(s); | ||||
829 | log_puts(": prime = "); | ||||
830 | log_puti(s->sub.prime); | ||||
831 | log_puts("\n"); | ||||
832 | } | ||||
833 | #endif | ||||
834 | s->sub.prime--; | ||||
835 | } | ||||
836 | } | ||||
837 | if (s->mode & MODE_PLAY0x01) { | ||||
838 | dev_mix_badd(d, s); | ||||
839 | if (s->pstate != SLOT_STOP4) | ||||
840 | s->ops->fill(s->arg); | ||||
841 | } | ||||
842 | ps = &s->next; | ||||
843 | } | ||||
844 | if ((d->mode & MODE_PLAY0x01) && d->encbuf) { | ||||
845 | enc_do(&d->enc, (unsigned char *)DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan), | ||||
846 | d->encbuf, d->round); | ||||
847 | } | ||||
848 | } | ||||
849 | |||||
850 | /* | ||||
851 | * called at every clock tick by the device | ||||
852 | */ | ||||
853 | void | ||||
854 | dev_onmove(struct dev *d, int delta) | ||||
855 | { | ||||
856 | long long pos; | ||||
857 | struct slot *s, *snext; | ||||
858 | |||||
859 | d->delta += delta; | ||||
860 | |||||
861 | for (s = d->slot_list; s != NULL((void*)0); s = snext) { | ||||
862 | /* | ||||
863 | * s->ops->onmove() may remove the slot | ||||
864 | */ | ||||
865 | snext = s->next; | ||||
866 | pos = s->delta_rem + | ||||
867 | (long long)s->delta * d->round + | ||||
868 | (long long)delta * s->round; | ||||
869 | s->delta = pos / (int)d->round; | ||||
870 | s->delta_rem = pos % d->round; | ||||
871 | if (s->delta_rem < 0) { | ||||
872 | s->delta_rem += d->round; | ||||
873 | s->delta--; | ||||
874 | } | ||||
875 | if (s->delta >= 0) | ||||
876 | s->ops->onmove(s->arg); | ||||
877 | } | ||||
878 | |||||
879 | if (mtc_array[0].dev == d && mtc_array[0].tstate == MTC_RUN3) | ||||
880 | mtc_midi_qfr(&mtc_array[0], delta); | ||||
881 | } | ||||
882 | |||||
883 | void | ||||
884 | dev_master(struct dev *d, unsigned int master) | ||||
885 | { | ||||
886 | struct ctl *c; | ||||
887 | unsigned int v; | ||||
888 | |||||
889 | if (log_level >= 2) { | ||||
890 | dev_log(d); | ||||
891 | log_puts(": master volume set to "); | ||||
892 | log_putu(master); | ||||
893 | log_puts("\n"); | ||||
894 | } | ||||
895 | if (d->master_enabled) { | ||||
896 | d->master = master; | ||||
897 | if (d->mode & MODE_PLAY0x01) | ||||
898 | dev_mix_adjvol(d); | ||||
899 | } else { | ||||
900 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
901 | if (c->scope != CTL_HW0 || c->u.hw.dev != d) | ||||
902 | continue; | ||||
903 | if (c->type != CTL_NUM2 || | ||||
904 | strcmp(c->group, d->name) != 0 || | ||||
905 | strcmp(c->node0.name, "output") != 0 || | ||||
906 | strcmp(c->func, "level") != 0) | ||||
907 | continue; | ||||
908 | v = (master * c->maxval + 64) / 127; | ||||
909 | ctl_setval(c, v); | ||||
910 | } | ||||
911 | } | ||||
912 | } | ||||
913 | |||||
914 | /* | ||||
915 | * Create a sndio device | ||||
916 | */ | ||||
917 | struct dev * | ||||
918 | dev_new(char *path, struct aparams *par, | ||||
919 | unsigned int mode, unsigned int bufsz, unsigned int round, | ||||
920 | unsigned int rate, unsigned int hold, unsigned int autovol) | ||||
921 | { | ||||
922 | struct dev *d, **pd; | ||||
923 | |||||
924 | if (dev_sndnum == DEV_NMAX16) { | ||||
925 | if (log_level >= 1) | ||||
926 | log_puts("too many devices\n"); | ||||
927 | return NULL((void*)0); | ||||
928 | } | ||||
929 | d = xmalloc(sizeof(struct dev)); | ||||
930 | d->path = path; | ||||
931 | d->num = dev_sndnum++; | ||||
932 | |||||
933 | d->reqpar = *par; | ||||
934 | d->reqmode = mode; | ||||
935 | d->reqpchan = d->reqrchan = 0; | ||||
936 | d->reqbufsz = bufsz; | ||||
937 | d->reqround = round; | ||||
938 | d->reqrate = rate; | ||||
939 | d->hold = hold; | ||||
940 | d->autovol = autovol; | ||||
941 | d->refcnt = 0; | ||||
942 | d->pstate = DEV_CFG0; | ||||
943 | d->slot_list = NULL((void*)0); | ||||
944 | d->master = MIDI_MAXCTL127; | ||||
945 | d->master_enabled = 0; | ||||
946 | d->alt_next = d; | ||||
947 | snprintf(d->name, CTL_NAMEMAX16, "%u", d->num); | ||||
948 | for (pd = &dev_list; *pd != NULL((void*)0); pd = &(*pd)->next) | ||||
949 | ; | ||||
950 | d->next = *pd; | ||||
951 | *pd = d; | ||||
952 | return d; | ||||
953 | } | ||||
954 | |||||
955 | /* | ||||
956 | * adjust device parameters and mode | ||||
957 | */ | ||||
958 | void | ||||
959 | dev_adjpar(struct dev *d, int mode, | ||||
960 | int pmax, int rmax) | ||||
961 | { | ||||
962 | d->reqmode |= mode & MODE_AUDIOMASK(0x01 | 0x02 | 0x10); | ||||
963 | if (mode & MODE_PLAY0x01) { | ||||
964 | if (d->reqpchan < pmax + 1) | ||||
965 | d->reqpchan = pmax + 1; | ||||
966 | } | ||||
967 | if (mode & MODE_REC0x02) { | ||||
968 | if (d->reqrchan < rmax + 1) | ||||
969 | d->reqrchan = rmax + 1; | ||||
970 | } | ||||
971 | } | ||||
972 | |||||
973 | /* | ||||
974 | * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer, | ||||
975 | * monitor, midi control, and any necessary conversions. | ||||
976 | * | ||||
977 | * Note that record and play buffers are always allocated, even if the | ||||
978 | * underlying device doesn't support both modes. | ||||
979 | */ | ||||
980 | int | ||||
981 | dev_allocbufs(struct dev *d) | ||||
982 | { | ||||
983 | /* | ||||
984 | * Create record buffer. | ||||
985 | */ | ||||
986 | |||||
987 | /* Create device <-> demuxer buffer */ | ||||
988 | d->rbuf = xmalloc(d->round * d->rchan * sizeof(adata_t)); | ||||
989 | |||||
990 | /* Insert a converter, if needed. */ | ||||
991 | if (!aparams_native(&d->par)) { | ||||
992 | dec_init(&d->dec, &d->par, d->rchan); | ||||
993 | d->decbuf = xmalloc(d->round * d->rchan * d->par.bps); | ||||
994 | } else | ||||
995 | d->decbuf = NULL((void*)0); | ||||
996 | |||||
997 | /* | ||||
998 | * Create play buffer | ||||
999 | */ | ||||
1000 | |||||
1001 | /* Create device <-> mixer buffer */ | ||||
1002 | d->poffs = 0; | ||||
1003 | d->psize = d->bufsz + d->round; | ||||
1004 | d->pbuf = xmalloc(d->psize * d->pchan * sizeof(adata_t)); | ||||
1005 | d->mode |= MODE_MON0x10; | ||||
1006 | |||||
1007 | /* Append a converter, if needed. */ | ||||
1008 | if (!aparams_native(&d->par)) { | ||||
1009 | enc_init(&d->enc, &d->par, d->pchan); | ||||
1010 | d->encbuf = xmalloc(d->round * d->pchan * d->par.bps); | ||||
1011 | } else | ||||
1012 | d->encbuf = NULL((void*)0); | ||||
1013 | |||||
1014 | /* | ||||
1015 | * Initially fill the record buffer with zeroed samples. This ensures | ||||
1016 | * that when a client records from a play-only device the client just | ||||
1017 | * gets silence. | ||||
1018 | */ | ||||
1019 | memset(d->rbuf, 0, d->round * d->rchan * sizeof(adata_t)); | ||||
1020 | |||||
1021 | if (log_level >= 2) { | ||||
1022 | dev_log(d); | ||||
1023 | log_puts(": "); | ||||
1024 | log_putu(d->rate); | ||||
1025 | log_puts("Hz, "); | ||||
1026 | aparams_log(&d->par); | ||||
1027 | if (d->mode & MODE_PLAY0x01) { | ||||
1028 | log_puts(", play 0:"); | ||||
1029 | log_puti(d->pchan - 1); | ||||
1030 | } | ||||
1031 | if (d->mode & MODE_REC0x02) { | ||||
1032 | log_puts(", rec 0:"); | ||||
1033 | log_puti(d->rchan - 1); | ||||
1034 | } | ||||
1035 | log_puts(", "); | ||||
1036 | log_putu(d->bufsz / d->round); | ||||
1037 | log_puts(" blocks of "); | ||||
1038 | log_putu(d->round); | ||||
1039 | log_puts(" frames"); | ||||
1040 | if (d == mtc_array[0].dev) | ||||
1041 | log_puts(", mtc"); | ||||
1042 | log_puts("\n"); | ||||
1043 | } | ||||
1044 | return 1; | ||||
1045 | } | ||||
1046 | |||||
1047 | /* | ||||
1048 | * Reset parameters and open the device. | ||||
1049 | */ | ||||
1050 | int | ||||
1051 | dev_open(struct dev *d) | ||||
1052 | { | ||||
1053 | d->mode = d->reqmode; | ||||
1054 | d->round = d->reqround; | ||||
1055 | d->bufsz = d->reqbufsz; | ||||
1056 | d->rate = d->reqrate; | ||||
1057 | d->pchan = d->reqpchan; | ||||
1058 | d->rchan = d->reqrchan; | ||||
1059 | d->par = d->reqpar; | ||||
1060 | if (d->pchan == 0) | ||||
1061 | d->pchan = 2; | ||||
1062 | if (d->rchan == 0) | ||||
1063 | d->rchan = 2; | ||||
1064 | if (!dev_sio_open(d)) { | ||||
1065 | if (log_level >= 1) { | ||||
1066 | dev_log(d); | ||||
1067 | log_puts(": failed to open audio device\n"); | ||||
1068 | } | ||||
1069 | return 0; | ||||
1070 | } | ||||
1071 | if (!dev_allocbufs(d)) | ||||
1072 | return 0; | ||||
1073 | |||||
1074 | d->pstate = DEV_INIT1; | ||||
1075 | return 1; | ||||
1076 | } | ||||
1077 | |||||
1078 | /* | ||||
1079 | * Force all slots to exit and close device, called after an error | ||||
1080 | */ | ||||
1081 | void | ||||
1082 | dev_abort(struct dev *d) | ||||
1083 | { | ||||
1084 | int i; | ||||
1085 | struct slot *s; | ||||
1086 | struct ctlslot *c; | ||||
1087 | struct opt *o; | ||||
1088 | |||||
1089 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1090 | if (s->opt == NULL((void*)0) || s->opt->dev != d) | ||||
1091 | continue; | ||||
1092 | if (s->ops) { | ||||
1093 | s->ops->exit(s->arg); | ||||
1094 | s->ops = NULL((void*)0); | ||||
1095 | } | ||||
1096 | } | ||||
1097 | d->slot_list = NULL((void*)0); | ||||
1098 | |||||
1099 | for (o = opt_list; o != NULL((void*)0); o = o->next) { | ||||
1100 | if (o->dev != d) | ||||
1101 | continue; | ||||
1102 | for (c = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, c++) { | ||||
1103 | if (c->ops == NULL((void*)0)) | ||||
1104 | continue; | ||||
1105 | if (c->opt == o) { | ||||
1106 | c->ops->exit(s->arg); | ||||
1107 | c->ops = NULL((void*)0); | ||||
1108 | } | ||||
1109 | } | ||||
1110 | |||||
1111 | midi_abort(o->midi); | ||||
1112 | } | ||||
1113 | |||||
1114 | if (d->pstate != DEV_CFG0) | ||||
1115 | dev_close(d); | ||||
1116 | } | ||||
1117 | |||||
1118 | /* | ||||
1119 | * force the device to go in DEV_CFG state, the caller is supposed to | ||||
1120 | * ensure buffers are drained | ||||
1121 | */ | ||||
1122 | void | ||||
1123 | dev_freebufs(struct dev *d) | ||||
1124 | { | ||||
1125 | #ifdef DEBUG1 | ||||
1126 | if (log_level >= 3) { | ||||
1127 | dev_log(d); | ||||
1128 | log_puts(": closing\n"); | ||||
1129 | } | ||||
1130 | #endif | ||||
1131 | if (d->mode & MODE_PLAY0x01) { | ||||
1132 | if (d->encbuf != NULL((void*)0)) | ||||
1133 | xfree(d->encbuf); | ||||
1134 | xfree(d->pbuf); | ||||
1135 | } | ||||
1136 | if (d->mode & MODE_REC0x02) { | ||||
1137 | if (d->decbuf != NULL((void*)0)) | ||||
1138 | xfree(d->decbuf); | ||||
1139 | xfree(d->rbuf); | ||||
1140 | } | ||||
1141 | } | ||||
1142 | |||||
1143 | /* | ||||
1144 | * Close the device and exit all slots | ||||
1145 | */ | ||||
1146 | void | ||||
1147 | dev_close(struct dev *d) | ||||
1148 | { | ||||
1149 | d->pstate = DEV_CFG0; | ||||
1150 | dev_sio_close(d); | ||||
1151 | dev_freebufs(d); | ||||
1152 | |||||
1153 | if (d->master_enabled) { | ||||
1154 | d->master_enabled = 0; | ||||
1155 | ctl_del(CTL_DEV_MASTER1, d, NULL((void*)0)); | ||||
1156 | } | ||||
1157 | } | ||||
1158 | |||||
1159 | int | ||||
1160 | dev_ref(struct dev *d) | ||||
1161 | { | ||||
1162 | #ifdef DEBUG1 | ||||
1163 | if (log_level >= 3) { | ||||
1164 | dev_log(d); | ||||
1165 | log_puts(": device requested\n"); | ||||
1166 | } | ||||
1167 | #endif | ||||
1168 | if (d->pstate == DEV_CFG0 && !dev_open(d)) | ||||
1169 | return 0; | ||||
1170 | d->refcnt++; | ||||
1171 | return 1; | ||||
1172 | } | ||||
1173 | |||||
1174 | void | ||||
1175 | dev_unref(struct dev *d) | ||||
1176 | { | ||||
1177 | #ifdef DEBUG1 | ||||
1178 | if (log_level >= 3) { | ||||
1179 | dev_log(d); | ||||
1180 | log_puts(": device released\n"); | ||||
1181 | } | ||||
1182 | #endif | ||||
1183 | d->refcnt--; | ||||
1184 | if (d->refcnt == 0 && d->pstate == DEV_INIT1) | ||||
1185 | dev_close(d); | ||||
1186 | } | ||||
1187 | |||||
1188 | /* | ||||
1189 | * initialize the device with the current parameters | ||||
1190 | */ | ||||
1191 | int | ||||
1192 | dev_init(struct dev *d) | ||||
1193 | { | ||||
1194 | if ((d->reqmode & MODE_AUDIOMASK(0x01 | 0x02 | 0x10)) == 0) { | ||||
1195 | #ifdef DEBUG1 | ||||
1196 | dev_log(d); | ||||
1197 | log_puts(": has no streams\n"); | ||||
1198 | #endif | ||||
1199 | return 0; | ||||
1200 | } | ||||
1201 | if (d->hold && !dev_ref(d)) | ||||
1202 | return 0; | ||||
1203 | return 1; | ||||
1204 | } | ||||
1205 | |||||
1206 | /* | ||||
1207 | * Unless the device is already in process of closing, request it to close | ||||
1208 | */ | ||||
1209 | void | ||||
1210 | dev_done(struct dev *d) | ||||
1211 | { | ||||
1212 | #ifdef DEBUG1 | ||||
1213 | if (log_level >= 3) { | ||||
1214 | dev_log(d); | ||||
1215 | log_puts(": draining\n"); | ||||
1216 | } | ||||
1217 | #endif | ||||
1218 | if (mtc_array[0].dev == d && mtc_array[0].tstate != MTC_STOP1) | ||||
1219 | mtc_stop(&mtc_array[0]); | ||||
1220 | if (d->hold) | ||||
1221 | dev_unref(d); | ||||
1222 | } | ||||
1223 | |||||
1224 | struct dev * | ||||
1225 | dev_bynum(int num) | ||||
1226 | { | ||||
1227 | struct dev *d; | ||||
1228 | |||||
1229 | for (d = dev_list; d != NULL((void*)0); d = d->next) { | ||||
1230 | if (d->num == num) | ||||
1231 | return d; | ||||
1232 | } | ||||
1233 | return NULL((void*)0); | ||||
1234 | } | ||||
1235 | |||||
1236 | /* | ||||
1237 | * Free the device | ||||
1238 | */ | ||||
1239 | void | ||||
1240 | dev_del(struct dev *d) | ||||
1241 | { | ||||
1242 | struct dev **p; | ||||
1243 | |||||
1244 | #ifdef DEBUG1 | ||||
1245 | if (log_level >= 3) { | ||||
1246 | dev_log(d); | ||||
1247 | log_puts(": deleting\n"); | ||||
1248 | } | ||||
1249 | #endif | ||||
1250 | if (d->pstate != DEV_CFG0) | ||||
1251 | dev_close(d); | ||||
1252 | for (p = &dev_list; *p != d; p = &(*p)->next) { | ||||
1253 | #ifdef DEBUG1 | ||||
1254 | if (*p == NULL((void*)0)) { | ||||
1255 | dev_log(d); | ||||
1256 | log_puts(": device to delete not on the list\n"); | ||||
1257 | panic(); | ||||
1258 | } | ||||
1259 | #endif | ||||
1260 | } | ||||
1261 | *p = d->next; | ||||
1262 | xfree(d); | ||||
1263 | } | ||||
1264 | |||||
1265 | unsigned int | ||||
1266 | dev_roundof(struct dev *d, unsigned int newrate) | ||||
1267 | { | ||||
1268 | return (d->round * newrate + d->rate / 2) / d->rate; | ||||
1269 | } | ||||
1270 | |||||
1271 | /* | ||||
1272 | * If the device is paused, then resume it. | ||||
1273 | */ | ||||
1274 | void | ||||
1275 | dev_wakeup(struct dev *d) | ||||
1276 | { | ||||
1277 | if (d->pstate == DEV_INIT1) { | ||||
1278 | if (log_level >= 2) { | ||||
1279 | dev_log(d); | ||||
1280 | log_puts(": device started\n"); | ||||
1281 | } | ||||
1282 | if (d->mode & MODE_PLAY0x01) { | ||||
1283 | d->prime = d->bufsz; | ||||
1284 | } else { | ||||
1285 | d->prime = 0; | ||||
1286 | } | ||||
1287 | d->poffs = 0; | ||||
1288 | |||||
1289 | /* | ||||
1290 | * empty cycles don't increment delta, so it's ok to | ||||
1291 | * start at 0 | ||||
1292 | **/ | ||||
1293 | d->delta = 0; | ||||
1294 | |||||
1295 | d->pstate = DEV_RUN2; | ||||
1296 | dev_sio_start(d); | ||||
1297 | } | ||||
1298 | } | ||||
1299 | |||||
1300 | /* | ||||
1301 | * Return true if both of the given devices can run the same | ||||
1302 | * clients | ||||
1303 | */ | ||||
1304 | int | ||||
1305 | dev_iscompat(struct dev *o, struct dev *n) | ||||
1306 | { | ||||
1307 | if (((long long)o->round * n->rate != (long long)n->round * o->rate) || | ||||
1308 | ((long long)o->bufsz * n->rate != (long long)n->bufsz * o->rate)) { | ||||
1309 | if (log_level >= 1) { | ||||
1310 | log_puts(n->name); | ||||
1311 | log_puts(": not compatible with "); | ||||
1312 | log_puts(o->name); | ||||
1313 | log_puts("\n"); | ||||
1314 | } | ||||
1315 | return 0; | ||||
1316 | } | ||||
1317 | return 1; | ||||
1318 | } | ||||
1319 | |||||
1320 | /* | ||||
1321 | * Close the device, but attempt to migrate everything to a new sndio | ||||
1322 | * device. | ||||
1323 | */ | ||||
1324 | struct dev * | ||||
1325 | dev_migrate(struct dev *odev) | ||||
1326 | { | ||||
1327 | struct dev *ndev; | ||||
1328 | struct opt *o; | ||||
1329 | struct slot *s; | ||||
1330 | int i; | ||||
1331 | |||||
1332 | /* not opened */ | ||||
1333 | if (odev->pstate == DEV_CFG0) | ||||
1334 | return odev; | ||||
1335 | |||||
1336 | ndev = odev; | ||||
1337 | while (1) { | ||||
1338 | /* try next one, circulating through the list */ | ||||
1339 | ndev = ndev->alt_next; | ||||
1340 | if (ndev == odev) { | ||||
1341 | if (log_level >= 1) { | ||||
1342 | dev_log(odev); | ||||
1343 | log_puts(": no fall-back device found\n"); | ||||
1344 | } | ||||
1345 | return NULL((void*)0); | ||||
1346 | } | ||||
1347 | |||||
1348 | |||||
1349 | if (!dev_ref(ndev)) | ||||
1350 | continue; | ||||
1351 | |||||
1352 | /* check if new parameters are compatible with old ones */ | ||||
1353 | if (!dev_iscompat(odev, ndev)) { | ||||
1354 | dev_unref(ndev); | ||||
1355 | continue; | ||||
1356 | } | ||||
1357 | |||||
1358 | /* found it!*/ | ||||
1359 | break; | ||||
1360 | } | ||||
1361 | |||||
1362 | if (log_level >= 1) { | ||||
1363 | dev_log(odev); | ||||
1364 | log_puts(": switching to "); | ||||
1365 | dev_log(ndev); | ||||
1366 | log_puts("\n"); | ||||
1367 | } | ||||
1368 | |||||
1369 | if (mtc_array[0].dev == odev) | ||||
1370 | mtc_setdev(&mtc_array[0], ndev); | ||||
1371 | |||||
1372 | /* move opts to new device (also moves clients using the opts) */ | ||||
1373 | for (o = opt_list; o != NULL((void*)0); o = o->next) { | ||||
1374 | if (o->dev != odev) | ||||
1375 | continue; | ||||
1376 | if (strcmp(o->name, o->dev->name) == 0) | ||||
1377 | continue; | ||||
1378 | opt_setdev(o, ndev); | ||||
1379 | } | ||||
1380 | |||||
1381 | /* terminate remaining clients */ | ||||
1382 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1383 | if (s->opt == NULL((void*)0) || s->opt->dev != odev) | ||||
1384 | continue; | ||||
1385 | if (s->ops != NULL((void*)0)) { | ||||
1386 | s->ops->exit(s); | ||||
1387 | s->ops = NULL((void*)0); | ||||
1388 | } | ||||
1389 | } | ||||
1390 | |||||
1391 | /* slots and/or MMC hold refs, drop ours */ | ||||
1392 | dev_unref(ndev); | ||||
1393 | |||||
1394 | return ndev; | ||||
1395 | } | ||||
1396 | |||||
1397 | /* | ||||
1398 | * check that all clients controlled by MMC are ready to start, if so, | ||||
1399 | * attach them all at the same position | ||||
1400 | */ | ||||
1401 | void | ||||
1402 | mtc_trigger(struct mtc *mtc) | ||||
1403 | { | ||||
1404 | int i; | ||||
1405 | struct slot *s; | ||||
1406 | |||||
1407 | if (mtc->tstate != MTC_START2) { | ||||
1408 | if (log_level >= 2) { | ||||
1409 | dev_log(mtc->dev); | ||||
1410 | log_puts(": not started by mmc yet, waiting...\n"); | ||||
1411 | } | ||||
1412 | return; | ||||
1413 | } | ||||
1414 | |||||
1415 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1416 | if (s->opt == NULL((void*)0) || s->opt->mtc != mtc) | ||||
1417 | continue; | ||||
1418 | if (s->pstate != SLOT_READY2) { | ||||
1419 | #ifdef DEBUG1 | ||||
1420 | if (log_level >= 3) { | ||||
1421 | slot_log(s); | ||||
1422 | log_puts(": not ready, start delayed\n"); | ||||
1423 | } | ||||
1424 | #endif | ||||
1425 | return; | ||||
1426 | } | ||||
1427 | } | ||||
1428 | if (!dev_ref(mtc->dev)) | ||||
1429 | return; | ||||
1430 | |||||
1431 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1432 | if (s->opt == NULL((void*)0) || s->opt->mtc != mtc) | ||||
1433 | continue; | ||||
1434 | slot_attach(s); | ||||
1435 | s->pstate = SLOT_RUN3; | ||||
1436 | } | ||||
1437 | mtc->tstate = MTC_RUN3; | ||||
1438 | mtc_midi_full(mtc); | ||||
1439 | dev_wakeup(mtc->dev); | ||||
1440 | } | ||||
1441 | |||||
1442 | /* | ||||
1443 | * start all slots simultaneously | ||||
1444 | */ | ||||
1445 | void | ||||
1446 | mtc_start(struct mtc *mtc) | ||||
1447 | { | ||||
1448 | if (mtc->tstate == MTC_STOP1) { | ||||
1449 | mtc->tstate = MTC_START2; | ||||
1450 | mtc_trigger(mtc); | ||||
1451 | #ifdef DEBUG1 | ||||
1452 | } else { | ||||
1453 | if (log_level >= 3) { | ||||
1454 | dev_log(mtc->dev); | ||||
1455 | log_puts(": ignoring mmc start\n"); | ||||
1456 | } | ||||
1457 | #endif | ||||
1458 | } | ||||
1459 | } | ||||
1460 | |||||
1461 | /* | ||||
1462 | * stop all slots simultaneously | ||||
1463 | */ | ||||
1464 | void | ||||
1465 | mtc_stop(struct mtc *mtc) | ||||
1466 | { | ||||
1467 | switch (mtc->tstate) { | ||||
1468 | case MTC_START2: | ||||
1469 | mtc->tstate = MTC_STOP1; | ||||
1470 | return; | ||||
1471 | case MTC_RUN3: | ||||
1472 | mtc->tstate = MTC_STOP1; | ||||
1473 | dev_unref(mtc->dev); | ||||
1474 | break; | ||||
1475 | default: | ||||
1476 | #ifdef DEBUG1 | ||||
1477 | if (log_level >= 3) { | ||||
1478 | dev_log(mtc->dev); | ||||
1479 | log_puts(": ignored mmc stop\n"); | ||||
1480 | } | ||||
1481 | #endif | ||||
1482 | return; | ||||
1483 | } | ||||
1484 | } | ||||
1485 | |||||
1486 | /* | ||||
1487 | * relocate all slots simultaneously | ||||
1488 | */ | ||||
1489 | void | ||||
1490 | mtc_loc(struct mtc *mtc, unsigned int origin) | ||||
1491 | { | ||||
1492 | if (log_level >= 2) { | ||||
1493 | dev_log(mtc->dev); | ||||
1494 | log_puts(": relocated to "); | ||||
1495 | log_putu(origin); | ||||
1496 | log_puts("\n"); | ||||
1497 | } | ||||
1498 | if (mtc->tstate == MTC_RUN3) | ||||
1499 | mtc_stop(mtc); | ||||
1500 | mtc->origin = origin; | ||||
1501 | if (mtc->tstate == MTC_RUN3) | ||||
1502 | mtc_start(mtc); | ||||
1503 | } | ||||
1504 | |||||
1505 | /* | ||||
1506 | * set MMC device | ||||
1507 | */ | ||||
1508 | void | ||||
1509 | mtc_setdev(struct mtc *mtc, struct dev *d) | ||||
1510 | { | ||||
1511 | struct opt *o; | ||||
1512 | |||||
1513 | if (mtc->dev == d) | ||||
1514 | return; | ||||
1515 | |||||
1516 | if (log_level >= 2) { | ||||
1517 | dev_log(d); | ||||
1518 | log_puts(": set to be MIDI clock source\n"); | ||||
1519 | } | ||||
1520 | |||||
1521 | /* adjust clock and ref counter, if needed */ | ||||
1522 | if (mtc->tstate == MTC_RUN3) { | ||||
1523 | mtc->delta -= mtc->dev->delta; | ||||
1524 | dev_unref(mtc->dev); | ||||
1525 | } | ||||
1526 | |||||
1527 | mtc->dev = d; | ||||
1528 | |||||
1529 | if (mtc->tstate == MTC_RUN3) { | ||||
1530 | mtc->delta += mtc->dev->delta; | ||||
1531 | dev_ref(mtc->dev); | ||||
1532 | dev_wakeup(mtc->dev); | ||||
1533 | } | ||||
1534 | |||||
1535 | /* move in once anything using MMC */ | ||||
1536 | for (o = opt_list; o != NULL((void*)0); o = o->next) { | ||||
1537 | if (o->mtc == mtc) | ||||
1538 | opt_setdev(o, mtc->dev); | ||||
1539 | } | ||||
1540 | } | ||||
1541 | |||||
1542 | /* | ||||
1543 | * allocate buffers & conversion chain | ||||
1544 | */ | ||||
1545 | void | ||||
1546 | slot_initconv(struct slot *s) | ||||
1547 | { | ||||
1548 | unsigned int dev_nch; | ||||
1549 | struct dev *d = s->opt->dev; | ||||
1550 | |||||
1551 | if (s->mode & MODE_PLAY0x01) { | ||||
1552 | cmap_init(&s->mix.cmap, | ||||
1553 | s->opt->pmin, s->opt->pmin + s->mix.nch - 1, | ||||
1554 | s->opt->pmin, s->opt->pmin + s->mix.nch - 1, | ||||
1555 | 0, d->pchan - 1, | ||||
1556 | s->opt->pmin, s->opt->pmax); | ||||
1557 | s->mix.decbuf = NULL((void*)0); | ||||
1558 | s->mix.resampbuf = NULL((void*)0); | ||||
1559 | if (!aparams_native(&s->par)) { | ||||
1560 | dec_init(&s->mix.dec, &s->par, s->mix.nch); | ||||
1561 | s->mix.decbuf = | ||||
1562 | xmalloc(s->round * s->mix.nch * sizeof(adata_t)); | ||||
1563 | } | ||||
1564 | if (s->rate != d->rate) { | ||||
1565 | resamp_init(&s->mix.resamp, s->round, d->round, | ||||
1566 | s->mix.nch); | ||||
1567 | s->mix.resampbuf = | ||||
1568 | xmalloc(d->round * s->mix.nch * sizeof(adata_t)); | ||||
1569 | } | ||||
1570 | s->mix.join = 1; | ||||
1571 | s->mix.expand = 1; | ||||
1572 | if (s->opt->dup && s->mix.cmap.nch > 0) { | ||||
1573 | dev_nch = d->pchan < (s->opt->pmax + 1) ? | ||||
1574 | d->pchan - s->opt->pmin : | ||||
1575 | s->opt->pmax - s->opt->pmin + 1; | ||||
1576 | if (dev_nch > s->mix.nch) | ||||
1577 | s->mix.expand = dev_nch / s->mix.nch; | ||||
1578 | else if (s->mix.nch > dev_nch) | ||||
1579 | s->mix.join = s->mix.nch / dev_nch; | ||||
1580 | } | ||||
1581 | } | ||||
1582 | |||||
1583 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1584 | unsigned int outchan = (s->opt->mode & MODE_MON0x10) ? | ||||
1585 | d->pchan : d->rchan; | ||||
1586 | |||||
1587 | s->sub.encbuf = NULL((void*)0); | ||||
1588 | s->sub.resampbuf = NULL((void*)0); | ||||
1589 | cmap_init(&s->sub.cmap, | ||||
1590 | 0, outchan - 1, | ||||
1591 | s->opt->rmin, s->opt->rmax, | ||||
1592 | s->opt->rmin, s->opt->rmin + s->sub.nch - 1, | ||||
1593 | s->opt->rmin, s->opt->rmin + s->sub.nch - 1); | ||||
1594 | if (s->rate != d->rate) { | ||||
1595 | resamp_init(&s->sub.resamp, d->round, s->round, | ||||
1596 | s->sub.nch); | ||||
1597 | s->sub.resampbuf = | ||||
1598 | xmalloc(d->round * s->sub.nch * sizeof(adata_t)); | ||||
1599 | } | ||||
1600 | if (!aparams_native(&s->par)) { | ||||
1601 | enc_init(&s->sub.enc, &s->par, s->sub.nch); | ||||
1602 | s->sub.encbuf = | ||||
1603 | xmalloc(s->round * s->sub.nch * sizeof(adata_t)); | ||||
1604 | } | ||||
1605 | s->sub.join = 1; | ||||
1606 | s->sub.expand = 1; | ||||
1607 | if (s->opt->dup && s->sub.cmap.nch > 0) { | ||||
1608 | dev_nch = outchan < (s->opt->rmax + 1) ? | ||||
1609 | outchan - s->opt->rmin : | ||||
1610 | s->opt->rmax - s->opt->rmin + 1; | ||||
1611 | if (dev_nch > s->sub.nch) | ||||
1612 | s->sub.join = dev_nch / s->sub.nch; | ||||
1613 | else if (s->sub.nch > dev_nch) | ||||
1614 | s->sub.expand = s->sub.nch / dev_nch; | ||||
1615 | } | ||||
1616 | |||||
1617 | /* | ||||
1618 | * cmap_copy() doesn't write samples in all channels, | ||||
1619 | * for instance when mono->stereo conversion is | ||||
1620 | * disabled. So we have to prefill cmap_copy() output | ||||
1621 | * with silence. | ||||
1622 | */ | ||||
1623 | if (s->sub.resampbuf) { | ||||
1624 | memset(s->sub.resampbuf, 0, | ||||
1625 | d->round * s->sub.nch * sizeof(adata_t)); | ||||
1626 | } else if (s->sub.encbuf) { | ||||
1627 | memset(s->sub.encbuf, 0, | ||||
1628 | s->round * s->sub.nch * sizeof(adata_t)); | ||||
1629 | } else { | ||||
1630 | memset(s->sub.buf.data, 0, | ||||
1631 | s->appbufsz * s->sub.nch * sizeof(adata_t)); | ||||
1632 | } | ||||
1633 | } | ||||
1634 | } | ||||
1635 | |||||
1636 | /* | ||||
1637 | * allocate buffers & conversion chain | ||||
1638 | */ | ||||
1639 | void | ||||
1640 | slot_allocbufs(struct slot *s) | ||||
1641 | { | ||||
1642 | if (s->mode & MODE_PLAY0x01) { | ||||
1643 | s->mix.bpf = s->par.bps * s->mix.nch; | ||||
1644 | abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf); | ||||
1645 | } | ||||
1646 | |||||
1647 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1648 | s->sub.bpf = s->par.bps * s->sub.nch; | ||||
1649 | abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf); | ||||
1650 | } | ||||
1651 | |||||
1652 | #ifdef DEBUG1 | ||||
1653 | if (log_level >= 3) { | ||||
1654 | slot_log(s); | ||||
1655 | log_puts(": allocated "); | ||||
1656 | log_putu(s->appbufsz); | ||||
1657 | log_puts("/"); | ||||
1658 | log_putu(SLOT_BUFSZ(s)((s)->appbufsz + (s)->opt->dev->bufsz / (s)->opt ->dev->round * (s)->round)); | ||||
1659 | log_puts(" fr buffers\n"); | ||||
1660 | } | ||||
1661 | #endif | ||||
1662 | } | ||||
1663 | |||||
1664 | /* | ||||
1665 | * free buffers & conversion chain | ||||
1666 | */ | ||||
1667 | void | ||||
1668 | slot_freebufs(struct slot *s) | ||||
1669 | { | ||||
1670 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1671 | abuf_done(&s->sub.buf); | ||||
1672 | } | ||||
1673 | |||||
1674 | if (s->mode & MODE_PLAY0x01) { | ||||
1675 | abuf_done(&s->mix.buf); | ||||
1676 | } | ||||
1677 | } | ||||
1678 | |||||
1679 | /* | ||||
1680 | * allocate a new slot and register the given call-backs | ||||
1681 | */ | ||||
1682 | struct slot * | ||||
1683 | slot_new(struct opt *opt, unsigned int id, char *who, | ||||
1684 | struct slotops *ops, void *arg, int mode) | ||||
1685 | { | ||||
1686 | char *p; | ||||
1687 | char name[SLOT_NAMEMAX8]; | ||||
1688 | char ctl_name[CTL_NAMEMAX16]; | ||||
1689 | unsigned int i, ser, bestser, bestidx; | ||||
1690 | struct slot *unit[DEV_NSLOT8]; | ||||
1691 | struct slot *s; | ||||
1692 | |||||
1693 | /* | ||||
1694 | * create a ``valid'' control name (lowcase, remove [^a-z], truncate) | ||||
1695 | */ | ||||
1696 | for (i = 0, p = who; ; p++) { | ||||
1697 | if (i == SLOT_NAMEMAX8 - 1 || *p == '\0') { | ||||
1698 | name[i] = '\0'; | ||||
1699 | break; | ||||
1700 | } else if (*p >= 'A' && *p <= 'Z') { | ||||
1701 | name[i++] = *p + 'a' - 'A'; | ||||
1702 | } else if (*p >= 'a' && *p <= 'z') | ||||
1703 | name[i++] = *p; | ||||
1704 | } | ||||
1705 | if (i == 0) | ||||
1706 | strlcpy(name, "noname", SLOT_NAMEMAX8); | ||||
1707 | |||||
1708 | /* | ||||
1709 | * build a unit-to-slot map for this name | ||||
1710 | */ | ||||
1711 | for (i = 0; i < DEV_NSLOT8; i++) | ||||
1712 | unit[i] = NULL((void*)0); | ||||
1713 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1714 | if (strcmp(s->name, name) == 0) | ||||
1715 | unit[s->unit] = s; | ||||
1716 | } | ||||
1717 | |||||
1718 | /* | ||||
1719 | * find the free slot with the least unit number and same id | ||||
1720 | */ | ||||
1721 | for (i = 0; i < DEV_NSLOT8; i++) { | ||||
1722 | s = unit[i]; | ||||
1723 | if (s != NULL((void*)0) && s->ops == NULL((void*)0) && s->id == id) | ||||
1724 | goto found; | ||||
1725 | } | ||||
1726 | |||||
1727 | /* | ||||
1728 | * find the free slot with the least unit number | ||||
1729 | */ | ||||
1730 | for (i = 0; i < DEV_NSLOT8; i++) { | ||||
1731 | s = unit[i]; | ||||
1732 | if (s != NULL((void*)0) && s->ops == NULL((void*)0)) { | ||||
1733 | s->id = id; | ||||
1734 | goto found; | ||||
1735 | } | ||||
1736 | } | ||||
1737 | |||||
1738 | /* | ||||
1739 | * couldn't find a matching slot, pick oldest free slot | ||||
1740 | * and set its name/unit | ||||
1741 | */ | ||||
1742 | bestser = 0; | ||||
1743 | bestidx = DEV_NSLOT8; | ||||
1744 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1745 | if (s->ops != NULL((void*)0)) | ||||
1746 | continue; | ||||
1747 | ser = slot_serial - s->serial; | ||||
1748 | if (ser > bestser) { | ||||
1749 | bestser = ser; | ||||
1750 | bestidx = i; | ||||
1751 | } | ||||
1752 | } | ||||
1753 | |||||
1754 | if (bestidx == DEV_NSLOT8) { | ||||
1755 | if (log_level >= 1) { | ||||
1756 | log_puts(name); | ||||
1757 | log_puts(": out of sub-device slots\n"); | ||||
1758 | } | ||||
1759 | return NULL((void*)0); | ||||
1760 | } | ||||
1761 | |||||
1762 | s = slot_array + bestidx; | ||||
1763 | ctl_del(CTL_SLOT_LEVEL3, s, NULL((void*)0)); | ||||
1764 | s->vol = MIDI_MAXCTL127; | ||||
1765 | strlcpy(s->name, name, SLOT_NAMEMAX8); | ||||
1766 | s->serial = slot_serial++; | ||||
1767 | for (i = 0; unit[i] != NULL((void*)0); i++) | ||||
1768 | ; /* nothing */ | ||||
1769 | s->unit = i; | ||||
1770 | s->id = id; | ||||
1771 | s->opt = opt; | ||||
1772 | slot_ctlname(s, ctl_name, CTL_NAMEMAX16); | ||||
1773 | ctl_new(CTL_SLOT_LEVEL3, s, NULL((void*)0), | ||||
1774 | CTL_NUM2, "app", ctl_name, -1, "level", | ||||
1775 | NULL((void*)0), -1, 127, s->vol); | ||||
1776 | |||||
1777 | found: | ||||
1778 | /* open device, this may change opt's device */ | ||||
1779 | if (!opt_ref(s->opt)) | ||||
1780 | return NULL((void*)0); | ||||
1781 | s->opt = opt; | ||||
1782 | s->ops = ops; | ||||
1783 | s->arg = arg; | ||||
1784 | s->pstate = SLOT_INIT0; | ||||
1785 | s->mode = mode; | ||||
1786 | aparams_init(&s->par); | ||||
1787 | if (s->mode & MODE_PLAY0x01) | ||||
1788 | s->mix.nch = s->opt->pmax - s->opt->pmin + 1; | ||||
1789 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) | ||||
1790 | s->sub.nch = s->opt->rmax - s->opt->rmin + 1; | ||||
1791 | s->xrun = s->opt->mtc != NULL((void*)0) ? XRUN_SYNC1 : XRUN_IGNORE0; | ||||
1792 | s->appbufsz = s->opt->dev->bufsz; | ||||
1793 | s->round = s->opt->dev->round; | ||||
1794 | s->rate = s->opt->dev->rate; | ||||
1795 | dev_midi_slotdesc(s->opt->dev, s); | ||||
1796 | dev_midi_vol(s->opt->dev, s); | ||||
1797 | #ifdef DEBUG1 | ||||
1798 | if (log_level >= 3) { | ||||
1799 | slot_log(s); | ||||
1800 | log_puts(": using "); | ||||
1801 | log_puts(s->opt->name); | ||||
1802 | log_puts(", mode = "); | ||||
1803 | log_putx(mode); | ||||
1804 | log_puts("\n"); | ||||
1805 | } | ||||
1806 | #endif | ||||
1807 | return s; | ||||
1808 | } | ||||
1809 | |||||
1810 | /* | ||||
1811 | * release the given slot | ||||
1812 | */ | ||||
1813 | void | ||||
1814 | slot_del(struct slot *s) | ||||
1815 | { | ||||
1816 | s->arg = s; | ||||
1817 | s->ops = &zomb_slotops; | ||||
1818 | switch (s->pstate) { | ||||
1819 | case SLOT_INIT0: | ||||
1820 | s->ops = NULL((void*)0); | ||||
1821 | break; | ||||
1822 | case SLOT_START1: | ||||
1823 | case SLOT_READY2: | ||||
1824 | case SLOT_RUN3: | ||||
1825 | case SLOT_STOP4: | ||||
1826 | slot_stop(s, 0); | ||||
1827 | break; | ||||
1828 | } | ||||
1829 | opt_unref(s->opt); | ||||
1830 | } | ||||
1831 | |||||
1832 | /* | ||||
1833 | * change the slot play volume; called either by the slot or by MIDI | ||||
1834 | */ | ||||
1835 | void | ||||
1836 | slot_setvol(struct slot *s, unsigned int vol) | ||||
1837 | { | ||||
1838 | #ifdef DEBUG1 | ||||
1839 | if (log_level >= 3) { | ||||
1840 | slot_log(s); | ||||
1841 | log_puts(": setting volume "); | ||||
1842 | log_putu(vol); | ||||
1843 | log_puts("\n"); | ||||
1844 | } | ||||
1845 | #endif | ||||
1846 | s->vol = vol; | ||||
1847 | s->mix.vol = MIDI_TO_ADATA(s->vol)(aparams_ctltovol[s->vol] << (16 - 16)); | ||||
1848 | } | ||||
1849 | |||||
1850 | /* | ||||
1851 | * set device for this slot | ||||
1852 | */ | ||||
1853 | void | ||||
1854 | slot_setopt(struct slot *s, struct opt *o) | ||||
1855 | { | ||||
1856 | struct opt *t; | ||||
1857 | struct dev *odev, *ndev; | ||||
1858 | struct ctl *c; | ||||
1859 | |||||
1860 | if (s->opt == NULL((void*)0) || s->opt == o) | ||||
1861 | return; | ||||
1862 | |||||
1863 | if (log_level >= 2) { | ||||
1864 | slot_log(s); | ||||
1865 | log_puts(": moving to opt "); | ||||
1866 | log_puts(o->name); | ||||
1867 | log_puts("\n"); | ||||
1868 | } | ||||
1869 | |||||
1870 | odev = s->opt->dev; | ||||
1871 | if (s->ops != NULL((void*)0)) { | ||||
1872 | ndev = opt_ref(o); | ||||
1873 | if (ndev == NULL((void*)0)) | ||||
1874 | return; | ||||
1875 | |||||
1876 | if (!dev_iscompat(odev, ndev)) { | ||||
1877 | opt_unref(o); | ||||
1878 | return; | ||||
1879 | } | ||||
1880 | } | ||||
1881 | |||||
1882 | if (s->pstate == SLOT_RUN3 || s->pstate == SLOT_STOP4) | ||||
1883 | slot_detach(s); | ||||
1884 | |||||
1885 | t = s->opt; | ||||
1886 | s->opt = o; | ||||
1887 | |||||
1888 | c = ctl_find(CTL_SLOT_LEVEL3, s, NULL((void*)0)); | ||||
1889 | ctl_update(c); | ||||
1890 | |||||
1891 | if (o->dev != t->dev) { | ||||
1892 | dev_midi_slotdesc(odev, s); | ||||
1893 | dev_midi_slotdesc(ndev, s); | ||||
1894 | dev_midi_vol(ndev, s); | ||||
1895 | } | ||||
1896 | |||||
1897 | if (s->pstate == SLOT_RUN3 || s->pstate == SLOT_STOP4) | ||||
1898 | slot_attach(s); | ||||
1899 | |||||
1900 | if (s->ops != NULL((void*)0)) { | ||||
1901 | opt_unref(t); | ||||
1902 | return; | ||||
1903 | } | ||||
1904 | } | ||||
1905 | |||||
1906 | /* | ||||
1907 | * attach the slot to the device (ie start playing & recording | ||||
1908 | */ | ||||
1909 | void | ||||
1910 | slot_attach(struct slot *s) | ||||
1911 | { | ||||
1912 | struct dev *d = s->opt->dev; | ||||
1913 | long long pos; | ||||
1914 | |||||
1915 | if (((s->mode & MODE_PLAY0x01) && !(s->opt->mode & MODE_PLAY0x01)) || | ||||
1916 | ((s->mode & MODE_RECMASK(0x02 | 0x10)) && !(s->opt->mode & MODE_RECMASK(0x02 | 0x10)))) { | ||||
1917 | if (log_level >= 1) { | ||||
1918 | slot_log(s); | ||||
1919 | log_puts(" at "); | ||||
1920 | log_puts(s->opt->name); | ||||
1921 | log_puts(": mode not allowed on this sub-device\n"); | ||||
1922 | } | ||||
1923 | } | ||||
1924 | |||||
1925 | /* | ||||
1926 | * setup converions layer | ||||
1927 | */ | ||||
1928 | slot_initconv(s); | ||||
1929 | |||||
1930 | /* | ||||
1931 | * start the device if not started | ||||
1932 | */ | ||||
1933 | dev_wakeup(d); | ||||
1934 | |||||
1935 | /* | ||||
1936 | * adjust initial clock | ||||
1937 | */ | ||||
1938 | pos = s->delta_rem + | ||||
1939 | (long long)s->delta * d->round + | ||||
1940 | (long long)d->delta * s->round; | ||||
1941 | s->delta = pos / (int)d->round; | ||||
1942 | s->delta_rem = pos % d->round; | ||||
1943 | if (s->delta_rem < 0) { | ||||
1944 | s->delta_rem += d->round; | ||||
1945 | s->delta--; | ||||
1946 | } | ||||
1947 | |||||
1948 | #ifdef DEBUG1 | ||||
1949 | if (log_level >= 2) { | ||||
1950 | slot_log(s); | ||||
1951 | log_puts(": attached at "); | ||||
1952 | log_puti(s->delta); | ||||
1953 | log_puts(" + "); | ||||
1954 | log_puti(s->delta_rem); | ||||
1955 | log_puts("/"); | ||||
1956 | log_puti(s->round); | ||||
1957 | log_puts("\n"); | ||||
1958 | } | ||||
1959 | #endif | ||||
1960 | |||||
1961 | /* | ||||
1962 | * We dont check whether the device is dying, | ||||
1963 | * because dev_xxx() functions are supposed to | ||||
1964 | * work (i.e., not to crash) | ||||
1965 | */ | ||||
1966 | |||||
1967 | s->next = d->slot_list; | ||||
1968 | d->slot_list = s; | ||||
1969 | if (s->mode & MODE_PLAY0x01) { | ||||
1970 | s->mix.vol = MIDI_TO_ADATA(s->vol)(aparams_ctltovol[s->vol] << (16 - 16)); | ||||
1971 | dev_mix_adjvol(d); | ||||
1972 | } | ||||
1973 | } | ||||
1974 | |||||
1975 | /* | ||||
1976 | * if MMC is enabled, and try to attach all slots synchronously, else | ||||
1977 | * simply attach the slot | ||||
1978 | */ | ||||
1979 | void | ||||
1980 | slot_ready(struct slot *s) | ||||
1981 | { | ||||
1982 | /* | ||||
1983 | * device may be disconnected, and if so we're called from | ||||
1984 | * slot->ops->exit() on a closed device | ||||
1985 | */ | ||||
1986 | if (s->opt->dev->pstate == DEV_CFG0) | ||||
1987 | return; | ||||
1988 | if (s->opt->mtc == NULL((void*)0)) { | ||||
1989 | slot_attach(s); | ||||
1990 | s->pstate = SLOT_RUN3; | ||||
1991 | } else | ||||
1992 | mtc_trigger(s->opt->mtc); | ||||
1993 | } | ||||
1994 | |||||
1995 | /* | ||||
1996 | * setup buffers & conversion layers, prepare the slot to receive data | ||||
1997 | * (for playback) or start (recording). | ||||
1998 | */ | ||||
1999 | void | ||||
2000 | slot_start(struct slot *s) | ||||
2001 | { | ||||
2002 | struct dev *d = s->opt->dev; | ||||
2003 | #ifdef DEBUG1 | ||||
2004 | if (s->pstate != SLOT_INIT0) { | ||||
2005 | slot_log(s); | ||||
2006 | log_puts(": slot_start: wrong state\n"); | ||||
2007 | panic(); | ||||
2008 | } | ||||
2009 | if (s->mode & MODE_PLAY0x01) { | ||||
2010 | if (log_level >= 3) { | ||||
2011 | slot_log(s); | ||||
2012 | log_puts(": playing "); | ||||
2013 | aparams_log(&s->par); | ||||
2014 | log_puts(" -> "); | ||||
2015 | aparams_log(&d->par); | ||||
2016 | log_puts("\n"); | ||||
2017 | } | ||||
2018 | } | ||||
2019 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2020 | if (log_level >= 3) { | ||||
2021 | slot_log(s); | ||||
2022 | log_puts(": recording "); | ||||
2023 | aparams_log(&s->par); | ||||
2024 | log_puts(" <- "); | ||||
2025 | aparams_log(&d->par); | ||||
2026 | log_puts("\n"); | ||||
2027 | } | ||||
2028 | } | ||||
2029 | #endif | ||||
2030 | slot_allocbufs(s); | ||||
2031 | |||||
2032 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2033 | /* | ||||
2034 | * N-th recorded block is the N-th played block | ||||
2035 | */ | ||||
2036 | s->sub.prime = d->bufsz / d->round; | ||||
2037 | } | ||||
2038 | s->skip = 0; | ||||
2039 | |||||
2040 | /* | ||||
2041 | * get the current position, the origin is when the first sample | ||||
2042 | * played and/or recorded | ||||
2043 | */ | ||||
2044 | s->delta = -(long long)d->bufsz * s->round / d->round; | ||||
2045 | s->delta_rem = 0; | ||||
2046 | |||||
2047 | if (s->mode & MODE_PLAY0x01) { | ||||
2048 | s->pstate = SLOT_START1; | ||||
2049 | } else { | ||||
2050 | s->pstate = SLOT_READY2; | ||||
2051 | slot_ready(s); | ||||
2052 | } | ||||
2053 | } | ||||
2054 | |||||
2055 | /* | ||||
2056 | * stop playback and recording, and free conversion layers | ||||
2057 | */ | ||||
2058 | void | ||||
2059 | slot_detach(struct slot *s) | ||||
2060 | { | ||||
2061 | struct slot **ps; | ||||
2062 | struct dev *d = s->opt->dev; | ||||
2063 | long long pos; | ||||
2064 | |||||
2065 | for (ps = &d->slot_list; *ps != s; ps = &(*ps)->next) { | ||||
2066 | #ifdef DEBUG1 | ||||
2067 | if (*ps == NULL((void*)0)) { | ||||
2068 | slot_log(s); | ||||
2069 | log_puts(": can't detach, not on list\n"); | ||||
2070 | panic(); | ||||
2071 | } | ||||
2072 | #endif | ||||
2073 | } | ||||
2074 | *ps = s->next; | ||||
2075 | |||||
2076 | /* | ||||
2077 | * adjust clock, go back d->delta ticks so that slot_attach() | ||||
2078 | * could be called with the resulting state | ||||
2079 | */ | ||||
2080 | pos = s->delta_rem + | ||||
2081 | (long long)s->delta * d->round - | ||||
2082 | (long long)d->delta * s->round; | ||||
2083 | s->delta = pos / (int)d->round; | ||||
2084 | s->delta_rem = pos % d->round; | ||||
2085 | if (s->delta_rem < 0) { | ||||
2086 | s->delta_rem += d->round; | ||||
2087 | s->delta--; | ||||
2088 | } | ||||
2089 | |||||
2090 | #ifdef DEBUG1 | ||||
2091 | if (log_level >= 2) { | ||||
2092 | slot_log(s); | ||||
2093 | log_puts(": detached at "); | ||||
2094 | log_puti(s->delta); | ||||
2095 | log_puts(" + "); | ||||
2096 | log_puti(s->delta_rem); | ||||
2097 | log_puts("/"); | ||||
2098 | log_puti(d->round); | ||||
2099 | log_puts("\n"); | ||||
2100 | } | ||||
2101 | #endif | ||||
2102 | if (s->mode & MODE_PLAY0x01) | ||||
2103 | dev_mix_adjvol(d); | ||||
2104 | |||||
2105 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2106 | if (s->sub.encbuf) { | ||||
2107 | xfree(s->sub.encbuf); | ||||
2108 | s->sub.encbuf = NULL((void*)0); | ||||
2109 | } | ||||
2110 | if (s->sub.resampbuf) { | ||||
2111 | xfree(s->sub.resampbuf); | ||||
2112 | s->sub.resampbuf = NULL((void*)0); | ||||
2113 | } | ||||
2114 | } | ||||
2115 | |||||
2116 | if (s->mode & MODE_PLAY0x01) { | ||||
2117 | if (s->mix.decbuf) { | ||||
2118 | xfree(s->mix.decbuf); | ||||
2119 | s->mix.decbuf = NULL((void*)0); | ||||
2120 | } | ||||
2121 | if (s->mix.resampbuf) { | ||||
2122 | xfree(s->mix.resampbuf); | ||||
2123 | s->mix.resampbuf = NULL((void*)0); | ||||
2124 | } | ||||
2125 | } | ||||
2126 | } | ||||
2127 | |||||
2128 | /* | ||||
2129 | * put the slot in stopping state (draining play buffers) or | ||||
2130 | * stop & detach if no data to drain. | ||||
2131 | */ | ||||
2132 | void | ||||
2133 | slot_stop(struct slot *s, int drain) | ||||
2134 | { | ||||
2135 | #ifdef DEBUG1 | ||||
2136 | if (log_level >= 3) { | ||||
2137 | slot_log(s); | ||||
2138 | log_puts(": stopping\n"); | ||||
2139 | } | ||||
2140 | #endif | ||||
2141 | if (s->pstate == SLOT_START1) { | ||||
2142 | /* | ||||
2143 | * If in rec-only mode, we're already in the READY or | ||||
2144 | * RUN states. We're here because the play buffer was | ||||
2145 | * not full enough, try to start so it's drained. | ||||
2146 | */ | ||||
2147 | s->pstate = SLOT_READY2; | ||||
2148 | slot_ready(s); | ||||
2149 | } | ||||
2150 | |||||
2151 | if (s->pstate == SLOT_RUN3) { | ||||
2152 | if ((s->mode & MODE_PLAY0x01) && drain) { | ||||
2153 | /* | ||||
2154 | * Don't detach, dev_cycle() will do it for us | ||||
2155 | * when the buffer is drained. | ||||
2156 | */ | ||||
2157 | s->pstate = SLOT_STOP4; | ||||
2158 | return; | ||||
2159 | } | ||||
2160 | slot_detach(s); | ||||
2161 | } else if (s->pstate == SLOT_STOP4) { | ||||
2162 | slot_detach(s); | ||||
2163 | } else { | ||||
2164 | #ifdef DEBUG1 | ||||
2165 | if (log_level >= 3) { | ||||
2166 | slot_log(s); | ||||
2167 | log_puts(": not drained (blocked by mmc)\n"); | ||||
2168 | } | ||||
2169 | #endif | ||||
2170 | } | ||||
2171 | |||||
2172 | s->pstate = SLOT_INIT0; | ||||
2173 | s->ops->eof(s->arg); | ||||
2174 | slot_freebufs(s); | ||||
2175 | } | ||||
2176 | |||||
2177 | void | ||||
2178 | slot_skip_update(struct slot *s) | ||||
2179 | { | ||||
2180 | int skip; | ||||
2181 | |||||
2182 | skip = slot_skip(s); | ||||
2183 | while (skip > 0) { | ||||
2184 | #ifdef DEBUG1 | ||||
2185 | if (log_level >= 4) { | ||||
2186 | slot_log(s); | ||||
2187 | log_puts(": catching skipped block\n"); | ||||
2188 | } | ||||
2189 | #endif | ||||
2190 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) | ||||
2191 | s->ops->flush(s->arg); | ||||
2192 | if (s->mode & MODE_PLAY0x01) | ||||
2193 | s->ops->fill(s->arg); | ||||
2194 | skip--; | ||||
2195 | } | ||||
2196 | } | ||||
2197 | |||||
2198 | /* | ||||
2199 | * notify the slot that we just wrote in the play buffer, must be called | ||||
2200 | * after each write | ||||
2201 | */ | ||||
2202 | void | ||||
2203 | slot_write(struct slot *s) | ||||
2204 | { | ||||
2205 | if (s->pstate == SLOT_START1 && s->mix.buf.used == s->mix.buf.len) { | ||||
2206 | #ifdef DEBUG1 | ||||
2207 | if (log_level >= 4) { | ||||
2208 | slot_log(s); | ||||
2209 | log_puts(": switching to READY state\n"); | ||||
2210 | } | ||||
2211 | #endif | ||||
2212 | s->pstate = SLOT_READY2; | ||||
2213 | slot_ready(s); | ||||
2214 | } | ||||
2215 | slot_skip_update(s); | ||||
2216 | } | ||||
2217 | |||||
2218 | /* | ||||
2219 | * notify the slot that we freed some space in the rec buffer | ||||
2220 | */ | ||||
2221 | void | ||||
2222 | slot_read(struct slot *s) | ||||
2223 | { | ||||
2224 | slot_skip_update(s); | ||||
2225 | } | ||||
2226 | |||||
2227 | /* | ||||
2228 | * allocate at control slot | ||||
2229 | */ | ||||
2230 | struct ctlslot * | ||||
2231 | ctlslot_new(struct opt *o, struct ctlops *ops, void *arg) | ||||
2232 | { | ||||
2233 | struct ctlslot *s; | ||||
2234 | struct ctl *c; | ||||
2235 | int i; | ||||
2236 | |||||
2237 | i = 0; | ||||
2238 | for (;;) { | ||||
2239 | if (i == DEV_NCTLSLOT8) | ||||
2240 | return NULL((void*)0); | ||||
2241 | s = ctlslot_array + i; | ||||
2242 | if (s->ops == NULL((void*)0)) | ||||
2243 | break; | ||||
2244 | i++; | ||||
2245 | } | ||||
2246 | s->opt = o; | ||||
2247 | s->self = 1 << i; | ||||
2248 | if (!opt_ref(o)) | ||||
2249 | return NULL((void*)0); | ||||
2250 | s->ops = ops; | ||||
2251 | s->arg = arg; | ||||
2252 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
2253 | if (!ctlslot_visible(s, c)) | ||||
2254 | continue; | ||||
2255 | c->refs_mask |= s->self; | ||||
2256 | } | ||||
2257 | return s; | ||||
2258 | } | ||||
2259 | |||||
2260 | /* | ||||
2261 | * free control slot | ||||
2262 | */ | ||||
2263 | void | ||||
2264 | ctlslot_del(struct ctlslot *s) | ||||
2265 | { | ||||
2266 | struct ctl *c, **pc; | ||||
2267 | |||||
2268 | pc = &ctl_list; | ||||
2269 | while ((c = *pc) != NULL((void*)0)) { | ||||
2270 | c->refs_mask &= ~s->self; | ||||
2271 | if (c->refs_mask == 0) { | ||||
2272 | *pc = c->next; | ||||
2273 | xfree(c); | ||||
2274 | } else | ||||
2275 | pc = &c->next; | ||||
2276 | } | ||||
2277 | s->ops = NULL((void*)0); | ||||
2278 | opt_unref(s->opt); | ||||
2279 | } | ||||
2280 | |||||
2281 | int | ||||
2282 | ctlslot_visible(struct ctlslot *s, struct ctl *c) | ||||
2283 | { | ||||
2284 | if (s->opt == NULL((void*)0)) | ||||
2285 | return 1; | ||||
2286 | switch (c->scope) { | ||||
2287 | case CTL_HW0: | ||||
2288 | case CTL_DEV_MASTER1: | ||||
2289 | return (s->opt->dev == c->u.any.arg0); | ||||
2290 | case CTL_OPT_DEV2: | ||||
2291 | return (s->opt == c->u.any.arg0); | ||||
2292 | case CTL_SLOT_LEVEL3: | ||||
2293 | return (s->opt->dev == c->u.slot_level.slot->opt->dev); | ||||
2294 | default: | ||||
2295 | return 0; | ||||
2296 | } | ||||
2297 | } | ||||
2298 | |||||
2299 | struct ctl * | ||||
2300 | ctlslot_lookup(struct ctlslot *s, int addr) | ||||
2301 | { | ||||
2302 | struct ctl *c; | ||||
2303 | |||||
2304 | c = ctl_list; | ||||
2305 | while (1) { | ||||
2306 | if (c == NULL((void*)0)) | ||||
2307 | return NULL((void*)0); | ||||
2308 | if (c->type != CTL_NONE0 && c->addr == addr) | ||||
2309 | break; | ||||
2310 | c = c->next; | ||||
2311 | } | ||||
2312 | if (!ctlslot_visible(s, c)) | ||||
2313 | return NULL((void*)0); | ||||
2314 | return c; | ||||
2315 | } | ||||
2316 | |||||
2317 | void | ||||
2318 | ctlslot_update(struct ctlslot *s) | ||||
2319 | { | ||||
2320 | struct ctl *c; | ||||
2321 | unsigned int refs_mask; | ||||
2322 | |||||
2323 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
2324 | if (c->type == CTL_NONE0) | ||||
2325 | continue; | ||||
2326 | refs_mask = ctlslot_visible(s, c) ? s->self : 0; | ||||
2327 | |||||
2328 | /* nothing to do if no visibility change */ | ||||
2329 | if (((c->refs_mask & s->self) ^ refs_mask) == 0) | ||||
2330 | continue; | ||||
2331 | /* if control becomes visble */ | ||||
2332 | if (refs_mask) | ||||
2333 | c->refs_mask |= s->self; | ||||
2334 | /* if control is hidden */ | ||||
2335 | c->desc_mask |= s->self; | ||||
2336 | } | ||||
2337 | } | ||||
2338 | |||||
2339 | void | ||||
2340 | ctl_node_log(struct ctl_node *c) | ||||
2341 | { | ||||
2342 | log_puts(c->name); | ||||
2343 | if (c->unit >= 0) | ||||
2344 | log_putu(c->unit); | ||||
2345 | } | ||||
2346 | |||||
2347 | void | ||||
2348 | ctl_log(struct ctl *c) | ||||
2349 | { | ||||
2350 | if (c->group[0] != 0) { | ||||
2351 | log_puts(c->group); | ||||
2352 | log_puts("/"); | ||||
2353 | } | ||||
2354 | ctl_node_log(&c->node0); | ||||
2355 | log_puts("."); | ||||
2356 | log_puts(c->func); | ||||
2357 | log_puts("="); | ||||
2358 | switch (c->type) { | ||||
2359 | case CTL_NONE0: | ||||
2360 | log_puts("none"); | ||||
2361 | break; | ||||
2362 | case CTL_NUM2: | ||||
2363 | case CTL_SW3: | ||||
2364 | log_putu(c->curval); | ||||
2365 | break; | ||||
2366 | case CTL_VEC4: | ||||
2367 | case CTL_LIST5: | ||||
2368 | case CTL_SEL6: | ||||
2369 | ctl_node_log(&c->node1); | ||||
2370 | log_puts(":"); | ||||
2371 | log_putu(c->curval); | ||||
2372 | } | ||||
2373 | log_puts(" at "); | ||||
2374 | log_putu(c->addr); | ||||
2375 | log_puts(" -> "); | ||||
2376 | switch (c->scope) { | ||||
2377 | case CTL_HW0: | ||||
2378 | log_puts("hw:"); | ||||
2379 | log_puts(c->u.hw.dev->name); | ||||
2380 | log_puts("/"); | ||||
2381 | log_putu(c->u.hw.addr); | ||||
2382 | break; | ||||
2383 | case CTL_DEV_MASTER1: | ||||
2384 | log_puts("dev_master:"); | ||||
2385 | log_puts(c->u.dev_master.dev->name); | ||||
2386 | break; | ||||
2387 | case CTL_SLOT_LEVEL3: | ||||
2388 | log_puts("slot_level:"); | ||||
2389 | log_puts(c->u.slot_level.slot->name); | ||||
2390 | log_putu(c->u.slot_level.slot->unit); | ||||
2391 | break; | ||||
2392 | case CTL_OPT_DEV2: | ||||
2393 | log_puts("opt_dev:"); | ||||
2394 | log_puts(c->u.opt_dev.opt->name); | ||||
2395 | log_puts("/"); | ||||
2396 | log_puts(c->u.opt_dev.dev->name); | ||||
2397 | break; | ||||
2398 | default: | ||||
2399 | log_puts("unknown"); | ||||
2400 | } | ||||
2401 | } | ||||
2402 | |||||
2403 | int | ||||
2404 | ctl_setval(struct ctl *c, int val) | ||||
2405 | { | ||||
2406 | if (c->curval == val) { | ||||
2407 | if (log_level >= 3) { | ||||
2408 | ctl_log(c); | ||||
2409 | log_puts(": already set\n"); | ||||
2410 | } | ||||
2411 | return 1; | ||||
2412 | } | ||||
2413 | if (val < 0 || val > c->maxval) { | ||||
2414 | if (log_level >= 3) { | ||||
2415 | log_putu(val); | ||||
2416 | log_puts(": ctl val out of bounds\n"); | ||||
2417 | } | ||||
2418 | return 0; | ||||
2419 | } | ||||
2420 | |||||
2421 | switch (c->scope) { | ||||
2422 | case CTL_HW0: | ||||
2423 | if (log_level >= 3) { | ||||
2424 | ctl_log(c); | ||||
2425 | log_puts(": marked as dirty\n"); | ||||
2426 | } | ||||
2427 | c->curval = val; | ||||
2428 | c->dirty = 1; | ||||
2429 | return dev_ref(c->u.hw.dev); | ||||
2430 | case CTL_DEV_MASTER1: | ||||
2431 | if (!c->u.dev_master.dev->master_enabled) | ||||
2432 | return 1; | ||||
2433 | dev_master(c->u.dev_master.dev, val); | ||||
2434 | dev_midi_master(c->u.dev_master.dev); | ||||
2435 | c->val_mask = ~0U; | ||||
2436 | c->curval = val; | ||||
2437 | return 1; | ||||
2438 | case CTL_SLOT_LEVEL3: | ||||
2439 | slot_setvol(c->u.slot_level.slot, val); | ||||
2440 | // XXX change dev_midi_vol() into slot_midi_vol() | ||||
2441 | dev_midi_vol(c->u.slot_level.slot->opt->dev, c->u.slot_level.slot); | ||||
2442 | c->val_mask = ~0U; | ||||
2443 | c->curval = val; | ||||
2444 | return 1; | ||||
2445 | case CTL_OPT_DEV2: | ||||
2446 | c->u.opt_dev.opt->alt_first = c->u.opt_dev.dev; | ||||
2447 | opt_setdev(c->u.opt_dev.opt, c->u.opt_dev.dev); | ||||
2448 | return 1; | ||||
2449 | default: | ||||
2450 | if (log_level >= 2) { | ||||
2451 | ctl_log(c); | ||||
2452 | log_puts(": not writable\n"); | ||||
2453 | } | ||||
2454 | return 1; | ||||
2455 | } | ||||
2456 | } | ||||
2457 | |||||
2458 | /* | ||||
2459 | * add a ctl | ||||
2460 | */ | ||||
2461 | struct ctl * | ||||
2462 | ctl_new(int scope, void *arg0, void *arg1, | ||||
2463 | int type, char *gstr, | ||||
2464 | char *str0, int unit0, char *func, | ||||
2465 | char *str1, int unit1, int maxval, int val) | ||||
2466 | { | ||||
2467 | struct ctl *c, **pc; | ||||
2468 | struct ctlslot *s; | ||||
2469 | int addr; | ||||
2470 | int i; | ||||
2471 | |||||
2472 | /* | ||||
2473 | * find the smallest unused addr number and | ||||
2474 | * the last position in the list | ||||
2475 | */ | ||||
2476 | addr = 0; | ||||
2477 | for (pc = &ctl_list; (c = *pc) != NULL((void*)0); pc = &c->next) { | ||||
2478 | if (c->addr > addr) | ||||
2479 | addr = c->addr; | ||||
2480 | } | ||||
2481 | addr++; | ||||
2482 | |||||
2483 | c = xmalloc(sizeof(struct ctl)); | ||||
2484 | c->type = type; | ||||
2485 | strlcpy(c->func, func, CTL_NAMEMAX16); | ||||
2486 | strlcpy(c->group, gstr, CTL_NAMEMAX16); | ||||
2487 | strlcpy(c->node0.name, str0, CTL_NAMEMAX16); | ||||
2488 | c->node0.unit = unit0; | ||||
2489 | if (c->type == CTL_VEC4 || c->type == CTL_LIST5 || c->type == CTL_SEL6) { | ||||
2490 | strlcpy(c->node1.name, str1, CTL_NAMEMAX16); | ||||
| |||||
2491 | c->node1.unit = unit1; | ||||
2492 | } else | ||||
2493 | memset(&c->node1, 0, sizeof(struct ctl_node)); | ||||
2494 | c->scope = scope; | ||||
2495 | c->u.any.arg0 = arg0; | ||||
2496 | switch (scope) { | ||||
2497 | case CTL_HW0: | ||||
2498 | c->u.hw.addr = *(unsigned int *)arg1; | ||||
2499 | break; | ||||
2500 | case CTL_OPT_DEV2: | ||||
2501 | c->u.any.arg1 = arg1; | ||||
2502 | break; | ||||
2503 | default: | ||||
2504 | c->u.any.arg1 = NULL((void*)0); | ||||
2505 | } | ||||
2506 | c->addr = addr; | ||||
2507 | c->maxval = maxval; | ||||
2508 | c->val_mask = ~0; | ||||
2509 | c->desc_mask = ~0; | ||||
2510 | c->curval = val; | ||||
2511 | c->dirty = 0; | ||||
2512 | c->refs_mask = CTL_DEVMASK(1 << 31); | ||||
2513 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2514 | if (s->ops == NULL((void*)0)) | ||||
2515 | continue; | ||||
2516 | if (ctlslot_visible(s, c)) | ||||
2517 | c->refs_mask |= 1 << i; | ||||
2518 | } | ||||
2519 | c->next = *pc; | ||||
2520 | *pc = c; | ||||
2521 | #ifdef DEBUG1 | ||||
2522 | if (log_level >= 2) { | ||||
2523 | ctl_log(c); | ||||
2524 | log_puts(": added\n"); | ||||
2525 | } | ||||
2526 | #endif | ||||
2527 | return c; | ||||
2528 | } | ||||
2529 | |||||
2530 | void | ||||
2531 | ctl_update(struct ctl *c) | ||||
2532 | { | ||||
2533 | struct ctlslot *s; | ||||
2534 | unsigned int refs_mask; | ||||
2535 | int i; | ||||
2536 | |||||
2537 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2538 | if (s->ops == NULL((void*)0)) | ||||
2539 | continue; | ||||
2540 | refs_mask = ctlslot_visible(s, c) ? s->self : 0; | ||||
2541 | |||||
2542 | /* nothing to do if no visibility change */ | ||||
2543 | if (((c->refs_mask & s->self) ^ refs_mask) == 0) | ||||
2544 | continue; | ||||
2545 | /* if control becomes visble */ | ||||
2546 | if (refs_mask) | ||||
2547 | c->refs_mask |= s->self; | ||||
2548 | /* if control is hidden */ | ||||
2549 | c->desc_mask |= s->self; | ||||
2550 | } | ||||
2551 | } | ||||
2552 | |||||
2553 | int | ||||
2554 | ctl_match(struct ctl *c, int scope, void *arg0, void *arg1) | ||||
2555 | { | ||||
2556 | if (c->type == CTL_NONE0 || c->scope != scope || c->u.any.arg0 != arg0) | ||||
2557 | return 0; | ||||
2558 | if (arg0 != NULL((void*)0) && c->u.any.arg0 != arg0) | ||||
2559 | return 0; | ||||
2560 | switch (scope) { | ||||
2561 | case CTL_HW0: | ||||
2562 | if (arg1 != NULL((void*)0) && c->u.hw.addr != *(unsigned int *)arg1) | ||||
2563 | return 0; | ||||
2564 | break; | ||||
2565 | case CTL_OPT_DEV2: | ||||
2566 | if (arg1 != NULL((void*)0) && c->u.any.arg1 != arg1) | ||||
2567 | return 0; | ||||
2568 | break; | ||||
2569 | } | ||||
2570 | return 1; | ||||
2571 | } | ||||
2572 | |||||
2573 | struct ctl * | ||||
2574 | ctl_find(int scope, void *arg0, void *arg1) | ||||
2575 | { | ||||
2576 | struct ctl *c; | ||||
2577 | |||||
2578 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
2579 | if (ctl_match(c, scope, arg0, arg1)) | ||||
2580 | return c; | ||||
2581 | } | ||||
2582 | return NULL((void*)0); | ||||
2583 | } | ||||
2584 | |||||
2585 | int | ||||
2586 | ctl_onval(int scope, void *arg0, void *arg1, int val) | ||||
2587 | { | ||||
2588 | struct ctl *c; | ||||
2589 | |||||
2590 | c = ctl_find(scope, arg0, arg1); | ||||
2591 | if (c == NULL((void*)0)) | ||||
2592 | return 0; | ||||
2593 | c->curval = val; | ||||
2594 | c->val_mask = ~0U; | ||||
2595 | return 1; | ||||
2596 | } | ||||
2597 | |||||
2598 | void | ||||
2599 | ctl_del(int scope, void *arg0, void *arg1) | ||||
2600 | { | ||||
2601 | struct ctl *c, **pc; | ||||
2602 | |||||
2603 | pc = &ctl_list; | ||||
2604 | for (;;) { | ||||
2605 | c = *pc; | ||||
2606 | if (c == NULL((void*)0)) | ||||
2607 | return; | ||||
2608 | if (ctl_match(c, scope, arg0, arg1)) { | ||||
2609 | #ifdef DEBUG1 | ||||
2610 | if (log_level >= 2) { | ||||
2611 | ctl_log(c); | ||||
2612 | log_puts(": removed\n"); | ||||
2613 | } | ||||
2614 | #endif | ||||
2615 | c->refs_mask &= ~CTL_DEVMASK(1 << 31); | ||||
2616 | if (c->refs_mask == 0) { | ||||
2617 | *pc = c->next; | ||||
2618 | xfree(c); | ||||
2619 | continue; | ||||
2620 | } | ||||
2621 | c->type = CTL_NONE0; | ||||
2622 | c->desc_mask = ~0; | ||||
2623 | } | ||||
2624 | pc = &c->next; | ||||
2625 | } | ||||
2626 | } | ||||
2627 | |||||
2628 | void | ||||
2629 | dev_ctlsync(struct dev *d) | ||||
2630 | { | ||||
2631 | struct ctl *c; | ||||
2632 | struct ctlslot *s; | ||||
2633 | int found, i; | ||||
2634 | |||||
2635 | found = 0; | ||||
2636 | for (c = ctl_list; c != NULL((void*)0); c = c->next) { | ||||
| |||||
2637 | if (c->scope == CTL_HW0 && | ||||
2638 | c->u.hw.dev == d && | ||||
2639 | c->type == CTL_NUM2 && | ||||
2640 | strcmp(c->group, d->name) == 0 && | ||||
2641 | strcmp(c->node0.name, "output") == 0 && | ||||
2642 | strcmp(c->func, "level") == 0) | ||||
2643 | found = 1; | ||||
2644 | } | ||||
2645 | |||||
2646 | if (d->master_enabled && found) { | ||||
2647 | if (log_level >= 2) { | ||||
2648 | dev_log(d); | ||||
2649 | log_puts(": software master level control disabled\n"); | ||||
2650 | } | ||||
2651 | d->master_enabled = 0; | ||||
2652 | ctl_del(CTL_DEV_MASTER1, d, NULL((void*)0)); | ||||
2653 | } else if (!d->master_enabled
| ||||
2654 | if (log_level >= 2) { | ||||
2655 | dev_log(d); | ||||
2656 | log_puts(": software master level control enabled\n"); | ||||
2657 | } | ||||
2658 | d->master_enabled = 1; | ||||
2659 | ctl_new(CTL_DEV_MASTER1, d, NULL((void*)0), | ||||
2660 | CTL_NUM2, d->name, "output", -1, "level", | ||||
2661 | NULL((void*)0), -1, 127, d->master); | ||||
2662 | } | ||||
2663 | |||||
2664 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2665 | if (s->ops == NULL((void*)0)) | ||||
2666 | continue; | ||||
2667 | if (s->opt->dev == d) | ||||
2668 | s->ops->sync(s->arg); | ||||
2669 | } | ||||
2670 | } |