Bug Summary

File:src/usr.bin/aucat/aucat.c
Warning:line 604, column 3
Value stored to 'ocnt' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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