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
72struct 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 */
101unsigned int dev_mode;			/* bitmap of SIO_{PLAY,REC} */
102unsigned int dev_bufsz;			/* device buffer size */
103unsigned int dev_round;			/* device block size */
104int dev_rate;				/* device sample rate (Hz) */
105unsigned int dev_pchan, dev_rchan;	/* play & rec channels count */
106adata_t *dev_pbuf, *dev_rbuf;		/* play & rec buffers */
107struct aparams dev_par;			/* device sample format */
108struct conv dev_enc, dev_dec;		/* format conversions */
109unsigned char *dev_encbuf, *dev_decbuf;	/* buf for format conversions */
110long long dev_pos;			/* last MMC position in frames */
111#define DEV_STOP	0		/* stopped */
112#define DEV_START	1		/* started */
113unsigned int dev_pstate;		/* one of above */
114char *dev_name;				/* device sndio(7) name */
115char *dev_port;				/* control port sndio(7) name */
116struct sio_hdl *dev_sh;			/* device handle */
117struct mio_hdl *dev_mh;			/* MIDI control port handle */
118unsigned int dev_volctl = MIDI_MAXCTL;	/* master volume */
119
120/*
121 * MIDI parser state
122 */
123#define MIDI_MSGMAX	32		/* max size of MIDI msg */
124unsigned char dev_msg[MIDI_MSGMAX];	/* parsed input message */
125unsigned int dev_mst;			/* input MIDI running status */
126unsigned int dev_mused;			/* bytes used in ``msg'' */
127unsigned int dev_midx;			/* current ``msg'' size */
128unsigned int dev_mlen;			/* expected ``msg'' length */
129unsigned int dev_prime;			/* blocks to write to start */
130
131unsigned int log_level = 1;
132volatile sig_atomic_t quit_flag = 0;
133struct slot *slot_list = NULL;
134
135/*
136 * length of voice and common MIDI messages (status byte included)
137 */
138const unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
139const unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
140
141char 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
146static void *
147allocbuf(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
159static void
160slot_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
176static void
177slot_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
197static void
198slot_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
222static int
223slot_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
295static void
296slot_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
397static void
398slot_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
437static void
438slot_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
455static void
456slot_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
481static void
482slot_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
495static void
496play_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
529static void
530play_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 */
560static int
561slot_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
595static void
596rec_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
628static void
629rec_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 */
643static void
644slot_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
674static int
675dev_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
782static void
783dev_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
794static void
795dev_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
814static void
815dev_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 */
842static void
843dev_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 */
866static void
867dev_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 */
889static void
890dev_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
923static void
924dev_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 */
991static void
992midi_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
1035static int
1036slot_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
1063static int
1064slot_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
1079static void
1080slot_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
1096static int
1097offline(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
1141static int
1142playrec_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
1203static void
1204sigint(int s)
1205{
1206	if (quit_flag)
1207		_exit(1);
1208	quit_flag = 1;
1209}
1210
1211static int
1212playrec(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
1310static int
1311opt_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
1326static int
1327opt_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
1340static int
1341opt_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
1368static int
1369opt_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;
1400failed:
1401	log_puts(str);
1402	log_puts(": channel mapping expected\n");
1403	return 0;
1404}
1405
1406static int
1407opt_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;
1438failed:
1439	log_puts(str);
1440	log_puts(": channel count expected\n");
1441	return 0;
1442}
1443
1444static int
1445opt_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
1462static int
1463opt_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
1476int
1477main(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