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