This is sounduss.c in view mode; [Download] [Up]
/* * sounduss.c - Implementation of the Linux/FreeBSD sound device * * Written by * Teemu Rantanen (tvr@cs.hut.fi) * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. * */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include "vice.h" #include "sound.h" #if defined(HAVE_LINUX_SOUNDCARD_H) #include <linux/soundcard.h> #endif #if defined(HAVE_MACHINE_SOUNDCARD_H) #include <machine/soundcard.h> #endif static int uss_fd = -1; static int uss_8bit = 0; static int uss_bufsize = 0; static int uss_fragsize = 0; static int uss_bufferstatus(warn_t *s, int first); static int uss_init(warn_t *w, char *param, int *speed, int *fragsize, int *fragnr, double bufsize) { int st, tmp, orig; if (!param) param = "/dev/dsp"; uss_fd = open(param, O_WRONLY, 0777); if (uss_fd < 0) { warn(w, -1, "cannot open '%s' for writing", param); return 1; } /* samplesize 16 bits */ #ifdef WORDS_BIGENDIAN orig = tmp = AFMT_S16_BE; #else orig = tmp = AFMT_S16_LE; #endif st = ioctl(uss_fd, SNDCTL_DSP_SETFMT, &tmp); if (st < 0 || orig != tmp || getenv("USS8BIT")) { /* samplesize 8 bits */ orig = tmp = AFMT_U8; st = ioctl(uss_fd, SNDCTL_DSP_SETFMT, &tmp); if (st < 0 || orig != tmp) { warn(w, -1, "SNDCTL_DSP_SETFMT failed"); goto fail; } warn(w, -1, "playing 8bit sample"); uss_8bit = 1; } /* no stereo */ tmp = 0; st = ioctl(uss_fd, SNDCTL_DSP_STEREO, &tmp); if (st < 0 || tmp != 0) { warn(w, -1, "SNDCTL_DSP_STEREO failed"); goto fail; } /* speed */ tmp = *speed; st = ioctl(uss_fd, SNDCTL_DSP_SPEED, &tmp); if (st < 0 || tmp <= 0) { warn(w, -1, "SNDCTL_DSP_SPEED failed"); goto fail; } *speed = tmp; /* fragments */ for (tmp = 1; 1 << tmp < *fragsize; tmp++); orig = tmp = tmp + (*fragnr << 16) + !uss_8bit; st = ioctl(uss_fd, SNDCTL_DSP_SETFRAGMENT, &tmp); if (st < 0 || (tmp^orig)&0xffff) { warn(w, -1, "SNDCTL_DSP_SETFRAGMENT failed"); goto fail; } if (tmp != orig) { if (tmp >> 16 > *fragnr) { warn(w, -1, "SNDCTL_DSP_SETFRAGMENT: too many fragments"); goto fail; } *fragnr = tmp >> 16; if (*fragnr < 3) { warn(w, -1, "SNDCTL_DSP_SETFRAGMENT: too few fragments"); goto fail; } } uss_bufsize = (*fragsize)*(*fragnr); uss_fragsize = *fragsize; return 0; fail: close(uss_fd); uss_fd = -1; uss_8bit = 0; uss_bufsize = 0; uss_fragsize = 0; return 1; } static int uss_write(warn_t *w, SWORD *pbuf, int nr) { int total, i, now; if (uss_8bit) { /* XXX: ugly to change contents of the buffer */ for (i = 0; i < nr; i++) ((char *)pbuf)[i] = pbuf[i]/256 + 128; total = nr; } else total = nr*sizeof(SWORD); for (i = 0; i < total; i += now) { now = write(uss_fd, (char *)pbuf + i, total - i); if (now <= 0) { if (now < 0) perror("uss_write"); return 1; } } return 0; } static int uss_bufferstatus(warn_t *w, int first) { audio_buf_info info; int st, ret; st = ioctl(uss_fd, SNDCTL_DSP_GETOSPACE, &info); if (st < 0) { warn(w, -1, "SNDCTL_DSP_GETOSPACE failed"); return -1; } ret = info.fragments*info.fragsize; if (ret != info.bytes) { warn(w, 11, "GETOSPACE: ret(%d)!=bytes(%d)", ret, info.bytes); ret = info.bytes; } if (ret < 0) { warn(w, 12, "GETOSPACE: bytes < 0"); ret = 0; } if (!uss_8bit) ret /= sizeof(SWORD); if (ret > uss_bufsize) { warn(w, 13, "GETOSPACE: bytes > bufsize"); ret = uss_bufsize; } #if defined(linux) /* * GETOSPACE before first write returns random value (or actually the * value on which the device was when it was closed last time). I hope * this has been fixed after 'Sound Driver:3.5-beta2-960210' */ if (first && !ret) { ret = 1; warn(w, -1, "SNDCTL_DSP_GETOSPACE not reliable after open()"); } #endif return ret; } static void uss_close(warn_t *w) { close(uss_fd); uss_fd = -1; uss_8bit = 0; uss_bufsize = 0; uss_fragsize = 0; } static int uss_suspend(warn_t *w) { int st; st = ioctl(uss_fd, SNDCTL_DSP_POST, NULL); if (st < 0) { warn(w, -1, "SNDCTL_DSP_POST failed"); return 1; } return 0; } static sound_device_t uss_device = { "uss", uss_init, uss_write, NULL, NULL, uss_bufferstatus, uss_close, uss_suspend, NULL }; int sound_init_uss_device(void) { return sound_register_device(&uss_device); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.