Annotation of src/usr.bin/sndiod/dev.c, Revision 1.2
1.2 ! ratchov 1: /* $OpenBSD: dev.c,v 1.1 2012/11/23 07:03:28 ratchov Exp $ */
1.1 ratchov 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: int dev_open(struct dev *);
31: void dev_close(struct dev *);
32: void dev_clear(struct dev *);
33: void dev_master(struct dev *, unsigned int);
34:
35: void slot_attach(struct slot *);
36: void slot_ready(struct slot *);
37: void slot_mix_drop(struct slot *);
38: void slot_sub_sil(struct slot *);
39:
40: void zomb_onmove(void *, int);
41: void zomb_onvol(void *, unsigned int);
42: void zomb_fill(void *);
43: void zomb_flush(void *);
44: void zomb_eof(void *);
45: void zomb_mmcstart(void *);
46: void zomb_mmcstop(void *);
47: void zomb_mmcloc(void *, unsigned int);
48: void zomb_exit(void *);
49:
50: void dev_midi_imsg(void *, unsigned char *, int);
51: void dev_midi_omsg(void *, unsigned char *, int);
52: void dev_midi_fill(void *, int);
53: void dev_midi_exit(void *);
54:
55: struct midiops dev_midiops = {
56: dev_midi_imsg,
57: dev_midi_omsg,
58: dev_midi_fill,
59: dev_midi_exit
60: };
61:
62: struct slotops zomb_slotops = {
63: zomb_onmove,
64: zomb_onvol,
65: zomb_fill,
66: zomb_flush,
67: zomb_eof,
68: zomb_mmcstart,
69: zomb_mmcstop,
70: zomb_mmcloc,
71: zomb_exit
72: };
73:
74: struct dev *dev_list = NULL;
75: unsigned int dev_sndnum = 0;
76:
77: void
78: dev_log(struct dev *d)
79: {
80: log_puts("snd");
81: log_putu(d->num);
82: }
83:
84: void
85: slot_log(struct slot *s)
86: {
87: #ifdef DEBUG
88: static char *pstates[] = {
89: "ini", "sta", "rdy", "run", "stp", "mid"
90: };
91: static char *tstates[] = {
92: "off", "sta", "run", "stp"
93: };
94: #endif
95: log_puts(s->name);
96: log_putu(s->unit);
97: #ifdef DEBUG
98: if (log_level >= 3) {
99: log_puts(" vol=");
100: log_putu(s->vol);
101: if (s->ops) {
102: log_puts(",pst=");
103: log_puts(pstates[s->pstate]);
104: log_puts(",mmc=");
105: log_puts(tstates[s->tstate]);
106: }
107: }
108: #endif
109: }
110:
111: void
112: zomb_onmove(void *arg, int delta)
113: {
114: }
115:
116: void
117: zomb_onvol(void *arg, unsigned int vol)
118: {
119: }
120:
121: void
122: zomb_fill(void *arg)
123: {
124: }
125:
126: void
127: zomb_flush(void *arg)
128: {
129: }
130:
131: void
132: zomb_eof(void *arg)
133: {
134: struct slot *s = arg;
135:
136: #ifdef DEBUG
137: if (log_level >= 3) {
138: slot_log(s);
139: log_puts(": zomb_eof\n");
140: }
141: #endif
142: s->ops = NULL;
143: }
144:
145: void
146: zomb_mmcstart(void *arg)
147: {
148: }
149:
150: void
151: zomb_mmcstop(void *arg)
152: {
153: }
154:
155: void
156: zomb_mmcloc(void *arg, unsigned int pos)
157: {
158: }
159:
160: void
161: zomb_exit(void *arg)
162: {
163: #ifdef DEBUG
164: struct slot *s = arg;
165:
166: if (log_level >= 3) {
167: slot_log(s);
168: log_puts(": zomb_exit\n");
169: }
170: #endif
171: }
172:
173: /*
174: * send a quarter frame MTC message
175: */
176: void
177: dev_midi_qfr(struct dev *d, int delta)
178: {
179: unsigned char buf[2];
180: unsigned int data;
181: int qfrlen;
182:
183: d->mtc.delta += delta * MTC_SEC;
184: qfrlen = d->rate * (MTC_SEC / (4 * d->mtc.fps));
185: while (d->mtc.delta >= qfrlen) {
186: switch (d->mtc.qfr) {
187: case 0:
188: data = d->mtc.fr & 0xf;
189: break;
190: case 1:
191: data = d->mtc.fr >> 4;
192: break;
193: case 2:
194: data = d->mtc.sec & 0xf;
195: break;
196: case 3:
197: data = d->mtc.sec >> 4;
198: break;
199: case 4:
200: data = d->mtc.min & 0xf;
201: break;
202: case 5:
203: data = d->mtc.min >> 4;
204: break;
205: case 6:
206: data = d->mtc.hr & 0xf;
207: break;
208: case 7:
209: data = (d->mtc.hr >> 4) | (d->mtc.fps_id << 1);
210: /*
211: * tick messages are sent 2 frames ahead
212: */
213: d->mtc.fr += 2;
214: if (d->mtc.fr < d->mtc.fps)
215: break;
216: d->mtc.fr -= d->mtc.fps;
217: d->mtc.sec++;
218: if (d->mtc.sec < 60)
219: break;
220: d->mtc.sec = 0;
221: d->mtc.min++;
222: if (d->mtc.min < 60)
223: break;
224: d->mtc.min = 0;
225: d->mtc.hr++;
226: if (d->mtc.hr < 24)
227: break;
228: d->mtc.hr = 0;
229: break;
230: default:
231: /* NOTREACHED */
232: data = 0;
233: }
234: buf[0] = 0xf1;
235: buf[1] = (d->mtc.qfr << 4) | data;
236: d->mtc.qfr++;
237: d->mtc.qfr &= 7;
238: midi_send(d->midi, buf, 2);
239: d->mtc.delta -= qfrlen;
240: }
241: }
242:
243: /*
244: * send a full frame MTC message
245: */
246: void
247: dev_midi_full(struct dev *d)
248: {
249: struct sysex x;
250: unsigned int fps;
251:
252: d->mtc.delta = MTC_SEC * dev_getpos(d);
253: if (d->rate % (30 * 4 * d->round) == 0) {
254: d->mtc.fps_id = MTC_FPS_30;
255: d->mtc.fps = 30;
256: } else if (d->rate % (25 * 4 * d->round) == 0) {
257: d->mtc.fps_id = MTC_FPS_25;
258: d->mtc.fps = 25;
259: } else {
260: d->mtc.fps_id = MTC_FPS_24;
261: d->mtc.fps = 24;
262: }
263: #ifdef DEBUG
264: if (log_level >= 3) {
265: dev_log(d);
266: log_puts(": mtc full frame at ");
267: log_puti(d->mtc.delta);
268: log_puts(", ");
269: log_puti(d->mtc.fps);
270: log_puts(" fps\n");
271: }
272: #endif
273: fps = d->mtc.fps;
274: d->mtc.hr = (d->mtc.origin / (MTC_SEC * 3600)) % 24;
275: d->mtc.min = (d->mtc.origin / (MTC_SEC * 60)) % 60;
276: d->mtc.sec = (d->mtc.origin / (MTC_SEC)) % 60;
277: d->mtc.fr = (d->mtc.origin / (MTC_SEC / fps)) % fps;
278:
279: x.start = SYSEX_START;
280: x.type = SYSEX_TYPE_RT;
281: x.dev = 0x7f;
282: x.id0 = SYSEX_MTC;
283: x.id1 = SYSEX_MTC_FULL;
284: x.u.full.hr = d->mtc.hr | (d->mtc.fps_id << 5);
285: x.u.full.min = d->mtc.min;
286: x.u.full.sec = d->mtc.sec;
287: x.u.full.fr = d->mtc.fr;
288: x.u.full.end = SYSEX_END;
289: d->mtc.qfr = 0;
290: midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(full));
291: }
292:
293: /*
294: * send a volume change MIDI message
295: */
296: void
297: dev_midi_vol(struct dev *d, struct slot *s)
298: {
299: unsigned char msg[3];
300:
301: msg[0] = MIDI_CTL | (s - d->slot);
302: msg[1] = MIDI_CTL_VOL;
303: msg[2] = s->vol;
304: midi_send(d->midi, msg, 3);
305: }
306:
307: /*
308: * send a master volume MIDI message
309: */
310: void
311: dev_midi_master(struct dev *d)
312: {
313: struct sysex x;
314:
315: memset(&x, 0, sizeof(struct sysex));
316: x.start = SYSEX_START;
317: x.type = SYSEX_TYPE_RT;
318: x.id0 = SYSEX_CONTROL;
319: x.id1 = SYSEX_MASTER;
320: x.u.master.fine = 0;
321: x.u.master.coarse = d->master;
322: x.u.master.end = SYSEX_END;
323: midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(master));
324: }
325:
326: /*
327: * send a sndiod-specific slot description MIDI message
328: */
329: void
330: dev_midi_slotdesc(struct dev *d, struct slot *s)
331: {
332: struct sysex x;
333:
334: memset(&x, 0, sizeof(struct sysex));
335: x.start = SYSEX_START;
336: x.type = SYSEX_TYPE_EDU;
337: x.id0 = SYSEX_AUCAT;
338: x.id1 = SYSEX_AUCAT_SLOTDESC;
339: if (*s->name != '\0') {
340: snprintf((char *)x.u.slotdesc.name, SYSEX_NAMELEN,
341: "%s%u", s->name, s->unit);
342: }
343: x.u.slotdesc.chan = s - d->slot;
344: x.u.slotdesc.end = SYSEX_END;
345: midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(slotdesc));
346: }
347:
348: void
349: dev_midi_dump(struct dev *d)
350: {
351: struct sysex x;
352: struct slot *s;
353: int i;
354:
355: dev_midi_master(d);
356: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
357: dev_midi_slotdesc(d, s);
358: dev_midi_vol(d, s);
359: }
360: x.start = SYSEX_START;
361: x.type = SYSEX_TYPE_EDU;
362: x.dev = 0;
363: x.id0 = SYSEX_AUCAT;
364: x.id1 = SYSEX_AUCAT_DUMPEND;
365: x.u.dumpend.end = SYSEX_END;
366: midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(dumpend));
367: }
368:
369: void
370: dev_midi_imsg(void *arg, unsigned char *msg, int len)
371: {
372: #ifdef DEBUG
373: struct dev *d = arg;
374:
375: dev_log(d);
376: log_puts(": can't receive midi messages\n");
377: panic();
378: #endif
379: }
380:
381: void
382: dev_midi_omsg(void *arg, unsigned char *msg, int len)
383: {
384: struct dev *d = arg;
385: struct sysex *x;
386: unsigned int fps, chan;
387:
388: if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
389: chan = msg[0] & MIDI_CHANMASK;
390: if (chan >= DEV_NSLOT)
391: return;
392: slot_setvol(d->slot + chan, msg[2]);
393: return;
394: }
395: x = (struct sysex *)msg;
396: if (x->start != SYSEX_START)
397: return;
398: if (len < SYSEX_SIZE(empty))
399: return;
400: switch (x->type) {
401: case SYSEX_TYPE_RT:
402: if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
403: if (len == SYSEX_SIZE(master))
404: dev_master(d, x->u.master.coarse);
405: return;
406: }
407: if (x->id0 != SYSEX_MMC)
408: return;
409: switch (x->id1) {
410: case SYSEX_MMC_STOP:
411: if (len != SYSEX_SIZE(stop))
412: return;
413: if (log_level >= 2) {
414: dev_log(d);
415: log_puts(": mmc stop\n");
416: }
417: dev_mmcstop(d);
418: break;
419: case SYSEX_MMC_START:
420: if (len != SYSEX_SIZE(start))
421: return;
422: if (log_level >= 2) {
423: dev_log(d);
424: log_puts(": mmc start\n");
425: }
426: dev_mmcstart(d);
427: break;
428: case SYSEX_MMC_LOC:
429: if (len != SYSEX_SIZE(loc) ||
430: x->u.loc.len != SYSEX_MMC_LOC_LEN ||
431: x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
432: return;
433: switch (x->u.loc.hr >> 5) {
434: case MTC_FPS_24:
435: fps = 24;
436: break;
437: case MTC_FPS_25:
438: fps = 25;
439: break;
440: case MTC_FPS_30:
441: fps = 30;
442: break;
443: default:
444: dev_mmcstop(d);
445: return;
446: }
447: dev_mmcloc(d,
448: (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
449: x->u.loc.min * 60 * MTC_SEC +
450: x->u.loc.sec * MTC_SEC +
451: x->u.loc.fr * (MTC_SEC / fps) +
452: x->u.loc.cent * (MTC_SEC / 100 / fps));
453: break;
454: }
455: break;
456: case SYSEX_TYPE_EDU:
457: if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
458: return;
459: if (len != SYSEX_SIZE(dumpreq))
460: return;
461: dev_midi_dump(d);
462: break;
463: }
464: }
465:
466: void
467: dev_midi_fill(void *arg, int count)
468: {
1.2 ! ratchov 469: /* nothing to do */
1.1 ratchov 470: }
471:
472: void
473: dev_midi_exit(void *arg)
474: {
475: struct dev *d = arg;
476:
477: if (log_level >= 1) {
478: dev_log(d);
479: log_puts(": midi end point died\n");
480: }
481: if (d->pstate != DEV_CFG)
482: dev_close(d);
483: }
484:
485: void
486: slot_mix_drop(struct slot *s)
487: {
488: while (s->mix.drop > 0 && s->mix.buf.used >= s->round * s->mix.bpf) {
489: #ifdef DEBUG
490: if (log_level >= 4) {
491: slot_log(s);
492: log_puts(": dropped a play block\n");
493: }
494: #endif
495: abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
496: s->mix.drop--;
497: }
498: }
499:
500: void
501: slot_sub_sil(struct slot *s)
502: {
503: unsigned char *data;
504: int count;
505:
506: while (s->sub.silence > 0) {
507: data = abuf_wgetblk(&s->sub.buf, &count);
508: if (count < s->round * s->sub.bpf)
509: break;
510: #ifdef DEBUG
511: if (log_level >= 4) {
512: slot_log(s);
513: log_puts(": inserted a rec block of silence\n");
514: }
515: #endif
516: if (s->sub.encbuf)
517: enc_sil_do(&s->sub.enc, data, s->round);
518: else
519: memset(data, 0, s->round * s->sub.bpf);
520: abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf);
521: s->sub.silence--;
522: }
523: }
524:
525: /*
526: * merge play buffer contents into record buffer as if the
527: * play stream was recorded
528: */
529: void
530: dev_mon_snoop(struct dev *d)
531: {
532: }
533:
534: int
535: play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
536: {
537: int i, offs, vol, nch;
538: void *in;
539:
540: if (s->mix.resampbuf) {
541: todo = resamp_do(&s->mix.resamp,
542: res_in, s->mix.resampbuf, todo);
543: in = s->mix.resampbuf;
544: } else
545: in = res_in;
546:
547: nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
548: vol = ADATA_MUL(s->mix.weight, s->mix.vol) / s->mix.join;
549: cmap_add(&s->mix.cmap, in, out, vol, todo);
550:
551: offs = 0;
552: for (i = s->mix.join - 1; i > 0; i--) {
553: offs += nch;
554: if (offs > s->mix.cmap.inext)
555: break;
556: cmap_add(&s->mix.cmap, (adata_t *)in + offs, out, vol, todo);
557: }
558: offs = 0;
559: for (i = s->mix.expand - 1; i > 0; i--) {
560: offs += nch;
561: if (offs > s->mix.cmap.onext)
562: break;
563: cmap_add(&s->mix.cmap, in, (adata_t *)out + offs, vol, todo);
564: }
565: return todo;
566: }
567:
568: int
569: play_filt_dec(struct slot *s, void *in, void *out, int todo)
570: {
571: void *tmp;
572:
573: tmp = s->mix.decbuf;
574: if (tmp)
575: dec_do(&s->mix.dec, in, tmp, todo);
576: return play_filt_resamp(s, tmp ? tmp : in, out, todo);
577: }
578:
579: /*
580: * mix "todo" frames from the input block over the output block; if
581: * there are frames to drop, less frames are consumed from the input
582: */
583: void
584: dev_mix_badd(struct dev *d, struct slot *s)
585: {
586: adata_t *idata, *odata;
587: int icount;
588:
589: odata = DEV_PBUF(d);
590: idata = (adata_t *)abuf_rgetblk(&s->mix.buf, &icount);
591: #ifdef DEBUG
592: if (icount < s->round * s->mix.bpf) {
593: slot_log(s);
594: log_puts(": not enough data to mix (");
595: log_putu(icount);
596: log_puts("bytes)\n");
597: panic();
598: }
599: #endif
600: play_filt_dec(s, idata, odata, s->round);
601: abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
602: }
603:
604: void
605: dev_empty_cycle(struct dev *d)
606: {
607: unsigned char *base;
608: int nsamp;
609:
610: base = (unsigned char *)DEV_PBUF(d);
611: nsamp = d->round * d->pchan;
612: memset(base, 0, nsamp * sizeof(adata_t));
613: if (d->encbuf) {
614: enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
615: d->encbuf, d->round);
616: }
617: }
618:
619: /*
620: * Normalize input levels.
621: */
622: void
623: dev_mix_adjvol(struct dev *d)
624: {
625: unsigned int n;
626: struct slot *i, *j;
627: int weight;
628:
629: for (i = d->slot_list; i != NULL; i = i->next) {
630: if (!(i->mode & MODE_PLAY))
631: continue;
632: weight = ADATA_UNIT;
633: if (d->autovol) {
634: /*
635: * count the number of inputs that have
636: * overlapping channel sets
637: */
638: n = 0;
639: for (j = d->slot_list; j != NULL; j = j->next) {
640: if (!(j->mode & MODE_PLAY))
641: continue;
642: if (i->mix.slot_cmin <= j->mix.slot_cmax &&
643: i->mix.slot_cmax >= j->mix.slot_cmin)
644: n++;
645: }
646: weight /= n;
647: }
648: if (weight > i->mix.maxweight)
649: weight = i->mix.maxweight;
650: i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master));
651: #ifdef DEBUG
652: if (log_level >= 3) {
653: slot_log(i);
654: log_puts(": set weight: ");
655: log_puti(i->mix.weight);
656: log_puts("/");
657: log_puti(i->mix.maxweight);
658: log_puts("\n");
659: }
660: #endif
661: }
662: }
663:
664: void
665: dev_mix_cycle(struct dev *d)
666: {
667: struct slot *s, **ps;
668: unsigned char *base;
669: int nsamp;
670:
671: #ifdef DEBUG
672: if (log_level >= 4) {
673: dev_log(d);
674: log_puts(": dev_mix_cycle, poffs = ");
675: log_puti(d->poffs);
676: log_puts("\n");
677: }
678: #endif
679: base = (unsigned char *)DEV_PBUF(d);
680: nsamp = d->round * d->pchan;
681: memset(base, 0, nsamp * sizeof(adata_t));
682: ps = &d->slot_list;
683: while ((s = *ps) != NULL) {
684: if (!(s->mode & MODE_PLAY)) {
685: ps = &s->next;
686: continue;
687: }
688: #ifdef DEBUG
689: if (log_level >= 4) {
690: slot_log(s);
691: log_puts(": mixing, drop = ");
692: log_puti(s->mix.drop);
693: log_puts(" cycles\n");
694: }
695: #endif
696: slot_mix_drop(s);
697: if (s->mix.drop < 0) {
698: s->mix.drop++;
699: ps = &s->next;
700: continue;
701: }
702: if (s->mix.buf.used < s->round * s->mix.bpf &&
703: s->pstate == SLOT_STOP) {
704: /*
705: * partial blocks are zero-filled by socket
706: * layer
707: */
708: s->pstate = SLOT_INIT;
709: abuf_done(&s->mix.buf);
710: if (s->mix.decbuf)
711: xfree(s->mix.decbuf);
712: if (s->mix.resampbuf)
713: xfree(s->mix.resampbuf);
714: s->ops->eof(s->arg);
715: *ps = s->next;
716: dev_mix_adjvol(d);
717: continue;
718: }
719: if (s->mix.buf.used < s->round * s->mix.bpf &&
720: !(s->pstate == SLOT_STOP)) {
721: if (s->xrun == XRUN_IGNORE) {
722: if (s->mode & MODE_RECMASK)
723: s->sub.silence--;
724: s->delta -= s->round;
725: #ifdef DEBUG
726: if (log_level >= 3) {
727: slot_log(s);
728: log_puts(": underrun, pause cycle\n");
729: }
730: #endif
731: ps = &s->next;
732: continue;
733: }
734: if (s->xrun == XRUN_SYNC) {
735: s->mix.drop++;
736: ps = &s->next;
737: continue;
738: }
739: if (s->xrun == XRUN_ERROR) {
740: s->ops->exit(s->arg);
741: *ps = s->next;
742: continue;
743: }
744: } else {
745: dev_mix_badd(d, s);
746: if (s->pstate != SLOT_STOP)
747: s->ops->fill(s->arg);
748: }
749: ps = &s->next;
750: }
751: if (d->encbuf) {
752: enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
753: d->encbuf, d->round);
754: }
755: }
756:
757: int
758: rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
759: {
760: int i, vol, offs, nch;
761: void *out = res_out;
762:
763: out = (s->sub.resampbuf) ? s->sub.resampbuf : res_out;
764:
765: nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
766: vol = ADATA_UNIT / s->sub.join;
767: cmap_copy(&s->sub.cmap, in, out, vol, todo);
768:
769: offs = 0;
770: for (i = s->sub.join - 1; i > 0; i--) {
771: offs += nch;
772: cmap_add(&s->sub.cmap, (adata_t *)in + offs, out, vol, todo);
773: }
774: offs = 0;
775: for (i = s->sub.expand - 1; i > 0; i--) {
776: offs += nch;
777: cmap_copy(&s->sub.cmap, in, (adata_t *)out + offs, vol, todo);
778: }
779: if (s->sub.resampbuf) {
780: todo = resamp_do(&s->sub.resamp,
781: s->sub.resampbuf, res_out, todo);
782: }
783: return todo;
784: }
785:
786: int
787: rec_filt_enc(struct slot *s, void *in, void *out, int todo)
788: {
789: void *tmp;
790:
791: tmp = s->sub.encbuf;
792: todo = rec_filt_resamp(s, in, tmp ? tmp : out, todo);
793: if (tmp)
794: enc_do(&s->sub.enc, tmp, out, todo);
795: return todo;
796: }
797:
798: /*
799: * Copy data from slot to device
800: */
801: void
802: dev_sub_bcopy(struct dev *d, struct slot *s)
803: {
804: adata_t *idata, *odata;
805: int ocount;
806:
807: idata = (s->mode & MODE_MON) ? DEV_PBUF(d) : d->rbuf;
808: odata = (adata_t *)abuf_wgetblk(&s->sub.buf, &ocount);
809: #ifdef DEBUG
810: if (ocount < s->round * s->sub.bpf) {
811: log_puts("dev_sub_bcopy: not enough space\n");
812: panic();
813: }
814: #endif
815: ocount = rec_filt_enc(s, idata, odata, d->round);
816: abuf_wcommit(&s->sub.buf, ocount * s->sub.bpf);
817: }
818:
819: void
820: dev_sub_cycle(struct dev *d)
821: {
822: struct slot *s, **ps;
823:
824: #ifdef DEBUG
825: if (log_level >= 4) {
826: dev_log(d);
827: log_puts(": dev_sub_cycle\n");
828: }
829: #endif
830: if ((d->mode & MODE_REC) && d->decbuf)
831: dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round);
832: ps = &d->slot_list;
833: while ((s = *ps) != NULL) {
834: if (!(s->mode & MODE_RECMASK) || s->pstate == SLOT_STOP) {
835: ps = &s->next;
836: continue;
837: }
838: slot_sub_sil(s);
839: if (s->sub.silence < 0) {
840: s->sub.silence++;
841: ps = &s->next;
842: continue;
843: }
844: if (s->sub.buf.len - s->sub.buf.used < s->round * s->sub.bpf) {
845: if (s->xrun == XRUN_IGNORE) {
846: if (s->mode & MODE_PLAY)
847: s->mix.drop--;
848: s->delta -= s->round;
849: #ifdef DEBUG
850: if (log_level >= 3) {
851: slot_log(s);
852: log_puts(": overrun, pause cycle\n");
853: }
854: #endif
855: ps = &s->next;
856: continue;
857: }
858: if (s->xrun == XRUN_SYNC) {
859: s->sub.silence++;
860: ps = &s->next;
861: continue;
862: }
863: if (s->xrun == XRUN_ERROR) {
864: s->ops->exit(s->arg);
865: *ps = s->next;
866: continue;
867: }
868: } else {
869: dev_sub_bcopy(d, s);
870: s->ops->flush(s->arg);
871: }
872: ps = &s->next;
873: }
874: }
875:
876: /*
877: * called at every clock tick by the device
878: */
879: void
880: dev_onmove(struct dev *d, int delta)
881: {
882: long long pos;
883: struct slot *s, *snext;
884:
885: /*
886: * s->ops->onmove() may remove the slot
887: */
888: for (s = d->slot_list; s != NULL; s = snext) {
889: snext = s->next;
890: pos = (long long)delta * s->round + s->delta_rem;
891: s->delta_rem = pos % d->round;
892: s->delta += pos / (int)d->round;
893: if (s->delta >= 0)
894: s->ops->onmove(s->arg, delta);
895: }
896: if (d->tstate == MMC_RUN)
897: dev_midi_qfr(d, delta);
898: }
899:
900: void
901: dev_master(struct dev *d, unsigned int master)
902: {
903: if (log_level >= 2) {
904: dev_log(d);
905: log_puts(": master volume set to ");
906: log_putu(master);
907: log_puts("\n");
908: }
909: d->master = master;
910: if (d->mode & MODE_PLAY)
911: dev_mix_adjvol(d);
912: }
913:
914: void
915: dev_cycle(struct dev *d)
916: {
917: if (d->slot_list == NULL && d->tstate != MMC_RUN) {
918: if (log_level >= 2) {
919: dev_log(d);
920: log_puts(": device stopped\n");
921: }
922: dev_sio_stop(d);
923: d->pstate = DEV_INIT;
924: if (d->refcnt == 0)
925: dev_close(d);
926: else
927: dev_clear(d);
928: return;
929: }
930: #ifdef DEBUG
931: if (log_level >= 4) {
932: dev_log(d);
933: log_puts(": device cycle, prime = ");
934: log_putu(d->prime);
935: log_puts("\n");
936: }
937: #endif
938: if (d->prime > 0) {
939: d->prime -= d->round;
940: dev_empty_cycle(d);
941: } else {
942: if (d->mode & MODE_RECMASK)
943: dev_sub_cycle(d);
944: if (d->mode & MODE_PLAY)
945: dev_mix_cycle(d);
946: }
947: }
948:
949: /*
950: * return the latency that a stream would have if it's attached
951: */
952: int
953: dev_getpos(struct dev *d)
954: {
955: return (d->mode & MODE_PLAY) ? -d->bufsz : 0;
956: }
957:
958: /*
959: * Create a sndio device
960: */
961: struct dev *
962: dev_new(char *path, struct aparams *par,
963: unsigned int mode, unsigned int bufsz, unsigned int round,
964: unsigned int rate, unsigned int hold, unsigned int autovol)
965: {
966: struct dev *d;
967: unsigned int i;
968:
969: if (dev_sndnum == DEV_NMAX) {
970: if (log_level >= 1)
971: log_puts("too many devices\n");
972: return NULL;
973: }
974: d = xmalloc(sizeof(struct dev));
975: d->num = dev_sndnum++;
976:
977: /*
978: * XXX: below, we allocate a midi input buffer, since we don't
979: * receive raw midi data, so no need to allocate a input
980: * ibuf. Possibly set imsg & fill callbacks to NULL and
981: * use this to in midi_new() to check if buffers need to be
982: * allocated
983: */
984: d->midi = midi_new(&dev_midiops, d, MODE_MIDIIN | MODE_MIDIOUT);
985: midi_tag(d->midi, d->num);
986: d->path = path;
987: d->reqpar = *par;
988: d->reqmode = mode;
989: d->reqpchan = d->reqrchan = 0;
990: d->reqbufsz = bufsz;
991: d->reqround = round;
992: d->reqrate = rate;
993: d->hold = hold;
994: d->autovol = autovol;
995: d->autostart = 0;
996: d->refcnt = 0;
997: d->pstate = DEV_CFG;
998: d->serial = 0;
999: for (i = 0; i < DEV_NSLOT; i++) {
1000: d->slot[i].unit = i;
1001: d->slot[i].ops = NULL;
1002: d->slot[i].vol = MIDI_MAXCTL;
1003: d->slot[i].tstate = MMC_OFF;
1004: d->slot[i].serial = d->serial++;
1005: d->slot[i].name[0] = '\0';
1006: }
1007: d->slot_list = NULL;
1008: d->master = MIDI_MAXCTL;
1009: d->mtc.origin = 0;
1010: d->tstate = MMC_STOP;
1011: d->next = dev_list;
1012: dev_list = d;
1013: return d;
1014: }
1015:
1016: /*
1017: * adjust device parameters and mode
1018: */
1019: void
1020: dev_adjpar(struct dev *d, int mode,
1021: int pmin, int pmax, int rmin, int rmax)
1022: {
1023: d->reqmode |= mode & MODE_AUDIOMASK;
1024: if (mode & MODE_PLAY) {
1025: if (d->reqpchan < pmax + 1)
1026: d->reqpchan = pmax + 1;
1027: }
1028: if (mode & MODE_REC) {
1029: if (d->reqrchan < rmax + 1)
1030: d->reqrchan = rmax + 1;
1031: }
1032: }
1033:
1034: /*
1035: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
1036: * monitor, midi control, and any necessary conversions.
1037: */
1038: int
1039: dev_open(struct dev *d)
1040: {
1041: d->mode = d->reqmode;
1042: d->round = d->reqround;
1043: d->bufsz = d->reqbufsz;
1044: d->rate = d->reqrate;
1045: d->pchan = d->reqpchan;
1046: d->rchan = d->reqrchan;
1047: d->par = d->reqpar;
1048: if (d->pchan == 0)
1049: d->pchan = 2;
1050: if (d->rchan == 0)
1051: d->rchan = 2;
1052: if (!dev_sio_open(d)) {
1053: if (log_level >= 1) {
1054: dev_log(d);
1055: log_puts(": ");
1056: log_puts(d->path);
1057: log_puts(": failed to open audio device\n");
1058: }
1059: return 0;
1060: }
1061: if (d->mode & MODE_REC) {
1062: /*
1063: * Create device <-> demuxer buffer
1064: */
1065: d->rbuf = xmalloc(d->round * d->rchan * sizeof(adata_t));
1066:
1067: /*
1068: * Insert a converter, if needed.
1069: */
1070: if (!aparams_native(&d->par)) {
1071: dec_init(&d->dec, &d->par, d->rchan);
1072: d->decbuf = xmalloc(d->round * d->rchan * d->par.bps);
1073: } else
1074: d->decbuf = NULL;
1075: }
1076: if (d->mode & MODE_PLAY) {
1077: /*
1078: * Create device <-> mixer buffer
1079: */
1080: d->pbuf = xmalloc(d->bufsz * d->pchan * sizeof(adata_t));
1081: d->poffs = 0;
1082: d->mode |= MODE_MON;
1083:
1084: /*
1085: * Append a converter, if needed.
1086: */
1087: if (!aparams_native(&d->par)) {
1088: enc_init(&d->enc, &d->par, d->pchan);
1089: d->encbuf = xmalloc(d->round * d->pchan * d->par.bps);
1090: } else
1091: d->encbuf = NULL;
1092: }
1093: d->pstate = DEV_INIT;
1094: if (log_level >= 2) {
1095: dev_log(d);
1096: log_puts(": ");
1097: log_putu(d->rate);
1098: log_puts("Hz, ");
1099: aparams_log(&d->par);
1100: if (d->mode & MODE_PLAY) {
1101: log_puts(", play 0:");
1102: log_puti(d->pchan - 1);
1103: }
1104: if (d->mode & MODE_REC) {
1105: log_puts(", rec 0:");
1106: log_puti(d->rchan - 1);
1107: }
1108: log_puts(", ");
1109: log_putu(d->bufsz / d->round);
1110: log_puts(" blocks of ");
1111: log_putu(d->round);
1112: log_puts(" frames\n");
1113: }
1114: return 1;
1115: }
1116:
1117: /*
1118: * force the device to go in DEV_CFG state, the caller is supposed to
1119: * ensure buffers are drained
1120: */
1121: void
1122: dev_close(struct dev *d)
1123: {
1124: struct slot *s, *snext;
1125:
1126: #ifdef DEBUG
1127: if (log_level >= 3) {
1128: dev_log(d);
1129: log_puts(": closing\n");
1130: }
1131: #endif
1132: while ((s = d->slot_list) != NULL) {
1133: snext = s->next;
1134: if (s->ops)
1135: s->ops->exit(s->arg);
1136: s->ops = NULL;
1137: d->slot_list = snext;
1138: }
1139: dev_sio_close(d);
1140: if (d->mode & MODE_PLAY) {
1141: if (d->encbuf != NULL)
1142: xfree(d->encbuf);
1143: xfree(d->pbuf);
1144: }
1145: if (d->mode & MODE_REC) {
1146: if (d->decbuf != NULL)
1147: xfree(d->decbuf);
1148: xfree(d->rbuf);
1149: }
1150: dev_clear(d);
1151: d->pstate = DEV_CFG;
1152: }
1153:
1154: int
1155: dev_ref(struct dev *d)
1156: {
1157: #ifdef DEBUG
1158: if (log_level >= 3) {
1159: dev_log(d);
1160: log_puts(": device requested\n");
1161: }
1162: #endif
1163: if (d->pstate == DEV_CFG && !dev_open(d))
1164: return 0;
1165: d->refcnt++;
1166: return 1;
1167: }
1168:
1169: void
1170: dev_unref(struct dev *d)
1171: {
1172: #ifdef DEBUG
1173: if (log_level >= 3) {
1174: dev_log(d);
1175: log_puts(": device released\n");
1176: }
1177: #endif
1178: d->refcnt--;
1179: if (d->refcnt == 0 && d->pstate == DEV_INIT)
1180: dev_close(d);
1181: }
1182:
1183: /*
1184: * initialize the device with the current parameters
1185: */
1186: int
1187: dev_init(struct dev *d)
1188: {
1189: if ((d->reqmode & MODE_AUDIOMASK) == 0) {
1190: #ifdef DEBUG
1191: dev_log(d);
1192: log_puts(": has no streams\n");
1193: #endif
1194: return 0;
1195: }
1196: if (d->hold && !dev_ref(d))
1197: return 0;
1198: return 1;
1199: }
1200:
1201: /*
1202: * Unless the device is already in process of closing, request it to close
1203: */
1204: void
1205: dev_done(struct dev *d)
1206: {
1207: #ifdef DEBUG
1208: if (log_level >= 3) {
1209: dev_log(d);
1210: log_puts(": draining\n");
1211: }
1212: #endif
1213: if (d->hold)
1214: dev_unref(d);
1215: }
1216:
1217: struct dev *
1218: dev_bynum(int num)
1219: {
1220: struct dev *d;
1221:
1222: for (d = dev_list; d != NULL; d = d->next) {
1223: if (num-- == 0)
1224: return d;
1225: }
1226: return NULL;
1227: }
1228:
1229: /*
1230: * Free the device
1231: */
1232: void
1233: dev_del(struct dev *d)
1234: {
1235: struct dev **p;
1236:
1237: #ifdef DEBUG
1238: if (log_level >= 3) {
1239: dev_log(d);
1240: log_puts(": deleting\n");
1241: }
1242: #endif
1243: if (d->pstate != DEV_CFG)
1244: dev_close(d);
1245: for (p = &dev_list; *p != d; p = &(*p)->next) {
1246: #ifdef DEBUG
1247: if (*p == NULL) {
1248: dev_log(d);
1249: log_puts(": device to delete not on the list\n");
1250: panic();
1251: }
1252: #endif
1253: }
1254: midi_del(d->midi);
1255: *p = d->next;
1256: xfree(d);
1257: }
1258:
1259: unsigned int
1260: dev_roundof(struct dev *d, unsigned int newrate)
1261: {
1262: return (d->round * newrate + d->rate / 2) / d->rate;
1263: }
1264:
1265: /*
1266: * If the device is paused, then resume it.
1267: */
1268: void
1269: dev_wakeup(struct dev *d)
1270: {
1271: if (d->pstate == DEV_INIT) {
1272: if (log_level >= 2) {
1273: dev_log(d);
1274: log_puts(": device started\n");
1275: }
1276: if (d->mode & MODE_PLAY) {
1277: d->prime = d->bufsz;
1278: } else {
1279: d->prime = 0;
1280: }
1281: d->pstate = DEV_RUN;
1282: dev_sio_start(d);
1283: }
1284: }
1285:
1286: /*
1287: * Clear buffers of the play and record chains so that when the device
1288: * is started, playback and record start in sync.
1289: */
1290: void
1291: dev_clear(struct dev *d)
1292: {
1293: d->poffs = 0;
1294: }
1295:
1296: /*
1297: * check that all clients controlled by MMC are ready to start, if so,
1298: * attach them all at the same position
1299: */
1300: void
1301: dev_sync_attach(struct dev *d)
1302: {
1303: int i;
1304: struct slot *s;
1305:
1306: if (d->tstate != MMC_START) {
1307: if (log_level >= 2) {
1308: dev_log(d);
1309: log_puts(": not started by mmc yet, waiting...\n");
1310: }
1311: return;
1312: }
1313: for (i = 0; i < DEV_NSLOT; i++) {
1314: s = d->slot + i;
1315: if (!s->ops || s->tstate == MMC_OFF)
1316: continue;
1317: if (s->tstate != MMC_START || s->pstate != SLOT_READY) {
1318: #ifdef DEBUG
1319: if (log_level >= 3) {
1320: slot_log(s);
1321: log_puts(": not ready, start delayed\n");
1322: }
1323: #endif
1324: return;
1325: }
1326: }
1327: if (!dev_ref(d))
1328: return;
1329: for (i = 0; i < DEV_NSLOT; i++) {
1330: s = d->slot + i;
1331: if (!s->ops)
1332: continue;
1333: if (s->tstate == MMC_START) {
1334: #ifdef DEBUG
1335: if (log_level >= 3) {
1336: slot_log(s);
1337: log_puts(": started\n");
1338: }
1339: #endif
1340: s->tstate = MMC_RUN;
1341: slot_attach(s);
1342: }
1343: }
1344: d->tstate = MMC_RUN;
1345: dev_midi_full(d);
1346: dev_wakeup(d);
1347: }
1348:
1349: /*
1350: * start all slots simultaneously
1351: */
1352: void
1353: dev_mmcstart(struct dev *d)
1354: {
1355: if (d->tstate == MMC_STOP) {
1356: d->tstate = MMC_START;
1357: dev_sync_attach(d);
1358: #ifdef DEBUG
1359: } else {
1360: if (log_level >= 3) {
1361: dev_log(d);
1362: log_puts(": ignoring mmc start\n");
1363: }
1364: #endif
1365: }
1366: }
1367:
1368: /*
1369: * stop all slots simultaneously
1370: */
1371: void
1372: dev_mmcstop(struct dev *d)
1373: {
1374: int i;
1375: struct slot *s;
1376:
1377: switch (d->tstate) {
1378: case MMC_START:
1379: d->tstate = MMC_STOP;
1380: return;
1381: case MMC_RUN:
1382: d->tstate = MMC_STOP;
1383: dev_unref(d);
1384: break;
1385: default:
1386: #ifdef DEBUG
1387: if (log_level >= 3) {
1388: dev_log(d);
1389: log_puts(": ignored mmc stop\n");
1390: }
1391: #endif
1392: return;
1393: }
1394: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
1395: if (!s->ops)
1396: continue;
1397: if (s->tstate == MMC_RUN) {
1398: #ifdef DEBUG
1399: if (log_level >= 3) {
1400: slot_log(s);
1401: log_puts(": requested to stop\n");
1402: }
1403: #endif
1404: s->ops->mmcstop(s->arg);
1405: }
1406: }
1407: }
1408:
1409: /*
1410: * relocate all slots simultaneously
1411: */
1412: void
1413: dev_mmcloc(struct dev *d, unsigned int origin)
1414: {
1415: int i;
1416: struct slot *s;
1417:
1418: if (log_level >= 2) {
1419: dev_log(d);
1420: log_puts(": relocated to ");
1421: log_putu(origin);
1422: log_puts("\n");
1423: }
1424: if (d->tstate == MMC_RUN)
1425: dev_mmcstop(d);
1426: d->mtc.origin = origin;
1427: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
1428: if (!s->ops)
1429: continue;
1430: s->ops->mmcloc(s->arg, d->mtc.origin);
1431: }
1432: if (d->tstate == MMC_RUN)
1433: dev_mmcstart(d);
1434: }
1435:
1436: /*
1437: * allocate a new slot and register the given call-backs
1438: */
1439: struct slot *
1440: slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode)
1441: {
1442: char *p;
1443: char name[SLOT_NAMEMAX];
1444: unsigned int i, unit, umap = 0;
1445: unsigned int ser, bestser, bestidx;
1446: struct slot *s;
1447:
1448: /*
1449: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
1450: */
1451: for (i = 0, p = who; ; p++) {
1452: if (i == SLOT_NAMEMAX - 1 || *p == '\0') {
1453: name[i] = '\0';
1454: break;
1455: } else if (*p >= 'A' && *p <= 'Z') {
1456: name[i++] = *p + 'a' - 'A';
1457: } else if (*p >= 'a' && *p <= 'z')
1458: name[i++] = *p;
1459: }
1460: if (i == 0)
1461: strlcpy(name, "noname", SLOT_NAMEMAX);
1462:
1463: /*
1464: * find the first unused "unit" number for this name
1465: */
1466: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
1467: if (s->ops == NULL)
1468: continue;
1469: if (strcmp(s->name, name) == 0)
1470: umap |= (1 << s->unit);
1471: }
1472: for (unit = 0; ; unit++) {
1473: if ((umap & (1 << unit)) == 0)
1474: break;
1475: }
1476:
1477: /*
1478: * find a xfree controller slot with the same name/unit
1479: */
1480: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
1481: if (s->ops == NULL &&
1482: strcmp(s->name, name) == 0 &&
1483: s->unit == unit) {
1484: #ifdef DEBUG
1485: if (log_level >= 3) {
1486: log_puts(name);
1487: log_putu(unit);
1488: log_puts(": reused\n");
1489: }
1490: #endif
1491: goto found;
1492: }
1493: }
1494:
1495: /*
1496: * couldn't find a matching slot, pick oldest xfree slot
1497: * and set its name/unit
1498: */
1499: bestser = 0;
1500: bestidx = DEV_NSLOT;
1501: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
1502: if (s->ops != NULL)
1503: continue;
1504: ser = d->serial - s->serial;
1505: if (ser > bestser) {
1506: bestser = ser;
1507: bestidx = i;
1508: }
1509: }
1510: if (bestidx == DEV_NSLOT) {
1511: if (log_level >= 1) {
1512: log_puts(name);
1513: log_putu(unit);
1514: log_puts(": out of sub-device slots\n");
1515: }
1516: return NULL;
1517: }
1518: s = d->slot + bestidx;
1519: if (s->name[0] != '\0')
1520: s->vol = MIDI_MAXCTL;
1521: strlcpy(s->name, name, SLOT_NAMEMAX);
1522: s->serial = d->serial++;
1523: s->unit = unit;
1524: #ifdef DEBUG
1525: if (log_level >= 3) {
1526: log_puts(name);
1527: log_putu(unit);
1528: log_puts(": overwritten slot ");
1529: log_putu(bestidx);
1530: log_puts("\n");
1531: }
1532: #endif
1533:
1534: found:
1535: if (!dev_ref(d))
1536: return NULL;
1537: s->dev = d;
1538: s->ops = ops;
1539: s->arg = arg;
1540: s->pstate = SLOT_INIT;
1541: s->tstate = MMC_OFF;
1542:
1543: if ((mode & s->dev->mode) != mode) {
1544: if (log_level >= 1) {
1545: slot_log(s);
1546: log_puts(": requested mode not supported\n");
1547: }
1548: return 0;
1549: }
1550: s->mode = mode;
1551: s->par = d->par;
1552: if (s->mode & MODE_PLAY) {
1553: s->mix.slot_cmin = 0;
1554: s->mix.slot_cmax = d->pchan - 1;
1555: }
1556: if (s->mode & MODE_RECMASK) {
1557: s->sub.slot_cmin = 0;
1558: s->sub.slot_cmax = ((s->mode & MODE_MON) ?
1559: d->pchan : d->rchan) - 1;
1560: }
1561: s->xrun = XRUN_IGNORE;
1562: s->dup = 0;
1563: s->appbufsz = d->bufsz;
1564: s->round = d->round;
1565: dev_midi_slotdesc(d, s);
1566: dev_midi_vol(d, s);
1567: return s;
1568: }
1569:
1570: /*
1571: * release the given slot
1572: */
1573: void
1574: slot_del(struct slot *s)
1575: {
1576: s->arg = s;
1577: s->ops = &zomb_slotops;
1578: switch (s->pstate) {
1579: case SLOT_INIT:
1580: s->ops = NULL;
1581: break;
1582: case SLOT_START:
1583: case SLOT_READY:
1584: case SLOT_RUN:
1585: slot_stop(s);
1586: /* PASSTHROUGH */
1587: case SLOT_STOP:
1588: break;
1589: }
1590: dev_unref(s->dev);
1591: s->dev = NULL;
1592: }
1593:
1594: /*
1595: * change the slot play volume; called either by the slot or by MIDI
1596: */
1597: void
1598: slot_setvol(struct slot *s, unsigned int vol)
1599: {
1600: #ifdef DEBUG
1601: if (log_level >= 3) {
1602: slot_log(s);
1603: log_puts(": setting volume ");
1604: log_putu(vol);
1605: log_puts("\n");
1606: }
1607: #endif
1608: s->vol = vol;
1609: if (s->ops == NULL)
1610: return;
1611: s->mix.vol = MIDI_TO_ADATA(s->vol);
1612: }
1613:
1614: /*
1615: * attach the slot to the device (ie start playing & recording
1616: */
1617: void
1618: slot_attach(struct slot *s)
1619: {
1620: struct dev *d = s->dev;
1621: unsigned int slot_nch, dev_nch;
1622: int startpos;
1623:
1624: /*
1625: * start the device if not started
1626: */
1627: dev_wakeup(d);
1628:
1629: /*
1630: * get the current position, the origin is when the first sample
1631: * played and/or recorded
1632: */
1633: startpos = dev_getpos(d) * (int)s->round / (int)d->round;
1634: s->delta = startpos;
1635: s->delta_rem = 0;
1636: s->pstate = SLOT_RUN;
1637: #ifdef DEBUG
1638: if (log_level >= 3) {
1639: slot_log(s);
1640: log_puts(": attached at ");
1641: log_puti(startpos);
1642: log_puts("\n");
1643: }
1644: #endif
1645:
1646: /*
1647: * We dont check whether the device is dying,
1648: * because dev_xxx() functions are supposed to
1649: * work (i.e., not to crash)
1650: */
1651: #ifdef DEBUG
1652: if ((s->mode & d->mode) != s->mode) {
1653: slot_log(s);
1654: log_puts(": mode beyond device mode, not attaching\n");
1655: panic();
1656: }
1657: #endif
1658: s->next = d->slot_list;
1659: d->slot_list = s;
1660: if (s->mode & MODE_PLAY) {
1661: slot_nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
1662: dev_nch = s->mix.dev_cmax - s->mix.dev_cmin + 1;
1663: s->mix.decbuf = NULL;
1664: s->mix.resampbuf = NULL;
1665: s->mix.join = 1;
1666: s->mix.expand = 1;
1667: if (s->dup) {
1668: if (dev_nch > slot_nch)
1669: s->mix.expand = dev_nch / slot_nch;
1670: else if (dev_nch < slot_nch)
1671: s->mix.join = slot_nch / dev_nch;
1672: }
1673: cmap_init(&s->mix.cmap,
1674: s->mix.slot_cmin, s->mix.slot_cmax,
1675: s->mix.slot_cmin, s->mix.slot_cmax,
1676: 0, d->pchan - 1,
1677: s->mix.dev_cmin, s->mix.dev_cmax);
1678: if (!aparams_native(&s->par)) {
1679: dec_init(&s->mix.dec, &s->par, slot_nch);
1680: s->mix.decbuf =
1681: xmalloc(d->round * slot_nch * sizeof(adata_t));
1682: }
1683: if (s->rate != d->rate) {
1684: resamp_init(&s->mix.resamp, s->round, d->round,
1685: slot_nch);
1686: s->mix.resampbuf =
1687: xmalloc(d->round * slot_nch * sizeof(adata_t));
1688: }
1689: s->mix.drop = 0;
1690: s->mix.vol = MIDI_TO_ADATA(s->vol);
1691: dev_mix_adjvol(d);
1692: }
1693: if (s->mode & MODE_RECMASK) {
1694: slot_nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
1695: dev_nch = s->sub.dev_cmax - s->sub.dev_cmin + 1;
1696: s->sub.encbuf = NULL;
1697: s->sub.resampbuf = NULL;
1698: s->sub.join = 1;
1699: s->sub.expand = 1;
1700: if (s->dup) {
1701: if (dev_nch > slot_nch)
1702: s->sub.join = dev_nch / slot_nch;
1703: else if (dev_nch < slot_nch)
1704: s->sub.expand = slot_nch / dev_nch;
1705: }
1706: cmap_init(&s->sub.cmap,
1707: 0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
1708: s->sub.dev_cmin, s->sub.dev_cmax,
1709: s->sub.slot_cmin, s->sub.slot_cmax,
1710: s->sub.slot_cmin, s->sub.slot_cmax);
1711: if (s->rate != d->rate) {
1712: resamp_init(&s->sub.resamp, d->round, s->round,
1713: slot_nch);
1714: s->sub.resampbuf =
1715: xmalloc(d->round * slot_nch * sizeof(adata_t));
1716: }
1717: if (!aparams_native(&s->par)) {
1718: enc_init(&s->sub.enc, &s->par, slot_nch);
1719: s->sub.encbuf =
1720: xmalloc(d->round * slot_nch * sizeof(adata_t));
1721: }
1722:
1723: /*
1724: * N-th recorded block is the N-th played block
1725: */
1726: s->sub.silence = startpos / (int)s->round;
1727: }
1728: }
1729:
1730: /*
1731: * if MMC is enabled, and try to attach all slots synchronously, else
1732: * simply attach the slot
1733: */
1734: void
1735: slot_ready(struct slot *s)
1736: {
1737: if (s->tstate == MMC_OFF)
1738: slot_attach(s);
1739: else {
1740: s->tstate = MMC_START;
1741: dev_sync_attach(s->dev);
1742: }
1743: }
1744:
1745: /*
1746: * setup buffers & conversion layers, prepare the slot to receive data
1747: * (for playback) or start (recording).
1748: */
1749: void
1750: slot_start(struct slot *s)
1751: {
1752: unsigned int bufsz;
1753: #ifdef DEBUG
1754: struct dev *d = s->dev;
1755:
1756:
1757: if (s->pstate != SLOT_INIT) {
1758: slot_log(s);
1759: log_puts(": slot_start: wrong state\n");
1760: panic();
1761: }
1762: #endif
1763: bufsz = s->appbufsz;
1764: if (s->mode & MODE_PLAY) {
1765: #ifdef DEBUG
1766: if (log_level >= 3) {
1767: slot_log(s);
1768: log_puts(": playing ");
1769: aparams_log(&s->par);
1770: log_puts(" -> ");
1771: aparams_log(&d->par);
1772: log_puts("\n");
1773: }
1774: #endif
1775: s->mix.bpf = s->par.bps *
1776: (s->mix.slot_cmax - s->mix.slot_cmin + 1);
1777: abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
1778: }
1779: if (s->mode & MODE_RECMASK) {
1780: #ifdef DEBUG
1781: if (log_level >= 3) {
1782: slot_log(s);
1783: log_puts(": recording ");
1784: aparams_log(&s->par);
1785: log_puts(" <- ");
1786: aparams_log(&d->par);
1787: log_puts("\n");
1788: }
1789: #endif
1790: s->sub.bpf = s->par.bps *
1791: (s->sub.slot_cmax - s->sub.slot_cmin + 1);
1792: abuf_init(&s->sub.buf, bufsz * s->sub.bpf);
1793: }
1794: s->mix.weight = MIDI_TO_ADATA(MIDI_MAXCTL);
1795: #ifdef DEBUG
1796: if (log_level >= 3) {
1797: slot_log(s);
1798: log_puts(": allocated ");
1799: log_putu(s->appbufsz);
1800: log_puts("/");
1801: log_putu(SLOT_BUFSZ(s));
1802: log_puts(" fr buffers\n");
1803: }
1804: #endif
1805: if (s->mode & MODE_PLAY) {
1806: s->pstate = SLOT_START;
1807: } else {
1808: s->pstate = SLOT_READY;
1809: slot_ready(s);
1810: }
1811: }
1812:
1813: /*
1814: * stop playback and recording, and free conversion layers
1815: */
1816: void
1817: slot_detach(struct slot *s)
1818: {
1819: struct slot **ps;
1820:
1821: #ifdef DEBUG
1822: if (log_level >= 3) {
1823: slot_log(s);
1824: log_puts(": detaching\n");
1825: }
1826: #endif
1827: for (ps = &s->dev->slot_list; *ps != s; ps = &(*ps)->next) {
1828: #ifdef DEBUG
1829: if (s == NULL) {
1830: slot_log(s);
1831: log_puts(": can't detach, not on list\n");
1832: panic();
1833: }
1834: #endif
1835: }
1836: *ps = s->next;
1837: if (s->mode & MODE_RECMASK) {
1838: if (s->sub.encbuf)
1839: xfree(s->sub.encbuf);
1840: if (s->sub.resampbuf)
1841: xfree(s->sub.resampbuf);
1842: }
1843: if (s->mode & MODE_PLAY) {
1844: if (s->mix.decbuf)
1845: xfree(s->mix.decbuf);
1846: if (s->mix.resampbuf)
1847: xfree(s->mix.resampbuf);
1848: dev_mix_adjvol(s->dev);
1849: }
1850: }
1851:
1852: /*
1853: * put the slot in stopping state (draining play buffers) or
1854: * stop & detach if no data to drain.
1855: */
1856: void
1857: slot_stop(struct slot *s)
1858: {
1859: #ifdef DEBUG
1860: if (log_level >= 3) {
1861: slot_log(s);
1862: log_puts(": stopping\n");
1863: }
1864: #endif
1865: if (s->pstate == SLOT_START) {
1866: if (s->mode & MODE_PLAY) {
1867: s->pstate = SLOT_READY;
1868: slot_ready(s);
1869: } else
1870: s->pstate = SLOT_INIT;
1871: }
1872: if (s->mode & MODE_RECMASK)
1873: abuf_done(&s->sub.buf);
1874: if (s->pstate == SLOT_READY) {
1875: #ifdef DEBUG
1876: if (log_level >= 3) {
1877: slot_log(s);
1878: log_puts(": not drained (blocked by mmc)\n");
1879: }
1880: #endif
1881: if (s->mode & MODE_PLAY)
1882: abuf_done(&s->mix.buf);
1883: s->ops->eof(s->arg);
1884: s->pstate = SLOT_INIT;
1885: } else {
1886: /* s->pstate == SLOT_RUN */
1887: if (s->mode & MODE_PLAY)
1888: s->pstate = SLOT_STOP;
1889: else {
1890: slot_detach(s);
1891: s->pstate = SLOT_INIT;
1892: s->ops->eof(s->arg);
1893: }
1894: }
1895: if (s->tstate != MMC_OFF)
1896: s->tstate = MMC_STOP;
1897: }
1898:
1899: /*
1900: * notify the slot that we just wrote in the play buffer, must be called
1901: * after each write
1902: */
1903: void
1904: slot_write(struct slot *s)
1905: {
1906: if (s->pstate == SLOT_START && s->mix.buf.used == s->mix.buf.len) {
1907: #ifdef DEBUG
1908: if (log_level >= 4) {
1909: slot_log(s);
1910: log_puts(": switching to READY state\n");
1911: }
1912: #endif
1913: s->pstate = SLOT_READY;
1914: slot_ready(s);
1915: }
1916: }
1917:
1918: /*
1919: * notify the slot that we freed some space in the rec buffer
1920: */
1921: void
1922: slot_read(struct slot *s)
1923: {
1924: /* nothing yet */
1925: }