GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/aucat/aucat.c Lines: 0 739 0.0 %
Date: 2016-12-06 Branches: 0 480 0.0 %

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