Annotation of src/usr.bin/aucat/aproc.c, Revision 1.7
1.7 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.6 2008/08/14 09:39:16 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: {
73: DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
74: free(p);
75: }
76:
77: void
78: aproc_setin(struct aproc *p, struct abuf *ibuf)
79: {
80: LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
81: ibuf->rproc = p;
82: if (p->ops->newin)
83: p->ops->newin(p, ibuf);
84: }
85:
86: void
87: aproc_setout(struct aproc *p, struct abuf *obuf)
88: {
89: LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
90: obuf->wproc = p;
91: if (p->ops->newout)
92: p->ops->newout(p, obuf);
93: }
94:
95: int
96: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
97: {
98: struct abuf *obuf = LIST_FIRST(&p->obuflist);
99: struct file *f = p->u.io.file;
100: unsigned char *data;
101: unsigned count;
102:
1.6 ratchov 103: DPRINTFN(3, "rpipe_in: %s\n", p->name);
104:
1.1 ratchov 105: if (ABUF_FULL(obuf))
106: return 0;
107: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 108: count = file_read(f, data, count);
109: abuf_wcommit(obuf, count);
1.1 ratchov 110: abuf_flush(obuf);
111: return !ABUF_FULL(obuf);
112: }
113:
114: int
115: rpipe_out(struct aproc *p, struct abuf *obuf)
116: {
117: struct file *f = p->u.io.file;
118: unsigned char *data;
119: unsigned count;
120:
1.6 ratchov 121: DPRINTFN(3, "rpipe_out: %s\n", p->name);
122:
1.1 ratchov 123: if (!(f->state & FILE_ROK))
124: return 0;
125: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 126: count = file_read(f, data, count);
127: abuf_wcommit(obuf, count);
1.1 ratchov 128: return f->state & FILE_ROK;
129: }
130:
131: void
132: rpipe_del(struct aproc *p)
133: {
134: struct file *f = p->u.io.file;
135:
136: f->rproc = NULL;
137: f->events &= ~POLLIN;
138: aproc_del(p);
139: }
140:
141: void
142: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
143: {
144: DPRINTFN(3, "rpipe_eof: %s\n", p->name);
145: abuf_eof(LIST_FIRST(&p->obuflist));
146: rpipe_del(p);
147: }
148:
149: void
150: rpipe_hup(struct aproc *p, struct abuf *obuf)
151: {
152: DPRINTFN(3, "rpipe_hup: %s\n", p->name);
153: rpipe_del(p);
154: }
155:
156: struct aproc_ops rpipe_ops = {
157: "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL
158: };
159:
160: struct aproc *
161: rpipe_new(struct file *f)
162: {
163: struct aproc *p;
164:
165: p = aproc_new(&rpipe_ops, f->name);
166: p->u.io.file = f;
167: f->rproc = p;
168: f->events |= POLLIN;
169: return p;
170: }
171:
172: void
173: wpipe_del(struct aproc *p)
174: {
175: struct file *f = p->u.io.file;
176:
177: f->wproc = NULL;
178: f->events &= ~POLLOUT;
179: aproc_del(p);
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);
217: wpipe_del(p);
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);
228: wpipe_del(p);
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));
236: wpipe_del(p);
237: }
238:
239: struct aproc_ops wpipe_ops = {
240: "wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL
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 = {
457: "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout
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: void
500: sub_del(struct aproc *p)
501: {
502: aproc_del(p);
503: }
504:
505: int
506: sub_in(struct aproc *p, struct abuf *ibuf)
507: {
508: struct abuf *i, *inext;
1.3 ratchov 509: unsigned done, drop;
1.1 ratchov 510: int again;
511:
512: again = 1;
513: done = ibuf->used;
1.2 ratchov 514: for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1 ratchov 515: inext = LIST_NEXT(i, oent);
1.5 ratchov 516: if (!ABUF_WOK(i)) {
517: if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) {
518: if (i->xrun == XRUN_ERROR) {
519: sub_rm(p, i);
520: abuf_eof(i);
521: continue;
522: }
523: drop = ibuf->used;
524: if (i->xrun == XRUN_SYNC)
1.7 ! ratchov 525: i->silence += drop;
1.5 ratchov 526: i->subdone += drop;
1.7 ! ratchov 527: DPRINTF("sub_in: silence = %u\n", i->silence);
1.5 ratchov 528: }
1.3 ratchov 529: } else {
1.1 ratchov 530: sub_bcopy(ibuf, i);
531: abuf_flush(i);
532: }
533: if (!ABUF_WOK(i))
534: again = 0;
535: if (done > i->subdone)
536: done = i->subdone;
537: }
538: LIST_FOREACH(i, &p->obuflist, oent) {
539: i->subdone -= done;
540: }
1.6 ratchov 541: abuf_rdiscard(ibuf, done);
1.1 ratchov 542: return again;
543: }
544:
545: int
546: sub_out(struct aproc *p, struct abuf *obuf)
547: {
548: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
549: struct abuf *i, *inext;
550: unsigned done;
551:
552: if (obuf->subdone >= ibuf->used)
553: return 0;
554:
555: sub_bcopy(ibuf, obuf);
556:
557: done = ibuf->used;
558: LIST_FOREACH(i, &p->obuflist, oent) {
559: if (i != obuf && ABUF_WOK(i)) {
560: sub_bcopy(ibuf, i);
561: abuf_flush(i);
562: }
563: if (done > i->subdone)
564: done = i->subdone;
565: }
566: if (done == 0)
567: return 0;
568: LIST_FOREACH(i, &p->obuflist, oent) {
569: i->subdone -= done;
570: }
1.6 ratchov 571: abuf_rdiscard(ibuf, done);
1.1 ratchov 572: if (ABUF_EOF(ibuf)) {
573: abuf_hup(ibuf);
574: for (i = LIST_FIRST(&p->obuflist);
1.2 ratchov 575: i != LIST_END(&p->obuflist);
1.1 ratchov 576: i = inext) {
577: inext = LIST_NEXT(i, oent);
578: if (i != ibuf)
579: abuf_eof(i);
580: }
581: ibuf->wproc = NULL;
582: sub_del(p);
583: return 0;
584: }
585: abuf_fill(ibuf);
586: return 1;
587: }
588:
589: void
590: sub_eof(struct aproc *p, struct abuf *ibuf)
591: {
592: struct abuf *obuf;
593:
594: while (!LIST_EMPTY(&p->obuflist)) {
595: obuf = LIST_FIRST(&p->obuflist);
596: sub_rm(p, obuf);
597: abuf_eof(obuf);
598: }
599: sub_del(p);
600: }
601:
602: void
603: sub_hup(struct aproc *p, struct abuf *obuf)
604: {
605: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
606:
607: DPRINTF("sub_hup: %s: detached\n", p->name);
608: sub_rm(p, obuf);
609: if (LIST_EMPTY(&p->obuflist)) {
610: abuf_hup(ibuf);
611: sub_del(p);
612: } else
613: abuf_run(ibuf);
614: DPRINTF("sub_hup: done\n");
615: }
616:
617: void
618: sub_newout(struct aproc *p, struct abuf *obuf)
619: {
620: obuf->subdone = 0;
1.5 ratchov 621: obuf->xrun = XRUN_IGNORE;
1.1 ratchov 622: }
623:
624: struct aproc_ops sub_ops = {
625: "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout
626: };
627:
628: struct aproc *
629: sub_new(void)
630: {
631: struct aproc *p;
632:
633: p = aproc_new(&sub_ops, "copy");
1.5 ratchov 634: p->u.sub.flags = 0;
1.1 ratchov 635: return p;
636: }
637:
638:
639: /*
640: * Convert one block.
641: */
642: void
643: conv_bcopy(struct aconv *ist, struct aconv *ost,
644: struct abuf *ibuf, struct abuf *obuf)
645: {
646: int *ictx;
647: unsigned inch, ibps;
648: unsigned char *idata;
649: int ibnext, isigbit;
650: unsigned ishift;
651: int isnext;
652: unsigned ipos, orate;
653: unsigned ifr;
654: int *octx;
655: unsigned onch, oshift;
656: int osigbit;
657: unsigned obps;
658: unsigned char *odata;
659: int obnext, osnext;
660: unsigned opos, irate;
661: unsigned ofr;
662: unsigned c, i;
663: int s, *ctx;
664: unsigned icount, ocount;
665:
666: /*
667: * It's ok to have s uninitialized, but we dont want the compiler to
668: * complain about it.
669: */
670: s = (int)0xdeadbeef;
671:
672: /*
673: * Calculate max frames readable at once from the input buffer.
674: */
675: idata = abuf_rgetblk(ibuf, &icount, 0);
676: ifr = icount / ibuf->bpf;
677:
678: odata = abuf_wgetblk(obuf, &ocount, 0);
679: ofr = ocount / obuf->bpf;
680:
681: /*
682: * Partially copy structures into local variables, to avoid
683: * unnecessary indirections; this also allows the compiler to
684: * order local variables more "cache-friendly".
685: */
686: ictx = ist->ctx + ist->cmin;
687: octx = ist->ctx + ost->cmin;
688: inch = ist->nch;
689: ibps = ist->bps;
690: ibnext = ist->bnext;
691: isigbit = ist->sigbit;
692: ishift = ist->shift;
693: isnext = ist->snext;
694: ipos = ist->pos;
695: irate = ist->rate;
696: onch = ost->nch;
697: oshift = ost->shift;
698: osigbit = ost->sigbit;
699: obps = ost->bps;
700: obnext = ost->bnext;
701: osnext = ost->snext;
702: opos = ost->pos;
703: orate = ost->rate;
704:
705: /*
706: * Start conversion.
707: */
708: idata += ist->bfirst;
709: odata += ost->bfirst;
710: DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
711: for (;;) {
712: if ((int)(ipos - opos) > 0) {
713: if (ofr == 0)
714: break;
715: ctx = octx;
716: for (c = onch; c > 0; c--) {
717: s = *ctx++ << 16;
718: s >>= oshift;
719: s ^= osigbit;
720: for (i = obps; i > 0; i--) {
721: *odata = (unsigned char)s;
722: s >>= 8;
723: odata += obnext;
724: }
725: odata += osnext;
726: }
727: opos += irate;
728: ofr--;
729: } else {
730: if (ifr == 0)
731: break;
732: ctx = ictx;
733: for (c = inch; c > 0; c--) {
734: for (i = ibps; i > 0; i--) {
735: s <<= 8;
736: s |= *idata;
737: idata += ibnext;
738: }
739: s ^= isigbit;
740: s <<= ishift;
741: *ctx++ = (short)(s >> 16);
742: idata += isnext;
743: }
744: ipos += orate;
745: ifr--;
746: }
747: }
748: ist->pos = ipos;
749: ost->pos = opos;
750: DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
751:
752: /*
753: * Update FIFO pointers.
754: */
755: icount -= ifr * ist->bpf;
756: ocount -= ofr * ost->bpf;
1.6 ratchov 757: abuf_rdiscard(ibuf, icount);
758: abuf_wcommit(obuf, ocount);
1.1 ratchov 759: }
760:
761: void
762: conv_del(struct aproc *p)
763: {
764: aproc_del(p);
765: }
766:
767: int
768: conv_in(struct aproc *p, struct abuf *ibuf)
769: {
770: struct abuf *obuf = LIST_FIRST(&p->obuflist);
771:
772: if (!ABUF_WOK(obuf))
773: return 0;
774: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
775: abuf_flush(obuf);
776: return ABUF_WOK(obuf);
777: }
778:
779: int
780: conv_out(struct aproc *p, struct abuf *obuf)
781: {
782: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
783:
784: if (!ABUF_ROK(ibuf))
785: return 0;
786: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
787: if (ABUF_EOF(ibuf)) {
788: obuf->wproc = NULL;
789: abuf_hup(ibuf);
790: conv_del(p);
791: return 0;
792: }
793: abuf_fill(ibuf);
794: return 1;
795: }
796:
797: void
798: conv_eof(struct aproc *p, struct abuf *ibuf)
799: {
800: abuf_eof(LIST_FIRST(&p->obuflist));
801: conv_del(p);
802: }
803:
804: void
805: conv_hup(struct aproc *p, struct abuf *obuf)
806: {
807: abuf_hup(LIST_FIRST(&p->ibuflist));
808: conv_del(p);
809: }
810:
811: void
812: aconv_init(struct aconv *st, struct aparams *par, int input)
813: {
814: unsigned i;
815:
816: st->bps = par->bps;
817: st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
818: if (par->msb) {
819: st->shift = 32 - par->bps * 8;
820: } else {
821: st->shift = 32 - par->bits;
822: }
823: if ((par->le && input) || (!par->le && !input)) {
824: st->bfirst = st->bps - 1;
825: st->bnext = -1;
826: st->snext = 2 * st->bps;
827: } else {
828: st->bfirst = 0;
829: st->bnext = 1;
830: st->snext = 0;
831: }
832: st->cmin = par->cmin;
833: st->nch = par->cmax - par->cmin + 1;
834: st->bpf = st->nch * st->bps;
835: st->rate = par->rate;
836: st->pos = 0;
837:
838: for (i = 0; i < CHAN_MAX; i++)
839: st->ctx[i] = 0;
840: }
841:
842: struct aproc_ops conv_ops = {
843: "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL
844: };
845:
846: struct aproc *
847: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
848: {
849: struct aproc *p;
850:
851: p = aproc_new(&conv_ops, name);
852: aconv_init(&p->u.conv.ist, ipar, 1);
853: aconv_init(&p->u.conv.ost, opar, 0);
854: return p;
855: }