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