Correct playing mu-law and linear.

This commit is contained in:
minoura 2001-05-03 02:09:11 +00:00
parent 5c15afd718
commit 58b62ea0cf
3 changed files with 80 additions and 63 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vs.c,v 1.1 2001/05/02 13:00:20 minoura Exp $ */ /* $NetBSD: vs.c,v 1.2 2001/05/03 02:09:12 minoura Exp $ */
/* /*
* Copyright (c) 2001 Tetsuya Isaki. All rights reserved. * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
@ -100,8 +100,8 @@ static size_t vs_round_buffersize __P((void *, int, size_t));
static int vs_get_props __P((void *)); static int vs_get_props __P((void *));
/* lower functions */ /* lower functions */
static u_long vs_round_sr(u_long); static int vs_round_sr(u_long);
static void vs_set_sr(struct vs_softc *sc, u_long); static void vs_set_sr(struct vs_softc *sc, int);
static inline void vs_set_po(struct vs_softc *sc, u_long); static inline void vs_set_po(struct vs_softc *sc, u_long);
static int adpcm_estimindex[]; static int adpcm_estimindex[];
static int adpcm_estim[]; static int adpcm_estim[];
@ -160,18 +160,18 @@ static struct audio_device vs_device = {
}; };
struct { struct {
u_long low;
u_long rate; u_long rate;
u_char clk; u_char clk;
u_char den; u_char den;
} vs_l2r[] = { } vs_l2r[] = {
{ 13021, VS_RATE_15K, VS_CLK_8MHZ, VS_SRATE_512 }, { VS_RATE_15K, VS_CLK_8MHZ, VS_SRATE_512 },
{ 9115, VS_RATE_10K, VS_CLK_8MHZ, VS_SRATE_768 }, { VS_RATE_10K, VS_CLK_8MHZ, VS_SRATE_768 },
{ 6510, VS_RATE_7K, VS_CLK_8MHZ, VS_SRATE_1024}, { VS_RATE_7K, VS_CLK_8MHZ, VS_SRATE_1024},
{ 4557, VS_RATE_5K, VS_CLK_4MHZ, VS_SRATE_768 }, { VS_RATE_5K, VS_CLK_4MHZ, VS_SRATE_768 },
{ 0, VS_RATE_3K, VS_CLK_4MHZ, VS_SRATE_1024} { VS_RATE_3K, VS_CLK_4MHZ, VS_SRATE_1024}
}; };
#define NUM_RATE (sizeof(vs_l2r)/sizeof(vs_l2r[0]))
static int static int
vs_match(struct device *parent, struct cfdata *cf, void *aux) vs_match(struct device *parent, struct cfdata *cf, void *aux)
@ -258,24 +258,24 @@ vs_dmaintr(void *hdl)
if (sc->sc_pintr) { if (sc->sc_pintr) {
/* start next transfer */ /* start next transfer */
sc->sc_current.dmap += sc->sc_current.rawblk; sc->sc_current.dmap += sc->sc_current.blksize;
if (sc->sc_current.dmap + sc->sc_current.rawblk if (sc->sc_current.dmap + sc->sc_current.blksize
> sc->sc_current.bufsize) > sc->sc_current.bufsize)
sc->sc_current.dmap -= sc->sc_current.bufsize; sc->sc_current.dmap -= sc->sc_current.bufsize;
dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc, dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc,
sc->sc_current.xfer, sc->sc_current.xfer,
sc->sc_current.dmap, sc->sc_current.dmap,
sc->sc_current.hwblk); sc->sc_current.blksize);
sc->sc_pintr(sc->sc_parg); sc->sc_pintr(sc->sc_parg);
} else if (sc->sc_rintr) { } else if (sc->sc_rintr) {
/* start next transfer */ /* start next transfer */
sc->sc_current.dmap += sc->sc_current.rawblk; sc->sc_current.dmap += sc->sc_current.blksize;
if (sc->sc_current.dmap + sc->sc_current.rawblk if (sc->sc_current.dmap + sc->sc_current.blksize
>= sc->sc_current.bufsize) >= sc->sc_current.bufsize)
dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc, dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc,
sc->sc_current.xfer, sc->sc_current.xfer,
sc->sc_current.dmap, sc->sc_current.dmap,
sc->sc_current.hwblk); sc->sc_current.blksize);
sc->sc_rintr(sc->sc_rarg); sc->sc_rintr(sc->sc_rarg);
} else { } else {
printf ("vs_dmaintr: spurious interrupt\n"); printf ("vs_dmaintr: spurious interrupt\n");
@ -349,15 +349,30 @@ vs_query_encoding(void *hdl, struct audio_encoding *fp)
return 0; return 0;
} }
static u_long static int
vs_round_sr(u_long rate) vs_round_sr(u_long rate)
{ {
int i; int i;
for (i = 0; i < 5; i++) { int diff = rate;
if (rate >= vs_l2r[i].low) int nearest = 0;
return vs_l2r[i].rate;
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;
} }
/*NOTREACHED*/ } else {
if (vs_l2r[i].rate - rate < diff) {
diff = vs_l2r[i].rate - rate;
nearest = i;
}
}
}
if (diff * 100 / rate > 15)
return -1;
else
return nearest;
} }
static int static int
@ -367,10 +382,10 @@ vs_set_params(void *hdl, int setmode, int usemode,
struct vs_softc *sc = hdl; struct vs_softc *sc = hdl;
struct audio_params *p; struct audio_params *p;
int mode; int mode;
int rate;
DPRINTF(("vs_set_params: setmode=%d, usemode=%d\n", setmode, usemode)); DPRINTF(("vs_set_params: setmode=%d, usemode=%d\n", setmode, usemode));
sc->sc_current.pdenom = 1;
/* set first record info, then play info */ /* set first record info, then play info */
for (mode = AUMODE_RECORD; mode != -1; for (mode = AUMODE_RECORD; mode != -1;
mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) { mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) {
@ -382,8 +397,7 @@ vs_set_params(void *hdl, int setmode, int usemode,
if (p->channels != 1) if (p->channels != 1)
return (EINVAL); return (EINVAL);
p->sample_rate = vs_round_sr(p->sample_rate); rate = p->sample_rate;
p->sw_code = NULL; p->sw_code = NULL;
p->factor = 1; p->factor = 1;
switch (p->encoding) { switch (p->encoding) {
@ -392,7 +406,7 @@ vs_set_params(void *hdl, int setmode, int usemode,
return EINVAL; return EINVAL;
if (mode == AUMODE_PLAY) { if (mode == AUMODE_PLAY) {
p->sw_code = msm6258_mulaw_to_adpcm; p->sw_code = msm6258_mulaw_to_adpcm;
sc->sc_current.pdenom = 2; rate = p->sample_rate * 2;
} else { } else {
p->sw_code = msm6258_adpcm_to_mulaw; p->sw_code = msm6258_adpcm_to_mulaw;
p->factor = 2; p->factor = 2;
@ -404,7 +418,7 @@ vs_set_params(void *hdl, int setmode, int usemode,
return EINVAL; return EINVAL;
if (mode == AUMODE_PLAY) { if (mode == AUMODE_PLAY) {
p->sw_code = msm6258_ulinear8_to_adpcm; p->sw_code = msm6258_ulinear8_to_adpcm;
sc->sc_current.pdenom = 2; rate = p->sample_rate * 2;
} else { } else {
p->sw_code = msm6258_adpcm_to_ulinear8; p->sw_code = msm6258_adpcm_to_ulinear8;
p->factor = 2; p->factor = 2;
@ -413,34 +427,34 @@ vs_set_params(void *hdl, int setmode, int usemode,
case AUDIO_ENCODING_ADPCM: case AUDIO_ENCODING_ADPCM:
if (p->precision != 4) if (p->precision != 4)
return EINVAL; return EINVAL;
p->sw_code = NULL;
break; break;
default: default:
DPRINTF(("vs_set_params: mode=%d, encoding=%d\n", DPRINTF(("vs_set_params: mode=%d, encoding=%d\n",
mode, p->encoding)); mode, p->encoding));
return (EINVAL); return (EINVAL);
} }
rate = vs_round_sr(rate);
if (rate < 0)
return (EINVAL);
if (mode == AUMODE_PLAY)
sc->sc_current.prate = rate;
else
sc->sc_current.rrate = rate;
} }
return 0; return 0;
} }
static void static void
vs_set_sr(struct vs_softc *sc, u_long rate) vs_set_sr(struct vs_softc *sc, int rate)
{ {
int i; DPRINTF(("setting sample rate to %d, %d\n",
for (i = 0; i < 5; i++) { rate, (int)vs_l2r[rate].rate));
if (rate >= vs_l2r[i].low) {
bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC, bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC,
(bus_space_read_1 (sc->sc_iot, (bus_space_read_1 (sc->sc_iot, sc->sc_ppi,
sc->sc_ppi,
PPI_PORTC) & 0xf0) PPI_PORTC) & 0xf0)
| vs_l2r[i].den); | vs_l2r[rate].den);
adpcm_chgclk(vs_l2r[i].clk); adpcm_chgclk(vs_l2r[rate].clk);
return;
}
}
/*NOTREACHED*/
} }
static inline void static inline void
@ -467,8 +481,7 @@ vs_trigger_output(void *hdl, void *start, void *end, int bsize,
sc->sc_pintr = intr; sc->sc_pintr = intr;
sc->sc_parg = arg; sc->sc_parg = arg;
sc->sc_current.rawblk = bsize; sc->sc_current.blksize = bsize;
sc->sc_current.hwblk = bsize / sc->sc_current.pdenom;;
sc->sc_current.bufsize = (char*)end - (char*)start; sc->sc_current.bufsize = (char*)end - (char*)start;
sc->sc_current.dmap = 0; sc->sc_current.dmap = 0;
@ -482,8 +495,9 @@ vs_trigger_output(void *hdl, void *start, void *end, int bsize,
return (EINVAL); return (EINVAL);
} }
vs_set_sr(sc, p->sample_rate); vs_set_sr(sc, sc->sc_current.prate);
vs_set_po(sc, VS_PANOUT_LR); vs_set_po(sc, VS_PANOUT_LR);
xf = dmac_alloc_xfer (chan, sc->sc_dmat, vd->vd_map); xf = dmac_alloc_xfer (chan, sc->sc_dmat, vd->vd_map);
sc->sc_current.xfer = xf; sc->sc_current.xfer = xf;
chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC |
@ -492,10 +506,9 @@ vs_trigger_output(void *hdl, void *start, void *end, int bsize,
xf->dx_ocr = DMAC_OCR_DIR_MTD; xf->dx_ocr = DMAC_OCR_DIR_MTD;
xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT;
xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1;
if (sc->sc_current.pdenom == 2)
chan->ch_ocr |= DMAC_OCR_SIZE_BYTE_NOPACK;
dmac_load_xfer (chan->ch_softc, xf); dmac_load_xfer (chan->ch_softc, xf);
dmac_start_xfer_offset (chan->ch_softc, xf, 0, sc->sc_current.hwblk); dmac_start_xfer_offset (chan->ch_softc, xf, 0, sc->sc_current.blksize);
bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 2); bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 2);
return 0; return 0;
@ -508,6 +521,8 @@ vs_trigger_input(void *hdl, void *start, void *end, int bsize,
{ {
struct vs_softc *sc = hdl; struct vs_softc *sc = hdl;
struct vs_dma *vd; struct vs_dma *vd;
struct dmac_dma_xfer *xf;
struct dmac_channel_stat *chan = sc->sc_dma_ch;
DPRINTF(("vs_trigger_input\n")); DPRINTF(("vs_trigger_input\n"));
DPRINTF(("trigger_input: start=%p, bsize=%d, intr=%p, arg=%p\n", DPRINTF(("trigger_input: start=%p, bsize=%d, intr=%p, arg=%p\n",
@ -515,8 +530,7 @@ vs_trigger_input(void *hdl, void *start, void *end, int bsize,
sc->sc_rintr = intr; sc->sc_rintr = intr;
sc->sc_rarg = arg; sc->sc_rarg = arg;
sc->sc_current.rawblk = bsize; sc->sc_current.blksize = bsize;
sc->sc_current.hwblk = bsize;
sc->sc_current.bufsize = (char*)end - (char*)start; sc->sc_current.bufsize = (char*)end - (char*)start;
sc->sc_current.dmap = 0; sc->sc_current.dmap = 0;
@ -530,14 +544,18 @@ vs_trigger_input(void *hdl, void *start, void *end, int bsize,
return (EINVAL); return (EINVAL);
} }
vs_set_sr(sc, p->sample_rate); vs_set_sr(sc, sc->sc_current.rrate);
sc->sc_current.xfer xf = dmac_alloc_xfer (chan, sc->sc_dmat, vd->vd_map);
= dmac_prepare_xfer (sc->sc_dma_ch, sc->sc_dmat, vd->vd_map, sc->sc_current.xfer = xf;
DMAC_OCR_DIR_DTM, chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC |
DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT, DMAC_DCR_OPS_8BIT);
sc->sc_addr + MSM6258_DATA*2); chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL;
dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc, sc->sc_current.xfer, xf->dx_ocr = DMAC_OCR_DIR_DTM;
0, sc->sc_current.hwblk); xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT;
xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1;
dmac_load_xfer (chan->ch_softc, xf);
dmac_start_xfer_offset (chan->ch_softc, xf, 0, sc->sc_current.blksize);
bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 4); bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 4);
return 0; return 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: vsvar.h,v 1.1 2001/05/02 13:00:20 minoura Exp $ */ /* $NetBSD: vsvar.h,v 1.2 2001/05/03 02:09:12 minoura Exp $ */
/* /*
* Copyright (c) 2001 Tetsuya Isaki. All rights reserved. * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
@ -95,8 +95,8 @@ struct vs_softc {
struct { struct {
struct dmac_dma_xfer *xfer; struct dmac_dma_xfer *xfer;
int pdenom; int prate, rrate;
int bufsize, rawblk, hwblk; int bufsize, blksize;
int dmap; int dmap;
} sc_current; } sc_current;

View File

@ -1,4 +1,4 @@
/* $NetBSD: msm6258.c,v 1.2 2001/05/02 13:34:33 minoura Exp $ */ /* $NetBSD: msm6258.c,v 1.3 2001/05/03 02:09:11 minoura Exp $ */
/* /*
* Copyright (c) 2001 Tetsuya Isaki. All rights reserved. * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
@ -133,10 +133,9 @@ msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
register int i; register int i;
u_char f; u_char f;
for (i = 0; i < cc; i += 2) { for (i = 0; i < cc; i++) {
f = pcm2adpcm_step(p[i], y, x); f = pcm2adpcm_step(p[i], y, x);
p[i] = f + (pcm2adpcm_step(p[i+1], y, x) << 4); p[i] = f + (pcm2adpcm_step(p[i], y, x) << 4);
p[i+1] = 0;
} }
} }