summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm
diff options
context:
space:
mode:
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