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