Annotation of src/usr.bin/aucat/aproc.c, Revision 1.10
1.10 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.9 2008/08/14 09:47:51 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;
1.9 ratchov 398: if (LIST_EMPTY(&p->ibuflist) && (p->u.mix.flags & MIX_AUTOQUIT)) {
1.1 ratchov 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;
1.10 ! ratchov 468: }
! 469:
! 470: void
! 471: mix_pushzero(struct aproc *p)
! 472: {
! 473: struct abuf *obuf = LIST_FIRST(&p->obuflist);
! 474:
! 475: abuf_wcommit(obuf, obuf->mixtodo);
! 476: obuf->mixtodo = 0;
! 477: abuf_flush(obuf);
! 478: mix_bzero(p);
! 479: }
! 480:
! 481: /*
! 482: * Normalize input levels
! 483: */
! 484: void
! 485: mix_setmaster(struct aproc *p)
! 486: {
! 487: unsigned n;
! 488: struct abuf *buf;
! 489:
! 490: n = 0;
! 491: LIST_FOREACH(buf, &p->ibuflist, ient)
! 492: n++;
! 493: LIST_FOREACH(buf, &p->ibuflist, ient)
! 494: buf->mixvol = ADATA_UNIT / n;
1.1 ratchov 495: }
496:
497: /*
498: * Copy data from ibuf to obuf.
499: */
500: void
501: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
502: {
503: unsigned char *idata, *odata;
504: unsigned icount, ocount, scount;
505:
506: idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
507: if (icount == 0)
508: return;
509: odata = abuf_wgetblk(obuf, &ocount, 0);
510: if (ocount == 0)
511: return;
512: scount = (icount < ocount) ? icount : ocount;
513: memcpy(odata, idata, scount);
1.6 ratchov 514: abuf_wcommit(obuf, scount);
1.1 ratchov 515: obuf->subdone += scount;
516: DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
517: }
518:
519: void
520: sub_rm(struct aproc *p, struct abuf *obuf)
521: {
522: LIST_REMOVE(obuf, oent);
523: DPRINTF("sub_rm: %s\n", p->name);
524: }
525:
526: int
527: sub_in(struct aproc *p, struct abuf *ibuf)
528: {
529: struct abuf *i, *inext;
1.3 ratchov 530: unsigned done, drop;
1.1 ratchov 531: int again;
532:
533: again = 1;
534: done = ibuf->used;
1.2 ratchov 535: for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1 ratchov 536: inext = LIST_NEXT(i, oent);
1.5 ratchov 537: if (!ABUF_WOK(i)) {
538: if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) {
539: if (i->xrun == XRUN_ERROR) {
540: sub_rm(p, i);
541: abuf_eof(i);
542: continue;
543: }
544: drop = ibuf->used;
545: if (i->xrun == XRUN_SYNC)
1.7 ratchov 546: i->silence += drop;
1.5 ratchov 547: i->subdone += drop;
1.7 ratchov 548: DPRINTF("sub_in: silence = %u\n", i->silence);
1.5 ratchov 549: }
1.3 ratchov 550: } else {
1.1 ratchov 551: sub_bcopy(ibuf, i);
552: abuf_flush(i);
553: }
554: if (!ABUF_WOK(i))
555: again = 0;
556: if (done > i->subdone)
557: done = i->subdone;
558: }
559: LIST_FOREACH(i, &p->obuflist, oent) {
560: i->subdone -= done;
561: }
1.6 ratchov 562: abuf_rdiscard(ibuf, done);
1.1 ratchov 563: return again;
564: }
565:
566: int
567: sub_out(struct aproc *p, struct abuf *obuf)
568: {
569: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
570: struct abuf *i, *inext;
571: unsigned done;
572:
573: if (obuf->subdone >= ibuf->used)
574: return 0;
575:
576: sub_bcopy(ibuf, obuf);
577:
578: done = ibuf->used;
579: LIST_FOREACH(i, &p->obuflist, oent) {
580: if (i != obuf && ABUF_WOK(i)) {
581: sub_bcopy(ibuf, i);
582: abuf_flush(i);
583: }
584: if (done > i->subdone)
585: done = i->subdone;
586: }
587: if (done == 0)
588: return 0;
589: LIST_FOREACH(i, &p->obuflist, oent) {
590: i->subdone -= done;
591: }
1.6 ratchov 592: abuf_rdiscard(ibuf, done);
1.1 ratchov 593: if (ABUF_EOF(ibuf)) {
594: abuf_hup(ibuf);
595: for (i = LIST_FIRST(&p->obuflist);
1.2 ratchov 596: i != LIST_END(&p->obuflist);
1.1 ratchov 597: i = inext) {
598: inext = LIST_NEXT(i, oent);
599: if (i != ibuf)
600: abuf_eof(i);
601: }
602: ibuf->wproc = NULL;
1.8 ratchov 603: aproc_del(p);
1.1 ratchov 604: return 0;
605: }
606: abuf_fill(ibuf);
607: return 1;
608: }
609:
610: void
611: sub_eof(struct aproc *p, struct abuf *ibuf)
612: {
613: struct abuf *obuf;
614:
615: while (!LIST_EMPTY(&p->obuflist)) {
616: obuf = LIST_FIRST(&p->obuflist);
617: sub_rm(p, obuf);
618: abuf_eof(obuf);
619: }
1.8 ratchov 620: aproc_del(p);
1.1 ratchov 621: }
622:
623: void
624: sub_hup(struct aproc *p, struct abuf *obuf)
625: {
626: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
627:
628: DPRINTF("sub_hup: %s: detached\n", p->name);
629: sub_rm(p, obuf);
1.9 ratchov 630: if (LIST_EMPTY(&p->obuflist) && (p->u.sub.flags & SUB_AUTOQUIT)) {
1.1 ratchov 631: abuf_hup(ibuf);
1.8 ratchov 632: aproc_del(p);
1.1 ratchov 633: } else
634: abuf_run(ibuf);
635: DPRINTF("sub_hup: done\n");
636: }
637:
638: void
639: sub_newout(struct aproc *p, struct abuf *obuf)
640: {
641: obuf->subdone = 0;
1.5 ratchov 642: obuf->xrun = XRUN_IGNORE;
1.1 ratchov 643: }
644:
645: struct aproc_ops sub_ops = {
1.8 ratchov 646: "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout, NULL
1.1 ratchov 647: };
648:
649: struct aproc *
650: sub_new(void)
651: {
652: struct aproc *p;
653:
654: p = aproc_new(&sub_ops, "copy");
1.5 ratchov 655: p->u.sub.flags = 0;
1.1 ratchov 656: return p;
657: }
658:
659:
660: /*
661: * Convert one block.
662: */
663: void
664: conv_bcopy(struct aconv *ist, struct aconv *ost,
665: struct abuf *ibuf, struct abuf *obuf)
666: {
667: int *ictx;
668: unsigned inch, ibps;
669: unsigned char *idata;
670: int ibnext, isigbit;
671: unsigned ishift;
672: int isnext;
673: unsigned ipos, orate;
674: unsigned ifr;
675: int *octx;
676: unsigned onch, oshift;
677: int osigbit;
678: unsigned obps;
679: unsigned char *odata;
680: int obnext, osnext;
681: unsigned opos, irate;
682: unsigned ofr;
683: unsigned c, i;
684: int s, *ctx;
685: unsigned icount, ocount;
686:
687: /*
688: * It's ok to have s uninitialized, but we dont want the compiler to
689: * complain about it.
690: */
691: s = (int)0xdeadbeef;
692:
693: /*
694: * Calculate max frames readable at once from the input buffer.
695: */
696: idata = abuf_rgetblk(ibuf, &icount, 0);
697: ifr = icount / ibuf->bpf;
698:
699: odata = abuf_wgetblk(obuf, &ocount, 0);
700: ofr = ocount / obuf->bpf;
701:
702: /*
703: * Partially copy structures into local variables, to avoid
704: * unnecessary indirections; this also allows the compiler to
705: * order local variables more "cache-friendly".
706: */
707: ictx = ist->ctx + ist->cmin;
708: octx = ist->ctx + ost->cmin;
709: inch = ist->nch;
710: ibps = ist->bps;
711: ibnext = ist->bnext;
712: isigbit = ist->sigbit;
713: ishift = ist->shift;
714: isnext = ist->snext;
715: ipos = ist->pos;
716: irate = ist->rate;
717: onch = ost->nch;
718: oshift = ost->shift;
719: osigbit = ost->sigbit;
720: obps = ost->bps;
721: obnext = ost->bnext;
722: osnext = ost->snext;
723: opos = ost->pos;
724: orate = ost->rate;
725:
726: /*
727: * Start conversion.
728: */
729: idata += ist->bfirst;
730: odata += ost->bfirst;
731: DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
732: for (;;) {
733: if ((int)(ipos - opos) > 0) {
734: if (ofr == 0)
735: break;
736: ctx = octx;
737: for (c = onch; c > 0; c--) {
738: s = *ctx++ << 16;
739: s >>= oshift;
740: s ^= osigbit;
741: for (i = obps; i > 0; i--) {
742: *odata = (unsigned char)s;
743: s >>= 8;
744: odata += obnext;
745: }
746: odata += osnext;
747: }
748: opos += irate;
749: ofr--;
750: } else {
751: if (ifr == 0)
752: break;
753: ctx = ictx;
754: for (c = inch; c > 0; c--) {
755: for (i = ibps; i > 0; i--) {
756: s <<= 8;
757: s |= *idata;
758: idata += ibnext;
759: }
760: s ^= isigbit;
761: s <<= ishift;
762: *ctx++ = (short)(s >> 16);
763: idata += isnext;
764: }
765: ipos += orate;
766: ifr--;
767: }
768: }
769: ist->pos = ipos;
770: ost->pos = opos;
771: DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
772:
773: /*
774: * Update FIFO pointers.
775: */
776: icount -= ifr * ist->bpf;
777: ocount -= ofr * ost->bpf;
1.6 ratchov 778: abuf_rdiscard(ibuf, icount);
779: abuf_wcommit(obuf, ocount);
1.1 ratchov 780: }
781:
782: int
783: conv_in(struct aproc *p, struct abuf *ibuf)
784: {
785: struct abuf *obuf = LIST_FIRST(&p->obuflist);
786:
787: if (!ABUF_WOK(obuf))
788: return 0;
789: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
790: abuf_flush(obuf);
791: return ABUF_WOK(obuf);
792: }
793:
794: int
795: conv_out(struct aproc *p, struct abuf *obuf)
796: {
797: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
798:
799: if (!ABUF_ROK(ibuf))
800: return 0;
801: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
802: if (ABUF_EOF(ibuf)) {
803: obuf->wproc = NULL;
804: abuf_hup(ibuf);
1.8 ratchov 805: aproc_del(p);
1.1 ratchov 806: return 0;
807: }
808: abuf_fill(ibuf);
809: return 1;
810: }
811:
812: void
813: conv_eof(struct aproc *p, struct abuf *ibuf)
814: {
815: abuf_eof(LIST_FIRST(&p->obuflist));
1.8 ratchov 816: aproc_del(p);
1.1 ratchov 817: }
818:
819: void
820: conv_hup(struct aproc *p, struct abuf *obuf)
821: {
822: abuf_hup(LIST_FIRST(&p->ibuflist));
1.8 ratchov 823: aproc_del(p);
1.1 ratchov 824: }
825:
826: void
827: aconv_init(struct aconv *st, struct aparams *par, int input)
828: {
829: unsigned i;
830:
831: st->bps = par->bps;
832: st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
833: if (par->msb) {
834: st->shift = 32 - par->bps * 8;
835: } else {
836: st->shift = 32 - par->bits;
837: }
838: if ((par->le && input) || (!par->le && !input)) {
839: st->bfirst = st->bps - 1;
840: st->bnext = -1;
841: st->snext = 2 * st->bps;
842: } else {
843: st->bfirst = 0;
844: st->bnext = 1;
845: st->snext = 0;
846: }
847: st->cmin = par->cmin;
848: st->nch = par->cmax - par->cmin + 1;
849: st->bpf = st->nch * st->bps;
850: st->rate = par->rate;
851: st->pos = 0;
852:
853: for (i = 0; i < CHAN_MAX; i++)
854: st->ctx[i] = 0;
855: }
856:
857: struct aproc_ops conv_ops = {
1.8 ratchov 858: "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL, NULL
1.1 ratchov 859: };
860:
861: struct aproc *
862: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
863: {
864: struct aproc *p;
865:
866: p = aproc_new(&conv_ops, name);
867: aconv_init(&p->u.conv.ist, ipar, 1);
868: aconv_init(&p->u.conv.ost, opar, 0);
869: return p;
870: }