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