Annotation of src/usr.bin/aucat/wav.c, Revision 1.28
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.15 ratchov 188:
189: dbg_puts("wav(");
1.28 ! ratchov 190: if (f->slot >= 0) {
! 191: dbg_puts(f->dev->slot[f->slot].name);
! 192: dbg_putu(f->dev->slot[f->slot].unit);
1.15 ratchov 193: } else
194: dbg_puts(f->pipe.file.name);
195: dbg_puts(")/");
196: dbg_puts(pstates[f->pstate]);
197: }
198: #endif
199:
200: /*
201: * convert ``count'' samples using the given char->short map
202: */
203: void
204: wav_conv(unsigned char *data, unsigned count, short *map)
1.13 ratchov 205: {
1.15 ratchov 206: unsigned i;
207: unsigned char *iptr;
1.23 ratchov 208: adata_t *optr;
1.13 ratchov 209:
1.15 ratchov 210: iptr = data + count;
1.23 ratchov 211: optr = (adata_t *)data + count;
1.15 ratchov 212: for (i = count; i > 0; i--) {
213: --optr;
214: --iptr;
1.23 ratchov 215: *optr = (adata_t)(map[*iptr]) << (ADATA_BITS - 16);
1.15 ratchov 216: }
1.13 ratchov 217: }
218:
1.15 ratchov 219: /*
220: * read method of the file structure
221: */
222: unsigned
223: wav_read(struct file *file, unsigned char *data, unsigned count)
1.10 ratchov 224: {
1.15 ratchov 225: struct wav *f = (struct wav *)file;
226: unsigned n;
227:
228: if (f->map)
1.23 ratchov 229: count /= sizeof(adata_t);
1.15 ratchov 230: if (f->rbytes >= 0 && count > f->rbytes) {
231: count = f->rbytes; /* file->rbytes fits in count */
232: if (count == 0) {
233: #ifdef DEBUG
234: if (debug_level >= 3) {
235: wav_dbg(f);
236: dbg_puts(": read complete\n");
237: }
238: #endif
1.20 ratchov 239: if (!f->mmc)
1.15 ratchov 240: file_eof(&f->pipe.file);
241: return 0;
242: }
243: }
244: n = pipe_read(file, data, count);
245: if (n == 0)
1.14 ratchov 246: return 0;
1.15 ratchov 247: if (f->rbytes >= 0)
248: f->rbytes -= n;
249: if (f->map) {
250: wav_conv(data, n, f->map);
1.23 ratchov 251: n *= sizeof(adata_t);
1.15 ratchov 252: }
253: return n;
254: }
255:
256: /*
257: * write method of the file structure
258: */
259: unsigned
260: wav_write(struct file *file, unsigned char *data, unsigned count)
261: {
262: struct wav *f = (struct wav *)file;
263: unsigned n;
264:
265: if (f->wbytes >= 0 && count > f->wbytes) {
266: count = f->wbytes; /* wbytes fits in count */
267: if (count == 0) {
268: #ifdef DEBUG
269: if (debug_level >= 3) {
270: wav_dbg(f);
271: dbg_puts(": write complete\n");
272: }
273: #endif
274: file_hup(&f->pipe.file);
275: return 0;
276: }
277: }
278: n = pipe_write(file, data, count);
279: if (f->wbytes >= 0)
280: f->wbytes -= n;
281: f->endpos += n;
282: return n;
283: }
284:
285: /*
286: * close method of the file structure
287: */
288: void
289: wav_close(struct file *file)
290: {
1.27 ratchov 291: struct wav *f = (struct wav *)file, **pf;
1.15 ratchov 292:
293: if (f->mode & MODE_RECMASK) {
294: pipe_trunc(&f->pipe.file, f->endpos);
295: if (f->hdr == HDR_WAV) {
296: wav_writehdr(f->pipe.fd,
297: &f->hpar,
298: &f->startpos,
299: f->endpos - f->startpos);
300: }
301: }
302: pipe_close(file);
1.27 ratchov 303: if (f->pstate != WAV_CFG)
1.20 ratchov 304: dev_unref(f->dev);
1.27 ratchov 305: for (pf = &wav_list; *pf != f; pf = &(*pf)->next) {
306: #ifdef DEBUG
307: if (*pf == NULL) {
308: dbg_puts("wav_close: not on list\n");
309: dbg_panic();
310: }
311: #endif
1.20 ratchov 312: }
1.27 ratchov 313: *pf = f->next;
1.10 ratchov 314: }
315:
1.15 ratchov 316: /*
317: * attach play (rec) abuf structure to the device and
318: * switch to the ``RUN'' state; the play abug must not be empty
319: */
1.14 ratchov 320: int
1.15 ratchov 321: wav_attach(struct wav *f, int force)
1.10 ratchov 322: {
1.15 ratchov 323: struct abuf *rbuf = NULL, *wbuf = NULL;
1.20 ratchov 324: struct dev *d = f->dev;
1.13 ratchov 325:
1.15 ratchov 326: if (f->mode & MODE_PLAY)
1.17 ratchov 327: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.15 ratchov 328: if (f->mode & MODE_RECMASK)
1.17 ratchov 329: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.15 ratchov 330: f->pstate = WAV_RUN;
331: #ifdef DEBUG
332: if (debug_level >= 3) {
333: wav_dbg(f);
334: dbg_puts(": attaching\n");
335: }
336: #endif
1.18 ratchov 337:
338: /*
339: * start the device (dev_getpos() and dev_attach() must
340: * be called on a started device
341: */
1.20 ratchov 342: dev_wakeup(d);
1.18 ratchov 343:
1.20 ratchov 344: dev_attach(d, f->pipe.file.name, f->mode,
345: rbuf, &f->hpar, f->join ? d->opar.cmax - d->opar.cmin + 1 : 0,
346: wbuf, &f->hpar, f->join ? d->ipar.cmax - d->ipar.cmin + 1 : 0,
1.16 ratchov 347: f->xrun, f->maxweight);
1.15 ratchov 348: if (f->mode & MODE_PLAY)
1.20 ratchov 349: dev_setvol(d, rbuf, MIDI_TO_ADATA(f->vol));
1.14 ratchov 350: return 1;
1.13 ratchov 351: }
352:
1.15 ratchov 353: /*
1.27 ratchov 354: * allocate buffers, so client can start filling write-end.
355: */
356: void
357: wav_midiattach(struct wav *f)
358: {
359: struct abuf *rbuf = NULL, *wbuf = NULL;
360:
361: if (f->mode & MODE_MIDIOUT) {
362: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
363: aproc_setout(f->pipe.file.rproc, rbuf);
364: }
365: if (f->mode & MODE_MIDIIN) {
366: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
367: aproc_setin(f->pipe.file.wproc, wbuf);
368: }
369: f->pstate = WAV_MIDI;
370: dev_midiattach(f->dev, rbuf, wbuf);
371: }
372:
373: /*
1.15 ratchov 374: * allocate the play (rec) abuf structure; if this is a
375: * file to record, then attach it to the device
376: *
377: * XXX: buffer size should be larger than dev_bufsz, because
378: * in non-server mode we don't prime play buffers with
379: * silence
380: */
1.14 ratchov 381: void
1.15 ratchov 382: wav_allocbuf(struct wav *f)
1.13 ratchov 383: {
1.15 ratchov 384: struct abuf *buf;
1.20 ratchov 385: struct dev *d = f->dev;
1.15 ratchov 386: unsigned nfr;
1.13 ratchov 387:
1.15 ratchov 388: f->pstate = WAV_START;
389: if (f->mode & MODE_PLAY) {
1.20 ratchov 390: nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
1.15 ratchov 391: buf = abuf_new(nfr, &f->hpar);
392: aproc_setout(f->pipe.file.rproc, buf);
393: abuf_fill(buf);
394: if (!ABUF_WOK(buf) || (f->pipe.file.state & FILE_EOF))
395: f->pstate = WAV_READY;
396: }
397: if (f->mode & MODE_RECMASK) {
1.20 ratchov 398: nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
1.15 ratchov 399: buf = abuf_new(nfr, &f->hpar);
400: aproc_setin(f->pipe.file.wproc, buf);
401: f->pstate = WAV_READY;
402: }
403: #ifdef DEBUG
404: if (debug_level >= 3) {
405: wav_dbg(f);
406: dbg_puts(": allocating buffers\n");
407: }
408: #endif
1.28 ! ratchov 409: if (f->pstate == WAV_READY && dev_slotstart(d, f->slot))
1.15 ratchov 410: (void)wav_attach(f, 0);
1.13 ratchov 411: }
412:
1.15 ratchov 413: /*
414: * free abuf structure and switch to the ``INIT'' state
415: */
1.13 ratchov 416: void
1.15 ratchov 417: wav_freebuf(struct wav *f)
1.10 ratchov 418: {
1.15 ratchov 419: struct abuf *rbuf = NULL, *wbuf = NULL;
420:
421: if (f->mode & MODE_PLAY)
1.17 ratchov 422: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.15 ratchov 423: if (f->mode & MODE_RECMASK)
1.17 ratchov 424: wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
1.15 ratchov 425: f->pstate = WAV_INIT;
426: #ifdef DEBUG
427: if (debug_level >= 3) {
428: wav_dbg(f);
429: dbg_puts(": freeing buffers\n");
430: }
431: #endif
432: if (rbuf || wbuf)
1.28 ! ratchov 433: dev_slotstop(f->dev, f->slot);
1.15 ratchov 434: if (rbuf)
435: abuf_eof(rbuf);
436: if (wbuf)
437: abuf_hup(wbuf);
1.10 ratchov 438: }
439:
1.15 ratchov 440: /*
441: * switch to the ``INIT'' state performing
442: * necessary actions to reach it
443: */
1.10 ratchov 444: void
1.15 ratchov 445: wav_reset(struct wav *f)
1.10 ratchov 446: {
1.15 ratchov 447: switch (f->pstate) {
448: case WAV_START:
449: case WAV_READY:
1.28 ! ratchov 450: if (dev_slotstart(f->dev, f->slot))
1.15 ratchov 451: (void)wav_attach(f, 1);
452: /* PASSTHROUGH */
453: case WAV_RUN:
454: wav_freebuf(f);
455: /* PASSTHROUGH */
456: case WAV_INIT:
457: /* nothing yet */
458: break;
1.27 ratchov 459: case WAV_MIDI:
460: dbg_puts("wav_reset: in midi mode\n");
461: dbg_panic();
1.15 ratchov 462: }
1.10 ratchov 463: }
464:
1.15 ratchov 465: /*
466: * terminate the wav reader/writer
467: */
468: void
469: wav_exit(struct wav *f)
1.10 ratchov 470: {
1.20 ratchov 471: /* XXX: call file_close() ? */
1.27 ratchov 472: if (f->mode & (MODE_PLAY | MODE_MIDIOUT)) {
1.15 ratchov 473: aproc_del(f->pipe.file.rproc);
1.27 ratchov 474: } else if (f->mode & (MODE_RECMASK | MODE_MIDIIN)) {
1.15 ratchov 475: aproc_del(f->pipe.file.wproc);
476: }
1.10 ratchov 477: }
478:
1.15 ratchov 479: /*
1.27 ratchov 480: * allocate the device
481: */
482: int
483: wav_init(struct wav *f)
484: {
485: if (!dev_ref(f->dev)) {
486: wav_exit(f);
487: return 0;
488: }
489: if (!f->mmc)
490: f->dev->autostart = 1;
491: if (f->mode & MODE_MIDIMASK) {
492: wav_midiattach(f);
493: return 1;
494: }
1.28 ! ratchov 495: f->slot = dev_slotnew(f->dev, "wav", &ctl_wavops, f, 1);
1.27 ratchov 496: f->pstate = WAV_INIT;
497: if ((f->mode & f->dev->mode) != f->mode) {
498: #ifdef DEBUG
499: if (debug_level >= 1) {
500: wav_dbg(f);
501: dbg_puts(": ");
502: dbg_puts(": operation not supported by device\n");
503: }
504: #endif
505: wav_exit(f);
506: return 0;
507: }
508: wav_allocbuf(f);
509: return 1;
510: }
511:
512: /*
1.15 ratchov 513: * seek to f->mmcpos and prepare to start, close
514: * the file on error.
515: */
516: int
517: wav_seekmmc(struct wav *f)
1.10 ratchov 518: {
519: /*
1.15 ratchov 520: * don't go beyond the end-of-file, if so
521: * put it in INIT state so it dosn't start
1.10 ratchov 522: */
1.27 ratchov 523: if (f->mmcpos > f->endpos && !(f->mode & MODE_RECMASK)) {
1.15 ratchov 524: wav_reset(f);
525: /*
526: * don't make other stream wait for us
527: */
528: if (f->slot >= 0)
1.28 ! ratchov 529: dev_slotstart(f->dev, f->slot);
1.15 ratchov 530: return 0;
531: }
532: if (!pipe_seek(&f->pipe.file, f->mmcpos)) {
533: wav_exit(f);
534: return 0;
535: }
1.28 ! ratchov 536: if ((f->mode & MODE_RECMASK) && f->mmcpos > f->endpos)
1.27 ratchov 537: f->endpos = f->mmcpos;
1.15 ratchov 538: if (f->hdr == HDR_WAV)
539: f->wbytes = WAV_DATAMAX - f->mmcpos;
540: f->rbytes = f->endpos - f->mmcpos;
541: wav_reset(f);
542: wav_allocbuf(f);
543: return 1;
1.10 ratchov 544: }
545:
1.15 ratchov 546: /*
547: * read samples from the file and possibly start it
548: */
1.10 ratchov 549: int
1.15 ratchov 550: wav_rdata(struct wav *f)
1.10 ratchov 551: {
1.15 ratchov 552: struct aproc *p;
553: struct abuf *obuf;
1.10 ratchov 554:
1.15 ratchov 555: p = f->pipe.file.rproc;
1.17 ratchov 556: obuf = LIST_FIRST(&p->outs);
1.15 ratchov 557: if (obuf == NULL)
1.10 ratchov 558: return 0;
1.15 ratchov 559: if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
1.10 ratchov 560: return 0;
1.15 ratchov 561: if (!rfile_do(p, obuf->len, NULL))
1.10 ratchov 562: return 0;
1.15 ratchov 563: switch (f->pstate) {
564: case WAV_START:
565: if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
566: f->pstate = WAV_READY;
567: /* PASSTHROUGH */
568: case WAV_READY:
1.28 ! ratchov 569: if (dev_slotstart(f->dev, f->slot))
1.15 ratchov 570: (void)wav_attach(f, 0);
571: break;
572: case WAV_RUN:
573: break;
1.27 ratchov 574: case WAV_MIDI:
575: return 1;
576: #ifdef DEBUG
1.15 ratchov 577: default:
578: wav_dbg(f);
579: dbg_puts(": bad state\n");
580: dbg_panic();
581: #endif
582: }
1.20 ratchov 583: if (f->rbytes == 0 && f->mmc) {
1.15 ratchov 584: #ifdef DEBUG
585: if (debug_level >= 3) {
586: wav_dbg(f);
587: dbg_puts(": trying to restart\n");
588: }
589: #endif
590: if (!wav_seekmmc(f))
591: return 0;
592: }
1.10 ratchov 593: return 1;
594: }
595:
596: int
1.15 ratchov 597: wav_wdata(struct wav *f)
1.10 ratchov 598: {
1.15 ratchov 599: struct aproc *p;
600: struct abuf *ibuf;
1.10 ratchov 601:
1.15 ratchov 602: if (!(f->pipe.file.state & FILE_WOK))
1.10 ratchov 603: return 0;
1.15 ratchov 604: p = f->pipe.file.wproc;
1.17 ratchov 605: ibuf = LIST_FIRST(&p->ins);
1.15 ratchov 606: if (ibuf == NULL)
1.10 ratchov 607: return 0;
1.15 ratchov 608: if (!ABUF_ROK(ibuf))
1.10 ratchov 609: return 0;
1.15 ratchov 610: if (!wfile_do(p, ibuf->len, NULL))
1.10 ratchov 611: return 0;
612: return 1;
613: }
614:
1.15 ratchov 615: /*
616: * callback to set the volume, invoked by the MIDI control code
617: */
618: void
619: wav_setvol(void *arg, unsigned vol)
620: {
621: struct wav *f = (struct wav *)arg;
622: struct abuf *rbuf;
623:
624: f->vol = vol;
625: if ((f->mode & MODE_PLAY) && f->pstate == WAV_RUN) {
1.17 ratchov 626: rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
1.20 ratchov 627: dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(vol));
1.15 ratchov 628: }
629: }
630:
631: /*
632: * callback to start the stream, invoked by the MIDI control code
633: */
634: void
635: wav_startreq(void *arg)
636: {
637: struct wav *f = (struct wav *)arg;
638:
639: switch (f->pstate) {
1.27 ratchov 640: case WAV_INIT:
1.15 ratchov 641: #ifdef DEBUG
642: if (debug_level >= 2) {
643: wav_dbg(f);
644: dbg_puts(": skipped (failed to seek)\n");
645: }
646: #endif
647: return;
648: case WAV_READY:
649: if (f->mode & MODE_RECMASK)
1.27 ratchov 650: f->endpos = f->mmcpos + f->startpos;
1.15 ratchov 651: (void)wav_attach(f, 0);
652: break;
653: #ifdef DEBUG
654: default:
655: wav_dbg(f);
656: dbg_puts(": not in READY state\n");
657: dbg_panic();
658: break;
659: #endif
660: }
661: }
662:
663: /*
664: * callback to stop the stream, invoked by the MIDI control code
665: */
1.10 ratchov 666: void
1.15 ratchov 667: wav_stopreq(void *arg)
1.10 ratchov 668: {
1.15 ratchov 669: struct wav *f = (struct wav *)arg;
670:
671: #ifdef DEBUG
672: if (debug_level >= 2) {
673: wav_dbg(f);
674: dbg_puts(": stopping");
1.27 ratchov 675: if (f->pstate != WAV_INIT && (f->mode & MODE_RECMASK)) {
1.15 ratchov 676: dbg_puts(", ");
677: dbg_putu(f->endpos);
678: dbg_puts(" bytes recorded");
679: }
680: dbg_puts("\n");
681: }
682: #endif
1.20 ratchov 683: if (!f->mmc) {
1.15 ratchov 684: wav_exit(f);
685: return;
686: }
687: (void)wav_seekmmc(f);
1.10 ratchov 688: }
689:
1.15 ratchov 690: /*
691: * callback to relocate the stream, invoked by the MIDI control code
692: * on a stopped stream
693: */
1.10 ratchov 694: void
1.15 ratchov 695: wav_locreq(void *arg, unsigned mmc)
1.10 ratchov 696: {
1.15 ratchov 697: struct wav *f = (struct wav *)arg;
698:
699: #ifdef DEBUG
700: if (f->pstate == WAV_RUN) {
701: wav_dbg(f);
702: dbg_puts(": in RUN state\n");
703: dbg_panic();
704: }
705: #endif
706: f->mmcpos = f->startpos +
707: ((off_t)mmc * f->hpar.rate / MTC_SEC) * aparams_bpf(&f->hpar);
708: (void)wav_seekmmc(f);
1.10 ratchov 709: }
710:
1.15 ratchov 711: /*
1.20 ratchov 712: * Callback invoked when slot is gone
713: */
714: void
715: wav_quitreq(void *arg)
716: {
717: struct wav *f = (struct wav *)arg;
718:
719: #ifdef DEBUG
720: if (debug_level >= 3) {
721: wav_dbg(f);
722: dbg_puts(": slot gone\n");
723: }
724: #endif
725: if (f->pstate != WAV_RUN)
726: wav_exit(f);
727: }
728:
729: /*
1.26 ratchov 730: * determine the header by the file name
731: */
1.27 ratchov 732: int
733: wav_autohdr(char *name, struct dev *dev, unsigned *hdr, unsigned *mode)
1.26 ratchov 734: {
1.27 ratchov 735: char *ext;
1.26 ratchov 736:
1.27 ratchov 737: if (dev->reqmode & MODE_THRU)
738: *mode &= MODE_MIDIMASK;
739: if (*hdr == HDR_AUTO) {
740: ext = strrchr(name, '.');
741: if (ext != NULL) {
742: ext++;
743: if (strcasecmp(ext, "wav") == 0) {
744: *hdr = HDR_WAV;
745: *mode &= ~MODE_MIDIMASK;
746: } else if (strcasecmp(ext, "syx") == 0) {
747: *hdr = HDR_WAV;
748: *mode &= ~MODE_AUDIOMASK;
749: }
750: } else
751: *hdr = HDR_RAW;
752: }
753: if (*mode & MODE_AUDIOMASK)
754: *mode &= ~MODE_MIDIMASK;
755: if (*mode == 0) {
756: #ifdef DEBUG
757: if (debug_level >= 1) {
758: dbg_puts(name);
759: dbg_puts(": requested mode not supported\n");
760: }
761: #endif
762: return 0;
763: }
764: return 1;
1.26 ratchov 765: }
766:
767: /*
1.15 ratchov 768: * create a file reader in the ``INIT'' state
769: */
1.1 ratchov 770: struct wav *
1.27 ratchov 771: wav_new_in(struct fileops *ops, struct dev *dev,
772: unsigned mode, char *name, unsigned hdr,
773: struct aparams *par, unsigned xrun, unsigned volctl, int mmc, int join)
1.1 ratchov 774: {
1.10 ratchov 775: int fd;
1.1 ratchov 776: struct wav *f;
1.10 ratchov 777:
1.27 ratchov 778: if (!wav_autohdr(name, dev, &hdr, &mode))
779: return NULL;
780: if (strcmp(name, "-") == 0) {
781: fd = STDIN_FILENO;
782: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
783: perror(name);
784: } else {
1.10 ratchov 785: fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
786: if (fd < 0) {
787: perror(name);
788: return NULL;
789: }
790: }
1.1 ratchov 791: f = (struct wav *)pipe_new(ops, fd, name);
1.18 ratchov 792: if (f == NULL) {
793: close(fd);
794: return NULL;
795: }
1.27 ratchov 796: f->pstate = WAV_CFG;
1.1 ratchov 797: if (hdr == HDR_WAV) {
1.27 ratchov 798: if (!wav_readhdr(f->pipe.fd, par,
799: &f->startpos, &f->rbytes, &f->map)) {
1.10 ratchov 800: file_del((struct file *)f);
801: return NULL;
802: }
1.15 ratchov 803: f->endpos = f->startpos + f->rbytes;
1.6 ratchov 804: } else {
1.15 ratchov 805: f->startpos = 0;
806: f->endpos = pipe_endpos(&f->pipe.file);
807: if (f->endpos > 0) {
808: if (!pipe_seek(&f->pipe.file, 0)) {
809: file_del((struct file *)f);
810: return NULL;
811: }
812: f->rbytes = f->endpos;
813: } else
814: f->rbytes = -1;
1.6 ratchov 815: f->map = NULL;
816: }
1.27 ratchov 817: f->dev = dev;
818: f->mmc = mmc;
1.16 ratchov 819: f->join = join;
1.15 ratchov 820: f->mode = mode;
821: f->hpar = *par;
1.26 ratchov 822: f->hdr = hdr;
1.15 ratchov 823: f->xrun = xrun;
824: f->maxweight = MIDI_TO_ADATA(volctl);
1.27 ratchov 825: f->slot = -1;
1.15 ratchov 826: rwav_new((struct file *)f);
1.12 ratchov 827: #ifdef DEBUG
828: if (debug_level >= 2) {
829: dbg_puts(name);
1.27 ratchov 830: dbg_puts(":");
831: if (f->mode & MODE_PLAY) {
832: dbg_puts(" playing ");
833: aparams_dbg(par);
834: dbg_puts(" ");
835: dbg_putu(f->startpos);
836: dbg_puts("..");
837: dbg_putu(f->endpos);
838: if (f->mmc)
839: dbg_puts(", mmc");
840: }
841: if (f->mode & MODE_MIDIOUT)
842: dbg_puts(" midi/out");
1.12 ratchov 843: dbg_puts("\n");
844: }
845: #endif
1.27 ratchov 846: f->next = wav_list;
847: wav_list = f;
1.1 ratchov 848: return f;
849: }
850:
1.15 ratchov 851: /*
852: * create a file writer in the ``INIT'' state
853: */
1.1 ratchov 854: struct wav *
1.27 ratchov 855: wav_new_out(struct fileops *ops, struct dev *dev,
856: unsigned mode, char *name, unsigned hdr,
857: struct aparams *par, unsigned xrun, int mmc, int join)
1.1 ratchov 858: {
1.10 ratchov 859: int fd;
1.1 ratchov 860: struct wav *f;
1.10 ratchov 861:
1.27 ratchov 862: if (!wav_autohdr(name, dev, &hdr, &mode))
863: return NULL;
864: if (strcmp(name, "-") == 0) {
1.10 ratchov 865: fd = STDOUT_FILENO;
866: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
867: perror(name);
868: } else {
869: fd = open(name,
870: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
871: if (fd < 0) {
872: perror(name);
873: return NULL;
874: }
875: }
1.1 ratchov 876: f = (struct wav *)pipe_new(ops, fd, name);
1.18 ratchov 877: if (f == NULL) {
878: close(fd);
1.4 ratchov 879: return NULL;
1.18 ratchov 880: }
1.27 ratchov 881: f->pstate = WAV_CFG;
1.1 ratchov 882: if (hdr == HDR_WAV) {
1.2 ratchov 883: par->le = 1;
1.3 ratchov 884: par->sig = (par->bits <= 8) ? 0 : 1;
1.2 ratchov 885: par->bps = (par->bits + 7) / 8;
1.15 ratchov 886: if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) {
1.10 ratchov 887: file_del((struct file *)f);
888: return NULL;
889: }
1.1 ratchov 890: f->wbytes = WAV_DATAMAX;
1.15 ratchov 891: f->endpos = f->startpos;
892: } else {
1.1 ratchov 893: f->wbytes = -1;
1.15 ratchov 894: f->startpos = f->endpos = 0;
895: }
1.27 ratchov 896: f->dev = dev;
897: f->mmc = mmc;
1.16 ratchov 898: f->join = join;
1.15 ratchov 899: f->mode = mode;
900: f->hpar = *par;
1.1 ratchov 901: f->hdr = hdr;
1.15 ratchov 902: f->xrun = xrun;
903: wwav_new((struct file *)f);
1.12 ratchov 904: #ifdef DEBUG
905: if (debug_level >= 2) {
906: dbg_puts(name);
1.27 ratchov 907: dbg_puts(":");
908: if (f->mode & MODE_RECMASK) {
909: dbg_puts(" recording ");
910: aparams_dbg(par);
911: if (f->mmc)
912: dbg_puts(", mmc");
913: }
914: if (f->mode & MODE_MIDIIN)
915: dbg_puts(" midi/in");
1.12 ratchov 916: dbg_puts("\n");
917: }
918: #endif
1.27 ratchov 919: f->next = wav_list;
920: wav_list = f;
1.1 ratchov 921: return f;
922: }
923:
1.6 ratchov 924: void
1.15 ratchov 925: rwav_done(struct aproc *p)
926: {
927: struct wav *f = (struct wav *)p->u.io.file;
928:
929: if (f->slot >= 0)
1.28 ! ratchov 930: dev_slotdel(f->dev, f->slot);
1.15 ratchov 931: f->slot = -1;
932: rfile_done(p);
933: }
934:
935: int
936: rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
1.13 ratchov 937: {
1.15 ratchov 938: struct wav *f = (struct wav *)p->u.io.file;
939: struct abuf *obuf;
1.13 ratchov 940:
1.15 ratchov 941: if (!wav_rdata(f))
942: return 0;
1.17 ratchov 943: obuf = LIST_FIRST(&p->outs);
1.15 ratchov 944: if (obuf && f->pstate >= WAV_RUN) {
945: if (!abuf_flush(obuf))
946: return 0;
1.6 ratchov 947: }
1.15 ratchov 948: return 1;
1.6 ratchov 949: }
950:
1.15 ratchov 951: int
952: rwav_out(struct aproc *p, struct abuf *obuf)
1.1 ratchov 953: {
1.15 ratchov 954: struct wav *f = (struct wav *)p->u.io.file;
1.1 ratchov 955:
1.15 ratchov 956: if (f->pipe.file.state & FILE_RINUSE)
957: return 0;
958: for (;;) {
959: if (!wav_rdata(f))
1.1 ratchov 960: return 0;
961: }
1.15 ratchov 962: return 1;
963: }
964:
965: struct aproc *
966: rwav_new(struct file *f)
967: {
968: struct aproc *p;
969:
970: p = aproc_new(&rwav_ops, f->name);
971: p->u.io.file = f;
1.24 deraadt 972: p->u.io.partial = 0;
1.15 ratchov 973: f->rproc = p;
974: return p;
975: }
976:
977: void
978: wwav_done(struct aproc *p)
979: {
980: struct wav *f = (struct wav *)p->u.io.file;
981:
982: if (f->slot >= 0)
1.28 ! ratchov 983: dev_slotdel(f->dev, f->slot);
1.15 ratchov 984: f->slot = -1;
985: wfile_done(p);
986: }
987:
988: int
989: wwav_in(struct aproc *p, struct abuf *ibuf)
990: {
991: struct wav *f = (struct wav *)p->u.io.file;
992:
993: if (f->pipe.file.state & FILE_WINUSE)
1.8 jakemsr 994: return 0;
1.15 ratchov 995: for (;;) {
996: if (!wav_wdata(f))
997: return 0;
1.6 ratchov 998: }
1.15 ratchov 999: return 1;
1.1 ratchov 1000: }
1001:
1.15 ratchov 1002: int
1003: wwav_out(struct aproc *p, struct abuf *obuf_dummy)
1.1 ratchov 1004: {
1.17 ratchov 1005: struct abuf *ibuf = LIST_FIRST(&p->ins);
1.15 ratchov 1006: struct wav *f = (struct wav *)p->u.io.file;
1.3 ratchov 1007:
1.15 ratchov 1008: if (ibuf && f->pstate == WAV_RUN) {
1009: if (!abuf_fill(ibuf))
1.1 ratchov 1010: return 0;
1011: }
1.15 ratchov 1012: if (!wav_wdata(f))
1013: return 0;
1014: return 1;
1.1 ratchov 1015: }
1016:
1.15 ratchov 1017: struct aproc *
1018: wwav_new(struct file *f)
1.1 ratchov 1019: {
1.15 ratchov 1020: struct aproc *p;
1.1 ratchov 1021:
1.15 ratchov 1022: p = aproc_new(&wwav_ops, f->name);
1023: p->u.io.file = f;
1.24 deraadt 1024: p->u.io.partial = 0;
1.15 ratchov 1025: f->wproc = p;
1026: return p;
1.1 ratchov 1027: }