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