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