Subject: Propose: improve audio driver
To: None <tech-kern@netbsd.org>
From: Tetsuya Isaki <isaki@par.odn.ne.jp>
List: tech-kern
Date: 02/24/2002 13:58:35
----Next_Part(Sun_Feb_24_13:58:17_2002_595)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi,
I'd like to introduce the mechanism of factor=1/n to
struct audio_params for x68k vs(4) driver.
for details:
MI audio driver prepares sw_code and factor to be able
to play 8bit/sampling format with the hardware which can
play only 16bit/sampling, for example.
However, so that factor appoints whether data after
sw_code become several times of original one with integer,
MI audio driver does not support the case that data after
sw_code become smaller than original one.
Because X68k built-in ADPCM is 4bit/samping, originally
vs (driver for X68k built-in ADPCM; arch/x68k/dev/vs.c)
can play no format of 8bit/samping and 16bit/sampling format
with mechanism of existing sw_code and factor.
# However, due to a bug (see dev/ic/msm6258.c of attached patch)
# and the easy fix (sample_rate *= 2 in arch/x68k/dev/vs.c of
# attached patch), current vs(4) driver can play it fortunately
# under some conditions.
Here is my proposal. I've improved MI audio driver to use
factor=1/n and I've fixed a bug of vs(4). I attach the
patch to this mail. With this patch, vs(4) can play mulaw and
ulinear8 correctly. And I think there is no side effect on
any other audio drivers. I've tested only yds driver on i386.
Recording is untouched.
Please comments.
Thanks.
---
Tetsuya Isaki <isaki@par.odn.ne.jp / isaki@NetBSD.org>
----Next_Part(Sun_Feb_24_13:58:17_2002_595)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="vs-reduce-20020224.diff"
Index: arch/x68k/dev/vs.c
===================================================================
RCS file: /home/isaki/cvsroot/vs/src/sys/arch/x68k/dev/vs.c,v
retrieving revision 1.1.1.3
retrieving revision 1.11
diff -u -r1.1.1.3 -r1.11
--- arch/x68k/dev/vs.c 2001/12/24 09:31:20 1.1.1.3
+++ arch/x68k/dev/vs.c 2002/02/17 09:48:35 1.11
@@ -389,13 +389,16 @@
rate = p->sample_rate;
p->sw_code = NULL;
p->factor = 1;
+ p->reduce_factor = 1;
+ DPRINTF(1, ("vs_set_params: encoding=%d, precision=%d\n",
+ p->encoding, p->precision));
switch (p->encoding) {
case AUDIO_ENCODING_ULAW:
if (p->precision != 8)
return EINVAL;
if (mode == AUMODE_PLAY) {
p->sw_code = msm6258_mulaw_to_adpcm;
- rate = p->sample_rate * 2;
+ p->reduce_factor = 2;
} else {
p->sw_code = msm6258_adpcm_to_mulaw;
p->factor = 2;
@@ -407,7 +410,7 @@
return EINVAL;
if (mode == AUMODE_PLAY) {
p->sw_code = msm6258_ulinear8_to_adpcm;
- rate = p->sample_rate * 2;
+ p->reduce_factor = 2;
} else {
p->sw_code = msm6258_adpcm_to_ulinear8;
p->factor = 2;
Index: dev/audio.c
===================================================================
RCS file: /home/isaki/cvsroot/vs/src/sys/dev/audio.c,v
retrieving revision 1.1.1.5
retrieving revision 1.22
diff -u -r1.1.1.5 -r1.22
--- dev/audio.c 2002/02/17 05:28:35 1.1.1.5
+++ dev/audio.c 2002/02/17 09:48:36 1.22
@@ -184,7 +184,7 @@
/* The default audio mode: 8 kHz mono ulaw */
struct audio_params audio_default =
- { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1 };
+ { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1, 1 };
struct cfattach audio_ca = {
sizeof(struct audio_softc), audioprobe, audioattach,
@@ -929,6 +929,14 @@
}
#endif
+ /*
+ * Allocate buffer for temporary space for sw_code
+ */
+ sc->sc_tmpbufsize = 65536; /* XXX */
+ sc->sc_tmpbuf = malloc(sc->sc_tmpbufsize, M_DEVBUF, M_WAITOK);
+ if (sc->sc_tmpbuf == NULL)
+ return ENOMEM;
+
AUDIO_INITINFO(&ai);
ai.record.sample_rate = sc->sc_rparams.sample_rate;
ai.record.encoding = sc->sc_rparams.encoding;
@@ -954,6 +962,8 @@
sc->sc_open = 0;
sc->sc_mode = 0;
sc->sc_full_duplex = 0;
+ free(sc->sc_tmpbuf, M_DEVBUF);
+ sc->sc_tmpbuf = NULL;
return error;
}
@@ -1100,6 +1110,8 @@
sc->sc_async_audio = 0;
sc->sc_full_duplex = 0;
+ free(sc->sc_tmpbuf, M_DEVBUF);
+ sc->sc_tmpbuf = NULL;
splx(s);
DPRINTF(("audio_close: done\n"));
@@ -1363,6 +1375,9 @@
struct audio_ringbuffer *cb = &sc->sc_pr;
u_char *inp, *einp;
int saveerror, error, s, n, cc, used;
+ int *resid;
+ int buf_resid;
+ int buf_offset;
DPRINTFN(2,("audio_write: sc=%p count=%lu used=%d(hi=%d)\n",
sc, (unsigned long)uio->uio_resid, sc->sc_pr.used,
@@ -1404,7 +1419,28 @@
sc->sc_pparams.sw_code, sc->sc_pparams.factor));
error = 0;
- while (uio->uio_resid > 0 && !error) {
+
+ /*
+ * When sw_code reduces output length from input length,
+ * a conversion by sw_code is needed before putting to
+ * ring buffer.
+ */
+ uio_loop:
+ if (sc->sc_pparams.reduce_factor > 1) {
+ n = uio->uio_resid;
+ cc = n < sc->sc_tmpbufsize ? n : sc->sc_tmpbufsize;
+ error = uiomove(sc->sc_tmpbuf, cc, uio);
+ buf_resid = n - uio->uio_resid;
+ if (!sc->sc_pparams.sw_code)
+ panic("why is sw_code NULL?");
+ sc->sc_pparams.sw_code(sc->hw_hdl, sc->sc_tmpbuf, buf_resid);
+ buf_resid /= sc->sc_pparams.reduce_factor;
+ buf_offset = 0;
+ resid = &buf_resid;
+ } else {
+ resid = &uio->uio_resid;
+ }
+ while (*resid > 0 && !error ) {
s = splaudio();
while (cb->used >= cb->usedhigh) {
DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d "
@@ -1435,8 +1471,8 @@
}
if (n < cc)
cc = n; /* don't write beyond end of buffer */
- if (uio->uio_resid < cc)
- cc = uio->uio_resid; /* and no more than we have */
+ if (*resid < cc)
+ cc = *resid; /* and no more than we have */
#ifdef DIAGNOSTIC
/*
@@ -1452,9 +1488,16 @@
#endif
DPRINTFN(1, ("audio_write: uiomove cc=%d inp=%p, left=%lu\n",
cc, inp, (unsigned long)uio->uio_resid));
+ if (sc->sc_pparams.reduce_factor > 1){
+ memcpy(inp, sc->sc_tmpbuf + buf_offset, cc);
+ *resid -= cc;
+ buf_offset += cc;
+ } else
+ {
n = uio->uio_resid;
error = uiomove(inp, cc, uio);
cc = n - uio->uio_resid; /* number of bytes actually moved */
+ }
#ifdef AUDIO_DEBUG
if (error)
printf("audio_write:(1) uiomove failed %d; cc=%d "
@@ -1464,6 +1507,7 @@
* Continue even if uiomove() failed because we may have
* gotten a partial block.
*/
+ if (sc->sc_pparams.reduce_factor == 1)
if (sc->sc_pparams.sw_code) {
sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc);
/* Adjust count after the expansion. */
@@ -1513,6 +1557,8 @@
audio_fill_silence(&sc->sc_pparams, einp, cc);
}
}
+ if (uio->uio_resid > 0)
+ goto uio_loop;
return (error);
}
@@ -1896,7 +1942,8 @@
cb->outp += blksize;
if (cb->outp >= cb->end)
cb->outp = cb->start;
- cb->stamp += blksize / sc->sc_pparams.factor;
+ cb->stamp += blksize * sc->sc_pparams.reduce_factor
+ / sc->sc_pparams.factor;
if (cb->mmapped) {
DPRINTFN(5, ("audio_pint: mmapped outp=%p cc=%d inp=%p\n",
cb->outp, blksize, cb->inp));
@@ -1947,7 +1994,7 @@
} else {
inp = cb->inp;
cc = blksize - (inp - cb->start) % blksize;
- ccr = cc / sc->sc_pparams.factor;
+ ccr = cc * sc->sc_pparams.reduce_factor / sc->sc_pparams.factor;
if (cb->pause)
cb->pdrops += ccr;
else {
Index: dev/audio_if.h
===================================================================
RCS file: /home/isaki/cvsroot/vs/src/sys/dev/audio_if.h,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- dev/audio_if.h 2001/11/03 14:36:48 1.1.1.2
+++ dev/audio_if.h 2002/02/17 09:48:36 1.4
@@ -51,6 +51,7 @@
/* Software en/decode functions, set if SW coding required by HW */
void (*sw_code)(void *, u_char *, int);
int factor; /* coding space change */
+ int reduce_factor; /* coding space change */
};
/* The default audio mode: 8 kHz mono ulaw */
Index: dev/audiovar.h
===================================================================
RCS file: /home/isaki/cvsroot/vs/src/sys/dev/audiovar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- dev/audiovar.h 2001/11/03 14:35:04 1.1.1.1
+++ dev/audiovar.h 2002/02/17 09:48:36 1.4
@@ -111,6 +111,8 @@
/* Ring buffers, separate for record and play. */
struct audio_ringbuffer sc_rr; /* Record ring */
struct audio_ringbuffer sc_pr; /* Play ring */
+ u_char *sc_tmpbuf;
+ size_t sc_tmpbufsize;
u_char sc_blkset; /* Blocksize has been set */
Index: dev/ic/msm6258.c
===================================================================
RCS file: /home/isaki/cvsroot/vs/src/sys/dev/ic/msm6258.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- dev/ic/msm6258.c 2001/11/17 12:00:28 1.1.1.2
+++ dev/ic/msm6258.c 2001/11/17 12:03:00 1.3
@@ -135,11 +135,12 @@
char *x = &(mc->mc_estim);
short *y = &(mc->mc_amp);
register int i;
+ u_char *d = p;
u_char f;
- for (i = 0; i < cc; i++) {
- f = pcm2adpcm_step(p[i], y, x);
- p[i] = f + (pcm2adpcm_step(p[i], y, x) << 4);
+ for (i = 0; i < cc; ) {
+ f = pcm2adpcm_step(p[i++], y, x);
+ *d++ = f + (pcm2adpcm_step(p[i++], y, x) << 4);
}
}
----Next_Part(Sun_Feb_24_13:58:17_2002_595)----