Annotation of src/usr.bin/sndiod/dev.c, Revision 1.1
1.1 ! ratchov 1: /* $OpenBSD$ */
! 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: {
! 469: #ifdef DEBUG
! 470: struct dev *d = arg;
! 471:
! 472: dev_log(d);
! 473: log_puts(": can't receive fill input\n");
! 474: panic();
! 475: #endif
! 476: }
! 477:
! 478: void
! 479: dev_midi_exit(void *arg)
! 480: {
! 481: struct dev *d = arg;
! 482:
! 483: if (log_level >= 1) {
! 484: dev_log(d);
! 485: log_puts(": midi end point died\n");
! 486: }
! 487: if (d->pstate != DEV_CFG)
! 488: dev_close(d);
! 489: }
! 490:
! 491: void
! 492: slot_mix_drop(struct slot *s)
! 493: {
! 494: while (s->mix.drop > 0 && s->mix.buf.used >= s->round * s->mix.bpf) {
! 495: #ifdef DEBUG
! 496: if (log_level >= 4) {
! 497: slot_log(s);
! 498: log_puts(": dropped a play block\n");
! 499: }
! 500: #endif
! 501: abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
! 502: s->mix.drop--;
! 503: }
! 504: }
! 505:
! 506: void
! 507: slot_sub_sil(struct slot *s)
! 508: {
! 509: unsigned char *data;
! 510: int count;
! 511:
! 512: while (s->sub.silence > 0) {
! 513: data = abuf_wgetblk(&s->sub.buf, &count);
! 514: if (count < s->round * s->sub.bpf)
! 515: break;
! 516: #ifdef DEBUG
! 517: if (log_level >= 4) {
! 518: slot_log(s);
! 519: log_puts(": inserted a rec block of silence\n");
! 520: }
! 521: #endif
! 522: if (s->sub.encbuf)
! 523: enc_sil_do(&s->sub.enc, data, s->round);
! 524: else
! 525: memset(data, 0, s->round * s->sub.bpf);
! 526: abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf);
! 527: s->sub.silence--;
! 528: }
! 529: }
! 530:
! 531: /*
! 532: * merge play buffer contents into record buffer as if the
! 533: * play stream was recorded
! 534: */
! 535: void
! 536: dev_mon_snoop(struct dev *d)
! 537: {
! 538: }
! 539:
! 540: int
! 541: play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
! 542: {
! 543: int i, offs, vol, nch;
! 544: void *in;
! 545:
! 546: if (s->mix.resampbuf) {
! 547: todo = resamp_do(&s->mix.resamp,
! 548: res_in, s->mix.resampbuf, todo);
! 549: in = s->mix.resampbuf;
! 550: } else
! 551: in = res_in;
! 552:
! 553: nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
! 554: vol = ADATA_MUL(s->mix.weight, s->mix.vol) / s->mix.join;
! 555: cmap_add(&s->mix.cmap, in, out, vol, todo);
! 556:
! 557: offs = 0;
! 558: for (i = s->mix.join - 1; i > 0; i--) {
! 559: offs += nch;
! 560: if (offs > s->mix.cmap.inext)
! 561: break;
! 562: cmap_add(&s->mix.cmap, (adata_t *)in + offs, out, vol, todo);
! 563: }
! 564: offs = 0;
! 565: for (i = s->mix.expand - 1; i > 0; i--) {
! 566: offs += nch;
! 567: if (offs > s->mix.cmap.onext)
! 568: break;
! 569: cmap_add(&s->mix.cmap, in, (adata_t *)out + offs, vol, todo);
! 570: }
! 571: return todo;
! 572: }
! 573:
! 574: int
! 575: play_filt_dec(struct slot *s, void *in, void *out, int todo)
! 576: {
! 577: void *tmp;
! 578:
! 579: tmp = s->mix.decbuf;
! 580: if (tmp)
! 581: dec_do(&s->mix.dec, in, tmp, todo);
! 582: return play_filt_resamp(s, tmp ? tmp : in, out, todo);
! 583: }
! 584:
! 585: /*
! 586: * mix "todo" frames from the input block over the output block; if
! 587: * there are frames to drop, less frames are consumed from the input
! 588: */
! 589: void
! 590: dev_mix_badd(struct dev *d, struct slot *s)
! 591: {
! 592: adata_t *idata, *odata;
! 593: int icount;
! 594:
! 595: odata = DEV_PBUF(d);
! 596: idata = (adata_t *)abuf_rgetblk(&s->mix.buf, &icount);
! 597: #ifdef DEBUG
! 598: if (icount < s->round * s->mix.bpf) {
! 599: slot_log(s);
! 600: log_puts(": not enough data to mix (");
! 601: log_putu(icount);
! 602: log_puts("bytes)\n");
! 603: panic();
! 604: }
! 605: #endif
! 606: play_filt_dec(s, idata, odata, s->round);
! 607: abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
! 608: }
! 609:
! 610: void
! 611: dev_empty_cycle(struct dev *d)
! 612: {
! 613: unsigned char *base;
! 614: int nsamp;
! 615:
! 616: base = (unsigned char *)DEV_PBUF(d);
! 617: nsamp = d->round * d->pchan;
! 618: memset(base, 0, nsamp * sizeof(adata_t));
! 619: if (d->encbuf) {
! 620: enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
! 621: d->encbuf, d->round);
! 622: }
! 623: }
! 624:
! 625: /*
! 626: * Normalize input levels.
! 627: */
! 628: void
! 629: dev_mix_adjvol(struct dev *d)
! 630: {
! 631: unsigned int n;
! 632: struct slot *i, *j;
! 633: int weight;
! 634:
! 635: for (i = d->slot_list; i != NULL; i = i->next) {
! 636: if (!(i->mode & MODE_PLAY))
! 637: continue;
! 638: weight = ADATA_UNIT;
! 639: if (d->autovol) {
! 640: /*
! 641: * count the number of inputs that have
! 642: * overlapping channel sets
! 643: */
! 644: n = 0;
! 645: for (j = d->slot_list; j != NULL; j = j->next) {
! 646: if (!(j->mode & MODE_PLAY))
! 647: continue;
! 648: if (i->mix.slot_cmin <= j->mix.slot_cmax &&
! 649: i->mix.slot_cmax >= j->mix.slot_cmin)
! 650: n++;
! 651: }
! 652: weight /= n;
! 653: }
! 654: if (weight > i->mix.maxweight)
! 655: weight = i->mix.maxweight;
! 656: i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master));
! 657: #ifdef DEBUG
! 658: if (log_level >= 3) {
! 659: slot_log(i);
! 660: log_puts(": set weight: ");
! 661: log_puti(i->mix.weight);
! 662: log_puts("/");
! 663: log_puti(i->mix.maxweight);
! 664: log_puts("\n");
! 665: }
! 666: #endif
! 667: }
! 668: }
! 669:
! 670: void
! 671: dev_mix_cycle(struct dev *d)
! 672: {
! 673: struct slot *s, **ps;
! 674: unsigned char *base;
! 675: int nsamp;
! 676:
! 677: #ifdef DEBUG
! 678: if (log_level >= 4) {
! 679: dev_log(d);
! 680: log_puts(": dev_mix_cycle, poffs = ");
! 681: log_puti(d->poffs);
! 682: log_puts("\n");
! 683: }
! 684: #endif
! 685: base = (unsigned char *)DEV_PBUF(d);
! 686: nsamp = d->round * d->pchan;
! 687: memset(base, 0, nsamp * sizeof(adata_t));
! 688: ps = &d->slot_list;
! 689: while ((s = *ps) != NULL) {
! 690: if (!(s->mode & MODE_PLAY)) {
! 691: ps = &s->next;
! 692: continue;
! 693: }
! 694: #ifdef DEBUG
! 695: if (log_level >= 4) {
! 696: slot_log(s);
! 697: log_puts(": mixing, drop = ");
! 698: log_puti(s->mix.drop);
! 699: log_puts(" cycles\n");
! 700: }
! 701: #endif
! 702: slot_mix_drop(s);
! 703: if (s->mix.drop < 0) {
! 704: s->mix.drop++;
! 705: ps = &s->next;
! 706: continue;
! 707: }
! 708: if (s->mix.buf.used < s->round * s->mix.bpf &&
! 709: s->pstate == SLOT_STOP) {
! 710: /*
! 711: * partial blocks are zero-filled by socket
! 712: * layer
! 713: */
! 714: s->pstate = SLOT_INIT;
! 715: abuf_done(&s->mix.buf);
! 716: if (s->mix.decbuf)
! 717: xfree(s->mix.decbuf);
! 718: if (s->mix.resampbuf)
! 719: xfree(s->mix.resampbuf);
! 720: s->ops->eof(s->arg);
! 721: *ps = s->next;
! 722: dev_mix_adjvol(d);
! 723: continue;
! 724: }
! 725: if (s->mix.buf.used < s->round * s->mix.bpf &&
! 726: !(s->pstate == SLOT_STOP)) {
! 727: if (s->xrun == XRUN_IGNORE) {
! 728: if (s->mode & MODE_RECMASK)
! 729: s->sub.silence--;
! 730: s->delta -= s->round;
! 731: #ifdef DEBUG
! 732: if (log_level >= 3) {
! 733: slot_log(s);
! 734: log_puts(": underrun, pause cycle\n");
! 735: }
! 736: #endif
! 737: ps = &s->next;
! 738: continue;
! 739: }
! 740: if (s->xrun == XRUN_SYNC) {
! 741: s->mix.drop++;
! 742: ps = &s->next;
! 743: continue;
! 744: }
! 745: if (s->xrun == XRUN_ERROR) {
! 746: s->ops->exit(s->arg);
! 747: *ps = s->next;
! 748: continue;
! 749: }
! 750: } else {
! 751: dev_mix_badd(d, s);
! 752: if (s->pstate != SLOT_STOP)
! 753: s->ops->fill(s->arg);
! 754: }
! 755: ps = &s->next;
! 756: }
! 757: if (d->encbuf) {
! 758: enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
! 759: d->encbuf, d->round);
! 760: }
! 761: }
! 762:
! 763: int
! 764: rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
! 765: {
! 766: int i, vol, offs, nch;
! 767: void *out = res_out;
! 768:
! 769: out = (s->sub.resampbuf) ? s->sub.resampbuf : res_out;
! 770:
! 771: nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
! 772: vol = ADATA_UNIT / s->sub.join;
! 773: cmap_copy(&s->sub.cmap, in, out, vol, todo);
! 774:
! 775: offs = 0;
! 776: for (i = s->sub.join - 1; i > 0; i--) {
! 777: offs += nch;
! 778: cmap_add(&s->sub.cmap, (adata_t *)in + offs, out, vol, todo);
! 779: }
! 780: offs = 0;
! 781: for (i = s->sub.expand - 1; i > 0; i--) {
! 782: offs += nch;
! 783: cmap_copy(&s->sub.cmap, in, (adata_t *)out + offs, vol, todo);
! 784: }
! 785: if (s->sub.resampbuf) {
! 786: todo = resamp_do(&s->sub.resamp,
! 787: s->sub.resampbuf, res_out, todo);
! 788: }
! 789: return todo;
! 790: }
! 791:
! 792: int
! 793: rec_filt_enc(struct slot *s, void *in, void *out, int todo)
! 794: {
! 795: void *tmp;
! 796:
! 797: tmp = s->sub.encbuf;
! 798: todo = rec_filt_resamp(s, in, tmp ? tmp : out, todo);
! 799: if (tmp)
! 800: enc_do(&s->sub.enc, tmp, out, todo);
! 801: return todo;
! 802: }
! 803:
! 804: /*
! 805: * Copy data from slot to device
! 806: */
! 807: void
! 808: dev_sub_bcopy(struct dev *d, struct slot *s)
! 809: {
! 810: adata_t *idata, *odata;
! 811: int ocount;
! 812:
! 813: idata = (s->mode & MODE_MON) ? DEV_PBUF(d) : d->rbuf;
! 814: odata = (adata_t *)abuf_wgetblk(&s->sub.buf, &ocount);
! 815: #ifdef DEBUG
! 816: if (ocount < s->round * s->sub.bpf) {
! 817: log_puts("dev_sub_bcopy: not enough space\n");
! 818: panic();
! 819: }
! 820: #endif
! 821: ocount = rec_filt_enc(s, idata, odata, d->round);
! 822: abuf_wcommit(&s->sub.buf, ocount * s->sub.bpf);
! 823: }
! 824:
! 825: void
! 826: dev_sub_cycle(struct dev *d)
! 827: {
! 828: struct slot *s, **ps;
! 829:
! 830: #ifdef DEBUG
! 831: if (log_level >= 4) {
! 832: dev_log(d);
! 833: log_puts(": dev_sub_cycle\n");
! 834: }
! 835: #endif
! 836: if ((d->mode & MODE_REC) && d->decbuf)
! 837: dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round);
! 838: ps = &d->slot_list;
! 839: while ((s = *ps) != NULL) {
! 840: if (!(s->mode & MODE_RECMASK) || s->pstate == SLOT_STOP) {
! 841: ps = &s->next;
! 842: continue;
! 843: }
! 844: slot_sub_sil(s);
! 845: if (s->sub.silence < 0) {
! 846: s->sub.silence++;
! 847: ps = &s->next;
! 848: continue;
! 849: }
! 850: if (s->sub.buf.len - s->sub.buf.used < s->round * s->sub.bpf) {
! 851: if (s->xrun == XRUN_IGNORE) {
! 852: if (s->mode & MODE_PLAY)
! 853: s->mix.drop--;
! 854: s->delta -= s->round;
! 855: #ifdef DEBUG
! 856: if (log_level >= 3) {
! 857: slot_log(s);
! 858: log_puts(": overrun, pause cycle\n");
! 859: }
! 860: #endif
! 861: ps = &s->next;
! 862: continue;
! 863: }
! 864: if (s->xrun == XRUN_SYNC) {
! 865: s->sub.silence++;
! 866: ps = &s->next;
! 867: continue;
! 868: }
! 869: if (s->xrun == XRUN_ERROR) {
! 870: s->ops->exit(s->arg);
! 871: *ps = s->next;
! 872: continue;
! 873: }
! 874: } else {
! 875: dev_sub_bcopy(d, s);
! 876: s->ops->flush(s->arg);
! 877: }
! 878: ps = &s->next;
! 879: }
! 880: }
! 881:
! 882: /*
! 883: * called at every clock tick by the device
! 884: */
! 885: void
! 886: dev_onmove(struct dev *d, int delta)
! 887: {
! 888: long long pos;
! 889: struct slot *s, *snext;
! 890:
! 891: /*
! 892: * s->ops->onmove() may remove the slot
! 893: */
! 894: for (s = d->slot_list; s != NULL; s = snext) {
! 895: snext = s->next;
! 896: pos = (long long)delta * s->round + s->delta_rem;
! 897: s->delta_rem = pos % d->round;
! 898: s->delta += pos / (int)d->round;
! 899: if (s->delta >= 0)
! 900: s->ops->onmove(s->arg, delta);
! 901: }
! 902: if (d->tstate == MMC_RUN)
! 903: dev_midi_qfr(d, delta);
! 904: }
! 905:
! 906: void
! 907: dev_master(struct dev *d, unsigned int master)
! 908: {
! 909: if (log_level >= 2) {
! 910: dev_log(d);
! 911: log_puts(": master volume set to ");
! 912: log_putu(master);
! 913: log_puts("\n");
! 914: }
! 915: d->master = master;
! 916: if (d->mode & MODE_PLAY)
! 917: dev_mix_adjvol(d);
! 918: }
! 919:
! 920: void
! 921: dev_cycle(struct dev *d)
! 922: {
! 923: if (d->slot_list == NULL && d->tstate != MMC_RUN) {
! 924: if (log_level >= 2) {
! 925: dev_log(d);
! 926: log_puts(": device stopped\n");
! 927: }
! 928: dev_sio_stop(d);
! 929: d->pstate = DEV_INIT;
! 930: if (d->refcnt == 0)
! 931: dev_close(d);
! 932: else
! 933: dev_clear(d);
! 934: return;
! 935: }
! 936: #ifdef DEBUG
! 937: if (log_level >= 4) {
! 938: dev_log(d);
! 939: log_puts(": device cycle, prime = ");
! 940: log_putu(d->prime);
! 941: log_puts("\n");
! 942: }
! 943: #endif
! 944: if (d->prime > 0) {
! 945: d->prime -= d->round;
! 946: dev_empty_cycle(d);
! 947: } else {
! 948: if (d->mode & MODE_RECMASK)
! 949: dev_sub_cycle(d);
! 950: if (d->mode & MODE_PLAY)
! 951: dev_mix_cycle(d);
! 952: }
! 953: }
! 954:
! 955: /*
! 956: * return the latency that a stream would have if it's attached
! 957: */
! 958: int
! 959: dev_getpos(struct dev *d)
! 960: {
! 961: return (d->mode & MODE_PLAY) ? -d->bufsz : 0;
! 962: }
! 963:
! 964: /*
! 965: * Create a sndio device
! 966: */
! 967: struct dev *
! 968: dev_new(char *path, struct aparams *par,
! 969: unsigned int mode, unsigned int bufsz, unsigned int round,
! 970: unsigned int rate, unsigned int hold, unsigned int autovol)
! 971: {
! 972: struct dev *d;
! 973: unsigned int i;
! 974:
! 975: if (dev_sndnum == DEV_NMAX) {
! 976: if (log_level >= 1)
! 977: log_puts("too many devices\n");
! 978: return NULL;
! 979: }
! 980: d = xmalloc(sizeof(struct dev));
! 981: d->num = dev_sndnum++;
! 982:
! 983: /*
! 984: * XXX: below, we allocate a midi input buffer, since we don't
! 985: * receive raw midi data, so no need to allocate a input
! 986: * ibuf. Possibly set imsg & fill callbacks to NULL and
! 987: * use this to in midi_new() to check if buffers need to be
! 988: * allocated
! 989: */
! 990: d->midi = midi_new(&dev_midiops, d, MODE_MIDIIN | MODE_MIDIOUT);
! 991: midi_tag(d->midi, d->num);
! 992: d->path = path;
! 993: d->reqpar = *par;
! 994: d->reqmode = mode;
! 995: d->reqpchan = d->reqrchan = 0;
! 996: d->reqbufsz = bufsz;
! 997: d->reqround = round;
! 998: d->reqrate = rate;
! 999: d->hold = hold;
! 1000: d->autovol = autovol;
! 1001: d->autostart = 0;
! 1002: d->refcnt = 0;
! 1003: d->pstate = DEV_CFG;
! 1004: d->serial = 0;
! 1005: for (i = 0; i < DEV_NSLOT; i++) {
! 1006: d->slot[i].unit = i;
! 1007: d->slot[i].ops = NULL;
! 1008: d->slot[i].vol = MIDI_MAXCTL;
! 1009: d->slot[i].tstate = MMC_OFF;
! 1010: d->slot[i].serial = d->serial++;
! 1011: d->slot[i].name[0] = '\0';
! 1012: }
! 1013: d->slot_list = NULL;
! 1014: d->master = MIDI_MAXCTL;
! 1015: d->mtc.origin = 0;
! 1016: d->tstate = MMC_STOP;
! 1017: d->next = dev_list;
! 1018: dev_list = d;
! 1019: return d;
! 1020: }
! 1021:
! 1022: /*
! 1023: * adjust device parameters and mode
! 1024: */
! 1025: void
! 1026: dev_adjpar(struct dev *d, int mode,
! 1027: int pmin, int pmax, int rmin, int rmax)
! 1028: {
! 1029: d->reqmode |= mode & MODE_AUDIOMASK;
! 1030: if (mode & MODE_PLAY) {
! 1031: if (d->reqpchan < pmax + 1)
! 1032: d->reqpchan = pmax + 1;
! 1033: }
! 1034: if (mode & MODE_REC) {
! 1035: if (d->reqrchan < rmax + 1)
! 1036: d->reqrchan = rmax + 1;
! 1037: }
! 1038: }
! 1039:
! 1040: /*
! 1041: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
! 1042: * monitor, midi control, and any necessary conversions.
! 1043: */
! 1044: int
! 1045: dev_open(struct dev *d)
! 1046: {
! 1047: d->mode = d->reqmode;
! 1048: d->round = d->reqround;
! 1049: d->bufsz = d->reqbufsz;
! 1050: d->rate = d->reqrate;
! 1051: d->pchan = d->reqpchan;
! 1052: d->rchan = d->reqrchan;
! 1053: d->par = d->reqpar;
! 1054: if (d->pchan == 0)
! 1055: d->pchan = 2;
! 1056: if (d->rchan == 0)
! 1057: d->rchan = 2;
! 1058: if (!dev_sio_open(d)) {
! 1059: if (log_level >= 1) {
! 1060: dev_log(d);
! 1061: log_puts(": ");
! 1062: log_puts(d->path);
! 1063: log_puts(": failed to open audio device\n");
! 1064: }
! 1065: return 0;
! 1066: }
! 1067: if (d->mode & MODE_REC) {
! 1068: /*
! 1069: * Create device <-> demuxer buffer
! 1070: */
! 1071: d->rbuf = xmalloc(d->round * d->rchan * sizeof(adata_t));
! 1072:
! 1073: /*
! 1074: * Insert a converter, if needed.
! 1075: */
! 1076: if (!aparams_native(&d->par)) {
! 1077: dec_init(&d->dec, &d->par, d->rchan);
! 1078: d->decbuf = xmalloc(d->round * d->rchan * d->par.bps);
! 1079: } else
! 1080: d->decbuf = NULL;
! 1081: }
! 1082: if (d->mode & MODE_PLAY) {
! 1083: /*
! 1084: * Create device <-> mixer buffer
! 1085: */
! 1086: d->pbuf = xmalloc(d->bufsz * d->pchan * sizeof(adata_t));
! 1087: d->poffs = 0;
! 1088: d->mode |= MODE_MON;
! 1089:
! 1090: /*
! 1091: * Append a converter, if needed.
! 1092: */
! 1093: if (!aparams_native(&d->par)) {
! 1094: enc_init(&d->enc, &d->par, d->pchan);
! 1095: d->encbuf = xmalloc(d->round * d->pchan * d->par.bps);
! 1096: } else
! 1097: d->encbuf = NULL;
! 1098: }
! 1099: d->pstate = DEV_INIT;
! 1100: if (log_level >= 2) {
! 1101: dev_log(d);
! 1102: log_puts(": ");
! 1103: log_putu(d->rate);
! 1104: log_puts("Hz, ");
! 1105: aparams_log(&d->par);
! 1106: if (d->mode & MODE_PLAY) {
! 1107: log_puts(", play 0:");
! 1108: log_puti(d->pchan - 1);
! 1109: }
! 1110: if (d->mode & MODE_REC) {
! 1111: log_puts(", rec 0:");
! 1112: log_puti(d->rchan - 1);
! 1113: }
! 1114: log_puts(", ");
! 1115: log_putu(d->bufsz / d->round);
! 1116: log_puts(" blocks of ");
! 1117: log_putu(d->round);
! 1118: log_puts(" frames\n");
! 1119: }
! 1120: return 1;
! 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_close(struct dev *d)
! 1129: {
! 1130: struct slot *s, *snext;
! 1131:
! 1132: #ifdef DEBUG
! 1133: if (log_level >= 3) {
! 1134: dev_log(d);
! 1135: log_puts(": closing\n");
! 1136: }
! 1137: #endif
! 1138: while ((s = d->slot_list) != NULL) {
! 1139: snext = s->next;
! 1140: if (s->ops)
! 1141: s->ops->exit(s->arg);
! 1142: s->ops = NULL;
! 1143: d->slot_list = snext;
! 1144: }
! 1145: dev_sio_close(d);
! 1146: if (d->mode & MODE_PLAY) {
! 1147: if (d->encbuf != NULL)
! 1148: xfree(d->encbuf);
! 1149: xfree(d->pbuf);
! 1150: }
! 1151: if (d->mode & MODE_REC) {
! 1152: if (d->decbuf != NULL)
! 1153: xfree(d->decbuf);
! 1154: xfree(d->rbuf);
! 1155: }
! 1156: dev_clear(d);
! 1157: d->pstate = DEV_CFG;
! 1158: }
! 1159:
! 1160: int
! 1161: dev_ref(struct dev *d)
! 1162: {
! 1163: #ifdef DEBUG
! 1164: if (log_level >= 3) {
! 1165: dev_log(d);
! 1166: log_puts(": device requested\n");
! 1167: }
! 1168: #endif
! 1169: if (d->pstate == DEV_CFG && !dev_open(d))
! 1170: return 0;
! 1171: d->refcnt++;
! 1172: return 1;
! 1173: }
! 1174:
! 1175: void
! 1176: dev_unref(struct dev *d)
! 1177: {
! 1178: #ifdef DEBUG
! 1179: if (log_level >= 3) {
! 1180: dev_log(d);
! 1181: log_puts(": device released\n");
! 1182: }
! 1183: #endif
! 1184: d->refcnt--;
! 1185: if (d->refcnt == 0 && d->pstate == DEV_INIT)
! 1186: dev_close(d);
! 1187: }
! 1188:
! 1189: /*
! 1190: * initialize the device with the current parameters
! 1191: */
! 1192: int
! 1193: dev_init(struct dev *d)
! 1194: {
! 1195: if ((d->reqmode & MODE_AUDIOMASK) == 0) {
! 1196: #ifdef DEBUG
! 1197: dev_log(d);
! 1198: log_puts(": has no streams\n");
! 1199: #endif
! 1200: return 0;
! 1201: }
! 1202: if (d->hold && !dev_ref(d))
! 1203: return 0;
! 1204: return 1;
! 1205: }
! 1206:
! 1207: /*
! 1208: * Unless the device is already in process of closing, request it to close
! 1209: */
! 1210: void
! 1211: dev_done(struct dev *d)
! 1212: {
! 1213: #ifdef DEBUG
! 1214: if (log_level >= 3) {
! 1215: dev_log(d);
! 1216: log_puts(": draining\n");
! 1217: }
! 1218: #endif
! 1219: if (d->hold)
! 1220: dev_unref(d);
! 1221: }
! 1222:
! 1223: struct dev *
! 1224: dev_bynum(int num)
! 1225: {
! 1226: struct dev *d;
! 1227:
! 1228: for (d = dev_list; d != NULL; d = d->next) {
! 1229: if (num-- == 0)
! 1230: return d;
! 1231: }
! 1232: return NULL;
! 1233: }
! 1234:
! 1235: /*
! 1236: * Free the device
! 1237: */
! 1238: void
! 1239: dev_del(struct dev *d)
! 1240: {
! 1241: struct dev **p;
! 1242:
! 1243: #ifdef DEBUG
! 1244: if (log_level >= 3) {
! 1245: dev_log(d);
! 1246: log_puts(": deleting\n");
! 1247: }
! 1248: #endif
! 1249: if (d->pstate != DEV_CFG)
! 1250: dev_close(d);
! 1251: for (p = &dev_list; *p != d; p = &(*p)->next) {
! 1252: #ifdef DEBUG
! 1253: if (*p == NULL) {
! 1254: dev_log(d);
! 1255: log_puts(": device to delete not on the list\n");
! 1256: panic();
! 1257: }
! 1258: #endif
! 1259: }
! 1260: midi_del(d->midi);
! 1261: *p = d->next;
! 1262: xfree(d);
! 1263: }
! 1264:
! 1265: unsigned int
! 1266: dev_roundof(struct dev *d, unsigned int newrate)
! 1267: {
! 1268: return (d->round * newrate + d->rate / 2) / d->rate;
! 1269: }
! 1270:
! 1271: /*
! 1272: * If the device is paused, then resume it.
! 1273: */
! 1274: void
! 1275: dev_wakeup(struct dev *d)
! 1276: {
! 1277: if (d->pstate == DEV_INIT) {
! 1278: if (log_level >= 2) {
! 1279: dev_log(d);
! 1280: log_puts(": device started\n");
! 1281: }
! 1282: if (d->mode & MODE_PLAY) {
! 1283: d->prime = d->bufsz;
! 1284: } else {
! 1285: d->prime = 0;
! 1286: }
! 1287: d->pstate = DEV_RUN;
! 1288: dev_sio_start(d);
! 1289: }
! 1290: }
! 1291:
! 1292: /*
! 1293: * Clear buffers of the play and record chains so that when the device
! 1294: * is started, playback and record start in sync.
! 1295: */
! 1296: void
! 1297: dev_clear(struct dev *d)
! 1298: {
! 1299: d->poffs = 0;
! 1300: }
! 1301:
! 1302: /*
! 1303: * check that all clients controlled by MMC are ready to start, if so,
! 1304: * attach them all at the same position
! 1305: */
! 1306: void
! 1307: dev_sync_attach(struct dev *d)
! 1308: {
! 1309: int i;
! 1310: struct slot *s;
! 1311:
! 1312: if (d->tstate != MMC_START) {
! 1313: if (log_level >= 2) {
! 1314: dev_log(d);
! 1315: log_puts(": not started by mmc yet, waiting...\n");
! 1316: }
! 1317: return;
! 1318: }
! 1319: for (i = 0; i < DEV_NSLOT; i++) {
! 1320: s = d->slot + i;
! 1321: if (!s->ops || s->tstate == MMC_OFF)
! 1322: continue;
! 1323: if (s->tstate != MMC_START || s->pstate != SLOT_READY) {
! 1324: #ifdef DEBUG
! 1325: if (log_level >= 3) {
! 1326: slot_log(s);
! 1327: log_puts(": not ready, start delayed\n");
! 1328: }
! 1329: #endif
! 1330: return;
! 1331: }
! 1332: }
! 1333: if (!dev_ref(d))
! 1334: return;
! 1335: for (i = 0; i < DEV_NSLOT; i++) {
! 1336: s = d->slot + i;
! 1337: if (!s->ops)
! 1338: continue;
! 1339: if (s->tstate == MMC_START) {
! 1340: #ifdef DEBUG
! 1341: if (log_level >= 3) {
! 1342: slot_log(s);
! 1343: log_puts(": started\n");
! 1344: }
! 1345: #endif
! 1346: s->tstate = MMC_RUN;
! 1347: slot_attach(s);
! 1348: }
! 1349: }
! 1350: d->tstate = MMC_RUN;
! 1351: dev_midi_full(d);
! 1352: dev_wakeup(d);
! 1353: }
! 1354:
! 1355: /*
! 1356: * start all slots simultaneously
! 1357: */
! 1358: void
! 1359: dev_mmcstart(struct dev *d)
! 1360: {
! 1361: if (d->tstate == MMC_STOP) {
! 1362: d->tstate = MMC_START;
! 1363: dev_sync_attach(d);
! 1364: #ifdef DEBUG
! 1365: } else {
! 1366: if (log_level >= 3) {
! 1367: dev_log(d);
! 1368: log_puts(": ignoring mmc start\n");
! 1369: }
! 1370: #endif
! 1371: }
! 1372: }
! 1373:
! 1374: /*
! 1375: * stop all slots simultaneously
! 1376: */
! 1377: void
! 1378: dev_mmcstop(struct dev *d)
! 1379: {
! 1380: int i;
! 1381: struct slot *s;
! 1382:
! 1383: switch (d->tstate) {
! 1384: case MMC_START:
! 1385: d->tstate = MMC_STOP;
! 1386: return;
! 1387: case MMC_RUN:
! 1388: d->tstate = MMC_STOP;
! 1389: dev_unref(d);
! 1390: break;
! 1391: default:
! 1392: #ifdef DEBUG
! 1393: if (log_level >= 3) {
! 1394: dev_log(d);
! 1395: log_puts(": ignored mmc stop\n");
! 1396: }
! 1397: #endif
! 1398: return;
! 1399: }
! 1400: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
! 1401: if (!s->ops)
! 1402: continue;
! 1403: if (s->tstate == MMC_RUN) {
! 1404: #ifdef DEBUG
! 1405: if (log_level >= 3) {
! 1406: slot_log(s);
! 1407: log_puts(": requested to stop\n");
! 1408: }
! 1409: #endif
! 1410: s->ops->mmcstop(s->arg);
! 1411: }
! 1412: }
! 1413: }
! 1414:
! 1415: /*
! 1416: * relocate all slots simultaneously
! 1417: */
! 1418: void
! 1419: dev_mmcloc(struct dev *d, unsigned int origin)
! 1420: {
! 1421: int i;
! 1422: struct slot *s;
! 1423:
! 1424: if (log_level >= 2) {
! 1425: dev_log(d);
! 1426: log_puts(": relocated to ");
! 1427: log_putu(origin);
! 1428: log_puts("\n");
! 1429: }
! 1430: if (d->tstate == MMC_RUN)
! 1431: dev_mmcstop(d);
! 1432: d->mtc.origin = origin;
! 1433: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
! 1434: if (!s->ops)
! 1435: continue;
! 1436: s->ops->mmcloc(s->arg, d->mtc.origin);
! 1437: }
! 1438: if (d->tstate == MMC_RUN)
! 1439: dev_mmcstart(d);
! 1440: }
! 1441:
! 1442: /*
! 1443: * allocate a new slot and register the given call-backs
! 1444: */
! 1445: struct slot *
! 1446: slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode)
! 1447: {
! 1448: char *p;
! 1449: char name[SLOT_NAMEMAX];
! 1450: unsigned int i, unit, umap = 0;
! 1451: unsigned int ser, bestser, bestidx;
! 1452: struct slot *s;
! 1453:
! 1454: /*
! 1455: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
! 1456: */
! 1457: for (i = 0, p = who; ; p++) {
! 1458: if (i == SLOT_NAMEMAX - 1 || *p == '\0') {
! 1459: name[i] = '\0';
! 1460: break;
! 1461: } else if (*p >= 'A' && *p <= 'Z') {
! 1462: name[i++] = *p + 'a' - 'A';
! 1463: } else if (*p >= 'a' && *p <= 'z')
! 1464: name[i++] = *p;
! 1465: }
! 1466: if (i == 0)
! 1467: strlcpy(name, "noname", SLOT_NAMEMAX);
! 1468:
! 1469: /*
! 1470: * find the first unused "unit" number for this name
! 1471: */
! 1472: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
! 1473: if (s->ops == NULL)
! 1474: continue;
! 1475: if (strcmp(s->name, name) == 0)
! 1476: umap |= (1 << s->unit);
! 1477: }
! 1478: for (unit = 0; ; unit++) {
! 1479: if ((umap & (1 << unit)) == 0)
! 1480: break;
! 1481: }
! 1482:
! 1483: /*
! 1484: * find a xfree controller slot with the same name/unit
! 1485: */
! 1486: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
! 1487: if (s->ops == NULL &&
! 1488: strcmp(s->name, name) == 0 &&
! 1489: s->unit == unit) {
! 1490: #ifdef DEBUG
! 1491: if (log_level >= 3) {
! 1492: log_puts(name);
! 1493: log_putu(unit);
! 1494: log_puts(": reused\n");
! 1495: }
! 1496: #endif
! 1497: goto found;
! 1498: }
! 1499: }
! 1500:
! 1501: /*
! 1502: * couldn't find a matching slot, pick oldest xfree slot
! 1503: * and set its name/unit
! 1504: */
! 1505: bestser = 0;
! 1506: bestidx = DEV_NSLOT;
! 1507: for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
! 1508: if (s->ops != NULL)
! 1509: continue;
! 1510: ser = d->serial - s->serial;
! 1511: if (ser > bestser) {
! 1512: bestser = ser;
! 1513: bestidx = i;
! 1514: }
! 1515: }
! 1516: if (bestidx == DEV_NSLOT) {
! 1517: if (log_level >= 1) {
! 1518: log_puts(name);
! 1519: log_putu(unit);
! 1520: log_puts(": out of sub-device slots\n");
! 1521: }
! 1522: return NULL;
! 1523: }
! 1524: s = d->slot + bestidx;
! 1525: if (s->name[0] != '\0')
! 1526: s->vol = MIDI_MAXCTL;
! 1527: strlcpy(s->name, name, SLOT_NAMEMAX);
! 1528: s->serial = d->serial++;
! 1529: s->unit = unit;
! 1530: #ifdef DEBUG
! 1531: if (log_level >= 3) {
! 1532: log_puts(name);
! 1533: log_putu(unit);
! 1534: log_puts(": overwritten slot ");
! 1535: log_putu(bestidx);
! 1536: log_puts("\n");
! 1537: }
! 1538: #endif
! 1539:
! 1540: found:
! 1541: if (!dev_ref(d))
! 1542: return NULL;
! 1543: s->dev = d;
! 1544: s->ops = ops;
! 1545: s->arg = arg;
! 1546: s->pstate = SLOT_INIT;
! 1547: s->tstate = MMC_OFF;
! 1548:
! 1549: if ((mode & s->dev->mode) != mode) {
! 1550: if (log_level >= 1) {
! 1551: slot_log(s);
! 1552: log_puts(": requested mode not supported\n");
! 1553: }
! 1554: return 0;
! 1555: }
! 1556: s->mode = mode;
! 1557: s->par = d->par;
! 1558: if (s->mode & MODE_PLAY) {
! 1559: s->mix.slot_cmin = 0;
! 1560: s->mix.slot_cmax = d->pchan - 1;
! 1561: }
! 1562: if (s->mode & MODE_RECMASK) {
! 1563: s->sub.slot_cmin = 0;
! 1564: s->sub.slot_cmax = ((s->mode & MODE_MON) ?
! 1565: d->pchan : d->rchan) - 1;
! 1566: }
! 1567: s->xrun = XRUN_IGNORE;
! 1568: s->dup = 0;
! 1569: s->appbufsz = d->bufsz;
! 1570: s->round = d->round;
! 1571: dev_midi_slotdesc(d, s);
! 1572: dev_midi_vol(d, s);
! 1573: return s;
! 1574: }
! 1575:
! 1576: /*
! 1577: * release the given slot
! 1578: */
! 1579: void
! 1580: slot_del(struct slot *s)
! 1581: {
! 1582: s->arg = s;
! 1583: s->ops = &zomb_slotops;
! 1584: switch (s->pstate) {
! 1585: case SLOT_INIT:
! 1586: s->ops = NULL;
! 1587: break;
! 1588: case SLOT_START:
! 1589: case SLOT_READY:
! 1590: case SLOT_RUN:
! 1591: slot_stop(s);
! 1592: /* PASSTHROUGH */
! 1593: case SLOT_STOP:
! 1594: break;
! 1595: }
! 1596: dev_unref(s->dev);
! 1597: s->dev = NULL;
! 1598: }
! 1599:
! 1600: /*
! 1601: * change the slot play volume; called either by the slot or by MIDI
! 1602: */
! 1603: void
! 1604: slot_setvol(struct slot *s, unsigned int vol)
! 1605: {
! 1606: #ifdef DEBUG
! 1607: if (log_level >= 3) {
! 1608: slot_log(s);
! 1609: log_puts(": setting volume ");
! 1610: log_putu(vol);
! 1611: log_puts("\n");
! 1612: }
! 1613: #endif
! 1614: s->vol = vol;
! 1615: if (s->ops == NULL)
! 1616: return;
! 1617: s->mix.vol = MIDI_TO_ADATA(s->vol);
! 1618: }
! 1619:
! 1620: /*
! 1621: * attach the slot to the device (ie start playing & recording
! 1622: */
! 1623: void
! 1624: slot_attach(struct slot *s)
! 1625: {
! 1626: struct dev *d = s->dev;
! 1627: unsigned int slot_nch, dev_nch;
! 1628: int startpos;
! 1629:
! 1630: /*
! 1631: * start the device if not started
! 1632: */
! 1633: dev_wakeup(d);
! 1634:
! 1635: /*
! 1636: * get the current position, the origin is when the first sample
! 1637: * played and/or recorded
! 1638: */
! 1639: startpos = dev_getpos(d) * (int)s->round / (int)d->round;
! 1640: s->delta = startpos;
! 1641: s->delta_rem = 0;
! 1642: s->pstate = SLOT_RUN;
! 1643: #ifdef DEBUG
! 1644: if (log_level >= 3) {
! 1645: slot_log(s);
! 1646: log_puts(": attached at ");
! 1647: log_puti(startpos);
! 1648: log_puts("\n");
! 1649: }
! 1650: #endif
! 1651:
! 1652: /*
! 1653: * We dont check whether the device is dying,
! 1654: * because dev_xxx() functions are supposed to
! 1655: * work (i.e., not to crash)
! 1656: */
! 1657: #ifdef DEBUG
! 1658: if ((s->mode & d->mode) != s->mode) {
! 1659: slot_log(s);
! 1660: log_puts(": mode beyond device mode, not attaching\n");
! 1661: panic();
! 1662: }
! 1663: #endif
! 1664: s->next = d->slot_list;
! 1665: d->slot_list = s;
! 1666: if (s->mode & MODE_PLAY) {
! 1667: slot_nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
! 1668: dev_nch = s->mix.dev_cmax - s->mix.dev_cmin + 1;
! 1669: s->mix.decbuf = NULL;
! 1670: s->mix.resampbuf = NULL;
! 1671: s->mix.join = 1;
! 1672: s->mix.expand = 1;
! 1673: if (s->dup) {
! 1674: if (dev_nch > slot_nch)
! 1675: s->mix.expand = dev_nch / slot_nch;
! 1676: else if (dev_nch < slot_nch)
! 1677: s->mix.join = slot_nch / dev_nch;
! 1678: }
! 1679: cmap_init(&s->mix.cmap,
! 1680: s->mix.slot_cmin, s->mix.slot_cmax,
! 1681: s->mix.slot_cmin, s->mix.slot_cmax,
! 1682: 0, d->pchan - 1,
! 1683: s->mix.dev_cmin, s->mix.dev_cmax);
! 1684: if (!aparams_native(&s->par)) {
! 1685: dec_init(&s->mix.dec, &s->par, slot_nch);
! 1686: s->mix.decbuf =
! 1687: xmalloc(d->round * slot_nch * sizeof(adata_t));
! 1688: }
! 1689: if (s->rate != d->rate) {
! 1690: resamp_init(&s->mix.resamp, s->round, d->round,
! 1691: slot_nch);
! 1692: s->mix.resampbuf =
! 1693: xmalloc(d->round * slot_nch * sizeof(adata_t));
! 1694: }
! 1695: s->mix.drop = 0;
! 1696: s->mix.vol = MIDI_TO_ADATA(s->vol);
! 1697: dev_mix_adjvol(d);
! 1698: }
! 1699: if (s->mode & MODE_RECMASK) {
! 1700: slot_nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
! 1701: dev_nch = s->sub.dev_cmax - s->sub.dev_cmin + 1;
! 1702: s->sub.encbuf = NULL;
! 1703: s->sub.resampbuf = NULL;
! 1704: s->sub.join = 1;
! 1705: s->sub.expand = 1;
! 1706: if (s->dup) {
! 1707: if (dev_nch > slot_nch)
! 1708: s->sub.join = dev_nch / slot_nch;
! 1709: else if (dev_nch < slot_nch)
! 1710: s->sub.expand = slot_nch / dev_nch;
! 1711: }
! 1712: cmap_init(&s->sub.cmap,
! 1713: 0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
! 1714: s->sub.dev_cmin, s->sub.dev_cmax,
! 1715: s->sub.slot_cmin, s->sub.slot_cmax,
! 1716: s->sub.slot_cmin, s->sub.slot_cmax);
! 1717: if (s->rate != d->rate) {
! 1718: resamp_init(&s->sub.resamp, d->round, s->round,
! 1719: slot_nch);
! 1720: s->sub.resampbuf =
! 1721: xmalloc(d->round * slot_nch * sizeof(adata_t));
! 1722: }
! 1723: if (!aparams_native(&s->par)) {
! 1724: enc_init(&s->sub.enc, &s->par, slot_nch);
! 1725: s->sub.encbuf =
! 1726: xmalloc(d->round * slot_nch * sizeof(adata_t));
! 1727: }
! 1728:
! 1729: /*
! 1730: * N-th recorded block is the N-th played block
! 1731: */
! 1732: s->sub.silence = startpos / (int)s->round;
! 1733: }
! 1734: }
! 1735:
! 1736: /*
! 1737: * if MMC is enabled, and try to attach all slots synchronously, else
! 1738: * simply attach the slot
! 1739: */
! 1740: void
! 1741: slot_ready(struct slot *s)
! 1742: {
! 1743: if (s->tstate == MMC_OFF)
! 1744: slot_attach(s);
! 1745: else {
! 1746: s->tstate = MMC_START;
! 1747: dev_sync_attach(s->dev);
! 1748: }
! 1749: }
! 1750:
! 1751: /*
! 1752: * setup buffers & conversion layers, prepare the slot to receive data
! 1753: * (for playback) or start (recording).
! 1754: */
! 1755: void
! 1756: slot_start(struct slot *s)
! 1757: {
! 1758: unsigned int bufsz;
! 1759: #ifdef DEBUG
! 1760: struct dev *d = s->dev;
! 1761:
! 1762:
! 1763: if (s->pstate != SLOT_INIT) {
! 1764: slot_log(s);
! 1765: log_puts(": slot_start: wrong state\n");
! 1766: panic();
! 1767: }
! 1768: #endif
! 1769: bufsz = s->appbufsz;
! 1770: if (s->mode & MODE_PLAY) {
! 1771: #ifdef DEBUG
! 1772: if (log_level >= 3) {
! 1773: slot_log(s);
! 1774: log_puts(": playing ");
! 1775: aparams_log(&s->par);
! 1776: log_puts(" -> ");
! 1777: aparams_log(&d->par);
! 1778: log_puts("\n");
! 1779: }
! 1780: #endif
! 1781: s->mix.bpf = s->par.bps *
! 1782: (s->mix.slot_cmax - s->mix.slot_cmin + 1);
! 1783: abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
! 1784: }
! 1785: if (s->mode & MODE_RECMASK) {
! 1786: #ifdef DEBUG
! 1787: if (log_level >= 3) {
! 1788: slot_log(s);
! 1789: log_puts(": recording ");
! 1790: aparams_log(&s->par);
! 1791: log_puts(" <- ");
! 1792: aparams_log(&d->par);
! 1793: log_puts("\n");
! 1794: }
! 1795: #endif
! 1796: s->sub.bpf = s->par.bps *
! 1797: (s->sub.slot_cmax - s->sub.slot_cmin + 1);
! 1798: abuf_init(&s->sub.buf, bufsz * s->sub.bpf);
! 1799: }
! 1800: s->mix.weight = MIDI_TO_ADATA(MIDI_MAXCTL);
! 1801: #ifdef DEBUG
! 1802: if (log_level >= 3) {
! 1803: slot_log(s);
! 1804: log_puts(": allocated ");
! 1805: log_putu(s->appbufsz);
! 1806: log_puts("/");
! 1807: log_putu(SLOT_BUFSZ(s));
! 1808: log_puts(" fr buffers\n");
! 1809: }
! 1810: #endif
! 1811: if (s->mode & MODE_PLAY) {
! 1812: s->pstate = SLOT_START;
! 1813: } else {
! 1814: s->pstate = SLOT_READY;
! 1815: slot_ready(s);
! 1816: }
! 1817: }
! 1818:
! 1819: /*
! 1820: * stop playback and recording, and free conversion layers
! 1821: */
! 1822: void
! 1823: slot_detach(struct slot *s)
! 1824: {
! 1825: struct slot **ps;
! 1826:
! 1827: #ifdef DEBUG
! 1828: if (log_level >= 3) {
! 1829: slot_log(s);
! 1830: log_puts(": detaching\n");
! 1831: }
! 1832: #endif
! 1833: for (ps = &s->dev->slot_list; *ps != s; ps = &(*ps)->next) {
! 1834: #ifdef DEBUG
! 1835: if (s == NULL) {
! 1836: slot_log(s);
! 1837: log_puts(": can't detach, not on list\n");
! 1838: panic();
! 1839: }
! 1840: #endif
! 1841: }
! 1842: *ps = s->next;
! 1843: if (s->mode & MODE_RECMASK) {
! 1844: if (s->sub.encbuf)
! 1845: xfree(s->sub.encbuf);
! 1846: if (s->sub.resampbuf)
! 1847: xfree(s->sub.resampbuf);
! 1848: }
! 1849: if (s->mode & MODE_PLAY) {
! 1850: if (s->mix.decbuf)
! 1851: xfree(s->mix.decbuf);
! 1852: if (s->mix.resampbuf)
! 1853: xfree(s->mix.resampbuf);
! 1854: dev_mix_adjvol(s->dev);
! 1855: }
! 1856: }
! 1857:
! 1858: /*
! 1859: * put the slot in stopping state (draining play buffers) or
! 1860: * stop & detach if no data to drain.
! 1861: */
! 1862: void
! 1863: slot_stop(struct slot *s)
! 1864: {
! 1865: #ifdef DEBUG
! 1866: if (log_level >= 3) {
! 1867: slot_log(s);
! 1868: log_puts(": stopping\n");
! 1869: }
! 1870: #endif
! 1871: if (s->pstate == SLOT_START) {
! 1872: if (s->mode & MODE_PLAY) {
! 1873: s->pstate = SLOT_READY;
! 1874: slot_ready(s);
! 1875: } else
! 1876: s->pstate = SLOT_INIT;
! 1877: }
! 1878: if (s->mode & MODE_RECMASK)
! 1879: abuf_done(&s->sub.buf);
! 1880: if (s->pstate == SLOT_READY) {
! 1881: #ifdef DEBUG
! 1882: if (log_level >= 3) {
! 1883: slot_log(s);
! 1884: log_puts(": not drained (blocked by mmc)\n");
! 1885: }
! 1886: #endif
! 1887: if (s->mode & MODE_PLAY)
! 1888: abuf_done(&s->mix.buf);
! 1889: s->ops->eof(s->arg);
! 1890: s->pstate = SLOT_INIT;
! 1891: } else {
! 1892: /* s->pstate == SLOT_RUN */
! 1893: if (s->mode & MODE_PLAY)
! 1894: s->pstate = SLOT_STOP;
! 1895: else {
! 1896: slot_detach(s);
! 1897: s->pstate = SLOT_INIT;
! 1898: s->ops->eof(s->arg);
! 1899: }
! 1900: }
! 1901: if (s->tstate != MMC_OFF)
! 1902: s->tstate = MMC_STOP;
! 1903: }
! 1904:
! 1905: /*
! 1906: * notify the slot that we just wrote in the play buffer, must be called
! 1907: * after each write
! 1908: */
! 1909: void
! 1910: slot_write(struct slot *s)
! 1911: {
! 1912: if (s->pstate == SLOT_START && s->mix.buf.used == s->mix.buf.len) {
! 1913: #ifdef DEBUG
! 1914: if (log_level >= 4) {
! 1915: slot_log(s);
! 1916: log_puts(": switching to READY state\n");
! 1917: }
! 1918: #endif
! 1919: s->pstate = SLOT_READY;
! 1920: slot_ready(s);
! 1921: }
! 1922: }
! 1923:
! 1924: /*
! 1925: * notify the slot that we freed some space in the rec buffer
! 1926: */
! 1927: void
! 1928: slot_read(struct slot *s)
! 1929: {
! 1930: /* nothing yet */
! 1931: }