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