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