Modifications to aucc.c for more input formats and 14bit stereo output.

By Bernardo Innocenti, submitted as PR 6787.
Some KNF-ifying done by myself, so you might want to blame me instead
if the original patch worked for you.
	-is
This commit is contained in:
is 1999-03-04 20:45:01 +00:00
parent ad140b77ea
commit 946db35c9b
1 changed files with 603 additions and 168 deletions

View File

@ -1,6 +1,9 @@
/* $NetBSD: aucc.c,v 1.23 1998/08/17 21:16:09 augustss Exp $ */
/* $NetBSD: aucc.c,v 1.24 1999/03/04 20:45:01 is Exp $ */
/*
* Copyright (c) 1999 Bernardo Innocenti
* All rights reserved.
*
* Copyright (c) 1997 Stephan Thesing
* All rights reserved.
*
@ -30,6 +33,22 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* TODO:
*
* - ulaw -> 14bit conversion
* - channel allocation is wrong for 14bit mono
* - convert the... err... conversion routines to 68k asm for best performance
* XXX: NO. aucc audio is limited by chipmem speed, anyway. You dont
* want to make life difficult for amigappc work.
* -is
*
* - rely on auconv.c routines for ulaw/alaw conversions
* - perhaps use a calibration table for better 14bit output
* - set 31KHz AGA video mode to allow 44.1KHz even if grfcc is missing
* in the kernel
* - 14bit output requires maximum volume
*/
#include "aucc.h"
#if NAUCC > 0
@ -91,9 +110,13 @@ struct aucc_softc {
aucc_data_t sc_channel[4]; /* per channel freq, ... */
u_int sc_encoding; /* encoding AUDIO_ENCODING_.*/
int sc_channels; /* # of channels used */
int sc_precision; /* 8 or 16 bits */
int sc_14bit; /* 14bit output enabled */
int sc_intrcnt; /* interrupt count */
int sc_channelmask; /* which channels are used ? */
void (*sc_decodefunc) __P((u_char **, u_char *, int));
/* pointer to format conversion routine */
};
/* interrupt interfaces */
@ -116,7 +139,7 @@ struct cfattach aucc_ca = {
struct audio_device aucc_device = {
"Amiga-audio",
"x",
"2.0",
"aucc"
};
@ -178,11 +201,39 @@ int aucc_getdev __P((void *, struct audio_device *));
int aucc_set_port __P((void *, mixer_ctrl_t *));
int aucc_get_port __P((void *, mixer_ctrl_t *));
int aucc_query_devinfo __P((void *, mixer_devinfo_t *));
void aucc_encode __P((int, int, int, u_char *, u_short **));
void aucc_encode __P((int, int, int, int, u_char *, u_short **));
int aucc_set_params __P((void *, int, int,
struct audio_params *, struct audio_params *));
int aucc_get_props __P((void *));
static void aucc_decode_slinear8_1ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear8_2ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear8_3ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear8_4ch __P((u_char **, u_char *, int));
static void aucc_decode_ulinear8_1ch __P((u_char **, u_char *, int));
static void aucc_decode_ulinear8_2ch __P((u_char **, u_char *, int));
static void aucc_decode_ulinear8_3ch __P((u_char **, u_char *, int));
static void aucc_decode_ulinear8_4ch __P((u_char **, u_char *, int));
static void aucc_decode_ulaw_1ch __P((u_char **, u_char *, int));
static void aucc_decode_ulaw_2ch __P((u_char **, u_char *, int));
static void aucc_decode_ulaw_3ch __P((u_char **, u_char *, int));
static void aucc_decode_ulaw_4ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16_1ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16_2ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16_3ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16_4ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16sw_1ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16sw_2ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16sw_3ch __P((u_char **, u_char *, int));
static void aucc_decode_slinear16sw_4ch __P((u_char **, u_char *, int));
struct audio_hw_if sa_hw_if = {
aucc_open,
aucc_close,
@ -271,7 +322,6 @@ init_aucc(sc)
sc->sc_channel[i].nd_doublebuf=0;
DPRINTF(("dma buffer for channel %d is %p\n", i,
sc->sc_channel[i].nd_dma));
}
if (err) {
@ -282,15 +332,16 @@ init_aucc(sc)
sc->sc_channels=1;
sc->sc_channelmask=0xf;
sc->sc_precision=8;
sc->sc_14bit = 0;
sc->sc_encoding=AUDIO_ENCODING_ULAW;
sc->sc_decodefunc = aucc_decode_ulaw_1ch;
/* clear interrupts and dma: */
custom.intena = AUCC_ALLINTF;
custom.dmacon = AUCC_ALLDMAF;;
sc->sc_encoding=AUDIO_ENCODING_ULAW;
custom.dmacon = AUCC_ALLDMAF;
return err;
}
int
@ -382,6 +433,27 @@ aucc_query_encoding(addr, fp)
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
break;
case 3:
strcpy(fp->name, AudioEslinear);
fp->encoding = AUDIO_ENCODING_SLINEAR;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
break;
case 4:
strcpy(fp->name, AudioEslinear_be);
fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
break;
case 5:
strcpy(fp->name, AudioEslinear_le);
fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
break;
default:
return(EINVAL);
/*NOTREACHED*/
@ -401,32 +473,140 @@ aucc_set_params(addr, setmode, usemode, p, r)
return 0 ENXIO*/;
#ifdef AUCCDEBUG
printf("aucc_set_params(setmode 0x%x, usemode 0x%x, enc %d, bits %d, chn %d, sr %ld)\n",
setmode, usemode, p->encoding, p->precision, p->channels, p->sample_rate);
printf("aucc_set_params(setmode 0x%x, usemode 0x%x, "
"enc %d, bits %d, chn %d, sr %ld)\n", setmode, usemode,
p->encoding, p->precision, p->channels, p->sample_rate);
#endif
switch (p->precision) {
case 8:
switch (p->encoding) {
case AUDIO_ENCODING_ULAW:
switch (p->channels) {
case 1:
sc->sc_decodefunc = aucc_decode_ulaw_1ch;
break;
case 2:
sc->sc_decodefunc = aucc_decode_ulaw_2ch;
break;
case 3:
sc->sc_decodefunc = aucc_decode_ulaw_3ch;
break;
case 4:
sc->sc_decodefunc = aucc_decode_ulaw_4ch;
break;
default:
return EINVAL;
}
break;
case AUDIO_ENCODING_SLINEAR:
case AUDIO_ENCODING_SLINEAR_BE:
case AUDIO_ENCODING_SLINEAR_LE:
switch (p->channels) {
case 1:
sc->sc_decodefunc = aucc_decode_slinear8_1ch;
break;
case 2:
sc->sc_decodefunc = aucc_decode_slinear8_2ch;
break;
case 3:
sc->sc_decodefunc = aucc_decode_slinear8_3ch;
break;
case 4:
sc->sc_decodefunc = aucc_decode_slinear8_4ch;
break;
default:
return EINVAL;
}
break;
case AUDIO_ENCODING_ULINEAR:
case AUDIO_ENCODING_ULINEAR_BE:
case AUDIO_ENCODING_ULINEAR_LE:
switch (p->channels) {
case 1:
sc->sc_decodefunc = aucc_decode_ulinear8_1ch;
break;
case 2:
sc->sc_decodefunc = aucc_decode_ulinear8_2ch;
break;
case 3:
sc->sc_decodefunc = aucc_decode_ulinear8_3ch;
break;
case 4:
sc->sc_decodefunc = aucc_decode_ulinear8_4ch;
break;
default:
return EINVAL;
}
break;
default:
return EINVAL;
}
break;
case 16:
switch (p->encoding) {
#if BYTE_ORDER == BIG_ENDIAN
case AUDIO_ENCODING_SLINEAR:
#endif
case AUDIO_ENCODING_SLINEAR_BE:
switch (p->channels) {
case 1:
sc->sc_decodefunc = aucc_decode_slinear16_1ch;
break;
case 2:
sc->sc_decodefunc = aucc_decode_slinear16_2ch;
break;
case 3:
sc->sc_decodefunc = aucc_decode_slinear16_3ch;
break;
case 4:
sc->sc_decodefunc = aucc_decode_slinear16_4ch;
break;
default:
return EINVAL;
}
break;
#if BYTE_ORDER == LITTLE_ENDIAN
case AUDIO_ENCODING_SLINEAR:
#endif
case AUDIO_ENCODING_SLINEAR_LE:
switch (p->channels) {
case 1:
sc->sc_decodefunc = aucc_decode_slinear16sw_1ch;
break;
case 2:
sc->sc_decodefunc = aucc_decode_slinear16sw_2ch;
break;
case 3:
sc->sc_decodefunc = aucc_decode_slinear16sw_3ch;
break;
case 4:
sc->sc_decodefunc = aucc_decode_slinear16sw_4ch;
break;
default:
return EINVAL;
}
break;
default:
return EINVAL;
}
break;
default:
return EINVAL;
/* NOTREADCHED */
}
if (p->precision != 8)
return EINVAL;
if ((p->channels<1) || (p->channels>4))
return(EINVAL);
sc->sc_channels = p->channels;
sc->sc_encoding = p->encoding;
sc->sc_precision = p->precision;
sc->sc_14bit = ((p->precision == 16) && (p->channels <= 2));
sc->sc_channels = sc->sc_14bit ? (p->channels * 2) : p->channels;
return aucc_set_out_sr(addr, p->sample_rate);
}
@ -436,9 +616,8 @@ aucc_round_blocksize(addr, blk)
void *addr;
int blk;
{
return blk>AUDIO_BUF_SIZE?AUDIO_BUF_SIZE:blk; /* round up to even size */
/* round up to even size */
return blk > AUDIO_BUF_SIZE ? AUDIO_BUF_SIZE : blk;
}
int
@ -473,9 +652,8 @@ aucc_start_output(addr, p, cc, intr, arg)
{
struct aucc_softc *sc;
int mask;
int i,j,k;
u_short *dmap[4];
u_char *pp;
int i, j, k, len;
u_char *dmap[4];
sc = addr;
@ -491,7 +669,8 @@ aucc_start_output(addr, p, cc, intr, arg)
if (mask == 0) /* active and used channels are disjoint */
return EINVAL;
for (i=0;i<4;i++) { /* channels available ? */
for (i=0;i<4;i++) {
/* channels available ? */
if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
return EBUSY; /* channel is busy */
if (channel[i].isaudio == -1)
@ -519,33 +698,40 @@ aucc_start_output(addr, p, cc, intr, arg)
/* copy data to dma buffer */
pp=(u_char *)p;
if (sc->sc_channels == 1) {
dmap[0] =
dmap[1] =
dmap[2] =
dmap[3] = sc->sc_channel[j].nd_dma;
} else {
dmap[3] = (u_char *)sc->sc_channel[j].nd_dma;
}
else {
for (k=0; k<4; k++) {
if (masks2[k+j] & mask)
dmap[k]=sc->sc_channel[k+j].nd_dma;
dmap[k] = (u_char *)sc->sc_channel[k+j].nd_dma;
}
}
sc->sc_channel[j].nd_doublebuf ^= 1;
if (sc->sc_channel[j].nd_doublebuf) {
dmap[0] += AUDIO_BUF_SIZE/sizeof(u_short);
dmap[1] += AUDIO_BUF_SIZE/sizeof(u_short);
dmap[2] += AUDIO_BUF_SIZE/sizeof(u_short);
dmap[3] += AUDIO_BUF_SIZE/sizeof(u_short);
dmap[0] += AUDIO_BUF_SIZE;
dmap[1] += AUDIO_BUF_SIZE;
dmap[2] += AUDIO_BUF_SIZE;
dmap[3] += AUDIO_BUF_SIZE;
}
aucc_encode(sc->sc_encoding, sc->sc_channels, cc, pp, dmap);
/* compute output length in bytes per channel.
* divide by two only for 16bit->8bit conversion.
*/
len = cc / sc->sc_channels;
if (!sc->sc_14bit && (sc->sc_precision == 16))
len /= 2;
/* dma buffers: we use same buffer 4 all channels */
/* write dma location and length */
/* call audio decoding routine */
sc->sc_decodefunc (dmap, (u_char *)p, len);
/* dma buffers: we use same buffer 4 all channels
* write dma location and length
*/
for (i = k = 0; i < 4; i++) {
if (masks2[i] & mask) {
DPRINTF(("turning channel %d on\n",i));
@ -554,14 +740,16 @@ aucc_start_output(addr, p, cc, intr, arg)
channel[i].play_count = 1;
channel[i].handler = NULL;
custom.aud[i].per = sc->sc_channel[i].nd_per;
if (sc->sc_14bit && (i > 1))
custom.aud[i].vol = 1;
else
custom.aud[i].vol = sc->sc_channel[i].nd_volume;
custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
custom.aud[i].len=cc/(sc->sc_channels*2);
custom.aud[i].len = len / 2;
sc->sc_channel[i].nd_mask = mask;
DPRINTF(("per is %d, vol is %d, len is %d\n",\
sc->sc_channel[i].nd_per,
sc->sc_channel[i].nd_volume, cc>>1));
sc->sc_channel[i].nd_volume, len));
}
}
@ -649,6 +837,7 @@ aucc_set_port(addr, cp)
i=cp->un.mask;
if ((i<1) || (i>15))
return EINVAL;
sc->sc_channelmask=i;
break;
@ -796,7 +985,10 @@ aucc_inthdl(int ch)
DPRINTF(("inthandler called, channel %d, mask 0x%x\n",ch,mask));
custom.intreq=mask<<INTB_AUD0; /* clear request */
/* XXX: maybe we can leave ints and/or DMA on, if another sample has to be played?*/
/*
* XXX: maybe we can leave ints and/or DMA on,
* if another sample has to be played?
*/
custom.intena=mask<<INTB_AUD0;
/*
* XXX custom.dmacon=mask; NO!!!
@ -813,9 +1005,11 @@ aucc_inthdl(int ch)
/* call handler */
if (aucc->sc_channel[ch].nd_intr) {
DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
(*(aucc->sc_channel[ch].nd_intr))(aucc->sc_channel[ch].nd_intrdata);
(*(aucc->sc_channel[ch].nd_intr))
(aucc->sc_channel[ch].nd_intrdata);
}
else DPRINTF(("zero int handler\n"));
else
DPRINTF(("zero int handler\n"));
DPRINTF(("ints done\n"));
}
@ -824,8 +1018,7 @@ aucc_inthdl(int ch)
/* transform frequency to period, adjust bounds */
static u_int
freqtoper(u_int freq)
{
freqtoper(u_int freq) {
u_int per=eclockfreq*5/freq;
if (per<124)
@ -836,80 +1029,322 @@ freqtoper(u_int freq)
/* transform period to frequency */
static u_int
pertofreq(u_int per)
{
pertofreq(u_int per) {
u_int freq=eclockfreq*5/per;
return freq;
}
static void aucc_decode_slinear8_1ch (u_char **dmap, u_char *p, int i) {
memcpy (dmap[0], p, i);
}
static void aucc_decode_slinear8_2ch (u_char **dmap, u_char *p, int i) {
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
void
aucc_encode(enc, channels, i, p, dmap)
int enc, channels, i;
while (i--) {
*ch0++ = *p++;
*ch1++ = *p++;
}
}
static void aucc_decode_slinear8_3ch (u_char **dmap, u_char *p, int i) {
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
while (i--) {
*ch0++ = *p++;
*ch1++ = *p++;
*ch2++ = *p++;
}
}
static void aucc_decode_slinear8_4ch (u_char **dmap, u_char *p, int i) {
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch0++ = *p++;
*ch1++ = *p++;
*ch2++ = *p++;
*ch3++ = *p++;
}
}
static void
aucc_decode_ulinear8_1ch (dmap, p, i)
u_char **dmap;
u_char *p;
u_short **dmap;
int i;
{
char *q, *r, *s, *t;
int off;
u_char *tab;
u_char *ch0 = dmap[0];
#ifdef AUCCDEBUG
static int debctl = 6;
#endif
off = 0;
tab = NULL;
#ifdef AUCCDEBUG
if (--debctl >= 0)
printf("Enc: enc %d, chan %d, dmap %p %p %p %p\n",
enc, channels, dmap[0], dmap[1], dmap[2], dmap[3]);
#endif
switch (enc) {
case AUDIO_ENCODING_ULAW:
tab=ulaw_to_lin;
break;
case AUDIO_ENCODING_ULINEAR_BE:
case AUDIO_ENCODING_ULINEAR_LE:
off=-128;
break;
case AUDIO_ENCODING_SLINEAR_BE:
case AUDIO_ENCODING_SLINEAR_LE:
break;
default:
return;
while (i--)
*ch0++ = *p++ - 128;
}
q = (char *)dmap[0];
r = (char *)dmap[1];
s = (char *)dmap[2];
t = (char *)dmap[3];
static void
aucc_decode_ulinear8_2ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
if (tab)
while (i) {
switch (channels) {
case 4: *t++ = tab[*p++];
case 3: *s++ = tab[*p++];
case 2: *r++ = tab[*p++];
case 1: *q++ = tab[*p++];
while (i--) {
*ch0++ = *p++ - 128;
*ch1++ = *p++ - 128;
}
i -= channels;
}
else
while (i) {
switch (channels) {
case 4: *t++ = *p++ + off;
case 3: *s++ = *p++ + off;
case 2: *r++ = *p++ + off;
case 1: *q++ = *p++ + off;
}
i -= channels;
}
static void
aucc_decode_ulinear8_3ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
while (i--) {
*ch0++ = *p++ - 128;
*ch1++ = *p++ - 128;
*ch2++ = *p++ - 128;
}
}
static void
aucc_decode_ulinear8_4ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch0++ = *p++ - 128;
*ch1++ = *p++ - 128;
*ch2++ = *p++ - 128;
*ch3++ = *p++ - 128;
}
}
static void
aucc_decode_ulaw_1ch (dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
while (i--)
*ch0++ = ulaw_to_lin[*p++];
}
static void
aucc_decode_ulaw_2ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
while (i--) {
*ch0++ = ulaw_to_lin[*p++];
*ch1++ = ulaw_to_lin[*p++];
}
}
static void
aucc_decode_ulaw_3ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
while (i--) {
*ch0++ = ulaw_to_lin[*p++];
*ch1++ = ulaw_to_lin[*p++];
*ch2++ = ulaw_to_lin[*p++];
}
}
static void
aucc_decode_ulaw_4ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch0++ = ulaw_to_lin[*p++];
*ch1++ = ulaw_to_lin[*p++];
*ch2++ = ulaw_to_lin[*p++];
*ch3++ = ulaw_to_lin[*p++];
}
}
/* 14bit output */
static void
aucc_decode_slinear16_1ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch3 = dmap[1]; /* XXX should be 3 */
while (i--) {
*ch0++ = *p++;
*ch3++ = *p++ >> 2;
}
}
/* 14bit stereo output */
static void
aucc_decode_slinear16_2ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch0++ = *p++;
*ch3++ = *p++ >> 2;
*ch1++ = *p++;
*ch2++ = *p++ >> 2;
}
}
static void
aucc_decode_slinear16_3ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
while (i--) {
*ch0++ = *p++; p++;
*ch1++ = *p++; p++;
*ch2++ = *p++; p++;
}
}
static void
aucc_decode_slinear16_4ch (dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch0++ = *p++; p++;
*ch1++ = *p++; p++;
*ch2++ = *p++; p++;
*ch3++ = *p++; p++;
}
}
/* 14bit output, swap bytes */
static void
aucc_decode_slinear16sw_1ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch3 = dmap[3];
while (i--) {
*ch3++ = *p++ >> 2;
*ch0++ = *p++;
}
}
static void
aucc_decode_slinear16sw_2ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
*ch3++ = *p++ >> 2;
*ch0++ = *p++;
*ch2++ = *p++ >> 2;
*ch1++ = *p++;
}
}
static void
aucc_decode_slinear16sw_3ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
while (i--) {
p++; *ch0++ = *p++;
p++; *ch1++ = *p++;
p++; *ch2++ = *p++;
}
}
static void
aucc_decode_slinear16sw_4ch(dmap, p, i)
u_char **dmap;
u_char *p;
int i;
{
u_char *ch0 = dmap[0];
u_char *ch1 = dmap[1];
u_char *ch2 = dmap[2];
u_char *ch3 = dmap[3];
while (i--) {
p++; *ch0++ = *p++;
p++; *ch1++ = *p++;
p++; *ch2++ = *p++;
p++; *ch3++ = *p++;
}
}
#endif /* NAUCC > 0 */