Annotation of src/usr.bin/aucat/wav.c, Revision 1.27
1.7 ratchov 1: /*
2: * Copyright (c) 2008 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:
1.26 ratchov 17: #include <fcntl.h>
1.1 ratchov 18: #include <stdlib.h>
1.10 ratchov 19: #include <stdio.h>
1.26 ratchov 20: #include <string.h>
1.10 ratchov 21: #include <unistd.h>
1.1 ratchov 22:
1.10 ratchov 23: #include "abuf.h"
24: #include "aproc.h"
1.1 ratchov 25: #include "conf.h"
1.10 ratchov 26: #include "dev.h"
1.15 ratchov 27: #include "midi.h"
1.1 ratchov 28: #include "wav.h"
1.15 ratchov 29: #include "opt.h"
1.11 ratchov 30: #ifdef DEBUG
31: #include "dbg.h"
32: #endif
1.1 ratchov 33:
1.6 ratchov 34: short wav_ulawmap[256] = {
35: -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
36: -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
37: -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
38: -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
39: -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
40: -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
41: -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
42: -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
43: -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
44: -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
45: -876, -844, -812, -780, -748, -716, -684, -652,
46: -620, -588, -556, -524, -492, -460, -428, -396,
47: -372, -356, -340, -324, -308, -292, -276, -260,
48: -244, -228, -212, -196, -180, -164, -148, -132,
49: -120, -112, -104, -96, -88, -80, -72, -64,
50: -56, -48, -40, -32, -24, -16, -8, 0,
51: 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
52: 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
53: 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
54: 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
55: 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
56: 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
57: 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
58: 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
59: 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
60: 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
61: 876, 844, 812, 780, 748, 716, 684, 652,
62: 620, 588, 556, 524, 492, 460, 428, 396,
63: 372, 356, 340, 324, 308, 292, 276, 260,
64: 244, 228, 212, 196, 180, 164, 148, 132,
65: 120, 112, 104, 96, 88, 80, 72, 64,
66: 56, 48, 40, 32, 24, 16, 8, 0
67: };
68:
69: short wav_alawmap[256] = {
70: -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
71: -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
72: -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
73: -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
74: -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
75: -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
76: -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
77: -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
78: -344, -328, -376, -360, -280, -264, -312, -296,
79: -472, -456, -504, -488, -408, -392, -440, -424,
80: -88, -72, -120, -104, -24, -8, -56, -40,
81: -216, -200, -248, -232, -152, -136, -184, -168,
82: -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
83: -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
84: -688, -656, -752, -720, -560, -528, -624, -592,
85: -944, -912, -1008, -976, -816, -784, -880, -848,
86: 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
87: 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
88: 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
89: 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
90: 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
91: 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
92: 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
93: 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
94: 344, 328, 376, 360, 280, 264, 312, 296,
95: 472, 456, 504, 488, 408, 392, 440, 424,
96: 88, 72, 120, 104, 24, 8, 56, 40,
97: 216, 200, 248, 232, 152, 136, 184, 168,
98: 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
99: 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
100: 688, 656, 752, 720, 560, 528, 624, 592,
101: 944, 912, 1008, 976, 816, 784, 880, 848
102: };
103:
1.1 ratchov 104: /*
1.7 ratchov 105: * Max data of a .wav file. The total file size must be smaller than
1.1 ratchov 106: * 2^31, and we also have to leave some space for the headers (around 40
1.7 ratchov 107: * bytes).
1.3 ratchov 108: */
1.1 ratchov 109: #define WAV_DATAMAX (0x7fff0000)
110:
111: struct fileops wav_ops = {
112: "wav",
113: sizeof(struct wav),
114: wav_close,
115: wav_read,
116: wav_write,
117: NULL, /* start */
118: NULL, /* stop */
119: pipe_nfds,
120: pipe_pollfd,
121: pipe_revents
122: };
123:
1.27 ! ratchov 124: struct wav *wav_list = NULL;
! 125:
1.10 ratchov 126: int rwav_in(struct aproc *, struct abuf *);
127: int rwav_out(struct aproc *, struct abuf *);
128: void rwav_eof(struct aproc *, struct abuf *);
129: void rwav_hup(struct aproc *, struct abuf *);
130: void rwav_done(struct aproc *);
1.15 ratchov 131: struct aproc *rwav_new(struct file *);
1.10 ratchov 132:
133: int wwav_in(struct aproc *, struct abuf *);
134: int wwav_out(struct aproc *, struct abuf *);
135: void wwav_eof(struct aproc *, struct abuf *);
136: void wwav_hup(struct aproc *, struct abuf *);
137: void wwav_done(struct aproc *);
1.15 ratchov 138: struct aproc *wwav_new(struct file *);
139:
140: void wav_setvol(void *, unsigned);
141: void wav_startreq(void *);
142: void wav_stopreq(void *);
143: void wav_locreq(void *, unsigned);
1.20 ratchov 144: void wav_quitreq(void *);
1.15 ratchov 145:
146: struct ctl_ops ctl_wavops = {
147: wav_setvol,
148: wav_startreq,
149: wav_stopreq,
1.20 ratchov 150: wav_locreq,
151: wav_quitreq
1.15 ratchov 152: };
1.10 ratchov 153:
154: struct aproc_ops rwav_ops = {
155: "rwav",
156: rwav_in,
157: rwav_out,
1.15 ratchov 158: rfile_eof,
159: rfile_hup,
1.10 ratchov 160: NULL, /* newin */
161: NULL, /* newout */
162: NULL, /* ipos */
163: NULL, /* opos */
164: rwav_done
165: };
166:
167: struct aproc_ops wwav_ops = {
168: "wwav",
169: wwav_in,
170: wwav_out,
1.15 ratchov 171: wfile_eof,
172: wfile_hup,
1.10 ratchov 173: NULL, /* newin */
174: NULL, /* newout */
175: NULL, /* ipos */
176: NULL, /* opos */
177: wwav_done
178: };
179:
1.15 ratchov 180: #ifdef DEBUG
181: /*
182: * print the given wav structure
183: */
184: void
185: wav_dbg(struct wav *f)
186: {
1.27 ! ratchov 187: static char *pstates[] = { "cfg", "ini", "sta", "rdy", "run", "mid" };
1.20 ratchov 188: struct aproc *midi = f->dev ? f->dev->midi : NULL;
1.15 ratchov 189:
190: dbg_puts("wav(");
1.20 ratchov 191: if (f->slot >= 0 && APROC_OK(midi)) {
192: dbg_puts(midi->u.ctl.slot[f->slot].name);
193: dbg_putu(midi->u.ctl.slot[f->slot].unit);
1.15 ratchov 194: } else
195: dbg_puts(f->pipe.file.name);
196: dbg_puts(")/");
197: dbg_puts(pstates[f->pstate]);
198: }
199: #endif
200:
201: /*
202: * convert ``count'' samples using the given char->short map
203: */
204: void
205: wav_conv(unsigned char *data, unsigned count, short *map)
1.13 ratchov 206: {
1.15 ratchov 207: unsigned i;
208: unsigned char *iptr;
1.23 ratchov 209: adata_t *optr;
1.13 ratchov 210:
1.15 ratchov 211: iptr = data + count;
1.23 ratchov 212: optr = (adata_t *)data + count;
1.15 ratchov 213: for (i = count; i > 0; i--) {
214: --optr;
215: --iptr;
1.23 ratchov 216: *optr = (adata_t)(map[*iptr]) << (ADATA_BITS - 16);
1.15 ratchov 217: }
1.13 ratchov 218: }
219:
1.15 ratchov 220: /*
221: * read method of the file structure
222: */
223: unsigned
224: wav_read(struct file *file, unsigned char *data, unsigned count)
1.10 ratchov 225: {
1.15 ratchov 226: struct wav *f = (struct wav *)file;
227: unsigned n;
228:
229: if (f->map)
1.23 ratchov 230: count /= sizeof(adata_t);
1.15 ratchov 231: if (f->rbytes >= 0 && count > f->rbytes) {
232: count = f->rbytes; /* file->rbytes fits in count */
233: if (count == 0) {
234: #ifdef DEBUG
235: if (debug_level >= 3) {
236: wav_dbg(f);
237: dbg_puts(": read complete\n");
238: }
239: #endif
1.20 ratchov 240: if (!f->mmc)
1.15 ratchov 241: file_eof(&f->pipe.file);
242: return 0;
243: }
244: }
245: n = pipe_read(file, data, count);
246: if (n == 0)
1.14 ratchov 247: return 0;
1.15 ratchov 248: if (f->rbytes >= 0)
249: f->rbytes -= n;
250: if (f->map) {
251: wav_conv(data, n, f->map);
1.23 ratchov 252: n *= sizeof(adata_t);
1.15 ratchov 253: }
254: return n;
255: }
256:
257: /*
258: * write method of the file structure
259: */
260: unsigned
261: wav_write(struct file *file, unsigned char *data, unsigned count)
262: {
263: struct wav *f = (struct wav *)file;
264: unsigned n;
265:
266: if (f->wbytes >= 0 && count > f->wbytes) {
267: count = f->wbytes; /* wbytes fits in count */
268: if (count == 0) {
269: #ifdef DEBUG
270: if (debug_level >= 3) {
271: wav_dbg(f);
272: dbg_puts(": write complete\n");
273: }
274: #endif
275: file_hup(&f->pipe.file);
276: return 0;
277: }
278: }
279: n = pipe_write(file, data, count);
280: if (f->wbytes >= 0)
281: f->wbytes -= n;
282: f->endpos += n;
283: return n;
284: }
285:
286: /*
287: * close method of the file structure
288: */
289: void
290: wav_close(struct file *file)
291: {
1.27 ! ratchov 292: struct wav *f = (struct wav *)file, **pf;
1.15 ratchov 293:
294: if (f->mode & MODE_RECMASK) {
295: pipe_trunc(&f->pipe.file, f->endpos);
296: if (f->hdr == HDR_WAV) {
297: wav_writehdr(f->pipe.fd,
298: &f->hpar,
299: &f->startpos,
300: f->endpos - f->startpos);
301: }
302: }
303: pipe_close(file);
1.27 ! ratchov 304: if (f->pstate != WAV_CFG)
1.20 ratchov 305: dev_unref(f->dev);
1.27 ! ratchov 306: for (pf = &wav_list; *pf != f; pf = &(*pf)->next) {
! 307: #ifdef DEBUG
! 308: if (*pf == NULL) {
! 309: dbg_puts("wav_close: not on list\n");
! 310: dbg_panic();
! 311: }
! 312: #endif
1.20 ratchov 313: }
1.27 ! ratchov 314: *pf = f->next;
1.10 ratchov 315: }
316:
1.15 ratchov 317: /*
318: * attach play (rec) abuf structure to the device and
319: * switch to the ``RUN'' state; the play abug must not be empty
320: */
1.14 ratchov 321: int
1.15 ratchov 322: wav_attach(struct wav *f, int force)
1.10 ratchov 323: {
1.15 ratchov 324: struct abuf *rbuf = NULL, *wbuf = NULL;
1.20 ratchov 325: struct dev *d = f->dev;
1.13 ratchov 326:
1.15 ratchov 327: if (f->mode & MODE_PLAY)
1.17 ratchov 328: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.15 ratchov 329: if (f->mode & MODE_RECMASK)
1.17 ratchov 330: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.15 ratchov 331: f->pstate = WAV_RUN;
332: #ifdef DEBUG
333: if (debug_level >= 3) {
334: wav_dbg(f);
335: dbg_puts(": attaching\n");
336: }
337: #endif
1.18 ratchov 338:
339: /*
340: * start the device (dev_getpos() and dev_attach() must
341: * be called on a started device
342: */
1.20 ratchov 343: dev_wakeup(d);
1.18 ratchov 344:
1.20 ratchov 345: dev_attach(d, f->pipe.file.name, f->mode,
346: rbuf, &f->hpar, f->join ? d->opar.cmax - d->opar.cmin + 1 : 0,
347: wbuf, &f->hpar, f->join ? d->ipar.cmax - d->ipar.cmin + 1 : 0,
1.16 ratchov 348: f->xrun, f->maxweight);
1.15 ratchov 349: if (f->mode & MODE_PLAY)
1.20 ratchov 350: dev_setvol(d, rbuf, MIDI_TO_ADATA(f->vol));
1.14 ratchov 351: return 1;
1.13 ratchov 352: }
353:
1.15 ratchov 354: /*
1.27 ! ratchov 355: * allocate buffers, so client can start filling write-end.
! 356: */
! 357: void
! 358: wav_midiattach(struct wav *f)
! 359: {
! 360: struct abuf *rbuf = NULL, *wbuf = NULL;
! 361:
! 362: if (f->mode & MODE_MIDIOUT) {
! 363: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
! 364: aproc_setout(f->pipe.file.rproc, rbuf);
! 365: }
! 366: if (f->mode & MODE_MIDIIN) {
! 367: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
! 368: aproc_setin(f->pipe.file.wproc, wbuf);
! 369: }
! 370: f->pstate = WAV_MIDI;
! 371: dev_midiattach(f->dev, rbuf, wbuf);
! 372: }
! 373:
! 374: /*
1.15 ratchov 375: * allocate the play (rec) abuf structure; if this is a
376: * file to record, then attach it to the device
377: *
378: * XXX: buffer size should be larger than dev_bufsz, because
379: * in non-server mode we don't prime play buffers with
380: * silence
381: */
1.14 ratchov 382: void
1.15 ratchov 383: wav_allocbuf(struct wav *f)
1.13 ratchov 384: {
1.15 ratchov 385: struct abuf *buf;
1.20 ratchov 386: struct dev *d = f->dev;
1.15 ratchov 387: unsigned nfr;
1.13 ratchov 388:
1.15 ratchov 389: f->pstate = WAV_START;
390: if (f->mode & MODE_PLAY) {
1.20 ratchov 391: nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
1.15 ratchov 392: buf = abuf_new(nfr, &f->hpar);
393: aproc_setout(f->pipe.file.rproc, buf);
394: abuf_fill(buf);
395: if (!ABUF_WOK(buf) || (f->pipe.file.state & FILE_EOF))
396: f->pstate = WAV_READY;
397: }
398: if (f->mode & MODE_RECMASK) {
1.20 ratchov 399: nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
1.15 ratchov 400: buf = abuf_new(nfr, &f->hpar);
401: aproc_setin(f->pipe.file.wproc, buf);
402: f->pstate = WAV_READY;
403: }
404: #ifdef DEBUG
405: if (debug_level >= 3) {
406: wav_dbg(f);
407: dbg_puts(": allocating buffers\n");
408: }
409: #endif
1.20 ratchov 410: if (f->pstate == WAV_READY && ctl_slotstart(d->midi, f->slot))
1.15 ratchov 411: (void)wav_attach(f, 0);
1.13 ratchov 412: }
413:
1.15 ratchov 414: /*
415: * free abuf structure and switch to the ``INIT'' state
416: */
1.13 ratchov 417: void
1.15 ratchov 418: wav_freebuf(struct wav *f)
1.10 ratchov 419: {
1.15 ratchov 420: struct abuf *rbuf = NULL, *wbuf = NULL;
421:
422: if (f->mode & MODE_PLAY)
1.17 ratchov 423: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.15 ratchov 424: if (f->mode & MODE_RECMASK)
1.17 ratchov 425: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.15 ratchov 426: f->pstate = WAV_INIT;
427: #ifdef DEBUG
428: if (debug_level >= 3) {
429: wav_dbg(f);
430: dbg_puts(": freeing buffers\n");
431: }
432: #endif
433: if (rbuf || wbuf)
1.20 ratchov 434: ctl_slotstop(f->dev->midi, f->slot);
1.15 ratchov 435: if (rbuf)
436: abuf_eof(rbuf);
437: if (wbuf)
438: abuf_hup(wbuf);
1.10 ratchov 439: }
440:
1.15 ratchov 441: /*
442: * switch to the ``INIT'' state performing
443: * necessary actions to reach it
444: */
1.10 ratchov 445: void
1.15 ratchov 446: wav_reset(struct wav *f)
1.10 ratchov 447: {
1.15 ratchov 448: switch (f->pstate) {
449: case WAV_START:
450: case WAV_READY:
1.20 ratchov 451: if (ctl_slotstart(f->dev->midi, f->slot))
1.15 ratchov 452: (void)wav_attach(f, 1);
453: /* PASSTHROUGH */
454: case WAV_RUN:
455: wav_freebuf(f);
456: /* PASSTHROUGH */
457: case WAV_INIT:
458: /* nothing yet */
459: break;
1.27 ! ratchov 460: case WAV_MIDI:
! 461: dbg_puts("wav_reset: in midi mode\n");
! 462: dbg_panic();
1.15 ratchov 463: }
1.10 ratchov 464: }
465:
1.15 ratchov 466: /*
467: * terminate the wav reader/writer
468: */
469: void
470: wav_exit(struct wav *f)
1.10 ratchov 471: {
1.20 ratchov 472: /* XXX: call file_close() ? */
1.27 ! ratchov 473: if (f->mode & (MODE_PLAY | MODE_MIDIOUT)) {
1.15 ratchov 474: aproc_del(f->pipe.file.rproc);
1.27 ! ratchov 475: } else if (f->mode & (MODE_RECMASK | MODE_MIDIIN)) {
1.15 ratchov 476: aproc_del(f->pipe.file.wproc);
477: }
1.10 ratchov 478: }
479:
1.15 ratchov 480: /*
1.27 ! ratchov 481: * allocate the device
! 482: */
! 483: int
! 484: wav_init(struct wav *f)
! 485: {
! 486: if (!dev_ref(f->dev)) {
! 487: wav_exit(f);
! 488: return 0;
! 489: }
! 490: if (!f->mmc)
! 491: f->dev->autostart = 1;
! 492: if (f->mode & MODE_MIDIMASK) {
! 493: wav_midiattach(f);
! 494: return 1;
! 495: }
! 496: f->slot = ctl_slotnew(f->dev->midi, "wav", &ctl_wavops, f, 1);
! 497: f->pstate = WAV_INIT;
! 498: if ((f->mode & f->dev->mode) != f->mode) {
! 499: #ifdef DEBUG
! 500: if (debug_level >= 1) {
! 501: wav_dbg(f);
! 502: dbg_puts(": ");
! 503: dbg_puts(": operation not supported by device\n");
! 504: }
! 505: #endif
! 506: wav_exit(f);
! 507: return 0;
! 508: }
! 509: wav_allocbuf(f);
! 510: return 1;
! 511: }
! 512:
! 513: /*
1.15 ratchov 514: * seek to f->mmcpos and prepare to start, close
515: * the file on error.
516: */
517: int
518: wav_seekmmc(struct wav *f)
1.10 ratchov 519: {
520: /*
1.15 ratchov 521: * don't go beyond the end-of-file, if so
522: * put it in INIT state so it dosn't start
1.10 ratchov 523: */
1.27 ! ratchov 524: if (f->mmcpos > f->endpos && !(f->mode & MODE_RECMASK)) {
1.15 ratchov 525: wav_reset(f);
526: /*
527: * don't make other stream wait for us
528: */
529: if (f->slot >= 0)
1.20 ratchov 530: ctl_slotstart(f->dev->midi, f->slot);
1.15 ratchov 531: return 0;
532: }
533: if (!pipe_seek(&f->pipe.file, f->mmcpos)) {
534: wav_exit(f);
535: return 0;
536: }
1.27 ! ratchov 537: if (f->mode & MODE_RECMASK)
! 538: f->endpos = f->mmcpos;
1.15 ratchov 539: if (f->hdr == HDR_WAV)
540: f->wbytes = WAV_DATAMAX - f->mmcpos;
541: f->rbytes = f->endpos - f->mmcpos;
542: wav_reset(f);
543: wav_allocbuf(f);
544: return 1;
1.10 ratchov 545: }
546:
1.15 ratchov 547: /*
548: * read samples from the file and possibly start it
549: */
1.10 ratchov 550: int
1.15 ratchov 551: wav_rdata(struct wav *f)
1.10 ratchov 552: {
1.15 ratchov 553: struct aproc *p;
554: struct abuf *obuf;
1.10 ratchov 555:
1.15 ratchov 556: p = f->pipe.file.rproc;
1.17 ratchov 557: obuf = LIST_FIRST(&p->outs);
1.15 ratchov 558: if (obuf == NULL)
1.10 ratchov 559: return 0;
1.15 ratchov 560: if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
1.10 ratchov 561: return 0;
1.15 ratchov 562: if (!rfile_do(p, obuf->len, NULL))
1.10 ratchov 563: return 0;
1.15 ratchov 564: switch (f->pstate) {
565: case WAV_START:
566: if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
567: f->pstate = WAV_READY;
568: /* PASSTHROUGH */
569: case WAV_READY:
1.20 ratchov 570: if (ctl_slotstart(f->dev->midi, f->slot))
1.15 ratchov 571: (void)wav_attach(f, 0);
572: break;
573: case WAV_RUN:
574: break;
1.27 ! ratchov 575: case WAV_MIDI:
! 576: return 1;
! 577: #ifdef DEBUG
1.15 ratchov 578: default:
579: wav_dbg(f);
580: dbg_puts(": bad state\n");
581: dbg_panic();
582: #endif
583: }
1.20 ratchov 584: if (f->rbytes == 0 && f->mmc) {
1.15 ratchov 585: #ifdef DEBUG
586: if (debug_level >= 3) {
587: wav_dbg(f);
588: dbg_puts(": trying to restart\n");
589: }
590: #endif
591: if (!wav_seekmmc(f))
592: return 0;
593: }
1.10 ratchov 594: return 1;
595: }
596:
597: int
1.15 ratchov 598: wav_wdata(struct wav *f)
1.10 ratchov 599: {
1.15 ratchov 600: struct aproc *p;
601: struct abuf *ibuf;
1.10 ratchov 602:
1.15 ratchov 603: if (!(f->pipe.file.state & FILE_WOK))
1.10 ratchov 604: return 0;
1.15 ratchov 605: p = f->pipe.file.wproc;
1.17 ratchov 606: ibuf = LIST_FIRST(&p->ins);
1.15 ratchov 607: if (ibuf == NULL)
1.10 ratchov 608: return 0;
1.15 ratchov 609: if (!ABUF_ROK(ibuf))
1.10 ratchov 610: return 0;
1.15 ratchov 611: if (!wfile_do(p, ibuf->len, NULL))
1.10 ratchov 612: return 0;
613: return 1;
614: }
615:
1.15 ratchov 616: /*
617: * callback to set the volume, invoked by the MIDI control code
618: */
619: void
620: wav_setvol(void *arg, unsigned vol)
621: {
622: struct wav *f = (struct wav *)arg;
623: struct abuf *rbuf;
624:
625: f->vol = vol;
626: if ((f->mode & MODE_PLAY) && f->pstate == WAV_RUN) {
1.17 ratchov 627: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.20 ratchov 628: dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(vol));
1.15 ratchov 629: }
630: }
631:
632: /*
633: * callback to start the stream, invoked by the MIDI control code
634: */
635: void
636: wav_startreq(void *arg)
637: {
638: struct wav *f = (struct wav *)arg;
639:
640: switch (f->pstate) {
1.27 ! ratchov 641: case WAV_INIT:
1.15 ratchov 642: #ifdef DEBUG
643: if (debug_level >= 2) {
644: wav_dbg(f);
645: dbg_puts(": skipped (failed to seek)\n");
646: }
647: #endif
648: return;
649: case WAV_READY:
650: if (f->mode & MODE_RECMASK)
1.27 ! ratchov 651: f->endpos = f->mmcpos + f->startpos;
1.15 ratchov 652: (void)wav_attach(f, 0);
653: break;
654: #ifdef DEBUG
655: default:
656: wav_dbg(f);
657: dbg_puts(": not in READY state\n");
658: dbg_panic();
659: break;
660: #endif
661: }
662: }
663:
664: /*
665: * callback to stop the stream, invoked by the MIDI control code
666: */
1.10 ratchov 667: void
1.15 ratchov 668: wav_stopreq(void *arg)
1.10 ratchov 669: {
1.15 ratchov 670: struct wav *f = (struct wav *)arg;
671:
672: #ifdef DEBUG
673: if (debug_level >= 2) {
674: wav_dbg(f);
675: dbg_puts(": stopping");
1.27 ! ratchov 676: if (f->pstate != WAV_INIT && (f->mode & MODE_RECMASK)) {
1.15 ratchov 677: dbg_puts(", ");
678: dbg_putu(f->endpos);
679: dbg_puts(" bytes recorded");
680: }
681: dbg_puts("\n");
682: }
683: #endif
1.20 ratchov 684: if (!f->mmc) {
1.15 ratchov 685: wav_exit(f);
686: return;
687: }
688: (void)wav_seekmmc(f);
1.10 ratchov 689: }
690:
1.15 ratchov 691: /*
692: * callback to relocate the stream, invoked by the MIDI control code
693: * on a stopped stream
694: */
1.10 ratchov 695: void
1.15 ratchov 696: wav_locreq(void *arg, unsigned mmc)
1.10 ratchov 697: {
1.15 ratchov 698: struct wav *f = (struct wav *)arg;
699:
700: #ifdef DEBUG
701: if (f->pstate == WAV_RUN) {
702: wav_dbg(f);
703: dbg_puts(": in RUN state\n");
704: dbg_panic();
705: }
706: #endif
707: f->mmcpos = f->startpos +
708: ((off_t)mmc * f->hpar.rate / MTC_SEC) * aparams_bpf(&f->hpar);
709: (void)wav_seekmmc(f);
1.10 ratchov 710: }
711:
1.15 ratchov 712: /*
1.20 ratchov 713: * Callback invoked when slot is gone
714: */
715: void
716: wav_quitreq(void *arg)
717: {
718: struct wav *f = (struct wav *)arg;
719:
720: #ifdef DEBUG
721: if (debug_level >= 3) {
722: wav_dbg(f);
723: dbg_puts(": slot gone\n");
724: }
725: #endif
726: if (f->pstate != WAV_RUN)
727: wav_exit(f);
728: }
729:
730: /*
1.26 ratchov 731: * determine the header by the file name
732: */
1.27 ! ratchov 733: int
! 734: wav_autohdr(char *name, struct dev *dev, unsigned *hdr, unsigned *mode)
1.26 ratchov 735: {
1.27 ! ratchov 736: char *ext;
1.26 ratchov 737:
1.27 ! ratchov 738: if (dev->reqmode & MODE_THRU)
! 739: *mode &= MODE_MIDIMASK;
! 740: if (*hdr == HDR_AUTO) {
! 741: ext = strrchr(name, '.');
! 742: if (ext != NULL) {
! 743: ext++;
! 744: if (strcasecmp(ext, "wav") == 0) {
! 745: *hdr = HDR_WAV;
! 746: *mode &= ~MODE_MIDIMASK;
! 747: } else if (strcasecmp(ext, "syx") == 0) {
! 748: *hdr = HDR_WAV;
! 749: *mode &= ~MODE_AUDIOMASK;
! 750: }
! 751: } else
! 752: *hdr = HDR_RAW;
! 753: }
! 754: if (*mode & MODE_AUDIOMASK)
! 755: *mode &= ~MODE_MIDIMASK;
! 756: if (*mode == 0) {
! 757: #ifdef DEBUG
! 758: if (debug_level >= 1) {
! 759: dbg_puts(name);
! 760: dbg_puts(": requested mode not supported\n");
! 761: }
! 762: #endif
! 763: return 0;
! 764: }
! 765: return 1;
1.26 ratchov 766: }
767:
768: /*
1.15 ratchov 769: * create a file reader in the ``INIT'' state
770: */
1.1 ratchov 771: struct wav *
1.27 ! ratchov 772: wav_new_in(struct fileops *ops, struct dev *dev,
! 773: unsigned mode, char *name, unsigned hdr,
! 774: struct aparams *par, unsigned xrun, unsigned volctl, int mmc, int join)
1.1 ratchov 775: {
1.10 ratchov 776: int fd;
1.1 ratchov 777: struct wav *f;
1.10 ratchov 778:
1.27 ! ratchov 779: if (!wav_autohdr(name, dev, &hdr, &mode))
! 780: return NULL;
! 781: if (strcmp(name, "-") == 0) {
! 782: fd = STDIN_FILENO;
! 783: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
! 784: perror(name);
! 785: } else {
1.10 ratchov 786: fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
787: if (fd < 0) {
788: perror(name);
789: return NULL;
790: }
791: }
1.1 ratchov 792: f = (struct wav *)pipe_new(ops, fd, name);
1.18 ratchov 793: if (f == NULL) {
794: close(fd);
795: return NULL;
796: }
1.27 ! ratchov 797: f->pstate = WAV_CFG;
1.1 ratchov 798: if (hdr == HDR_WAV) {
1.27 ! ratchov 799: if (!wav_readhdr(f->pipe.fd, par,
! 800: &f->startpos, &f->rbytes, &f->map)) {
1.10 ratchov 801: file_del((struct file *)f);
802: return NULL;
803: }
1.15 ratchov 804: f->endpos = f->startpos + f->rbytes;
1.6 ratchov 805: } else {
1.15 ratchov 806: f->startpos = 0;
807: f->endpos = pipe_endpos(&f->pipe.file);
808: if (f->endpos > 0) {
809: if (!pipe_seek(&f->pipe.file, 0)) {
810: file_del((struct file *)f);
811: return NULL;
812: }
813: f->rbytes = f->endpos;
814: } else
815: f->rbytes = -1;
1.6 ratchov 816: f->map = NULL;
817: }
1.27 ! ratchov 818: f->dev = dev;
! 819: f->mmc = mmc;
1.16 ratchov 820: f->join = join;
1.15 ratchov 821: f->mode = mode;
822: f->hpar = *par;
1.26 ratchov 823: f->hdr = hdr;
1.15 ratchov 824: f->xrun = xrun;
825: f->maxweight = MIDI_TO_ADATA(volctl);
1.27 ! ratchov 826: f->slot = -1;
1.15 ratchov 827: rwav_new((struct file *)f);
1.12 ratchov 828: #ifdef DEBUG
829: if (debug_level >= 2) {
830: dbg_puts(name);
1.27 ! ratchov 831: dbg_puts(":");
! 832: if (f->mode & MODE_PLAY) {
! 833: dbg_puts(" playing ");
! 834: aparams_dbg(par);
! 835: dbg_puts(" ");
! 836: dbg_putu(f->startpos);
! 837: dbg_puts("..");
! 838: dbg_putu(f->endpos);
! 839: if (f->mmc)
! 840: dbg_puts(", mmc");
! 841: }
! 842: if (f->mode & MODE_MIDIOUT)
! 843: dbg_puts(" midi/out");
1.12 ratchov 844: dbg_puts("\n");
845: }
846: #endif
1.27 ! ratchov 847: f->next = wav_list;
! 848: wav_list = f;
1.1 ratchov 849: return f;
850: }
851:
1.15 ratchov 852: /*
853: * create a file writer in the ``INIT'' state
854: */
1.1 ratchov 855: struct wav *
1.27 ! ratchov 856: wav_new_out(struct fileops *ops, struct dev *dev,
! 857: unsigned mode, char *name, unsigned hdr,
! 858: struct aparams *par, unsigned xrun, int mmc, int join)
1.1 ratchov 859: {
1.10 ratchov 860: int fd;
1.1 ratchov 861: struct wav *f;
1.10 ratchov 862:
1.27 ! ratchov 863: if (!wav_autohdr(name, dev, &hdr, &mode))
! 864: return NULL;
! 865: if (strcmp(name, "-") == 0) {
1.10 ratchov 866: fd = STDOUT_FILENO;
867: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
868: perror(name);
869: } else {
870: fd = open(name,
871: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
872: if (fd < 0) {
873: perror(name);
874: return NULL;
875: }
876: }
1.1 ratchov 877: f = (struct wav *)pipe_new(ops, fd, name);
1.18 ratchov 878: if (f == NULL) {
879: close(fd);
1.4 ratchov 880: return NULL;
1.18 ratchov 881: }
1.27 ! ratchov 882: f->pstate = WAV_CFG;
1.1 ratchov 883: if (hdr == HDR_WAV) {
1.2 ratchov 884: par->le = 1;
1.3 ratchov 885: par->sig = (par->bits <= 8) ? 0 : 1;
1.2 ratchov 886: par->bps = (par->bits + 7) / 8;
1.15 ratchov 887: if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) {
1.10 ratchov 888: file_del((struct file *)f);
889: return NULL;
890: }
1.1 ratchov 891: f->wbytes = WAV_DATAMAX;
1.15 ratchov 892: f->endpos = f->startpos;
893: } else {
1.1 ratchov 894: f->wbytes = -1;
1.15 ratchov 895: f->startpos = f->endpos = 0;
896: }
1.27 ! ratchov 897: f->dev = dev;
! 898: f->mmc = mmc;
1.16 ratchov 899: f->join = join;
1.15 ratchov 900: f->mode = mode;
901: f->hpar = *par;
1.1 ratchov 902: f->hdr = hdr;
1.15 ratchov 903: f->xrun = xrun;
904: wwav_new((struct file *)f);
1.12 ratchov 905: #ifdef DEBUG
906: if (debug_level >= 2) {
907: dbg_puts(name);
1.27 ! ratchov 908: dbg_puts(":");
! 909: if (f->mode & MODE_RECMASK) {
! 910: dbg_puts(" recording ");
! 911: aparams_dbg(par);
! 912: if (f->mmc)
! 913: dbg_puts(", mmc");
! 914: }
! 915: if (f->mode & MODE_MIDIIN)
! 916: dbg_puts(" midi/in");
1.12 ratchov 917: dbg_puts("\n");
918: }
919: #endif
1.27 ! ratchov 920: f->next = wav_list;
! 921: wav_list = f;
1.1 ratchov 922: return f;
923: }
924:
1.6 ratchov 925: void
1.15 ratchov 926: rwav_done(struct aproc *p)
927: {
928: struct wav *f = (struct wav *)p->u.io.file;
929:
930: if (f->slot >= 0)
1.20 ratchov 931: ctl_slotdel(f->dev->midi, f->slot);
1.15 ratchov 932: f->slot = -1;
933: rfile_done(p);
934: }
935:
936: int
937: rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
1.13 ratchov 938: {
1.15 ratchov 939: struct wav *f = (struct wav *)p->u.io.file;
940: struct abuf *obuf;
1.13 ratchov 941:
1.15 ratchov 942: if (!wav_rdata(f))
943: return 0;
1.17 ratchov 944: obuf = LIST_FIRST(&p->outs);
1.15 ratchov 945: if (obuf && f->pstate >= WAV_RUN) {
946: if (!abuf_flush(obuf))
947: return 0;
1.6 ratchov 948: }
1.15 ratchov 949: return 1;
1.6 ratchov 950: }
951:
1.15 ratchov 952: int
953: rwav_out(struct aproc *p, struct abuf *obuf)
1.1 ratchov 954: {
1.15 ratchov 955: struct wav *f = (struct wav *)p->u.io.file;
1.1 ratchov 956:
1.15 ratchov 957: if (f->pipe.file.state & FILE_RINUSE)
958: return 0;
959: for (;;) {
960: if (!wav_rdata(f))
1.1 ratchov 961: return 0;
962: }
1.15 ratchov 963: return 1;
964: }
965:
966: struct aproc *
967: rwav_new(struct file *f)
968: {
969: struct aproc *p;
970:
971: p = aproc_new(&rwav_ops, f->name);
972: p->u.io.file = f;
1.24 deraadt 973: p->u.io.partial = 0;
1.15 ratchov 974: f->rproc = p;
975: return p;
976: }
977:
978: void
979: wwav_done(struct aproc *p)
980: {
981: struct wav *f = (struct wav *)p->u.io.file;
982:
983: if (f->slot >= 0)
1.20 ratchov 984: ctl_slotdel(f->dev->midi, f->slot);
1.15 ratchov 985: f->slot = -1;
986: wfile_done(p);
987: }
988:
989: int
990: wwav_in(struct aproc *p, struct abuf *ibuf)
991: {
992: struct wav *f = (struct wav *)p->u.io.file;
993:
994: if (f->pipe.file.state & FILE_WINUSE)
1.8 jakemsr 995: return 0;
1.15 ratchov 996: for (;;) {
997: if (!wav_wdata(f))
998: return 0;
1.6 ratchov 999: }
1.15 ratchov 1000: return 1;
1.1 ratchov 1001: }
1002:
1.15 ratchov 1003: int
1004: wwav_out(struct aproc *p, struct abuf *obuf_dummy)
1.1 ratchov 1005: {
1.17 ratchov 1006: struct abuf *ibuf = LIST_FIRST(&p->ins);
1.15 ratchov 1007: struct wav *f = (struct wav *)p->u.io.file;
1.3 ratchov 1008:
1.15 ratchov 1009: if (ibuf && f->pstate == WAV_RUN) {
1010: if (!abuf_fill(ibuf))
1.1 ratchov 1011: return 0;
1012: }
1.15 ratchov 1013: if (!wav_wdata(f))
1014: return 0;
1015: return 1;
1.1 ratchov 1016: }
1017:
1.15 ratchov 1018: struct aproc *
1019: wwav_new(struct file *f)
1.1 ratchov 1020: {
1.15 ratchov 1021: struct aproc *p;
1.1 ratchov 1022:
1.15 ratchov 1023: p = aproc_new(&wwav_ops, f->name);
1024: p->u.io.file = f;
1.24 deraadt 1025: p->u.io.partial = 0;
1.15 ratchov 1026: f->wproc = p;
1027: return p;
1.1 ratchov 1028: }