summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm
diff options
context:
space:
mode:
authorariff <ariff@FreeBSD.org>2007-03-16 17:16:24 +0000
committerariff <ariff@FreeBSD.org>2007-03-16 17:16:24 +0000
commit6324ae1e6c8d879dcc47ce61b2aa50ff0c4e04ac (patch)
treeeed366144f91408c9db0f0dbc438ecec8c8f7d18 /sys/dev/sound/pcm
parentc6b6d0211332031fa7da49d63ef1b36207f06475 (diff)
downloadFreeBSD-src-6324ae1e6c8d879dcc47ce61b2aa50ff0c4e04ac.zip
FreeBSD-src-6324ae1e6c8d879dcc47ce61b2aa50ff0c4e04ac.tar.gz
[stage: 5/9]
channel.c/channel_if.m: - Macros cleanups, prefer inlined min() over MIN(). - Rework chn_read()/chn_write() for better dead interrupt detection policy. Reduce scheduling overhead by doing pure 5 seconds sleep before giving up, instead of several cycle of brute micro sleeping. - Avoid calling wakeup_one() for non-sleeping channel (for example, vchan parent channel). - EWOULDBLOCK -> EAGAIN. - Fix possible divide-by-zero panic on chn_sync(). - Re-enforce ^2 blocksize policy, since there are too many broken userland apps that blindly assume it without even trying to do serious calculations. - New channel method - CHANNEL_SETFRAGMENTS(), a refined version of CHANNEL_SETBLOCKSIZE(). It accept _both_ blocksize and blockcount arguments, so the driver internals will have better hints for buffering and timing calculations. - Hook FEEDER_SWAPLR into feederchain building process. feeder_fmt.c: - Unified version of various filters, avoiding duplications. - malloc()less feeder_fmt. Informations can be retrieved dynamically by doing table lookup on static data. For cases such as converting from stereo to mono or reducing bit depth where input data is larger than output, cycle remaining available free space until it has been exhausted and start kicking 8 bytes reservoir space from there to complete the remaining requested count. - Introduce FEEDER_SWAPLR. Few super broken hardwares (found on several extremely cheap uaudio stick, possibly others) mistakenly wired left and right channels wrongly, screwing output or input.
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r--sys/dev/sound/pcm/channel.c483
-rw-r--r--sys/dev/sound/pcm/channel_if.m13
-rw-r--r--sys/dev/sound/pcm/feeder_fmt.c1981
3 files changed, 1225 insertions, 1252 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index b3ac7ba4..d099e8b 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -39,13 +39,20 @@ SND_DECLARE_FILE("$FreeBSD$");
#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
#endif
-#define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
+#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)
+#define CHN_STOPPED(c) (!CHN_STARTED(c))
+#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \
+ "PCMDIR_PLAY" : "PCMDIR_REC")
#define BUF_PARENT(c, b) \
(((c) != NULL && (c)->parentchannel != NULL && \
(c)->parentchannel->bufhard != NULL) ? \
(c)->parentchannel->bufhard : (b))
+#define CHN_TIMEOUT 5
+#define CHN_TIMEOUT_MIN 1
+#define CHN_TIMEOUT_MAX 10
+
/*
#define DEB(x) x
*/
@@ -96,6 +103,40 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
"buffering latency profile (0=aggresive 1=safe)");
+static int chn_timeout = CHN_TIMEOUT;
+
+#ifdef SND_DEBUG
+static int
+sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
+{
+ int err, val;
+
+ val = chn_timeout;
+ err = sysctl_handle_int(oidp, &val, sizeof(val), req);
+ if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
+ err = EINVAL;
+ else
+ chn_timeout = val;
+
+ return err;
+}
+SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW,
+ 0, sizeof(int), sysctl_hw_snd_timeout, "I",
+ "interrupt timeout (1 - 10)");
+#endif
+
+static int chn_usefrags = 0;
+TUNABLE_INT("hw.snd.usefrags", &chn_usefrags);
+static int chn_syncdelay = -1;
+TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay);
+#ifdef SND_DEBUG
+SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW,
+ &chn_usefrags, 1, "prefer setfragments() over setblocksize()");
+SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW,
+ &chn_syncdelay, 1,
+ "append (0-1000) millisecond trailing buffer delay on each sync");
+#endif
+
/**
* @brief Channel sync group lock
*
@@ -193,6 +234,7 @@ chn_wakeup(struct pcm_channel *c)
if (SLIST_EMPTY(&c->children)) {
if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
selwakeuppri(sndbuf_getsel(bs), PRIBIO);
+ wakeup_one(bs);
} else {
SLIST_FOREACH(pce, &c->children, link) {
CHN_LOCK(pce->channel);
@@ -200,8 +242,6 @@ chn_wakeup(struct pcm_channel *c)
CHN_UNLOCK(pce->channel);
}
}
-
- wakeup_one(bs);
}
static int
@@ -247,22 +287,21 @@ chn_dmaupdate(struct pcm_channel *c)
);
if (c->direction == PCMDIR_PLAY) {
- amt = MIN(delta, sndbuf_getready(b));
+ amt = min(delta, sndbuf_getready(b));
amt -= amt % sndbuf_getbps(b);
if (amt > 0)
sndbuf_dispose(b, NULL, amt);
} else {
- amt = MIN(delta, sndbuf_getfree(b));
+ amt = min(delta, sndbuf_getfree(b));
amt -= amt % sndbuf_getbps(b);
if (amt > 0)
sndbuf_acquire(b, NULL, amt);
}
- if (snd_verbose > 2 && (c->flags & CHN_F_TRIGGERED) && delta == 0) {
- device_printf(c->dev, "WARNING: PCMDIR_%s DMA completion "
+ if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
+ device_printf(c->dev, "WARNING: %s DMA completion "
"too fast/slow ! hwptr=%u, old=%u "
"delta=%u amt=%u ready=%u free=%u\n",
- (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC",
- hwptr, old, delta, amt,
+ CHN_DIRSTR(c), hwptr, old, delta, amt,
sndbuf_getready(b), sndbuf_getfree(b));
}
@@ -277,7 +316,7 @@ chn_wrupdate(struct pcm_channel *c)
CHN_LOCKASSERT(c);
KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
- if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
+ if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
return;
chn_dmaupdate(c);
ret = chn_wrfeed(c);
@@ -321,8 +360,11 @@ chn_wrfeed(struct pcm_channel *c)
if (sndbuf_getfree(b) > 0)
c->xruns++;
+#if 0
if (ret == 0 && sndbuf_getfree(b) < amt)
chn_wakeup(c);
+#endif
+ chn_wakeup(c);
return ret;
}
@@ -353,76 +395,59 @@ chn_wrintr(struct pcm_channel *c)
int
chn_write(struct pcm_channel *c, struct uio *buf)
{
- int ret, count, sz;
struct snd_dbuf *bs = c->bufsoft;
void *off;
- int t, x, togo, p;
+ int ret, timeout, sz, t, p;
CHN_LOCKASSERT(c);
ret = 0;
- count = hz;
-
- while (!ret && (buf->uio_resid > 0) && (count > 0)) {
- sz = sndbuf_getfree(bs);
- if (sz == 0) {
- if (c->flags & CHN_F_NBIO)
- ret = EWOULDBLOCK;
- else if (c->flags & CHN_F_NOTRIGGER) {
- /**
- * @todo Evaluate whether EAGAIN is truly desirable.
- * 4Front drivers behave like this, but I'm
- * not sure if it at all violates the "write
- * should be allowed to block" model.
- *
- * The idea is that, while set with CHN_F_NOTRIGGER,
- * a channel isn't playing, *but* without this we
- * end up with "interrupt timeout / channel dead".
- */
- ret = EAGAIN;
- } else {
- ret = chn_sleep(c, "pcmwr", c->timeout);
- if (ret == EWOULDBLOCK) {
- count -= c->timeout;
- ret = 0;
- } else if (ret == ERESTART || ret == EINTR) {
- c->flags |= CHN_F_ABORTING;
- return ret;
- } else if (ret == 0)
- count = hz;
- }
- } else {
- sz = MIN(sz, buf->uio_resid);
- KASSERT(sz > 0, ("confusion in chn_write"));
- /* printf("sz: %d\n", sz); */
+ timeout = chn_timeout * hz;
+ while (ret == 0 && buf->uio_resid > 0) {
+ sz = min(buf->uio_resid, sndbuf_getfree(bs));
+ if (sz > 0) {
/*
* The following assumes that the free space in
* the buffer can never be less around the
* unlock-uiomove-lock sequence.
*/
- togo = sz;
- while (ret == 0 && togo > 0) {
+ while (ret == 0 && sz > 0) {
p = sndbuf_getfreeptr(bs);
- t = MIN(togo, sndbuf_getsize(bs) - p);
+ t = min(sz, sndbuf_getsize(bs) - p);
off = sndbuf_getbufofs(bs, p);
CHN_UNLOCK(c);
ret = uiomove(off, t, buf);
CHN_LOCK(c);
- togo -= t;
- x = sndbuf_acquire(bs, NULL, t);
+ sz -= t;
+ sndbuf_acquire(bs, NULL, t);
}
ret = 0;
- if (!(c->flags & CHN_F_TRIGGERED))
+ if (CHN_STOPPED(c))
chn_start(c, 0);
+ } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
+ /**
+ * @todo Evaluate whether EAGAIN is truly desirable.
+ * 4Front drivers behave like this, but I'm
+ * not sure if it at all violates the "write
+ * should be allowed to block" model.
+ *
+ * The idea is that, while set with CHN_F_NOTRIGGER,
+ * a channel isn't playing, *but* without this we
+ * end up with "interrupt timeout / channel dead".
+ */
+ ret = EAGAIN;
+ } else {
+ ret = chn_sleep(c, "pcmwr", timeout);
+ if (ret == EAGAIN) {
+ ret = EINVAL;
+ c->flags |= CHN_F_DEAD;
+ printf("%s: play interrupt timeout, "
+ "channel dead\n", c->name);
+ } else if (ret == ERESTART || ret == EINTR)
+ c->flags |= CHN_F_ABORTING;
}
}
- /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
-
- if (count <= 0) {
- c->flags |= CHN_F_DEAD;
- printf("%s: play interrupt timeout, channel dead\n", c->name);
- }
return ret;
}
@@ -490,7 +515,7 @@ chn_rdupdate(struct pcm_channel *c)
CHN_LOCKASSERT(c);
KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
- if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
+ if ((c->flags & CHN_F_MAPPED) || CHN_STOPPED(c))
return;
chn_trigger(c, PCMTRIG_EMLDMARD);
chn_dmaupdate(c);
@@ -525,60 +550,51 @@ chn_rdintr(struct pcm_channel *c)
int
chn_read(struct pcm_channel *c, struct uio *buf)
{
- int ret, sz, count;
struct snd_dbuf *bs = c->bufsoft;
void *off;
- int t, x, togo, p;
+ int ret, timeout, sz, t, p;
CHN_LOCKASSERT(c);
- if (!(c->flags & CHN_F_TRIGGERED))
+
+ if (CHN_STOPPED(c))
chn_start(c, 0);
ret = 0;
- count = hz;
- while (!ret && (buf->uio_resid > 0) && (count > 0)) {
- sz = MIN(buf->uio_resid, sndbuf_getready(bs));
+ timeout = chn_timeout * hz;
+ while (ret == 0 && buf->uio_resid > 0) {
+ sz = min(buf->uio_resid, sndbuf_getready(bs));
if (sz > 0) {
/*
* The following assumes that the free space in
* the buffer can never be less around the
* unlock-uiomove-lock sequence.
*/
- togo = sz;
- while (ret == 0 && togo > 0) {
+ while (ret == 0 && sz > 0) {
p = sndbuf_getreadyptr(bs);
- t = MIN(togo, sndbuf_getsize(bs) - p);
+ t = min(sz, sndbuf_getsize(bs) - p);
off = sndbuf_getbufofs(bs, p);
CHN_UNLOCK(c);
ret = uiomove(off, t, buf);
CHN_LOCK(c);
- togo -= t;
- x = sndbuf_dispose(bs, NULL, t);
+ sz -= t;
+ sndbuf_dispose(bs, NULL, t);
}
ret = 0;
- } else {
- if (c->flags & CHN_F_NBIO)
- ret = EWOULDBLOCK;
- else {
- ret = chn_sleep(c, "pcmrd", c->timeout);
- if (ret == EWOULDBLOCK) {
- count -= c->timeout;
- ret = 0;
- } else if (ret == ERESTART || ret == EINTR) {
- c->flags |= CHN_F_ABORTING;
- return ret;
- } else
- count = hz;
- }
+ } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
+ ret = EAGAIN;
+ else {
+ ret = chn_sleep(c, "pcmrd", timeout);
+ if (ret == EAGAIN) {
+ ret = EINVAL;
+ c->flags |= CHN_F_DEAD;
+ printf("%s: record interrupt timeout, "
+ "channel dead\n", c->name);
+ } else if (ret == ERESTART || ret == EINTR)
+ c->flags |= CHN_F_ABORTING;
}
}
- if (count <= 0) {
- c->flags |= CHN_F_DEAD;
- printf("%s: record interrupt timeout, channel dead\n", c->name);
- }
-
return ret;
}
@@ -603,7 +619,7 @@ chn_start(struct pcm_channel *c, int force)
CHN_LOCKASSERT(c);
/* if we're running, or if we're prevented from triggering, bail */
- if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
+ if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
return EINVAL;
if (force) {
@@ -612,20 +628,22 @@ chn_start(struct pcm_channel *c, int force)
} else {
if (c->direction == PCMDIR_REC) {
i = sndbuf_getfree(bs);
- j = sndbuf_getready(b);
+ j = (i > 0) ? 1 : sndbuf_getready(b);
} else {
- struct snd_dbuf *pb;
-
- i = sndbuf_getready(bs);
+ if (sndbuf_getfree(bs) == 0) {
+ i = 1;
+ j = 0;
+ } else {
+ struct snd_dbuf *pb;
- pb = BUF_PARENT(c, b);
- j = min(sndbuf_xbytes(sndbuf_getsize(pb), pb, bs),
- sndbuf_getsize(bs));
+ pb = BUF_PARENT(c, b);
+ i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
+ j = sndbuf_getbps(pb);
+ }
}
if (snd_verbose > 3 && SLIST_EMPTY(&c->children))
- printf("%s: PCMDIR_%s (%s) threshold i=%d j=%d\n",
- __func__,
- (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC",
+ printf("%s: %s (%s) threshold i=%d j=%d\n",
+ __func__, CHN_DIRSTR(c),
(c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
i, j);
}
@@ -637,17 +655,20 @@ chn_start(struct pcm_channel *c, int force)
c->interrupts = 0;
c->xruns = 0;
if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
- chn_wrfeed(c);
+ sndbuf_fillsilence(b);
if (snd_verbose > 3)
printf("%s: %s starting! (%s) (ready=%d "
- "force=%d i=%d j=%d intrtimeout=%u)\n",
+ "force=%d i=%d j=%d intrtimeout=%u "
+ "latency=%dms)\n",
__func__,
(c->flags & CHN_F_HAS_VCHAN) ?
"VCHAN" : "HW",
(c->flags & CHN_F_CLOSING) ? "closing" :
"running",
sndbuf_getready(b),
- force, i, j, c->timeout);
+ force, i, j, c->timeout,
+ (sndbuf_getsize(b) * 1000) /
+ (sndbuf_getbps(b) * sndbuf_getspd(b)));
}
chn_trigger(c, PCMTRIG_START);
return 0;
@@ -677,20 +698,22 @@ chn_sync(struct pcm_channel *c, int threshold)
{
int ret, count, hcount, minflush, resid, residp;
struct snd_dbuf *b, *bs;
+ int syncdelay, blksz;
CHN_LOCKASSERT(c);
- if (c->flags & (CHN_F_DEAD | CHN_F_ABORTING))
+ bs = c->bufsoft;
+
+ if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
+ (threshold < 1 && sndbuf_getready(bs) < 1))
return 0;
if (c->direction != PCMDIR_PLAY)
return EINVAL;
- bs = c->bufsoft;
-
/* if we haven't yet started and nothing is buffered, else start*/
- if (!(c->flags & CHN_F_TRIGGERED)) {
- if (sndbuf_getready(bs) > 0) {
+ if (CHN_STOPPED(c)) {
+ if (threshold > 0 || sndbuf_getready(bs) > 0) {
ret = chn_start(c, 1);
if (ret)
return ret;
@@ -700,8 +723,22 @@ chn_sync(struct pcm_channel *c, int threshold)
b = BUF_PARENT(c, c->bufhard);
- threshold += sndbuf_getready(b);
- minflush = sndbuf_xbytes(threshold, b, bs);
+ minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
+
+ syncdelay = chn_syncdelay;
+
+ if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
+ minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
+
+ /*
+ * Append (0-1000) millisecond trailing buffer (if needed)
+ * for slower / high latency hardwares (notably USB audio)
+ * to avoid audible truncation.
+ */
+ if (syncdelay > 0)
+ minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) *
+ ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
+
minflush -= minflush % sndbuf_getbps(bs);
if (minflush > 0) {
@@ -713,17 +750,32 @@ chn_sync(struct pcm_channel *c, int threshold)
resid = sndbuf_getready(bs);
residp = resid;
- count = sndbuf_xbytes(minflush + resid, bs, b) / sndbuf_getblksz(b);
+ blksz = sndbuf_getblksz(b);
+ if (blksz < 1) {
+ printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
+ __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
+ sndbuf_getblksz(b), sndbuf_getblkcnt(b));
+ if (sndbuf_getblkcnt(b) > 0)
+ blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
+ if (blksz < 1)
+ blksz = 1;
+ }
+ count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
hcount = count;
ret = 0;
- while (count > 0 && resid > 0) {
+ if (snd_verbose > 3)
+ printf("%s: [begin] timeout=%d count=%d "
+ "minflush=%d resid=%d\n", __func__, c->timeout, count,
+ minflush, resid);
+
+ while (count > 0 && (resid > 0 || minflush > 0)) {
ret = chn_sleep(c, "pcmsyn", c->timeout);
if (ret == ERESTART || ret == EINTR) {
c->flags |= CHN_F_ABORTING;
break;
}
- if (ret == 0 || ret == EWOULDBLOCK) {
+ if (ret == 0 || ret == EAGAIN) {
resid = sndbuf_getready(bs);
if (resid == residp) {
--count;
@@ -771,7 +823,7 @@ chn_poll(struct pcm_channel *c, int ev, struct thread *td)
int ret;
CHN_LOCKASSERT(c);
- if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
+ if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)))
chn_start(c, 1);
ret = 0;
if (chn_polltrigger(c) && chn_pollreset(c))
@@ -795,7 +847,7 @@ chn_abort(struct pcm_channel *c)
struct snd_dbuf *bs = c->bufsoft;
CHN_LOCKASSERT(c);
- if (!(c->flags & CHN_F_TRIGGERED))
+ if (CHN_STOPPED(c))
return 0;
c->flags |= CHN_F_ABORTING;
@@ -805,7 +857,7 @@ chn_abort(struct pcm_channel *c)
sndbuf_setrun(b, 0);
if (!(c->flags & CHN_F_VIRTUAL))
chn_dmaupdate(c);
- missing = sndbuf_getready(bs) + sndbuf_getready(b);
+ missing = sndbuf_getready(bs);
c->flags &= ~CHN_F_ABORTING;
return missing;
@@ -1130,7 +1182,7 @@ chn_kill(struct pcm_channel *c)
struct snd_dbuf *b = c->bufhard;
struct snd_dbuf *bs = c->bufsoft;
- if (c->flags & CHN_F_TRIGGERED)
+ if (CHN_STARTED(c))
chn_trigger(c, PCMTRIG_ABORT);
while (chn_removefeeder(c) == 0);
if (CHANNEL_FREE(c->methods, c->devinfo))
@@ -1193,6 +1245,28 @@ round_pow2(u_int32_t v)
return ret;
}
+static u_int32_t
+round_blksz(u_int32_t v, int round)
+{
+ u_int32_t ret, tmp;
+
+ if (round < 1)
+ round = 1;
+
+ ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
+
+ if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
+ ret >>= 1;
+
+ tmp = ret - (ret % round);
+ while (tmp < 16 || tmp < round) {
+ ret <<= 1;
+ tmp = ret - (ret % round);
+ }
+
+ return ret;
+}
+
/*
* 4Front call it DSP Policy, while we call it "Latency Profile". The idea
* is to keep 2nd buffer short so that it doesn't cause long queue during
@@ -1285,19 +1359,18 @@ static int
chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
u_int32_t max, int *rblksz, int *rblkcnt)
{
- u_int32_t bufsz;
- int blksz, blkcnt;
- static int pblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
+ static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
CHN_LATENCY_PBLKCNT_REF;
- static int pbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
+ static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
CHN_LATENCY_PBUFSZ_REF;
- static int rblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
+ static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
CHN_LATENCY_RBLKCNT_REF;
- static int rbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
+ static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
CHN_LATENCY_RBUFSZ_REF;
+ u_int32_t bufsz;
+ int lprofile, blksz, blkcnt;
- if (CHN_LATENCY_MIN != 0 || CHN_LATENCY_MAX != 10 ||
- latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
+ if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
bps < 1 || datarate < 1 ||
!(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
if (rblksz != NULL)
@@ -1310,24 +1383,22 @@ chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
return CHN_2NDBUFMAXSIZE;
}
+ lprofile = chn_latency_profile;
+
if (dir == PCMDIR_PLAY) {
- blkcnt = pblkcnts[chn_latency_profile][latency];
- bufsz = pbufszs[chn_latency_profile][latency];
+ blkcnt = pblkcnts[lprofile][latency];
+ bufsz = pbufszs[lprofile][latency];
} else {
- blkcnt = rblkcnts[chn_latency_profile][latency];
- bufsz = rbufszs[chn_latency_profile][latency];
+ blkcnt = rblkcnts[lprofile][latency];
+ bufsz = rbufszs[lprofile][latency];
}
- bufsz = snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF, datarate);
+
+ bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
+ datarate));
if (bufsz > max)
bufsz = max;
- if (bufsz < 32)
- bufsz = 32;
- blksz = bufsz >> blkcnt;
- blksz -= blksz % bps;
- while (blksz < 16 || blksz < bps)
- blksz += bps;
- while ((blksz << blkcnt) > bufsz && blkcnt > 1)
- blkcnt--;
+ blksz = round_blksz(bufsz >> blkcnt, bps);
+
if (rblksz != NULL)
*rblksz = blksz;
if (rblkcnt != NULL)
@@ -1336,22 +1407,17 @@ chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
return blksz << blkcnt;
}
-/*
- * Note that there is no strict requirement to align blksz to the
- * nearest ^2, except for hardware CHANNEL_SETBLOCKSIZE. If the application
- * trying to act smarter and requesting for specific blksz/blkcnt, so be it.
- */
static int
chn_resizebuf(struct pcm_channel *c, int latency,
int blkcnt, int blksz)
{
struct snd_dbuf *b, *bs, *pb;
- int sblksz, sblkcnt, hblksz, limit = 1;
+ int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1;
int ret;
CHN_LOCKASSERT(c);
- if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED) ||
+ if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) ||
!(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
return EINVAL;
@@ -1399,14 +1465,8 @@ chn_resizebuf(struct pcm_channel *c, int latency,
* defeat the purpose of having custom control. The least
* we can do is round it to the nearest ^2 and align it.
*/
- sblksz = round_pow2(blksz);
- sblksz -= sblksz % sndbuf_getbps(bs);
- sblkcnt = blkcnt;
- while (sblksz < 16 || sblksz < sndbuf_getbps(bs))
- sblksz += sndbuf_getbps(bs);
- if (snd_verbose > 3 && !(blksz == 0 || blkcnt == -1))
- printf("%s: requested blksz=%d blkcnt=%d -> %d/%d\n",
- __func__, blksz, blkcnt, sblksz, sblkcnt);
+ sblksz = round_blksz(blksz, sndbuf_getbps(bs));
+ sblkcnt = round_pow2(blkcnt);
limit = 0;
}
@@ -1419,39 +1479,48 @@ chn_resizebuf(struct pcm_channel *c, int latency,
sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
c->timeout = c->parentchannel->timeout;
} else {
+ hblkcnt = 2;
if (c->flags & CHN_F_HAS_SIZE) {
- hblksz = sndbuf_xbytes(sblksz, bs, b);
- if (snd_verbose > 3)
- printf("%s: sblksz=%d -> hblksz=%d\n",
- __func__, sblksz, hblksz);
+ hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
+ sndbuf_getbps(b));
+ hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
} else
chn_calclatency(c->direction, latency,
sndbuf_getbps(b),
sndbuf_getbps(b) * sndbuf_getspd(b),
- CHN_2NDBUFMAXSIZE, &hblksz, NULL);
+ CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
- hblksz = round_pow2(hblksz);
if ((hblksz << 1) > sndbuf_getmaxsize(b))
- hblksz = sndbuf_getmaxsize(b) >> 1;
+ hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
+ sndbuf_getbps(b));
+
+ while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
+ if (hblkcnt < 4)
+ hblksz >>= 1;
+ else
+ hblkcnt >>= 1;
+ }
+
hblksz -= hblksz % sndbuf_getbps(b);
- while (hblksz < 16 || hblksz < sndbuf_getbps(b))
- hblksz += sndbuf_getbps(b);
#if 0
hblksz = sndbuf_getmaxsize(b) >> 1;
+ hblksz -= hblksz % sndbuf_getbps(b);
+ hblkcnt = 2;
#endif
+
CHN_UNLOCK(c);
- sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
- c->devinfo, hblksz));
+ if (chn_usefrags == 0 ||
+ CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
+ hblksz, hblkcnt) < 1)
+ sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
+ c->devinfo, hblksz));
CHN_LOCK(c);
if (!SLIST_EMPTY(&c->children)) {
- /*
- * Virtual channels underneath. Set the biggest
- * possible value for their mixing space.
- */
- sblksz = CHN_2NDBUFMAXSIZE >> 1;
- sblksz -= sblksz % sndbuf_getbps(bs);
+ sblksz = round_blksz(
+ sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
+ sndbuf_getbps(bs));
sblkcnt = 2;
limit = 0;
} else if (limit != 0)
@@ -1460,24 +1529,34 @@ chn_resizebuf(struct pcm_channel *c, int latency,
/*
* Interrupt timeout
*/
- c->timeout = ((u_int64_t)hz * sndbuf_getblksz(b)) /
+ c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) /
((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
if (c->timeout < 1)
c->timeout = 1;
- c->timeout <<= 1;
}
if (limit > CHN_2NDBUFMAXSIZE)
limit = CHN_2NDBUFMAXSIZE;
- hblksz = sblksz;
- while ((sblksz * sblkcnt) < limit) {
- sblksz += hblksz;
- if ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
- sblksz -= hblksz;
+#if 0
+ while (limit > 0 && (sblksz * sblkcnt) > limit) {
+ if (sblkcnt < 4)
break;
- }
+ sblkcnt >>= 1;
}
+#endif
+
+ while ((sblksz * sblkcnt) < limit)
+ sblkcnt <<= 1;
+
+ while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
+ if (sblkcnt < 4)
+ sblksz >>= 1;
+ else
+ sblkcnt >>= 1;
+ }
+
+ sblksz -= sblksz % sndbuf_getbps(bs);
if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
@@ -1497,9 +1576,9 @@ chn_resizebuf(struct pcm_channel *c, int latency,
chn_resetbuf(c);
if (snd_verbose > 3)
- printf("%s: PCMDIR_%s (%s) timeout=%u "
+ printf("%s: %s (%s) timeout=%u "
"b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
- __func__, (c->direction == PCMDIR_REC) ? "REC" : "PLAY",
+ __func__, CHN_DIRSTR(c),
(c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
c->timeout,
sndbuf_getsize(b), sndbuf_getblksz(b),
@@ -1540,7 +1619,7 @@ chn_tryspeed(struct pcm_channel *c, int speed)
DEB(printf("want speed %d, ", speed));
if (speed <= 0)
return EINVAL;
- if (CANCHANGE(c)) {
+ if (CHN_STOPPED(c)) {
r = 0;
c->speed = speed;
sndbuf_setspd(bs, speed);
@@ -1622,7 +1701,7 @@ chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
int r;
CHN_LOCKASSERT(c);
- if (CANCHANGE(c)) {
+ if (CHN_STOPPED(c)) {
DEB(printf("want format %d\n", fmt));
c->format = fmt;
r = chn_buildfeeder(c);
@@ -1702,7 +1781,7 @@ chn_getptr(struct pcm_channel *c)
int hwptr;
CHN_LOCKASSERT(c);
- hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
+ hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
}
@@ -1744,7 +1823,8 @@ chn_buildfeeder(struct pcm_channel *c)
char fmtstr[AFMTSTR_MAXSZ];
CHN_LOCKASSERT(c);
- while (chn_removefeeder(c) == 0);
+ while (chn_removefeeder(c) == 0)
+ ;
KASSERT((c->feeder == NULL), ("feeder chain not empty"));
c->align = sndbuf_getalign(c->bufsoft);
@@ -1786,10 +1866,16 @@ chn_buildfeeder(struct pcm_channel *c)
}
c->feederflags &= ~(1 << FEEDER_VOLUME);
if (c->direction == PCMDIR_PLAY &&
- !(c->flags & CHN_F_VIRTUAL) &&
- c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
- c->parentsnddev->mixer_dev)
+ !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
+ (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
+ c->parentsnddev->mixer_dev)
c->feederflags |= 1 << FEEDER_VOLUME;
+ if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
+ ((c->direction == PCMDIR_PLAY &&
+ (c->parentsnddev->flags & SD_F_PSWAPLR)) ||
+ (c->direction == PCMDIR_REC &&
+ (c->parentsnddev->flags & SD_F_RSWAPLR))))
+ c->feederflags |= 1 << FEEDER_SWAPLR;
flags = c->feederflags;
fmtlist = chn_getcaps(c)->fmtlist;
@@ -1830,14 +1916,13 @@ chn_buildfeeder(struct pcm_channel *c)
c->feeder->desc->out & AFMT_STEREO)
desc.in |= AFMT_STEREO;
desc.out = desc.in;
- fc = feeder_getclass(&desc);
- if (fc != NULL && fc->desc != NULL)
- desc.flags = fc->desc->flags;
- } else {
- fc = feeder_getclass(&desc);
- if (fc != NULL && fc->desc != NULL)
- desc = *fc->desc;
+ } else if (type == FEEDER_SWAPLR) {
+ desc.in = c->feeder->desc->out;
+ desc.in |= AFMT_STEREO;
+ desc.out = desc.in;
}
+
+ fc = feeder_getclass(&desc);
DEB(printf("got %p\n", fc));
if (fc == NULL) {
DEB(printf("can't find required feeder type %d\n", type));
@@ -1845,6 +1930,9 @@ chn_buildfeeder(struct pcm_channel *c)
return EOPNOTSUPP;
}
+ if (desc.in == 0 || desc.out == 0)
+ desc = *fc->desc;
+
DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
tmp[0] = desc.in;
tmp[1] = 0;
@@ -1932,7 +2020,7 @@ chn_notify(struct pcm_channel *c, u_int32_t flags)
return ENODEV;
}
- run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
+ run = (CHN_STARTED(c)) ? 1 : 0;
/*
* if the hwchan is running, we can't change its rate, format or
* blocksize
@@ -1974,9 +2062,10 @@ chn_notify(struct pcm_channel *c, u_int32_t flags)
SLIST_FOREACH(pce, &c->children, link) {
child = pce->channel;
CHN_LOCK(child);
- if (child->flags & CHN_F_TRIGGERED)
- nrun = 1;
+ nrun = CHN_STARTED(child);
CHN_UNLOCK(child);
+ if (nrun)
+ break;
}
if (nrun && !run)
chn_start(c, 1);
diff --git a/sys/dev/sound/pcm/channel_if.m b/sys/dev/sound/pcm/channel_if.m
index d0c07c3..3429a33 100644
--- a/sys/dev/sound/pcm/channel_if.m
+++ b/sys/dev/sound/pcm/channel_if.m
@@ -83,6 +83,12 @@ CODE {
return 0;
}
+ static int
+ channel_nosetfragments(kobj_t obj, void *data, u_int32_t blocksize, u_int32_t blockcount)
+ {
+ return 0;
+ }
+
};
METHOD void* init {
@@ -132,6 +138,13 @@ METHOD u_int32_t setblocksize {
u_int32_t blocksize;
};
+METHOD int setfragments {
+ kobj_t obj;
+ void *data;
+ u_int32_t blocksize;
+ u_int32_t blockcount;
+} DEFAULT channel_nosetfragments;
+
METHOD int trigger {
kobj_t obj;
void *data;
diff --git a/sys/dev/sound/pcm/feeder_fmt.c b/sys/dev/sound/pcm/feeder_fmt.c
index 0ccc7b9..8698178 100644
--- a/sys/dev/sound/pcm/feeder_fmt.c
+++ b/sys/dev/sound/pcm/feeder_fmt.c
@@ -41,87 +41,83 @@
SND_DECLARE_FILE("$FreeBSD$");
-MALLOC_DEFINE(M_FMTFEEDER, "fmtfeed", "pcm format feeder");
-
-#define FMT_TRACE(x...) /* printf(x) */
-#define FMT_TEST(x, y...) /* if (x) FMT_TRACE(y) */
-
-struct feed_fmt_info {
- int bps, bufsz;
- uint8_t *buffer;
+static int feeder_fmt_stereodownmix = 0;
+TUNABLE_INT("hw.snd.feeder_fmt_stereodownmix", &feeder_fmt_stereodownmix);
+#ifdef SND_DEBUG
+SYSCTL_INT(_hw_snd, OID_AUTO, feeder_fmt_stereodownmix, CTLFLAG_RW,
+ &feeder_fmt_stereodownmix, 1, "averaging stereo downmix");
+#endif
+
+#define FEEDFMT_RESERVOIR 8 /* 32bit stereo */
+
+static uint8_t ulaw_to_u8_tbl[] = {
+ 3, 7, 11, 15, 19, 23, 27, 31,
+ 35, 39, 43, 47, 51, 55, 59, 63,
+ 66, 68, 70, 72, 74, 76, 78, 80,
+ 82, 84, 86, 88, 90, 92, 94, 96,
+ 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113,
+ 113, 114, 114, 115, 115, 116, 116, 117,
+ 117, 118, 118, 119, 119, 120, 120, 121,
+ 121, 121, 122, 122, 122, 122, 123, 123,
+ 123, 123, 124, 124, 124, 124, 125, 125,
+ 125, 125, 125, 125, 126, 126, 126, 126,
+ 126, 126, 126, 126, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 253, 249, 245, 241, 237, 233, 229, 225,
+ 221, 217, 213, 209, 205, 201, 197, 193,
+ 190, 188, 186, 184, 182, 180, 178, 176,
+ 174, 172, 170, 168, 166, 164, 162, 160,
+ 158, 157, 156, 155, 154, 153, 152, 151,
+ 150, 149, 148, 147, 146, 145, 144, 143,
+ 143, 142, 142, 141, 141, 140, 140, 139,
+ 139, 138, 138, 137, 137, 136, 136, 135,
+ 135, 135, 134, 134, 134, 134, 133, 133,
+ 133, 133, 132, 132, 132, 132, 131, 131,
+ 131, 131, 131, 131, 130, 130, 130, 130,
+ 130, 130, 130, 130, 129, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 129, 129,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
};
-/*
- * Sign inverted ulaw/alaw -> 8 table
- */
-static uint8_t ulaw_to_s8_tbl[] = {
- 131, 135, 139, 143, 147, 151, 155, 159,
- 163, 167, 171, 175, 179, 183, 187, 191,
- 194, 196, 198, 200, 202, 204, 206, 208,
- 210, 212, 214, 216, 218, 220, 222, 224,
- 226, 227, 228, 229, 230, 231, 232, 233,
- 234, 235, 236, 237, 238, 239, 240, 241,
- 241, 242, 242, 243, 243, 244, 244, 245,
- 245, 246, 246, 247, 247, 248, 248, 249,
- 249, 249, 250, 250, 250, 250, 251, 251,
- 251, 251, 252, 252, 252, 252, 253, 253,
- 253, 253, 253, 253, 254, 254, 254, 254,
- 254, 254, 254, 254, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 125, 121, 117, 113, 109, 105, 101, 97,
- 93, 89, 85, 81, 77, 73, 69, 65,
- 62, 60, 58, 56, 54, 52, 50, 48,
- 46, 44, 42, 40, 38, 36, 34, 32,
- 30, 29, 28, 27, 26, 25, 24, 23,
- 22, 21, 20, 19, 18, 17, 16, 15,
- 15, 14, 14, 13, 13, 12, 12, 11,
- 11, 10, 10, 9, 9, 8, 8, 7,
- 7, 7, 6, 6, 6, 6, 5, 5,
- 5, 5, 4, 4, 4, 4, 3, 3,
- 3, 3, 3, 3, 2, 2, 2, 2,
- 2, 2, 2, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static uint8_t alaw_to_s8_tbl[] = {
- 236, 237, 234, 235, 240, 241, 238, 239,
- 228, 229, 226, 227, 232, 233, 230, 231,
- 246, 246, 245, 245, 248, 248, 247, 247,
- 242, 242, 241, 241, 244, 244, 243, 243,
- 171, 175, 163, 167, 187, 191, 179, 183,
- 139, 143, 131, 135, 155, 159, 147, 151,
- 214, 216, 210, 212, 222, 224, 218, 220,
- 198, 200, 194, 196, 206, 208, 202, 204,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 251, 251, 251, 251, 252, 252, 252, 252,
- 249, 249, 249, 249, 250, 250, 250, 250,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 253, 253, 253, 253, 253, 253, 253, 253,
- 20, 19, 22, 21, 16, 15, 18, 17,
- 28, 27, 30, 29, 24, 23, 26, 25,
- 10, 10, 11, 11, 8, 8, 9, 9,
- 14, 14, 15, 15, 12, 12, 13, 13,
- 85, 81, 93, 89, 69, 65, 77, 73,
- 117, 113, 125, 121, 101, 97, 109, 105,
- 42, 40, 46, 44, 34, 32, 38, 36,
- 58, 56, 62, 60, 50, 48, 54, 52,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 5, 5, 5, 4, 4, 4, 4,
- 7, 7, 7, 7, 6, 6, 6, 6,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3,
+static uint8_t alaw_to_u8_tbl[] = {
+ 108, 109, 106, 107, 112, 113, 110, 111,
+ 100, 101, 98, 99, 104, 105, 102, 103,
+ 118, 118, 117, 117, 120, 120, 119, 119,
+ 114, 114, 113, 113, 116, 116, 115, 115,
+ 43, 47, 35, 39, 59, 63, 51, 55,
+ 11, 15, 3, 7, 27, 31, 19, 23,
+ 86, 88, 82, 84, 94, 96, 90, 92,
+ 70, 72, 66, 68, 78, 80, 74, 76,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 123, 123, 123, 123, 124, 124, 124, 124,
+ 121, 121, 121, 121, 122, 122, 122, 122,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 125, 125, 125, 125, 125, 125, 125, 125,
+ 148, 147, 150, 149, 144, 143, 146, 145,
+ 156, 155, 158, 157, 152, 151, 154, 153,
+ 138, 138, 139, 139, 136, 136, 137, 137,
+ 142, 142, 143, 143, 140, 140, 141, 141,
+ 213, 209, 221, 217, 197, 193, 205, 201,
+ 245, 241, 253, 249, 229, 225, 237, 233,
+ 170, 168, 174, 172, 162, 160, 166, 164,
+ 186, 184, 190, 188, 178, 176, 182, 180,
+ 129, 129, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 129, 129,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 133, 133, 133, 133, 132, 132, 132, 132,
+ 135, 135, 135, 135, 134, 134, 134, 134,
+ 130, 130, 130, 130, 130, 130, 130, 130,
+ 131, 131, 131, 131, 131, 131, 131, 131,
};
static uint8_t u8_to_ulaw_tbl[] = {
@@ -200,17 +196,23 @@ feed_table_8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
{
int j, sign, k;
uint8_t *tbl = (uint8_t *)f->data;
-
- if (count < 1)
- return 0;
+
+ if (count < PCM_8_BPS)
+ return (0);
+
k = FEEDER_FEED(f->source, c, b, count, source);
+ if (k < PCM_8_BPS)
+ return (0);
+
j = k;
- sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80;
- while (j > 0) {
+ sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00;
+
+ do {
j--;
b[j] = tbl[b[j]] ^ sign;
- }
- return k;
+ } while (j != 0);
+
+ return (k);
}
static int
@@ -219,26 +221,32 @@ feed_table_16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
{
int i, j, sign, k;
uint8_t *tbl = (uint8_t *)f->data;
-
- if (count < 2)
- return 0;
+
+ if (count < PCM_16_BPS)
+ return (0);
+
k = FEEDER_FEED(f->source, c, b, count >> 1, source);
+ if (k < PCM_8_BPS)
+ return (0);
+
i = k;
k <<= 1;
j = k;
- sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80;
+ sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00;
+
if (f->desc->out & AFMT_BIGENDIAN) {
- while (i > 0) {
+ do {
b[--j] = 0;
b[--j] = tbl[b[--i]] ^ sign;
- }
+ } while (i != 0);
} else {
- while (i > 0) {
+ do {
b[--j] = tbl[b[--i]] ^ sign;
b[--j] = 0;
- }
+ } while (i != 0);
}
- return k;
+
+ return (k);
}
static int
@@ -248,100 +256,106 @@ feed_table_xlaw(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
int j, sign, k;
uint8_t *tbl = (uint8_t *)f->data;
- if (count < 1)
- return 0;
+ if (count < PCM_8_BPS)
+ return (0);
+
k = FEEDER_FEED(f->source, c, b, count, source);
- j = k;
+ if (k < PCM_8_BPS)
+ return (0);
+
+ j = k ;
sign = (f->desc->in & AFMT_SIGNED) ? 0x80 : 0x00;
- while (j > 0) {
+
+ do {
j--;
b[j] = tbl[b[j] ^ sign];
- }
- return k;
+ } while (j != 0);
+
+ return (k);
}
static struct pcm_feederdesc feeder_ulawto8_desc[] = {
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_ulawto8_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_8),
+ KOBJMETHOD(feeder_feed, feed_table_8),
{0, 0}
};
-FEEDER_DECLARE(feeder_ulawto8, 0, ulaw_to_s8_tbl);
+FEEDER_DECLARE(feeder_ulawto8, 0, ulaw_to_u8_tbl);
static struct pcm_feederdesc feeder_alawto8_desc[] = {
{FEEDER_FMT, AFMT_A_LAW, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_A_LAW, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_alawto8_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_8),
+ KOBJMETHOD(feeder_feed, feed_table_8),
{0, 0}
};
-FEEDER_DECLARE(feeder_alawto8, 0, alaw_to_s8_tbl);
+FEEDER_DECLARE(feeder_alawto8, 0, alaw_to_u8_tbl);
static struct pcm_feederdesc feeder_ulawto16_desc[] = {
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_ulawto16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_16),
+ KOBJMETHOD(feeder_feed, feed_table_16),
{0, 0}
};
-FEEDER_DECLARE(feeder_ulawto16, 0, ulaw_to_s8_tbl);
+FEEDER_DECLARE(feeder_ulawto16, 0, ulaw_to_u8_tbl);
static struct pcm_feederdesc feeder_alawto16_desc[] = {
{FEEDER_FMT, AFMT_A_LAW, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_A_LAW, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_A_LAW, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_A_LAW, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_alawto16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_16),
+ KOBJMETHOD(feeder_feed, feed_table_16),
{0, 0}
};
-FEEDER_DECLARE(feeder_alawto16, 0, alaw_to_s8_tbl);
+FEEDER_DECLARE(feeder_alawto16, 0, alaw_to_u8_tbl);
static struct pcm_feederdesc feeder_8toulaw_desc[] = {
{FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_MU_LAW|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_MU_LAW, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_MU_LAW|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_8toulaw_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_xlaw),
+ KOBJMETHOD(feeder_feed, feed_table_xlaw),
{0, 0}
};
FEEDER_DECLARE(feeder_8toulaw, 0, u8_to_ulaw_tbl);
static struct pcm_feederdesc feeder_8toalaw_desc[] = {
{FEEDER_FMT, AFMT_U8, AFMT_A_LAW, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_A_LAW|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_A_LAW, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_A_LAW|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_8toalaw_methods[] = {
- KOBJMETHOD(feeder_feed, feed_table_xlaw),
+ KOBJMETHOD(feeder_feed, feed_table_xlaw),
{0, 0}
};
FEEDER_DECLARE(feeder_8toalaw, 0, u8_to_alaw_tbl);
@@ -350,553 +364,487 @@ FEEDER_DECLARE(feeder_8toalaw, 0, u8_to_alaw_tbl);
* All conversion done in byte level to preserve endianess.
*/
+#define FEEDFMT_SWAP_SIGN(f) (((((f)->desc->in & AFMT_SIGNED) == 0) != \
+ (((f)->desc->out & AFMT_SIGNED) == 0)) \
+ ? 0x80 : 0x00)
+
+/*
+ * Bit conversion
+ */
+
+#define FBIT_DATA(i, o, c) ((intptr_t)((((c) & 0xf) << 6) | \
+ (((i) & 0x7) << 3) | ((o) & 0x7)))
+#define FBIT_OUTBPS(m) ((m) & 0x7)
+#define FBIT_INBPS(m) FBIT_OUTBPS((m) >> 3)
+#define FBIT_CHANNELS(m) (((m) >> 6) & 0xf)
+
static int
-feed_fmt_init(struct pcm_feeder *f)
+feed_updownbit_init(struct pcm_feeder *f)
{
- struct feed_fmt_info *info;
+ int ibps, obps, channels;
- info = malloc(sizeof(*info), M_FMTFEEDER, M_NOWAIT | M_ZERO);
- if (info == NULL)
- return ENOMEM;
-
- info->bps = 1;
- info->bps <<= (f->desc->in & AFMT_STEREO) ? 1 : 0;
- if (f->desc->in & AFMT_16BIT)
- info->bps <<= 1;
- else if (f->desc->in & AFMT_24BIT)
- info->bps *= 3;
- else if (f->desc->in & AFMT_32BIT)
- info->bps <<= 2;
- info->bufsz = feeder_buffersize - (feeder_buffersize % info->bps);
-
- info->buffer = malloc(info->bufsz, M_FMTFEEDER, M_NOWAIT | M_ZERO);
- if (info->buffer == NULL) {
- free(info, M_FMTFEEDER);
- return ENOMEM;
- }
+ if (f->desc->in == f->desc->out || (f->desc->in & AFMT_STEREO) !=
+ (f->desc->out & AFMT_STEREO))
+ return (-1);
- f->data = info;
+ channels = (f->desc->in & AFMT_STEREO) ? 2 : 1;
- return 0;
+ if (f->desc->in & AFMT_32BIT)
+ ibps = PCM_32_BPS;
+ else if (f->desc->in & AFMT_24BIT)
+ ibps = PCM_24_BPS;
+ else if (f->desc->in & AFMT_16BIT)
+ ibps = PCM_16_BPS;
+ else
+ ibps = PCM_8_BPS;
+
+ if (f->desc->out & AFMT_32BIT)
+ obps = PCM_32_BPS;
+ else if (f->desc->out & AFMT_24BIT)
+ obps = PCM_24_BPS;
+ else if (f->desc->out & AFMT_16BIT)
+ obps = PCM_16_BPS;
+ else
+ obps = PCM_8_BPS;
+
+ f->data = (void *)FBIT_DATA(ibps, obps, channels);
+
+ return (0);
}
static int
-feed_fmt_free(struct pcm_feeder *f)
+feed_upbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+ uint32_t count, void *source)
{
- struct feed_fmt_info *info = f->data;
+ int i, j, k, sign, ibps, ialign, obps, oalign, pad;
+ uint8_t *src, *dst;
- if (info) {
- if (info->buffer)
- free(info->buffer, M_FMTFEEDER);
- free(info, M_FMTFEEDER);
- }
- f->data = NULL;
- return 0;
-}
+ ibps = FBIT_INBPS((intptr_t)f->data);
+ obps = FBIT_OUTBPS((intptr_t)f->data);
-#define swap_sign(fdr) \
- (((((fdr)->desc->in & AFMT_SIGNED) && \
- !((fdr)->desc->out & AFMT_SIGNED)) || \
- (!((fdr)->desc->in & AFMT_SIGNED) && \
- ((fdr)->desc->out & AFMT_SIGNED))) ? 0x80 : 0x00)
+ ialign = ibps * FBIT_CHANNELS((intptr_t)f->data);
+ oalign = obps * FBIT_CHANNELS((intptr_t)f->data);
+
+ if (count < oalign)
+ return (0);
+
+ k = FEEDER_FEED(f->source, c, b, (count / oalign) * ialign, source);
+ if (k < ialign)
+ return (0);
+
+ k -= k % ialign;
+ j = (k / ibps) * obps;
+ pad = obps - ibps;
+ src = b + k;
+ dst = b + j;
+ sign = FEEDFMT_SWAP_SIGN(f);
-/*
- * Bit conversion
- */
-static int
-feed_8to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k;
- int sign;
-
- if (count < 2)
- return 0;
- k = FEEDER_FEED(f->source, c, b, count >> 1, source);
- i = k;
- k <<= 1;
- j = k;
- sign = swap_sign(f);
if (f->desc->out & AFMT_BIGENDIAN) {
- while (i > 0) {
- b[--j] = 0;
- b[--j] = b[--i] ^ sign;
- }
+ do {
+ i = pad;
+ do {
+ *--dst = 0;
+ } while (--i != 0);
+ i = ibps;
+ while (--i != 0)
+ *--dst = *--src;
+ *--dst = *--src ^ sign;
+ } while (dst != b);
} else {
- while (i > 0) {
- b[--j] = b[--i] ^ sign;
- b[--j] = 0;
- }
+ do {
+ *--dst = *--src ^ sign;
+ i = ibps;
+ while (--i != 0)
+ *--dst = *--src;
+ i = pad;
+ do {
+ *--dst = 0;
+ } while (--i != 0);
+ } while (dst != b);
}
- return k;
+
+ return (j);
}
+
static struct pcm_feederdesc feeder_8to16_desc[] = {
{FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U8, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U8, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U8, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_8to16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_8to16),
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
{0, 0}
};
FEEDER_DECLARE(feeder_8to16, 0, NULL);
-static int
-feed_16to8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k, sign;
- uint8_t *src = info->buffer;
-
- if (count < 1)
- return 0;
- k = count << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- k &= ~1;
- i = k;
- j = k >> 1;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 1) {
- i--;
- b[--j] = src[--i] ^ sign;
- }
- } else {
- while (i > 1) {
- b[--j] = src[--i] ^ sign;
- i--;
- }
- }
- return k >> 1;
-}
-static struct pcm_feederdesc feeder_16to8_desc[] = {
- {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_BE, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_BE, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_LE, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_LE, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_BE, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_BE, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
+static struct pcm_feederdesc feeder_8to24_desc[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_U24_LE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S24_LE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_U24_BE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S24_BE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_S24_LE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_U24_LE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_S24_BE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_U24_BE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
-static kobj_method_t feeder_16to8_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_16to8),
+static kobj_method_t feeder_8to24_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
{0, 0}
};
-FEEDER_DECLARE(feeder_16to8, 0, NULL);
+FEEDER_DECLARE(feeder_8to24, 0, NULL);
+
+static struct pcm_feederdesc feeder_8to32_desc[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_8to32_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_8to32, 0, NULL);
-static int
-feed_16to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k, sign;
-
- if (count < 3)
- return 0;
- k = (count / 3) << 1;
- k = FEEDER_FEED(f->source, c, b, k, source);
- if (k < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- k &= ~1;
- i = k;
- j = (k >> 1) * 3;
- k = j;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 1) {
- b[--j] = 0;
- b[--j] = b[--i];
- b[--j] = b[--i] ^ sign;
- }
- } else {
- while (i > 1) {
- b[--j] = b[--i] ^ sign;
- b[--j] = b[--i];
- b[--j] = 0;
- }
- }
- return k;
-}
static struct pcm_feederdesc feeder_16to24_desc[] = {
{FEEDER_FMT, AFMT_U16_LE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_LE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U16_BE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_BE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U16_LE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_LE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U16_BE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_BE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_16to24_methods[] = {
- KOBJMETHOD(feeder_feed, feed_16to24),
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
{0, 0}
};
FEEDER_DECLARE(feeder_16to24, 0, NULL);
+static struct pcm_feederdesc feeder_16to32_desc[] = {
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_16to32_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_16to32, 0, NULL);
+
+static struct pcm_feederdesc feeder_24to32_desc[] = {
+ {FEEDER_FMT, AFMT_U24_LE, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_24to32_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_upbit),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_24to32, 0, NULL);
+
static int
-feed_24to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+feed_downbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
uint32_t count, void *source)
{
- struct feed_fmt_info *info = f->data;
- int i, j, k, sign;
- uint8_t *src = info->buffer;
-
- if (count < 2)
- return 0;
- k = (count >> 1) * 3;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 3) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__);
- k -= k % 3;
- i = (k / 3) << 1;
- j = i;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 1) {
- k--;
- b[--i] = src[--k];
- b[--i] = src[--k] ^ sign;
+ int i, j, k, sign, be, ibps, ialign, obps, oalign,dump;
+ uint8_t *src, *dst, *end;
+ uint8_t reservoir[FEEDFMT_RESERVOIR];
+
+ ibps = FBIT_INBPS((intptr_t)f->data);
+ obps = FBIT_OUTBPS((intptr_t)f->data);
+
+ ialign = ibps * FBIT_CHANNELS((intptr_t)f->data);
+ oalign = obps * FBIT_CHANNELS((intptr_t)f->data);
+
+ if (count < oalign)
+ return (0);
+
+ dst = b;
+ dump = ibps - obps;
+ sign = FEEDFMT_SWAP_SIGN(f);
+ be = (f->desc->in & AFMT_BIGENDIAN) ? 1 : 0;
+ k = count - (count % oalign);
+
+ do {
+ if (k < oalign)
+ break;
+
+ if (k < ialign) {
+ src = reservoir;
+ j = ialign;
+ } else {
+ src = dst;
+ j = k;
}
- } else {
- while (i > 1) {
- b[--i] = src[--k] ^ sign;
- b[--i] = src[--k];
- k--;
+
+ j = FEEDER_FEED(f->source, c, src, j - (j % ialign), source);
+ if (j < ialign)
+ break;
+
+ j -= j % ialign;
+ j *= obps;
+ j /= ibps;
+ end = dst + j;
+
+ if (be != 0) {
+ do {
+ *dst++ = *src++ ^ sign;
+ i = obps;
+ while (--i != 0)
+ *dst++ = *src++;
+ src += dump;
+ } while (dst != end);
+ } else {
+ do {
+ src += dump;
+ i = obps;
+ while (--i != 0)
+ *dst++ = *src++;
+ *dst++ = *src++ ^ sign;
+ } while (dst != end);
}
- }
- return j;
+
+ k -= j;
+ } while (k != 0);
+
+ return (dst - b);
}
+
+static struct pcm_feederdesc feeder_16to8_desc[] = {
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_16to8_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_16to8, 0, NULL);
+
+static struct pcm_feederdesc feeder_24to8_desc[] = {
+ {FEEDER_FMT, AFMT_U24_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_24to8_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_24to8, 0, NULL);
+
static struct pcm_feederdesc feeder_24to16_desc[] = {
{FEEDER_FMT, AFMT_U24_LE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_LE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U24_BE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_BE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U24_LE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_LE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U24_BE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_BE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_24to16_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_24to16),
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
{0, 0}
};
-FEEDER_DECLARE(feeder_24to16, 1, NULL);
-
-static int
-feed_16to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, sign, k;
-
- if (count < 4)
- return 0;
- k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 1, source);
- if (k < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- k &= ~1;
- i = k;
- j = k << 1;
- k = j;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 1) {
- b[--j] = 0;
- b[--j] = 0;
- b[--j] = b[--i];
- b[--j] = b[--i] ^ sign;
- }
- } else {
- while (i > 1) {
- b[--j] = b[--i] ^ sign;
- b[--j] = b[--i];
- b[--j] = 0;
- b[--j] = 0;
- }
- }
- return k;
-}
-static struct pcm_feederdesc feeder_16to32_desc[] = {
- {FEEDER_FMT, AFMT_U16_LE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_LE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_BE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_BE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_LE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_LE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_BE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_BE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
+FEEDER_DECLARE(feeder_24to16, 0, NULL);
+
+static struct pcm_feederdesc feeder_32to8_desc[] = {
+ {FEEDER_FMT, AFMT_U32_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
-static kobj_method_t feeder_16to32_methods[] = {
- KOBJMETHOD(feeder_feed, feed_16to32),
+static kobj_method_t feeder_32to8_methods[] = {
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
{0, 0}
};
-FEEDER_DECLARE(feeder_16to32, 0, NULL);
+FEEDER_DECLARE(feeder_32to8, 0, NULL);
-static int
-feed_32to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k, sign;
- uint8_t *src = info->buffer;
-
- if (count < 2)
- return 0;
- k = (count & ~1) << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__);
- k &= ~3;
- i = k;
- k >>= 1;
- j = k;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 3) {
- i -= 2;
- b[--j] = src[--i];
- b[--j] = src[--i] ^ sign;
- }
- } else {
- while (i > 3) {
- b[--j] = src[--i] ^ sign;
- b[--j] = src[--i];
- i -= 2;
- }
- }
- return k;
-}
static struct pcm_feederdesc feeder_32to16_desc[] = {
{FEEDER_FMT, AFMT_U32_LE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_LE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_32to16_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_32to16),
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
{0, 0}
};
-FEEDER_DECLARE(feeder_32to16, 1, NULL);
+FEEDER_DECLARE(feeder_32to16, 0, NULL);
-static int
-feed_24to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k, sign;
-
- if (count < 4)
- return 0;
- k = FEEDER_FEED(f->source, c, b, (count >> 2) * 3, source);
- if (k < 3) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__);
- k -= k % 3;
- i = k;
- k = (k / 3) << 2;
- j = k;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 2) {
- b[--j] = 0;
- b[--j] = b[--i];
- b[--j] = b[--i];
- b[--j] = b[--i] ^ sign;
- }
- } else {
- while (i > 2) {
- b[--j] = b[--i] ^ sign;
- b[--j] = b[--i];
- b[--j] = b[--i];
- b[--j] = 0;
- }
- }
- return k;
-}
-static struct pcm_feederdesc feeder_24to32_desc[] = {
- {FEEDER_FMT, AFMT_U24_LE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_LE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U24_BE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_BE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U24_LE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_LE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U24_BE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_BE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
- {0, 0, 0, 0},
-};
-static kobj_method_t feeder_24to32_methods[] = {
- KOBJMETHOD(feeder_feed, feed_24to32),
- {0, 0}
-};
-FEEDER_DECLARE(feeder_24to32, 1, NULL);
-
-static int
-feed_32to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k, sign;
- uint8_t *src = info->buffer;
-
- if (count < 3)
- return 0;
- k = (count / 3) << 2;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__);
- k &= ~3;
- i = k;
- k = (k >> 2) * 3;
- j = k;
- sign = swap_sign(f);
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 3) {
- --i;
- b[--j] = src[--i];
- b[--j] = src[--i];
- b[--j] = src[--i] ^ sign;
- }
- } else {
- while (i > 3) {
- b[--j] = src[--i] ^ sign;
- b[--j] = src[--i];
- b[--j] = src[--i];
- --i;
- }
- }
- return k;
-}
static struct pcm_feederdesc feeder_32to24_desc[] = {
{FEEDER_FMT, AFMT_U32_LE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_LE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_32to24_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_32to24),
+ KOBJMETHOD(feeder_init, feed_updownbit_init),
+ KOBJMETHOD(feeder_feed, feed_downbit),
{0, 0}
};
-FEEDER_DECLARE(feeder_32to24, 1, NULL);
+FEEDER_DECLARE(feeder_32to24, 0, NULL);
/*
* Bit conversion end
*/
@@ -905,169 +853,88 @@ FEEDER_DECLARE(feeder_32to24, 1, NULL);
* Channel conversion (mono -> stereo)
*/
static int
-feed_monotostereo8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+feed_monotostereo(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
uint32_t count, void *source)
{
- int i, j, k;
+ int bps, i, j, k, l;
+ uint8_t v;
- if (count < 2)
- return 0;
- k = FEEDER_FEED(f->source, c, b, count >> 1, source);
- i = k;
- j = k << 1;
- while (i > 0) {
- b[--j] = b[--i];
- b[--j] = b[i];
- }
- return k << 1;
+ bps = (int)((intptr_t)f->data);
+ if (count < (bps << 1))
+ return (0);
+
+ j = FEEDER_FEED(f->source, c, b, (count - (count % bps)) >> 1, source);
+ if (j < bps)
+ return (0);
+
+ j -= j % bps;
+ i = j << 1;
+ l = i;
+
+ do {
+ k = bps;
+ do {
+ v = b[--j];
+ b[--i] = v;
+ b[i - bps] = v;
+ } while (--k != 0);
+ i -= bps;
+ } while (i != 0);
+
+ return (l);
}
+
static struct pcm_feederdesc feeder_monotostereo8_desc[] = {
- {FEEDER_FMT, AFMT_U8, AFMT_U8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S8, AFMT_S8|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_MU_LAW, AFMT_MU_LAW|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_A_LAW, AFMT_A_LAW|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_MU_LAW, AFMT_MU_LAW | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_A_LAW, AFMT_A_LAW | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_monotostereo8_methods[] = {
- KOBJMETHOD(feeder_feed, feed_monotostereo8),
+ KOBJMETHOD(feeder_feed, feed_monotostereo),
{0, 0}
};
-FEEDER_DECLARE(feeder_monotostereo8, 0, NULL);
+FEEDER_DECLARE(feeder_monotostereo8, 0, (void *)PCM_8_BPS);
-static int
-feed_monotostereo16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k;
- uint8_t l, m;
-
- if (count < 4)
- return 0;
- k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 1, source);
- if (k < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- k &= ~1;
- i = k;
- j = k << 1;
- while (i > 1) {
- l = b[--i];
- m = b[--i];
- b[--j] = l;
- b[--j] = m;
- b[--j] = l;
- b[--j] = m;
- }
- return k << 1;
-}
static struct pcm_feederdesc feeder_monotostereo16_desc[] = {
- {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_monotostereo16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_monotostereo16),
+ KOBJMETHOD(feeder_feed, feed_monotostereo),
{0, 0}
};
-FEEDER_DECLARE(feeder_monotostereo16, 0, NULL);
+FEEDER_DECLARE(feeder_monotostereo16, 0, (void *)PCM_16_BPS);
-static int
-feed_monotostereo24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k;
- uint8_t l, m, n;
-
- if (count < 6)
- return 0;
- k = FEEDER_FEED(f->source, c, b, ((count / 6) * 6) >> 1, source);
- if (k < 3) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__);
- k -= k % 3;
- i = k;
- j = k << 1;
- while (i > 2) {
- l = b[--i];
- m = b[--i];
- n = b[--i];
- b[--j] = l;
- b[--j] = m;
- b[--j] = n;
- b[--j] = l;
- b[--j] = m;
- b[--j] = n;
- }
- return k << 1;
-}
static struct pcm_feederdesc feeder_monotostereo24_desc[] = {
- {FEEDER_FMT, AFMT_U24_LE, AFMT_U24_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_LE, AFMT_S24_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U24_BE, AFMT_U24_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S24_BE, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE, AFMT_U24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE, AFMT_S24_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE, AFMT_U24_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE, AFMT_S24_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_monotostereo24_methods[] = {
- KOBJMETHOD(feeder_feed, feed_monotostereo24),
+ KOBJMETHOD(feeder_feed, feed_monotostereo),
{0, 0}
};
-FEEDER_DECLARE(feeder_monotostereo24, 0, NULL);
+FEEDER_DECLARE(feeder_monotostereo24, 0, (void *)PCM_24_BPS);
-static int
-feed_monotostereo32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j, k;
- uint8_t l, m, n, o;
-
- if (count < 8)
- return 0;
- k = FEEDER_FEED(f->source, c, b, (count & ~7) >> 1, source);
- if (k < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__);
- k &= ~3;
- i = k;
- j = k << 1;
- while (i > 3) {
- l = b[--i];
- m = b[--i];
- n = b[--i];
- o = b[--i];
- b[--j] = l;
- b[--j] = m;
- b[--j] = n;
- b[--j] = o;
- b[--j] = l;
- b[--j] = m;
- b[--j] = n;
- b[--j] = o;
- }
- return k << 1;
-}
static struct pcm_feederdesc feeder_monotostereo32_desc[] = {
- {FEEDER_FMT, AFMT_U32_LE, AFMT_U32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S32_LE, AFMT_S32_LE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_U32_BE, AFMT_U32_BE|AFMT_STEREO, 0},
- {FEEDER_FMT, AFMT_S32_BE, AFMT_S32_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE, AFMT_U32_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE, AFMT_S32_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_monotostereo32_methods[] = {
- KOBJMETHOD(feeder_feed, feed_monotostereo32),
+ KOBJMETHOD(feeder_feed, feed_monotostereo),
{0, 0}
};
-FEEDER_DECLARE(feeder_monotostereo32, 0, NULL);
+FEEDER_DECLARE(feeder_monotostereo32, 0, (void *)PCM_32_BPS);
/*
* Channel conversion (mono -> stereo) end
*/
@@ -1075,176 +942,219 @@ FEEDER_DECLARE(feeder_monotostereo32, 0, NULL);
/*
* Channel conversion (stereo -> mono)
*/
+#define FEEDER_FMT_STEREODOWNMIX(FMTBIT, FMT_INTCAST, SIGN, \
+ SIGNS, ENDIAN, ENDIANS) \
+static void \
+SIGNS##FMTBIT##ENDIANS##_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy) \
+{ \
+ int32_t v; \
+ \
+ v = ((FMT_INTCAST)PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sx) + \
+ PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sy)) >> 1; \
+ PCM_WRITE_##SIGN##FMTBIT##_##ENDIAN(dst, v); \
+}
+
+FEEDER_FMT_STEREODOWNMIX(8, int32_t, S, s, NE, ne);
+FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, LE, le);
+FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, LE, le);
+FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, LE, le);
+FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, BE, be);
+FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, BE, be);
+FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, BE, be);
+FEEDER_FMT_STEREODOWNMIX(8, int32_t, U, u, NE, ne);
+FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, LE, le);
+FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, LE, le);
+FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, LE, le);
+FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, BE, be);
+FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, BE, be);
+FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, BE, be);
+
+static void
+ulaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy)
+{
+ uint8_t v;
+
+ v = ((uint32_t)ulaw_to_u8_tbl[*sx] + ulaw_to_u8_tbl[*sy]) >> 1;
+ *dst = u8_to_ulaw_tbl[v];
+}
+
+static void
+alaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy)
+{
+ uint8_t v;
+
+ v = ((uint32_t)alaw_to_u8_tbl[*sx] + alaw_to_u8_tbl[*sy]) >> 1;
+ *dst = u8_to_alaw_tbl[v];
+}
+
+typedef void (*feed_fmt_stereodownmix_filter)(uint8_t *,
+ uint8_t *, uint8_t *);
+
+struct feed_fmt_stereodownmix_info {
+ uint32_t format;
+ int bps;
+ feed_fmt_stereodownmix_filter func[2];
+};
+
+static struct feed_fmt_stereodownmix_info feed_fmt_stereodownmix_tbl[] = {
+ { AFMT_S8, PCM_8_BPS, { NULL, s8ne_stereodownmix }},
+ { AFMT_S16_LE, PCM_16_BPS, { NULL, s16le_stereodownmix }},
+ { AFMT_S16_BE, PCM_16_BPS, { NULL, s16be_stereodownmix }},
+ { AFMT_S24_LE, PCM_24_BPS, { NULL, s24le_stereodownmix }},
+ { AFMT_S24_BE, PCM_24_BPS, { NULL, s24be_stereodownmix }},
+ { AFMT_S32_LE, PCM_32_BPS, { NULL, s32le_stereodownmix }},
+ { AFMT_S32_BE, PCM_32_BPS, { NULL, s32be_stereodownmix }},
+ { AFMT_U8, PCM_8_BPS, { NULL, u8ne_stereodownmix }},
+ { AFMT_A_LAW, PCM_8_BPS, { NULL, alaw_stereodownmix }},
+ { AFMT_MU_LAW, PCM_8_BPS, { NULL, ulaw_stereodownmix }},
+ { AFMT_U16_LE, PCM_16_BPS, { NULL, u16le_stereodownmix }},
+ { AFMT_U16_BE, PCM_16_BPS, { NULL, u16be_stereodownmix }},
+ { AFMT_U24_LE, PCM_24_BPS, { NULL, u24le_stereodownmix }},
+ { AFMT_U24_BE, PCM_24_BPS, { NULL, u24be_stereodownmix }},
+ { AFMT_U32_LE, PCM_32_BPS, { NULL, u32le_stereodownmix }},
+ { AFMT_U32_BE, PCM_32_BPS, { NULL, u32be_stereodownmix }},
+};
+
+#define FSM_DATA(i, j) ((intptr_t)((((i) & 0x1f) << 1) | ((j) & 0x1)))
+#define FSM_INFOIDX(m) (((m) >> 1) & 0x1f)
+#define FSM_FUNCIDX(m) ((m) & 0x1)
+
static int
-feed_stereotomono8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
+feed_stereotomono_init(struct pcm_feeder *f)
{
- struct feed_fmt_info *info = f->data;
- int i, j, k;
- uint8_t *src = info->buffer;
-
- if (count < 1)
- return 0;
- k = count << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 1, "%s: Bytes not 8bit (stereo) aligned.\n", __func__);
- k &= ~1;
- i = k >> 1;
- j = i;
- while (i > 0) {
- k--;
- b[--i] = src[--k];
+ int i, funcidx;
+
+ if (!(f->desc->in & AFMT_STEREO) || (f->desc->out & AFMT_STEREO))
+ return (-1);
+
+ funcidx = (feeder_fmt_stereodownmix != 0) ? 1 : 0;
+
+ for (i = 0; i < sizeof(feed_fmt_stereodownmix_tbl) /
+ sizeof(feed_fmt_stereodownmix_tbl[0]); i++) {
+ if (f->desc->out == feed_fmt_stereodownmix_tbl[i].format) {
+ f->data = (void *)FSM_DATA(i, funcidx);
+ return (0);
+ }
}
- return j;
+
+ return (-1);
+}
+
+static int
+feed_stereotomono(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+ uint32_t count, void *source)
+{
+ struct feed_fmt_stereodownmix_info *info;
+ feed_fmt_stereodownmix_filter stereodownmix;
+ int i, j, k, ibps, obps;
+ uint8_t *src, *dst, *end;
+ uint8_t reservoir[FEEDFMT_RESERVOIR];
+
+ info = &feed_fmt_stereodownmix_tbl[FSM_INFOIDX((intptr_t)f->data)];
+ obps = info->bps;
+
+ if (count < obps)
+ return (0);
+
+ stereodownmix = info->func[FSM_FUNCIDX((intptr_t)f->data)];
+ ibps = obps << 1;
+ dst = b;
+ k = count - (count % obps);
+
+ do {
+ if (k < obps)
+ break;
+
+ if (k < ibps) {
+ src = reservoir;
+ j = ibps;
+ } else {
+ src = dst;
+ j = k;
+ }
+
+ j = FEEDER_FEED(f->source, c, src, j - (j % ibps), source);
+ if (j < ibps)
+ break;
+
+ j -= j % ibps;
+ j >>= 1;
+ end = dst + j;
+
+ if (stereodownmix != NULL) {
+ do {
+ stereodownmix(dst, src, src + obps);
+ dst += obps;
+ src += ibps;
+ } while (dst != end);
+ } else {
+ do {
+ i = obps;
+ do {
+ *dst++ = *src++;
+ } while (--i != 0);
+ src += obps;
+ } while (dst != end);
+ }
+
+ k -= j;
+ } while (k != 0);
+
+ return (dst - b);
}
+
static struct pcm_feederdesc feeder_stereotomono8_desc[] = {
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_MU_LAW, 0},
- {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_A_LAW, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_MU_LAW, 0},
+ {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_stereotomono8_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_stereotomono8),
+ KOBJMETHOD(feeder_init, feed_stereotomono_init),
+ KOBJMETHOD(feeder_feed, feed_stereotomono),
{0, 0}
};
FEEDER_DECLARE(feeder_stereotomono8, 0, NULL);
-static int
-feed_stereotomono16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k;
- uint8_t *src = info->buffer;
-
- if (count < 2)
- return 0;
- k = (count & ~1) << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 3, "%s: Bytes not 16bit (stereo) aligned.\n", __func__);
- k &= ~3;
- i = k >> 1;
- j = i;
- while (i > 1) {
- k -= 2;
- b[--i] = src[--k];
- b[--i] = src[--k];
- }
- return j;
-}
static struct pcm_feederdesc feeder_stereotomono16_desc[] = {
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S16_BE, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_stereotomono16_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_stereotomono16),
+ KOBJMETHOD(feeder_init, feed_stereotomono_init),
+ KOBJMETHOD(feeder_feed, feed_stereotomono),
{0, 0}
};
FEEDER_DECLARE(feeder_stereotomono16, 0, NULL);
-static int
-feed_stereotomono24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k;
- uint8_t *src = info->buffer;
-
- if (count < 3)
- return 0;
- k = ((count / 3) * 3) << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 6) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k % 6, "%s: Bytes not 24bit (stereo) aligned.\n", __func__);
- k -= k % 6;
- i = k >> 1;
- j = i;
- while (i > 2) {
- k -= 3;
- b[--i] = src[--k];
- b[--i] = src[--k];
- b[--i] = src[--k];
- }
- return j;
-}
static struct pcm_feederdesc feeder_stereotomono24_desc[] = {
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S24_BE, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_stereotomono24_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_stereotomono24),
+ KOBJMETHOD(feeder_init, feed_stereotomono_init),
+ KOBJMETHOD(feeder_feed, feed_stereotomono),
{0, 0}
};
FEEDER_DECLARE(feeder_stereotomono24, 0, NULL);
-static int
-feed_stereotomono32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- struct feed_fmt_info *info = f->data;
- int i, j, k;
- uint8_t *src = info->buffer;
-
- if (count < 4)
- return 0;
- k = (count & ~3) << 1;
- k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source);
- if (k < 8) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, k);
- return 0;
- }
- FMT_TEST(k & 7, "%s: Bytes not 32bit (stereo) aligned.\n", __func__);
- k &= ~7;
- i = k >> 1;
- j = i;
- while (i > 3) {
- k -= 4;
- b[--i] = src[--k];
- b[--i] = src[--k];
- b[--i] = src[--k];
- b[--i] = src[--k];
- }
- return j;
-}
static struct pcm_feederdesc feeder_stereotomono32_desc[] = {
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S32_BE, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_stereotomono32_methods[] = {
- KOBJMETHOD(feeder_init, feed_fmt_init),
- KOBJMETHOD(feeder_free, feed_fmt_free),
- KOBJMETHOD(feeder_feed, feed_stereotomono32),
+ KOBJMETHOD(feeder_init, feed_stereotomono_init),
+ KOBJMETHOD(feeder_feed, feed_stereotomono),
{0, 0}
};
FEEDER_DECLARE(feeder_stereotomono32, 0, NULL);
@@ -1256,307 +1166,268 @@ FEEDER_DECLARE(feeder_stereotomono32, 0, NULL);
* Sign conversion
*/
static int
-feed_sign8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+feed_sign(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
uint32_t count, void *source)
{
- int i, j;
-
- if (count < 1)
- return 0;
- j = FEEDER_FEED(f->source, c, b, count, source);
- i = j;
- while (i > 0)
- b[--i] ^= 0x80;
- return j;
+ int i, j, bps, ofs;
+
+ bps = (int)((intptr_t)f->data);
+ if (count < bps)
+ return (0);
+
+ i = FEEDER_FEED(f->source, c, b, count - (count % bps), source);
+ if (i < bps)
+ return (0);
+
+ i -= i % bps;
+ j = i;
+ ofs = (f->desc->in & AFMT_BIGENDIAN) ? bps : 1;
+
+ do {
+ b[i - ofs] ^= 0x80;
+ i -= bps;
+ } while (i != 0);
+
+ return (j);
}
static struct pcm_feederdesc feeder_sign8_desc[] = {
{FEEDER_FMT, AFMT_U8, AFMT_S8, 0},
- {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S8, AFMT_U8, 0},
- {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_sign8_methods[] = {
- KOBJMETHOD(feeder_feed, feed_sign8),
+ KOBJMETHOD(feeder_feed, feed_sign),
{0, 0}
};
-FEEDER_DECLARE(feeder_sign8, 0, NULL);
+FEEDER_DECLARE(feeder_sign8, 0, (void *)PCM_8_BPS);
-static int
-feed_sign16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j;
-
- if (count < 2)
- return 0;
- j = FEEDER_FEED(f->source, c, b, count & ~1, source);
- if (j < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- j &= ~1;
- i = j;
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 1) {
- i--;
- b[--i] ^= 0x80;
- }
- } else {
- while (i > 1) {
- b[--i] ^= 0x80;
- i--;
- }
- }
- return j;
-}
static struct pcm_feederdesc feeder_sign16_desc[] = {
{FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U16_BE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_BE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_sign16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_sign16),
+ KOBJMETHOD(feeder_feed, feed_sign),
{0, 0}
};
-FEEDER_DECLARE(feeder_sign16, 0, NULL);
+FEEDER_DECLARE(feeder_sign16, 0, (void *)PCM_16_BPS);
-static int
-feed_sign24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j;
-
- if (count < 3)
- return 0;
- j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, source);
- if (j < 3) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__);
- j -= j % 3;
- i = j;
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 2) {
- i -= 2;
- b[--i] ^= 0x80;
- }
- } else {
- while (i > 2) {
- b[--i] ^= 0x80;
- i -= 2;
- }
- }
- return j;
-}
static struct pcm_feederdesc feeder_sign24_desc[] = {
{FEEDER_FMT, AFMT_U24_LE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_LE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U24_BE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_BE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_sign24_methods[] = {
- KOBJMETHOD(feeder_feed, feed_sign24),
+ KOBJMETHOD(feeder_feed, feed_sign),
{0, 0}
};
-FEEDER_DECLARE(feeder_sign24, 0, NULL);
+FEEDER_DECLARE(feeder_sign24, 0, (void *)PCM_24_BPS);
-static int
-feed_sign32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j;
-
- if (count < 4)
- return 0;
- j = FEEDER_FEED(f->source, c, b, count & ~3, source);
- if (j < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__);
- j &= ~3;
- i = j;
- if (f->desc->in & AFMT_BIGENDIAN) {
- while (i > 3) {
- i -= 3;
- b[--i] ^= 0x80;
- }
- } else {
- while (i > 3) {
- b[--i] ^= 0x80;
- i -= 3;
- }
- }
- return j;
-}
static struct pcm_feederdesc feeder_sign32_desc[] = {
{FEEDER_FMT, AFMT_U32_LE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_sign32_methods[] = {
- KOBJMETHOD(feeder_feed, feed_sign32),
+ KOBJMETHOD(feeder_feed, feed_sign),
{0, 0}
};
-FEEDER_DECLARE(feeder_sign32, 0, NULL);
-/*
- * Sign conversion end.
- */
+FEEDER_DECLARE(feeder_sign32, 0, (void *)PCM_32_BPS);
/*
- * Endian conversion.
+ * Endian conversion
*/
static int
-feed_endian16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+feed_endian(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
uint32_t count, void *source)
{
- int i, j;
- uint8_t v;
-
- if (count < 2)
- return 0;
- j = FEEDER_FEED(f->source, c, b, count & ~1, source);
- if (j < 2) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__);
- j &= ~1;
- i = j;
- while (i > 1) {
- v = b[--i];
- b[i] = b[i - 1];
- b[--i] = v;
- }
- return j;
+ int i, j, k, bps;
+ uint8_t *buf, v;
+
+ bps = (int)((intptr_t)f->data);
+ if (count < bps)
+ return (0);
+
+ k = FEEDER_FEED(f->source, c, b, count - (count % bps), source);
+ if (k < bps)
+ return (0);
+
+ k -= k % bps;
+ j = bps >> 1;
+ buf = b + k;
+
+ do {
+ buf -= bps;
+ i = j;
+ do {
+ v = buf[--i];
+ buf[i] = buf[bps - i - 1];
+ buf[bps - i - 1] = v;
+ } while (i != 0);
+ } while (buf != b);
+
+ return (k);
}
static struct pcm_feederdesc feeder_endian16_desc[] = {
{FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0},
- {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0},
- {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0},
- {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0},
- {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_endian16_methods[] = {
- KOBJMETHOD(feeder_feed, feed_endian16),
+ KOBJMETHOD(feeder_feed, feed_endian),
{0, 0}
};
-FEEDER_DECLARE(feeder_endian16, 0, NULL);
+FEEDER_DECLARE(feeder_endian16, 0, (void *)PCM_16_BPS);
-static int
-feed_endian24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j;
- uint8_t v;
-
- if (count < 3)
- return 0;
- j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, source);
- if (j < 3) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__);
- j -= j % 3;
- i = j;
- while (i > 2) {
- v = b[--i];
- b[i] = b[i - 2];
- b[i -= 2] = v;
- }
- return j;
-}
static struct pcm_feederdesc feeder_endian24_desc[] = {
{FEEDER_FMT, AFMT_U24_LE, AFMT_U24_BE, 0},
- {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_LE, AFMT_S24_BE, 0},
- {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U24_BE, AFMT_U24_LE, 0},
- {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S24_BE, AFMT_S24_LE, 0},
- {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_endian24_methods[] = {
- KOBJMETHOD(feeder_feed, feed_endian24),
+ KOBJMETHOD(feeder_feed, feed_endian),
{0, 0}
};
-FEEDER_DECLARE(feeder_endian24, 0, NULL);
+FEEDER_DECLARE(feeder_endian24, 0, (void *)PCM_24_BPS);
-static int
-feed_endian32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
- uint32_t count, void *source)
-{
- int i, j;
- uint8_t l, m;
-
- if (count < 4)
- return 0;
- j = FEEDER_FEED(f->source, c, b, count & ~3, source);
- if (j < 4) {
- FMT_TRACE("%s: Not enough data (Got: %d bytes)\n",
- __func__, j);
- return 0;
- }
- FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__);
- j &= ~3;
- i = j;
- while (i > 3) {
- l = b[--i];
- m = b[--i];
- b[i] = b[i - 1];
- b[i + 1] = b[i - 2];
- b[--i] = m;
- b[--i] = l;
- }
- return j;
-}
static struct pcm_feederdesc feeder_endian32_desc[] = {
{FEEDER_FMT, AFMT_U32_LE, AFMT_U32_BE, 0},
- {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_LE, AFMT_S32_BE, 0},
- {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_U32_BE, AFMT_U32_LE, 0},
- {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
{FEEDER_FMT, AFMT_S32_BE, AFMT_S32_LE, 0},
- {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
{0, 0, 0, 0},
};
static kobj_method_t feeder_endian32_methods[] = {
- KOBJMETHOD(feeder_feed, feed_endian32),
+ KOBJMETHOD(feeder_feed, feed_endian),
{0, 0}
};
-FEEDER_DECLARE(feeder_endian32, 0, NULL);
+FEEDER_DECLARE(feeder_endian32, 0, (void *)PCM_32_BPS);
/*
* Endian conversion end
*/
+
+/*
+ * L/R swap conversion
+ */
+static int
+feed_swaplr(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+ uint32_t count, void *source)
+{
+ int i, j, bps, smpsz;
+ uint8_t *buf, v;
+
+ bps = (int)((intptr_t)f->data);
+ smpsz = bps << 1;
+ if (count < smpsz)
+ return (0);
+
+ j = FEEDER_FEED(f->source, c, b, count - (count % smpsz), source);
+ if (j < smpsz)
+ return (0);
+
+ j -= j % smpsz;
+ buf = b + j;
+
+ do {
+ buf -= smpsz;
+ i = bps;
+ do {
+ v = buf[--i];
+ buf[i] = buf[bps + i];
+ buf[bps + i] = v;
+ } while (i != 0);
+ } while (buf != b);
+
+ return (j);
+}
+
+static struct pcm_feederdesc feeder_swaplr8_desc[] = {
+ {FEEDER_SWAPLR, AFMT_S8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_MU_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_swaplr8_methods[] = {
+ KOBJMETHOD(feeder_feed, feed_swaplr),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_swaplr8, -1, (void *)PCM_8_BPS);
+
+static struct pcm_feederdesc feeder_swaplr16_desc[] = {
+ {FEEDER_SWAPLR, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_swaplr16_methods[] = {
+ KOBJMETHOD(feeder_feed, feed_swaplr),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_swaplr16, -1, (void *)PCM_16_BPS);
+
+static struct pcm_feederdesc feeder_swaplr24_desc[] = {
+ {FEEDER_SWAPLR, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_swaplr24_methods[] = {
+ KOBJMETHOD(feeder_feed, feed_swaplr),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_swaplr24, -1, (void *)PCM_24_BPS);
+
+static struct pcm_feederdesc feeder_swaplr32_desc[] = {
+ {FEEDER_SWAPLR, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
+ {FEEDER_SWAPLR, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
+ {0, 0, 0, 0},
+};
+static kobj_method_t feeder_swaplr32_methods[] = {
+ KOBJMETHOD(feeder_feed, feed_swaplr),
+ {0, 0}
+};
+FEEDER_DECLARE(feeder_swaplr32, -1, (void *)PCM_32_BPS);
+/*
+ * L/R swap conversion end
+ */
OpenPOWER on IntegriCloud