#line 2 "dacio-linux.c" #include /*(perror)*/ #include /*O_WRONLY*/ #include /*(ioctl)*/ #include /*(write)*/ #if defined(LINUX) || defined(__FreeBSD__) #include /*SNDCTL_XXX*/ #else #include #endif #include /*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/dsp" #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; } buf; static DacioConfInfo dci; void dacioConf(DacioConfInfo *dcp) { int tmp; #if 0 if (ioctl(fd, SNDCTL_DSP_RESET) < 0) { perror("dacioConf"); exit(1); } #endif switch (dcp->bits) { case 0: case 8: dcp->bits = 8; tmp = AFMT_U8; break; case 16: tmp = AFMT_S16_LE; break; default: fprintf(stderr, "Don't know how to handle %d bit output.\n", dcp->bits); exit(1); break; } if (ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0) { perror("dacioConf"); exit(1); } switch (tmp) { case AFMT_U8: if (dcp->bits != 8) { fprintf(stderr, "soundcard doesn't support 8bits.\n"); exit(1); } break; case AFMT_S16_LE: if (dcp->bits != 16) { fprintf(stderr, "soundcard doesn't support 16bits.\n"); exit(1); } break; } /*fprintf(stderr, "fmt = 0x%x\n", tmp);*/ if (ioctl(fd, SNDCTL_DSP_STEREO, &dcp->stereo) < 0) { perror("dacioConf"); exit(1); } /*fprintf(stderr, "stereo = %d\n", dcp->stereo);*/ if (ioctl(fd, SNDCTL_DSP_SPEED, &dcp->speed) < 0) { perror("dacioConf"); exit(1); } /*fprintf(stderr, "speed = %d\n", dcp->speed);*/ if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buf.size) < 0) { perror("dacioConf"); exit(1); } /*fprintf(stderr, "sound buffer size = 0x%x\n", buf.size);*/ tmp = buf.size; while (tmp <= (0.1 * (dcp->speed * (dcp->stereo+1) * (dcp->bits/8)))) tmp += buf.size; buf.size = tmp; /*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; } void dacioSync(void) { if (ioctl(fd, SNDCTL_DSP_SYNC, NULL) < 0) { perror("dacioSync"); exit(1); } } /* OS independent part (?) */ void dacioFlush(void) { int s; if (buf.p.p8 <= buf.top) return; switch (dci.bits) { case 8: for ( ; buf.p.p8 < buf.bot; buf.p.p8++) *buf.p.p8 = 128; break; case 16: for ( ; buf.p.p8 < buf.bot; buf.p.p16++) *buf.p.p16 = 0; 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 = buf.p.p8; i15 *s15p = buf.p.p16; switch (dci.bits) { case 8: for (; n > 0; n--) { i31x tmp; *u8p++ = to8bit(*inbufp++, tmp); /* L */ *u8p++ = to8bit(*inbufp++, tmp); /* R */ } buf.p.p8 = u8p; break; case 16: for (; n > 0; n--) { *s15p++ = to16bit(*inbufp++); /* L */ *s15p++ = to16bit(*inbufp++); /* R */ } buf.p.p16 = s15p; break; } inbuf.p = inbufp; } /* mono */ static void dacioOutHirevM(i15x n) { const i31 *inbufp = inbuf.p; u8 *u8p = buf.p.p8; i15 *s16p = buf.p.p16; switch (dci.bits) { case 8: for (; n > 0; n--) { i31x tmp; *u8p++ = to8bit(*inbufp, tmp); inbufp += 2; } buf.p.p8 = u8p; break; case 16: for (; n > 0; n--) { *s16p++ = to16bit(*inbufp); inbufp += 2; } buf.p.p16 = s16p; break; } inbuf.p = inbufp; } #define dacioOutHirev(x) \ if (dci.stereo) dacioOutHirevS(x); else dacioOutHirevM(x) #define bufRest() ((dci.stereo? (buf.bot - buf.p.p8)/2 : buf.bot - buf.p.p8)/(dci.bits/8)) 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); }