Annotation of src/usr.bin/aucat/aucat.c, Revision 1.153
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.153 ! ratchov 426: static void
! 427: play_filt_resamp(struct slot *s, void *res_in, void *out, int *icnt, int *ocnt)
1.146 ratchov 428: {
429: int i, offs, vol, nch;
430: void *in;
431:
432: if (s->resampbuf) {
1.153 ! ratchov 433: resamp_do(&s->resamp, res_in, s->resampbuf, icnt, ocnt);
1.146 ratchov 434: in = s->resampbuf;
435: } else
436: in = res_in;
437:
438: nch = s->cmap.nch;
439: vol = s->vol / s->join; /* XXX */
1.153 ! ratchov 440: cmap_add(&s->cmap, in, out, vol, *ocnt);
1.146 ratchov 441:
442: offs = 0;
443: for (i = s->join - 1; i > 0; i--) {
444: offs += nch;
1.153 ! ratchov 445: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, *ocnt);
1.146 ratchov 446: }
447: offs = 0;
448: for (i = s->expand - 1; i > 0; i--) {
449: offs += nch;
1.153 ! ratchov 450: cmap_add(&s->cmap, in, (adata_t *)out + offs, vol, *ocnt);
1.146 ratchov 451: }
452: }
453:
1.153 ! ratchov 454: static void
! 455: play_filt_dec(struct slot *s, void *in, void *out, int *icnt, int *ocnt)
1.146 ratchov 456: {
457: void *tmp;
458:
459: tmp = s->convbuf;
460: if (tmp) {
461: switch (s->afile.fmt) {
462: case AFILE_FMT_PCM:
1.153 ! ratchov 463: dec_do(&s->conv, in, tmp, *icnt);
1.146 ratchov 464: break;
465: case AFILE_FMT_ULAW:
1.153 ! ratchov 466: dec_do_ulaw(&s->conv, in, tmp, *icnt, 0);
1.146 ratchov 467: break;
468: case AFILE_FMT_ALAW:
1.153 ! ratchov 469: dec_do_ulaw(&s->conv, in, tmp, *icnt, 1);
1.146 ratchov 470: break;
471: case AFILE_FMT_FLOAT:
1.153 ! ratchov 472: dec_do_float(&s->conv, in, tmp, *icnt);
1.146 ratchov 473: break;
474: }
1.153 ! ratchov 475: } else
! 476: tmp = in;
! 477: play_filt_resamp(s, tmp, out, icnt, ocnt);
1.146 ratchov 478: }
1.108 ratchov 479:
1.120 ratchov 480: /*
1.146 ratchov 481: * Mix as many as possible frames (but not more than a block) from the
482: * slot buffer to the given location. Return the number of frames mixed
483: * in the output buffer
1.120 ratchov 484: */
1.146 ratchov 485: static int
486: slot_mix_badd(struct slot *s, adata_t *odata)
487: {
488: adata_t *idata;
1.153 ! ratchov 489: int len, icnt, ocnt;
1.146 ratchov 490:
1.153 ! ratchov 491: idata = (adata_t *)abuf_rgetblk(&s->buf, &len);
! 492: icnt = len / s->bpf;
! 493: if (icnt > s->round)
! 494: icnt = s->round;
1.146 ratchov 495: #ifdef DEBUG
1.153 ! ratchov 496: if (icnt == 0) {
1.146 ratchov 497: log_puts("slot_mix_badd: not enough data\n");
498: panic();
499: }
1.133 ratchov 500: #endif
1.153 ! ratchov 501: ocnt = dev_round;
! 502: play_filt_dec(s, idata, odata, &icnt, &ocnt);
! 503: abuf_rdiscard(&s->buf, icnt * s->bpf);
! 504: return ocnt;
1.146 ratchov 505: }
506:
1.153 ! ratchov 507: static void
! 508: rec_filt_resamp(struct slot *s, void *in, void *res_out, int *icnt, int *ocnt)
1.146 ratchov 509: {
510: int i, vol, offs, nch;
511: void *out = res_out;
512:
513: out = (s->resampbuf) ? s->resampbuf : res_out;
514:
515: nch = s->cmap.nch;
516: vol = ADATA_UNIT / s->join;
1.153 ! ratchov 517: cmap_copy(&s->cmap, in, out, vol, *icnt);
1.146 ratchov 518:
519: offs = 0;
520: for (i = s->join - 1; i > 0; i--) {
521: offs += nch;
1.153 ! ratchov 522: cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, *icnt);
1.146 ratchov 523: }
524: offs = 0;
525: for (i = s->expand - 1; i > 0; i--) {
526: offs += nch;
1.153 ! ratchov 527: cmap_copy(&s->cmap, in, (adata_t *)out + offs, vol, *icnt);
1.146 ratchov 528: }
1.153 ! ratchov 529: if (s->resampbuf)
! 530: resamp_do(&s->resamp, s->resampbuf, res_out, icnt, ocnt);
! 531: else
! 532: *ocnt = *icnt;
1.146 ratchov 533: }
534:
1.153 ! ratchov 535: static void
! 536: rec_filt_enc(struct slot *s, void *in, void *out, int *icnt, int *ocnt)
1.146 ratchov 537: {
538: void *tmp;
539:
540: tmp = s->convbuf;
1.153 ! ratchov 541: rec_filt_resamp(s, in, tmp ? tmp : out, icnt, ocnt);
1.146 ratchov 542: if (tmp)
1.153 ! ratchov 543: enc_do(&s->conv, tmp, out, *ocnt);
1.146 ratchov 544: }
1.133 ratchov 545:
546: /*
1.146 ratchov 547: * Copy "todo" frames from the given buffer to the slot buffer,
548: * but not more than a block.
1.133 ratchov 549: */
1.146 ratchov 550: static void
551: slot_sub_bcopy(struct slot *s, adata_t *idata, int todo)
552: {
553: adata_t *odata;
1.153 ! ratchov 554: int len, icnt, ocnt;
1.146 ratchov 555:
1.153 ! ratchov 556: odata = (adata_t *)abuf_wgetblk(&s->buf, &len);
1.146 ratchov 557: #ifdef DEBUG
1.153 ! ratchov 558: if (len < s->round * s->bpf) {
1.146 ratchov 559: log_puts("slot_sub_bcopy: not enough space\n");
560: panic();
561: }
1.120 ratchov 562: #endif
1.153 ! ratchov 563: icnt = todo;
! 564: ocnt = len / s->bpf;
! 565: rec_filt_enc(s, idata, odata, &icnt, &ocnt);
! 566: abuf_wcommit(&s->buf, ocnt * s->bpf);
1.146 ratchov 567: }
568:
569: static int
570: dev_open(char *dev, int mode, int bufsz, char *port)
571: {
572: int rate, pmax, rmax;
573: struct sio_par par;
574: struct slot *s;
575:
576: if (port) {
577: dev_port = port;
578: dev_mh = mio_open(dev_port, MIO_IN, 0);
579: if (dev_mh == NULL) {
580: log_puts(port);
581: log_puts(": couldn't open midi port\n");
582: return 0;
583: }
584: } else
585: dev_mh = NULL;
586:
587: dev_name = dev;
588: dev_sh = sio_open(dev, mode, 0);
589: if (dev_sh == NULL) {
590: log_puts(dev_name);
591: log_puts(": couldn't open audio device\n");
592: return 0;
593: }
594:
595: rate = pmax = rmax = 0;
596: for (s = slot_list; s != NULL; s = s->next) {
597: if (s->afile.rate > rate)
598: rate = s->afile.rate;
599: if (s->mode == SIO_PLAY) {
600: if (s->cmax > pmax)
601: pmax = s->cmax;
602: }
603: if (s->mode == SIO_REC) {
604: if (s->cmax > rmax)
605: rmax = s->cmax;
606: }
607: }
608: sio_initpar(&par);
609: par.bits = ADATA_BITS;
610: par.bps = sizeof(adata_t);
611: par.msb = 0;
612: par.le = SIO_LE_NATIVE;
613: if (mode & SIO_PLAY)
614: par.pchan = pmax + 1;
615: if (mode & SIO_REC)
616: par.rchan = rmax + 1;
617: par.appbufsz = bufsz > 0 ? bufsz : rate * DEFAULT_BUFSZ_MS / 1000;
618: if (!sio_setpar(dev_sh, &par) || !sio_getpar(dev_sh, &par)) {
619: log_puts(dev_name);
620: log_puts(": couldn't set audio params\n");
621: return 0;
622: }
623: if (par.bits != ADATA_BITS ||
624: par.bps != sizeof(adata_t) ||
1.152 ratchov 625: (par.bps > 1 && par.le != SIO_LE_NATIVE) ||
626: (par.bps * 8 > par.bits && par.msb)) {
1.146 ratchov 627: log_puts(dev_name);
628: log_puts(": unsupported audio params\n");
629: return 0;
630: }
631: dev_mode = mode;
632: dev_rate = par.rate;
633: dev_bufsz = par.bufsz;
634: dev_round = par.round;
635: if (mode & SIO_PLAY) {
636: dev_pchan = par.pchan;
637: dev_pbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
638: }
639: if (mode & SIO_REC) {
640: dev_rchan = par.rchan;
641: dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round);
642: }
643: dev_mmcpos = 0;
644: dev_pstate = DEV_STOP;
645: if (log_level >= 2) {
646: log_puts(dev_name);
647: log_puts(": ");
648: log_putu(dev_rate);
649: log_puts("Hz");
650: if (dev_mode & SIO_PLAY) {
651: log_puts(", play 0:");
652: log_puti(dev_pchan - 1);
653: }
654: if (dev_mode & SIO_REC) {
655: log_puts(", rec 0:");
656: log_puti(dev_rchan - 1);
657: }
658: log_puts(", ");
659: log_putu(dev_bufsz / dev_round);
660: log_puts(" blocks of ");
661: log_putu(dev_round);
662: log_puts(" frames\n");
663: }
664: return 1;
665: }
1.120 ratchov 666:
1.146 ratchov 667: static void
668: dev_close(void)
669: {
670: sio_close(dev_sh);
671: if (dev_mh)
672: mio_close(dev_mh);
673: if (dev_mode & SIO_PLAY)
1.150 mmcc 674: free(dev_pbuf);
1.146 ratchov 675: if (dev_mode & SIO_REC)
1.150 mmcc 676: free(dev_rbuf);
1.146 ratchov 677: }
678:
679: static void
680: dev_master(int val)
681: {
682: struct slot *s;
683: int mastervol, slotvol;
1.143 ratchov 684:
1.146 ratchov 685: mastervol = MIDI_TO_ADATA(dev_volctl);
686: for (s = slot_list; s != NULL; s = s->next) {
687: slotvol = MIDI_TO_ADATA(val);
688: s->vol = ADATA_MUL(mastervol, slotvol);
689: }
1.78 ratchov 690: #ifdef DEBUG
1.146 ratchov 691: if (log_level >= 3) {
692: log_puts("master volume set to ");
693: log_putu(val);
694: log_puts("\n");
695: }
1.78 ratchov 696: #endif
1.146 ratchov 697: }
1.7 deraadt 698:
1.146 ratchov 699: static void
700: dev_slotvol(int midich, int val)
701: {
702: struct slot *s;
703: int mastervol, slotvol;
704:
705: for (s = slot_list; s != NULL; s = s->next) {
706: if (midich == 0) {
707: mastervol = MIDI_TO_ADATA(dev_volctl);
708: slotvol = MIDI_TO_ADATA(val);
709: s->vol = ADATA_MUL(mastervol, slotvol);
710: #ifdef DEBUG
711: if (log_level >= 3) {
712: slot_log(s);
713: log_puts(": volume set to ");
714: log_putu(val);
715: log_puts("\n");
716: }
717: #endif
718: break;
719: }
720: }
721: }
1.129 ratchov 722:
1.28 ratchov 723: /*
1.146 ratchov 724: * start all slots simultaneously
1.28 ratchov 725: */
1.146 ratchov 726: static void
727: dev_mmcstart(void)
1.28 ratchov 728: {
1.146 ratchov 729: struct slot *s;
730:
731: if (dev_pstate == DEV_STOP) {
732: dev_pstate = DEV_START;
733: for (s = slot_list; s != NULL; s = s->next)
734: slot_start(s, dev_mmcpos);
735: dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0;
736: sio_start(dev_sh);
737: if (log_level >= 2)
738: log_puts("started\n");
739: } else {
740: #ifdef DEBUG
741: if (log_level >= 3)
742: log_puts("ignoring mmc start\n");
743: #endif
744: }
1.28 ratchov 745: }
1.22 ratchov 746:
1.146 ratchov 747: /*
748: * stop all slots simultaneously
749: */
750: static void
751: dev_mmcstop(void)
752: {
753: struct slot *s;
754:
755: if (dev_pstate == DEV_START) {
756: dev_pstate = DEV_STOP;
757: for (s = slot_list; s != NULL; s = s->next)
758: slot_stop(s);
759: sio_stop(dev_sh);
760: if (log_level >= 2)
761: log_puts("stopped\n");
762: } else {
1.78 ratchov 763: #ifdef DEBUG
1.146 ratchov 764: if (log_level >= 3)
765: log_puts("ignored mmc stop\n");
766: #endif
767: }
768: }
769:
1.78 ratchov 770: /*
1.146 ratchov 771: * relocate all slots simultaneously
1.78 ratchov 772: */
1.146 ratchov 773: static void
774: dev_mmcloc(unsigned int mmc)
1.78 ratchov 775: {
1.146 ratchov 776: if (dev_mmcpos == mmc)
777: return;
778: dev_mmcpos = mmc;
779: if (log_level >= 2) {
780: log_puts("relocated to ");
781: log_putu((dev_mmcpos / (MTC_SEC * 3600)) % 24);
782: log_puts(":");
783: log_putu((dev_mmcpos / (MTC_SEC * 60)) % 60);
784: log_puts(":");
785: log_putu((dev_mmcpos / (MTC_SEC)) % 60);
786: log_puts(".");
787: log_putu((dev_mmcpos / (MTC_SEC / 100)) % 100);
788: log_puts("\n");
789: }
790: if (dev_pstate == DEV_START) {
791: dev_mmcstop();
792: dev_mmcstart();
793: }
794: }
795:
796: static void
797: dev_imsg(unsigned char *msg, unsigned int len)
798: {
799: struct sysex *x;
800: unsigned int fps, chan;
801:
802: if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
803: chan = msg[0] & MIDI_CHANMASK;
804: dev_slotvol(chan, msg[2]);
805: return;
806: }
807: x = (struct sysex *)msg;
808: if (x->start != SYSEX_START)
809: return;
810: if (len < SYSEX_SIZE(empty))
811: return;
812: if (x->type != SYSEX_TYPE_RT)
813: return;
814: if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
815: if (len == SYSEX_SIZE(master))
816: dev_master(x->u.master.coarse);
817: return;
818: }
819: if (x->id0 != SYSEX_MMC)
820: return;
821: switch (x->id1) {
822: case SYSEX_MMC_STOP:
823: if (len != SYSEX_SIZE(stop))
824: return;
825: dev_mmcstop();
826: break;
827: case SYSEX_MMC_START:
828: if (len != SYSEX_SIZE(start))
829: return;
830: dev_mmcstart();
831: break;
832: case SYSEX_MMC_LOC:
833: if (len != SYSEX_SIZE(loc) ||
834: x->u.loc.len != SYSEX_MMC_LOC_LEN ||
835: x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
836: return;
837: switch (x->u.loc.hr >> 5) {
838: case MTC_FPS_24:
839: fps = 24;
840: break;
841: case MTC_FPS_25:
842: fps = 25;
843: break;
844: case MTC_FPS_30:
845: fps = 30;
846: break;
847: default:
848: dev_mmcstop();
849: return;
850: }
851: dev_mmcloc((x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
852: x->u.loc.min * 60 * MTC_SEC +
853: x->u.loc.sec * MTC_SEC +
854: x->u.loc.fr * (MTC_SEC / fps) +
855: x->u.loc.cent * (MTC_SEC / 100 / fps));
856: break;
857: }
1.78 ratchov 858: }
859:
860: /*
1.149 ratchov 861: * parse the given data chunk and call imsg() for each message
1.78 ratchov 862: */
1.146 ratchov 863: static void
864: midi_in(unsigned char *idata, int icount)
1.78 ratchov 865: {
1.146 ratchov 866: int i;
867: unsigned char c;
868:
869: for (i = 0; i < icount; i++) {
870: c = *idata++;
871: if (c >= 0xf8) {
1.149 ratchov 872: /* we don't use real-time events */
1.146 ratchov 873: } else if (c == SYSEX_END) {
874: if (dev_mst == SYSEX_START) {
875: dev_msg[dev_midx++] = c;
876: dev_imsg(dev_msg, dev_midx);
877: }
878: dev_mst = 0;
879: dev_midx = 0;
880: } else if (c >= 0xf0) {
881: dev_msg[0] = c;
882: dev_mlen = common_len[c & 7];
883: dev_mst = c;
884: dev_midx = 1;
885: } else if (c >= 0x80) {
886: dev_msg[0] = c;
887: dev_mlen = voice_len[(c >> 4) & 7];
888: dev_mst = c;
889: dev_midx = 1;
890: } else if (dev_mst) {
891: if (dev_midx == 0 && dev_mst != SYSEX_START)
892: dev_msg[dev_midx++] = dev_mst;
893: dev_msg[dev_midx++] = c;
894: if (dev_midx == dev_mlen) {
895: dev_imsg(dev_msg, dev_midx);
896: if (dev_mst >= 0xf0)
897: dev_mst = 0;
898: dev_midx = 0;
899: } else if (dev_midx == MIDI_MSGMAX) {
900: /* sysex too long */
901: dev_mst = 0;
902: }
903: }
904: }
1.78 ratchov 905: }
1.15 ratchov 906:
1.146 ratchov 907: static int
908: slot_list_mix(unsigned int round, unsigned int pchan, adata_t *pbuf)
1.15 ratchov 909: {
1.146 ratchov 910: unsigned int done, n;
911: struct slot *s;
1.13 uwe 912:
1.146 ratchov 913: memset(pbuf, 0, pchan * round * sizeof(adata_t));
914: done = 0;
915: for (s = slot_list; s != NULL; s = s->next) {
916: if (s->pstate == SLOT_INIT || !(s->mode & SIO_PLAY))
917: continue;
918: if (s->pstate == SLOT_STOP && s->buf.used < s->bpf) {
919: #ifdef DEBUG
920: if (log_level >= 3) {
921: slot_log(s);
922: log_puts(": drained, done\n");
923: }
924: #endif
1.148 ratchov 925: slot_stop(s);
1.146 ratchov 926: continue;
927: }
928: n = slot_mix_badd(s, dev_pbuf);
929: if (n > done)
930: done = n;
931: }
932: return done;
1.15 ratchov 933: }
1.13 uwe 934:
1.146 ratchov 935: static int
936: slot_list_copy(unsigned int count, unsigned int rchan, adata_t *rbuf)
1.15 ratchov 937: {
1.146 ratchov 938: unsigned int done;
939: struct slot *s;
1.28 ratchov 940:
1.146 ratchov 941: done = 0;
942: for (s = slot_list; s != NULL; s = s->next) {
943: if (s->pstate == SLOT_INIT || !(s->mode & SIO_REC))
944: continue;
945: slot_sub_bcopy(s, rbuf, count);
946: done = count;
947: }
948: return done;
1.15 ratchov 949: }
1.4 millert 950:
1.146 ratchov 951: static void
952: slot_list_iodo(void)
1.15 ratchov 953: {
1.146 ratchov 954: struct slot *s;
955:
956: for (s = slot_list; s != NULL; s = s->next) {
957: if (s->pstate != SLOT_RUN)
958: continue;
959: if ((s->mode & SIO_PLAY) && (s->buf.used == 0))
960: slot_fill(s);
961: if ((s->mode & SIO_REC) && (s->buf.used == s->buf.len))
962: slot_flush(s);
963: }
1.1 kstailey 964: }
965:
1.146 ratchov 966: static int
967: offline(void)
1.74 ratchov 968: {
1.146 ratchov 969: unsigned int todo;
970: int rate, cmax;
971: struct slot *s;
972:
973: rate = cmax = 0;
974: for (s = slot_list; s != NULL; s = s->next) {
975: if (s->afile.rate > rate)
976: rate = s->afile.rate;
977: if (s->cmax > cmax)
978: cmax = s->cmax;
979: }
980: dev_sh = NULL;
981: dev_name = "offline";
982: dev_mode = SIO_PLAY | SIO_REC;
983: dev_rate = rate;
984: dev_bufsz = rate;
985: dev_round = rate;
986: dev_pchan = dev_rchan = cmax + 1;
987: dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
988: dev_pstate = DEV_STOP;
989: dev_mmcpos = 0;
990: for (s = slot_list; s != NULL; s = s->next)
991: slot_init(s);
992: for (s = slot_list; s != NULL; s = s->next)
993: slot_start(s, 0);
994: for (;;) {
995: todo = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
996: if (todo == 0)
997: break;
998: slot_list_copy(todo, dev_pchan, dev_pbuf);
999: slot_list_iodo();
1000: }
1.150 mmcc 1001: free(dev_pbuf);
1.146 ratchov 1002: while (slot_list)
1003: slot_del(slot_list);
1004: return 1;
1.74 ratchov 1005: }
1006:
1.146 ratchov 1007: static int
1008: playrec_cycle(void)
1.84 ratchov 1009: {
1.146 ratchov 1010: unsigned int n, todo;
1011: unsigned char *p;
1012: int pcnt, rcnt;
1013:
1014: #ifdef DEBUG
1015: if (log_level >= 4) {
1016: log_puts(dev_name);
1017: log_puts(": cycle, prime = ");
1018: log_putu(dev_prime);
1019: log_puts("\n");
1020: }
1021: #endif
1022: pcnt = rcnt = 0;
1023: if (dev_mode & SIO_REC) {
1024: if (dev_prime > 0)
1025: dev_prime--;
1026: else {
1027: todo = dev_round * dev_rchan * sizeof(adata_t);
1028: p = (unsigned char *)dev_rbuf;
1029: while (todo > 0) {
1030: n = sio_read(dev_sh, p, todo);
1031: if (n == 0) {
1032: log_puts(dev_name);
1.151 ratchov 1033: log_puts(": failed to read "
1034: "from device\n");
1.146 ratchov 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();
1.151 ratchov 1116: }
1.146 ratchov 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();
1.150 mmcc 1151: free(pfds);
1.146 ratchov 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;
1.151 ratchov 1278:
1.146 ratchov 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) {
1.149 ratchov 1359: log_puts("at least -i or -o required\n");
1.146 ratchov 1360: return 1;
1.151 ratchov 1361: }
1.146 ratchov 1362: if (!playrec(dev, mode, bufsz, port))
1363: return 1;
1.120 ratchov 1364: }
1.61 ratchov 1365: return 0;
1.1 kstailey 1366: }