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.2 retrieving revision 1.8 diff -u -r1.1.1.2 -r1.8 --- arch/x68k/dev/vs.c 2001/11/13 09:45:57 1.1.1.2 +++ arch/x68k/dev/vs.c 2001/11/13 09:48:46 1.8 @@ -99,10 +99,20 @@ static int vs_get_props __P((void *)); /* lower functions */ -static int vs_round_sr(u_long); +static int vs_round_sr1(u_long, int); +static int vs_round_sr(u_long, int*); static void vs_set_sr(struct vs_softc *sc, int); static inline void vs_set_po(struct vs_softc *sc, u_long); +static void vs_mulaw_to_adpcm2(void *, u_char *, int); +static void vs_mulaw_to_adpcm3(void *, u_char *, int); +static void vs_mulaw_to_adpcm4(void *, u_char *, int); +static void vs_ulinear8_to_adpcm2(void *, u_char *, int); +static void vs_ulinear8_to_adpcm3(void *, u_char *, int); +static void vs_ulinear8_to_adpcm4(void *, u_char *, int); +static void vs_to_adpcm_multi(void *, u_char *, int, + void (*)(void *, u_char *, int), int); + extern struct cfdata vs_cd; struct cfattach vs_ca = { @@ -339,32 +349,50 @@ } static int -vs_round_sr(u_long rate) +vs_round_sr1(u_long rate, int p) { int i; + int d; int diff = rate; int nearest = 0; for (i = 0; i < NUM_RATE; i++) { - if (rate >= vs_l2r[i].rate) { - if (rate - vs_l2r[i].rate < diff) { - diff = rate - vs_l2r[i].rate; - nearest = i; - } - } else { - if (vs_l2r[i].rate - rate < diff) { - diff = vs_l2r[i].rate - rate; - nearest = i; - } + d = rate - vs_l2r[i].rate; + d = d < 0 ? -d : d; + if (d < diff) { + diff = d; + nearest = i; } } - if (diff * 100 / rate > 15) + if (diff * 100 / rate > p) return -1; else return nearest; } static int +vs_round_sr(u_long rate, int *m) +{ + int per[] = {8, 15}; + int i, j; + int r; + int p; + int multiple; +#define MAX_MULTIPLE (4) + + for (i = 0; i < sizeof(per)/sizeof(per[0]); i++) { + for (j = 1; j <= MAX_MULTIPLE; j++) { + r = vs_round_sr1(rate / j, per[i]); + if (r >= 0) { + *m = j; + return r; + } + } + } + return -1; +} + +static int vs_set_params(void *hdl, int setmode, int usemode, struct audio_params *play, struct audio_params *rec) { @@ -372,6 +400,7 @@ struct audio_params *p; int mode; int rate; + int multi; DPRINTF(1, ("vs_set_params: setmode=%d, usemode=%d\n", setmode, usemode)); @@ -386,16 +415,42 @@ if (p->channels != 1) return (EINVAL); - rate = p->sample_rate; p->sw_code = NULL; p->factor = 1; +#ifdef AUDIO_REDUCE + p->reduce_factor = 1; +#endif + DPRINTF(1, ("vs_set_params: encoding=%d, precision=%d\n", + p->encoding, p->precision)); + + DPRINTF(1, ("vs_set_params: rate=%d -> ", rate)); + rate = vs_round_sr(p->sample_rate, &multi); + DPRINTF(1, ("%d * %d\n", rate, multi)); + if (rate < 0) + return (EINVAL); + 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; + switch (multi) { + case 1: + p->sw_code = msm6258_mulaw_to_adpcm; + break; + case 2: + p->sw_code = vs_mulaw_to_adpcm2; + break; + case 3: + p->sw_code = vs_mulaw_to_adpcm3; + break; + case 4: + p->sw_code = vs_mulaw_to_adpcm4; + break; + } +#ifdef AUDIO_REDUCE + p->reduce_factor = 2 * multi; +#endif } else { p->sw_code = msm6258_adpcm_to_mulaw; p->factor = 2; @@ -406,15 +461,30 @@ if (p->precision != 8) return EINVAL; if (mode == AUMODE_PLAY) { - p->sw_code = msm6258_ulinear8_to_adpcm; - rate = p->sample_rate * 2; + switch (multi) { + case 1: + p->sw_code = msm6258_ulinear8_to_adpcm; + break; + case 2: + p->sw_code = vs_ulinear8_to_adpcm2; + break; + case 3: + p->sw_code = vs_ulinear8_to_adpcm3; + break; + case 4: + p->sw_code = vs_ulinear8_to_adpcm4; + break; + } +#ifdef AUDIO_REDUCE + p->reduce_factor = 2 * multi; +#endif } else { p->sw_code = msm6258_adpcm_to_ulinear8; p->factor = 2; } break; case AUDIO_ENCODING_ADPCM: - if (p->precision != 4) + if (p->precision != 4 || multi > 1) return EINVAL; break; default: @@ -422,11 +492,6 @@ mode, p->encoding)); return (EINVAL); } - DPRINTF(1, ("vs_set_params: rate=%d -> ", rate)); - rate = vs_round_sr(rate); - DPRINTF(1, ("%d\n", rate)); - if (rate < 0) - return (EINVAL); if (mode == AUMODE_PLAY) sc->sc_current.prate = rate; else @@ -765,4 +830,55 @@ DPRINTF(1, ("vs_get_props\n")); return 0 /* | dependent | half duplex | no mmap */; } + +static void +vs_mulaw_to_adpcm2(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_mulaw_to_adpcm, 2); +} + +static void +vs_mulaw_to_adpcm3(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_mulaw_to_adpcm, 3); +} + +static void +vs_mulaw_to_adpcm4(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_mulaw_to_adpcm, 4); +} + +static void +vs_ulinear8_to_adpcm2(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_ulinear8_to_adpcm, 2); +} + +static void +vs_ulinear8_to_adpcm3(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_ulinear8_to_adpcm, 3); +} + +static void +vs_ulinear8_to_adpcm4(void *hdl, u_char *p, int cc) +{ + vs_to_adpcm_multi(hdl, p, cc, msm6258_ulinear8_to_adpcm, 4); +} + +static void +vs_to_adpcm_multi(void *hdl, u_char *p, int cc, + void (*sw_code)(void*, u_char*, int), int multi) +{ + int i; + u_char *d = p; + + for (i = 0; i < cc; i++) { + if (i % multi == 0) + *d++ = p[i]; + } + sw_code(hdl, p, cc); +} + #endif /* NAUDIO > 0 && NVS > 0*/ Index: dev/audio.c =================================================================== RCS file: /home/isaki/cvsroot/vs/src/sys/dev/audio.c,v retrieving revision 1.1.1.3 retrieving revision 1.19 diff -u -r1.1.1.3 -r1.19 --- dev/audio.c 2001/11/17 12:00:28 1.1.1.3 +++ dev/audio.c 2001/11/18 02:42:39 1.19 @@ -184,7 +184,11 @@ /* The default audio mode: 8 kHz mono ulaw */ struct audio_params audio_default = +#ifdef AUDIO_REDUCE + { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1, 1 }; +#else { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1 }; +#endif struct cfattach audio_ca = { sizeof(struct audio_softc), audioprobe, audioattach, @@ -934,6 +938,16 @@ } #endif +#ifdef AUDIO_REDUCE + /* + * 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; +#endif + AUDIO_INITINFO(&ai); ai.record.sample_rate = sc->sc_rparams.sample_rate; ai.record.encoding = sc->sc_rparams.encoding; @@ -959,6 +973,10 @@ sc->sc_open = 0; sc->sc_mode = 0; sc->sc_full_duplex = 0; +#ifdef AUDIO_REDUCE + free(sc->sc_tmpbuf, M_DEVBUF); + sc->sc_tmpbuf = NULL; +#endif return error; } @@ -1105,6 +1123,10 @@ sc->sc_async_audio = 0; sc->sc_full_duplex = 0; +#ifdef AUDIO_REDUCE + free(sc->sc_tmpbuf, M_DEVBUF); + sc->sc_tmpbuf = NULL; +#endif splx(s); DPRINTF(("audio_close: done\n")); @@ -1368,6 +1390,11 @@ struct audio_ringbuffer *cb = &sc->sc_pr; u_char *inp, *einp; int saveerror, error, s, n, cc, used; +#ifdef AUDIO_REDUCE + int *resid; + int buf_resid; + int buf_offset; +#endif DPRINTFN(2,("audio_write: sc=%p count=%lu used=%d(hi=%d)\n", sc, (unsigned long)uio->uio_resid, sc->sc_pr.used, @@ -1409,7 +1436,31 @@ sc->sc_pparams.sw_code, sc->sc_pparams.factor)); error = 0; +#ifdef AUDIO_REDUCE + /* + * 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 ) { +#else while (uio->uio_resid > 0 && !error) { +#endif s = splaudio(); while (cb->used >= cb->usedhigh) { DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d " @@ -1440,8 +1491,13 @@ } if (n < cc) cc = n; /* don't write beyond end of buffer */ +#ifdef AUDIO_REDUCE + if (*resid < cc) + cc = *resid; +#else if (uio->uio_resid < cc) cc = uio->uio_resid; /* and no more than we have */ +#endif #ifdef DIAGNOSTIC /* @@ -1457,9 +1513,18 @@ #endif DPRINTFN(1, ("audio_write: uiomove cc=%d inp=%p, left=%lu\n", cc, inp, (unsigned long)uio->uio_resid)); +#ifdef AUDIO_REDUCE + if (sc->sc_pparams.reduce_factor > 1){ + memcpy(inp, sc->sc_tmpbuf + buf_offset, cc); + *resid -= cc; + buf_offset += cc; + } else +#endif + { 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 " @@ -1469,6 +1534,9 @@ * Continue even if uiomove() failed because we may have * gotten a partial block. */ +#ifdef AUDIO_REDUCE + if (sc->sc_pparams.reduce_factor == 1) +#endif if (sc->sc_pparams.sw_code) { sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc); /* Adjust count after the expansion. */ @@ -1518,6 +1586,10 @@ audio_fill_silence(&sc->sc_pparams, einp, cc); } } +#ifdef AUDIO_REDUCE + if (uio->uio_resid > 0) + goto uio_loop; +#endif return (error); } @@ -1901,7 +1973,12 @@ cb->outp += blksize; if (cb->outp >= cb->end) cb->outp = cb->start; +#ifdef AUDIO_REDUCE + cb->stamp += blksize * sc->sc_pparams.reduce_factor + / sc->sc_pparams.factor; +#else cb->stamp += blksize / sc->sc_pparams.factor; +#endif if (cb->mmapped) { DPRINTFN(5, ("audio_pint: mmapped outp=%p cc=%d inp=%p\n", cb->outp, blksize, cb->inp)); @@ -1952,7 +2029,11 @@ } else { inp = cb->inp; cc = blksize - (inp - cb->start) % blksize; +#ifdef AUDIO_REDUCE + ccr = cc * sc->sc_pparams.reduce_factor / sc->sc_pparams.factor; +#else ccr = cc / sc->sc_pparams.factor; +#endif 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.3 diff -u -r1.1.1.2 -r1.3 --- dev/audio_if.h 2001/11/03 14:36:48 1.1.1.2 +++ dev/audio_if.h 2001/11/11 12:03:41 1.3 @@ -51,6 +51,9 @@ /* Software en/decode functions, set if SW coding required by HW */ void (*sw_code)(void *, u_char *, int); int factor; /* coding space change */ +#ifdef AUDIO_REDUCE + int reduce_factor; /* coding space change */ +#endif }; /* 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.3 diff -u -r1.1.1.1 -r1.3 --- dev/audiovar.h 2001/11/03 14:35:04 1.1.1.1 +++ dev/audiovar.h 2001/11/13 14:42:25 1.3 @@ -111,6 +111,10 @@ /* Ring buffers, separate for record and play. */ struct audio_ringbuffer sc_rr; /* Record ring */ struct audio_ringbuffer sc_pr; /* Play ring */ +#ifdef AUDIO_REDUCE + u_char *sc_tmpbuf; + size_t sc_tmpbufsize; +#endif 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); } }