Annotation of src/usr.bin/aucat/aproc.c, Revision 1.41
1.41 ! ratchov 1: /* $OpenBSD: aproc.c,v 1.40 2009/11/15 21:44:09 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.41 ! ratchov 160: rfile_in(struct aproc *p, struct abuf *ibuf_dummy)
1.1 ratchov 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
1.41 ! ratchov 180: rfile_out(struct aproc *p, struct abuf *obuf)
1.1 ratchov 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.41 ! ratchov 199: rfile_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
1.41 ! ratchov 222: rfile_eof(struct aproc *p, struct abuf *ibuf_dummy)
1.1 ratchov 223: {
1.8 ratchov 224: aproc_del(p);
1.1 ratchov 225: }
226:
227: void
1.41 ! ratchov 228: rfile_hup(struct aproc *p, struct abuf *obuf)
1.1 ratchov 229: {
1.8 ratchov 230: aproc_del(p);
1.1 ratchov 231: }
232:
1.41 ! ratchov 233: struct aproc_ops rfile_ops = {
1.12 ratchov 234: "rpipe",
1.41 ! ratchov 235: rfile_in,
! 236: rfile_out,
! 237: rfile_eof,
! 238: rfile_hup,
1.12 ratchov 239: NULL, /* newin */
240: NULL, /* newout */
241: aproc_ipos,
242: aproc_opos,
1.41 ! ratchov 243: rfile_done
1.1 ratchov 244: };
245:
246: struct aproc *
1.41 ! ratchov 247: rfile_new(struct file *f)
1.1 ratchov 248: {
249: struct aproc *p;
250:
1.41 ! ratchov 251: p = aproc_new(&rfile_ops, f->name);
1.1 ratchov 252: p->u.io.file = f;
1.31 ratchov 253: f->rproc = p;
1.1 ratchov 254: return p;
255: }
256:
257: void
1.41 ! ratchov 258: wfile_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
1.41 ! ratchov 281: wfile_in(struct aproc *p, struct abuf *ibuf)
1.1 ratchov 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
1.41 ! ratchov 300: wfile_out(struct aproc *p, struct abuf *obuf_dummy)
1.1 ratchov 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
1.41 ! ratchov 324: wfile_eof(struct aproc *p, struct abuf *ibuf)
1.1 ratchov 325: {
1.8 ratchov 326: aproc_del(p);
1.1 ratchov 327: }
328:
329: void
1.41 ! ratchov 330: wfile_hup(struct aproc *p, struct abuf *obuf_dummy)
1.1 ratchov 331: {
1.8 ratchov 332: aproc_del(p);
1.1 ratchov 333: }
334:
1.41 ! ratchov 335: struct aproc_ops wfile_ops = {
1.12 ratchov 336: "wpipe",
1.41 ! ratchov 337: wfile_in,
! 338: wfile_out,
! 339: wfile_eof,
! 340: wfile_hup,
1.12 ratchov 341: NULL, /* newin */
342: NULL, /* newout */
343: aproc_ipos,
344: aproc_opos,
1.41 ! ratchov 345: wfile_done
1.1 ratchov 346: };
347:
348: struct aproc *
1.41 ! ratchov 349: wfile_new(struct file *f)
1.1 ratchov 350: {
351: struct aproc *p;
352:
1.41 ! ratchov 353: p = aproc_new(&wfile_ops, f->name);
1.1 ratchov 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;
1.40 ratchov 628: struct abuf *i, *j;
1.24 ratchov 629: int weight;
1.10 ratchov 630:
1.40 ratchov 631: /*
632: * count the number of inputs. If a set of inputs
633: * uses channels that have no intersection, they are
634: * counted only once because they don't need to
635: * share their volume
636: */
1.10 ratchov 637: n = 0;
1.40 ratchov 638: LIST_FOREACH(i, &p->ibuflist, ient) {
639: j = LIST_NEXT(i, ient);
640: for (;;) {
641: if (j == NULL) {
642: n++;
643: break;
644: }
645: if (i->cmin > j->cmax || i->cmax < j->cmin)
646: break;
647: j = LIST_NEXT(j, ient);
648: }
1.24 ratchov 649: }
1.40 ratchov 650: LIST_FOREACH(i, &p->ibuflist, ient) {
1.24 ratchov 651: weight = ADATA_UNIT / n;
1.40 ratchov 652: if (weight > i->r.mix.maxweight)
653: weight = i->r.mix.maxweight;
654: i->r.mix.weight = weight;
1.24 ratchov 655: }
1.1 ratchov 656: }
657:
1.22 ratchov 658: void
659: mix_clear(struct aproc *p)
660: {
661: struct abuf *obuf = LIST_FIRST(&p->obuflist);
662:
663: p->u.mix.lat = 0;
1.36 ratchov 664: obuf->w.mix.todo = 0;
1.22 ratchov 665: }
666:
1.1 ratchov 667: /*
668: * Copy data from ibuf to obuf.
669: */
670: void
671: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
672: {
1.13 ratchov 673: short *idata, *odata;
674: unsigned i, j, ocnt, inext, istart;
1.1 ratchov 675: unsigned icount, ocount, scount;
676:
1.36 ratchov 677: idata = (short *)abuf_rgetblk(ibuf, &icount, obuf->w.sub.done);
1.13 ratchov 678: icount /= ibuf->bpf;
1.1 ratchov 679: if (icount == 0)
680: return;
1.13 ratchov 681: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
682: ocount /= obuf->bpf;
1.1 ratchov 683: if (ocount == 0)
684: return;
1.13 ratchov 685: istart = obuf->cmin - ibuf->cmin;
686: inext = ibuf->cmax - obuf->cmax + istart;
687: ocnt = obuf->cmax - obuf->cmin + 1;
1.1 ratchov 688: scount = (icount < ocount) ? icount : ocount;
1.13 ratchov 689: idata += istart;
690: for (i = scount; i > 0; i--) {
691: for (j = ocnt; j > 0; j--) {
692: *odata = *idata;
693: odata++;
694: idata++;
695: }
696: idata += inext;
697: }
1.31 ratchov 698: abuf_wcommit(obuf, scount * obuf->bpf);
1.36 ratchov 699: obuf->w.sub.done += scount * ibuf->bpf;
1.1 ratchov 700: }
701:
1.28 ratchov 702: /*
1.33 ratchov 703: * Handle buffer overruns. Return 0 if the stream died.
1.28 ratchov 704: */
705: int
706: sub_xrun(struct abuf *ibuf, struct abuf *i)
707: {
708: unsigned fdrop;
709:
1.36 ratchov 710: if (i->w.sub.done > 0)
1.28 ratchov 711: return 1;
1.36 ratchov 712: if (i->w.sub.xrun == XRUN_ERROR) {
1.28 ratchov 713: abuf_eof(i);
714: return 0;
715: }
716: fdrop = ibuf->used / ibuf->bpf;
1.36 ratchov 717: if (i->w.sub.xrun == XRUN_SYNC)
1.28 ratchov 718: i->silence += fdrop * i->bpf;
719: else {
720: abuf_ipos(i, -(int)fdrop);
721: if (i->duplex) {
722: i->duplex->silence += fdrop * i->duplex->bpf;
723: abuf_opos(i->duplex, -(int)fdrop);
724: }
725: }
1.36 ratchov 726: i->w.sub.done += fdrop * ibuf->bpf;
1.28 ratchov 727: return 1;
728: }
729:
1.1 ratchov 730: int
731: sub_in(struct aproc *p, struct abuf *ibuf)
732: {
733: struct abuf *i, *inext;
1.28 ratchov 734: unsigned idone;
1.31 ratchov 735:
1.12 ratchov 736: if (!ABUF_ROK(ibuf))
737: return 0;
1.28 ratchov 738: idone = ibuf->len;
1.12 ratchov 739: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
1.1 ratchov 740: inext = LIST_NEXT(i, oent);
1.5 ratchov 741: if (!ABUF_WOK(i)) {
1.38 ratchov 742: if (p->flags & APROC_DROP) {
1.28 ratchov 743: if (!sub_xrun(ibuf, i))
1.5 ratchov 744: continue;
745: }
1.12 ratchov 746: } else
1.1 ratchov 747: sub_bcopy(ibuf, i);
1.36 ratchov 748: if (idone > i->w.sub.done)
749: idone = i->w.sub.done;
1.12 ratchov 750: if (!abuf_flush(i))
751: continue;
1.1 ratchov 752: }
1.28 ratchov 753: if (LIST_EMPTY(&p->obuflist)) {
1.38 ratchov 754: if (p->flags & APROC_QUIT) {
1.28 ratchov 755: aproc_del(p);
756: return 0;
757: }
1.38 ratchov 758: if (!(p->flags & APROC_DROP))
1.28 ratchov 759: return 0;
760: idone = ibuf->used;
761: p->u.sub.idle += idone / ibuf->bpf;
762: }
763: if (idone == 0)
764: return 0;
1.1 ratchov 765: LIST_FOREACH(i, &p->obuflist, oent) {
1.36 ratchov 766: i->w.sub.done -= idone;
1.1 ratchov 767: }
1.28 ratchov 768: abuf_rdiscard(ibuf, idone);
769: p->u.sub.lat -= idone / ibuf->bpf;
1.12 ratchov 770: return 1;
1.1 ratchov 771: }
772:
773: int
774: sub_out(struct aproc *p, struct abuf *obuf)
775: {
776: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
777: struct abuf *i, *inext;
1.28 ratchov 778: unsigned idone;
1.1 ratchov 779:
1.12 ratchov 780: if (!ABUF_WOK(obuf))
781: return 0;
1.28 ratchov 782: if (!abuf_fill(ibuf))
783: return 0; /* eof */
784: idone = ibuf->len;
1.12 ratchov 785: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
786: inext = LIST_NEXT(i, oent);
1.28 ratchov 787: sub_bcopy(ibuf, i);
1.36 ratchov 788: if (idone > i->w.sub.done)
789: idone = i->w.sub.done;
1.12 ratchov 790: if (!abuf_flush(i))
791: continue;
1.1 ratchov 792: }
1.28 ratchov 793: if (LIST_EMPTY(&p->obuflist) || idone == 0)
794: return 0;
1.1 ratchov 795: LIST_FOREACH(i, &p->obuflist, oent) {
1.36 ratchov 796: i->w.sub.done -= idone;
1.1 ratchov 797: }
1.28 ratchov 798: abuf_rdiscard(ibuf, idone);
799: p->u.sub.lat -= idone / ibuf->bpf;
1.1 ratchov 800: return 1;
801: }
802:
803: void
804: sub_eof(struct aproc *p, struct abuf *ibuf)
805: {
1.8 ratchov 806: aproc_del(p);
1.1 ratchov 807: }
808:
809: void
810: sub_hup(struct aproc *p, struct abuf *obuf)
811: {
1.28 ratchov 812: struct abuf *i, *ibuf = LIST_FIRST(&p->ibuflist);
813: unsigned idone;
1.1 ratchov 814:
1.28 ratchov 815: if (!aproc_inuse(p)) {
816: /*
1.33 ratchov 817: * Find a blocked output.
1.28 ratchov 818: */
819: idone = ibuf->len;
820: LIST_FOREACH(i, &p->obuflist, oent) {
1.36 ratchov 821: if (ABUF_WOK(i) && i->w.sub.done < ibuf->used) {
1.28 ratchov 822: abuf_run(i);
823: return;
824: }
1.36 ratchov 825: if (idone > i->w.sub.done)
826: idone = i->w.sub.done;
1.28 ratchov 827: }
828: /*
1.33 ratchov 829: * No blocked outputs. Check if input is blocked.
1.28 ratchov 830: */
831: if (LIST_EMPTY(&p->obuflist) || idone == ibuf->used)
832: abuf_run(ibuf);
833: }
1.1 ratchov 834: }
835:
836: void
837: sub_newout(struct aproc *p, struct abuf *obuf)
838: {
1.22 ratchov 839: p->u.sub.idle = 0;
1.36 ratchov 840: obuf->w.sub.done = 0;
841: obuf->w.sub.xrun = XRUN_IGNORE;
1.1 ratchov 842: }
843:
1.12 ratchov 844: void
845: sub_ipos(struct aproc *p, struct abuf *ibuf, int delta)
846: {
847: p->u.sub.lat += delta;
1.38 ratchov 848: if (p->u.sub.ctl)
849: ctl_ontick(p->u.sub.ctl, delta);
1.12 ratchov 850: aproc_ipos(p, ibuf, delta);
851: }
852:
1.1 ratchov 853: struct aproc_ops sub_ops = {
1.12 ratchov 854: "sub",
855: sub_in,
856: sub_out,
857: sub_eof,
858: sub_hup,
859: NULL,
860: sub_newout,
861: sub_ipos,
862: aproc_opos,
863: NULL
1.1 ratchov 864: };
865:
866: struct aproc *
1.38 ratchov 867: sub_new(char *name, int maxlat, struct aproc *ctl)
1.1 ratchov 868: {
869: struct aproc *p;
870:
1.12 ratchov 871: p = aproc_new(&sub_ops, name);
1.22 ratchov 872: p->u.sub.idle = 0;
1.12 ratchov 873: p->u.sub.lat = 0;
874: p->u.sub.maxlat = maxlat;
1.38 ratchov 875: p->u.sub.ctl = ctl;
1.1 ratchov 876: return p;
1.22 ratchov 877: }
878:
879: void
880: sub_clear(struct aproc *p)
881: {
882: p->u.mix.lat = 0;
1.1 ratchov 883: }
884:
885: /*
886: * Convert one block.
887: */
888: void
1.15 ratchov 889: resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
890: {
891: unsigned inch;
892: short *idata;
1.27 ratchov 893: unsigned oblksz;
1.15 ratchov 894: unsigned ifr;
895: unsigned onch;
1.27 ratchov 896: int s1, s2, diff;
1.15 ratchov 897: short *odata;
1.27 ratchov 898: unsigned iblksz;
1.15 ratchov 899: unsigned ofr;
900: unsigned c;
1.31 ratchov 901: short *ctxbuf, *ctx;
1.27 ratchov 902: unsigned ctx_start;
1.15 ratchov 903: unsigned icount, ocount;
904:
905: /*
906: * Calculate max frames readable at once from the input buffer.
907: */
908: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
909: ifr = icount / ibuf->bpf;
910: icount = ifr * ibuf->bpf;
911:
912: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
913: ofr = ocount / obuf->bpf;
914: ocount = ofr * obuf->bpf;
915:
916: /*
917: * Partially copy structures into local variables, to avoid
918: * unnecessary indirections; this also allows the compiler to
919: * order local variables more "cache-friendly".
920: */
1.27 ratchov 921: diff = p->u.resamp.diff;
1.15 ratchov 922: inch = ibuf->cmax - ibuf->cmin + 1;
1.26 ratchov 923: iblksz = p->u.resamp.iblksz;
1.15 ratchov 924: onch = obuf->cmax - obuf->cmin + 1;
1.26 ratchov 925: oblksz = p->u.resamp.oblksz;
1.15 ratchov 926: ctxbuf = p->u.resamp.ctx;
1.27 ratchov 927: ctx_start = p->u.resamp.ctx_start;
1.15 ratchov 928:
929: /*
930: * Start conversion.
931: */
932: for (;;) {
1.27 ratchov 933: if (diff < 0) {
1.15 ratchov 934: if (ifr == 0)
935: break;
1.27 ratchov 936: ctx_start ^= 1;
937: ctx = ctxbuf + ctx_start;
1.15 ratchov 938: for (c = inch; c > 0; c--) {
1.29 ratchov 939: *ctx = *idata++;
1.27 ratchov 940: ctx += RESAMP_NCTX;
1.15 ratchov 941: }
1.27 ratchov 942: diff += oblksz;
1.15 ratchov 943: ifr--;
1.27 ratchov 944: } else {
945: if (ofr == 0)
946: break;
947: ctx = ctxbuf;
948: for (c = onch; c > 0; c--) {
1.29 ratchov 949: s1 = ctx[ctx_start];
950: s2 = ctx[ctx_start ^ 1];
1.27 ratchov 951: ctx += RESAMP_NCTX;
952: *odata++ = s1 + (s2 - s1) * diff / (int)oblksz;
953: }
954: diff -= iblksz;
955: ofr--;
1.15 ratchov 956: }
957: }
1.27 ratchov 958: p->u.resamp.diff = diff;
959: p->u.resamp.ctx_start = ctx_start;
1.15 ratchov 960: /*
961: * Update FIFO pointers.
962: */
963: icount -= ifr * ibuf->bpf;
964: ocount -= ofr * obuf->bpf;
965: abuf_rdiscard(ibuf, icount);
966: abuf_wcommit(obuf, ocount);
967: }
968:
969: int
970: resamp_in(struct aproc *p, struct abuf *ibuf)
971: {
972: struct abuf *obuf = LIST_FIRST(&p->obuflist);
973:
974: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
975: return 0;
976: resamp_bcopy(p, ibuf, obuf);
977: if (!abuf_flush(obuf))
978: return 0;
979: return 1;
980: }
981:
982: int
983: resamp_out(struct aproc *p, struct abuf *obuf)
984: {
985: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
986:
987: if (!abuf_fill(ibuf))
988: return 0;
989: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
990: return 0;
991: resamp_bcopy(p, ibuf, obuf);
992: return 1;
993: }
994:
995: void
996: resamp_eof(struct aproc *p, struct abuf *ibuf)
997: {
998: aproc_del(p);
999: }
1000:
1001: void
1002: resamp_hup(struct aproc *p, struct abuf *obuf)
1003: {
1004: aproc_del(p);
1005: }
1006:
1007: void
1008: resamp_ipos(struct aproc *p, struct abuf *ibuf, int delta)
1009: {
1.31 ratchov 1010: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1.15 ratchov 1011: long long ipos;
1012: int ifac, ofac;
1013:
1.26 ratchov 1014: ifac = p->u.resamp.iblksz;
1015: ofac = p->u.resamp.oblksz;
1.15 ratchov 1016: ipos = p->u.resamp.idelta + (long long)delta * ofac;
1017: delta = (ipos + ifac - 1) / ifac;
1018: p->u.resamp.idelta = ipos - (long long)delta * ifac;
1019: abuf_ipos(obuf, delta);
1020: }
1021:
1022: void
1023: resamp_opos(struct aproc *p, struct abuf *obuf, int delta)
1024: {
1025: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1026: long long opos;
1027: int ifac, ofac;
1028:
1.26 ratchov 1029: ifac = p->u.resamp.iblksz;
1030: ofac = p->u.resamp.oblksz;
1.15 ratchov 1031: opos = p->u.resamp.odelta + (long long)delta * ifac;
1032: delta = (opos + ofac - 1) / ofac;
1033: p->u.resamp.odelta = opos - (long long)delta * ofac;
1034: abuf_opos(ibuf, delta);
1035: }
1036:
1037: struct aproc_ops resamp_ops = {
1038: "resamp",
1039: resamp_in,
1040: resamp_out,
1041: resamp_eof,
1042: resamp_hup,
1043: NULL,
1044: NULL,
1045: resamp_ipos,
1046: resamp_opos,
1047: NULL
1048: };
1049:
1050: struct aproc *
1.26 ratchov 1051: resamp_new(char *name, unsigned iblksz, unsigned oblksz)
1.15 ratchov 1052: {
1053: struct aproc *p;
1.16 ratchov 1054: unsigned i;
1.15 ratchov 1055:
1056: p = aproc_new(&resamp_ops, name);
1.26 ratchov 1057: p->u.resamp.iblksz = iblksz;
1058: p->u.resamp.oblksz = oblksz;
1.27 ratchov 1059: p->u.resamp.diff = 0;
1.15 ratchov 1060: p->u.resamp.idelta = 0;
1061: p->u.resamp.odelta = 0;
1.27 ratchov 1062: p->u.resamp.ctx_start = 0;
1063: for (i = 0; i < NCHAN_MAX * RESAMP_NCTX; i++)
1.16 ratchov 1064: p->u.resamp.ctx[i] = 0;
1.17 ratchov 1065: return p;
1066: }
1067:
1068: /*
1069: * Convert one block.
1070: */
1071: void
1072: cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1073: {
1074: unsigned inch;
1075: short *idata;
1076: unsigned onch;
1077: short *odata;
1078: short *ctx, *ictx, *octx;
1079: unsigned c, f, scount, icount, ocount;
1080:
1081: /*
1082: * Calculate max frames readable at once from the input buffer.
1083: */
1084: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1085: icount /= ibuf->bpf;
1086: if (icount == 0)
1087: return;
1088: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
1089: ocount /= obuf->bpf;
1090: if (ocount == 0)
1091: return;
1092: scount = icount < ocount ? icount : ocount;
1093: inch = ibuf->cmax - ibuf->cmin + 1;
1094: onch = obuf->cmax - obuf->cmin + 1;
1095: ictx = p->u.cmap.ctx + ibuf->cmin;
1096: octx = p->u.cmap.ctx + obuf->cmin;
1097:
1098: for (f = scount; f > 0; f--) {
1099: ctx = ictx;
1100: for (c = inch; c > 0; c--) {
1101: *ctx = *idata;
1102: idata++;
1103: ctx++;
1104: }
1105: ctx = octx;
1106: for (c = onch; c > 0; c--) {
1107: *odata = *ctx;
1108: odata++;
1109: ctx++;
1110: }
1111: }
1112: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1113: abuf_wcommit(obuf, scount * obuf->bpf);
1114: }
1115:
1116: int
1117: cmap_in(struct aproc *p, struct abuf *ibuf)
1118: {
1119: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1120:
1121: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1122: return 0;
1123: cmap_bcopy(p, ibuf, obuf);
1124: if (!abuf_flush(obuf))
1125: return 0;
1126: return 1;
1127: }
1128:
1129: int
1130: cmap_out(struct aproc *p, struct abuf *obuf)
1131: {
1132: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1133:
1134: if (!abuf_fill(ibuf))
1135: return 0;
1136: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1137: return 0;
1138: cmap_bcopy(p, ibuf, obuf);
1139: return 1;
1140: }
1141:
1142: void
1143: cmap_eof(struct aproc *p, struct abuf *ibuf)
1144: {
1145: aproc_del(p);
1146: }
1147:
1148: void
1149: cmap_hup(struct aproc *p, struct abuf *obuf)
1150: {
1151: aproc_del(p);
1152: }
1153:
1154: struct aproc_ops cmap_ops = {
1155: "cmap",
1156: cmap_in,
1157: cmap_out,
1158: cmap_eof,
1159: cmap_hup,
1160: NULL,
1161: NULL,
1.19 ratchov 1162: aproc_ipos,
1163: aproc_opos,
1.17 ratchov 1164: NULL
1165: };
1166:
1167: struct aproc *
1168: cmap_new(char *name, struct aparams *ipar, struct aparams *opar)
1169: {
1170: struct aproc *p;
1171: unsigned i;
1172:
1173: p = aproc_new(&cmap_ops, name);
1174: for (i = 0; i < NCHAN_MAX; i++)
1175: p->u.cmap.ctx[i] = 0;
1.19 ratchov 1176: return p;
1177: }
1178:
1179: /*
1180: * Convert one block.
1181: */
1182: void
1183: enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1184: {
1185: unsigned nch, scount, icount, ocount;
1186: unsigned f;
1187: short *idata;
1188: int s;
1189: unsigned oshift;
1190: int osigbit;
1191: unsigned obps;
1192: unsigned i;
1193: unsigned char *odata;
1194: int obnext;
1195: int osnext;
1196:
1197: /*
1198: * Calculate max frames readable at once from the input buffer.
1199: */
1200: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1201: icount /= ibuf->bpf;
1202: if (icount == 0)
1203: return;
1204: odata = abuf_wgetblk(obuf, &ocount, 0);
1205: ocount /= obuf->bpf;
1206: if (ocount == 0)
1207: return;
1208: scount = (icount < ocount) ? icount : ocount;
1209: nch = ibuf->cmax - ibuf->cmin + 1;
1210: /*
1211: * Partially copy structures into local variables, to avoid
1212: * unnecessary indirections; this also allows the compiler to
1213: * order local variables more "cache-friendly".
1214: */
1215: oshift = p->u.conv.shift;
1216: osigbit = p->u.conv.sigbit;
1217: obps = p->u.conv.bps;
1218: obnext = p->u.conv.bnext;
1219: osnext = p->u.conv.snext;
1220:
1221: /*
1222: * Start conversion.
1223: */
1224: odata += p->u.conv.bfirst;
1225: for (f = scount * nch; f > 0; f--) {
1226: s = *idata++;
1227: s <<= 16;
1228: s >>= oshift;
1229: s ^= osigbit;
1230: for (i = obps; i > 0; i--) {
1231: *odata = (unsigned char)s;
1232: s >>= 8;
1233: odata += obnext;
1234: }
1235: odata += osnext;
1236: }
1237:
1238: /*
1239: * Update FIFO pointers.
1240: */
1241: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1242: abuf_wcommit(obuf, scount * obuf->bpf);
1243: }
1244:
1245: int
1246: enc_in(struct aproc *p, struct abuf *ibuf)
1247: {
1248: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1249:
1250: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1251: return 0;
1252: enc_bcopy(p, ibuf, obuf);
1253: if (!abuf_flush(obuf))
1254: return 0;
1255: return 1;
1256: }
1257:
1258: int
1259: enc_out(struct aproc *p, struct abuf *obuf)
1260: {
1261: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1262:
1263: if (!abuf_fill(ibuf))
1264: return 0;
1265: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1266: return 0;
1267: enc_bcopy(p, ibuf, obuf);
1268: return 1;
1269: }
1270:
1271: void
1272: enc_eof(struct aproc *p, struct abuf *ibuf)
1273: {
1274: aproc_del(p);
1275: }
1276:
1277: void
1278: enc_hup(struct aproc *p, struct abuf *obuf)
1279: {
1280: aproc_del(p);
1281: }
1282:
1283: struct aproc_ops enc_ops = {
1284: "enc",
1285: enc_in,
1286: enc_out,
1287: enc_eof,
1288: enc_hup,
1289: NULL,
1290: NULL,
1291: aproc_ipos,
1292: aproc_opos,
1293: NULL
1294: };
1295:
1296: struct aproc *
1297: enc_new(char *name, struct aparams *par)
1298: {
1299: struct aproc *p;
1300:
1301: p = aproc_new(&enc_ops, name);
1302: p->u.conv.bps = par->bps;
1303: p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
1304: if (par->msb) {
1305: p->u.conv.shift = 32 - par->bps * 8;
1306: } else {
1307: p->u.conv.shift = 32 - par->bits;
1308: }
1309: if (!par->le) {
1310: p->u.conv.bfirst = par->bps - 1;
1311: p->u.conv.bnext = -1;
1312: p->u.conv.snext = 2 * par->bps;
1313: } else {
1314: p->u.conv.bfirst = 0;
1315: p->u.conv.bnext = 1;
1316: p->u.conv.snext = 0;
1317: }
1318: return p;
1319: }
1320:
1321: /*
1322: * Convert one block.
1323: */
1324: void
1325: dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
1326: {
1327: unsigned nch, scount, icount, ocount;
1328: unsigned f;
1329: unsigned ibps;
1330: unsigned i;
1331: int s = 0xdeadbeef;
1332: unsigned char *idata;
1333: int ibnext;
1334: int isnext;
1335: int isigbit;
1336: unsigned ishift;
1337: short *odata;
1338:
1339: /*
1340: * Calculate max frames readable at once from the input buffer.
1341: */
1342: idata = abuf_rgetblk(ibuf, &icount, 0);
1343: icount /= ibuf->bpf;
1344: if (icount == 0)
1345: return;
1346: odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
1347: ocount /= obuf->bpf;
1348: if (ocount == 0)
1349: return;
1350: scount = (icount < ocount) ? icount : ocount;
1351: nch = obuf->cmax - obuf->cmin + 1;
1352: /*
1353: * Partially copy structures into local variables, to avoid
1354: * unnecessary indirections; this also allows the compiler to
1355: * order local variables more "cache-friendly".
1356: */
1357: ibps = p->u.conv.bps;
1358: ibnext = p->u.conv.bnext;
1359: isigbit = p->u.conv.sigbit;
1360: ishift = p->u.conv.shift;
1361: isnext = p->u.conv.snext;
1362:
1363: /*
1364: * Start conversion.
1365: */
1366: idata += p->u.conv.bfirst;
1367: for (f = scount * nch; f > 0; f--) {
1368: for (i = ibps; i > 0; i--) {
1369: s <<= 8;
1370: s |= *idata;
1371: idata += ibnext;
1372: }
1373: idata += isnext;
1374: s ^= isigbit;
1375: s <<= ishift;
1376: s >>= 16;
1377: *odata++ = s;
1378: }
1379:
1380: /*
1381: * Update FIFO pointers.
1382: */
1383: abuf_rdiscard(ibuf, scount * ibuf->bpf);
1384: abuf_wcommit(obuf, scount * obuf->bpf);
1385: }
1386:
1387: int
1388: dec_in(struct aproc *p, struct abuf *ibuf)
1389: {
1390: struct abuf *obuf = LIST_FIRST(&p->obuflist);
1391:
1392: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1393: return 0;
1394: dec_bcopy(p, ibuf, obuf);
1395: if (!abuf_flush(obuf))
1396: return 0;
1397: return 1;
1398: }
1399:
1400: int
1401: dec_out(struct aproc *p, struct abuf *obuf)
1402: {
1403: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
1404:
1405: if (!abuf_fill(ibuf))
1406: return 0;
1407: if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1408: return 0;
1409: dec_bcopy(p, ibuf, obuf);
1410: return 1;
1411: }
1412:
1413: void
1414: dec_eof(struct aproc *p, struct abuf *ibuf)
1415: {
1416: aproc_del(p);
1417: }
1418:
1419: void
1420: dec_hup(struct aproc *p, struct abuf *obuf)
1421: {
1422: aproc_del(p);
1423: }
1424:
1425: struct aproc_ops dec_ops = {
1426: "dec",
1427: dec_in,
1428: dec_out,
1429: dec_eof,
1430: dec_hup,
1431: NULL,
1432: NULL,
1433: aproc_ipos,
1434: aproc_opos,
1435: NULL
1436: };
1437:
1438: struct aproc *
1439: dec_new(char *name, struct aparams *par)
1440: {
1441: struct aproc *p;
1442:
1443: p = aproc_new(&dec_ops, name);
1444: p->u.conv.bps = par->bps;
1445: p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
1446: if (par->msb) {
1447: p->u.conv.shift = 32 - par->bps * 8;
1448: } else {
1449: p->u.conv.shift = 32 - par->bits;
1450: }
1451: if (par->le) {
1452: p->u.conv.bfirst = par->bps - 1;
1453: p->u.conv.bnext = -1;
1454: p->u.conv.snext = 2 * par->bps;
1455: } else {
1456: p->u.conv.bfirst = 0;
1457: p->u.conv.bnext = 1;
1458: p->u.conv.snext = 0;
1459: }
1.1 ratchov 1460: return p;
1461: }