Annotation of src/usr.bin/aucat/aucat.c, Revision 1.154
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 {
1.149 ratchov 73: struct slot *next; /* next on the play/rec list */
1.146 ratchov 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 */
1.149 ratchov 93: struct afile afile; /* file desc & friends */
1.146 ratchov 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:
1.147 jmc 136: char usagestr[] = "usage: aucat [-dn] [-b size] "
137: "[-c min:max] [-e enc] [-f device] [-h fmt]\n\t"
138: "[-i file] [-j flag] [-o file] [-q port] [-r rate] [-v volume]\n";
1.146 ratchov 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)) {
1.150 mmcc 217: free(s);
1.146 ratchov 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);
1.151 ratchov 310: if (s->afile.fmt != AFILE_FMT_PCM ||
311: !aparams_native(&s->afile.par)) {
1.146 ratchov 312: dec_init(&s->conv, &s->afile.par, slot_nch);
313: s->convbuf =
314: xmalloc(s->round * slot_nch * sizeof(adata_t));
315: }
316: if (s->afile.rate != dev_rate) {
317: resamp_init(&s->resamp, s->round, dev_round,
318: slot_nch);
319: s->resampbuf =
320: xmalloc(dev_round * slot_nch * sizeof(adata_t));
321: }
322: }
323: if (s->mode & SIO_REC) {
324: if (s->dup) {
325: if (dev_rchan > slot_nch)
326: s->join = dev_rchan / slot_nch;
327: else if (dev_rchan < slot_nch)
328: s->expand = slot_nch / dev_rchan;
329: }
330: cmap_init(&s->cmap,
331: 0, dev_rchan - 1,
332: 0, dev_rchan - 1,
333: s->cmin, s->cmax,
334: s->cmin, s->cmax);
335: if (s->afile.rate != dev_rate) {
336: resamp_init(&s->resamp, dev_round, s->round,
337: slot_nch);
338: s->resampbuf =
339: xmalloc(dev_round * slot_nch * sizeof(adata_t));
340: }
341: if (!aparams_native(&s->afile.par)) {
342: enc_init(&s->conv, &s->afile.par, slot_nch);
343: s->convbuf =
344: xmalloc(s->round * slot_nch * sizeof(adata_t));
345: }
346: }
347: s->pstate = SLOT_INIT;
348: #ifdef DEBUG
349: if (log_level >= 3) {
350: slot_log(s);
351: log_puts(": chain initialized\n");
352: }
353: #endif
354: }
355:
356: static void
357: slot_start(struct slot *s, unsigned int mmc)
358: {
359: off_t mmcpos;
360:
361: #ifdef DEBUG
362: if (s->pstate != SLOT_INIT) {
363: slot_log(s);
364: log_puts(": slot_start: wrong state\n");
365: panic();
366: }
367: #endif
368: mmcpos = ((off_t)mmc * s->afile.rate / MTC_SEC) * s->bpf;
369: if (!afile_seek(&s->afile, mmcpos)) {
370: s->pstate = SLOT_INIT;
371: return;
372: }
373: s->pstate = SLOT_RUN;
374: if (s->mode & SIO_PLAY)
375: slot_fill(s);
376: #ifdef DEBUG
377: if (log_level >= 2) {
378: slot_log(s);
379: log_puts(": started\n");
380: }
381: #endif
382: }
1.1 kstailey 383:
1.146 ratchov 384: static void
385: slot_stop(struct slot *s)
386: {
387: if (s->pstate == SLOT_INIT)
388: return;
389: if (s->mode & SIO_REC)
390: slot_flush(s);
391: if (s->mode & SIO_PLAY)
392: s->buf.used = s->buf.start = 0;
393: s->pstate = SLOT_INIT;
1.78 ratchov 394: #ifdef DEBUG
1.146 ratchov 395: if (log_level >= 2) {
396: slot_log(s);
397: log_puts(": stopped\n");
398: }
1.78 ratchov 399: #endif
1.146 ratchov 400: }
1.11 jaredy 401:
1.146 ratchov 402: static void
403: slot_del(struct slot *s)
404: {
405: struct slot **ps;
1.61 ratchov 406:
1.146 ratchov 407: if (s->pstate != SLOT_CFG) {
408: slot_stop(s);
409: afile_close(&s->afile);
410: #ifdef DEBUG
411: if (log_level >= 3) {
412: slot_log(s);
413: log_puts(": closed\n");
414: }
1.108 ratchov 415: #endif
1.146 ratchov 416: abuf_done(&s->buf);
1.150 mmcc 417: free(s->resampbuf);
418: free(s->convbuf);
1.146 ratchov 419: }
420: for (ps = &slot_list; *ps != s; ps = &(*ps)->next)
421: ; /* nothing */
422: *ps = s->next;
1.150 mmcc 423: free(s);
1.146 ratchov 424: }
425:
1.154 ! ratchov 426: static int
! 427: slot_ocnt(struct slot *s, int icnt)
! 428: {
! 429: return s->resampbuf ? resamp_ocnt(&s->resamp, icnt) : icnt;
! 430: }
! 431:
! 432: static int
! 433: slot_icnt(struct slot *s, int ocnt)
! 434: {
! 435: return s->resampbuf ? resamp_icnt(&s->resamp, ocnt) : ocnt;
! 436: }
! 437:
1.153 ratchov 438: static void
1.154 ! ratchov 439: play_filt_resamp(struct slot *s, void *res_in, void *out, int icnt, int ocnt)
1.146 ratchov 440: {
441: int i, offs, vol, nch;
442: void *in;
443:
444: if (s->resampbuf) {
1.153 ratchov 445: resamp_do(&s->resamp, res_in, s->resampbuf, icnt, ocnt);
1.146 ratchov 446: in = s->resampbuf;
447: } else
448: in = res_in;
449:
450: nch = s->cmap.nch;
451: vol = s->vol / s->join; /* XXX */
1.154 ! ratchov 452: cmap_add(&s->cmap, in, out, vol, ocnt);
1.146 ratchov 453:
454: offs = 0;
455: for (i = s->join - 1; i > 0; i--) {
456: offs += nch;
1.154 ! ratchov 457: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, ocnt);
1.146 ratchov 458: }
459: offs = 0;
460: for (i = s->expand - 1; i > 0; i--) {
461: offs += nch;
1.154 ! ratchov 462: cmap_add(&s->cmap, in, (adata_t *)out + offs, vol, ocnt);
1.146 ratchov 463: }
464: }
465:
1.153 ratchov 466: static void
1.154 ! ratchov 467: play_filt_dec(struct slot *s, void *in, void *out, int icnt, int ocnt)
1.146 ratchov 468: {
469: void *tmp;
470:
471: tmp = s->convbuf;
472: if (tmp) {
473: switch (s->afile.fmt) {
474: case AFILE_FMT_PCM:
1.154 ! ratchov 475: dec_do(&s->conv, in, tmp, icnt);
1.146 ratchov 476: break;
477: case AFILE_FMT_ULAW:
1.154 ! ratchov 478: dec_do_ulaw(&s->conv, in, tmp, icnt, 0);
1.146 ratchov 479: break;
480: case AFILE_FMT_ALAW:
1.154 ! ratchov 481: dec_do_ulaw(&s->conv, in, tmp, icnt, 1);
1.146 ratchov 482: break;
483: case AFILE_FMT_FLOAT:
1.154 ! ratchov 484: dec_do_float(&s->conv, in, tmp, icnt);
1.146 ratchov 485: break;
486: }
1.153 ratchov 487: } else
488: tmp = in;
489: play_filt_resamp(s, tmp, out, icnt, ocnt);
1.146 ratchov 490: }
1.108 ratchov 491:
1.120 ratchov 492: /*
1.146 ratchov 493: * Mix as many as possible frames (but not more than a block) from the
494: * slot buffer to the given location. Return the number of frames mixed
495: * in the output buffer
1.120 ratchov 496: */
1.146 ratchov 497: static int
498: slot_mix_badd(struct slot *s, adata_t *odata)
499: {
500: adata_t *idata;
1.154 ! ratchov 501: int len, icnt, ocnt, otodo, odone;
1.146 ratchov 502:
1.154 ! ratchov 503: odone = 0;
! 504: otodo = dev_round;
! 505: while (otodo > 0) {
! 506: idata = (adata_t *)abuf_rgetblk(&s->buf, &len);
! 507:
! 508: icnt = len / s->bpf;
! 509: ocnt = slot_ocnt(s, icnt);
! 510: if (ocnt > otodo) {
! 511: ocnt = otodo;
! 512: icnt = slot_icnt(s, ocnt);
! 513: }
! 514: if (icnt == 0)
! 515: break;
! 516: play_filt_dec(s, idata, odata, icnt, ocnt);
! 517: abuf_rdiscard(&s->buf, icnt * s->bpf);
! 518: otodo -= ocnt;
! 519: odone += ocnt;
! 520: odata += ocnt * dev_pchan;
! 521: }
! 522: return odone;
1.146 ratchov 523: }
524:
1.153 ratchov 525: static void
1.154 ! ratchov 526: rec_filt_resamp(struct slot *s, void *in, void *res_out, int icnt, int ocnt)
1.146 ratchov 527: {
528: int i, vol, offs, nch;
529: void *out = res_out;
530:
531: out = (s->resampbuf) ? s->resampbuf : res_out;
532:
533: nch = s->cmap.nch;
534: vol = ADATA_UNIT / s->join;
1.154 ! ratchov 535: cmap_copy(&s->cmap, in, out, vol, icnt);
1.146 ratchov 536:
537: offs = 0;
538: for (i = s->join - 1; i > 0; i--) {
539: offs += nch;
1.154 ! ratchov 540: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, icnt);
1.146 ratchov 541: }
542: offs = 0;
543: for (i = s->expand - 1; i > 0; i--) {
544: offs += nch;
1.154 ! ratchov 545: cmap_copy(&s->cmap, in, (adata_t *)out + offs, vol, icnt);
1.146 ratchov 546: }
1.153 ratchov 547: if (s->resampbuf)
548: resamp_do(&s->resamp, s->resampbuf, res_out, icnt, ocnt);
549: else
1.154 ! ratchov 550: ocnt = icnt;
1.146 ratchov 551: }
552:
1.153 ratchov 553: static void
1.154 ! ratchov 554: rec_filt_enc(struct slot *s, void *in, void *out, int icnt, int ocnt)
1.146 ratchov 555: {
556: void *tmp;
557:
558: tmp = s->convbuf;
1.153 ratchov 559: rec_filt_resamp(s, in, tmp ? tmp : out, icnt, ocnt);
1.146 ratchov 560: if (tmp)
1.154 ! ratchov 561: enc_do(&s->conv, tmp, out, ocnt);
1.146 ratchov 562: }
1.133 ratchov 563:
564: /*
1.146 ratchov 565: * Copy "todo" frames from the given buffer to the slot buffer,
566: * but not more than a block.
1.133 ratchov 567: */
1.146 ratchov 568: static void
1.154 ! ratchov 569: slot_sub_bcopy(struct slot *s, adata_t *idata, int itodo)
1.146 ratchov 570: {
571: adata_t *odata;
1.153 ratchov 572: int len, icnt, ocnt;
1.146 ratchov 573:
1.154 ! ratchov 574: while (itodo > 0) {
! 575: odata = (adata_t *)abuf_wgetblk(&s->buf, &len);
! 576:
! 577: ocnt = len / s->bpf;
! 578: icnt = slot_icnt(s, ocnt);
! 579: if (icnt > itodo) {
! 580: icnt = itodo;
! 581: ocnt = slot_ocnt(s, icnt);
! 582: }
! 583: if (ocnt == 0)
! 584: break;
! 585: rec_filt_enc(s, idata, odata, icnt, ocnt);
! 586: abuf_wcommit(&s->buf, ocnt * s->bpf);
! 587: itodo -= icnt;
! 588: idata += icnt * dev_rchan;
! 589: }
1.146 ratchov 590: }
591:
592: static int
593: dev_open(char *dev, int mode, int bufsz, char *port)
594: {
595: int rate, pmax, rmax;
596: struct sio_par par;
597: struct slot *s;
598:
599: if (port) {
600: dev_port = port;
601: dev_mh = mio_open(dev_port, MIO_IN, 0);
602: if (dev_mh == NULL) {
603: log_puts(port);
604: log_puts(": couldn't open midi port\n");
605: return 0;
606: }
607: } else
608: dev_mh = NULL;
609:
610: dev_name = dev;
611: dev_sh = sio_open(dev, mode, 0);
612: if (dev_sh == NULL) {
613: log_puts(dev_name);
614: log_puts(": couldn't open audio device\n");
615: return 0;
616: }
617:
618: rate = pmax = rmax = 0;
619: for (s = slot_list; s != NULL; s = s->next) {
620: if (s->afile.rate > rate)
621: rate = s->afile.rate;
622: if (s->mode == SIO_PLAY) {
623: if (s->cmax > pmax)
624: pmax = s->cmax;
625: }
626: if (s->mode == SIO_REC) {
627: if (s->cmax > rmax)
628: rmax = s->cmax;
629: }
630: }
631: sio_initpar(&par);
632: par.bits = ADATA_BITS;
633: par.bps = sizeof(adata_t);
634: par.msb = 0;
635: par.le = SIO_LE_NATIVE;
636: if (mode & SIO_PLAY)
637: par.pchan = pmax + 1;
638: if (mode & SIO_REC)
639: par.rchan = rmax + 1;
640: par.appbufsz = bufsz > 0 ? bufsz : rate * DEFAULT_BUFSZ_MS / 1000;
641: if (!sio_setpar(dev_sh, &par) || !sio_getpar(dev_sh, &par)) {
642: log_puts(dev_name);
643: log_puts(": couldn't set audio params\n");
644: return 0;
645: }
646: if (par.bits != ADATA_BITS ||
647: par.bps != sizeof(adata_t) ||
1.152 ratchov 648: (par.bps > 1 && par.le != SIO_LE_NATIVE) ||
649: (par.bps * 8 > par.bits && par.msb)) {
1.146 ratchov 650: log_puts(dev_name);
651: log_puts(": unsupported audio params\n");
652: return 0;
653: }
654: dev_mode = mode;
655: dev_rate = par.rate;
656: dev_bufsz = par.bufsz;
657: dev_round = par.round;
658: if (mode & SIO_PLAY) {
659: dev_pchan = par.pchan;
660: dev_pbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
661: }
662: if (mode & SIO_REC) {
663: dev_rchan = par.rchan;
664: dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round);
665: }
666: dev_mmcpos = 0;
667: dev_pstate = DEV_STOP;
668: if (log_level >= 2) {
669: log_puts(dev_name);
670: log_puts(": ");
671: log_putu(dev_rate);
672: log_puts("Hz");
673: if (dev_mode & SIO_PLAY) {
674: log_puts(", play 0:");
675: log_puti(dev_pchan - 1);
676: }
677: if (dev_mode & SIO_REC) {
678: log_puts(", rec 0:");
679: log_puti(dev_rchan - 1);
680: }
681: log_puts(", ");
682: log_putu(dev_bufsz / dev_round);
683: log_puts(" blocks of ");
684: log_putu(dev_round);
685: log_puts(" frames\n");
686: }
687: return 1;
688: }
1.120 ratchov 689:
1.146 ratchov 690: static void
691: dev_close(void)
692: {
693: sio_close(dev_sh);
694: if (dev_mh)
695: mio_close(dev_mh);
696: if (dev_mode & SIO_PLAY)
1.150 mmcc 697: free(dev_pbuf);
1.146 ratchov 698: if (dev_mode & SIO_REC)
1.150 mmcc 699: free(dev_rbuf);
1.146 ratchov 700: }
701:
702: static void
703: dev_master(int val)
704: {
705: struct slot *s;
706: int mastervol, slotvol;
1.143 ratchov 707:
1.146 ratchov 708: mastervol = MIDI_TO_ADATA(dev_volctl);
709: for (s = slot_list; s != NULL; s = s->next) {
710: slotvol = MIDI_TO_ADATA(val);
711: s->vol = ADATA_MUL(mastervol, slotvol);
712: }
1.78 ratchov 713: #ifdef DEBUG
1.146 ratchov 714: if (log_level >= 3) {
715: log_puts("master volume set to ");
716: log_putu(val);
717: log_puts("\n");
718: }
1.78 ratchov 719: #endif
1.146 ratchov 720: }
1.7 deraadt 721:
1.146 ratchov 722: static void
723: dev_slotvol(int midich, int val)
724: {
725: struct slot *s;
726: int mastervol, slotvol;
727:
728: for (s = slot_list; s != NULL; s = s->next) {
729: if (midich == 0) {
730: mastervol = MIDI_TO_ADATA(dev_volctl);
731: slotvol = MIDI_TO_ADATA(val);
732: s->vol = ADATA_MUL(mastervol, slotvol);
733: #ifdef DEBUG
734: if (log_level >= 3) {
735: slot_log(s);
736: log_puts(": volume set to ");
737: log_putu(val);
738: log_puts("\n");
739: }
740: #endif
741: break;
742: }
743: }
744: }
1.129 ratchov 745:
1.28 ratchov 746: /*
1.146 ratchov 747: * start all slots simultaneously
1.28 ratchov 748: */
1.146 ratchov 749: static void
750: dev_mmcstart(void)
1.28 ratchov 751: {
1.146 ratchov 752: struct slot *s;
753:
754: if (dev_pstate == DEV_STOP) {
755: dev_pstate = DEV_START;
756: for (s = slot_list; s != NULL; s = s->next)
757: slot_start(s, dev_mmcpos);
758: dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0;
759: sio_start(dev_sh);
760: if (log_level >= 2)
761: log_puts("started\n");
762: } else {
763: #ifdef DEBUG
764: if (log_level >= 3)
765: log_puts("ignoring mmc start\n");
766: #endif
767: }
1.28 ratchov 768: }
1.22 ratchov 769:
1.146 ratchov 770: /*
771: * stop all slots simultaneously
772: */
773: static void
774: dev_mmcstop(void)
775: {
776: struct slot *s;
777:
778: if (dev_pstate == DEV_START) {
779: dev_pstate = DEV_STOP;
780: for (s = slot_list; s != NULL; s = s->next)
781: slot_stop(s);
782: sio_stop(dev_sh);
783: if (log_level >= 2)
784: log_puts("stopped\n");
785: } else {
1.78 ratchov 786: #ifdef DEBUG
1.146 ratchov 787: if (log_level >= 3)
788: log_puts("ignored mmc stop\n");
789: #endif
790: }
791: }
792:
1.78 ratchov 793: /*
1.146 ratchov 794: * relocate all slots simultaneously
1.78 ratchov 795: */
1.146 ratchov 796: static void
797: dev_mmcloc(unsigned int mmc)
1.78 ratchov 798: {
1.146 ratchov 799: if (dev_mmcpos == mmc)
800: return;
801: dev_mmcpos = mmc;
802: if (log_level >= 2) {
803: log_puts("relocated to ");
804: log_putu((dev_mmcpos / (MTC_SEC * 3600)) % 24);
805: log_puts(":");
806: log_putu((dev_mmcpos / (MTC_SEC * 60)) % 60);
807: log_puts(":");
808: log_putu((dev_mmcpos / (MTC_SEC)) % 60);
809: log_puts(".");
810: log_putu((dev_mmcpos / (MTC_SEC / 100)) % 100);
811: log_puts("\n");
812: }
813: if (dev_pstate == DEV_START) {
814: dev_mmcstop();
815: dev_mmcstart();
816: }
817: }
818:
819: static void
820: dev_imsg(unsigned char *msg, unsigned int len)
821: {
822: struct sysex *x;
823: unsigned int fps, chan;
824:
825: if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
826: chan = msg[0] & MIDI_CHANMASK;
827: dev_slotvol(chan, msg[2]);
828: return;
829: }
830: x = (struct sysex *)msg;
831: if (x->start != SYSEX_START)
832: return;
833: if (len < SYSEX_SIZE(empty))
834: return;
835: if (x->type != SYSEX_TYPE_RT)
836: return;
837: if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
838: if (len == SYSEX_SIZE(master))
839: dev_master(x->u.master.coarse);
840: return;
841: }
842: if (x->id0 != SYSEX_MMC)
843: return;
844: switch (x->id1) {
845: case SYSEX_MMC_STOP:
846: if (len != SYSEX_SIZE(stop))
847: return;
848: dev_mmcstop();
849: break;
850: case SYSEX_MMC_START:
851: if (len != SYSEX_SIZE(start))
852: return;
853: dev_mmcstart();
854: break;
855: case SYSEX_MMC_LOC:
856: if (len != SYSEX_SIZE(loc) ||
857: x->u.loc.len != SYSEX_MMC_LOC_LEN ||
858: x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
859: return;
860: switch (x->u.loc.hr >> 5) {
861: case MTC_FPS_24:
862: fps = 24;
863: break;
864: case MTC_FPS_25:
865: fps = 25;
866: break;
867: case MTC_FPS_30:
868: fps = 30;
869: break;
870: default:
871: dev_mmcstop();
872: return;
873: }
874: dev_mmcloc((x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
875: x->u.loc.min * 60 * MTC_SEC +
876: x->u.loc.sec * MTC_SEC +
877: x->u.loc.fr * (MTC_SEC / fps) +
878: x->u.loc.cent * (MTC_SEC / 100 / fps));
879: break;
880: }
1.78 ratchov 881: }
882:
883: /*
1.149 ratchov 884: * parse the given data chunk and call imsg() for each message
1.78 ratchov 885: */
1.146 ratchov 886: static void
887: midi_in(unsigned char *idata, int icount)
1.78 ratchov 888: {
1.146 ratchov 889: int i;
890: unsigned char c;
891:
892: for (i = 0; i < icount; i++) {
893: c = *idata++;
894: if (c >= 0xf8) {
1.149 ratchov 895: /* we don't use real-time events */
1.146 ratchov 896: } else if (c == SYSEX_END) {
897: if (dev_mst == SYSEX_START) {
898: dev_msg[dev_midx++] = c;
899: dev_imsg(dev_msg, dev_midx);
900: }
901: dev_mst = 0;
902: dev_midx = 0;
903: } else if (c >= 0xf0) {
904: dev_msg[0] = c;
905: dev_mlen = common_len[c & 7];
906: dev_mst = c;
907: dev_midx = 1;
908: } else if (c >= 0x80) {
909: dev_msg[0] = c;
910: dev_mlen = voice_len[(c >> 4) & 7];
911: dev_mst = c;
912: dev_midx = 1;
913: } else if (dev_mst) {
914: if (dev_midx == 0 && dev_mst != SYSEX_START)
915: dev_msg[dev_midx++] = dev_mst;
916: dev_msg[dev_midx++] = c;
917: if (dev_midx == dev_mlen) {
918: dev_imsg(dev_msg, dev_midx);
919: if (dev_mst >= 0xf0)
920: dev_mst = 0;
921: dev_midx = 0;
922: } else if (dev_midx == MIDI_MSGMAX) {
923: /* sysex too long */
924: dev_mst = 0;
925: }
926: }
927: }
1.78 ratchov 928: }
1.15 ratchov 929:
1.146 ratchov 930: static int
931: slot_list_mix(unsigned int round, unsigned int pchan, adata_t *pbuf)
1.15 ratchov 932: {
1.146 ratchov 933: unsigned int done, n;
934: struct slot *s;
1.13 uwe 935:
1.146 ratchov 936: memset(pbuf, 0, pchan * round * sizeof(adata_t));
937: done = 0;
938: for (s = slot_list; s != NULL; s = s->next) {
939: if (s->pstate == SLOT_INIT || !(s->mode & SIO_PLAY))
940: continue;
941: if (s->pstate == SLOT_STOP && s->buf.used < s->bpf) {
942: #ifdef DEBUG
943: if (log_level >= 3) {
944: slot_log(s);
945: log_puts(": drained, done\n");
946: }
947: #endif
1.148 ratchov 948: slot_stop(s);
1.146 ratchov 949: continue;
950: }
951: n = slot_mix_badd(s, dev_pbuf);
952: if (n > done)
953: done = n;
954: }
955: return done;
1.15 ratchov 956: }
1.13 uwe 957:
1.146 ratchov 958: static int
959: slot_list_copy(unsigned int count, unsigned int rchan, adata_t *rbuf)
1.15 ratchov 960: {
1.146 ratchov 961: unsigned int done;
962: struct slot *s;
1.28 ratchov 963:
1.146 ratchov 964: done = 0;
965: for (s = slot_list; s != NULL; s = s->next) {
966: if (s->pstate == SLOT_INIT || !(s->mode & SIO_REC))
967: continue;
968: slot_sub_bcopy(s, rbuf, count);
969: done = count;
970: }
971: return done;
1.15 ratchov 972: }
1.4 millert 973:
1.146 ratchov 974: static void
975: slot_list_iodo(void)
1.15 ratchov 976: {
1.146 ratchov 977: struct slot *s;
978:
979: for (s = slot_list; s != NULL; s = s->next) {
980: if (s->pstate != SLOT_RUN)
981: continue;
982: if ((s->mode & SIO_PLAY) && (s->buf.used == 0))
983: slot_fill(s);
984: if ((s->mode & SIO_REC) && (s->buf.used == s->buf.len))
985: slot_flush(s);
986: }
1.1 kstailey 987: }
988:
1.146 ratchov 989: static int
990: offline(void)
1.74 ratchov 991: {
1.146 ratchov 992: unsigned int todo;
993: int rate, cmax;
994: struct slot *s;
995:
996: rate = cmax = 0;
997: for (s = slot_list; s != NULL; s = s->next) {
998: if (s->afile.rate > rate)
999: rate = s->afile.rate;
1000: if (s->cmax > cmax)
1001: cmax = s->cmax;
1002: }
1003: dev_sh = NULL;
1004: dev_name = "offline";
1005: dev_mode = SIO_PLAY | SIO_REC;
1006: dev_rate = rate;
1007: dev_bufsz = rate;
1008: dev_round = rate;
1009: dev_pchan = dev_rchan = cmax + 1;
1010: dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
1011: dev_pstate = DEV_STOP;
1012: dev_mmcpos = 0;
1013: for (s = slot_list; s != NULL; s = s->next)
1014: slot_init(s);
1015: for (s = slot_list; s != NULL; s = s->next)
1016: slot_start(s, 0);
1017: for (;;) {
1018: todo = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
1019: if (todo == 0)
1020: break;
1021: slot_list_copy(todo, dev_pchan, dev_pbuf);
1022: slot_list_iodo();
1023: }
1.150 mmcc 1024: free(dev_pbuf);
1.146 ratchov 1025: while (slot_list)
1026: slot_del(slot_list);
1027: return 1;
1.74 ratchov 1028: }
1029:
1.146 ratchov 1030: static int
1031: playrec_cycle(void)
1.84 ratchov 1032: {
1.146 ratchov 1033: unsigned int n, todo;
1034: unsigned char *p;
1035: int pcnt, rcnt;
1036:
1037: #ifdef DEBUG
1038: if (log_level >= 4) {
1039: log_puts(dev_name);
1040: log_puts(": cycle, prime = ");
1041: log_putu(dev_prime);
1042: log_puts("\n");
1043: }
1044: #endif
1045: pcnt = rcnt = 0;
1046: if (dev_mode & SIO_REC) {
1047: if (dev_prime > 0)
1048: dev_prime--;
1049: else {
1050: todo = dev_round * dev_rchan * sizeof(adata_t);
1051: p = (unsigned char *)dev_rbuf;
1052: while (todo > 0) {
1053: n = sio_read(dev_sh, p, todo);
1054: if (n == 0) {
1055: log_puts(dev_name);
1.151 ratchov 1056: log_puts(": failed to read "
1057: "from device\n");
1.146 ratchov 1058: return 0;
1059: }
1060: p += n;
1061: todo -= n;
1062: }
1063: rcnt = slot_list_copy(dev_round, dev_rchan, dev_rbuf);
1064: }
1065: }
1066: if (dev_mode & SIO_PLAY) {
1067: pcnt = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
1068: todo = sizeof(adata_t) * dev_pchan * dev_round;
1069: n = sio_write(dev_sh, dev_pbuf, todo);
1070: if (n == 0) {
1071: log_puts(dev_name);
1072: log_puts(": failed to write to device\n");
1073: return 0;
1074: }
1075: }
1076: slot_list_iodo();
1077: return pcnt > 0 || rcnt > 0;
1.84 ratchov 1078: }
1079:
1.146 ratchov 1080: static void
1081: sigint(int s)
1.22 ratchov 1082: {
1.146 ratchov 1083: if (quit_flag)
1084: _exit(1);
1085: quit_flag = 1;
1.22 ratchov 1086: }
1087:
1.146 ratchov 1088: static int
1089: playrec(char *dev, int mode, int bufsz, char *port)
1.61 ratchov 1090: {
1.146 ratchov 1091: #define MIDIBUFSZ 0x100
1092: unsigned char mbuf[MIDIBUFSZ];
1.61 ratchov 1093: struct sigaction sa;
1.146 ratchov 1094: struct pollfd *pfds;
1095: struct slot *s;
1096: int n, ns, nm, ev;
1097:
1098: if (!dev_open(dev, mode, bufsz, port))
1099: return 0;
1100: n = sio_nfds(dev_sh);
1101: if (dev_mh)
1102: n += mio_nfds(dev_mh);
1103: pfds = xmalloc(n * sizeof(struct pollfd));
1104: for (s = slot_list; s != NULL; s = s->next)
1105: slot_init(s);
1106: if (dev_mh == NULL)
1107: dev_mmcstart();
1108: else {
1109: if (log_level >= 2)
1110: log_puts("ready, waiting for mmc messages\n");
1111: }
1.61 ratchov 1112:
1113: quit_flag = 0;
1114: sigfillset(&sa.sa_mask);
1115: sa.sa_flags = SA_RESTART;
1116: sa.sa_handler = sigint;
1.146 ratchov 1117: sigaction(SIGINT, &sa, NULL);
1118: sigaction(SIGTERM, &sa, NULL);
1119: sigaction(SIGHUP, &sa, NULL);
1120: while (!quit_flag) {
1121: if (dev_pstate == DEV_START) {
1122: ev = 0;
1123: if (mode & SIO_PLAY)
1124: ev |= POLLOUT;
1125: if (mode & SIO_REC)
1126: ev |= POLLIN;
1127: ns = sio_pollfd(dev_sh, pfds, ev);
1128: } else
1129: ns = 0;
1130: if (dev_mh)
1131: nm = mio_pollfd(dev_mh, pfds + ns, POLLIN);
1132: else
1133: nm = 0;
1134: if (poll(pfds, ns + nm, -1) < 0) {
1135: if (errno == EINTR)
1136: continue;
1137: log_puts("poll failed\n");
1138: panic();
1.151 ratchov 1139: }
1.146 ratchov 1140: if (dev_pstate == DEV_START) {
1141: ev = sio_revents(dev_sh, pfds);
1142: if (ev & POLLHUP) {
1143: log_puts(dev);
1144: log_puts(": audio device gone, stopping\n");
1145: break;
1146: }
1147: if (ev & (POLLIN | POLLOUT)) {
1148: if (!playrec_cycle() && dev_mh == NULL)
1149: break;
1150: }
1151: }
1152: if (dev_mh) {
1153: ev = mio_revents(dev_mh, pfds + ns);
1154: if (ev & POLLHUP) {
1155: log_puts(dev_port);
1156: log_puts(": midi port gone, stopping\n");
1157: break;
1158: }
1159: if (ev & POLLIN) {
1160: n = mio_read(dev_mh, mbuf, MIDIBUFSZ);
1161: midi_in(mbuf, n);
1162: }
1163: }
1164: }
1165: sigfillset(&sa.sa_mask);
1166: sa.sa_flags = SA_RESTART;
1167: sa.sa_handler = SIG_DFL;
1168: sigaction(SIGINT, &sa, NULL);
1169: sigaction(SIGTERM, &sa, NULL);
1170: sigaction(SIGHUP, &sa, NULL);
1171:
1172: if (dev_pstate == DEV_START)
1173: dev_mmcstop();
1.150 mmcc 1174: free(pfds);
1.146 ratchov 1175: dev_close();
1176: while (slot_list)
1177: slot_del(slot_list);
1178: return 1;
1179: }
1180:
1181: static int
1182: opt_onoff(char *s, int *flag)
1183: {
1184: if (strcmp("off", s) == 0) {
1185: *flag = 0;
1186: return 1;
1187: }
1188: if (strcmp("on", s) == 0) {
1189: *flag = 1;
1190: return 1;
1191: }
1192: log_puts(s);
1193: log_puts(": on/off expected\n");
1194: return 0;
1195: }
1196:
1197: static int
1198: opt_enc(char *s, struct aparams *par)
1199: {
1200: int len;
1201:
1202: len = aparams_strtoenc(par, s);
1203: if (len == 0 || s[len] != '\0') {
1204: log_puts(s);
1205: log_puts(": bad encoding\n");
1206: return 0;
1207: }
1208: return 1;
1209: }
1210:
1211: static int
1212: opt_hdr(char *s, int *hdr)
1213: {
1214: if (strcmp("auto", s) == 0) {
1215: *hdr = AFILE_HDR_AUTO;
1216: return 1;
1217: }
1218: if (strcmp("raw", s) == 0) {
1219: *hdr = AFILE_HDR_RAW;
1220: return 1;
1221: }
1222: if (strcmp("wav", s) == 0) {
1223: *hdr = AFILE_HDR_WAV;
1224: return 1;
1225: }
1226: if (strcmp("aiff", s) == 0) {
1227: *hdr = AFILE_HDR_AIFF;
1228: return 1;
1229: }
1230: if (strcmp("au", s) == 0) {
1231: *hdr = AFILE_HDR_AU;
1232: return 1;
1233: }
1234: log_puts(s);
1235: log_puts(": bad header type\n");
1236: return 0;
1237: }
1238:
1239: static int
1240: opt_ch(char *s, int *rcmin, int *rcmax)
1241: {
1242: char *next, *end;
1243: long cmin, cmax;
1244:
1245: errno = 0;
1246: cmin = strtol(s, &next, 10);
1247: if (next == s || *next != ':')
1248: goto failed;
1249: cmax = strtol(++next, &end, 10);
1250: if (end == next || *end != '\0')
1251: goto failed;
1252: if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
1253: goto failed;
1254: *rcmin = cmin;
1255: *rcmax = cmax;
1256: return 1;
1257: failed:
1258: log_puts(s);
1259: log_puts(": channel range expected\n");
1260: return 0;
1.61 ratchov 1261: }
1262:
1.146 ratchov 1263: static int
1264: opt_num(char *s, int min, int max, int *num)
1.61 ratchov 1265: {
1.146 ratchov 1266: const char *errstr;
1.61 ratchov 1267:
1.146 ratchov 1268: *num = strtonum(s, min, max, &errstr);
1269: if (errstr) {
1270: log_puts(s);
1271: log_puts(": expected integer between ");
1272: log_puti(min);
1273: log_puts(" and ");
1274: log_puti(max);
1275: log_puts("\n");
1276: return 0;
1277: }
1278: return 1;
1.120 ratchov 1279: }
1280:
1.1 kstailey 1281: int
1.120 ratchov 1282: main(int argc, char **argv)
1.1 kstailey 1283: {
1.146 ratchov 1284: int dup, cmin, cmax, rate, vol, bufsz, hdr, mode;
1285: char *port, *dev;
1286: struct aparams par;
1287: int n_flag, c;
1288:
1289: vol = 127;
1290: dup = 0;
1.120 ratchov 1291: bufsz = 0;
1.146 ratchov 1292: rate = DEFAULT_RATE;
1293: cmin = 0;
1294: cmax = 1;
1295: aparams_init(&par);
1296: hdr = AFILE_HDR_AUTO;
1297: n_flag = 0;
1298: port = NULL;
1299: dev = NULL;
1300: mode = 0;
1.151 ratchov 1301:
1.146 ratchov 1302: while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) {
1.15 ratchov 1303: switch (c) {
1.146 ratchov 1304: case 'b':
1305: if (!opt_num(optarg, 1, RATE_MAX, &bufsz))
1306: return 1;
1.74 ratchov 1307: break;
1.15 ratchov 1308: case 'c':
1.146 ratchov 1309: if (!opt_ch(optarg, &cmin, &cmax))
1310: return 1;
1.15 ratchov 1311: break;
1.146 ratchov 1312: case 'd':
1313: log_level++;
1.15 ratchov 1314: break;
1315: case 'e':
1.146 ratchov 1316: if (!opt_enc(optarg, &par))
1317: return 1;
1.15 ratchov 1318: break;
1.146 ratchov 1319: case 'f':
1320: dev = optarg;
1.15 ratchov 1321: break;
1.146 ratchov 1322: case 'h':
1323: if (!opt_hdr(optarg, &hdr))
1324: return 1;
1.35 ratchov 1325: break;
1.15 ratchov 1326: case 'i':
1.146 ratchov 1327: if (!slot_new(optarg, SIO_PLAY,
1328: &par, hdr, cmin, cmax, rate, dup, vol))
1329: return 1;
1330: mode |= SIO_PLAY;
1.15 ratchov 1331: break;
1.146 ratchov 1332: case 'j':
1333: if (!opt_onoff(optarg, &dup))
1334: return 1;
1.92 ratchov 1335: break;
1.146 ratchov 1336: case 'n':
1337: n_flag = 1;
1.4 millert 1338: break;
1.146 ratchov 1339: case 'o':
1340: if (!slot_new(optarg, SIO_REC,
1341: &par, hdr, cmin, cmax, rate, dup, 0))
1342: return 1;
1343: mode |= SIO_REC;
1.74 ratchov 1344: break;
1.146 ratchov 1345: case 'q':
1346: port = optarg;
1.120 ratchov 1347: break;
1.146 ratchov 1348: case 'r':
1349: if (!opt_num(optarg, RATE_MIN, RATE_MAX, &rate))
1350: return 1;
1.120 ratchov 1351: break;
1.146 ratchov 1352: case 'v':
1353: if (!opt_num(optarg, 0, MIDI_MAXCTL, &vol))
1354: return 1;
1.92 ratchov 1355: break;
1.11 jaredy 1356: default:
1.146 ratchov 1357: goto bad_usage;
1.4 millert 1358: }
1359: }
1360: argc -= optind;
1361: argv += optind;
1.146 ratchov 1362: if (argc != 0) {
1363: bad_usage:
1364: log_puts(usagestr);
1365: return 1;
1366: }
1367: if (n_flag) {
1368: if (dev != NULL || port != NULL) {
1369: log_puts("-f and -q make no sense in off-line mode\n");
1370: return 1;
1.125 ratchov 1371: }
1.146 ratchov 1372: if (mode != (SIO_PLAY | SIO_REC)) {
1373: log_puts("both -i and -o required\n");
1374: return 0;
1375: }
1376: if (!offline())
1377: return 1;
1.125 ratchov 1378: } else {
1.146 ratchov 1379: if (dev == NULL)
1380: dev = SIO_DEVANY;
1381: if (mode == 0) {
1.149 ratchov 1382: log_puts("at least -i or -o required\n");
1.146 ratchov 1383: return 1;
1.151 ratchov 1384: }
1.146 ratchov 1385: if (!playrec(dev, mode, bufsz, port))
1386: return 1;
1.120 ratchov 1387: }
1.61 ratchov 1388: return 0;
1.1 kstailey 1389: }