Index: stable/8/sys/dev/sound/pcm/feeder_mixer.c =================================================================== --- stable/8/sys/dev/sound/pcm/feeder_mixer.c (revision 318980) +++ stable/8/sys/dev/sound/pcm/feeder_mixer.c (revision 318981) @@ -1,402 +1,402 @@ /*- * Copyright (c) 2008-2009 Ariff Abdullah * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef _KERNEL #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_snd.h" #endif #include #include #include #include "feeder_if.h" #define SND_USE_FXDIV #include "snd_fxdiv_gen.h" SND_DECLARE_FILE("$FreeBSD$"); #endif #undef SND_FEEDER_MULTIFORMAT #define SND_FEEDER_MULTIFORMAT 1 typedef void (*feed_mixer_t)(uint8_t *, uint8_t *, uint32_t); #define FEEDMIXER_DECLARE(SIGN, BIT, ENDIAN) \ static void \ feed_mixer_##SIGN##BIT##ENDIAN(uint8_t *src, uint8_t *dst, \ uint32_t count) \ { \ intpcm##BIT##_t z; \ intpcm_t x, y; \ \ src += count; \ dst += count; \ \ do { \ src -= PCM_##BIT##_BPS; \ dst -= PCM_##BIT##_BPS; \ count -= PCM_##BIT##_BPS; \ x = PCM_READ_##SIGN##BIT##_##ENDIAN(src); \ y = PCM_READ_##SIGN##BIT##_##ENDIAN(dst); \ z = INTPCM##BIT##_T(x) + y; \ x = PCM_CLAMP_##SIGN##BIT(z); \ _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, x); \ } while (count != 0); \ } #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_DECLARE(S, 16, LE) FEEDMIXER_DECLARE(S, 32, LE) #endif #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_DECLARE(S, 16, BE) FEEDMIXER_DECLARE(S, 32, BE) #endif #ifdef SND_FEEDER_MULTIFORMAT FEEDMIXER_DECLARE(S, 8, NE) FEEDMIXER_DECLARE(S, 24, LE) FEEDMIXER_DECLARE(S, 24, BE) FEEDMIXER_DECLARE(U, 8, NE) FEEDMIXER_DECLARE(U, 16, LE) FEEDMIXER_DECLARE(U, 24, LE) FEEDMIXER_DECLARE(U, 32, LE) FEEDMIXER_DECLARE(U, 16, BE) FEEDMIXER_DECLARE(U, 24, BE) FEEDMIXER_DECLARE(U, 32, BE) #endif struct feed_mixer_info { uint32_t format; int bps; feed_mixer_t mix; }; #define FEEDMIXER_ENTRY(SIGN, BIT, ENDIAN) \ { \ AFMT_##SIGN##BIT##_##ENDIAN, PCM_##BIT##_BPS, \ feed_mixer_##SIGN##BIT##ENDIAN \ } static struct feed_mixer_info feed_mixer_info_tab[] = { FEEDMIXER_ENTRY(S, 8, NE), #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_ENTRY(S, 16, LE), FEEDMIXER_ENTRY(S, 32, LE), #endif #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_ENTRY(S, 16, BE), FEEDMIXER_ENTRY(S, 32, BE), #endif #ifdef SND_FEEDER_MULTIFORMAT FEEDMIXER_ENTRY(S, 24, LE), FEEDMIXER_ENTRY(S, 24, BE), FEEDMIXER_ENTRY(U, 8, NE), FEEDMIXER_ENTRY(U, 16, LE), FEEDMIXER_ENTRY(U, 24, LE), FEEDMIXER_ENTRY(U, 32, LE), FEEDMIXER_ENTRY(U, 16, BE), FEEDMIXER_ENTRY(U, 24, BE), FEEDMIXER_ENTRY(U, 32, BE), #endif { AFMT_AC3, PCM_16_BPS, NULL }, { AFMT_MU_LAW, PCM_8_BPS, feed_mixer_U8NE }, /* dummy */ { AFMT_A_LAW, PCM_8_BPS, feed_mixer_U8NE } /* dummy */ }; #define FEEDMIXER_TAB_SIZE ((int32_t) \ (sizeof(feed_mixer_info_tab) / \ sizeof(feed_mixer_info_tab[0]))) #define FEEDMIXER_DATA(i, c) ((void *) \ - ((uintptr_t)((((i) & 0x1f) << 5) | \ - ((c) & 0x1f)))) -#define FEEDMIXER_INFOIDX(d) ((uint32_t)((uintptr_t)(d) >> 5) & 0x1f) -#define FEEDMIXER_CHANNELS(d) ((uint32_t)((uintptr_t)(d)) & 0x1f) + ((uintptr_t)((((i) & 0x1f) << 7) | \ + ((c) & 0x7f)))) +#define FEEDMIXER_INFOIDX(d) ((uint32_t)((uintptr_t)(d) >> 7) & 0x1f) +#define FEEDMIXER_CHANNELS(d) ((uint32_t)((uintptr_t)(d)) & 0x7f) static int feed_mixer_init(struct pcm_feeder *f) { int i; if (f->desc->in != f->desc->out) return (EINVAL); for (i = 0; i < FEEDMIXER_TAB_SIZE; i++) { if (AFMT_ENCODING(f->desc->in) == feed_mixer_info_tab[i].format) { f->data = FEEDMIXER_DATA(i, AFMT_CHANNEL(f->desc->in)); return (0); } } return (EINVAL); } static int feed_mixer_set(struct pcm_feeder *f, int what, int value) { switch (what) { case FEEDMIXER_CHANNELS: if (value < SND_CHN_MIN || value > SND_CHN_MAX) return (EINVAL); f->data = FEEDMIXER_DATA(FEEDMIXER_INFOIDX(f->data), value); break; default: return (EINVAL); break; } return (0); } static __inline int feed_mixer_rec(struct pcm_channel *c) { struct pcm_channel *ch; struct snd_dbuf *b, *bs; uint32_t cnt, maxfeed; int rdy; /* * Reset ready and moving pointer. We're not using bufsoft * anywhere since its sole purpose is to become the primary * distributor for the recorded buffer and also as an interrupt * threshold progress indicator. */ b = c->bufsoft; b->rp = 0; b->rl = 0; cnt = sndbuf_getsize(b); maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(b)); do { cnt = FEEDER_FEED(c->feeder->source, c, b->tmpbuf, min(cnt, maxfeed), c->bufhard); if (cnt != 0) { sndbuf_acquire(b, b->tmpbuf, cnt); cnt = sndbuf_getfree(b); } } while (cnt != 0); /* Not enough data */ if (b->rl < sndbuf_getalign(b)) { b->rl = 0; return (0); } /* * Keep track of ready and moving pointer since we will use * bufsoft over and over again, pretending nothing has happened. */ rdy = b->rl; CHN_FOREACH(ch, c, children.busy) { CHN_LOCK(ch); if (CHN_STOPPED(ch) || (ch->flags & CHN_F_DIRTY)) { CHN_UNLOCK(ch); continue; } #ifdef SND_DEBUG if ((c->flags & CHN_F_DIRTY) && VCHAN_SYNC_REQUIRED(ch)) { if (vchan_sync(ch) != 0) { CHN_UNLOCK(ch); continue; } } #endif bs = ch->bufsoft; if (ch->flags & CHN_F_MMAP) sndbuf_dispose(bs, NULL, sndbuf_getready(bs)); cnt = sndbuf_getfree(bs); if (cnt < sndbuf_getalign(bs)) { CHN_UNLOCK(ch); continue; } maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(bs)); do { cnt = FEEDER_FEED(ch->feeder, ch, bs->tmpbuf, min(cnt, maxfeed), b); if (cnt != 0) { sndbuf_acquire(bs, bs->tmpbuf, cnt); cnt = sndbuf_getfree(bs); } } while (cnt != 0); /* * Not entirely flushed out... */ if (b->rl != 0) ch->xruns++; CHN_UNLOCK(ch); /* * Rewind buffer position for next virtual channel. */ b->rp = 0; b->rl = rdy; } /* * Set ready pointer to indicate that our children are ready * to be woken up, also as an interrupt threshold progress * indicator. */ b->rl = 1; c->flags &= ~CHN_F_DIRTY; /* * Return 0 to bail out early from sndbuf_feed() loop. * No need to increase feedcount counter since part of this * feeder chains already include feed_root(). */ return (0); } static int feed_mixer_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feed_mixer_info *info; struct snd_dbuf *src = source; struct pcm_channel *ch; uint32_t cnt, mcnt, rcnt, sz; int passthrough; uint8_t *tmp; if (c->direction == PCMDIR_REC) return (feed_mixer_rec(c)); sz = sndbuf_getsize(src); if (sz < count) count = sz; info = &feed_mixer_info_tab[FEEDMIXER_INFOIDX(f->data)]; sz = info->bps * FEEDMIXER_CHANNELS(f->data); count = SND_FXROUND(count, sz); if (count < sz) return (0); /* * We are going to use our source as a temporary buffer since it's * got no other purpose. We obtain our data by traversing the channel * list of children and calling mixer function to mix count bytes from * each into our destination buffer, b. */ tmp = sndbuf_getbuf(src); rcnt = 0; mcnt = 0; passthrough = 0; /* 'passthrough' / 'exclusive' marker */ CHN_FOREACH(ch, c, children.busy) { CHN_LOCK(ch); if (CHN_STOPPED(ch) || (ch->flags & CHN_F_DIRTY)) { CHN_UNLOCK(ch); continue; } #ifdef SND_DEBUG if ((c->flags & CHN_F_DIRTY) && VCHAN_SYNC_REQUIRED(ch)) { if (vchan_sync(ch) != 0) { CHN_UNLOCK(ch); continue; } } #endif if ((ch->flags & CHN_F_MMAP) && !(ch->flags & CHN_F_CLOSING)) sndbuf_acquire(ch->bufsoft, NULL, sndbuf_getfree(ch->bufsoft)); if (info->mix == NULL) { /* * Passthrough. Dump the first digital/passthrough * channel into destination buffer, and the rest into * nothingness (mute effect). */ if (passthrough == 0 && (ch->format & AFMT_PASSTHROUGH)) { rcnt = SND_FXROUND(FEEDER_FEED(ch->feeder, ch, b, count, ch->bufsoft), sz); passthrough = 1; } else FEEDER_FEED(ch->feeder, ch, tmp, count, ch->bufsoft); } else if (c->flags & CHN_F_EXCLUSIVE) { /* * Exclusive. Dump the first 'exclusive' channel into * destination buffer, and the rest into nothingness * (mute effect). */ if (passthrough == 0 && (ch->flags & CHN_F_EXCLUSIVE)) { rcnt = SND_FXROUND(FEEDER_FEED(ch->feeder, ch, b, count, ch->bufsoft), sz); passthrough = 1; } else FEEDER_FEED(ch->feeder, ch, tmp, count, ch->bufsoft); } else { if (rcnt == 0) { rcnt = SND_FXROUND(FEEDER_FEED(ch->feeder, ch, b, count, ch->bufsoft), sz); mcnt = count - rcnt; } else { cnt = SND_FXROUND(FEEDER_FEED(ch->feeder, ch, tmp, count, ch->bufsoft), sz); if (cnt != 0) { if (mcnt != 0) { memset(b + rcnt, sndbuf_zerodata( f->desc->out), mcnt); mcnt = 0; } info->mix(tmp, b, cnt); if (cnt > rcnt) rcnt = cnt; } } } CHN_UNLOCK(ch); } if (++c->feedcount == 0) c->feedcount = 2; c->flags &= ~CHN_F_DIRTY; return (rcnt); } static struct pcm_feederdesc feeder_mixer_desc[] = { { FEEDER_MIXER, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; static kobj_method_t feeder_mixer_methods[] = { KOBJMETHOD(feeder_init, feed_mixer_init), KOBJMETHOD(feeder_set, feed_mixer_set), KOBJMETHOD(feeder_feed, feed_mixer_feed), KOBJMETHOD_END }; FEEDER_DECLARE(feeder_mixer, NULL); Index: stable/8/sys/dev/sound/pcm =================================================================== --- stable/8/sys/dev/sound/pcm (revision 318980) +++ stable/8/sys/dev/sound/pcm (revision 318981) Property changes on: stable/8/sys/dev/sound/pcm ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev/sound/pcm:r318820 Index: stable/8/sys/dev/sound =================================================================== --- stable/8/sys/dev/sound (revision 318980) +++ stable/8/sys/dev/sound (revision 318981) Property changes on: stable/8/sys/dev/sound ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev/sound:r318820 Index: stable/8/sys/dev =================================================================== --- stable/8/sys/dev (revision 318980) +++ stable/8/sys/dev (revision 318981) Property changes on: stable/8/sys/dev ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev:r318820 Index: stable/8/sys/tools/sound/snd_fxdiv_gen.awk =================================================================== --- stable/8/sys/tools/sound/snd_fxdiv_gen.awk (revision 318980) +++ stable/8/sys/tools/sound/snd_fxdiv_gen.awk (revision 318981) @@ -1,142 +1,142 @@ #!/usr/bin/awk -f # # Copyright (c) 2008-2009 Ariff Abdullah # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # function floor(x, r) { r = int(x); if (r > x) r--; return (r + 0); } function shl(x, y) { while (y > 0) { x *= 2; y--; } return (x); } function shr(x, y) { while (y > 0 && x != 0) { x = floor(x / 2); y--; } return (x); } function calcdiv(r, x, y, z) { y = floor(FXONE / x); z = FXSHIFT; while (shr((y * x), z) < 1) y++; while ((y % 2) == 0 && z > 0) { y = floor(y / 2); z--; } r["mul"] = y; r["shift"] = z; } BEGIN { FXSHIFT = 16; FXONE = shl(1, FXSHIFT); - SND_CHN_MAX = 18; + SND_CHN_MAX = 127; PCM_8_BPS = 1; PCM_16_BPS = 2; PCM_24_BPS = 3; PCM_32_BPS = 4; SND_MAX_ALIGN = SND_CHN_MAX * PCM_32_BPS; for (i = 1; i <= SND_CHN_MAX; i++) { aligns[PCM_8_BPS * i] = 1; aligns[PCM_16_BPS * i] = 1; aligns[PCM_24_BPS * i] = 1; aligns[PCM_32_BPS * i] = 1; } printf("#ifndef _SND_FXDIV_GEN_H_\n"); printf("#define _SND_FXDIV_GEN_H_\n\n"); printf("/*\n"); printf(" * Generated using snd_fxdiv_gen.awk, heaven, wind and awesome.\n"); printf(" *\n"); printf(" * DO NOT EDIT!\n"); printf(" */\n\n"); printf("#ifdef SND_USE_FXDIV\n\n"); printf("/*\n"); printf(" * Fast unsigned 32bit integer division and rounding, accurate for\n"); printf(" * x = 1 - %d. This table should be enough to handle possible\n", FXONE); - printf(" * division for 1 - 72 (more can be generated though..).\n"); + printf(" * division for 1 - 508 (more can be generated though..).\n"); printf(" *\n"); - printf(" * 72 = SND_CHN_MAX * PCM_32_BPS, which is why....\n"); + printf(" * 508 = SND_CHN_MAX * PCM_32_BPS, which is why....\n"); printf(" */\n\n"); printf("static const uint32_t snd_fxdiv_table[][2] = {\n"); for (i = 1; i <= SND_MAX_ALIGN; i++) { if (aligns[i] != 1) continue; calcdiv(r, i); printf("\t[0x%02x] = { 0x%04x, 0x%02x },", \ i, r["mul"], r["shift"]); printf("\t/* x / %-2d = (x * %-5d) >> %-2d */\n", \ i, r["mul"], r["shift"]); } printf("};\n\n"); printf("#define SND_FXDIV_MAX\t\t0x%08x\n", FXONE); printf("#define SND_FXDIV(x, y)\t\t(((uint32_t)(x) *\t\t\t\\\n"); printf("\t\t\t\t snd_fxdiv_table[y][0]) >>\t\t\\\n"); printf("\t\t\t\t snd_fxdiv_table[y][1])\n"); printf("#define SND_FXROUND(x, y)\t(SND_FXDIV(x, y) * (y))\n"); printf("#define SND_FXMOD(x, y)\t\t((x) - SND_FXROUND(x, y))\n\n"); printf("#else\t/* !SND_USE_FXDIV */\n\n"); printf("#define SND_FXDIV_MAX\t\t0x%08x\n", 131072); printf("#define SND_FXDIV(x, y)\t\t((x) / (y))\n"); printf("#define SND_FXROUND(x, y)\t((x) - ((x) %% (y)))\n"); printf("#define SND_FXMOD(x, y)\t\t((x) %% (y))\n\n"); printf("#endif\t/* SND_USE_FXDIV */\n\n"); printf("#endif\t/* !_SND_FXDIV_GEN_H_ */\n"); } Index: stable/8/sys/tools =================================================================== --- stable/8/sys/tools (revision 318980) +++ stable/8/sys/tools (revision 318981) Property changes on: stable/8/sys/tools ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/tools:r318820 Index: stable/8/sys =================================================================== --- stable/8/sys (revision 318980) +++ stable/8/sys (revision 318981) Property changes on: stable/8/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r318820