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