Annotation of src/usr.bin/aucat/aproc.c, Revision 1.32
1.32 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.31 2009/01/23 17:38: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: *
1.15 ratchov 34: * - resamp: resample streams in native format
35: *
1.1 ratchov 36: * TODO
37: *
38: * (easy) split the "conv" into 2 converters: one for input (that
39: * convers anything to 16bit signed) and one for the output (that
40: * converts 16bit signed to anything)
41: *
42: * (hard) add a lowpass filter for the resampler. Quality is
43: * not acceptable as is.
1.12 ratchov 44: *
1.1 ratchov 45: */
46: #include <err.h>
47: #include <limits.h>
48: #include <stdio.h>
49: #include <stdlib.h>
50: #include <string.h>
51:
52: #include "conf.h"
53: #include "aparams.h"
54: #include "abuf.h"
55: #include "aproc.h"
56: #include "file.h"
57:
58: struct aproc *
59: aproc_new(struct aproc_ops *ops, char *name)
60: {
61: struct aproc *p;
62:
63: p = malloc(sizeof(struct aproc));
64: if (p == NULL)
65: err(1, name);
66: LIST_INIT(&p->ibuflist);
67: LIST_INIT(&p->obuflist);
68: p->name = name;
69: p->ops = ops;
1.30 ratchov 70: p->refs = 0;
1.1 ratchov 71: return p;
72: }
73:
74: void
75: aproc_del(struct aproc *p)
76: {
1.12 ratchov 77: struct abuf *i;
78:
79: DPRINTF("aproc_del: %s(%s): terminating...\n", p->ops->name, p->name);
80:
1.8 ratchov 81: if (p->ops->done)
82: p->ops->done(p);
1.12 ratchov 83:
84: while (!LIST_EMPTY(&p->ibuflist)) {
85: i = LIST_FIRST(&p->ibuflist);
86: abuf_hup(i);
87: }
88: while (!LIST_EMPTY(&p->obuflist)) {
89: i = LIST_FIRST(&p->obuflist);
90: abuf_eof(i);
91: }
1.30 ratchov 92: if (p->refs > 0) {
93: DPRINTF("aproc_del: %s(%s): has refs\n", p->ops->name, p->name);
94: return;
95: }
1.12 ratchov 96: DPRINTF("aproc_del: %s(%s): freed\n", p->ops->name, p->name);
1.1 ratchov 97: free(p);
98: }
99:
100: void
101: aproc_setin(struct aproc *p, struct abuf *ibuf)
102: {
103: LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
104: ibuf->rproc = p;
105: if (p->ops->newin)
106: p->ops->newin(p, ibuf);
107: }
108:
109: void
110: aproc_setout(struct aproc *p, struct abuf *obuf)
111: {
112: LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
113: obuf->wproc = p;
114: if (p->ops->newout)
115: p->ops->newout(p, obuf);
116: }
117:
1.12 ratchov 118: void
119: aproc_ipos(struct aproc *p, struct abuf *ibuf, int delta)
120: {
121: struct abuf *obuf;
122:
123: DPRINTFN(3, "aproc_ipos: %s: delta = %d\n", p->name, delta);
124:
125: LIST_FOREACH(obuf, &p->obuflist, oent) {
126: abuf_ipos(obuf, delta);
127: }
128: }
129:
130: void
131: aproc_opos(struct aproc *p, struct abuf *obuf, int delta)
132: {
133: struct abuf *ibuf;
134:
135: DPRINTFN(3, "aproc_opos: %s: delta = %d\n", p->name, delta);
136:
137: LIST_FOREACH(ibuf, &p->ibuflist, ient) {
138: abuf_opos(ibuf, delta);
139: }
140: }
141:
1.1 ratchov 142: int
1.28 ratchov 143: aproc_inuse(struct aproc *p)
144: {
145: struct abuf *i;
146:
147: LIST_FOREACH(i, &p->ibuflist, ient) {
148: if (i->inuse)
149: return 1;
150: }
151: LIST_FOREACH(i, &p->obuflist, oent) {
152: if (i->inuse)
153: return 1;
154: }
155: DPRINTFN(3, "aproc_inuse: %s: not inuse\n", p->name);
156: return 0;
157: }
158:
159: int
1.32 ! ratchov 160: aproc_depend(struct aproc *p, struct aproc *dep)
! 161: {
! 162: struct abuf *i;
! 163:
! 164: if (p == dep)
! 165: return 1;
! 166: LIST_FOREACH(i, &p->ibuflist, ient) {
! 167: if (i->wproc && aproc_depend(i->wproc, dep))
! 168: return 1;
! 169: }
! 170: return 0;
! 171: }
! 172:
! 173: int
1.1 ratchov 174: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
175: {
176: struct abuf *obuf = LIST_FIRST(&p->obuflist);
177: struct file *f = p->u.io.file;
178: unsigned char *data;
179: unsigned count;
180:
1.6 ratchov 181: DPRINTFN(3, "rpipe_in: %s\n", p->name);
182:
1.12 ratchov 183: if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
1.1 ratchov 184: return 0;
185: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 186: count = file_read(f, data, count);
1.12 ratchov 187: if (count == 0)
188: return 0;
1.6 ratchov 189: abuf_wcommit(obuf, count);
1.12 ratchov 190: if (!abuf_flush(obuf))
191: return 0;
192: return 1;
1.1 ratchov 193: }
194:
195: int
196: rpipe_out(struct aproc *p, struct abuf *obuf)
197: {
198: struct file *f = p->u.io.file;
199: unsigned char *data;
200: unsigned count;
201:
1.32 ! ratchov 202: if (f->state & FILE_RINUSE)
1.12 ratchov 203: return 0;
1.6 ratchov 204: DPRINTFN(3, "rpipe_out: %s\n", p->name);
1.31 ratchov 205:
1.12 ratchov 206: if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
1.1 ratchov 207: return 0;
208: data = abuf_wgetblk(obuf, &count, 0);
1.6 ratchov 209: count = file_read(f, data, count);
1.12 ratchov 210: if (count == 0)
211: return 0;
1.6 ratchov 212: abuf_wcommit(obuf, count);
1.12 ratchov 213: return 1;
1.1 ratchov 214: }
215:
216: void
1.8 ratchov 217: rpipe_done(struct aproc *p)
1.1 ratchov 218: {
219: struct file *f = p->u.io.file;
220:
1.30 ratchov 221: if (f == NULL)
222: return;
1.1 ratchov 223: f->rproc = NULL;
1.12 ratchov 224: if (f->wproc == NULL)
225: file_del(f);
1.30 ratchov 226: p->u.io.file = NULL;
1.1 ratchov 227: }
228:
229: void
230: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
231: {
232: DPRINTFN(3, "rpipe_eof: %s\n", p->name);
1.8 ratchov 233: aproc_del(p);
1.1 ratchov 234: }
235:
236: void
237: rpipe_hup(struct aproc *p, struct abuf *obuf)
238: {
239: DPRINTFN(3, "rpipe_hup: %s\n", p->name);
1.8 ratchov 240: aproc_del(p);
1.1 ratchov 241: }
242:
243: struct aproc_ops rpipe_ops = {
1.12 ratchov 244: "rpipe",
245: rpipe_in,
246: rpipe_out,
247: rpipe_eof,
248: rpipe_hup,
249: NULL, /* newin */
250: NULL, /* newout */
251: aproc_ipos,
252: aproc_opos,
253: rpipe_done
1.1 ratchov 254: };
255:
256: struct aproc *
257: rpipe_new(struct file *f)
258: {
259: struct aproc *p;
260:
261: p = aproc_new(&rpipe_ops, f->name);
262: p->u.io.file = f;
1.31 ratchov 263: f->rproc = p;
1.1 ratchov 264: return p;
265: }
266:
267: void
1.8 ratchov 268: wpipe_done(struct aproc *p)
1.1 ratchov 269: {
270: struct file *f = p->u.io.file;
271:
1.30 ratchov 272: if (f == NULL)
273: return;
1.1 ratchov 274: f->wproc = NULL;
1.12 ratchov 275: if (f->rproc == NULL)
276: file_del(f);
1.30 ratchov 277: p->u.io.file = NULL;
1.1 ratchov 278: }
279:
280: int
281: wpipe_in(struct aproc *p, struct abuf *ibuf)
282: {
283: struct file *f = p->u.io.file;
284: unsigned char *data;
285: unsigned count;
286:
1.32 ! ratchov 287: if (f->state & FILE_WINUSE)
1.12 ratchov 288: return 0;
1.6 ratchov 289: DPRINTFN(3, "wpipe_in: %s\n", p->name);
290:
1.12 ratchov 291: if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
1.1 ratchov 292: return 0;
293: data = abuf_rgetblk(ibuf, &count, 0);
294: count = file_write(f, data, count);
1.12 ratchov 295: if (count == 0)
296: return 0;
1.6 ratchov 297: abuf_rdiscard(ibuf, count);
1.12 ratchov 298: return 1;
1.1 ratchov 299: }
300:
301: int
302: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
303: {
304: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
305: struct file *f = p->u.io.file;
306: unsigned char *data;
307: unsigned count;
308:
1.6 ratchov 309: DPRINTFN(3, "wpipe_out: %s\n", p->name);
310:
1.12 ratchov 311: if (!abuf_fill(ibuf)) {
1.31 ratchov 312: DPRINTFN(3, "wpipe_out: fill failed\n");
1.12 ratchov 313: return 0;
314: }
315: if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
1.1 ratchov 316: return 0;
317: data = abuf_rgetblk(ibuf, &count, 0);
1.12 ratchov 318: if (count == 0) {
319: DPRINTF("wpipe_out: %s: underrun\n", p->name);
320: return 0;
321: }
1.1 ratchov 322: count = file_write(f, data, count);
1.12 ratchov 323: if (count == 0)
324: return 0;
1.6 ratchov 325: abuf_rdiscard(ibuf, count);
1.1 ratchov 326: return 1;
327: }
328:
329: void
330: wpipe_eof(struct aproc *p, struct abuf *ibuf)
331: {
332: DPRINTFN(3, "wpipe_eof: %s\n", p->name);
1.8 ratchov 333: aproc_del(p);
1.1 ratchov 334: }
335:
336: void
337: wpipe_hup(struct aproc *p, struct abuf *obuf_dummy)
338: {
339: DPRINTFN(3, "wpipe_hup: %s\n", p->name);
1.8 ratchov 340: aproc_del(p);
1.1 ratchov 341: }
342:
343: struct aproc_ops wpipe_ops = {
1.12 ratchov 344: "wpipe",
345: wpipe_in,
346: wpipe_out,
347: wpipe_eof,
348: wpipe_hup,
349: NULL, /* newin */
350: NULL, /* newout */
351: aproc_ipos,
352: aproc_opos,
353: wpipe_done
1.1 ratchov 354: };
355:
356: struct aproc *
357: wpipe_new(struct file *f)
358: {
359: struct aproc *p;
360:
361: p = aproc_new(&wpipe_ops, f->name);
362: p->u.io.file = f;
363: f->wproc = p;
364: return p;
365: }
366:
367: /*
1.28 ratchov 368: * Append the given amount of silence (or less if there's not enough
369: * space), and crank mixitodo accordingly
1.1 ratchov 370: */
371: void
1.28 ratchov 372: mix_bzero(struct abuf *obuf, unsigned zcount)
1.1 ratchov 373: {
374: short *odata;
375: unsigned ocount;
376:
1.28 ratchov 377: DPRINTFN(4, "mix_bzero: used = %u, zcount = %u\n", obuf->used, zcount);
1.14 ratchov 378: odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixitodo);
1.12 ratchov 379: ocount -= ocount % obuf->bpf;
1.28 ratchov 380: if (ocount > zcount)
381: ocount = zcount;
1.1 ratchov 382: memset(odata, 0, ocount);
1.14 ratchov 383: obuf->mixitodo += ocount;
1.1 ratchov 384: }
385:
386: /*
387: * Mix an input block over an output block.
388: */
389: void
390: mix_badd(struct abuf *ibuf, struct abuf *obuf)
391: {
392: short *idata, *odata;
1.13 ratchov 393: unsigned i, j, icnt, onext, ostart;
1.28 ratchov 394: unsigned scount, icount, ocount, zcount;
1.23 ratchov 395: int vol;
1.1 ratchov 396:
1.6 ratchov 397: DPRINTFN(4, "mix_badd: todo = %u, done = %u\n",
1.14 ratchov 398: obuf->mixitodo, ibuf->mixodone);
1.1 ratchov 399:
1.28 ratchov 400: /*
401: * calculate the maximum we can read
402: */
1.1 ratchov 403: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1.13 ratchov 404: icount /= ibuf->bpf;
1.1 ratchov 405: if (icount == 0)
406: return;
407:
1.28 ratchov 408: /*
409: * zero-fill if necessary
410: */
411: zcount = ibuf->mixodone + icount * obuf->bpf;
412: if (zcount > obuf->mixitodo)
413: mix_bzero(obuf, zcount - obuf->mixitodo);
414:
415: /*
416: * calculate the maximum we can write
417: */
1.14 ratchov 418: odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixodone);
1.13 ratchov 419: ocount /= obuf->bpf;
1.1 ratchov 420: if (ocount == 0)
421: return;
422:
1.23 ratchov 423: vol = (ibuf->mixweight * ibuf->mixvol) >> ADATA_SHIFT;
1.31 ratchov 424: ostart = ibuf->cmin - obuf->cmin;
1.13 ratchov 425: onext = obuf->cmax - ibuf->cmax + ostart;
426: icnt = ibuf->cmax - ibuf->cmin + 1;
427: odata += ostart;
1.1 ratchov 428: scount = (icount < ocount) ? icount : ocount;
1.13 ratchov 429: for (i = scount; i > 0; i--) {
430: for (j = icnt; j > 0; j--) {
431: *odata += (*idata * vol) >> ADATA_SHIFT;
432: idata++;
433: odata++;
434: }
435: odata += onext;
436: }
437: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1.14 ratchov 438: ibuf->mixodone += scount * obuf->bpf;
1.1 ratchov 439:
1.6 ratchov 440: DPRINTFN(4, "mix_badd: added %u, done = %u, todo = %u\n",
1.14 ratchov 441: scount, ibuf->mixodone, obuf->mixitodo);
1.1 ratchov 442: }
443:
1.28 ratchov 444: /*
445: * Handle buffer underrun, return 0 if stream died.
446: */
447: int
448: mix_xrun(struct abuf *i, struct abuf *obuf)
449: {
450: unsigned fdrop;
1.31 ratchov 451:
1.28 ratchov 452: if (i->mixodone > 0)
453: return 1;
454: if (i->xrun == XRUN_ERROR) {
455: abuf_hup(i);
456: return 0;
457: }
458: mix_bzero(obuf, obuf->len);
459: fdrop = obuf->mixitodo / obuf->bpf;
460: i->mixodone += fdrop * obuf->bpf;
461: if (i->xrun == XRUN_SYNC)
462: i->drop += fdrop * i->bpf;
463: else {
464: abuf_opos(i, -(int)fdrop);
465: if (i->duplex) {
466: DPRINTF("mix_xrun: duplex %u\n", fdrop);
467: i->duplex->drop += fdrop * i->duplex->bpf;
468: abuf_ipos(i->duplex, -(int)fdrop);
469: }
470: }
471: DPRINTF("mix_xrun: drop = %u\n", i->drop);
472: return 1;
473: }
474:
1.1 ratchov 475: int
476: mix_in(struct aproc *p, struct abuf *ibuf)
477: {
478: struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
1.28 ratchov 479: unsigned odone;
1.1 ratchov 480:
1.28 ratchov 481: DPRINTFN(4, "mix_in: used/len = %u/%u, done/todo = %u/%u\n",
482: ibuf->used, ibuf->len, ibuf->mixodone, obuf->mixitodo);
1.31 ratchov 483:
1.28 ratchov 484: if (!ABUF_ROK(ibuf))
1.1 ratchov 485: return 0;
1.28 ratchov 486: odone = obuf->len;
487: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
488: inext = LIST_NEXT(i, ient);
489: if (!abuf_fill(i))
490: continue; /* eof */
491: mix_badd(i, obuf);
492: if (odone > i->mixodone)
493: odone = i->mixodone;
494: }
495: if (LIST_EMPTY(&p->ibuflist) || odone == 0)
496: return 0;
497: p->u.mix.lat += odone / obuf->bpf;
1.1 ratchov 498: LIST_FOREACH(i, &p->ibuflist, ient) {
1.28 ratchov 499: i->mixodone -= odone;
1.1 ratchov 500: }
1.28 ratchov 501: abuf_wcommit(obuf, odone);
502: obuf->mixitodo -= odone;
1.12 ratchov 503: if (!abuf_flush(obuf))
504: return 0; /* hup */
1.1 ratchov 505: return 1;
506: }
507:
508: int
509: mix_out(struct aproc *p, struct abuf *obuf)
510: {
511: struct abuf *i, *inext;
1.28 ratchov 512: unsigned odone;
1.1 ratchov 513:
1.28 ratchov 514: DPRINTFN(4, "mix_out: used/len = %u/%u, todo/len = %u/%u\n",
515: obuf->used, obuf->len, obuf->mixitodo, obuf->len);
1.1 ratchov 516:
1.12 ratchov 517: if (!ABUF_WOK(obuf))
1.31 ratchov 518: return 0;
1.28 ratchov 519: odone = obuf->len;
1.12 ratchov 520: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
1.1 ratchov 521: inext = LIST_NEXT(i, ient);
1.12 ratchov 522: if (!abuf_fill(i))
1.28 ratchov 523: continue; /* eof */
1.5 ratchov 524: if (!ABUF_ROK(i)) {
1.28 ratchov 525: if (p->u.mix.flags & MIX_DROP) {
526: if (!mix_xrun(i, obuf))
1.5 ratchov 527: continue;
528: }
1.3 ratchov 529: } else
530: mix_badd(i, obuf);
1.28 ratchov 531: if (odone > i->mixodone)
532: odone = i->mixodone;
533: }
534: if (LIST_EMPTY(&p->ibuflist)) {
535: if (p->u.mix.flags & MIX_AUTOQUIT) {
536: DPRINTF("mix_out: nothing more to do...\n");
537: aproc_del(p);
538: return 0;
539: }
540: if (!(p->u.mix.flags & MIX_DROP))
541: return 0;
542: mix_bzero(obuf, obuf->len);
543: odone = obuf->mixitodo;
544: p->u.mix.idle += odone / obuf->bpf;
1.1 ratchov 545: }
1.28 ratchov 546: if (odone == 0)
1.1 ratchov 547: return 0;
1.28 ratchov 548: p->u.mix.lat += odone / obuf->bpf;
1.1 ratchov 549: LIST_FOREACH(i, &p->ibuflist, ient) {
1.28 ratchov 550: i->mixodone -= odone;
1.1 ratchov 551: }
1.28 ratchov 552: abuf_wcommit(obuf, odone);
553: obuf->mixitodo -= odone;
1.1 ratchov 554: return 1;
555: }
556:
557: void
558: mix_eof(struct aproc *p, struct abuf *ibuf)
559: {
1.28 ratchov 560: struct abuf *i, *obuf = LIST_FIRST(&p->obuflist);
561: unsigned odone;
1.1 ratchov 562:
563: DPRINTF("mix_eof: %s: detached\n", p->name);
1.12 ratchov 564: mix_setmaster(p);
565:
1.28 ratchov 566: if (!aproc_inuse(p)) {
567: DPRINTF("mix_eof: %s: from input\n", p->name);
568: /*
569: * find a blocked input
570: */
571: odone = obuf->len;
572: LIST_FOREACH(i, &p->ibuflist, ient) {
573: if (ABUF_ROK(i) && i->mixodone < obuf->mixitodo) {
574: abuf_run(i);
575: return;
576: }
577: if (odone > i->mixodone)
578: odone = i->mixodone;
579: }
580: /*
581: * no blocked inputs, check if output is blocked
582: */
583: if (LIST_EMPTY(&p->ibuflist) || odone == obuf->mixitodo)
584: abuf_run(obuf);
585: }
1.1 ratchov 586: }
587:
588: void
589: mix_hup(struct aproc *p, struct abuf *obuf)
590: {
591: DPRINTF("mix_hup: %s: done\n", p->name);
592: aproc_del(p);
593: }
594:
595: void
596: mix_newin(struct aproc *p, struct abuf *ibuf)
597: {
1.13 ratchov 598: struct abuf *obuf = LIST_FIRST(&p->obuflist);
599:
600: if (!obuf || ibuf->cmin < obuf->cmin || ibuf->cmax > obuf->cmax) {
601: fprintf(stderr, "mix_newin: channel ranges mismatch\n");
602: abort();
603: }
1.22 ratchov 604: p->u.mix.idle = 0;
1.14 ratchov 605: ibuf->mixodone = 0;
1.23 ratchov 606: ibuf->mixvol = ADATA_UNIT;
607: ibuf->mixweight = ADATA_UNIT;
1.24 ratchov 608: ibuf->mixmaxweight = ADATA_UNIT;
1.5 ratchov 609: ibuf->xrun = XRUN_IGNORE;
1.1 ratchov 610: }
611:
612: void
613: mix_newout(struct aproc *p, struct abuf *obuf)
614: {
1.21 ratchov 615: DPRINTF("mix_newout: using %u fpb\n", obuf->len / obuf->bpf);
1.14 ratchov 616: obuf->mixitodo = 0;
1.1 ratchov 617: }
618:
1.12 ratchov 619: void
620: mix_opos(struct aproc *p, struct abuf *obuf, int delta)
621: {
622: DPRINTFN(3, "mix_opos: lat = %d/%d\n", p->u.mix.lat, p->u.mix.maxlat);
623: p->u.mix.lat -= delta;
624: aproc_opos(p, obuf, delta);
625: }
626:
1.1 ratchov 627: struct aproc_ops mix_ops = {
1.12 ratchov 628: "mix",
629: mix_in,
630: mix_out,
631: mix_eof,
632: mix_hup,
633: mix_newin,
634: mix_newout,
635: aproc_ipos,
636: mix_opos,
637: NULL
1.1 ratchov 638: };
639:
640: struct aproc *
1.12 ratchov 641: mix_new(char *name, int maxlat)
1.1 ratchov 642: {
643: struct aproc *p;
644:
1.12 ratchov 645: p = aproc_new(&mix_ops, name);
1.5 ratchov 646: p->u.mix.flags = 0;
1.22 ratchov 647: p->u.mix.idle = 0;
1.12 ratchov 648: p->u.mix.lat = 0;
649: p->u.mix.maxlat = maxlat;
1.1 ratchov 650: return p;
1.10 ratchov 651: }
652:
653: /*
654: * Normalize input levels
655: */
656: void
657: mix_setmaster(struct aproc *p)
658: {
659: unsigned n;
660: struct abuf *buf;
1.24 ratchov 661: int weight;
1.10 ratchov 662:
663: n = 0;
1.24 ratchov 664: LIST_FOREACH(buf, &p->ibuflist, ient) {
665: n++;
666: }
667: LIST_FOREACH(buf, &p->ibuflist, ient) {
668: weight = ADATA_UNIT / n;
669: if (weight > buf->mixmaxweight)
670: weight = buf->mixmaxweight;
671: buf->mixweight = weight;
672: DPRINTF("mix_setmaster: %p: %d/%d -> %d\n", buf,
673: buf->mixweight, buf->mixmaxweight, weight);
674: }
1.1 ratchov 675: }
676:
1.22 ratchov 677: void
678: mix_clear(struct aproc *p)
679: {
680: struct abuf *obuf = LIST_FIRST(&p->obuflist);
681:
682: p->u.mix.lat = 0;
683: obuf->mixitodo = 0;
684: }
685:
1.1 ratchov 686: /*
687: * Copy data from ibuf to obuf.
688: */
689: void
690: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
691: {
1.13 ratchov 692: short *idata, *odata;
693: unsigned i, j, ocnt, inext, istart;
1.1 ratchov 694: unsigned icount, ocount, scount;
695:
1.14 ratchov 696: idata = (short *)abuf_rgetblk(ibuf, &icount, obuf->subidone);
1.13 ratchov 697: icount /= ibuf->bpf;
1.1 ratchov 698: if (icount == 0)
699: return;
1.13 ratchov 700: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
701: ocount /= obuf->bpf;
1.1 ratchov 702: if (ocount == 0)
703: return;
1.13 ratchov 704: istart = obuf->cmin - ibuf->cmin;
705: inext = ibuf->cmax - obuf->cmax + istart;
706: ocnt = obuf->cmax - obuf->cmin + 1;
1.1 ratchov 707: scount = (icount < ocount) ? icount : ocount;
1.13 ratchov 708: idata += istart;
709: for (i = scount; i > 0; i--) {
710: for (j = ocnt; j > 0; j--) {
711: *odata = *idata;
712: odata++;
713: idata++;
714: }
715: idata += inext;
716: }
1.31 ratchov 717: abuf_wcommit(obuf, scount * obuf->bpf);
1.14 ratchov 718: obuf->subidone += scount * ibuf->bpf;
1.13 ratchov 719: DPRINTFN(4, "sub_bcopy: %u frames\n", scount);
1.1 ratchov 720: }
721:
1.28 ratchov 722: /*
723: * Handle buffer overruns, return 0 if the stream died
724: */
725: int
726: sub_xrun(struct abuf *ibuf, struct abuf *i)
727: {
728: unsigned fdrop;
729:
730: if (i->subidone > 0)
731: return 1;
732: if (i->xrun == XRUN_ERROR) {
733: abuf_eof(i);
734: return 0;
735: }
736: fdrop = ibuf->used / ibuf->bpf;
737: if (i->xrun == XRUN_SYNC)
738: i->silence += fdrop * i->bpf;
739: else {
740: abuf_ipos(i, -(int)fdrop);
741: if (i->duplex) {
742: DPRINTF("sub_xrun: duplex %u\n", fdrop);
743: i->duplex->silence += fdrop * i->duplex->bpf;
744: abuf_opos(i->duplex, -(int)fdrop);
745: }
746: }
747: i->subidone += fdrop * ibuf->bpf;
748: DPRINTF("sub_xrun: silence = %u\n", i->silence);
749: return 1;
750: }
751:
1.1 ratchov 752: int
753: sub_in(struct aproc *p, struct abuf *ibuf)
754: {
755: struct abuf *i, *inext;
1.28 ratchov 756: unsigned idone;
1.31 ratchov 757:
1.12 ratchov 758: if (!ABUF_ROK(ibuf))
759: return 0;
1.28 ratchov 760: idone = ibuf->len;
1.12 ratchov 761: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
1.1 ratchov 762: inext = LIST_NEXT(i, oent);
1.5 ratchov 763: if (!ABUF_WOK(i)) {
1.28 ratchov 764: if (p->u.sub.flags & SUB_DROP) {
765: if (!sub_xrun(ibuf, i))
1.5 ratchov 766: continue;
767: }
1.12 ratchov 768: } else
1.1 ratchov 769: sub_bcopy(ibuf, i);
1.28 ratchov 770: if (idone > i->subidone)
771: idone = i->subidone;
1.12 ratchov 772: if (!abuf_flush(i))
773: continue;
1.1 ratchov 774: }
1.28 ratchov 775: if (LIST_EMPTY(&p->obuflist)) {
776: if (p->u.sub.flags & SUB_AUTOQUIT) {
777: DPRINTF("sub_in: nothing more to do...\n");
778: aproc_del(p);
779: return 0;
780: }
781: if (!(p->u.sub.flags & SUB_DROP))
782: return 0;
783: idone = ibuf->used;
784: p->u.sub.idle += idone / ibuf->bpf;
785: }
786: if (idone == 0)
787: return 0;
1.1 ratchov 788: LIST_FOREACH(i, &p->obuflist, oent) {
1.28 ratchov 789: i->subidone -= idone;
1.1 ratchov 790: }
1.28 ratchov 791: abuf_rdiscard(ibuf, idone);
792: p->u.sub.lat -= idone / ibuf->bpf;
1.12 ratchov 793: return 1;
1.1 ratchov 794: }
795:
796: int
797: sub_out(struct aproc *p, struct abuf *obuf)
798: {
799: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
800: struct abuf *i, *inext;
1.28 ratchov 801: unsigned idone;
1.1 ratchov 802:
1.12 ratchov 803: if (!ABUF_WOK(obuf))
804: return 0;
1.28 ratchov 805: if (!abuf_fill(ibuf))
806: return 0; /* eof */
807: idone = ibuf->len;
1.12 ratchov 808: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
809: inext = LIST_NEXT(i, oent);
1.28 ratchov 810: sub_bcopy(ibuf, i);
811: if (idone > i->subidone)
812: idone = i->subidone;
1.12 ratchov 813: if (!abuf_flush(i))
814: continue;
1.1 ratchov 815: }
1.28 ratchov 816: if (LIST_EMPTY(&p->obuflist) || idone == 0)
817: return 0;
1.1 ratchov 818: LIST_FOREACH(i, &p->obuflist, oent) {
1.28 ratchov 819: i->subidone -= idone;
1.1 ratchov 820: }
1.28 ratchov 821: abuf_rdiscard(ibuf, idone);
822: p->u.sub.lat -= idone / ibuf->bpf;
1.1 ratchov 823: return 1;
824: }
825:
826: void
827: sub_eof(struct aproc *p, struct abuf *ibuf)
828: {
1.28 ratchov 829: DPRINTF("sub_hup: %s: eof\n", p->name);
1.8 ratchov 830: aproc_del(p);
1.1 ratchov 831: }
832:
833: void
834: sub_hup(struct aproc *p, struct abuf *obuf)
835: {
1.28 ratchov 836: struct abuf *i, *ibuf = LIST_FIRST(&p->ibuflist);
837: unsigned idone;
1.1 ratchov 838:
839: DPRINTF("sub_hup: %s: detached\n", p->name);
1.28 ratchov 840:
841: if (!aproc_inuse(p)) {
842: DPRINTF("sub_hup: %s: from input\n", p->name);
843: /*
844: * find a blocked output
845: */
846: idone = ibuf->len;
847: LIST_FOREACH(i, &p->obuflist, oent) {
848: if (ABUF_WOK(i) && i->subidone < ibuf->used) {
849: abuf_run(i);
850: return;
851: }
852: if (idone > i->subidone)
853: idone = i->subidone;
854: }
855: /*
856: * no blocked outputs, check if input is blocked
857: */
858: if (LIST_EMPTY(&p->obuflist) || idone == ibuf->used)
859: abuf_run(ibuf);
860: }
1.1 ratchov 861: }
862:
863: void
864: sub_newout(struct aproc *p, struct abuf *obuf)
865: {
1.13 ratchov 866: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
867:
868: if (!ibuf || obuf->cmin < ibuf->cmin || obuf->cmax > ibuf->cmax) {
869: fprintf(stderr, "sub_newout: channel ranges mismatch\n");
870: abort();
871: }
1.22 ratchov 872: p->u.sub.idle = 0;
1.14 ratchov 873: obuf->subidone = 0;
1.5 ratchov 874: obuf->xrun = XRUN_IGNORE;
1.1 ratchov 875: }
876:
1.12 ratchov 877: void
878: sub_ipos(struct aproc *p, struct abuf *ibuf, int delta)
879: {
880: p->u.sub.lat += delta;
881: DPRINTFN(3, "sub_ipos: lat = %d/%d\n", p->u.sub.lat, p->u.sub.maxlat);
882: aproc_ipos(p, ibuf, delta);
883: }
884:
1.1 ratchov 885: struct aproc_ops sub_ops = {
1.12 ratchov 886: "sub",
887: sub_in,
888: sub_out,
889: sub_eof,
890: sub_hup,
891: NULL,
892: sub_newout,
893: sub_ipos,
894: aproc_opos,
895: NULL
1.1 ratchov 896: };
897:
898: struct aproc *
1.12 ratchov 899: sub_new(char *name, int maxlat)
1.1 ratchov 900: {
901: struct aproc *p;
902:
1.12 ratchov 903: p = aproc_new(&sub_ops, name);
1.5 ratchov 904: p->u.sub.flags = 0;
1.22 ratchov 905: p->u.sub.idle = 0;
1.12 ratchov 906: p->u.sub.lat = 0;
907: p->u.sub.maxlat = maxlat;
1.1 ratchov 908: return p;
1.22 ratchov 909: }
910:
911: void
912: sub_clear(struct aproc *p)
913: {
914: p->u.mix.lat = 0;
1.1 ratchov 915: }
916:
917: /*
918: * Convert one block.
919: */
920: void
1.15 ratchov 921: resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
922: {
923: unsigned inch;
924: short *idata;
1.27 ratchov 925: unsigned oblksz;
1.15 ratchov 926: unsigned ifr;
927: unsigned onch;
1.27 ratchov 928: int s1, s2, diff;
1.15 ratchov 929: short *odata;
1.27 ratchov 930: unsigned iblksz;
1.15 ratchov 931: unsigned ofr;
932: unsigned c;
1.31 ratchov 933: short *ctxbuf, *ctx;
1.27 ratchov 934: unsigned ctx_start;
1.15 ratchov 935: unsigned icount, ocount;
936:
937: /*
938: * Calculate max frames readable at once from the input buffer.
939: */
940: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
941: ifr = icount / ibuf->bpf;
942: icount = ifr * ibuf->bpf;
943:
944: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
945: ofr = ocount / obuf->bpf;
946: ocount = ofr * obuf->bpf;
947:
948: /*
949: * Partially copy structures into local variables, to avoid
950: * unnecessary indirections; this also allows the compiler to
951: * order local variables more "cache-friendly".
952: */
1.27 ratchov 953: diff = p->u.resamp.diff;
1.15 ratchov 954: inch = ibuf->cmax - ibuf->cmin + 1;
1.26 ratchov 955: iblksz = p->u.resamp.iblksz;
1.15 ratchov 956: onch = obuf->cmax - obuf->cmin + 1;
1.26 ratchov 957: oblksz = p->u.resamp.oblksz;
1.15 ratchov 958: ctxbuf = p->u.resamp.ctx;
1.27 ratchov 959: ctx_start = p->u.resamp.ctx_start;
1.15 ratchov 960:
961: /*
962: * Start conversion.
963: */
964: DPRINTFN(4, "resamp_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
965: for (;;) {
1.27 ratchov 966: if (diff < 0) {
1.15 ratchov 967: if (ifr == 0)
968: break;
1.27 ratchov 969: ctx_start ^= 1;
970: ctx = ctxbuf + ctx_start;
1.15 ratchov 971: for (c = inch; c > 0; c--) {
1.29 ratchov 972: *ctx = *idata++;
1.27 ratchov 973: ctx += RESAMP_NCTX;
1.15 ratchov 974: }
1.27 ratchov 975: diff += oblksz;
1.15 ratchov 976: ifr--;
1.27 ratchov 977: } else {
978: if (ofr == 0)
979: break;
980: ctx = ctxbuf;
981: for (c = onch; c > 0; c--) {
1.29 ratchov 982: s1 = ctx[ctx_start];
983: s2 = ctx[ctx_start ^ 1];
1.27 ratchov 984: ctx += RESAMP_NCTX;
985: *odata++ = s1 + (s2 - s1) * diff / (int)oblksz;
986: }
987: diff -= iblksz;
988: ofr--;
1.15 ratchov 989: }
990: }
1.27 ratchov 991: p->u.resamp.diff = diff;
992: p->u.resamp.ctx_start = ctx_start;
1.15 ratchov 993: DPRINTFN(4, "resamp_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
994:
995: /*
996: * Update FIFO pointers.
997: */
998: icount -= ifr * ibuf->bpf;
999: ocount -= ofr * obuf->bpf;
1000: abuf_rdiscard(ibuf, icount);
1001: abuf_wcommit(obuf, ocount);
1002: }
1003:
1004: int
1005: resamp_in(struct aproc *p, struct abuf *ibuf)
1006: {
1007: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1008:
1009: DPRINTFN(4, "resamp_in: %s\n", p->name);
1010:
1011: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1012: return 0;
1013: resamp_bcopy(p, ibuf, obuf);
1014: if (!abuf_flush(obuf))
1015: return 0;
1016: return 1;
1017: }
1018:
1019: int
1020: resamp_out(struct aproc *p, struct abuf *obuf)
1021: {
1022: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1023:
1024: DPRINTFN(4, "resamp_out: %s\n", p->name);
1025:
1026: if (!abuf_fill(ibuf))
1027: return 0;
1028: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1029: return 0;
1030: resamp_bcopy(p, ibuf, obuf);
1031: return 1;
1032: }
1033:
1034: void
1035: resamp_eof(struct aproc *p, struct abuf *ibuf)
1036: {
1037: DPRINTFN(4, "resamp_eof: %s\n", p->name);
1038:
1039: aproc_del(p);
1040: }
1041:
1042: void
1043: resamp_hup(struct aproc *p, struct abuf *obuf)
1044: {
1045: DPRINTFN(4, "resamp_hup: %s\n", p->name);
1046:
1047: aproc_del(p);
1048: }
1049:
1050: void
1051: resamp_ipos(struct aproc *p, struct abuf *ibuf, int delta)
1052: {
1.31 ratchov 1053: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1.15 ratchov 1054: long long ipos;
1055: int ifac, ofac;
1056:
1057: DPRINTFN(3, "resamp_ipos: %d\n", delta);
1058:
1.26 ratchov 1059: ifac = p->u.resamp.iblksz;
1060: ofac = p->u.resamp.oblksz;
1.15 ratchov 1061: ipos = p->u.resamp.idelta + (long long)delta * ofac;
1062: delta = (ipos + ifac - 1) / ifac;
1063: p->u.resamp.idelta = ipos - (long long)delta * ifac;
1064: abuf_ipos(obuf, delta);
1065: }
1066:
1067: void
1068: resamp_opos(struct aproc *p, struct abuf *obuf, int delta)
1069: {
1070: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1071: long long opos;
1072: int ifac, ofac;
1073:
1074: DPRINTFN(3, "resamp_opos: %d\n", delta);
1075:
1.26 ratchov 1076: ifac = p->u.resamp.iblksz;
1077: ofac = p->u.resamp.oblksz;
1.15 ratchov 1078: opos = p->u.resamp.odelta + (long long)delta * ifac;
1079: delta = (opos + ofac - 1) / ofac;
1080: p->u.resamp.odelta = opos - (long long)delta * ofac;
1081: abuf_opos(ibuf, delta);
1082: }
1083:
1084: struct aproc_ops resamp_ops = {
1085: "resamp",
1086: resamp_in,
1087: resamp_out,
1088: resamp_eof,
1089: resamp_hup,
1090: NULL,
1091: NULL,
1092: resamp_ipos,
1093: resamp_opos,
1094: NULL
1095: };
1096:
1097: struct aproc *
1.26 ratchov 1098: resamp_new(char *name, unsigned iblksz, unsigned oblksz)
1.15 ratchov 1099: {
1100: struct aproc *p;
1.16 ratchov 1101: unsigned i;
1.15 ratchov 1102:
1103: p = aproc_new(&resamp_ops, name);
1.26 ratchov 1104: p->u.resamp.iblksz = iblksz;
1105: p->u.resamp.oblksz = oblksz;
1.27 ratchov 1106: p->u.resamp.diff = 0;
1.15 ratchov 1107: p->u.resamp.idelta = 0;
1108: p->u.resamp.odelta = 0;
1.27 ratchov 1109: p->u.resamp.ctx_start = 0;
1110: for (i = 0; i < NCHAN_MAX * RESAMP_NCTX; i++)
1.16 ratchov 1111: p->u.resamp.ctx[i] = 0;
1.25 ratchov 1112: #ifdef DEBUG
1.26 ratchov 1113: if (debug_level > 0)
1114: fprintf(stderr, "resamp_new: %u/%u\n", iblksz, oblksz);
1.25 ratchov 1115: #endif
1.17 ratchov 1116: return p;
1117: }
1118:
1119: /*
1120: * Convert one block.
1121: */
1122: void
1123: cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1124: {
1125: unsigned inch;
1126: short *idata;
1127: unsigned onch;
1128: short *odata;
1129: short *ctx, *ictx, *octx;
1130: unsigned c, f, scount, icount, ocount;
1131:
1132: /*
1133: * Calculate max frames readable at once from the input buffer.
1134: */
1135: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1136: icount /= ibuf->bpf;
1137: if (icount == 0)
1138: return;
1139: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
1140: ocount /= obuf->bpf;
1141: if (ocount == 0)
1142: return;
1143: scount = icount < ocount ? icount : ocount;
1144: inch = ibuf->cmax - ibuf->cmin + 1;
1145: onch = obuf->cmax - obuf->cmin + 1;
1146: ictx = p->u.cmap.ctx + ibuf->cmin;
1147: octx = p->u.cmap.ctx + obuf->cmin;
1148:
1149: for (f = scount; f > 0; f--) {
1150: ctx = ictx;
1151: for (c = inch; c > 0; c--) {
1152: *ctx = *idata;
1153: idata++;
1154: ctx++;
1155: }
1156: ctx = octx;
1157: for (c = onch; c > 0; c--) {
1158: *odata = *ctx;
1159: odata++;
1160: ctx++;
1161: }
1162: }
1163: DPRINTFN(4, "cmap_bcopy: scount = %u\n", scount);
1164: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1165: abuf_wcommit(obuf, scount * obuf->bpf);
1166: }
1167:
1168: int
1169: cmap_in(struct aproc *p, struct abuf *ibuf)
1170: {
1171: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1172:
1173: DPRINTFN(4, "cmap_in: %s\n", p->name);
1174:
1175: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1176: return 0;
1177: cmap_bcopy(p, ibuf, obuf);
1178: if (!abuf_flush(obuf))
1179: return 0;
1180: return 1;
1181: }
1182:
1183: int
1184: cmap_out(struct aproc *p, struct abuf *obuf)
1185: {
1186: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1187:
1188: DPRINTFN(4, "cmap_out: %s\n", p->name);
1189:
1190: if (!abuf_fill(ibuf))
1191: return 0;
1192: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1193: return 0;
1194: cmap_bcopy(p, ibuf, obuf);
1195: return 1;
1196: }
1197:
1198: void
1199: cmap_eof(struct aproc *p, struct abuf *ibuf)
1200: {
1201: DPRINTFN(4, "cmap_eof: %s\n", p->name);
1202:
1203: aproc_del(p);
1204: }
1205:
1206: void
1207: cmap_hup(struct aproc *p, struct abuf *obuf)
1208: {
1209: DPRINTFN(4, "cmap_hup: %s\n", p->name);
1210:
1211: aproc_del(p);
1212: }
1213:
1214: struct aproc_ops cmap_ops = {
1215: "cmap",
1216: cmap_in,
1217: cmap_out,
1218: cmap_eof,
1219: cmap_hup,
1220: NULL,
1221: NULL,
1.19 ratchov 1222: aproc_ipos,
1223: aproc_opos,
1.17 ratchov 1224: NULL
1225: };
1226:
1227: struct aproc *
1228: cmap_new(char *name, struct aparams *ipar, struct aparams *opar)
1229: {
1230: struct aproc *p;
1231: unsigned i;
1232:
1233: p = aproc_new(&cmap_ops, name);
1234: for (i = 0; i < NCHAN_MAX; i++)
1235: p->u.cmap.ctx[i] = 0;
1.25 ratchov 1236: #ifdef DEBUG
1.17 ratchov 1237: if (debug_level > 0) {
1.25 ratchov 1238: fprintf(stderr, "cmap_new: %s: ", p->name);
1.12 ratchov 1239: aparams_print2(ipar, opar);
1.25 ratchov 1240: fprintf(stderr, "\n");
1.19 ratchov 1241: }
1.25 ratchov 1242: #endif
1.19 ratchov 1243: return p;
1244: }
1245:
1246: /*
1247: * Convert one block.
1248: */
1249: void
1250: enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1251: {
1252: unsigned nch, scount, icount, ocount;
1253: unsigned f;
1254: short *idata;
1255: int s;
1256: unsigned oshift;
1257: int osigbit;
1258: unsigned obps;
1259: unsigned i;
1260: unsigned char *odata;
1261: int obnext;
1262: int osnext;
1263:
1264: /*
1265: * Calculate max frames readable at once from the input buffer.
1266: */
1267: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1268: icount /= ibuf->bpf;
1269: if (icount == 0)
1270: return;
1271: odata = abuf_wgetblk(obuf, &ocount, 0);
1272: ocount /= obuf->bpf;
1273: if (ocount == 0)
1274: return;
1275: scount = (icount < ocount) ? icount : ocount;
1276: nch = ibuf->cmax - ibuf->cmin + 1;
1277: DPRINTFN(4, "enc_bcopy: scount = %u, nch = %u\n", scount, nch);
1278:
1279: /*
1280: * Partially copy structures into local variables, to avoid
1281: * unnecessary indirections; this also allows the compiler to
1282: * order local variables more "cache-friendly".
1283: */
1284: oshift = p->u.conv.shift;
1285: osigbit = p->u.conv.sigbit;
1286: obps = p->u.conv.bps;
1287: obnext = p->u.conv.bnext;
1288: osnext = p->u.conv.snext;
1289:
1290: /*
1291: * Start conversion.
1292: */
1293: odata += p->u.conv.bfirst;
1294: for (f = scount * nch; f > 0; f--) {
1295: s = *idata++;
1296: s <<= 16;
1297: s >>= oshift;
1298: s ^= osigbit;
1299: for (i = obps; i > 0; i--) {
1300: *odata = (unsigned char)s;
1301: s >>= 8;
1302: odata += obnext;
1303: }
1304: odata += osnext;
1305: }
1306:
1307: /*
1308: * Update FIFO pointers.
1309: */
1310: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1311: abuf_wcommit(obuf, scount * obuf->bpf);
1312: }
1313:
1314: int
1315: enc_in(struct aproc *p, struct abuf *ibuf)
1316: {
1317: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1318:
1319: DPRINTFN(4, "enc_in: %s\n", p->name);
1320:
1321: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1322: return 0;
1323: enc_bcopy(p, ibuf, obuf);
1324: if (!abuf_flush(obuf))
1325: return 0;
1326: return 1;
1327: }
1328:
1329: int
1330: enc_out(struct aproc *p, struct abuf *obuf)
1331: {
1332: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1333:
1334: DPRINTFN(4, "enc_out: %s\n", p->name);
1335:
1336: if (!abuf_fill(ibuf))
1337: return 0;
1338: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1339: return 0;
1340: enc_bcopy(p, ibuf, obuf);
1341: return 1;
1342: }
1343:
1344: void
1345: enc_eof(struct aproc *p, struct abuf *ibuf)
1346: {
1347: DPRINTFN(4, "enc_eof: %s\n", p->name);
1348:
1349: aproc_del(p);
1350: }
1351:
1352: void
1353: enc_hup(struct aproc *p, struct abuf *obuf)
1354: {
1355: DPRINTFN(4, "enc_hup: %s\n", p->name);
1356:
1357: aproc_del(p);
1358: }
1359:
1360: struct aproc_ops enc_ops = {
1361: "enc",
1362: enc_in,
1363: enc_out,
1364: enc_eof,
1365: enc_hup,
1366: NULL,
1367: NULL,
1368: aproc_ipos,
1369: aproc_opos,
1370: NULL
1371: };
1372:
1373: struct aproc *
1374: enc_new(char *name, struct aparams *par)
1375: {
1376: struct aproc *p;
1377:
1378: p = aproc_new(&enc_ops, name);
1379: p->u.conv.bps = par->bps;
1380: p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
1381: if (par->msb) {
1382: p->u.conv.shift = 32 - par->bps * 8;
1383: } else {
1384: p->u.conv.shift = 32 - par->bits;
1385: }
1386: if (!par->le) {
1387: p->u.conv.bfirst = par->bps - 1;
1388: p->u.conv.bnext = -1;
1389: p->u.conv.snext = 2 * par->bps;
1390: } else {
1391: p->u.conv.bfirst = 0;
1392: p->u.conv.bnext = 1;
1393: p->u.conv.snext = 0;
1394: }
1.25 ratchov 1395: #ifdef DEBUG
1.19 ratchov 1396: if (debug_level > 0) {
1397: fprintf(stderr, "enc_new: %s: ", p->name);
1398: aparams_print(par);
1399: fprintf(stderr, "\n");
1400: }
1.25 ratchov 1401: #endif
1.19 ratchov 1402: return p;
1403: }
1404:
1405: /*
1406: * Convert one block.
1407: */
1408: void
1409: dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1410: {
1411: unsigned nch, scount, icount, ocount;
1412: unsigned f;
1413: unsigned ibps;
1414: unsigned i;
1415: int s = 0xdeadbeef;
1416: unsigned char *idata;
1417: int ibnext;
1418: int isnext;
1419: int isigbit;
1420: unsigned ishift;
1421: short *odata;
1422:
1423: /*
1424: * Calculate max frames readable at once from the input buffer.
1425: */
1426: idata = abuf_rgetblk(ibuf, &icount, 0);
1427: icount /= ibuf->bpf;
1428: if (icount == 0)
1429: return;
1430: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
1431: ocount /= obuf->bpf;
1432: if (ocount == 0)
1433: return;
1434: scount = (icount < ocount) ? icount : ocount;
1435: nch = obuf->cmax - obuf->cmin + 1;
1436: DPRINTFN(4, "dec_bcopy: scount = %u, nch = %u\n", scount, nch);
1437:
1438: /*
1439: * Partially copy structures into local variables, to avoid
1440: * unnecessary indirections; this also allows the compiler to
1441: * order local variables more "cache-friendly".
1442: */
1443: ibps = p->u.conv.bps;
1444: ibnext = p->u.conv.bnext;
1445: isigbit = p->u.conv.sigbit;
1446: ishift = p->u.conv.shift;
1447: isnext = p->u.conv.snext;
1448:
1449: /*
1450: * Start conversion.
1451: */
1452: idata += p->u.conv.bfirst;
1453: for (f = scount * nch; f > 0; f--) {
1454: for (i = ibps; i > 0; i--) {
1455: s <<= 8;
1456: s |= *idata;
1457: idata += ibnext;
1458: }
1459: idata += isnext;
1460: s ^= isigbit;
1461: s <<= ishift;
1462: s >>= 16;
1463: *odata++ = s;
1464: }
1465:
1466: /*
1467: * Update FIFO pointers.
1468: */
1469: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1470: abuf_wcommit(obuf, scount * obuf->bpf);
1471: }
1472:
1473: int
1474: dec_in(struct aproc *p, struct abuf *ibuf)
1475: {
1476: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1477:
1478: DPRINTFN(4, "dec_in: %s\n", p->name);
1479:
1480: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1481: return 0;
1482: dec_bcopy(p, ibuf, obuf);
1483: if (!abuf_flush(obuf))
1484: return 0;
1485: return 1;
1486: }
1487:
1488: int
1489: dec_out(struct aproc *p, struct abuf *obuf)
1490: {
1491: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1492:
1493: DPRINTFN(4, "dec_out: %s\n", p->name);
1494:
1495: if (!abuf_fill(ibuf))
1496: return 0;
1497: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1498: return 0;
1499: dec_bcopy(p, ibuf, obuf);
1500: return 1;
1501: }
1502:
1503: void
1504: dec_eof(struct aproc *p, struct abuf *ibuf)
1505: {
1506: DPRINTFN(4, "dec_eof: %s\n", p->name);
1507:
1508: aproc_del(p);
1509: }
1510:
1511: void
1512: dec_hup(struct aproc *p, struct abuf *obuf)
1513: {
1514: DPRINTFN(4, "dec_hup: %s\n", p->name);
1515:
1516: aproc_del(p);
1517: }
1518:
1519: struct aproc_ops dec_ops = {
1520: "dec",
1521: dec_in,
1522: dec_out,
1523: dec_eof,
1524: dec_hup,
1525: NULL,
1526: NULL,
1527: aproc_ipos,
1528: aproc_opos,
1529: NULL
1530: };
1531:
1532: struct aproc *
1533: dec_new(char *name, struct aparams *par)
1534: {
1535: struct aproc *p;
1536:
1537: p = aproc_new(&dec_ops, name);
1538: p->u.conv.bps = par->bps;
1539: p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
1540: if (par->msb) {
1541: p->u.conv.shift = 32 - par->bps * 8;
1542: } else {
1543: p->u.conv.shift = 32 - par->bits;
1544: }
1545: if (par->le) {
1546: p->u.conv.bfirst = par->bps - 1;
1547: p->u.conv.bnext = -1;
1548: p->u.conv.snext = 2 * par->bps;
1549: } else {
1550: p->u.conv.bfirst = 0;
1551: p->u.conv.bnext = 1;
1552: p->u.conv.snext = 0;
1553: }
1.25 ratchov 1554: #ifdef DEBUG
1.19 ratchov 1555: if (debug_level > 0) {
1.31 ratchov 1556: fprintf(stderr, "dec_new: %s: ", p->name);
1.19 ratchov 1557: aparams_print(par);
1558: fprintf(stderr, "\n");
1.12 ratchov 1559: }
1.25 ratchov 1560: #endif
1.1 ratchov 1561: return p;
1562: }