Annotation of src/usr.bin/aucat/aucat.c, Revision 1.146
1.1 kstailey 1: /*
1.146 ! ratchov 2: * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org>
1.1 kstailey 3: *
1.15 ratchov 4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: */
1.145 deraadt 16:
1.146 ! ratchov 17: #include <fcntl.h>
1.55 ratchov 18: #include <errno.h>
1.146 ! ratchov 19: #include <poll.h>
1.15 ratchov 20: #include <signal.h>
1.135 ratchov 21: #include <sndio.h>
1.1 kstailey 22: #include <stdio.h>
1.4 millert 23: #include <stdlib.h>
1.8 david 24: #include <string.h>
1.1 kstailey 25: #include <unistd.h>
1.146 ! ratchov 26: #include "abuf.h"
! 27: #include "afile.h"
! 28: #include "dsp.h"
! 29: #include "sysex.h"
! 30: #include "utils.h"
! 31:
! 32: /*
! 33: * masks to extract command and channel of status byte
! 34: */
! 35: #define MIDI_CMDMASK 0xf0
! 36: #define MIDI_CHANMASK 0x0f
! 37:
! 38: /*
! 39: * MIDI status bytes of voice messages
! 40: */
! 41: #define MIDI_NOFF 0x80 /* note off */
! 42: #define MIDI_NON 0x90 /* note on */
! 43: #define MIDI_KAT 0xa0 /* key after touch */
! 44: #define MIDI_CTL 0xb0 /* controller */
! 45: #define MIDI_PC 0xc0 /* program change */
! 46: #define MIDI_CAT 0xd0 /* channel after touch */
! 47: #define MIDI_BEND 0xe0 /* pitch bend */
! 48: #define MIDI_ACK 0xfe /* active sensing message */
! 49:
! 50: /*
! 51: * MIDI controller numbers
! 52: */
! 53: #define MIDI_CTL_VOL 7
! 54:
! 55: /*
! 56: * Max coarse value
! 57: */
! 58: #define MIDI_MAXCTL 127
! 59:
! 60: /*
! 61: * MIDI status bytes for sysex
! 62: */
! 63: #define MIDI_SX_START 0xf0
! 64: #define MIDI_SX_STOP 0xf7
! 65:
! 66: /*
! 67: * audio device defaults
! 68: */
! 69: #define DEFAULT_RATE 48000
! 70: #define DEFAULT_BUFSZ_MS 200
! 71:
! 72: struct slot {
! 73: struct slot *next; /* next on the play list */
! 74: int vol; /* dynamic range */
! 75: int volctl; /* volume in the 0..127 range */
! 76: struct abuf buf; /* file i/o buffer */
! 77: int bpf; /* bytes per frame */
! 78: int cmin, cmax; /* file channel range */
! 79: struct cmap cmap; /* channel mapper state */
! 80: struct resamp resamp; /* resampler state */
! 81: struct conv conv; /* format encoder state */
! 82: int join; /* channel join factor */
! 83: int expand; /* channel expand factor */
! 84: void *resampbuf, *convbuf; /* conversion tmp buffers */
! 85: int dup; /* mono-to-stereo and alike */
! 86: int round; /* slot-side block size */
! 87: int mode; /* MODE_{PLAY,REC} */
! 88: #define SLOT_CFG 0 /* buffers not allocated yet */
! 89: #define SLOT_INIT 1 /* not trying to do anything */
! 90: #define SLOT_RUN 2 /* playing/recording */
! 91: #define SLOT_STOP 3 /* draining (play only) */
! 92: int pstate; /* one of above */
! 93: struct afile afile; /* file desc & friends */
! 94: };
! 95:
! 96: /*
! 97: * device properties
! 98: */
! 99: unsigned int dev_mode; /* bitmap of SIO_{PLAY,REC} */
! 100: unsigned int dev_bufsz; /* device buffer size */
! 101: unsigned int dev_round; /* device block size */
! 102: int dev_rate; /* device sample rate (Hz) */
! 103: unsigned int dev_pchan, dev_rchan; /* play & rec channels count */
! 104: adata_t *dev_pbuf, *dev_rbuf; /* play & rec buffers */
! 105: unsigned int dev_mmcpos; /* last MMC position */
! 106: #define DEV_STOP 0 /* stopped */
! 107: #define DEV_START 1 /* started */
! 108: unsigned int dev_pstate; /* one of above */
! 109: char *dev_name; /* device sndio(7) name */
! 110: char *dev_port; /* control port sndio(7) name */
! 111: struct sio_hdl *dev_sh; /* device handle */
! 112: struct mio_hdl *dev_mh; /* MIDI control port handle */
! 113: unsigned int dev_volctl = MIDI_MAXCTL; /* master volume */
! 114:
! 115: /*
! 116: * MIDI parser state
! 117: */
! 118: #define MIDI_MSGMAX 32 /* max size of MIDI msg */
! 119: unsigned char dev_msg[MIDI_MSGMAX]; /* parsed input message */
! 120: unsigned int dev_mst; /* input MIDI running status */
! 121: unsigned int dev_mused; /* bytes used in ``msg'' */
! 122: unsigned int dev_midx; /* current ``msg'' size */
! 123: unsigned int dev_mlen; /* expected ``msg'' length */
! 124: unsigned int dev_prime; /* blocks to write to start */
! 125:
! 126: unsigned int log_level = 1;
! 127: volatile sig_atomic_t quit_flag = 0;
! 128: struct slot *slot_list = NULL;
! 129:
! 130: /*
! 131: * length of voice and common MIDI messages (status byte included)
! 132: */
! 133: unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
! 134: unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
! 135:
! 136: char usagestr[] = "usage: aucat [-d] [-b nframes] "
! 137: "[-c min:max] [-e enc] [-f device]\n\t"
! 138: "[-j flag] [-q port] [-r rate] [-v volume]\n";
! 139:
! 140: static void
! 141: slot_log(struct slot *s)
! 142: {
! 143: #ifdef DEBUG
! 144: static char *pstates[] = {
! 145: "cfg", "ini", "run", "stp"
! 146: };
! 147: #endif
! 148: log_puts(s->afile.path);
! 149: #ifdef DEBUG
! 150: if (log_level >= 3) {
! 151: log_puts(",pst=");
! 152: log_puts(pstates[s->pstate]);
! 153: }
! 154: #endif
! 155: }
! 156:
! 157: static void
! 158: slot_flush(struct slot *s)
! 159: {
! 160: int todo, count, n;
! 161: unsigned char *data;
! 162:
! 163: todo = s->buf.used;
! 164: while (todo > 0) {
! 165: data = abuf_rgetblk(&s->buf, &count);
! 166: if (count > todo)
! 167: count = todo;
! 168: n = afile_write(&s->afile, data, count);
! 169: if (n == 0) {
! 170: slot_log(s);
! 171: log_puts(": can't write, disabled\n");
! 172: s->pstate = SLOT_INIT;
! 173: return;
! 174: }
! 175: abuf_rdiscard(&s->buf, n);
! 176: todo -= n;
! 177: }
! 178: }
! 179:
! 180: static void
! 181: slot_fill(struct slot *s)
! 182: {
! 183: int todo, count, n;
! 184: unsigned char *data;
! 185:
! 186: todo = s->buf.len;
! 187: while (todo > 0) {
! 188: data = abuf_wgetblk(&s->buf, &count);
! 189: if (count > todo)
! 190: count = todo;
! 191: n = afile_read(&s->afile, data, count);
! 192: if (n == 0) {
! 193: #ifdef DEBUG
! 194: if (log_level >= 3) {
! 195: slot_log(s);
! 196: log_puts(": eof reached, stopping\n");
! 197: }
! 198: #endif
! 199: s->pstate = SLOT_STOP;
! 200: break;
! 201: }
! 202: abuf_wcommit(&s->buf, n);
! 203: todo -= n;
! 204: }
! 205: }
! 206:
! 207: static int
! 208: slot_new(char *path, int mode, struct aparams *par, int hdr,
! 209: int cmin, int cmax, int rate, int dup, int vol)
! 210: {
! 211: struct slot *s;
! 212:
! 213: s = xmalloc(sizeof(struct slot));
! 214: if (!afile_open(&s->afile, path, hdr,
! 215: mode == SIO_PLAY ? AFILE_FREAD : AFILE_FWRITE,
! 216: par, rate, cmax - cmin + 1)) {
! 217: xfree(s);
! 218: return 0;
! 219: }
! 220: s->cmin = cmin;
! 221: s->cmax = cmin + s->afile.nch - 1;
! 222: s->dup = dup;
! 223: s->vol = MIDI_TO_ADATA(vol);
! 224: s->mode = mode;
! 225: s->pstate = SLOT_CFG;
! 226: if (log_level >= 2) {
! 227: slot_log(s);
! 228: log_puts(": ");
! 229: log_puts(s->mode == SIO_PLAY ? "play" : "rec");
! 230: log_puts(", chan ");
! 231: log_putu(s->cmin);
! 232: log_puts(":");
! 233: log_putu(s->cmax);
! 234: log_puts(", ");
! 235: log_putu(s->afile.rate);
! 236: log_puts("Hz, ");
! 237: switch (s->afile.fmt) {
! 238: case AFILE_FMT_PCM:
! 239: aparams_log(&s->afile.par);
! 240: break;
! 241: case AFILE_FMT_ULAW:
! 242: log_puts("ulaw");
! 243: break;
! 244: case AFILE_FMT_ALAW:
! 245: log_puts("alaw");
! 246: break;
! 247: case AFILE_FMT_FLOAT:
! 248: log_puts("f32le");
! 249: break;
! 250: }
! 251: if (s->mode == SIO_PLAY && s->afile.endpos >= 0) {
! 252: log_puts(", bytes ");
! 253: log_puti(s->afile.startpos);
! 254: log_puts("..");
! 255: log_puti(s->afile.endpos);
! 256: }
! 257: log_puts("\n");
! 258: }
! 259: s->next = slot_list;
! 260: slot_list = s;
! 261: return 1;
! 262: }
! 263:
! 264: static void
! 265: slot_init(struct slot *s)
! 266: {
! 267: unsigned int slot_nch, bufsz;
! 268:
! 269: #ifdef DEBUG
! 270: if (s->pstate != SLOT_CFG) {
! 271: slot_log(s);
! 272: log_puts(": slot_init: wrong state\n");
! 273: panic();
! 274: }
! 275: #endif
! 276: s->bpf = s->afile.par.bps * (s->cmax - s->cmin + 1);
! 277: s->round = (dev_round * s->afile.rate + dev_rate / 2) / dev_rate;
! 278:
! 279: bufsz = s->round * (dev_bufsz / dev_round);
! 280: bufsz -= bufsz % s->round;
! 281: if (bufsz == 0)
! 282: bufsz = s->round;
! 283: abuf_init(&s->buf, bufsz * s->bpf);
! 284: #ifdef DEBUG
! 285: if (log_level >= 3) {
! 286: slot_log(s);
! 287: log_puts(": allocated ");
! 288: log_putu(bufsz);
! 289: log_puts(" frame buffer\n");
! 290: }
! 291: #endif
! 292:
! 293: slot_nch = s->cmax - s->cmin + 1;
! 294: s->convbuf = NULL;
! 295: s->resampbuf = NULL;
! 296: s->join = 1;
! 297: s->expand = 1;
! 298: if (s->mode & SIO_PLAY) {
! 299: if (s->dup) {
! 300: if (dev_pchan > slot_nch)
! 301: s->expand = dev_pchan / slot_nch;
! 302: else if (dev_pchan < slot_nch)
! 303: s->join = slot_nch / dev_pchan;
! 304: }
! 305: cmap_init(&s->cmap,
! 306: s->cmin, s->cmax,
! 307: s->cmin, s->cmax,
! 308: 0, dev_pchan - 1,
! 309: 0, dev_pchan - 1);
! 310: if (s->afile.fmt != AFILE_FMT_PCM || !aparams_native(&s->afile.par)) {
! 311: dec_init(&s->conv, &s->afile.par, slot_nch);
! 312: s->convbuf =
! 313: xmalloc(s->round * slot_nch * sizeof(adata_t));
! 314: }
! 315: if (s->afile.rate != dev_rate) {
! 316: resamp_init(&s->resamp, s->round, dev_round,
! 317: slot_nch);
! 318: s->resampbuf =
! 319: xmalloc(dev_round * slot_nch * sizeof(adata_t));
! 320: }
! 321: }
! 322: if (s->mode & SIO_REC) {
! 323: if (s->dup) {
! 324: if (dev_rchan > slot_nch)
! 325: s->join = dev_rchan / slot_nch;
! 326: else if (dev_rchan < slot_nch)
! 327: s->expand = slot_nch / dev_rchan;
! 328: }
! 329: cmap_init(&s->cmap,
! 330: 0, dev_rchan - 1,
! 331: 0, dev_rchan - 1,
! 332: s->cmin, s->cmax,
! 333: s->cmin, s->cmax);
! 334: if (s->afile.rate != dev_rate) {
! 335: resamp_init(&s->resamp, dev_round, s->round,
! 336: slot_nch);
! 337: s->resampbuf =
! 338: xmalloc(dev_round * slot_nch * sizeof(adata_t));
! 339: }
! 340: if (!aparams_native(&s->afile.par)) {
! 341: enc_init(&s->conv, &s->afile.par, slot_nch);
! 342: s->convbuf =
! 343: xmalloc(s->round * slot_nch * sizeof(adata_t));
! 344: }
! 345: }
! 346: s->pstate = SLOT_INIT;
! 347: #ifdef DEBUG
! 348: if (log_level >= 3) {
! 349: slot_log(s);
! 350: log_puts(": chain initialized\n");
! 351: }
! 352: #endif
! 353: }
! 354:
! 355: static void
! 356: slot_start(struct slot *s, unsigned int mmc)
! 357: {
! 358: off_t mmcpos;
! 359:
! 360: #ifdef DEBUG
! 361: if (s->pstate != SLOT_INIT) {
! 362: slot_log(s);
! 363: log_puts(": slot_start: wrong state\n");
! 364: panic();
! 365: }
! 366: #endif
! 367: mmcpos = ((off_t)mmc * s->afile.rate / MTC_SEC) * s->bpf;
! 368: if (!afile_seek(&s->afile, mmcpos)) {
! 369: s->pstate = SLOT_INIT;
! 370: return;
! 371: }
! 372: s->pstate = SLOT_RUN;
! 373: if (s->mode & SIO_PLAY)
! 374: slot_fill(s);
! 375: #ifdef DEBUG
! 376: if (log_level >= 2) {
! 377: slot_log(s);
! 378: log_puts(": started\n");
! 379: }
! 380: #endif
! 381: }
1.1 kstailey 382:
1.146 ! ratchov 383: static void
! 384: slot_stop(struct slot *s)
! 385: {
! 386: if (s->pstate == SLOT_INIT)
! 387: return;
! 388: if (s->mode & SIO_REC)
! 389: slot_flush(s);
! 390: if (s->mode & SIO_PLAY)
! 391: s->buf.used = s->buf.start = 0;
! 392: s->pstate = SLOT_INIT;
1.78 ratchov 393: #ifdef DEBUG
1.146 ! ratchov 394: if (log_level >= 2) {
! 395: slot_log(s);
! 396: log_puts(": stopped\n");
! 397: }
1.78 ratchov 398: #endif
1.146 ! ratchov 399: }
1.11 jaredy 400:
1.146 ! ratchov 401: static void
! 402: slot_del(struct slot *s)
! 403: {
! 404: struct slot **ps;
1.61 ratchov 405:
1.146 ! ratchov 406: if (s->pstate != SLOT_CFG) {
! 407: slot_stop(s);
! 408: afile_close(&s->afile);
! 409: #ifdef DEBUG
! 410: if (log_level >= 3) {
! 411: slot_log(s);
! 412: log_puts(": closed\n");
! 413: }
1.108 ratchov 414: #endif
1.146 ! ratchov 415: abuf_done(&s->buf);
! 416: if (s->resampbuf)
! 417: xfree(s->resampbuf);
! 418: if (s->convbuf)
! 419: xfree(s->convbuf);
! 420: }
! 421: for (ps = &slot_list; *ps != s; ps = &(*ps)->next)
! 422: ; /* nothing */
! 423: *ps = s->next;
! 424: xfree(s);
! 425: }
! 426:
! 427: static int
! 428: play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
! 429: {
! 430: int i, offs, vol, nch;
! 431: void *in;
! 432:
! 433: if (s->resampbuf) {
! 434: todo = resamp_do(&s->resamp,
! 435: res_in, s->resampbuf, todo);
! 436: in = s->resampbuf;
! 437: } else
! 438: in = res_in;
! 439:
! 440: nch = s->cmap.nch;
! 441: vol = s->vol / s->join; /* XXX */
! 442: cmap_add(&s->cmap, in, out, vol, todo);
! 443:
! 444: offs = 0;
! 445: for (i = s->join - 1; i > 0; i--) {
! 446: offs += nch;
! 447: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, todo);
! 448: }
! 449: offs = 0;
! 450: for (i = s->expand - 1; i > 0; i--) {
! 451: offs += nch;
! 452: cmap_add(&s->cmap, in, (adata_t *)out + offs, vol, todo);
! 453: }
! 454: return todo;
! 455: }
! 456:
! 457: static int
! 458: play_filt_dec(struct slot *s, void *in, void *out, int todo)
! 459: {
! 460: void *tmp;
! 461:
! 462: tmp = s->convbuf;
! 463: if (tmp) {
! 464: switch (s->afile.fmt) {
! 465: case AFILE_FMT_PCM:
! 466: dec_do(&s->conv, in, tmp, todo);
! 467: break;
! 468: case AFILE_FMT_ULAW:
! 469: dec_do_ulaw(&s->conv, in, tmp, todo, 0);
! 470: break;
! 471: case AFILE_FMT_ALAW:
! 472: dec_do_ulaw(&s->conv, in, tmp, todo, 1);
! 473: break;
! 474: case AFILE_FMT_FLOAT:
! 475: dec_do_float(&s->conv, in, tmp, todo);
! 476: break;
! 477: }
! 478: }
! 479: return play_filt_resamp(s, tmp ? tmp : in, out, todo);
! 480: }
1.108 ratchov 481:
1.120 ratchov 482: /*
1.146 ! ratchov 483: * Mix as many as possible frames (but not more than a block) from the
! 484: * slot buffer to the given location. Return the number of frames mixed
! 485: * in the output buffer
1.120 ratchov 486: */
1.146 ! ratchov 487: static int
! 488: slot_mix_badd(struct slot *s, adata_t *odata)
! 489: {
! 490: adata_t *idata;
! 491: int icount, todo, done;
! 492:
! 493: idata = (adata_t *)abuf_rgetblk(&s->buf, &icount);
! 494: todo = icount / s->bpf;
! 495: if (todo > s->round)
! 496: todo = s->round;
! 497: #ifdef DEBUG
! 498: if (todo == 0) {
! 499: log_puts("slot_mix_badd: not enough data\n");
! 500: panic();
! 501: }
1.133 ratchov 502: #endif
1.146 ! ratchov 503: done = play_filt_dec(s, idata, odata, todo);
! 504: abuf_rdiscard(&s->buf, todo * s->bpf);
! 505: return done;
! 506: }
! 507:
! 508: static int
! 509: rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
! 510: {
! 511: int i, vol, offs, nch;
! 512: void *out = res_out;
! 513:
! 514: out = (s->resampbuf) ? s->resampbuf : res_out;
! 515:
! 516: nch = s->cmap.nch;
! 517: vol = ADATA_UNIT / s->join;
! 518: cmap_copy(&s->cmap, in, out, vol, todo);
! 519:
! 520: offs = 0;
! 521: for (i = s->join - 1; i > 0; i--) {
! 522: offs += nch;
! 523: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, todo);
! 524: }
! 525: offs = 0;
! 526: for (i = s->expand - 1; i > 0; i--) {
! 527: offs += nch;
! 528: cmap_copy(&s->cmap, in, (adata_t *)out + offs, vol, todo);
! 529: }
! 530: if (s->resampbuf) {
! 531: todo = resamp_do(&s->resamp,
! 532: s->resampbuf, res_out, todo);
! 533: }
! 534: return todo;
! 535: }
! 536:
! 537: static int
! 538: rec_filt_enc(struct slot *s, void *in, void *out, int todo)
! 539: {
! 540: void *tmp;
! 541:
! 542: tmp = s->convbuf;
! 543: todo = rec_filt_resamp(s, in, tmp ? tmp : out, todo);
! 544: if (tmp)
! 545: enc_do(&s->conv, tmp, out, todo);
! 546: return todo;
! 547: }
1.133 ratchov 548:
549: /*
1.146 ! ratchov 550: * Copy "todo" frames from the given buffer to the slot buffer,
! 551: * but not more than a block.
1.133 ratchov 552: */
1.146 ! ratchov 553: static void
! 554: slot_sub_bcopy(struct slot *s, adata_t *idata, int todo)
! 555: {
! 556: adata_t *odata;
! 557: int ocount;
! 558:
! 559: odata = (adata_t *)abuf_wgetblk(&s->buf, &ocount);
! 560: #ifdef DEBUG
! 561: if (ocount < s->round * s->bpf) {
! 562: log_puts("slot_sub_bcopy: not enough space\n");
! 563: panic();
! 564: }
1.120 ratchov 565: #endif
1.146 ! ratchov 566: ocount = rec_filt_enc(s, idata, odata, todo);
! 567: abuf_wcommit(&s->buf, ocount * s->bpf);
! 568: }
! 569:
! 570: static int
! 571: dev_open(char *dev, int mode, int bufsz, char *port)
! 572: {
! 573: int rate, pmax, rmax;
! 574: struct sio_par par;
! 575: struct slot *s;
! 576:
! 577: if (port) {
! 578: dev_port = port;
! 579: dev_mh = mio_open(dev_port, MIO_IN, 0);
! 580: if (dev_mh == NULL) {
! 581: log_puts(port);
! 582: log_puts(": couldn't open midi port\n");
! 583: return 0;
! 584: }
! 585: } else
! 586: dev_mh = NULL;
! 587:
! 588: dev_name = dev;
! 589: dev_sh = sio_open(dev, mode, 0);
! 590: if (dev_sh == NULL) {
! 591: log_puts(dev_name);
! 592: log_puts(": couldn't open audio device\n");
! 593: return 0;
! 594: }
! 595:
! 596: rate = pmax = rmax = 0;
! 597: for (s = slot_list; s != NULL; s = s->next) {
! 598: if (s->afile.rate > rate)
! 599: rate = s->afile.rate;
! 600: if (s->mode == SIO_PLAY) {
! 601: if (s->cmax > pmax)
! 602: pmax = s->cmax;
! 603: }
! 604: if (s->mode == SIO_REC) {
! 605: if (s->cmax > rmax)
! 606: rmax = s->cmax;
! 607: }
! 608: }
! 609: sio_initpar(&par);
! 610: par.bits = ADATA_BITS;
! 611: par.bps = sizeof(adata_t);
! 612: par.msb = 0;
! 613: par.le = SIO_LE_NATIVE;
! 614: if (mode & SIO_PLAY)
! 615: par.pchan = pmax + 1;
! 616: if (mode & SIO_REC)
! 617: par.rchan = rmax + 1;
! 618: par.appbufsz = bufsz > 0 ? bufsz : rate * DEFAULT_BUFSZ_MS / 1000;
! 619: if (!sio_setpar(dev_sh, &par) || !sio_getpar(dev_sh, &par)) {
! 620: log_puts(dev_name);
! 621: log_puts(": couldn't set audio params\n");
! 622: return 0;
! 623: }
! 624: if (par.bits != ADATA_BITS ||
! 625: par.bps != sizeof(adata_t) ||
! 626: par.le != SIO_LE_NATIVE ||
! 627: (par.bps != SIO_BPS(par.bits) && par.msb)) {
! 628: log_puts(dev_name);
! 629: log_puts(": unsupported audio params\n");
! 630: return 0;
! 631: }
! 632: dev_mode = mode;
! 633: dev_rate = par.rate;
! 634: dev_bufsz = par.bufsz;
! 635: dev_round = par.round;
! 636: if (mode & SIO_PLAY) {
! 637: dev_pchan = par.pchan;
! 638: dev_pbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
! 639: }
! 640: if (mode & SIO_REC) {
! 641: dev_rchan = par.rchan;
! 642: dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round);
! 643: }
! 644: dev_mmcpos = 0;
! 645: dev_pstate = DEV_STOP;
! 646: if (log_level >= 2) {
! 647: log_puts(dev_name);
! 648: log_puts(": ");
! 649: log_putu(dev_rate);
! 650: log_puts("Hz");
! 651: if (dev_mode & SIO_PLAY) {
! 652: log_puts(", play 0:");
! 653: log_puti(dev_pchan - 1);
! 654: }
! 655: if (dev_mode & SIO_REC) {
! 656: log_puts(", rec 0:");
! 657: log_puti(dev_rchan - 1);
! 658: }
! 659: log_puts(", ");
! 660: log_putu(dev_bufsz / dev_round);
! 661: log_puts(" blocks of ");
! 662: log_putu(dev_round);
! 663: log_puts(" frames\n");
! 664: }
! 665: return 1;
! 666: }
1.120 ratchov 667:
1.146 ! ratchov 668: static void
! 669: dev_close(void)
! 670: {
! 671: sio_close(dev_sh);
! 672: if (dev_mh)
! 673: mio_close(dev_mh);
! 674: if (dev_mode & SIO_PLAY)
! 675: xfree(dev_pbuf);
! 676: if (dev_mode & SIO_REC)
! 677: xfree(dev_rbuf);
! 678: }
! 679:
! 680: static void
! 681: dev_master(int val)
! 682: {
! 683: struct slot *s;
! 684: int mastervol, slotvol;
1.143 ratchov 685:
1.146 ! ratchov 686: mastervol = MIDI_TO_ADATA(dev_volctl);
! 687: for (s = slot_list; s != NULL; s = s->next) {
! 688: slotvol = MIDI_TO_ADATA(val);
! 689: s->vol = ADATA_MUL(mastervol, slotvol);
! 690: }
1.78 ratchov 691: #ifdef DEBUG
1.146 ! ratchov 692: if (log_level >= 3) {
! 693: log_puts("master volume set to ");
! 694: log_putu(val);
! 695: log_puts("\n");
! 696: }
1.78 ratchov 697: #endif
1.146 ! ratchov 698: }
1.7 deraadt 699:
1.146 ! ratchov 700: static void
! 701: dev_slotvol(int midich, int val)
! 702: {
! 703: struct slot *s;
! 704: int mastervol, slotvol;
! 705:
! 706: for (s = slot_list; s != NULL; s = s->next) {
! 707: if (midich == 0) {
! 708: mastervol = MIDI_TO_ADATA(dev_volctl);
! 709: slotvol = MIDI_TO_ADATA(val);
! 710: s->vol = ADATA_MUL(mastervol, slotvol);
! 711: #ifdef DEBUG
! 712: if (log_level >= 3) {
! 713: slot_log(s);
! 714: log_puts(": volume set to ");
! 715: log_putu(val);
! 716: log_puts("\n");
! 717: }
! 718: #endif
! 719: break;
! 720: }
! 721: }
! 722: }
1.129 ratchov 723:
1.28 ratchov 724: /*
1.146 ! ratchov 725: * start all slots simultaneously
1.28 ratchov 726: */
1.146 ! ratchov 727: static void
! 728: dev_mmcstart(void)
1.28 ratchov 729: {
1.146 ! ratchov 730: struct slot *s;
! 731:
! 732: if (dev_pstate == DEV_STOP) {
! 733: dev_pstate = DEV_START;
! 734: for (s = slot_list; s != NULL; s = s->next)
! 735: slot_start(s, dev_mmcpos);
! 736: dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0;
! 737: sio_start(dev_sh);
! 738: if (log_level >= 2)
! 739: log_puts("started\n");
! 740: } else {
! 741: #ifdef DEBUG
! 742: if (log_level >= 3)
! 743: log_puts("ignoring mmc start\n");
! 744: #endif
! 745: }
1.28 ratchov 746: }
1.22 ratchov 747:
1.146 ! ratchov 748: /*
! 749: * stop all slots simultaneously
! 750: */
! 751: static void
! 752: dev_mmcstop(void)
! 753: {
! 754: struct slot *s;
! 755:
! 756: if (dev_pstate == DEV_START) {
! 757: dev_pstate = DEV_STOP;
! 758: for (s = slot_list; s != NULL; s = s->next)
! 759: slot_stop(s);
! 760: sio_stop(dev_sh);
! 761: if (log_level >= 2)
! 762: log_puts("stopped\n");
! 763: } else {
1.78 ratchov 764: #ifdef DEBUG
1.146 ! ratchov 765: if (log_level >= 3)
! 766: log_puts("ignored mmc stop\n");
! 767: #endif
! 768: }
! 769: }
! 770:
1.78 ratchov 771: /*
1.146 ! ratchov 772: * relocate all slots simultaneously
1.78 ratchov 773: */
1.146 ! ratchov 774: static void
! 775: dev_mmcloc(unsigned int mmc)
1.78 ratchov 776: {
1.146 ! ratchov 777: if (dev_mmcpos == mmc)
! 778: return;
! 779: dev_mmcpos = mmc;
! 780: if (log_level >= 2) {
! 781: log_puts("relocated to ");
! 782: log_putu((dev_mmcpos / (MTC_SEC * 3600)) % 24);
! 783: log_puts(":");
! 784: log_putu((dev_mmcpos / (MTC_SEC * 60)) % 60);
! 785: log_puts(":");
! 786: log_putu((dev_mmcpos / (MTC_SEC)) % 60);
! 787: log_puts(".");
! 788: log_putu((dev_mmcpos / (MTC_SEC / 100)) % 100);
! 789: log_puts("\n");
! 790: }
! 791: if (dev_pstate == DEV_START) {
! 792: dev_mmcstop();
! 793: dev_mmcstart();
! 794: }
! 795: }
! 796:
! 797: static void
! 798: dev_imsg(unsigned char *msg, unsigned int len)
! 799: {
! 800: struct sysex *x;
! 801: unsigned int fps, chan;
! 802:
! 803: if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
! 804: chan = msg[0] & MIDI_CHANMASK;
! 805: dev_slotvol(chan, msg[2]);
! 806: return;
! 807: }
! 808: x = (struct sysex *)msg;
! 809: if (x->start != SYSEX_START)
! 810: return;
! 811: if (len < SYSEX_SIZE(empty))
! 812: return;
! 813: if (x->type != SYSEX_TYPE_RT)
! 814: return;
! 815: if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
! 816: if (len == SYSEX_SIZE(master))
! 817: dev_master(x->u.master.coarse);
! 818: return;
! 819: }
! 820: if (x->id0 != SYSEX_MMC)
! 821: return;
! 822: switch (x->id1) {
! 823: case SYSEX_MMC_STOP:
! 824: if (len != SYSEX_SIZE(stop))
! 825: return;
! 826: dev_mmcstop();
! 827: break;
! 828: case SYSEX_MMC_START:
! 829: if (len != SYSEX_SIZE(start))
! 830: return;
! 831: dev_mmcstart();
! 832: break;
! 833: case SYSEX_MMC_LOC:
! 834: if (len != SYSEX_SIZE(loc) ||
! 835: x->u.loc.len != SYSEX_MMC_LOC_LEN ||
! 836: x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
! 837: return;
! 838: switch (x->u.loc.hr >> 5) {
! 839: case MTC_FPS_24:
! 840: fps = 24;
! 841: break;
! 842: case MTC_FPS_25:
! 843: fps = 25;
! 844: break;
! 845: case MTC_FPS_30:
! 846: fps = 30;
! 847: break;
! 848: default:
! 849: dev_mmcstop();
! 850: return;
! 851: }
! 852: dev_mmcloc((x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
! 853: x->u.loc.min * 60 * MTC_SEC +
! 854: x->u.loc.sec * MTC_SEC +
! 855: x->u.loc.fr * (MTC_SEC / fps) +
! 856: x->u.loc.cent * (MTC_SEC / 100 / fps));
! 857: break;
! 858: }
1.78 ratchov 859: }
860:
861: /*
1.146 ! ratchov 862: * parse then given data chunk, and calling imsg() for each message
1.78 ratchov 863: */
1.146 ! ratchov 864: static void
! 865: midi_in(unsigned char *idata, int icount)
1.78 ratchov 866: {
1.146 ! ratchov 867: int i;
! 868: unsigned char c;
! 869:
! 870: for (i = 0; i < icount; i++) {
! 871: c = *idata++;
! 872: if (c >= 0xf8) {
! 873: /* we don't use reat-time events */
! 874: } else if (c == SYSEX_END) {
! 875: if (dev_mst == SYSEX_START) {
! 876: dev_msg[dev_midx++] = c;
! 877: dev_imsg(dev_msg, dev_midx);
! 878: }
! 879: dev_mst = 0;
! 880: dev_midx = 0;
! 881: } else if (c >= 0xf0) {
! 882: dev_msg[0] = c;
! 883: dev_mlen = common_len[c & 7];
! 884: dev_mst = c;
! 885: dev_midx = 1;
! 886: } else if (c >= 0x80) {
! 887: dev_msg[0] = c;
! 888: dev_mlen = voice_len[(c >> 4) & 7];
! 889: dev_mst = c;
! 890: dev_midx = 1;
! 891: } else if (dev_mst) {
! 892: if (dev_midx == 0 && dev_mst != SYSEX_START)
! 893: dev_msg[dev_midx++] = dev_mst;
! 894: dev_msg[dev_midx++] = c;
! 895: if (dev_midx == dev_mlen) {
! 896: dev_imsg(dev_msg, dev_midx);
! 897: if (dev_mst >= 0xf0)
! 898: dev_mst = 0;
! 899: dev_midx = 0;
! 900: } else if (dev_midx == MIDI_MSGMAX) {
! 901: /* sysex too long */
! 902: dev_mst = 0;
! 903: }
! 904: }
! 905: }
1.78 ratchov 906: }
1.15 ratchov 907:
1.146 ! ratchov 908: static int
! 909: slot_list_mix(unsigned int round, unsigned int pchan, adata_t *pbuf)
1.15 ratchov 910: {
1.146 ! ratchov 911: unsigned int done, n;
! 912: struct slot *s;
1.13 uwe 913:
1.146 ! ratchov 914: memset(pbuf, 0, pchan * round * sizeof(adata_t));
! 915: done = 0;
! 916: for (s = slot_list; s != NULL; s = s->next) {
! 917: if (s->pstate == SLOT_INIT || !(s->mode & SIO_PLAY))
! 918: continue;
! 919: if (s->pstate == SLOT_STOP && s->buf.used < s->bpf) {
! 920: s->pstate = SLOT_INIT;
! 921: #ifdef DEBUG
! 922: if (log_level >= 3) {
! 923: slot_log(s);
! 924: log_puts(": drained, done\n");
! 925: }
! 926: #endif
! 927: continue;
! 928: }
! 929: n = slot_mix_badd(s, dev_pbuf);
! 930: if (n > done)
! 931: done = n;
! 932: }
! 933: return done;
1.15 ratchov 934: }
1.13 uwe 935:
1.146 ! ratchov 936: static int
! 937: slot_list_copy(unsigned int count, unsigned int rchan, adata_t *rbuf)
1.15 ratchov 938: {
1.146 ! ratchov 939: unsigned int done;
! 940: struct slot *s;
1.28 ratchov 941:
1.146 ! ratchov 942: done = 0;
! 943: for (s = slot_list; s != NULL; s = s->next) {
! 944: if (s->pstate == SLOT_INIT || !(s->mode & SIO_REC))
! 945: continue;
! 946: slot_sub_bcopy(s, rbuf, count);
! 947: done = count;
! 948: }
! 949: return done;
1.15 ratchov 950: }
1.4 millert 951:
1.146 ! ratchov 952: static void
! 953: slot_list_iodo(void)
1.15 ratchov 954: {
1.146 ! ratchov 955: struct slot *s;
! 956:
! 957: for (s = slot_list; s != NULL; s = s->next) {
! 958: if (s->pstate != SLOT_RUN)
! 959: continue;
! 960: if ((s->mode & SIO_PLAY) && (s->buf.used == 0))
! 961: slot_fill(s);
! 962: if ((s->mode & SIO_REC) && (s->buf.used == s->buf.len))
! 963: slot_flush(s);
! 964: }
1.1 kstailey 965: }
966:
1.146 ! ratchov 967: static int
! 968: offline(void)
1.74 ratchov 969: {
1.146 ! ratchov 970: unsigned int todo;
! 971: int rate, cmax;
! 972: struct slot *s;
! 973:
! 974: rate = cmax = 0;
! 975: for (s = slot_list; s != NULL; s = s->next) {
! 976: if (s->afile.rate > rate)
! 977: rate = s->afile.rate;
! 978: if (s->cmax > cmax)
! 979: cmax = s->cmax;
! 980: }
! 981: dev_sh = NULL;
! 982: dev_name = "offline";
! 983: dev_mode = SIO_PLAY | SIO_REC;
! 984: dev_rate = rate;
! 985: dev_bufsz = rate;
! 986: dev_round = rate;
! 987: dev_pchan = dev_rchan = cmax + 1;
! 988: dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
! 989: dev_pstate = DEV_STOP;
! 990: dev_mmcpos = 0;
! 991: for (s = slot_list; s != NULL; s = s->next)
! 992: slot_init(s);
! 993: for (s = slot_list; s != NULL; s = s->next)
! 994: slot_start(s, 0);
! 995: for (;;) {
! 996: todo = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
! 997: if (todo == 0)
! 998: break;
! 999: slot_list_copy(todo, dev_pchan, dev_pbuf);
! 1000: slot_list_iodo();
! 1001: }
! 1002: xfree(dev_pbuf);
! 1003: while (slot_list)
! 1004: slot_del(slot_list);
! 1005: return 1;
1.74 ratchov 1006: }
1007:
1.146 ! ratchov 1008: static int
! 1009: playrec_cycle(void)
1.84 ratchov 1010: {
1.146 ! ratchov 1011: unsigned int n, todo;
! 1012: unsigned char *p;
! 1013: int pcnt, rcnt;
! 1014:
! 1015: #ifdef DEBUG
! 1016: if (log_level >= 4) {
! 1017: log_puts(dev_name);
! 1018: log_puts(": cycle, prime = ");
! 1019: log_putu(dev_prime);
! 1020: log_puts("\n");
! 1021: }
! 1022: #endif
! 1023: pcnt = rcnt = 0;
! 1024: if (dev_mode & SIO_REC) {
! 1025: if (dev_prime > 0)
! 1026: dev_prime--;
! 1027: else {
! 1028: todo = dev_round * dev_rchan * sizeof(adata_t);
! 1029: p = (unsigned char *)dev_rbuf;
! 1030: while (todo > 0) {
! 1031: n = sio_read(dev_sh, p, todo);
! 1032: if (n == 0) {
! 1033: log_puts(dev_name);
! 1034: log_puts(": failed to read from device\n");
! 1035: return 0;
! 1036: }
! 1037: p += n;
! 1038: todo -= n;
! 1039: }
! 1040: rcnt = slot_list_copy(dev_round, dev_rchan, dev_rbuf);
! 1041: }
! 1042: }
! 1043: if (dev_mode & SIO_PLAY) {
! 1044: pcnt = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
! 1045: todo = sizeof(adata_t) * dev_pchan * dev_round;
! 1046: n = sio_write(dev_sh, dev_pbuf, todo);
! 1047: if (n == 0) {
! 1048: log_puts(dev_name);
! 1049: log_puts(": failed to write to device\n");
! 1050: return 0;
! 1051: }
! 1052: }
! 1053: slot_list_iodo();
! 1054: return pcnt > 0 || rcnt > 0;
1.84 ratchov 1055: }
1056:
1.146 ! ratchov 1057: static void
! 1058: sigint(int s)
1.22 ratchov 1059: {
1.146 ! ratchov 1060: if (quit_flag)
! 1061: _exit(1);
! 1062: quit_flag = 1;
1.22 ratchov 1063: }
1064:
1.146 ! ratchov 1065: static int
! 1066: playrec(char *dev, int mode, int bufsz, char *port)
1.61 ratchov 1067: {
1.146 ! ratchov 1068: #define MIDIBUFSZ 0x100
! 1069: unsigned char mbuf[MIDIBUFSZ];
1.61 ratchov 1070: struct sigaction sa;
1.146 ! ratchov 1071: struct pollfd *pfds;
! 1072: struct slot *s;
! 1073: int n, ns, nm, ev;
! 1074:
! 1075: if (!dev_open(dev, mode, bufsz, port))
! 1076: return 0;
! 1077: n = sio_nfds(dev_sh);
! 1078: if (dev_mh)
! 1079: n += mio_nfds(dev_mh);
! 1080: pfds = xmalloc(n * sizeof(struct pollfd));
! 1081: for (s = slot_list; s != NULL; s = s->next)
! 1082: slot_init(s);
! 1083: if (dev_mh == NULL)
! 1084: dev_mmcstart();
! 1085: else {
! 1086: if (log_level >= 2)
! 1087: log_puts("ready, waiting for mmc messages\n");
! 1088: }
1.61 ratchov 1089:
1090: quit_flag = 0;
1091: sigfillset(&sa.sa_mask);
1092: sa.sa_flags = SA_RESTART;
1093: sa.sa_handler = sigint;
1.146 ! ratchov 1094: sigaction(SIGINT, &sa, NULL);
! 1095: sigaction(SIGTERM, &sa, NULL);
! 1096: sigaction(SIGHUP, &sa, NULL);
! 1097: while (!quit_flag) {
! 1098: if (dev_pstate == DEV_START) {
! 1099: ev = 0;
! 1100: if (mode & SIO_PLAY)
! 1101: ev |= POLLOUT;
! 1102: if (mode & SIO_REC)
! 1103: ev |= POLLIN;
! 1104: ns = sio_pollfd(dev_sh, pfds, ev);
! 1105: } else
! 1106: ns = 0;
! 1107: if (dev_mh)
! 1108: nm = mio_pollfd(dev_mh, pfds + ns, POLLIN);
! 1109: else
! 1110: nm = 0;
! 1111: if (poll(pfds, ns + nm, -1) < 0) {
! 1112: if (errno == EINTR)
! 1113: continue;
! 1114: log_puts("poll failed\n");
! 1115: panic();
! 1116: }
! 1117: if (dev_pstate == DEV_START) {
! 1118: ev = sio_revents(dev_sh, pfds);
! 1119: if (ev & POLLHUP) {
! 1120: log_puts(dev);
! 1121: log_puts(": audio device gone, stopping\n");
! 1122: break;
! 1123: }
! 1124: if (ev & (POLLIN | POLLOUT)) {
! 1125: if (!playrec_cycle() && dev_mh == NULL)
! 1126: break;
! 1127: }
! 1128: }
! 1129: if (dev_mh) {
! 1130: ev = mio_revents(dev_mh, pfds + ns);
! 1131: if (ev & POLLHUP) {
! 1132: log_puts(dev_port);
! 1133: log_puts(": midi port gone, stopping\n");
! 1134: break;
! 1135: }
! 1136: if (ev & POLLIN) {
! 1137: n = mio_read(dev_mh, mbuf, MIDIBUFSZ);
! 1138: midi_in(mbuf, n);
! 1139: }
! 1140: }
! 1141: }
! 1142: sigfillset(&sa.sa_mask);
! 1143: sa.sa_flags = SA_RESTART;
! 1144: sa.sa_handler = SIG_DFL;
! 1145: sigaction(SIGINT, &sa, NULL);
! 1146: sigaction(SIGTERM, &sa, NULL);
! 1147: sigaction(SIGHUP, &sa, NULL);
! 1148:
! 1149: if (dev_pstate == DEV_START)
! 1150: dev_mmcstop();
! 1151: xfree(pfds);
! 1152: dev_close();
! 1153: while (slot_list)
! 1154: slot_del(slot_list);
! 1155: return 1;
! 1156: }
! 1157:
! 1158: static int
! 1159: opt_onoff(char *s, int *flag)
! 1160: {
! 1161: if (strcmp("off", s) == 0) {
! 1162: *flag = 0;
! 1163: return 1;
! 1164: }
! 1165: if (strcmp("on", s) == 0) {
! 1166: *flag = 1;
! 1167: return 1;
! 1168: }
! 1169: log_puts(s);
! 1170: log_puts(": on/off expected\n");
! 1171: return 0;
! 1172: }
! 1173:
! 1174: static int
! 1175: opt_enc(char *s, struct aparams *par)
! 1176: {
! 1177: int len;
! 1178:
! 1179: len = aparams_strtoenc(par, s);
! 1180: if (len == 0 || s[len] != '\0') {
! 1181: log_puts(s);
! 1182: log_puts(": bad encoding\n");
! 1183: return 0;
! 1184: }
! 1185: return 1;
! 1186: }
! 1187:
! 1188: static int
! 1189: opt_hdr(char *s, int *hdr)
! 1190: {
! 1191: if (strcmp("auto", s) == 0) {
! 1192: *hdr = AFILE_HDR_AUTO;
! 1193: return 1;
! 1194: }
! 1195: if (strcmp("raw", s) == 0) {
! 1196: *hdr = AFILE_HDR_RAW;
! 1197: return 1;
! 1198: }
! 1199: if (strcmp("wav", s) == 0) {
! 1200: *hdr = AFILE_HDR_WAV;
! 1201: return 1;
! 1202: }
! 1203: if (strcmp("aiff", s) == 0) {
! 1204: *hdr = AFILE_HDR_AIFF;
! 1205: return 1;
! 1206: }
! 1207: if (strcmp("au", s) == 0) {
! 1208: *hdr = AFILE_HDR_AU;
! 1209: return 1;
! 1210: }
! 1211: log_puts(s);
! 1212: log_puts(": bad header type\n");
! 1213: return 0;
! 1214: }
! 1215:
! 1216: static int
! 1217: opt_ch(char *s, int *rcmin, int *rcmax)
! 1218: {
! 1219: char *next, *end;
! 1220: long cmin, cmax;
! 1221:
! 1222: errno = 0;
! 1223: cmin = strtol(s, &next, 10);
! 1224: if (next == s || *next != ':')
! 1225: goto failed;
! 1226: cmax = strtol(++next, &end, 10);
! 1227: if (end == next || *end != '\0')
! 1228: goto failed;
! 1229: if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
! 1230: goto failed;
! 1231: *rcmin = cmin;
! 1232: *rcmax = cmax;
! 1233: return 1;
! 1234: failed:
! 1235: log_puts(s);
! 1236: log_puts(": channel range expected\n");
! 1237: return 0;
1.61 ratchov 1238: }
1239:
1.146 ! ratchov 1240: static int
! 1241: opt_num(char *s, int min, int max, int *num)
1.61 ratchov 1242: {
1.146 ! ratchov 1243: const char *errstr;
1.61 ratchov 1244:
1.146 ! ratchov 1245: *num = strtonum(s, min, max, &errstr);
! 1246: if (errstr) {
! 1247: log_puts(s);
! 1248: log_puts(": expected integer between ");
! 1249: log_puti(min);
! 1250: log_puts(" and ");
! 1251: log_puti(max);
! 1252: log_puts("\n");
! 1253: return 0;
! 1254: }
! 1255: return 1;
1.120 ratchov 1256: }
1257:
1.1 kstailey 1258: int
1.120 ratchov 1259: main(int argc, char **argv)
1.1 kstailey 1260: {
1.146 ! ratchov 1261: int dup, cmin, cmax, rate, vol, bufsz, hdr, mode;
! 1262: char *port, *dev;
! 1263: struct aparams par;
! 1264: int n_flag, c;
! 1265:
! 1266: vol = 127;
! 1267: dup = 0;
1.120 ratchov 1268: bufsz = 0;
1.146 ! ratchov 1269: rate = DEFAULT_RATE;
! 1270: cmin = 0;
! 1271: cmax = 1;
! 1272: aparams_init(&par);
! 1273: hdr = AFILE_HDR_AUTO;
! 1274: n_flag = 0;
! 1275: port = NULL;
! 1276: dev = NULL;
! 1277: mode = 0;
! 1278:
! 1279: while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) {
1.15 ratchov 1280: switch (c) {
1.146 ! ratchov 1281: case 'b':
! 1282: if (!opt_num(optarg, 1, RATE_MAX, &bufsz))
! 1283: return 1;
1.74 ratchov 1284: break;
1.15 ratchov 1285: case 'c':
1.146 ! ratchov 1286: if (!opt_ch(optarg, &cmin, &cmax))
! 1287: return 1;
1.15 ratchov 1288: break;
1.146 ! ratchov 1289: case 'd':
! 1290: log_level++;
1.15 ratchov 1291: break;
1292: case 'e':
1.146 ! ratchov 1293: if (!opt_enc(optarg, &par))
! 1294: return 1;
1.15 ratchov 1295: break;
1.146 ! ratchov 1296: case 'f':
! 1297: dev = optarg;
1.15 ratchov 1298: break;
1.146 ! ratchov 1299: case 'h':
! 1300: if (!opt_hdr(optarg, &hdr))
! 1301: return 1;
1.35 ratchov 1302: break;
1.15 ratchov 1303: case 'i':
1.146 ! ratchov 1304: if (!slot_new(optarg, SIO_PLAY,
! 1305: &par, hdr, cmin, cmax, rate, dup, vol))
! 1306: return 1;
! 1307: mode |= SIO_PLAY;
1.15 ratchov 1308: break;
1.146 ! ratchov 1309: case 'j':
! 1310: if (!opt_onoff(optarg, &dup))
! 1311: return 1;
1.92 ratchov 1312: break;
1.146 ! ratchov 1313: case 'n':
! 1314: n_flag = 1;
1.4 millert 1315: break;
1.146 ! ratchov 1316: case 'o':
! 1317: if (!slot_new(optarg, SIO_REC,
! 1318: &par, hdr, cmin, cmax, rate, dup, 0))
! 1319: return 1;
! 1320: mode |= SIO_REC;
1.74 ratchov 1321: break;
1.146 ! ratchov 1322: case 'q':
! 1323: port = optarg;
1.120 ratchov 1324: break;
1.146 ! ratchov 1325: case 'r':
! 1326: if (!opt_num(optarg, RATE_MIN, RATE_MAX, &rate))
! 1327: return 1;
1.120 ratchov 1328: break;
1.146 ! ratchov 1329: case 'v':
! 1330: if (!opt_num(optarg, 0, MIDI_MAXCTL, &vol))
! 1331: return 1;
1.92 ratchov 1332: break;
1.11 jaredy 1333: default:
1.146 ! ratchov 1334: goto bad_usage;
1.4 millert 1335: }
1336: }
1337: argc -= optind;
1338: argv += optind;
1.146 ! ratchov 1339: if (argc != 0) {
! 1340: bad_usage:
! 1341: log_puts(usagestr);
! 1342: return 1;
! 1343: }
! 1344: if (n_flag) {
! 1345: if (dev != NULL || port != NULL) {
! 1346: log_puts("-f and -q make no sense in off-line mode\n");
! 1347: return 1;
1.125 ratchov 1348: }
1.146 ! ratchov 1349: if (mode != (SIO_PLAY | SIO_REC)) {
! 1350: log_puts("both -i and -o required\n");
! 1351: return 0;
! 1352: }
! 1353: if (!offline())
! 1354: return 1;
1.125 ratchov 1355: } else {
1.146 ! ratchov 1356: if (dev == NULL)
! 1357: dev = SIO_DEVANY;
! 1358: if (mode == 0) {
! 1359: log_puts("at least of -i and -o required\n");
! 1360: return 1;
! 1361: }
! 1362: if (!playrec(dev, mode, bufsz, port))
! 1363: return 1;
1.120 ratchov 1364: }
1.61 ratchov 1365: return 0;
1.1 kstailey 1366: }