File: | src/usr.bin/sndiod/dev.c |
Warning: | line 2496, 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.107 2023/12/09 22:12:03 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)(((long long)(s->mix.weight) * (long long)(s->mix .vol)) >> (24 - 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 << (24 - 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)(((long long)(weight) * (long long)((aparams_ctltovol[d ->master] << (24 - 16)))) >> (24 - 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 << (24 - 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) && d->idle >= d->bufsz && | ||||
684 | (mtc_array[0].dev != d || 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 | d->idle = 0; | ||||
748 | |||||
749 | /* | ||||
750 | * skip cycles for XRUN_SYNC correction | ||||
751 | */ | ||||
752 | slot_skip(s); | ||||
753 | if (s->skip < 0) { | ||||
754 | s->skip++; | ||||
755 | ps = &s->next; | ||||
756 | continue; | ||||
757 | } | ||||
758 | |||||
759 | #ifdef DEBUG1 | ||||
760 | if (s->pstate == SLOT_STOP4 && !(s->mode & MODE_PLAY0x01)) { | ||||
761 | slot_log(s); | ||||
762 | log_puts(": rec-only slots can't be drained\n"); | ||||
763 | panic(); | ||||
764 | } | ||||
765 | #endif | ||||
766 | /* | ||||
767 | * check if stopped stream finished draining | ||||
768 | */ | ||||
769 | if (s->pstate == SLOT_STOP4 && | ||||
770 | s->mix.buf.used < s->round * s->mix.bpf) { | ||||
771 | /* | ||||
772 | * partial blocks are zero-filled by socket | ||||
773 | * layer, so s->mix.buf.used == 0 and we can | ||||
774 | * destroy the buffer | ||||
775 | */ | ||||
776 | *ps = s->next; | ||||
777 | s->pstate = SLOT_INIT0; | ||||
778 | s->ops->eof(s->arg); | ||||
779 | slot_freebufs(s); | ||||
780 | dev_mix_adjvol(d); | ||||
781 | #ifdef DEBUG1 | ||||
782 | if (log_level >= 3) { | ||||
783 | slot_log(s); | ||||
784 | log_puts(": drained\n"); | ||||
785 | } | ||||
786 | #endif | ||||
787 | continue; | ||||
788 | } | ||||
789 | |||||
790 | /* | ||||
791 | * check for xruns | ||||
792 | */ | ||||
793 | if (((s->mode & MODE_PLAY0x01) && | ||||
794 | s->mix.buf.used < s->round * s->mix.bpf) || | ||||
795 | ((s->mode & MODE_RECMASK(0x02 | 0x10)) && | ||||
796 | s->sub.buf.len - s->sub.buf.used < | ||||
797 | s->round * s->sub.bpf)) { | ||||
798 | |||||
799 | #ifdef DEBUG1 | ||||
800 | if (log_level >= 3) { | ||||
801 | slot_log(s); | ||||
802 | log_puts(": xrun, pause cycle\n"); | ||||
803 | } | ||||
804 | #endif | ||||
805 | if (s->xrun == XRUN_IGNORE0) { | ||||
806 | s->delta -= s->round; | ||||
807 | ps = &s->next; | ||||
808 | } else if (s->xrun == XRUN_SYNC1) { | ||||
809 | s->skip++; | ||||
810 | ps = &s->next; | ||||
811 | } else if (s->xrun == XRUN_ERROR2) { | ||||
812 | s->ops->exit(s->arg); | ||||
813 | *ps = s->next; | ||||
814 | } else { | ||||
815 | #ifdef DEBUG1 | ||||
816 | slot_log(s); | ||||
817 | log_puts(": bad xrun mode\n"); | ||||
818 | panic(); | ||||
819 | #endif | ||||
820 | } | ||||
821 | continue; | ||||
822 | } | ||||
823 | if ((s->mode & MODE_RECMASK(0x02 | 0x10)) && !(s->pstate == SLOT_STOP4)) { | ||||
824 | if (s->sub.prime == 0) { | ||||
825 | dev_sub_bcopy(d, s); | ||||
826 | s->ops->flush(s->arg); | ||||
827 | } else { | ||||
828 | #ifdef DEBUG1 | ||||
829 | if (log_level >= 3) { | ||||
830 | slot_log(s); | ||||
831 | log_puts(": prime = "); | ||||
832 | log_puti(s->sub.prime); | ||||
833 | log_puts("\n"); | ||||
834 | } | ||||
835 | #endif | ||||
836 | s->sub.prime--; | ||||
837 | } | ||||
838 | } | ||||
839 | if (s->mode & MODE_PLAY0x01) { | ||||
840 | dev_mix_badd(d, s); | ||||
841 | if (s->pstate != SLOT_STOP4) | ||||
842 | s->ops->fill(s->arg); | ||||
843 | } | ||||
844 | ps = &s->next; | ||||
845 | } | ||||
846 | if ((d->mode & MODE_PLAY0x01) && d->encbuf) { | ||||
847 | enc_do(&d->enc, (unsigned char *)DEV_PBUF(d)((d)->pbuf + (d)->poffs * (d)->pchan), | ||||
848 | d->encbuf, d->round); | ||||
849 | } | ||||
850 | } | ||||
851 | |||||
852 | /* | ||||
853 | * called at every clock tick by the device | ||||
854 | */ | ||||
855 | void | ||||
856 | dev_onmove(struct dev *d, int delta) | ||||
857 | { | ||||
858 | long long pos; | ||||
859 | struct slot *s, *snext; | ||||
860 | |||||
861 | d->delta += delta; | ||||
862 | |||||
863 | if (d->slot_list == NULL((void *)0)) | ||||
864 | d->idle += delta; | ||||
865 | |||||
866 | for (s = d->slot_list; s != NULL((void *)0); s = snext) { | ||||
867 | /* | ||||
868 | * s->ops->onmove() may remove the slot | ||||
869 | */ | ||||
870 | snext = s->next; | ||||
871 | pos = s->delta_rem + | ||||
872 | (long long)s->delta * d->round + | ||||
873 | (long long)delta * s->round; | ||||
874 | s->delta = pos / (int)d->round; | ||||
875 | s->delta_rem = pos % d->round; | ||||
876 | if (s->delta_rem < 0) { | ||||
877 | s->delta_rem += d->round; | ||||
878 | s->delta--; | ||||
879 | } | ||||
880 | if (s->delta >= 0) | ||||
881 | s->ops->onmove(s->arg); | ||||
882 | } | ||||
883 | |||||
884 | if (mtc_array[0].dev == d && mtc_array[0].tstate == MTC_RUN3) | ||||
885 | mtc_midi_qfr(&mtc_array[0], delta); | ||||
886 | } | ||||
887 | |||||
888 | void | ||||
889 | dev_master(struct dev *d, unsigned int master) | ||||
890 | { | ||||
891 | struct ctl *c; | ||||
892 | unsigned int v; | ||||
893 | |||||
894 | if (log_level >= 2) { | ||||
895 | dev_log(d); | ||||
896 | log_puts(": master volume set to "); | ||||
897 | log_putu(master); | ||||
898 | log_puts("\n"); | ||||
899 | } | ||||
900 | if (d->master_enabled) { | ||||
901 | d->master = master; | ||||
902 | if (d->mode & MODE_PLAY0x01) | ||||
903 | dev_mix_adjvol(d); | ||||
904 | } else { | ||||
905 | for (c = ctl_list; c != NULL((void *)0); c = c->next) { | ||||
906 | if (c->scope != CTL_HW0 || c->u.hw.dev != d) | ||||
907 | continue; | ||||
908 | if (c->type != CTL_NUM2 || | ||||
909 | strcmp(c->group, d->name) != 0 || | ||||
910 | strcmp(c->node0.name, "output") != 0 || | ||||
911 | strcmp(c->func, "level") != 0) | ||||
912 | continue; | ||||
913 | v = (master * c->maxval + 64) / 127; | ||||
914 | ctl_setval(c, v); | ||||
915 | } | ||||
916 | } | ||||
917 | } | ||||
918 | |||||
919 | /* | ||||
920 | * Create a sndio device | ||||
921 | */ | ||||
922 | struct dev * | ||||
923 | dev_new(char *path, struct aparams *par, | ||||
924 | unsigned int mode, unsigned int bufsz, unsigned int round, | ||||
925 | unsigned int rate, unsigned int hold, unsigned int autovol) | ||||
926 | { | ||||
927 | struct dev *d, **pd; | ||||
928 | |||||
929 | if (dev_sndnum == DEV_NMAX16) { | ||||
930 | if (log_level >= 1) | ||||
931 | log_puts("too many devices\n"); | ||||
932 | return NULL((void *)0); | ||||
933 | } | ||||
934 | d = xmalloc(sizeof(struct dev)); | ||||
935 | d->path = path; | ||||
936 | d->num = dev_sndnum++; | ||||
937 | |||||
938 | d->reqpar = *par; | ||||
939 | d->reqmode = mode; | ||||
940 | d->reqpchan = d->reqrchan = 0; | ||||
941 | d->reqbufsz = bufsz; | ||||
942 | d->reqround = round; | ||||
943 | d->reqrate = rate; | ||||
944 | d->hold = hold; | ||||
945 | d->autovol = autovol; | ||||
946 | d->refcnt = 0; | ||||
947 | d->pstate = DEV_CFG0; | ||||
948 | d->slot_list = NULL((void *)0); | ||||
949 | d->master = MIDI_MAXCTL127; | ||||
950 | d->master_enabled = 0; | ||||
951 | d->alt_next = d; | ||||
952 | snprintf(d->name, CTL_NAMEMAX16, "%u", d->num); | ||||
953 | for (pd = &dev_list; *pd != NULL((void *)0); pd = &(*pd)->next) | ||||
954 | ; | ||||
955 | d->next = *pd; | ||||
956 | *pd = d; | ||||
957 | return d; | ||||
958 | } | ||||
959 | |||||
960 | /* | ||||
961 | * adjust device parameters and mode | ||||
962 | */ | ||||
963 | void | ||||
964 | dev_adjpar(struct dev *d, int mode, | ||||
965 | int pmax, int rmax) | ||||
966 | { | ||||
967 | d->reqmode |= mode & MODE_AUDIOMASK(0x01 | 0x02 | 0x10); | ||||
968 | if (mode & MODE_PLAY0x01) { | ||||
969 | if (d->reqpchan < pmax + 1) | ||||
970 | d->reqpchan = pmax + 1; | ||||
971 | } | ||||
972 | if (mode & MODE_REC0x02) { | ||||
973 | if (d->reqrchan < rmax + 1) | ||||
974 | d->reqrchan = rmax + 1; | ||||
975 | } | ||||
976 | } | ||||
977 | |||||
978 | /* | ||||
979 | * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer, | ||||
980 | * monitor, midi control, and any necessary conversions. | ||||
981 | * | ||||
982 | * Note that record and play buffers are always allocated, even if the | ||||
983 | * underlying device doesn't support both modes. | ||||
984 | */ | ||||
985 | int | ||||
986 | dev_allocbufs(struct dev *d) | ||||
987 | { | ||||
988 | /* | ||||
989 | * Create record buffer. | ||||
990 | */ | ||||
991 | |||||
992 | /* Create device <-> demuxer buffer */ | ||||
993 | d->rbuf = xmalloc(d->round * d->rchan * sizeof(adata_t)); | ||||
994 | |||||
995 | /* Insert a converter, if needed. */ | ||||
996 | if (!aparams_native(&d->par)) { | ||||
997 | dec_init(&d->dec, &d->par, d->rchan); | ||||
998 | d->decbuf = xmalloc(d->round * d->rchan * d->par.bps); | ||||
999 | } else | ||||
1000 | d->decbuf = NULL((void *)0); | ||||
1001 | |||||
1002 | /* | ||||
1003 | * Create play buffer | ||||
1004 | */ | ||||
1005 | |||||
1006 | /* Create device <-> mixer buffer */ | ||||
1007 | d->poffs = 0; | ||||
1008 | d->psize = d->bufsz + d->round; | ||||
1009 | d->pbuf = xmalloc(d->psize * d->pchan * sizeof(adata_t)); | ||||
1010 | d->mode |= MODE_MON0x10; | ||||
1011 | |||||
1012 | /* Append a converter, if needed. */ | ||||
1013 | if (!aparams_native(&d->par)) { | ||||
1014 | enc_init(&d->enc, &d->par, d->pchan); | ||||
1015 | d->encbuf = xmalloc(d->round * d->pchan * d->par.bps); | ||||
1016 | } else | ||||
1017 | d->encbuf = NULL((void *)0); | ||||
1018 | |||||
1019 | /* | ||||
1020 | * Initially fill the record buffer with zeroed samples. This ensures | ||||
1021 | * that when a client records from a play-only device the client just | ||||
1022 | * gets silence. | ||||
1023 | */ | ||||
1024 | memset(d->rbuf, 0, d->round * d->rchan * sizeof(adata_t)); | ||||
1025 | |||||
1026 | if (log_level >= 2) { | ||||
1027 | dev_log(d); | ||||
1028 | log_puts(": "); | ||||
1029 | log_putu(d->rate); | ||||
1030 | log_puts("Hz, "); | ||||
1031 | aparams_log(&d->par); | ||||
1032 | if (d->mode & MODE_PLAY0x01) { | ||||
1033 | log_puts(", play 0:"); | ||||
1034 | log_puti(d->pchan - 1); | ||||
1035 | } | ||||
1036 | if (d->mode & MODE_REC0x02) { | ||||
1037 | log_puts(", rec 0:"); | ||||
1038 | log_puti(d->rchan - 1); | ||||
1039 | } | ||||
1040 | log_puts(", "); | ||||
1041 | log_putu(d->bufsz / d->round); | ||||
1042 | log_puts(" blocks of "); | ||||
1043 | log_putu(d->round); | ||||
1044 | log_puts(" frames"); | ||||
1045 | if (d == mtc_array[0].dev) | ||||
1046 | log_puts(", mtc"); | ||||
1047 | log_puts("\n"); | ||||
1048 | } | ||||
1049 | return 1; | ||||
1050 | } | ||||
1051 | |||||
1052 | /* | ||||
1053 | * Reset parameters and open the device. | ||||
1054 | */ | ||||
1055 | int | ||||
1056 | dev_open(struct dev *d) | ||||
1057 | { | ||||
1058 | d->mode = d->reqmode; | ||||
1059 | d->round = d->reqround; | ||||
1060 | d->bufsz = d->reqbufsz; | ||||
1061 | d->rate = d->reqrate; | ||||
1062 | d->pchan = d->reqpchan; | ||||
1063 | d->rchan = d->reqrchan; | ||||
1064 | d->par = d->reqpar; | ||||
1065 | if (d->pchan == 0) | ||||
1066 | d->pchan = 2; | ||||
1067 | if (d->rchan == 0) | ||||
1068 | d->rchan = 2; | ||||
1069 | if (!dev_sio_open(d)) { | ||||
1070 | if (log_level >= 1) { | ||||
1071 | dev_log(d); | ||||
1072 | log_puts(": failed to open audio device\n"); | ||||
1073 | } | ||||
1074 | return 0; | ||||
1075 | } | ||||
1076 | if (!dev_allocbufs(d)) | ||||
1077 | return 0; | ||||
1078 | |||||
1079 | d->pstate = DEV_INIT1; | ||||
1080 | return 1; | ||||
1081 | } | ||||
1082 | |||||
1083 | /* | ||||
1084 | * Force all slots to exit and close device, called after an error | ||||
1085 | */ | ||||
1086 | void | ||||
1087 | dev_abort(struct dev *d) | ||||
1088 | { | ||||
1089 | int i; | ||||
1090 | struct slot *s; | ||||
1091 | struct ctlslot *c; | ||||
1092 | struct opt *o; | ||||
1093 | |||||
1094 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1095 | if (s->opt == NULL((void *)0) || s->opt->dev != d) | ||||
1096 | continue; | ||||
1097 | if (s->ops) { | ||||
1098 | s->ops->exit(s->arg); | ||||
1099 | s->ops = NULL((void *)0); | ||||
1100 | } | ||||
1101 | } | ||||
1102 | d->slot_list = NULL((void *)0); | ||||
1103 | |||||
1104 | for (o = opt_list; o != NULL((void *)0); o = o->next) { | ||||
1105 | if (o->dev != d) | ||||
1106 | continue; | ||||
1107 | for (c = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, c++) { | ||||
1108 | if (c->ops == NULL((void *)0)) | ||||
1109 | continue; | ||||
1110 | if (c->opt == o) { | ||||
1111 | c->ops->exit(s->arg); | ||||
1112 | c->ops = NULL((void *)0); | ||||
1113 | } | ||||
1114 | } | ||||
1115 | |||||
1116 | midi_abort(o->midi); | ||||
1117 | } | ||||
1118 | |||||
1119 | if (d->pstate != DEV_CFG0) | ||||
1120 | dev_close(d); | ||||
1121 | } | ||||
1122 | |||||
1123 | /* | ||||
1124 | * force the device to go in DEV_CFG state, the caller is supposed to | ||||
1125 | * ensure buffers are drained | ||||
1126 | */ | ||||
1127 | void | ||||
1128 | dev_freebufs(struct dev *d) | ||||
1129 | { | ||||
1130 | #ifdef DEBUG1 | ||||
1131 | if (log_level >= 3) { | ||||
1132 | dev_log(d); | ||||
1133 | log_puts(": closing\n"); | ||||
1134 | } | ||||
1135 | #endif | ||||
1136 | if (d->mode & MODE_PLAY0x01) { | ||||
1137 | if (d->encbuf != NULL((void *)0)) | ||||
1138 | xfree(d->encbuf); | ||||
1139 | xfree(d->pbuf); | ||||
1140 | } | ||||
1141 | if (d->mode & MODE_REC0x02) { | ||||
1142 | if (d->decbuf != NULL((void *)0)) | ||||
1143 | xfree(d->decbuf); | ||||
1144 | xfree(d->rbuf); | ||||
1145 | } | ||||
1146 | } | ||||
1147 | |||||
1148 | /* | ||||
1149 | * Close the device and exit all slots | ||||
1150 | */ | ||||
1151 | void | ||||
1152 | dev_close(struct dev *d) | ||||
1153 | { | ||||
1154 | d->pstate = DEV_CFG0; | ||||
1155 | dev_sio_close(d); | ||||
1156 | dev_freebufs(d); | ||||
1157 | |||||
1158 | if (d->master_enabled) { | ||||
1159 | d->master_enabled = 0; | ||||
1160 | ctl_del(CTL_DEV_MASTER1, d, NULL((void *)0)); | ||||
1161 | } | ||||
1162 | } | ||||
1163 | |||||
1164 | int | ||||
1165 | dev_ref(struct dev *d) | ||||
1166 | { | ||||
1167 | #ifdef DEBUG1 | ||||
1168 | if (log_level >= 3) { | ||||
1169 | dev_log(d); | ||||
1170 | log_puts(": device requested\n"); | ||||
1171 | } | ||||
1172 | #endif | ||||
1173 | if (d->pstate == DEV_CFG0 && !dev_open(d)) | ||||
1174 | return 0; | ||||
1175 | d->refcnt++; | ||||
1176 | return 1; | ||||
1177 | } | ||||
1178 | |||||
1179 | void | ||||
1180 | dev_unref(struct dev *d) | ||||
1181 | { | ||||
1182 | #ifdef DEBUG1 | ||||
1183 | if (log_level >= 3) { | ||||
1184 | dev_log(d); | ||||
1185 | log_puts(": device released\n"); | ||||
1186 | } | ||||
1187 | #endif | ||||
1188 | d->refcnt--; | ||||
1189 | if (d->refcnt == 0 && d->pstate == DEV_INIT1) | ||||
1190 | dev_close(d); | ||||
1191 | } | ||||
1192 | |||||
1193 | /* | ||||
1194 | * initialize the device with the current parameters | ||||
1195 | */ | ||||
1196 | int | ||||
1197 | dev_init(struct dev *d) | ||||
1198 | { | ||||
1199 | if ((d->reqmode & MODE_AUDIOMASK(0x01 | 0x02 | 0x10)) == 0) { | ||||
1200 | #ifdef DEBUG1 | ||||
1201 | dev_log(d); | ||||
1202 | log_puts(": has no streams\n"); | ||||
1203 | #endif | ||||
1204 | return 0; | ||||
1205 | } | ||||
1206 | if (d->hold && !dev_ref(d)) | ||||
1207 | return 0; | ||||
1208 | return 1; | ||||
1209 | } | ||||
1210 | |||||
1211 | /* | ||||
1212 | * Unless the device is already in process of closing, request it to close | ||||
1213 | */ | ||||
1214 | void | ||||
1215 | dev_done(struct dev *d) | ||||
1216 | { | ||||
1217 | #ifdef DEBUG1 | ||||
1218 | if (log_level >= 3) { | ||||
1219 | dev_log(d); | ||||
1220 | log_puts(": draining\n"); | ||||
1221 | } | ||||
1222 | #endif | ||||
1223 | if (mtc_array[0].dev == d && mtc_array[0].tstate != MTC_STOP1) | ||||
1224 | mtc_stop(&mtc_array[0]); | ||||
1225 | if (d->hold) | ||||
1226 | dev_unref(d); | ||||
1227 | } | ||||
1228 | |||||
1229 | struct dev * | ||||
1230 | dev_bynum(int num) | ||||
1231 | { | ||||
1232 | struct dev *d; | ||||
1233 | |||||
1234 | for (d = dev_list; d != NULL((void *)0); d = d->next) { | ||||
1235 | if (d->num == num) | ||||
1236 | return d; | ||||
1237 | } | ||||
1238 | return NULL((void *)0); | ||||
1239 | } | ||||
1240 | |||||
1241 | /* | ||||
1242 | * Free the device | ||||
1243 | */ | ||||
1244 | void | ||||
1245 | dev_del(struct dev *d) | ||||
1246 | { | ||||
1247 | struct dev **p; | ||||
1248 | |||||
1249 | #ifdef DEBUG1 | ||||
1250 | if (log_level >= 3) { | ||||
1251 | dev_log(d); | ||||
1252 | log_puts(": deleting\n"); | ||||
1253 | } | ||||
1254 | #endif | ||||
1255 | if (d->pstate != DEV_CFG0) | ||||
1256 | dev_close(d); | ||||
1257 | for (p = &dev_list; *p != d; p = &(*p)->next) { | ||||
1258 | #ifdef DEBUG1 | ||||
1259 | if (*p == NULL((void *)0)) { | ||||
1260 | dev_log(d); | ||||
1261 | log_puts(": device to delete not on the list\n"); | ||||
1262 | panic(); | ||||
1263 | } | ||||
1264 | #endif | ||||
1265 | } | ||||
1266 | *p = d->next; | ||||
1267 | xfree(d); | ||||
1268 | } | ||||
1269 | |||||
1270 | unsigned int | ||||
1271 | dev_roundof(struct dev *d, unsigned int newrate) | ||||
1272 | { | ||||
1273 | return (d->round * newrate + d->rate / 2) / d->rate; | ||||
1274 | } | ||||
1275 | |||||
1276 | /* | ||||
1277 | * If the device is paused, then resume it. | ||||
1278 | */ | ||||
1279 | void | ||||
1280 | dev_wakeup(struct dev *d) | ||||
1281 | { | ||||
1282 | if (d->pstate == DEV_INIT1) { | ||||
1283 | if (log_level >= 2) { | ||||
1284 | dev_log(d); | ||||
1285 | log_puts(": device started\n"); | ||||
1286 | } | ||||
1287 | if (d->mode & MODE_PLAY0x01) { | ||||
1288 | d->prime = d->bufsz; | ||||
1289 | } else { | ||||
1290 | d->prime = 0; | ||||
1291 | } | ||||
1292 | d->idle = 0; | ||||
1293 | d->poffs = 0; | ||||
1294 | |||||
1295 | /* | ||||
1296 | * empty cycles don't increment delta, so it's ok to | ||||
1297 | * start at 0 | ||||
1298 | **/ | ||||
1299 | d->delta = 0; | ||||
1300 | |||||
1301 | d->pstate = DEV_RUN2; | ||||
1302 | dev_sio_start(d); | ||||
1303 | } | ||||
1304 | } | ||||
1305 | |||||
1306 | /* | ||||
1307 | * Return true if both of the given devices can run the same | ||||
1308 | * clients | ||||
1309 | */ | ||||
1310 | int | ||||
1311 | dev_iscompat(struct dev *o, struct dev *n) | ||||
1312 | { | ||||
1313 | if (((long long)o->round * n->rate != (long long)n->round * o->rate) || | ||||
1314 | ((long long)o->bufsz * n->rate != (long long)n->bufsz * o->rate)) { | ||||
1315 | if (log_level >= 1) { | ||||
1316 | log_puts(n->name); | ||||
1317 | log_puts(": not compatible with "); | ||||
1318 | log_puts(o->name); | ||||
1319 | log_puts("\n"); | ||||
1320 | } | ||||
1321 | return 0; | ||||
1322 | } | ||||
1323 | return 1; | ||||
1324 | } | ||||
1325 | |||||
1326 | /* | ||||
1327 | * Close the device, but attempt to migrate everything to a new sndio | ||||
1328 | * device. | ||||
1329 | */ | ||||
1330 | struct dev * | ||||
1331 | dev_migrate(struct dev *odev) | ||||
1332 | { | ||||
1333 | struct dev *ndev; | ||||
1334 | struct opt *o; | ||||
1335 | struct slot *s; | ||||
1336 | int i; | ||||
1337 | |||||
1338 | /* not opened */ | ||||
1339 | if (odev->pstate == DEV_CFG0) | ||||
1340 | return odev; | ||||
1341 | |||||
1342 | ndev = odev; | ||||
1343 | while (1) { | ||||
1344 | /* try next one, circulating through the list */ | ||||
1345 | ndev = ndev->alt_next; | ||||
1346 | if (ndev == odev) { | ||||
1347 | if (log_level >= 1) { | ||||
1348 | dev_log(odev); | ||||
1349 | log_puts(": no fall-back device found\n"); | ||||
1350 | } | ||||
1351 | return NULL((void *)0); | ||||
1352 | } | ||||
1353 | |||||
1354 | |||||
1355 | if (!dev_ref(ndev)) | ||||
1356 | continue; | ||||
1357 | |||||
1358 | /* check if new parameters are compatible with old ones */ | ||||
1359 | if (!dev_iscompat(odev, ndev)) { | ||||
1360 | dev_unref(ndev); | ||||
1361 | continue; | ||||
1362 | } | ||||
1363 | |||||
1364 | /* found it!*/ | ||||
1365 | break; | ||||
1366 | } | ||||
1367 | |||||
1368 | if (log_level >= 1) { | ||||
1369 | dev_log(odev); | ||||
1370 | log_puts(": switching to "); | ||||
1371 | dev_log(ndev); | ||||
1372 | log_puts("\n"); | ||||
1373 | } | ||||
1374 | |||||
1375 | if (mtc_array[0].dev == odev) | ||||
1376 | mtc_setdev(&mtc_array[0], ndev); | ||||
1377 | |||||
1378 | /* move opts to new device (also moves clients using the opts) */ | ||||
1379 | for (o = opt_list; o != NULL((void *)0); o = o->next) { | ||||
1380 | if (o->dev != odev) | ||||
1381 | continue; | ||||
1382 | if (strcmp(o->name, o->dev->name) == 0) | ||||
1383 | continue; | ||||
1384 | opt_setdev(o, ndev); | ||||
1385 | } | ||||
1386 | |||||
1387 | /* terminate remaining clients */ | ||||
1388 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1389 | if (s->opt == NULL((void *)0) || s->opt->dev != odev) | ||||
1390 | continue; | ||||
1391 | if (s->ops != NULL((void *)0)) { | ||||
1392 | s->ops->exit(s->arg); | ||||
1393 | s->ops = NULL((void *)0); | ||||
1394 | } | ||||
1395 | } | ||||
1396 | |||||
1397 | /* slots and/or MMC hold refs, drop ours */ | ||||
1398 | dev_unref(ndev); | ||||
1399 | |||||
1400 | return ndev; | ||||
1401 | } | ||||
1402 | |||||
1403 | /* | ||||
1404 | * check that all clients controlled by MMC are ready to start, if so, | ||||
1405 | * attach them all at the same position | ||||
1406 | */ | ||||
1407 | void | ||||
1408 | mtc_trigger(struct mtc *mtc) | ||||
1409 | { | ||||
1410 | int i; | ||||
1411 | struct slot *s; | ||||
1412 | |||||
1413 | if (mtc->tstate != MTC_START2) { | ||||
1414 | if (log_level >= 2) { | ||||
1415 | dev_log(mtc->dev); | ||||
1416 | log_puts(": not started by mmc yet, waiting...\n"); | ||||
1417 | } | ||||
1418 | return; | ||||
1419 | } | ||||
1420 | |||||
1421 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1422 | if (s->opt == NULL((void *)0) || s->opt->mtc != mtc) | ||||
1423 | continue; | ||||
1424 | if (s->pstate != SLOT_READY2) { | ||||
1425 | #ifdef DEBUG1 | ||||
1426 | if (log_level >= 3) { | ||||
1427 | slot_log(s); | ||||
1428 | log_puts(": not ready, start delayed\n"); | ||||
1429 | } | ||||
1430 | #endif | ||||
1431 | return; | ||||
1432 | } | ||||
1433 | } | ||||
1434 | if (!dev_ref(mtc->dev)) | ||||
1435 | return; | ||||
1436 | |||||
1437 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1438 | if (s->opt == NULL((void *)0) || s->opt->mtc != mtc) | ||||
1439 | continue; | ||||
1440 | slot_attach(s); | ||||
1441 | s->pstate = SLOT_RUN3; | ||||
1442 | } | ||||
1443 | mtc->tstate = MTC_RUN3; | ||||
1444 | mtc_midi_full(mtc); | ||||
1445 | dev_wakeup(mtc->dev); | ||||
1446 | } | ||||
1447 | |||||
1448 | /* | ||||
1449 | * start all slots simultaneously | ||||
1450 | */ | ||||
1451 | void | ||||
1452 | mtc_start(struct mtc *mtc) | ||||
1453 | { | ||||
1454 | if (mtc->tstate == MTC_STOP1) { | ||||
1455 | mtc->tstate = MTC_START2; | ||||
1456 | mtc_trigger(mtc); | ||||
1457 | #ifdef DEBUG1 | ||||
1458 | } else { | ||||
1459 | if (log_level >= 3) { | ||||
1460 | dev_log(mtc->dev); | ||||
1461 | log_puts(": ignoring mmc start\n"); | ||||
1462 | } | ||||
1463 | #endif | ||||
1464 | } | ||||
1465 | } | ||||
1466 | |||||
1467 | /* | ||||
1468 | * stop all slots simultaneously | ||||
1469 | */ | ||||
1470 | void | ||||
1471 | mtc_stop(struct mtc *mtc) | ||||
1472 | { | ||||
1473 | switch (mtc->tstate) { | ||||
1474 | case MTC_START2: | ||||
1475 | mtc->tstate = MTC_STOP1; | ||||
1476 | return; | ||||
1477 | case MTC_RUN3: | ||||
1478 | mtc->tstate = MTC_STOP1; | ||||
1479 | dev_unref(mtc->dev); | ||||
1480 | break; | ||||
1481 | default: | ||||
1482 | #ifdef DEBUG1 | ||||
1483 | if (log_level >= 3) { | ||||
1484 | dev_log(mtc->dev); | ||||
1485 | log_puts(": ignored mmc stop\n"); | ||||
1486 | } | ||||
1487 | #endif | ||||
1488 | return; | ||||
1489 | } | ||||
1490 | } | ||||
1491 | |||||
1492 | /* | ||||
1493 | * relocate all slots simultaneously | ||||
1494 | */ | ||||
1495 | void | ||||
1496 | mtc_loc(struct mtc *mtc, unsigned int origin) | ||||
1497 | { | ||||
1498 | if (log_level >= 2) { | ||||
1499 | dev_log(mtc->dev); | ||||
1500 | log_puts(": relocated to "); | ||||
1501 | log_putu(origin); | ||||
1502 | log_puts("\n"); | ||||
1503 | } | ||||
1504 | if (mtc->tstate == MTC_RUN3) | ||||
1505 | mtc_stop(mtc); | ||||
1506 | mtc->origin = origin; | ||||
1507 | if (mtc->tstate == MTC_RUN3) | ||||
1508 | mtc_start(mtc); | ||||
1509 | } | ||||
1510 | |||||
1511 | /* | ||||
1512 | * set MMC device | ||||
1513 | */ | ||||
1514 | void | ||||
1515 | mtc_setdev(struct mtc *mtc, struct dev *d) | ||||
1516 | { | ||||
1517 | struct opt *o; | ||||
1518 | |||||
1519 | if (mtc->dev == d) | ||||
1520 | return; | ||||
1521 | |||||
1522 | if (log_level >= 2) { | ||||
1523 | dev_log(d); | ||||
1524 | log_puts(": set to be MIDI clock source\n"); | ||||
1525 | } | ||||
1526 | |||||
1527 | /* adjust clock and ref counter, if needed */ | ||||
1528 | if (mtc->tstate == MTC_RUN3) { | ||||
1529 | mtc->delta -= mtc->dev->delta; | ||||
1530 | dev_unref(mtc->dev); | ||||
1531 | } | ||||
1532 | |||||
1533 | mtc->dev = d; | ||||
1534 | |||||
1535 | if (mtc->tstate == MTC_RUN3) { | ||||
1536 | mtc->delta += mtc->dev->delta; | ||||
1537 | dev_ref(mtc->dev); | ||||
1538 | dev_wakeup(mtc->dev); | ||||
1539 | } | ||||
1540 | |||||
1541 | /* move in once anything using MMC */ | ||||
1542 | for (o = opt_list; o != NULL((void *)0); o = o->next) { | ||||
1543 | if (o->mtc == mtc) | ||||
1544 | opt_setdev(o, mtc->dev); | ||||
1545 | } | ||||
1546 | } | ||||
1547 | |||||
1548 | /* | ||||
1549 | * allocate buffers & conversion chain | ||||
1550 | */ | ||||
1551 | void | ||||
1552 | slot_initconv(struct slot *s) | ||||
1553 | { | ||||
1554 | unsigned int dev_nch; | ||||
1555 | struct dev *d = s->opt->dev; | ||||
1556 | |||||
1557 | if (s->mode & MODE_PLAY0x01) { | ||||
1558 | cmap_init(&s->mix.cmap, | ||||
1559 | s->opt->pmin, s->opt->pmin + s->mix.nch - 1, | ||||
1560 | s->opt->pmin, s->opt->pmin + s->mix.nch - 1, | ||||
1561 | 0, d->pchan - 1, | ||||
1562 | s->opt->pmin, s->opt->pmax); | ||||
1563 | s->mix.decbuf = NULL((void *)0); | ||||
1564 | s->mix.resampbuf = NULL((void *)0); | ||||
1565 | if (!aparams_native(&s->par)) { | ||||
1566 | dec_init(&s->mix.dec, &s->par, s->mix.nch); | ||||
1567 | s->mix.decbuf = | ||||
1568 | xmalloc(s->round * s->mix.nch * sizeof(adata_t)); | ||||
1569 | } | ||||
1570 | if (s->rate != d->rate) { | ||||
1571 | resamp_init(&s->mix.resamp, s->round, d->round, | ||||
1572 | s->mix.nch); | ||||
1573 | s->mix.resampbuf = | ||||
1574 | xmalloc(d->round * s->mix.nch * sizeof(adata_t)); | ||||
1575 | } | ||||
1576 | s->mix.join = 1; | ||||
1577 | s->mix.expand = 1; | ||||
1578 | if (s->opt->dup && s->mix.cmap.nch > 0) { | ||||
1579 | dev_nch = d->pchan < (s->opt->pmax + 1) ? | ||||
1580 | d->pchan - s->opt->pmin : | ||||
1581 | s->opt->pmax - s->opt->pmin + 1; | ||||
1582 | if (dev_nch > s->mix.nch) | ||||
1583 | s->mix.expand = dev_nch / s->mix.nch; | ||||
1584 | else if (s->mix.nch > dev_nch) | ||||
1585 | s->mix.join = s->mix.nch / dev_nch; | ||||
1586 | } | ||||
1587 | } | ||||
1588 | |||||
1589 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1590 | unsigned int outchan = (s->opt->mode & MODE_MON0x10) ? | ||||
1591 | d->pchan : d->rchan; | ||||
1592 | |||||
1593 | s->sub.encbuf = NULL((void *)0); | ||||
1594 | s->sub.resampbuf = NULL((void *)0); | ||||
1595 | cmap_init(&s->sub.cmap, | ||||
1596 | 0, outchan - 1, | ||||
1597 | s->opt->rmin, s->opt->rmax, | ||||
1598 | s->opt->rmin, s->opt->rmin + s->sub.nch - 1, | ||||
1599 | s->opt->rmin, s->opt->rmin + s->sub.nch - 1); | ||||
1600 | if (s->rate != d->rate) { | ||||
1601 | resamp_init(&s->sub.resamp, d->round, s->round, | ||||
1602 | s->sub.nch); | ||||
1603 | s->sub.resampbuf = | ||||
1604 | xmalloc(d->round * s->sub.nch * sizeof(adata_t)); | ||||
1605 | } | ||||
1606 | if (!aparams_native(&s->par)) { | ||||
1607 | enc_init(&s->sub.enc, &s->par, s->sub.nch); | ||||
1608 | s->sub.encbuf = | ||||
1609 | xmalloc(s->round * s->sub.nch * sizeof(adata_t)); | ||||
1610 | } | ||||
1611 | s->sub.join = 1; | ||||
1612 | s->sub.expand = 1; | ||||
1613 | if (s->opt->dup && s->sub.cmap.nch > 0) { | ||||
1614 | dev_nch = outchan < (s->opt->rmax + 1) ? | ||||
1615 | outchan - s->opt->rmin : | ||||
1616 | s->opt->rmax - s->opt->rmin + 1; | ||||
1617 | if (dev_nch > s->sub.nch) | ||||
1618 | s->sub.join = dev_nch / s->sub.nch; | ||||
1619 | else if (s->sub.nch > dev_nch) | ||||
1620 | s->sub.expand = s->sub.nch / dev_nch; | ||||
1621 | } | ||||
1622 | |||||
1623 | /* | ||||
1624 | * cmap_copy() doesn't write samples in all channels, | ||||
1625 | * for instance when mono->stereo conversion is | ||||
1626 | * disabled. So we have to prefill cmap_copy() output | ||||
1627 | * with silence. | ||||
1628 | */ | ||||
1629 | if (s->sub.resampbuf) { | ||||
1630 | memset(s->sub.resampbuf, 0, | ||||
1631 | d->round * s->sub.nch * sizeof(adata_t)); | ||||
1632 | } else if (s->sub.encbuf) { | ||||
1633 | memset(s->sub.encbuf, 0, | ||||
1634 | s->round * s->sub.nch * sizeof(adata_t)); | ||||
1635 | } else { | ||||
1636 | memset(s->sub.buf.data, 0, | ||||
1637 | s->appbufsz * s->sub.nch * sizeof(adata_t)); | ||||
1638 | } | ||||
1639 | } | ||||
1640 | } | ||||
1641 | |||||
1642 | /* | ||||
1643 | * allocate buffers & conversion chain | ||||
1644 | */ | ||||
1645 | void | ||||
1646 | slot_allocbufs(struct slot *s) | ||||
1647 | { | ||||
1648 | if (s->mode & MODE_PLAY0x01) { | ||||
1649 | s->mix.bpf = s->par.bps * s->mix.nch; | ||||
1650 | abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf); | ||||
1651 | } | ||||
1652 | |||||
1653 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1654 | s->sub.bpf = s->par.bps * s->sub.nch; | ||||
1655 | abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf); | ||||
1656 | } | ||||
1657 | |||||
1658 | #ifdef DEBUG1 | ||||
1659 | if (log_level >= 3) { | ||||
1660 | slot_log(s); | ||||
1661 | log_puts(": allocated "); | ||||
1662 | log_putu(s->appbufsz); | ||||
1663 | log_puts("/"); | ||||
1664 | log_putu(SLOT_BUFSZ(s)((s)->appbufsz + (s)->opt->dev->bufsz / (s)->opt ->dev->round * (s)->round)); | ||||
1665 | log_puts(" fr buffers\n"); | ||||
1666 | } | ||||
1667 | #endif | ||||
1668 | } | ||||
1669 | |||||
1670 | /* | ||||
1671 | * free buffers & conversion chain | ||||
1672 | */ | ||||
1673 | void | ||||
1674 | slot_freebufs(struct slot *s) | ||||
1675 | { | ||||
1676 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
1677 | abuf_done(&s->sub.buf); | ||||
1678 | } | ||||
1679 | |||||
1680 | if (s->mode & MODE_PLAY0x01) { | ||||
1681 | abuf_done(&s->mix.buf); | ||||
1682 | } | ||||
1683 | } | ||||
1684 | |||||
1685 | /* | ||||
1686 | * allocate a new slot and register the given call-backs | ||||
1687 | */ | ||||
1688 | struct slot * | ||||
1689 | slot_new(struct opt *opt, unsigned int id, char *who, | ||||
1690 | struct slotops *ops, void *arg, int mode) | ||||
1691 | { | ||||
1692 | char *p; | ||||
1693 | char name[SLOT_NAMEMAX8]; | ||||
1694 | char ctl_name[CTL_NAMEMAX16]; | ||||
1695 | unsigned int i, ser, bestser, bestidx; | ||||
1696 | struct slot *unit[DEV_NSLOT8]; | ||||
1697 | struct slot *s; | ||||
1698 | |||||
1699 | /* | ||||
1700 | * create a ``valid'' control name (lowcase, remove [^a-z], truncate) | ||||
1701 | */ | ||||
1702 | for (i = 0, p = who; ; p++) { | ||||
1703 | if (i == SLOT_NAMEMAX8 - 1 || *p == '\0') { | ||||
1704 | name[i] = '\0'; | ||||
1705 | break; | ||||
1706 | } else if (*p >= 'A' && *p <= 'Z') { | ||||
1707 | name[i++] = *p + 'a' - 'A'; | ||||
1708 | } else if (*p >= 'a' && *p <= 'z') | ||||
1709 | name[i++] = *p; | ||||
1710 | } | ||||
1711 | if (i == 0) | ||||
1712 | strlcpy(name, "noname", SLOT_NAMEMAX8); | ||||
1713 | |||||
1714 | /* | ||||
1715 | * build a unit-to-slot map for this name | ||||
1716 | */ | ||||
1717 | for (i = 0; i < DEV_NSLOT8; i++) | ||||
1718 | unit[i] = NULL((void *)0); | ||||
1719 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1720 | if (strcmp(s->name, name) == 0) | ||||
1721 | unit[s->unit] = s; | ||||
1722 | } | ||||
1723 | |||||
1724 | /* | ||||
1725 | * find the free slot with the least unit number and same id | ||||
1726 | */ | ||||
1727 | for (i = 0; i < DEV_NSLOT8; i++) { | ||||
1728 | s = unit[i]; | ||||
1729 | if (s != NULL((void *)0) && s->ops == NULL((void *)0) && s->id == id) | ||||
1730 | goto found; | ||||
1731 | } | ||||
1732 | |||||
1733 | /* | ||||
1734 | * find the free slot with the least unit number | ||||
1735 | */ | ||||
1736 | for (i = 0; i < DEV_NSLOT8; i++) { | ||||
1737 | s = unit[i]; | ||||
1738 | if (s != NULL((void *)0) && s->ops == NULL((void *)0)) { | ||||
1739 | s->id = id; | ||||
1740 | goto found; | ||||
1741 | } | ||||
1742 | } | ||||
1743 | |||||
1744 | /* | ||||
1745 | * couldn't find a matching slot, pick oldest free slot | ||||
1746 | * and set its name/unit | ||||
1747 | */ | ||||
1748 | bestser = 0; | ||||
1749 | bestidx = DEV_NSLOT8; | ||||
1750 | for (i = 0, s = slot_array; i < DEV_NSLOT8; i++, s++) { | ||||
1751 | if (s->ops != NULL((void *)0)) | ||||
1752 | continue; | ||||
1753 | ser = slot_serial - s->serial; | ||||
1754 | if (ser > bestser) { | ||||
1755 | bestser = ser; | ||||
1756 | bestidx = i; | ||||
1757 | } | ||||
1758 | } | ||||
1759 | |||||
1760 | if (bestidx == DEV_NSLOT8) { | ||||
1761 | if (log_level >= 1) { | ||||
1762 | log_puts(name); | ||||
1763 | log_puts(": out of sub-device slots\n"); | ||||
1764 | } | ||||
1765 | return NULL((void *)0); | ||||
1766 | } | ||||
1767 | |||||
1768 | s = slot_array + bestidx; | ||||
1769 | ctl_del(CTL_SLOT_LEVEL3, s, NULL((void *)0)); | ||||
1770 | s->vol = MIDI_MAXCTL127; | ||||
1771 | strlcpy(s->name, name, SLOT_NAMEMAX8); | ||||
1772 | s->serial = slot_serial++; | ||||
1773 | for (i = 0; unit[i] != NULL((void *)0); i++) | ||||
1774 | ; /* nothing */ | ||||
1775 | s->unit = i; | ||||
1776 | s->id = id; | ||||
1777 | s->opt = opt; | ||||
1778 | slot_ctlname(s, ctl_name, CTL_NAMEMAX16); | ||||
1779 | ctl_new(CTL_SLOT_LEVEL3, s, NULL((void *)0), | ||||
1780 | CTL_NUM2, "app", ctl_name, -1, "level", | ||||
1781 | NULL((void *)0), -1, 127, s->vol); | ||||
1782 | |||||
1783 | found: | ||||
1784 | /* open device, this may change opt's device */ | ||||
1785 | if (!opt_ref(opt)) | ||||
1786 | return NULL((void *)0); | ||||
1787 | s->opt = opt; | ||||
1788 | s->ops = ops; | ||||
1789 | s->arg = arg; | ||||
1790 | s->pstate = SLOT_INIT0; | ||||
1791 | s->mode = mode; | ||||
1792 | aparams_init(&s->par); | ||||
1793 | if (s->mode & MODE_PLAY0x01) | ||||
1794 | s->mix.nch = s->opt->pmax - s->opt->pmin + 1; | ||||
1795 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) | ||||
1796 | s->sub.nch = s->opt->rmax - s->opt->rmin + 1; | ||||
1797 | s->xrun = s->opt->mtc != NULL((void *)0) ? XRUN_SYNC1 : XRUN_IGNORE0; | ||||
1798 | s->appbufsz = s->opt->dev->bufsz; | ||||
1799 | s->round = s->opt->dev->round; | ||||
1800 | s->rate = s->opt->dev->rate; | ||||
1801 | dev_midi_slotdesc(s->opt->dev, s); | ||||
1802 | dev_midi_vol(s->opt->dev, s); | ||||
1803 | #ifdef DEBUG1 | ||||
1804 | if (log_level >= 3) { | ||||
1805 | slot_log(s); | ||||
1806 | log_puts(": using "); | ||||
1807 | log_puts(s->opt->name); | ||||
1808 | log_puts(", mode = "); | ||||
1809 | log_putx(mode); | ||||
1810 | log_puts("\n"); | ||||
1811 | } | ||||
1812 | #endif | ||||
1813 | return s; | ||||
1814 | } | ||||
1815 | |||||
1816 | /* | ||||
1817 | * release the given slot | ||||
1818 | */ | ||||
1819 | void | ||||
1820 | slot_del(struct slot *s) | ||||
1821 | { | ||||
1822 | s->arg = s; | ||||
1823 | s->ops = &zomb_slotops; | ||||
1824 | switch (s->pstate) { | ||||
1825 | case SLOT_INIT0: | ||||
1826 | s->ops = NULL((void *)0); | ||||
1827 | break; | ||||
1828 | case SLOT_START1: | ||||
1829 | case SLOT_READY2: | ||||
1830 | case SLOT_RUN3: | ||||
1831 | case SLOT_STOP4: | ||||
1832 | slot_stop(s, 0); | ||||
1833 | break; | ||||
1834 | } | ||||
1835 | opt_unref(s->opt); | ||||
1836 | } | ||||
1837 | |||||
1838 | /* | ||||
1839 | * change the slot play volume; called either by the slot or by MIDI | ||||
1840 | */ | ||||
1841 | void | ||||
1842 | slot_setvol(struct slot *s, unsigned int vol) | ||||
1843 | { | ||||
1844 | #ifdef DEBUG1 | ||||
1845 | if (log_level >= 3) { | ||||
1846 | slot_log(s); | ||||
1847 | log_puts(": setting volume "); | ||||
1848 | log_putu(vol); | ||||
1849 | log_puts("\n"); | ||||
1850 | } | ||||
1851 | #endif | ||||
1852 | s->vol = vol; | ||||
1853 | s->mix.vol = MIDI_TO_ADATA(s->vol)(aparams_ctltovol[s->vol] << (24 - 16)); | ||||
1854 | } | ||||
1855 | |||||
1856 | /* | ||||
1857 | * set device for this slot | ||||
1858 | */ | ||||
1859 | void | ||||
1860 | slot_setopt(struct slot *s, struct opt *o) | ||||
1861 | { | ||||
1862 | struct opt *t; | ||||
1863 | struct dev *odev, *ndev; | ||||
1864 | struct ctl *c; | ||||
1865 | |||||
1866 | if (s->opt == NULL((void *)0) || s->opt == o) | ||||
1867 | return; | ||||
1868 | |||||
1869 | if (log_level >= 2) { | ||||
1870 | slot_log(s); | ||||
1871 | log_puts(": moving to opt "); | ||||
1872 | log_puts(o->name); | ||||
1873 | log_puts("\n"); | ||||
1874 | } | ||||
1875 | |||||
1876 | odev = s->opt->dev; | ||||
1877 | if (s->ops != NULL((void *)0)) { | ||||
1878 | ndev = opt_ref(o); | ||||
1879 | if (ndev == NULL((void *)0)) | ||||
1880 | return; | ||||
1881 | |||||
1882 | if (!dev_iscompat(odev, ndev)) { | ||||
1883 | opt_unref(o); | ||||
1884 | return; | ||||
1885 | } | ||||
1886 | } | ||||
1887 | |||||
1888 | if (s->pstate == SLOT_RUN3 || s->pstate == SLOT_STOP4) | ||||
1889 | slot_detach(s); | ||||
1890 | |||||
1891 | t = s->opt; | ||||
1892 | s->opt = o; | ||||
1893 | |||||
1894 | c = ctl_find(CTL_SLOT_LEVEL3, s, NULL((void *)0)); | ||||
1895 | ctl_update(c); | ||||
1896 | |||||
1897 | if (o->dev != t->dev) { | ||||
1898 | dev_midi_slotdesc(odev, s); | ||||
1899 | dev_midi_slotdesc(ndev, s); | ||||
1900 | dev_midi_vol(ndev, s); | ||||
1901 | } | ||||
1902 | |||||
1903 | if (s->pstate == SLOT_RUN3 || s->pstate == SLOT_STOP4) | ||||
1904 | slot_attach(s); | ||||
1905 | |||||
1906 | if (s->ops != NULL((void *)0)) { | ||||
1907 | opt_unref(t); | ||||
1908 | return; | ||||
1909 | } | ||||
1910 | } | ||||
1911 | |||||
1912 | /* | ||||
1913 | * attach the slot to the device (ie start playing & recording | ||||
1914 | */ | ||||
1915 | void | ||||
1916 | slot_attach(struct slot *s) | ||||
1917 | { | ||||
1918 | struct dev *d = s->opt->dev; | ||||
1919 | long long pos; | ||||
1920 | |||||
1921 | if (((s->mode & MODE_PLAY0x01) && !(s->opt->mode & MODE_PLAY0x01)) || | ||||
1922 | ((s->mode & MODE_RECMASK(0x02 | 0x10)) && !(s->opt->mode & MODE_RECMASK(0x02 | 0x10)))) { | ||||
1923 | if (log_level >= 1) { | ||||
1924 | slot_log(s); | ||||
1925 | log_puts(" at "); | ||||
1926 | log_puts(s->opt->name); | ||||
1927 | log_puts(": mode not allowed on this sub-device\n"); | ||||
1928 | } | ||||
1929 | } | ||||
1930 | |||||
1931 | /* | ||||
1932 | * setup conversions layer | ||||
1933 | */ | ||||
1934 | slot_initconv(s); | ||||
1935 | |||||
1936 | /* | ||||
1937 | * start the device if not started | ||||
1938 | */ | ||||
1939 | dev_wakeup(d); | ||||
1940 | |||||
1941 | /* | ||||
1942 | * adjust initial clock | ||||
1943 | */ | ||||
1944 | pos = s->delta_rem + | ||||
1945 | (long long)s->delta * d->round + | ||||
1946 | (long long)d->delta * s->round; | ||||
1947 | s->delta = pos / (int)d->round; | ||||
1948 | s->delta_rem = pos % d->round; | ||||
1949 | if (s->delta_rem < 0) { | ||||
1950 | s->delta_rem += d->round; | ||||
1951 | s->delta--; | ||||
1952 | } | ||||
1953 | |||||
1954 | #ifdef DEBUG1 | ||||
1955 | if (log_level >= 2) { | ||||
1956 | slot_log(s); | ||||
1957 | log_puts(": attached at "); | ||||
1958 | log_puti(s->delta); | ||||
1959 | log_puts(" + "); | ||||
1960 | log_puti(s->delta_rem); | ||||
1961 | log_puts("/"); | ||||
1962 | log_puti(s->round); | ||||
1963 | log_puts("\n"); | ||||
1964 | } | ||||
1965 | #endif | ||||
1966 | |||||
1967 | /* | ||||
1968 | * We dont check whether the device is dying, | ||||
1969 | * because dev_xxx() functions are supposed to | ||||
1970 | * work (i.e., not to crash) | ||||
1971 | */ | ||||
1972 | |||||
1973 | s->next = d->slot_list; | ||||
1974 | d->slot_list = s; | ||||
1975 | if (s->mode & MODE_PLAY0x01) { | ||||
1976 | s->mix.vol = MIDI_TO_ADATA(s->vol)(aparams_ctltovol[s->vol] << (24 - 16)); | ||||
1977 | dev_mix_adjvol(d); | ||||
1978 | } | ||||
1979 | } | ||||
1980 | |||||
1981 | /* | ||||
1982 | * if MMC is enabled, and try to attach all slots synchronously, else | ||||
1983 | * simply attach the slot | ||||
1984 | */ | ||||
1985 | void | ||||
1986 | slot_ready(struct slot *s) | ||||
1987 | { | ||||
1988 | /* | ||||
1989 | * device may be disconnected, and if so we're called from | ||||
1990 | * slot->ops->exit() on a closed device | ||||
1991 | */ | ||||
1992 | if (s->opt->dev->pstate == DEV_CFG0) | ||||
1993 | return; | ||||
1994 | if (s->opt->mtc == NULL((void *)0)) { | ||||
1995 | slot_attach(s); | ||||
1996 | s->pstate = SLOT_RUN3; | ||||
1997 | } else | ||||
1998 | mtc_trigger(s->opt->mtc); | ||||
1999 | } | ||||
2000 | |||||
2001 | /* | ||||
2002 | * setup buffers & conversion layers, prepare the slot to receive data | ||||
2003 | * (for playback) or start (recording). | ||||
2004 | */ | ||||
2005 | void | ||||
2006 | slot_start(struct slot *s) | ||||
2007 | { | ||||
2008 | struct dev *d = s->opt->dev; | ||||
2009 | #ifdef DEBUG1 | ||||
2010 | if (s->pstate != SLOT_INIT0) { | ||||
2011 | slot_log(s); | ||||
2012 | log_puts(": slot_start: wrong state\n"); | ||||
2013 | panic(); | ||||
2014 | } | ||||
2015 | if (s->mode & MODE_PLAY0x01) { | ||||
2016 | if (log_level >= 3) { | ||||
2017 | slot_log(s); | ||||
2018 | log_puts(": playing "); | ||||
2019 | aparams_log(&s->par); | ||||
2020 | log_puts(" -> "); | ||||
2021 | aparams_log(&d->par); | ||||
2022 | log_puts("\n"); | ||||
2023 | } | ||||
2024 | } | ||||
2025 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2026 | if (log_level >= 3) { | ||||
2027 | slot_log(s); | ||||
2028 | log_puts(": recording "); | ||||
2029 | aparams_log(&s->par); | ||||
2030 | log_puts(" <- "); | ||||
2031 | aparams_log(&d->par); | ||||
2032 | log_puts("\n"); | ||||
2033 | } | ||||
2034 | } | ||||
2035 | #endif | ||||
2036 | slot_allocbufs(s); | ||||
2037 | |||||
2038 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2039 | /* | ||||
2040 | * N-th recorded block is the N-th played block | ||||
2041 | */ | ||||
2042 | s->sub.prime = d->bufsz / d->round; | ||||
2043 | } | ||||
2044 | s->skip = 0; | ||||
2045 | |||||
2046 | /* | ||||
2047 | * get the current position, the origin is when the first sample | ||||
2048 | * played and/or recorded | ||||
2049 | */ | ||||
2050 | s->delta = -(long long)d->bufsz * s->round / d->round; | ||||
2051 | s->delta_rem = 0; | ||||
2052 | |||||
2053 | if (s->mode & MODE_PLAY0x01) { | ||||
2054 | s->pstate = SLOT_START1; | ||||
2055 | } else { | ||||
2056 | s->pstate = SLOT_READY2; | ||||
2057 | slot_ready(s); | ||||
2058 | } | ||||
2059 | } | ||||
2060 | |||||
2061 | /* | ||||
2062 | * stop playback and recording, and free conversion layers | ||||
2063 | */ | ||||
2064 | void | ||||
2065 | slot_detach(struct slot *s) | ||||
2066 | { | ||||
2067 | struct slot **ps; | ||||
2068 | struct dev *d = s->opt->dev; | ||||
2069 | long long pos; | ||||
2070 | |||||
2071 | for (ps = &d->slot_list; *ps != s; ps = &(*ps)->next) { | ||||
2072 | #ifdef DEBUG1 | ||||
2073 | if (*ps == NULL((void *)0)) { | ||||
2074 | slot_log(s); | ||||
2075 | log_puts(": can't detach, not on list\n"); | ||||
2076 | panic(); | ||||
2077 | } | ||||
2078 | #endif | ||||
2079 | } | ||||
2080 | *ps = s->next; | ||||
2081 | |||||
2082 | /* | ||||
2083 | * adjust clock, go back d->delta ticks so that slot_attach() | ||||
2084 | * could be called with the resulting state | ||||
2085 | */ | ||||
2086 | pos = s->delta_rem + | ||||
2087 | (long long)s->delta * d->round - | ||||
2088 | (long long)d->delta * s->round; | ||||
2089 | s->delta = pos / (int)d->round; | ||||
2090 | s->delta_rem = pos % d->round; | ||||
2091 | if (s->delta_rem < 0) { | ||||
2092 | s->delta_rem += d->round; | ||||
2093 | s->delta--; | ||||
2094 | } | ||||
2095 | |||||
2096 | #ifdef DEBUG1 | ||||
2097 | if (log_level >= 2) { | ||||
2098 | slot_log(s); | ||||
2099 | log_puts(": detached at "); | ||||
2100 | log_puti(s->delta); | ||||
2101 | log_puts(" + "); | ||||
2102 | log_puti(s->delta_rem); | ||||
2103 | log_puts("/"); | ||||
2104 | log_puti(d->round); | ||||
2105 | log_puts("\n"); | ||||
2106 | } | ||||
2107 | #endif | ||||
2108 | if (s->mode & MODE_PLAY0x01) | ||||
2109 | dev_mix_adjvol(d); | ||||
2110 | |||||
2111 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) { | ||||
2112 | if (s->sub.encbuf) { | ||||
2113 | xfree(s->sub.encbuf); | ||||
2114 | s->sub.encbuf = NULL((void *)0); | ||||
2115 | } | ||||
2116 | if (s->sub.resampbuf) { | ||||
2117 | xfree(s->sub.resampbuf); | ||||
2118 | s->sub.resampbuf = NULL((void *)0); | ||||
2119 | } | ||||
2120 | } | ||||
2121 | |||||
2122 | if (s->mode & MODE_PLAY0x01) { | ||||
2123 | if (s->mix.decbuf) { | ||||
2124 | xfree(s->mix.decbuf); | ||||
2125 | s->mix.decbuf = NULL((void *)0); | ||||
2126 | } | ||||
2127 | if (s->mix.resampbuf) { | ||||
2128 | xfree(s->mix.resampbuf); | ||||
2129 | s->mix.resampbuf = NULL((void *)0); | ||||
2130 | } | ||||
2131 | } | ||||
2132 | } | ||||
2133 | |||||
2134 | /* | ||||
2135 | * put the slot in stopping state (draining play buffers) or | ||||
2136 | * stop & detach if no data to drain. | ||||
2137 | */ | ||||
2138 | void | ||||
2139 | slot_stop(struct slot *s, int drain) | ||||
2140 | { | ||||
2141 | #ifdef DEBUG1 | ||||
2142 | if (log_level >= 3) { | ||||
2143 | slot_log(s); | ||||
2144 | log_puts(": stopping\n"); | ||||
2145 | } | ||||
2146 | #endif | ||||
2147 | if (s->pstate == SLOT_START1) { | ||||
2148 | /* | ||||
2149 | * If in rec-only mode, we're already in the READY or | ||||
2150 | * RUN states. We're here because the play buffer was | ||||
2151 | * not full enough, try to start so it's drained. | ||||
2152 | */ | ||||
2153 | s->pstate = SLOT_READY2; | ||||
2154 | slot_ready(s); | ||||
2155 | } | ||||
2156 | |||||
2157 | if (s->pstate == SLOT_RUN3) { | ||||
2158 | if ((s->mode & MODE_PLAY0x01) && drain) { | ||||
2159 | /* | ||||
2160 | * Don't detach, dev_cycle() will do it for us | ||||
2161 | * when the buffer is drained. | ||||
2162 | */ | ||||
2163 | s->pstate = SLOT_STOP4; | ||||
2164 | return; | ||||
2165 | } | ||||
2166 | slot_detach(s); | ||||
2167 | } else if (s->pstate == SLOT_STOP4) { | ||||
2168 | slot_detach(s); | ||||
2169 | } else { | ||||
2170 | #ifdef DEBUG1 | ||||
2171 | if (log_level >= 3) { | ||||
2172 | slot_log(s); | ||||
2173 | log_puts(": not drained (blocked by mmc)\n"); | ||||
2174 | } | ||||
2175 | #endif | ||||
2176 | } | ||||
2177 | |||||
2178 | s->pstate = SLOT_INIT0; | ||||
2179 | s->ops->eof(s->arg); | ||||
2180 | slot_freebufs(s); | ||||
2181 | } | ||||
2182 | |||||
2183 | void | ||||
2184 | slot_skip_update(struct slot *s) | ||||
2185 | { | ||||
2186 | int skip; | ||||
2187 | |||||
2188 | skip = slot_skip(s); | ||||
2189 | while (skip > 0) { | ||||
2190 | #ifdef DEBUG1 | ||||
2191 | if (log_level >= 4) { | ||||
2192 | slot_log(s); | ||||
2193 | log_puts(": catching skipped block\n"); | ||||
2194 | } | ||||
2195 | #endif | ||||
2196 | if (s->mode & MODE_RECMASK(0x02 | 0x10)) | ||||
2197 | s->ops->flush(s->arg); | ||||
2198 | if (s->mode & MODE_PLAY0x01) | ||||
2199 | s->ops->fill(s->arg); | ||||
2200 | skip--; | ||||
2201 | } | ||||
2202 | } | ||||
2203 | |||||
2204 | /* | ||||
2205 | * notify the slot that we just wrote in the play buffer, must be called | ||||
2206 | * after each write | ||||
2207 | */ | ||||
2208 | void | ||||
2209 | slot_write(struct slot *s) | ||||
2210 | { | ||||
2211 | if (s->pstate == SLOT_START1 && s->mix.buf.used == s->mix.buf.len) { | ||||
2212 | #ifdef DEBUG1 | ||||
2213 | if (log_level >= 4) { | ||||
2214 | slot_log(s); | ||||
2215 | log_puts(": switching to READY state\n"); | ||||
2216 | } | ||||
2217 | #endif | ||||
2218 | s->pstate = SLOT_READY2; | ||||
2219 | slot_ready(s); | ||||
2220 | } | ||||
2221 | slot_skip_update(s); | ||||
2222 | } | ||||
2223 | |||||
2224 | /* | ||||
2225 | * notify the slot that we freed some space in the rec buffer | ||||
2226 | */ | ||||
2227 | void | ||||
2228 | slot_read(struct slot *s) | ||||
2229 | { | ||||
2230 | slot_skip_update(s); | ||||
2231 | } | ||||
2232 | |||||
2233 | /* | ||||
2234 | * allocate at control slot | ||||
2235 | */ | ||||
2236 | struct ctlslot * | ||||
2237 | ctlslot_new(struct opt *o, struct ctlops *ops, void *arg) | ||||
2238 | { | ||||
2239 | struct ctlslot *s; | ||||
2240 | struct ctl *c; | ||||
2241 | int i; | ||||
2242 | |||||
2243 | i = 0; | ||||
2244 | for (;;) { | ||||
2245 | if (i == DEV_NCTLSLOT8) | ||||
2246 | return NULL((void *)0); | ||||
2247 | s = ctlslot_array + i; | ||||
2248 | if (s->ops == NULL((void *)0)) | ||||
2249 | break; | ||||
2250 | i++; | ||||
2251 | } | ||||
2252 | s->opt = o; | ||||
2253 | s->self = 1 << i; | ||||
2254 | if (!opt_ref(o)) | ||||
2255 | return NULL((void *)0); | ||||
2256 | s->ops = ops; | ||||
2257 | s->arg = arg; | ||||
2258 | for (c = ctl_list; c != NULL((void *)0); c = c->next) { | ||||
2259 | if (!ctlslot_visible(s, c)) | ||||
2260 | continue; | ||||
2261 | c->refs_mask |= s->self; | ||||
2262 | } | ||||
2263 | return s; | ||||
2264 | } | ||||
2265 | |||||
2266 | /* | ||||
2267 | * free control slot | ||||
2268 | */ | ||||
2269 | void | ||||
2270 | ctlslot_del(struct ctlslot *s) | ||||
2271 | { | ||||
2272 | struct ctl *c, **pc; | ||||
2273 | |||||
2274 | pc = &ctl_list; | ||||
2275 | while ((c = *pc) != NULL((void *)0)) { | ||||
2276 | c->refs_mask &= ~s->self; | ||||
2277 | if (c->refs_mask == 0) { | ||||
2278 | *pc = c->next; | ||||
2279 | xfree(c); | ||||
2280 | } else | ||||
2281 | pc = &c->next; | ||||
2282 | } | ||||
2283 | s->ops = NULL((void *)0); | ||||
2284 | opt_unref(s->opt); | ||||
2285 | } | ||||
2286 | |||||
2287 | int | ||||
2288 | ctlslot_visible(struct ctlslot *s, struct ctl *c) | ||||
2289 | { | ||||
2290 | if (s->opt == NULL((void *)0)) | ||||
2291 | return 1; | ||||
2292 | switch (c->scope) { | ||||
2293 | case CTL_HW0: | ||||
2294 | case CTL_DEV_MASTER1: | ||||
2295 | return (s->opt->dev == c->u.any.arg0); | ||||
2296 | case CTL_OPT_DEV2: | ||||
2297 | return (s->opt == c->u.any.arg0); | ||||
2298 | case CTL_SLOT_LEVEL3: | ||||
2299 | return (s->opt->dev == c->u.slot_level.slot->opt->dev); | ||||
2300 | default: | ||||
2301 | return 0; | ||||
2302 | } | ||||
2303 | } | ||||
2304 | |||||
2305 | struct ctl * | ||||
2306 | ctlslot_lookup(struct ctlslot *s, int addr) | ||||
2307 | { | ||||
2308 | struct ctl *c; | ||||
2309 | |||||
2310 | c = ctl_list; | ||||
2311 | while (1) { | ||||
2312 | if (c == NULL((void *)0)) | ||||
2313 | return NULL((void *)0); | ||||
2314 | if (c->type != CTL_NONE0 && c->addr == addr) | ||||
2315 | break; | ||||
2316 | c = c->next; | ||||
2317 | } | ||||
2318 | if (!ctlslot_visible(s, c)) | ||||
2319 | return NULL((void *)0); | ||||
2320 | return c; | ||||
2321 | } | ||||
2322 | |||||
2323 | void | ||||
2324 | ctlslot_update(struct ctlslot *s) | ||||
2325 | { | ||||
2326 | struct ctl *c; | ||||
2327 | unsigned int refs_mask; | ||||
2328 | |||||
2329 | for (c = ctl_list; c != NULL((void *)0); c = c->next) { | ||||
2330 | if (c->type == CTL_NONE0) | ||||
2331 | continue; | ||||
2332 | refs_mask = ctlslot_visible(s, c) ? s->self : 0; | ||||
2333 | |||||
2334 | /* nothing to do if no visibility change */ | ||||
2335 | if (((c->refs_mask & s->self) ^ refs_mask) == 0) | ||||
2336 | continue; | ||||
2337 | /* if control becomes visible */ | ||||
2338 | if (refs_mask) | ||||
2339 | c->refs_mask |= s->self; | ||||
2340 | /* if control is hidden */ | ||||
2341 | c->desc_mask |= s->self; | ||||
2342 | } | ||||
2343 | } | ||||
2344 | |||||
2345 | void | ||||
2346 | ctl_node_log(struct ctl_node *c) | ||||
2347 | { | ||||
2348 | log_puts(c->name); | ||||
2349 | if (c->unit >= 0) | ||||
2350 | log_putu(c->unit); | ||||
2351 | } | ||||
2352 | |||||
2353 | void | ||||
2354 | ctl_log(struct ctl *c) | ||||
2355 | { | ||||
2356 | if (c->group[0] != 0) { | ||||
2357 | log_puts(c->group); | ||||
2358 | log_puts("/"); | ||||
2359 | } | ||||
2360 | ctl_node_log(&c->node0); | ||||
2361 | log_puts("."); | ||||
2362 | log_puts(c->func); | ||||
2363 | log_puts("="); | ||||
2364 | switch (c->type) { | ||||
2365 | case CTL_NONE0: | ||||
2366 | log_puts("none"); | ||||
2367 | break; | ||||
2368 | case CTL_NUM2: | ||||
2369 | case CTL_SW3: | ||||
2370 | log_putu(c->curval); | ||||
2371 | break; | ||||
2372 | case CTL_VEC4: | ||||
2373 | case CTL_LIST5: | ||||
2374 | case CTL_SEL6: | ||||
2375 | ctl_node_log(&c->node1); | ||||
2376 | log_puts(":"); | ||||
2377 | log_putu(c->curval); | ||||
2378 | } | ||||
2379 | log_puts(" at "); | ||||
2380 | log_putu(c->addr); | ||||
2381 | log_puts(" -> "); | ||||
2382 | switch (c->scope) { | ||||
2383 | case CTL_HW0: | ||||
2384 | log_puts("hw:"); | ||||
2385 | log_puts(c->u.hw.dev->name); | ||||
2386 | log_puts("/"); | ||||
2387 | log_putu(c->u.hw.addr); | ||||
2388 | break; | ||||
2389 | case CTL_DEV_MASTER1: | ||||
2390 | log_puts("dev_master:"); | ||||
2391 | log_puts(c->u.dev_master.dev->name); | ||||
2392 | break; | ||||
2393 | case CTL_SLOT_LEVEL3: | ||||
2394 | log_puts("slot_level:"); | ||||
2395 | log_puts(c->u.slot_level.slot->name); | ||||
2396 | log_putu(c->u.slot_level.slot->unit); | ||||
2397 | break; | ||||
2398 | case CTL_OPT_DEV2: | ||||
2399 | log_puts("opt_dev:"); | ||||
2400 | log_puts(c->u.opt_dev.opt->name); | ||||
2401 | log_puts("/"); | ||||
2402 | log_puts(c->u.opt_dev.dev->name); | ||||
2403 | break; | ||||
2404 | default: | ||||
2405 | log_puts("unknown"); | ||||
2406 | } | ||||
2407 | } | ||||
2408 | |||||
2409 | int | ||||
2410 | ctl_setval(struct ctl *c, int val) | ||||
2411 | { | ||||
2412 | if (c->curval == val) { | ||||
2413 | if (log_level >= 3) { | ||||
2414 | ctl_log(c); | ||||
2415 | log_puts(": already set\n"); | ||||
2416 | } | ||||
2417 | return 1; | ||||
2418 | } | ||||
2419 | if (val < 0 || val > c->maxval) { | ||||
2420 | if (log_level >= 3) { | ||||
2421 | log_putu(val); | ||||
2422 | log_puts(": ctl val out of bounds\n"); | ||||
2423 | } | ||||
2424 | return 0; | ||||
2425 | } | ||||
2426 | |||||
2427 | switch (c->scope) { | ||||
2428 | case CTL_HW0: | ||||
2429 | if (log_level >= 3) { | ||||
2430 | ctl_log(c); | ||||
2431 | log_puts(": marked as dirty\n"); | ||||
2432 | } | ||||
2433 | c->curval = val; | ||||
2434 | c->dirty = 1; | ||||
2435 | return dev_ref(c->u.hw.dev); | ||||
2436 | case CTL_DEV_MASTER1: | ||||
2437 | if (!c->u.dev_master.dev->master_enabled) | ||||
2438 | return 1; | ||||
2439 | dev_master(c->u.dev_master.dev, val); | ||||
2440 | dev_midi_master(c->u.dev_master.dev); | ||||
2441 | c->val_mask = ~0U; | ||||
2442 | c->curval = val; | ||||
2443 | return 1; | ||||
2444 | case CTL_SLOT_LEVEL3: | ||||
2445 | slot_setvol(c->u.slot_level.slot, val); | ||||
2446 | // XXX change dev_midi_vol() into slot_midi_vol() | ||||
2447 | dev_midi_vol(c->u.slot_level.slot->opt->dev, c->u.slot_level.slot); | ||||
2448 | c->val_mask = ~0U; | ||||
2449 | c->curval = val; | ||||
2450 | return 1; | ||||
2451 | case CTL_OPT_DEV2: | ||||
2452 | c->u.opt_dev.opt->alt_first = c->u.opt_dev.dev; | ||||
2453 | opt_setdev(c->u.opt_dev.opt, c->u.opt_dev.dev); | ||||
2454 | return 1; | ||||
2455 | default: | ||||
2456 | if (log_level >= 2) { | ||||
2457 | ctl_log(c); | ||||
2458 | log_puts(": not writable\n"); | ||||
2459 | } | ||||
2460 | return 1; | ||||
2461 | } | ||||
2462 | } | ||||
2463 | |||||
2464 | /* | ||||
2465 | * add a ctl | ||||
2466 | */ | ||||
2467 | struct ctl * | ||||
2468 | ctl_new(int scope, void *arg0, void *arg1, | ||||
2469 | int type, char *gstr, | ||||
2470 | char *str0, int unit0, char *func, | ||||
2471 | char *str1, int unit1, int maxval, int val) | ||||
2472 | { | ||||
2473 | struct ctl *c, **pc; | ||||
2474 | struct ctlslot *s; | ||||
2475 | int addr; | ||||
2476 | int i; | ||||
2477 | |||||
2478 | /* | ||||
2479 | * find the smallest unused addr number and | ||||
2480 | * the last position in the list | ||||
2481 | */ | ||||
2482 | addr = 0; | ||||
2483 | for (pc = &ctl_list; (c = *pc) != NULL((void *)0); pc = &c->next) { | ||||
2484 | if (c->addr > addr) | ||||
2485 | addr = c->addr; | ||||
2486 | } | ||||
2487 | addr++; | ||||
2488 | |||||
2489 | c = xmalloc(sizeof(struct ctl)); | ||||
2490 | c->type = type; | ||||
2491 | strlcpy(c->func, func, CTL_NAMEMAX16); | ||||
2492 | strlcpy(c->group, gstr, CTL_NAMEMAX16); | ||||
2493 | strlcpy(c->node0.name, str0, CTL_NAMEMAX16); | ||||
2494 | c->node0.unit = unit0; | ||||
2495 | if (c->type == CTL_VEC4 || c->type == CTL_LIST5 || c->type == CTL_SEL6) { | ||||
2496 | strlcpy(c->node1.name, str1, CTL_NAMEMAX16); | ||||
| |||||
2497 | c->node1.unit = unit1; | ||||
2498 | } else | ||||
2499 | memset(&c->node1, 0, sizeof(struct ctl_node)); | ||||
2500 | c->scope = scope; | ||||
2501 | c->u.any.arg0 = arg0; | ||||
2502 | switch (scope) { | ||||
2503 | case CTL_HW0: | ||||
2504 | c->u.hw.addr = *(unsigned int *)arg1; | ||||
2505 | break; | ||||
2506 | case CTL_OPT_DEV2: | ||||
2507 | c->u.any.arg1 = arg1; | ||||
2508 | break; | ||||
2509 | default: | ||||
2510 | c->u.any.arg1 = NULL((void *)0); | ||||
2511 | } | ||||
2512 | c->addr = addr; | ||||
2513 | c->maxval = maxval; | ||||
2514 | c->val_mask = ~0; | ||||
2515 | c->desc_mask = ~0; | ||||
2516 | c->curval = val; | ||||
2517 | c->dirty = 0; | ||||
2518 | c->refs_mask = CTL_DEVMASK(1 << 31); | ||||
2519 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2520 | if (s->ops == NULL((void *)0)) | ||||
2521 | continue; | ||||
2522 | if (ctlslot_visible(s, c)) | ||||
2523 | c->refs_mask |= 1 << i; | ||||
2524 | } | ||||
2525 | c->next = *pc; | ||||
2526 | *pc = c; | ||||
2527 | #ifdef DEBUG1 | ||||
2528 | if (log_level >= 2) { | ||||
2529 | ctl_log(c); | ||||
2530 | log_puts(": added\n"); | ||||
2531 | } | ||||
2532 | #endif | ||||
2533 | return c; | ||||
2534 | } | ||||
2535 | |||||
2536 | void | ||||
2537 | ctl_update(struct ctl *c) | ||||
2538 | { | ||||
2539 | struct ctlslot *s; | ||||
2540 | unsigned int refs_mask; | ||||
2541 | int i; | ||||
2542 | |||||
2543 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2544 | if (s->ops == NULL((void *)0)) | ||||
2545 | continue; | ||||
2546 | refs_mask = ctlslot_visible(s, c) ? s->self : 0; | ||||
2547 | |||||
2548 | /* nothing to do if no visibility change */ | ||||
2549 | if (((c->refs_mask & s->self) ^ refs_mask) == 0) | ||||
2550 | continue; | ||||
2551 | /* if control becomes visible */ | ||||
2552 | if (refs_mask) | ||||
2553 | c->refs_mask |= s->self; | ||||
2554 | /* if control is hidden */ | ||||
2555 | c->desc_mask |= s->self; | ||||
2556 | } | ||||
2557 | } | ||||
2558 | |||||
2559 | int | ||||
2560 | ctl_match(struct ctl *c, int scope, void *arg0, void *arg1) | ||||
2561 | { | ||||
2562 | if (c->type == CTL_NONE0 || c->scope != scope || c->u.any.arg0 != arg0) | ||||
2563 | return 0; | ||||
2564 | if (arg0 != NULL((void *)0) && c->u.any.arg0 != arg0) | ||||
2565 | return 0; | ||||
2566 | switch (scope) { | ||||
2567 | case CTL_HW0: | ||||
2568 | if (arg1 != NULL((void *)0) && c->u.hw.addr != *(unsigned int *)arg1) | ||||
2569 | return 0; | ||||
2570 | break; | ||||
2571 | case CTL_OPT_DEV2: | ||||
2572 | if (arg1 != NULL((void *)0) && c->u.any.arg1 != arg1) | ||||
2573 | return 0; | ||||
2574 | break; | ||||
2575 | } | ||||
2576 | return 1; | ||||
2577 | } | ||||
2578 | |||||
2579 | struct ctl * | ||||
2580 | ctl_find(int scope, void *arg0, void *arg1) | ||||
2581 | { | ||||
2582 | struct ctl *c; | ||||
2583 | |||||
2584 | for (c = ctl_list; c != NULL((void *)0); c = c->next) { | ||||
2585 | if (ctl_match(c, scope, arg0, arg1)) | ||||
2586 | return c; | ||||
2587 | } | ||||
2588 | return NULL((void *)0); | ||||
2589 | } | ||||
2590 | |||||
2591 | int | ||||
2592 | ctl_onval(int scope, void *arg0, void *arg1, int val) | ||||
2593 | { | ||||
2594 | struct ctl *c; | ||||
2595 | |||||
2596 | c = ctl_find(scope, arg0, arg1); | ||||
2597 | if (c == NULL((void *)0)) | ||||
2598 | return 0; | ||||
2599 | c->curval = val; | ||||
2600 | c->val_mask = ~0U; | ||||
2601 | return 1; | ||||
2602 | } | ||||
2603 | |||||
2604 | void | ||||
2605 | ctl_del(int scope, void *arg0, void *arg1) | ||||
2606 | { | ||||
2607 | struct ctl *c, **pc; | ||||
2608 | |||||
2609 | pc = &ctl_list; | ||||
2610 | for (;;) { | ||||
2611 | c = *pc; | ||||
2612 | if (c == NULL((void *)0)) | ||||
2613 | return; | ||||
2614 | if (ctl_match(c, scope, arg0, arg1)) { | ||||
2615 | #ifdef DEBUG1 | ||||
2616 | if (log_level >= 2) { | ||||
2617 | ctl_log(c); | ||||
2618 | log_puts(": removed\n"); | ||||
2619 | } | ||||
2620 | #endif | ||||
2621 | c->refs_mask &= ~CTL_DEVMASK(1 << 31); | ||||
2622 | if (c->refs_mask == 0) { | ||||
2623 | *pc = c->next; | ||||
2624 | xfree(c); | ||||
2625 | continue; | ||||
2626 | } | ||||
2627 | c->type = CTL_NONE0; | ||||
2628 | c->desc_mask = ~0; | ||||
2629 | } | ||||
2630 | pc = &c->next; | ||||
2631 | } | ||||
2632 | } | ||||
2633 | |||||
2634 | void | ||||
2635 | dev_ctlsync(struct dev *d) | ||||
2636 | { | ||||
2637 | struct ctl *c; | ||||
2638 | struct ctlslot *s; | ||||
2639 | int found, i; | ||||
2640 | |||||
2641 | found = 0; | ||||
2642 | for (c = ctl_list; c != NULL((void *)0); c = c->next) { | ||||
| |||||
2643 | if (c->scope == CTL_HW0 && | ||||
2644 | c->u.hw.dev == d && | ||||
2645 | c->type == CTL_NUM2 && | ||||
2646 | strcmp(c->group, d->name) == 0 && | ||||
2647 | strcmp(c->node0.name, "output") == 0 && | ||||
2648 | strcmp(c->func, "level") == 0) | ||||
2649 | found = 1; | ||||
2650 | } | ||||
2651 | |||||
2652 | if (d->master_enabled && found) { | ||||
2653 | if (log_level >= 2) { | ||||
2654 | dev_log(d); | ||||
2655 | log_puts(": software master level control disabled\n"); | ||||
2656 | } | ||||
2657 | d->master_enabled = 0; | ||||
2658 | ctl_del(CTL_DEV_MASTER1, d, NULL((void *)0)); | ||||
2659 | } else if (!d->master_enabled
| ||||
2660 | if (log_level >= 2) { | ||||
2661 | dev_log(d); | ||||
2662 | log_puts(": software master level control enabled\n"); | ||||
2663 | } | ||||
2664 | d->master_enabled = 1; | ||||
2665 | ctl_new(CTL_DEV_MASTER1, d, NULL((void *)0), | ||||
2666 | CTL_NUM2, d->name, "output", -1, "level", | ||||
2667 | NULL((void *)0), -1, 127, d->master); | ||||
2668 | } | ||||
2669 | |||||
2670 | for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT8; i++, s++) { | ||||
2671 | if (s->ops == NULL((void *)0)) | ||||
2672 | continue; | ||||
2673 | if (s->opt->dev == d) | ||||
2674 | s->ops->sync(s->arg); | ||||
2675 | } | ||||
2676 | } |