$NetBSD$

*** /dev/null	Fri Mar  6 05:54:22 1998
--- dacio-netbsd.c	Fri Mar  6 06:51:04 1998
***************
*** 0 ****
--- 1,278 ----
+ #include <stdio.h>	/*(perror)*/
+ #include <fcntl.h>	/*O_WRONLY*/
+ #include <sys/ioctl.h>	/*(ioctl)*/
+ #include <string.h>	/*(memset)*/
+ #include <unistd.h>	/*(write)*/
+ #include <sys/audioio.h> /*SNDCTL_XXX*/
+ #include <errno.h>	/*EINTR*/
+ #include "defs.h"	/*u8,u16*/
+ #include "dacio.h"	/*(dacioXXX)*/
+ #include "mem.h"	/*(memPerm)*/
+ 
+ #if 0
+ #define LIM_SIZE (32 * 256) /* 32ch * 8bit */
+ 
+ static u8 *lim;
+ 
+ static void
+ makeLim(void)
+ {
+     u8 *p;
+     i15x i;
+ 
+     lim = (u8 *)memPerm(LIM_SIZE) + LIM_SIZE/2;
+     p = lim-128;
+     for (i = 0; i < 256; i++, p++) *p = i;
+     for (; p < lim + LIM_SIZE/2; p++) *p = 255;
+ }
+ #endif
+ 
+ static int fd;
+ 
+ #ifndef DAC_DEV
+ #define DAC_DEV	"/dev/audio"
+ #endif
+ 
+ void
+ dacioInit(void)
+ {
+     fd = open(DAC_DEV, O_WRONLY);
+     if (fd < 0) {
+ 	perror("dacioInit");
+ 	exit(1);
+     }
+     /*makeLim();*/
+ }
+ 
+ static struct {
+     union {
+ 	u8 *p8;
+ 	i15 *p16;
+     } p;
+     u8 *top;
+     u8 *bot;
+     int size;
+     int shift;
+ } buf;
+ 
+ #define bufRest() ((buf.bot - buf.p.p8) >> buf.shift)
+ 
+ static DacioConfInfo dci;
+ 
+ void
+ dacioConf(DacioConfInfo *dcp)
+ {
+     audio_info_t info;
+ 
+ #if 0
+     if (ioctl(fd, AUDIO_FLUSH, 0) < 0) {
+ 	perror("dacioConf");
+ 	exit(1);
+     }
+ #endif
+     AUDIO_INITINFO(&info);
+     info.play.encoding = AUDIO_ENCODING_LINEAR;
+     info.play.precision = dcp->bits;
+     info.play.channels = dcp->stereo ? 2 : 1;
+     info.play.sample_rate = dcp->speed;
+     if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
+ 	perror("dacioConf");
+ 	exit(1);
+     }
+     /*fprintf(stderr, "fmt = 0x%x\n", tmp);*/
+ 
+     if (ioctl(fd, AUDIO_GETINFO, &info) < 0) {
+ 	perror("dacioConf");
+ 	exit(1);
+     }
+     buf.size = info.play.buffer_size;
+     /*fprintf(stderr, "buffer size = 0x%x\n", buf.size);*/
+     dci = *dcp;
+     /*if (buf.top != NULL) free(buf.top);*/
+     buf.top = memPerm(buf.size);
+     buf.p.p8 = buf.top;
+     buf.bot = buf.top + buf.size;
+     buf.shift = dci.stereo + ffs(dci.bits / 8) - 1;
+ }
+ 
+ void
+ dacioSync(void)
+ {
+     if (ioctl(fd, AUDIO_DRAIN, 0) < 0) {
+ 	perror("dacioSync");
+ 	exit(1);
+     }
+ }
+ 
+ /* OS independent part (?) */
+ 
+ void
+ dacioFlush(void)
+ {
+     i15x n;
+     u8 *u8p;
+     i15 *i15p;
+     int s;
+ 
+     if (buf.p.p8 <= buf.top) return;
+ 
+     n = bufRest() << dci.stereo;
+     switch (dci.bits) {
+     case 8:
+ 	u8p = buf.p.p8;
+ 	for (; n > 0; n--)
+ 	    *u8p++ = 128;
+ 	buf.p.p8 = u8p;
+ 	break;
+     case 16:
+ 	i15p = buf.p.p16;
+ 	for (; n > 0; n--)
+ 	    *i15p++ = 0;
+ 	buf.p.p16 = i15p;
+ 	break;
+     }
+ 
+  RETRY:
+     s = write(fd, buf.top, buf.size);
+     if (s < buf.size) {
+ 	if (s < 0) {
+ 	    if (errno == EINTR) goto RETRY;
+ 	    perror("dacioFlush");
+ 	} else fprintf(stderr, "wrote only %d bytes\n", s);
+ 	exit(1);
+     }
+     buf.p.p8 = buf.top;
+ }
+ 
+ static struct {
+     const i31 *p0;
+     const i31 *p;
+     i15x len;
+ } inbuf;
+ 
+ void
+ dacioIncomingBuf(const i31 *bp)
+ {
+     inbuf.p0 = bp;
+ }
+ 
+ void
+ dacioIncomingBufLen(i15x len)
+ {
+     inbuf.len = len;
+ }
+ 
+ static i15x gv = 0x40*0x40; /* default g.v = m.v = 64 */
+ 
+ /* gv = 0(min)..64*128(max) */
+ void
+ dacioGlobalVol(i15x v)
+ {
+     gv = v;
+ }
+ 
+ #define VOL_MAX		(64*64*128)	/* vol max * g.v max * m.v max */
+ #define VOL_MAX_LOG	( 6+ 6+  7)	/* 1 << VOL_MAX_LOG == VOL_MAX */
+ #define LEV_MAX		(128*VOL_MAX)
+ 
+ #if 0
+ #define to8bit(x, /*i31x*/tmpvar) \
+     ( tmpvar = (x) * gv, \
+      (tmpvar >= LEV_MAX) ? 255 : \
+      (tmpvar < -LEV_MAX) ? 0 : \
+      (u32x)tmpvar/VOL_MAX ^ 128 )
+ /*   ^^^^^^ see asm output w/o this */
+ #define to8bit(x, /*i31x*/tmpvar) \
+     ( tmpvar = (x) * gv + LEV_MAX, \
+      (tmpvar & ~(LEV_MAX*2-1)) ? \
+      ((tmpvar < 0)? 0 : 255) : \
+      (u32x)tmpvar/VOL_MAX)
+ #define to8bit(x, /*i31x*/tmpvar) lim[(x) * gv >> VOL_MAX_LOG]
+ #else
+ /* almost the same CPU usage as lim[] table mathod */
+ #define to8bit(x, /*i31x*/tmpvar) \
+     ( tmpvar = ((x) * gv + LEV_MAX) >> VOL_MAX_LOG, \
+      (tmpvar & ~255)? ~tmpvar >> 16 : tmpvar ) /* 16 will be OK */
+ /*                   ~(tmpvar >> 16) makes longer asm */
+ #endif
+ #define to16bit(x) \
+     ( ((x) * gv) >> 12 )
+ 
+ /* stereo */
+ static void
+ dacioOutHirevS(i15x n)
+ {
+     const i31 *inbufp = inbuf.p;
+     u8 *u8p;
+     i15 *i15p;
+ 
+     switch (dci.bits) {
+     case 8:
+ 	u8p = buf.p.p8;
+ 	for (; n > 0; n--) {
+ 	    i31x tmp;
+ 	    *u8p++ = to8bit(*inbufp++, tmp); /* L */
+ 	    *u8p++ = to8bit(*inbufp++, tmp); /* R */
+ 	}
+ 	buf.p.p8 = u8p;
+ 	break;
+     case 16:
+ 	i15p = buf.p.p16;
+ 	for (; n > 0; n--) {
+ 	    *i15p++ = to16bit(*inbufp++); /* L */
+ 	    *i15p++ = to16bit(*inbufp++); /* R */
+ 	}
+ 	buf.p.p16 = i15p;
+ 	break;
+     }
+     inbuf.p = inbufp;
+ }
+ 
+ /* mono */
+ static void
+ dacioOutHirevM(i15x n)
+ {
+     const i31 *inbufp = inbuf.p;
+     u8 *u8p;
+     i15 *i15p;
+ 
+     switch (dci.bits) {
+     case 8:
+ 	u8p = buf.p.p8;
+ 	for (; n > 0; n--) {
+ 	    i31x tmp;
+ 	    *u8p++ = to8bit(*inbufp, tmp);
+ 	    inbufp += 2;
+ 	}
+ 	buf.p.p8 = u8p;
+ 	break;
+     case 16:
+ 	i15p = buf.p.p16;
+ 	for (; n > 0; n--) {
+ 	    *i15p++ = to16bit(*inbufp);
+ 	    inbufp += 2;
+ 	}
+ 	buf.p.p16 = i15p;
+ 	break;
+     }
+     inbuf.p = inbufp;
+ }
+ 
+ #define dacioOutHirev(x) \
+     if (dci.stereo) dacioOutHirevS(x); else dacioOutHirevM(x)
+ 
+ void
+ dacioOut(void)
+ {
+     i31x iLen;
+     i31x oLen;
+ 
+     inbuf.p = inbuf.p0;
+     iLen = inbuf.len;
+     while ((oLen = bufRest()) <= iLen) {
+ 	iLen -= oLen;
+ 	dacioOutHirev(oLen);
+ 	dacioFlush();
+     }
+     dacioOutHirev(iLen);
+ }
