Annotation of src/usr.bin/aucat/aproc.c, Revision 1.4
1.4 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.3 2008/06/02 17:03:25 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) handle underruns in rpipe and mix
41: *
42: * (hard) handle overruns in wpipe and sub
43: *
44: * (hard) add a lowpass filter for the resampler. Quality is
45: * not acceptable as is.
46: */
47: #include <err.h>
48: #include <limits.h>
49: #include <stdio.h>
50: #include <stdlib.h>
51: #include <string.h>
52:
53: #include "conf.h"
54: #include "aparams.h"
55: #include "abuf.h"
56: #include "aproc.h"
57: #include "file.h"
58:
59: struct aproc *
60: aproc_new(struct aproc_ops *ops, char *name)
61: {
62: struct aproc *p;
63:
64: p = malloc(sizeof(struct aproc));
65: if (p == NULL)
66: err(1, name);
67: LIST_INIT(&p->ibuflist);
68: LIST_INIT(&p->obuflist);
69: p->name = name;
70: p->ops = ops;
71: return p;
72: }
73:
74: void
75: aproc_del(struct aproc *p)
76: {
77: DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
78: free(p);
79: }
80:
81: void
82: aproc_setin(struct aproc *p, struct abuf *ibuf)
83: {
84: LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
85: ibuf->rproc = p;
86: if (p->ops->newin)
87: p->ops->newin(p, ibuf);
88: }
89:
90: void
91: aproc_setout(struct aproc *p, struct abuf *obuf)
92: {
93: LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
94: obuf->wproc = p;
95: if (p->ops->newout)
96: p->ops->newout(p, obuf);
97: }
98:
99: int
100: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
101: {
102: struct abuf *obuf = LIST_FIRST(&p->obuflist);
103: struct file *f = p->u.io.file;
104: unsigned char *data;
105: unsigned count;
106:
107: if (ABUF_FULL(obuf))
108: return 0;
109: data = abuf_wgetblk(obuf, &count, 0);
110: obuf->used += file_read(f, data, count);
111: abuf_flush(obuf);
112: return !ABUF_FULL(obuf);
113: }
114:
115: int
116: rpipe_out(struct aproc *p, struct abuf *obuf)
117: {
118: struct file *f = p->u.io.file;
119: unsigned char *data;
120: unsigned count;
121:
122: if (!(f->state & FILE_ROK))
123: return 0;
124: data = abuf_wgetblk(obuf, &count, 0);
125: obuf->used += file_read(f, data, count);
126: return f->state & FILE_ROK;
127: }
128:
129: void
130: rpipe_del(struct aproc *p)
131: {
132: struct file *f = p->u.io.file;
133:
134: f->rproc = NULL;
135: f->events &= ~POLLIN;
136: aproc_del(p);
137: }
138:
139: void
140: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
141: {
142: DPRINTFN(3, "rpipe_eof: %s\n", p->name);
143: abuf_eof(LIST_FIRST(&p->obuflist));
144: rpipe_del(p);
145: }
146:
147: void
148: rpipe_hup(struct aproc *p, struct abuf *obuf)
149: {
150: DPRINTFN(3, "rpipe_hup: %s\n", p->name);
151: rpipe_del(p);
152: }
153:
154: struct aproc_ops rpipe_ops = {
155: "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL
156: };
157:
158: struct aproc *
159: rpipe_new(struct file *f)
160: {
161: struct aproc *p;
162:
163: p = aproc_new(&rpipe_ops, f->name);
164: p->u.io.file = f;
165: f->rproc = p;
166: f->events |= POLLIN;
167: return p;
168: }
169:
170: void
171: wpipe_del(struct aproc *p)
172: {
173: struct file *f = p->u.io.file;
174:
175: f->wproc = NULL;
176: f->events &= ~POLLOUT;
177: aproc_del(p);
178: }
179:
180: int
181: wpipe_in(struct aproc *p, struct abuf *ibuf)
182: {
183: struct file *f = p->u.io.file;
184: unsigned char *data;
185: unsigned count;
186:
187: if (!(f->state & FILE_WOK))
188: return 0;
189:
190: data = abuf_rgetblk(ibuf, &count, 0);
191: count = file_write(f, data, count);
192: ibuf->used -= count;
193: ibuf->start += count;
194: if (ibuf->start >= ibuf->len)
195: ibuf->start -= ibuf->len;
196: return f->state & FILE_WOK;
197: }
198:
199: int
200: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
201: {
202: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
203: struct file *f = p->u.io.file;
204: unsigned char *data;
205: unsigned count;
206:
207: if (ABUF_EMPTY(ibuf))
208: return 0;
209: data = abuf_rgetblk(ibuf, &count, 0);
210: count = file_write(f, data, count);
211: ibuf->used -= count;
212: ibuf->start += count;
213: if (ibuf->start >= ibuf->len)
214: ibuf->start -= ibuf->len;
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:
265: DPRINTFN(4, "mix_bzero: used = %u, zero = %u\n",
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:
285: DPRINTFN(4, "mix_badd: zero = %u, done = %u\n",
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++;
301: }
302:
303: ibuf->used -= scount;
304: ibuf->mixdone += scount;
305: ibuf->start += scount;
306: if (ibuf->start >= ibuf->len)
307: ibuf->start -= ibuf->len;
308:
309: DPRINTFN(4, "mix_badd: added %u, done = %u, zero = %u\n",
310: scount, ibuf->mixdone, obuf->mixtodo);
311: }
312:
313: /*
314: * Remove an input stream from the mixer.
315: */
316: void
317: mix_rm(struct aproc *p, struct abuf *ibuf)
318: {
319: LIST_REMOVE(ibuf, ient);
320: DPRINTF("mix_rm: %s\n", p->name);
321: }
322:
323: int
324: mix_in(struct aproc *p, struct abuf *ibuf)
325: {
326: struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
1.3 ratchov 327: unsigned icount, ocount;
1.1 ratchov 328:
329: DPRINTFN(4, "mix_in: used = %u, done = %u, zero = %u\n",
330: ibuf->used, ibuf->mixdone, obuf->mixtodo);
331:
1.3 ratchov 332: /*
333: * discard data already sent as silence
334: */
335: if (ibuf->mixdrop > 0) {
336: icount = ibuf->mixdrop;
337: if (icount > ibuf->used)
338: icount = ibuf->used;
339: ibuf->used -= icount;
340: ibuf->start += icount;
341: if (ibuf->start >= ibuf->len)
342: ibuf->start -= ibuf->len;
343: ibuf->mixdrop -= icount;
344: DPRINTF("mix_in: catched xruns, drop = %u\n", ibuf->mixdrop);
345: }
346:
1.1 ratchov 347: if (ibuf->mixdone >= obuf->mixtodo)
348: return 0;
349: mix_badd(ibuf, obuf);
350: ocount = obuf->mixtodo;
351: LIST_FOREACH(i, &p->ibuflist, ient) {
352: if (ocount > i->mixdone)
353: ocount = i->mixdone;
354: }
355: if (ocount == 0)
356: return 0;
357:
358: obuf->used += ocount;
359: obuf->mixtodo -= ocount;
360: abuf_flush(obuf);
361: mix_bzero(p);
1.2 ratchov 362: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1 ratchov 363: inext = LIST_NEXT(i, ient);
364: i->mixdone -= ocount;
365: if (i != ibuf && i->mixdone < obuf->mixtodo) {
366: if (ABUF_EOF(i)) {
367: mix_rm(p, i);
368: abuf_hup(i);
369: continue;
370: }
371: mix_badd(i, obuf);
372: abuf_fill(i);
373: }
374: }
375: return 1;
376: }
377:
378: int
379: mix_out(struct aproc *p, struct abuf *obuf)
380: {
381: struct abuf *i, *inext;
1.3 ratchov 382: unsigned ocount, drop;
1.1 ratchov 383:
384: DPRINTFN(4, "mix_out: used = %u, zero = %u\n",
385: obuf->used, obuf->mixtodo);
386:
387: mix_bzero(p);
388: ocount = obuf->mixtodo;
1.2 ratchov 389: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1 ratchov 390: inext = LIST_NEXT(i, ient);
1.3 ratchov 391: if (!ABUF_ROK(i) && i->mixdone == 0) {
392: drop = obuf->mixtodo;
393: i->mixdone += drop;
394: i->mixdrop += drop;
395: DPRINTF("mix_out: xrun, drop = %u\n", i->mixdrop);
396: } else
397: mix_badd(i, obuf);
1.1 ratchov 398: if (ocount > i->mixdone)
399: ocount = i->mixdone;
400: if (ABUF_EOF(i)) {
401: mix_rm(p, i);
402: abuf_hup(i);
403: continue;
404: }
405: abuf_fill(i);
406: }
407: if (ocount == 0)
408: return 0;
409: if (LIST_EMPTY(&p->ibuflist)) {
410: DPRINTF("mix_out: nothing more to do...\n");
411: obuf->wproc = NULL;
412: aproc_del(p);
413: return 0;
414: }
415: obuf->used += ocount;
416: obuf->mixtodo -= ocount;
417: LIST_FOREACH(i, &p->ibuflist, ient) {
418: i->mixdone -= ocount;
419: }
420: return 1;
421: }
422:
423: void
424: mix_eof(struct aproc *p, struct abuf *ibuf)
425: {
426: struct abuf *obuf = LIST_FIRST(&p->obuflist);
427:
428: DPRINTF("mix_eof: %s: detached\n", p->name);
429: mix_rm(p, ibuf);
430: /*
431: * If there's no more inputs, abuf_run() will trigger the eof
432: * condition and propagate it, so no need to handle it here.
433: */
434: abuf_run(obuf);
435: DPRINTF("mix_eof: done\n");
436: }
437:
438: void
439: mix_hup(struct aproc *p, struct abuf *obuf)
440: {
441: struct abuf *ibuf;
442:
443: while (!LIST_EMPTY(&p->ibuflist)) {
444: ibuf = LIST_FIRST(&p->ibuflist);
445: mix_rm(p, ibuf);
446: abuf_hup(ibuf);
447: }
448: DPRINTF("mix_hup: %s: done\n", p->name);
449: aproc_del(p);
450: }
451:
452: void
453: mix_newin(struct aproc *p, struct abuf *ibuf)
454: {
455: ibuf->mixdone = 0;
1.3 ratchov 456: ibuf->mixdrop = 0;
1.1 ratchov 457: ibuf->mixvol = ADATA_UNIT;
458: }
459:
460: void
461: mix_newout(struct aproc *p, struct abuf *obuf)
462: {
463: obuf->mixtodo = 0;
464: mix_bzero(p);
465: }
466:
467: struct aproc_ops mix_ops = {
468: "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout
469: };
470:
471: struct aproc *
472: mix_new(void)
473: {
474: struct aproc *p;
475:
476: p = aproc_new(&mix_ops, "softmix");
477: return p;
478: }
479:
480: /*
481: * Copy data from ibuf to obuf.
482: */
483: void
484: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
485: {
486: unsigned char *idata, *odata;
487: unsigned icount, ocount, scount;
488:
489: idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
490: if (icount == 0)
491: return;
492: odata = abuf_wgetblk(obuf, &ocount, 0);
493: if (ocount == 0)
494: return;
495: scount = (icount < ocount) ? icount : ocount;
496: memcpy(odata, idata, scount);
497: obuf->subdone += scount;
498: obuf->used += scount;
499: DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
500: }
501:
502: void
503: sub_rm(struct aproc *p, struct abuf *obuf)
504: {
505: LIST_REMOVE(obuf, oent);
506: DPRINTF("sub_rm: %s\n", p->name);
507: }
508:
509: void
510: sub_del(struct aproc *p)
511: {
512: aproc_del(p);
513: }
514:
515: int
516: sub_in(struct aproc *p, struct abuf *ibuf)
517: {
518: struct abuf *i, *inext;
1.3 ratchov 519: unsigned done, drop;
1.1 ratchov 520: int again;
521:
522: again = 1;
523: done = ibuf->used;
1.2 ratchov 524: for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1 ratchov 525: inext = LIST_NEXT(i, oent);
1.3 ratchov 526: if (!ABUF_WOK(i) && i->subdone == 0) {
527: drop = ibuf->used;
528: i->subdrop += drop;
529: i->subdone += drop;
530: DPRINTF("sub_in: xrun, drop = %u\n", i->subdrop);
531: } else {
1.1 ratchov 532: sub_bcopy(ibuf, i);
533: abuf_flush(i);
534: }
1.3 ratchov 535: #ifdef sub_xrun_disabled
1.1 ratchov 536: if (!ABUF_WOK(i))
537: again = 0;
1.3 ratchov 538: #endif
1.1 ratchov 539: if (done > i->subdone)
540: done = i->subdone;
541: }
542: LIST_FOREACH(i, &p->obuflist, oent) {
543: i->subdone -= done;
544: }
545: ibuf->used -= done;
546: ibuf->start += done;
547: if (ibuf->start >= ibuf->len)
548: ibuf->start -= ibuf->len;
549: return again;
550: }
551:
552: int
553: sub_out(struct aproc *p, struct abuf *obuf)
554: {
555: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
556: struct abuf *i, *inext;
1.3 ratchov 557: unsigned char *odata;
558: unsigned ocount;
1.1 ratchov 559: unsigned done;
560:
1.3 ratchov 561: /*
562: * generate silence for dropped samples
563: */
564: while (obuf->subdrop > 0) {
565: odata = abuf_wgetblk(obuf, &ocount, 0);
566: if (ocount >= obuf->subdrop)
567: ocount = obuf->subdrop;
568: if (ocount == 0)
569: break;
570: memset(odata, 0, ocount);
571: obuf->used += ocount;
572: obuf->subdrop -= ocount;
573: DPRINTF("sub_out: catched, drop = %u\n", obuf->subdrop);
574: }
575:
1.1 ratchov 576: if (obuf->subdone >= ibuf->used)
577: return 0;
578:
579: sub_bcopy(ibuf, obuf);
580:
581: done = ibuf->used;
582: LIST_FOREACH(i, &p->obuflist, oent) {
583: if (i != obuf && ABUF_WOK(i)) {
584: sub_bcopy(ibuf, i);
585: abuf_flush(i);
586: }
587: if (done > i->subdone)
588: done = i->subdone;
589: }
590: if (done == 0)
591: return 0;
592: LIST_FOREACH(i, &p->obuflist, oent) {
593: i->subdone -= done;
594: }
595: ibuf->used -= done;
596: ibuf->start += done;
597: if (ibuf->start >= ibuf->len)
598: ibuf->start -= ibuf->len;
599: if (ABUF_EOF(ibuf)) {
600: abuf_hup(ibuf);
601: for (i = LIST_FIRST(&p->obuflist);
1.2 ratchov 602: i != LIST_END(&p->obuflist);
1.1 ratchov 603: i = inext) {
604: inext = LIST_NEXT(i, oent);
605: if (i != ibuf)
606: abuf_eof(i);
607: }
608: ibuf->wproc = NULL;
609: sub_del(p);
610: return 0;
611: }
612: abuf_fill(ibuf);
613: return 1;
614: }
615:
616: void
617: sub_eof(struct aproc *p, struct abuf *ibuf)
618: {
619: struct abuf *obuf;
620:
621: while (!LIST_EMPTY(&p->obuflist)) {
622: obuf = LIST_FIRST(&p->obuflist);
623: sub_rm(p, obuf);
624: abuf_eof(obuf);
625: }
626: sub_del(p);
627: }
628:
629: void
630: sub_hup(struct aproc *p, struct abuf *obuf)
631: {
632: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
633:
634: DPRINTF("sub_hup: %s: detached\n", p->name);
635: sub_rm(p, obuf);
636: if (LIST_EMPTY(&p->obuflist)) {
637: abuf_hup(ibuf);
638: sub_del(p);
639: } else
640: abuf_run(ibuf);
641: DPRINTF("sub_hup: done\n");
642: }
643:
644: void
645: sub_newout(struct aproc *p, struct abuf *obuf)
646: {
647: obuf->subdone = 0;
1.3 ratchov 648: obuf->subdrop = 0;
1.1 ratchov 649: }
650:
651: struct aproc_ops sub_ops = {
652: "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout
653: };
654:
655: struct aproc *
656: sub_new(void)
657: {
658: struct aproc *p;
659:
660: p = aproc_new(&sub_ops, "copy");
661: return p;
662: }
663:
664:
665: /*
666: * Convert one block.
667: */
668: void
669: conv_bcopy(struct aconv *ist, struct aconv *ost,
670: struct abuf *ibuf, struct abuf *obuf)
671: {
672: int *ictx;
673: unsigned inch, ibps;
674: unsigned char *idata;
675: int ibnext, isigbit;
676: unsigned ishift;
677: int isnext;
678: unsigned ipos, orate;
679: unsigned ifr;
680: int *octx;
681: unsigned onch, oshift;
682: int osigbit;
683: unsigned obps;
684: unsigned char *odata;
685: int obnext, osnext;
686: unsigned opos, irate;
687: unsigned ofr;
688: unsigned c, i;
689: int s, *ctx;
690: unsigned icount, ocount;
691:
692: /*
693: * It's ok to have s uninitialized, but we dont want the compiler to
694: * complain about it.
695: */
696: s = (int)0xdeadbeef;
697:
698: /*
699: * Calculate max frames readable at once from the input buffer.
700: */
701: idata = abuf_rgetblk(ibuf, &icount, 0);
702: ifr = icount / ibuf->bpf;
703:
704: odata = abuf_wgetblk(obuf, &ocount, 0);
705: ofr = ocount / obuf->bpf;
706:
707: /*
708: * Partially copy structures into local variables, to avoid
709: * unnecessary indirections; this also allows the compiler to
710: * order local variables more "cache-friendly".
711: */
712: ictx = ist->ctx + ist->cmin;
713: octx = ist->ctx + ost->cmin;
714: inch = ist->nch;
715: ibps = ist->bps;
716: ibnext = ist->bnext;
717: isigbit = ist->sigbit;
718: ishift = ist->shift;
719: isnext = ist->snext;
720: ipos = ist->pos;
721: irate = ist->rate;
722: onch = ost->nch;
723: oshift = ost->shift;
724: osigbit = ost->sigbit;
725: obps = ost->bps;
726: obnext = ost->bnext;
727: osnext = ost->snext;
728: opos = ost->pos;
729: orate = ost->rate;
730:
731: /*
732: * Start conversion.
733: */
734: idata += ist->bfirst;
735: odata += ost->bfirst;
736: DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
737: for (;;) {
738: if ((int)(ipos - opos) > 0) {
739: if (ofr == 0)
740: break;
741: ctx = octx;
742: for (c = onch; c > 0; c--) {
743: s = *ctx++ << 16;
744: s >>= oshift;
745: s ^= osigbit;
746: for (i = obps; i > 0; i--) {
747: *odata = (unsigned char)s;
748: s >>= 8;
749: odata += obnext;
750: }
751: odata += osnext;
752: }
753: opos += irate;
754: ofr--;
755: } else {
756: if (ifr == 0)
757: break;
758: ctx = ictx;
759: for (c = inch; c > 0; c--) {
760: for (i = ibps; i > 0; i--) {
761: s <<= 8;
762: s |= *idata;
763: idata += ibnext;
764: }
765: s ^= isigbit;
766: s <<= ishift;
767: *ctx++ = (short)(s >> 16);
768: idata += isnext;
769: }
770: ipos += orate;
771: ifr--;
772: }
773: }
774: ist->pos = ipos;
775: ost->pos = opos;
776: DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
777:
778: /*
779: * Update FIFO pointers.
780: */
781: icount -= ifr * ist->bpf;
782: ibuf->used -= icount;
783: ibuf->start += icount;
784: if (ibuf->start >= ibuf->len)
785: ibuf->start -= ibuf->len;
786:
787: ocount -= ofr * ost->bpf;
788: obuf->used += ocount;
789: }
790:
791: void
792: conv_del(struct aproc *p)
793: {
794: aproc_del(p);
795: }
796:
797: int
798: conv_in(struct aproc *p, struct abuf *ibuf)
799: {
800: struct abuf *obuf = LIST_FIRST(&p->obuflist);
801:
802: if (!ABUF_WOK(obuf))
803: return 0;
804: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
805: abuf_flush(obuf);
806: return ABUF_WOK(obuf);
807: }
808:
809: int
810: conv_out(struct aproc *p, struct abuf *obuf)
811: {
812: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
813:
814: if (!ABUF_ROK(ibuf))
815: return 0;
816: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
817: if (ABUF_EOF(ibuf)) {
818: obuf->wproc = NULL;
819: abuf_hup(ibuf);
820: conv_del(p);
821: return 0;
822: }
823: abuf_fill(ibuf);
824: return 1;
825: }
826:
827: void
828: conv_eof(struct aproc *p, struct abuf *ibuf)
829: {
830: abuf_eof(LIST_FIRST(&p->obuflist));
831: conv_del(p);
832: }
833:
834: void
835: conv_hup(struct aproc *p, struct abuf *obuf)
836: {
837: abuf_hup(LIST_FIRST(&p->ibuflist));
838: conv_del(p);
839: }
840:
841: void
842: aconv_init(struct aconv *st, struct aparams *par, int input)
843: {
844: unsigned i;
845:
846: st->bps = par->bps;
847: st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
848: if (par->msb) {
849: st->shift = 32 - par->bps * 8;
850: } else {
851: st->shift = 32 - par->bits;
852: }
853: if ((par->le && input) || (!par->le && !input)) {
854: st->bfirst = st->bps - 1;
855: st->bnext = -1;
856: st->snext = 2 * st->bps;
857: } else {
858: st->bfirst = 0;
859: st->bnext = 1;
860: st->snext = 0;
861: }
862: st->cmin = par->cmin;
863: st->nch = par->cmax - par->cmin + 1;
864: st->bpf = st->nch * st->bps;
865: st->rate = par->rate;
866: st->pos = 0;
867:
868: for (i = 0; i < CHAN_MAX; i++)
869: st->ctx[i] = 0;
870: }
871:
872: struct aproc_ops conv_ops = {
873: "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL
874: };
875:
876: struct aproc *
877: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
878: {
879: struct aproc *p;
880:
881: p = aproc_new(&conv_ops, name);
882: aconv_init(&p->u.conv.ist, ipar, 1);
883: aconv_init(&p->u.conv.ost, opar, 0);
884: return p;
885: }