Annotation of src/usr.bin/aucat/aproc.c, Revision 1.8
1.8 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.7 2008/08/14 09:44:15 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: /*
18: * aproc structures are simple audio processing units. They are
19: * interconnected by abuf structures and form a kind of circuit. aproc
20: * structure have call-backs that do the actual processing.
21: *
22: * This module implements the following processing units:
23: *
24: * - rpipe: read end of an unix file (pipe, socket, device...)
25: *
26: * - wpipe: write end of an unix file (pipe, socket, device...)
27: *
28: * - mix: mix N inputs -> 1 output
29: *
30: * - sub: from 1 input -> extract/copy N outputs
31: *
32: * - conv: converts/resamples/remaps a single stream
33: *
34: * TODO
35: *
36: * (easy) split the "conv" into 2 converters: one for input (that
37: * convers anything to 16bit signed) and one for the output (that
38: * converts 16bit signed to anything)
39: *
40: * (hard) add a lowpass filter for the resampler. Quality is
41: * not acceptable as is.
42: */
43: #include <err.h>
44: #include <limits.h>
45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48:
49: #include "conf.h"
50: #include "aparams.h"
51: #include "abuf.h"
52: #include "aproc.h"
53: #include "file.h"
54:
55: struct aproc *
56: aproc_new(struct aproc_ops *ops, char *name)
57: {
58: struct aproc *p;
59:
60: p = malloc(sizeof(struct aproc));
61: if (p == NULL)
62: err(1, name);
63: LIST_INIT(&p->ibuflist);
64: LIST_INIT(&p->obuflist);
65: p->name = name;
66: p->ops = ops;
67: return p;
68: }
69:
70: void
71: aproc_del(struct aproc *p)
72: {
1.8 ! ratchov 73: if (p->ops->done)
! 74: p->ops->done(p);
1.1 ratchov 75: DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
76: free(p);
77: }
78:
79: void
80: aproc_setin(struct aproc *p, struct abuf *ibuf)
81: {
82: LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
83: ibuf->rproc = p;
84: if (p->ops->newin)
85: p->ops->newin(p, ibuf);
86: }
87:
88: void
89: aproc_setout(struct aproc *p, struct abuf *obuf)
90: {
91: LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
92: obuf->wproc = p;
93: if (p->ops->newout)
94: p->ops->newout(p, obuf);
95: }
96:
97: int
98: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
99: {
100: struct abuf *obuf = LIST_FIRST(&p->obuflist);
101: struct file *f = p->u.io.file;
102: unsigned char *data;
103: unsigned count;
104:
1.6 ratchov 105: DPRINTFN(3, "rpipe_in: %s\n", p->name);
106:
1.1 ratchov 107: if (ABUF_FULL(obuf))
108: return 0;
109: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 110: count = file_read(f, data, count);
111: abuf_wcommit(obuf, count);
1.1 ratchov 112: abuf_flush(obuf);
113: return !ABUF_FULL(obuf);
114: }
115:
116: int
117: rpipe_out(struct aproc *p, struct abuf *obuf)
118: {
119: struct file *f = p->u.io.file;
120: unsigned char *data;
121: unsigned count;
122:
1.6 ratchov 123: DPRINTFN(3, "rpipe_out: %s\n", p->name);
124:
1.1 ratchov 125: if (!(f->state & FILE_ROK))
126: return 0;
127: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 128: count = file_read(f, data, count);
129: abuf_wcommit(obuf, count);
1.1 ratchov 130: return f->state & FILE_ROK;
131: }
132:
133: void
1.8 ! ratchov 134: rpipe_done(struct aproc *p)
1.1 ratchov 135: {
136: struct file *f = p->u.io.file;
137:
138: f->rproc = NULL;
139: f->events &= ~POLLIN;
140: }
141:
142: void
143: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
144: {
145: DPRINTFN(3, "rpipe_eof: %s\n", p->name);
146: abuf_eof(LIST_FIRST(&p->obuflist));
1.8 ! ratchov 147: aproc_del(p);
1.1 ratchov 148: }
149:
150: void
151: rpipe_hup(struct aproc *p, struct abuf *obuf)
152: {
153: DPRINTFN(3, "rpipe_hup: %s\n", p->name);
1.8 ! ratchov 154: aproc_del(p);
1.1 ratchov 155: }
156:
157: struct aproc_ops rpipe_ops = {
1.8 ! ratchov 158: "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL, rpipe_done
1.1 ratchov 159: };
160:
161: struct aproc *
162: rpipe_new(struct file *f)
163: {
164: struct aproc *p;
165:
166: p = aproc_new(&rpipe_ops, f->name);
167: p->u.io.file = f;
168: f->rproc = p;
169: f->events |= POLLIN;
170: return p;
171: }
172:
173: void
1.8 ! ratchov 174: wpipe_done(struct aproc *p)
1.1 ratchov 175: {
176: struct file *f = p->u.io.file;
177:
178: f->wproc = NULL;
179: f->events &= ~POLLOUT;
180: }
181:
182: int
183: wpipe_in(struct aproc *p, struct abuf *ibuf)
184: {
185: struct file *f = p->u.io.file;
186: unsigned char *data;
187: unsigned count;
188:
1.6 ratchov 189: DPRINTFN(3, "wpipe_in: %s\n", p->name);
190:
1.1 ratchov 191: if (!(f->state & FILE_WOK))
192: return 0;
193:
194: data = abuf_rgetblk(ibuf, &count, 0);
195: count = file_write(f, data, count);
1.6 ratchov 196: abuf_rdiscard(ibuf, count);
1.1 ratchov 197: return f->state & FILE_WOK;
198: }
199:
200: int
201: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
202: {
203: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
204: struct file *f = p->u.io.file;
205: unsigned char *data;
206: unsigned count;
207:
1.6 ratchov 208: DPRINTFN(3, "wpipe_out: %s\n", p->name);
209:
1.1 ratchov 210: if (ABUF_EMPTY(ibuf))
211: return 0;
212: data = abuf_rgetblk(ibuf, &count, 0);
213: count = file_write(f, data, count);
1.6 ratchov 214: abuf_rdiscard(ibuf, count);
1.1 ratchov 215: if (ABUF_EOF(ibuf)) {
216: abuf_hup(ibuf);
1.8 ! ratchov 217: aproc_del(p);
1.1 ratchov 218: return 0;
219: }
220: abuf_fill(ibuf);
221: return 1;
222: }
223:
224: void
225: wpipe_eof(struct aproc *p, struct abuf *ibuf)
226: {
227: DPRINTFN(3, "wpipe_eof: %s\n", p->name);
1.8 ! ratchov 228: aproc_del(p);
1.1 ratchov 229: }
230:
231: void
232: wpipe_hup(struct aproc *p, struct abuf *obuf_dummy)
233: {
234: DPRINTFN(3, "wpipe_hup: %s\n", p->name);
235: abuf_hup(LIST_FIRST(&p->ibuflist));
1.8 ! ratchov 236: aproc_del(p);
1.1 ratchov 237: }
238:
239: struct aproc_ops wpipe_ops = {
1.8 ! ratchov 240: "wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL, wpipe_done
1.1 ratchov 241: };
242:
243: struct aproc *
244: wpipe_new(struct file *f)
245: {
246: struct aproc *p;
247:
248: p = aproc_new(&wpipe_ops, f->name);
249: p->u.io.file = f;
250: f->wproc = p;
251: f->events |= POLLOUT;
252: return p;
253: }
254:
255: /*
256: * Fill an output block with silence.
257: */
258: void
259: mix_bzero(struct aproc *p)
260: {
261: struct abuf *obuf = LIST_FIRST(&p->obuflist);
262: short *odata;
263: unsigned ocount;
264:
1.6 ratchov 265: DPRINTFN(4, "mix_bzero: used = %u, todo = %u\n",
1.1 ratchov 266: obuf->used, obuf->mixtodo);
267: odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo);
268: if (ocount == 0)
269: return;
270: memset(odata, 0, ocount);
271: obuf->mixtodo += ocount;
272: DPRINTFN(4, "mix_bzero: ocount %u, todo %u\n", ocount, obuf->mixtodo);
273: }
274:
275: /*
276: * Mix an input block over an output block.
277: */
278: void
279: mix_badd(struct abuf *ibuf, struct abuf *obuf)
280: {
281: short *idata, *odata;
282: unsigned i, scount, icount, ocount;
283: int vol = ibuf->mixvol;
284:
1.6 ratchov 285: DPRINTFN(4, "mix_badd: todo = %u, done = %u\n",
1.1 ratchov 286: obuf->mixtodo, ibuf->mixdone);
287:
288: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
289: if (icount == 0)
290: return;
291:
292: odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone);
293: if (ocount == 0)
294: return;
295:
296: scount = (icount < ocount) ? icount : ocount;
297: for (i = scount / sizeof(short); i > 0; i--) {
298: *odata += (*idata * vol) >> ADATA_SHIFT;
299: idata++;
300: odata++;
1.6 ratchov 301: }
302: abuf_rdiscard(ibuf, scount);
1.1 ratchov 303: ibuf->mixdone += scount;
304:
1.6 ratchov 305: DPRINTFN(4, "mix_badd: added %u, done = %u, todo = %u\n",
1.1 ratchov 306: scount, ibuf->mixdone, obuf->mixtodo);
307: }
308:
309: /*
310: * Remove an input stream from the mixer.
311: */
312: void
313: mix_rm(struct aproc *p, struct abuf *ibuf)
314: {
315: LIST_REMOVE(ibuf, ient);
316: DPRINTF("mix_rm: %s\n", p->name);
317: }
318:
319: int
320: mix_in(struct aproc *p, struct abuf *ibuf)
321: {
322: struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
1.7 ratchov 323: unsigned ocount;
1.1 ratchov 324:
1.7 ratchov 325: DPRINTFN(4, "mix_in: used = %u, done = %u, todo = %u\n",
1.1 ratchov 326: ibuf->used, ibuf->mixdone, obuf->mixtodo);
1.3 ratchov 327:
1.1 ratchov 328: if (ibuf->mixdone >= obuf->mixtodo)
329: return 0;
330: mix_badd(ibuf, obuf);
331: ocount = obuf->mixtodo;
332: LIST_FOREACH(i, &p->ibuflist, ient) {
333: if (ocount > i->mixdone)
334: ocount = i->mixdone;
335: }
336: if (ocount == 0)
337: return 0;
338:
1.6 ratchov 339: abuf_wcommit(obuf, ocount);
1.1 ratchov 340: obuf->mixtodo -= ocount;
341: abuf_flush(obuf);
342: mix_bzero(p);
1.2 ratchov 343: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1 ratchov 344: inext = LIST_NEXT(i, ient);
345: i->mixdone -= ocount;
346: if (i != ibuf && i->mixdone < obuf->mixtodo) {
347: if (ABUF_EOF(i)) {
348: mix_rm(p, i);
349: abuf_hup(i);
350: continue;
351: }
352: mix_badd(i, obuf);
353: abuf_fill(i);
354: }
355: }
356: return 1;
357: }
358:
359: int
360: mix_out(struct aproc *p, struct abuf *obuf)
361: {
362: struct abuf *i, *inext;
1.3 ratchov 363: unsigned ocount, drop;
1.1 ratchov 364:
1.6 ratchov 365: DPRINTFN(4, "mix_out: used = %u, todo = %u\n",
1.1 ratchov 366: obuf->used, obuf->mixtodo);
367:
368: mix_bzero(p);
369: ocount = obuf->mixtodo;
1.2 ratchov 370: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1 ratchov 371: inext = LIST_NEXT(i, ient);
1.5 ratchov 372: if (!ABUF_ROK(i)) {
373: if ((p->u.mix.flags & MIX_DROP) && i->mixdone == 0) {
374: if (i->xrun == XRUN_ERROR) {
375: mix_rm(p, i);
376: abuf_hup(i);
377: continue;
378: }
379: drop = obuf->mixtodo;
380: i->mixdone += drop;
381: if (i->xrun == XRUN_SYNC)
1.7 ratchov 382: i->drop += drop;
383: DPRINTF("mix_out: drop = %u\n", i->drop);
1.5 ratchov 384: }
1.3 ratchov 385: } else
386: mix_badd(i, obuf);
1.1 ratchov 387: if (ocount > i->mixdone)
388: ocount = i->mixdone;
389: if (ABUF_EOF(i)) {
390: mix_rm(p, i);
391: abuf_hup(i);
392: continue;
393: }
394: abuf_fill(i);
395: }
396: if (ocount == 0)
397: return 0;
398: if (LIST_EMPTY(&p->ibuflist)) {
399: DPRINTF("mix_out: nothing more to do...\n");
400: obuf->wproc = NULL;
401: aproc_del(p);
402: return 0;
403: }
1.6 ratchov 404: abuf_wcommit(obuf, ocount);
1.1 ratchov 405: obuf->mixtodo -= ocount;
406: LIST_FOREACH(i, &p->ibuflist, ient) {
407: i->mixdone -= ocount;
408: }
409: return 1;
410: }
411:
412: void
413: mix_eof(struct aproc *p, struct abuf *ibuf)
414: {
415: struct abuf *obuf = LIST_FIRST(&p->obuflist);
416:
417: DPRINTF("mix_eof: %s: detached\n", p->name);
418: mix_rm(p, ibuf);
419: /*
420: * If there's no more inputs, abuf_run() will trigger the eof
421: * condition and propagate it, so no need to handle it here.
422: */
423: abuf_run(obuf);
424: DPRINTF("mix_eof: done\n");
425: }
426:
427: void
428: mix_hup(struct aproc *p, struct abuf *obuf)
429: {
430: struct abuf *ibuf;
431:
432: while (!LIST_EMPTY(&p->ibuflist)) {
433: ibuf = LIST_FIRST(&p->ibuflist);
434: mix_rm(p, ibuf);
435: abuf_hup(ibuf);
436: }
437: DPRINTF("mix_hup: %s: done\n", p->name);
438: aproc_del(p);
439: }
440:
441: void
442: mix_newin(struct aproc *p, struct abuf *ibuf)
443: {
444: ibuf->mixdone = 0;
445: ibuf->mixvol = ADATA_UNIT;
1.5 ratchov 446: ibuf->xrun = XRUN_IGNORE;
1.1 ratchov 447: }
448:
449: void
450: mix_newout(struct aproc *p, struct abuf *obuf)
451: {
452: obuf->mixtodo = 0;
453: mix_bzero(p);
454: }
455:
456: struct aproc_ops mix_ops = {
1.8 ! ratchov 457: "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout, NULL
1.1 ratchov 458: };
459:
460: struct aproc *
461: mix_new(void)
462: {
463: struct aproc *p;
464:
465: p = aproc_new(&mix_ops, "softmix");
1.5 ratchov 466: p->u.mix.flags = 0;
1.1 ratchov 467: return p;
468: }
469:
470: /*
471: * Copy data from ibuf to obuf.
472: */
473: void
474: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
475: {
476: unsigned char *idata, *odata;
477: unsigned icount, ocount, scount;
478:
479: idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
480: if (icount == 0)
481: return;
482: odata = abuf_wgetblk(obuf, &ocount, 0);
483: if (ocount == 0)
484: return;
485: scount = (icount < ocount) ? icount : ocount;
486: memcpy(odata, idata, scount);
1.6 ratchov 487: abuf_wcommit(obuf, scount);
1.1 ratchov 488: obuf->subdone += scount;
489: DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
490: }
491:
492: void
493: sub_rm(struct aproc *p, struct abuf *obuf)
494: {
495: LIST_REMOVE(obuf, oent);
496: DPRINTF("sub_rm: %s\n", p->name);
497: }
498:
499: int
500: sub_in(struct aproc *p, struct abuf *ibuf)
501: {
502: struct abuf *i, *inext;
1.3 ratchov 503: unsigned done, drop;
1.1 ratchov 504: int again;
505:
506: again = 1;
507: done = ibuf->used;
1.2 ratchov 508: for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1 ratchov 509: inext = LIST_NEXT(i, oent);
1.5 ratchov 510: if (!ABUF_WOK(i)) {
511: if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) {
512: if (i->xrun == XRUN_ERROR) {
513: sub_rm(p, i);
514: abuf_eof(i);
515: continue;
516: }
517: drop = ibuf->used;
518: if (i->xrun == XRUN_SYNC)
1.7 ratchov 519: i->silence += drop;
1.5 ratchov 520: i->subdone += drop;
1.7 ratchov 521: DPRINTF("sub_in: silence = %u\n", i->silence);
1.5 ratchov 522: }
1.3 ratchov 523: } else {
1.1 ratchov 524: sub_bcopy(ibuf, i);
525: abuf_flush(i);
526: }
527: if (!ABUF_WOK(i))
528: again = 0;
529: if (done > i->subdone)
530: done = i->subdone;
531: }
532: LIST_FOREACH(i, &p->obuflist, oent) {
533: i->subdone -= done;
534: }
1.6 ratchov 535: abuf_rdiscard(ibuf, done);
1.1 ratchov 536: return again;
537: }
538:
539: int
540: sub_out(struct aproc *p, struct abuf *obuf)
541: {
542: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
543: struct abuf *i, *inext;
544: unsigned done;
545:
546: if (obuf->subdone >= ibuf->used)
547: return 0;
548:
549: sub_bcopy(ibuf, obuf);
550:
551: done = ibuf->used;
552: LIST_FOREACH(i, &p->obuflist, oent) {
553: if (i != obuf && ABUF_WOK(i)) {
554: sub_bcopy(ibuf, i);
555: abuf_flush(i);
556: }
557: if (done > i->subdone)
558: done = i->subdone;
559: }
560: if (done == 0)
561: return 0;
562: LIST_FOREACH(i, &p->obuflist, oent) {
563: i->subdone -= done;
564: }
1.6 ratchov 565: abuf_rdiscard(ibuf, done);
1.1 ratchov 566: if (ABUF_EOF(ibuf)) {
567: abuf_hup(ibuf);
568: for (i = LIST_FIRST(&p->obuflist);
1.2 ratchov 569: i != LIST_END(&p->obuflist);
1.1 ratchov 570: i = inext) {
571: inext = LIST_NEXT(i, oent);
572: if (i != ibuf)
573: abuf_eof(i);
574: }
575: ibuf->wproc = NULL;
1.8 ! ratchov 576: aproc_del(p);
1.1 ratchov 577: return 0;
578: }
579: abuf_fill(ibuf);
580: return 1;
581: }
582:
583: void
584: sub_eof(struct aproc *p, struct abuf *ibuf)
585: {
586: struct abuf *obuf;
587:
588: while (!LIST_EMPTY(&p->obuflist)) {
589: obuf = LIST_FIRST(&p->obuflist);
590: sub_rm(p, obuf);
591: abuf_eof(obuf);
592: }
1.8 ! ratchov 593: aproc_del(p);
1.1 ratchov 594: }
595:
596: void
597: sub_hup(struct aproc *p, struct abuf *obuf)
598: {
599: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
600:
601: DPRINTF("sub_hup: %s: detached\n", p->name);
602: sub_rm(p, obuf);
603: if (LIST_EMPTY(&p->obuflist)) {
604: abuf_hup(ibuf);
1.8 ! ratchov 605: aproc_del(p);
1.1 ratchov 606: } else
607: abuf_run(ibuf);
608: DPRINTF("sub_hup: done\n");
609: }
610:
611: void
612: sub_newout(struct aproc *p, struct abuf *obuf)
613: {
614: obuf->subdone = 0;
1.5 ratchov 615: obuf->xrun = XRUN_IGNORE;
1.1 ratchov 616: }
617:
618: struct aproc_ops sub_ops = {
1.8 ! ratchov 619: "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout, NULL
1.1 ratchov 620: };
621:
622: struct aproc *
623: sub_new(void)
624: {
625: struct aproc *p;
626:
627: p = aproc_new(&sub_ops, "copy");
1.5 ratchov 628: p->u.sub.flags = 0;
1.1 ratchov 629: return p;
630: }
631:
632:
633: /*
634: * Convert one block.
635: */
636: void
637: conv_bcopy(struct aconv *ist, struct aconv *ost,
638: struct abuf *ibuf, struct abuf *obuf)
639: {
640: int *ictx;
641: unsigned inch, ibps;
642: unsigned char *idata;
643: int ibnext, isigbit;
644: unsigned ishift;
645: int isnext;
646: unsigned ipos, orate;
647: unsigned ifr;
648: int *octx;
649: unsigned onch, oshift;
650: int osigbit;
651: unsigned obps;
652: unsigned char *odata;
653: int obnext, osnext;
654: unsigned opos, irate;
655: unsigned ofr;
656: unsigned c, i;
657: int s, *ctx;
658: unsigned icount, ocount;
659:
660: /*
661: * It's ok to have s uninitialized, but we dont want the compiler to
662: * complain about it.
663: */
664: s = (int)0xdeadbeef;
665:
666: /*
667: * Calculate max frames readable at once from the input buffer.
668: */
669: idata = abuf_rgetblk(ibuf, &icount, 0);
670: ifr = icount / ibuf->bpf;
671:
672: odata = abuf_wgetblk(obuf, &ocount, 0);
673: ofr = ocount / obuf->bpf;
674:
675: /*
676: * Partially copy structures into local variables, to avoid
677: * unnecessary indirections; this also allows the compiler to
678: * order local variables more "cache-friendly".
679: */
680: ictx = ist->ctx + ist->cmin;
681: octx = ist->ctx + ost->cmin;
682: inch = ist->nch;
683: ibps = ist->bps;
684: ibnext = ist->bnext;
685: isigbit = ist->sigbit;
686: ishift = ist->shift;
687: isnext = ist->snext;
688: ipos = ist->pos;
689: irate = ist->rate;
690: onch = ost->nch;
691: oshift = ost->shift;
692: osigbit = ost->sigbit;
693: obps = ost->bps;
694: obnext = ost->bnext;
695: osnext = ost->snext;
696: opos = ost->pos;
697: orate = ost->rate;
698:
699: /*
700: * Start conversion.
701: */
702: idata += ist->bfirst;
703: odata += ost->bfirst;
704: DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
705: for (;;) {
706: if ((int)(ipos - opos) > 0) {
707: if (ofr == 0)
708: break;
709: ctx = octx;
710: for (c = onch; c > 0; c--) {
711: s = *ctx++ << 16;
712: s >>= oshift;
713: s ^= osigbit;
714: for (i = obps; i > 0; i--) {
715: *odata = (unsigned char)s;
716: s >>= 8;
717: odata += obnext;
718: }
719: odata += osnext;
720: }
721: opos += irate;
722: ofr--;
723: } else {
724: if (ifr == 0)
725: break;
726: ctx = ictx;
727: for (c = inch; c > 0; c--) {
728: for (i = ibps; i > 0; i--) {
729: s <<= 8;
730: s |= *idata;
731: idata += ibnext;
732: }
733: s ^= isigbit;
734: s <<= ishift;
735: *ctx++ = (short)(s >> 16);
736: idata += isnext;
737: }
738: ipos += orate;
739: ifr--;
740: }
741: }
742: ist->pos = ipos;
743: ost->pos = opos;
744: DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
745:
746: /*
747: * Update FIFO pointers.
748: */
749: icount -= ifr * ist->bpf;
750: ocount -= ofr * ost->bpf;
1.6 ratchov 751: abuf_rdiscard(ibuf, icount);
752: abuf_wcommit(obuf, ocount);
1.1 ratchov 753: }
754:
755: int
756: conv_in(struct aproc *p, struct abuf *ibuf)
757: {
758: struct abuf *obuf = LIST_FIRST(&p->obuflist);
759:
760: if (!ABUF_WOK(obuf))
761: return 0;
762: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
763: abuf_flush(obuf);
764: return ABUF_WOK(obuf);
765: }
766:
767: int
768: conv_out(struct aproc *p, struct abuf *obuf)
769: {
770: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
771:
772: if (!ABUF_ROK(ibuf))
773: return 0;
774: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
775: if (ABUF_EOF(ibuf)) {
776: obuf->wproc = NULL;
777: abuf_hup(ibuf);
1.8 ! ratchov 778: aproc_del(p);
1.1 ratchov 779: return 0;
780: }
781: abuf_fill(ibuf);
782: return 1;
783: }
784:
785: void
786: conv_eof(struct aproc *p, struct abuf *ibuf)
787: {
788: abuf_eof(LIST_FIRST(&p->obuflist));
1.8 ! ratchov 789: aproc_del(p);
1.1 ratchov 790: }
791:
792: void
793: conv_hup(struct aproc *p, struct abuf *obuf)
794: {
795: abuf_hup(LIST_FIRST(&p->ibuflist));
1.8 ! ratchov 796: aproc_del(p);
1.1 ratchov 797: }
798:
799: void
800: aconv_init(struct aconv *st, struct aparams *par, int input)
801: {
802: unsigned i;
803:
804: st->bps = par->bps;
805: st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
806: if (par->msb) {
807: st->shift = 32 - par->bps * 8;
808: } else {
809: st->shift = 32 - par->bits;
810: }
811: if ((par->le && input) || (!par->le && !input)) {
812: st->bfirst = st->bps - 1;
813: st->bnext = -1;
814: st->snext = 2 * st->bps;
815: } else {
816: st->bfirst = 0;
817: st->bnext = 1;
818: st->snext = 0;
819: }
820: st->cmin = par->cmin;
821: st->nch = par->cmax - par->cmin + 1;
822: st->bpf = st->nch * st->bps;
823: st->rate = par->rate;
824: st->pos = 0;
825:
826: for (i = 0; i < CHAN_MAX; i++)
827: st->ctx[i] = 0;
828: }
829:
830: struct aproc_ops conv_ops = {
1.8 ! ratchov 831: "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL, NULL
1.1 ratchov 832: };
833:
834: struct aproc *
835: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
836: {
837: struct aproc *p;
838:
839: p = aproc_new(&conv_ops, name);
840: aconv_init(&p->u.conv.ist, ipar, 1);
841: aconv_init(&p->u.conv.ost, opar, 0);
842: return p;
843: }