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