aboutsummaryrefslogtreecommitdiff
path: root/desiredata/src/s_audio_oss.c
diff options
context:
space:
mode:
authorN.N. <matju@users.sourceforge.net>2010-01-05 22:49:36 +0000
committerN.N. <matju@users.sourceforge.net>2010-01-05 22:49:36 +0000
commit8dbec761cf858ea65900c8a094599857208d8c3a (patch)
tree3228c023f87f23a354da3b57fdc2afe5b7052032 /desiredata/src/s_audio_oss.c
parent529e59635598e2d90a7a49f6b4c676f8366109ba (diff)
svn path=/trunk/; revision=12907
Diffstat (limited to 'desiredata/src/s_audio_oss.c')
-rw-r--r--desiredata/src/s_audio_oss.c521
1 files changed, 0 insertions, 521 deletions
diff --git a/desiredata/src/s_audio_oss.c b/desiredata/src/s_audio_oss.c
deleted file mode 100644
index 323f114b..00000000
--- a/desiredata/src/s_audio_oss.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
-* Winfried Ritsch, Karl MacMillan, and others.
-* For information on usage and redistribution, and for a DISCLAIMER OF ALL
-* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* this file inputs and outputs audio using the OSS API available on linux. */
-#include <linux/soundcard.h>
-
-#define PD_PLUSPLUS_FACE
-#include "desire.h"
-using namespace desire;
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/mman.h>
-
-/* Defines */
-#define DEBUG(x) x
-#define DEBUG2(x) {x;}
-
-#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
-#define OSS_MAXDEV 4 /* maximum number of input or output devices */
-#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
-#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
-#define OSS_DEFAULTCH 2
-#define RME_DEFAULTCH 8 /* need this even if RME undefined */
-typedef int16_t t_oss_int16;
-typedef int32_t t_oss_int32;
-#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
-#define OSS_BYTESPERCHAN(width) (sys_dacblocksize * (width))
-#define OSS_XFERSAMPS(chans) (sys_dacblocksize* (chans))
-#define OSS_XFERSIZE(chans, width) (sys_dacblocksize * (chans) * (width))
-
-static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
-
-/* our device handles */
-struct t_oss_dev {
- int fd;
- unsigned int space; /* bytes available for writing/reading */
- int bufsize; /* total buffer size in blocks for this device */
- int dropcount; /* # of buffers to drop for resync (output only) */
- unsigned int nchannels; /* number of channels for this device */
- unsigned int bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
-};
-
-static t_oss_dev linux_dacs[OSS_MAXDEV];
-static t_oss_dev linux_adcs[OSS_MAXDEV];
-static int linux_noutdevs = 0;
-static int linux_nindevs = 0;
-
-/* OSS-specific private variables */
-static int oss_blockmode = 0; /* flag to use "blockmode" */
-static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
-
-/* don't assume we can turn all 31 bits when doing float-to-fix;
- otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
-#define FMAX 0x7ffff000
-#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
-
-/* ---------------- public routines ----------------------- */
-static int oss_ndev = 0;
-
-/* find out how many OSS devices we have. Since this has to
- open the devices to find out if they're there, we have
- to be called before audio is actually started up. So we
- cache the results, which in effect are the number of available devices. */
-void oss_init() {
- static int countedthem = 0;
- if (countedthem) return;
- for (int i=0; i<10; i++) {
- char devname[100];
- if (i == 0) strcpy(devname, "/dev/dsp"); else sprintf(devname, "/dev/dsp%d", i);
- int fd = open(devname, O_WRONLY|O_NONBLOCK);
- if (fd<0) break;
- oss_ndev++;
- close(fd);
- }
- countedthem = 1;
-}
-
-void oss_set32bit() {oss_32bit=1;}
-
-struct t_multidev {
- int fd;
- int channels;
- int format;
-};
-
-int oss_reset(int fd) {
- int err = ioctl(fd,SNDCTL_DSP_RESET);
- if (err<0) error("OSS: Could not reset");
- return err;
-}
-
-/* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
- but is proposed by Guenter Geiger to support extending OSS to handle
- 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
- I'm not clear why this isn't called AFMT_S32_[SLN]E... */
-
-#ifndef AFMT_S32_BLOCKED
-#define AFMT_S32_BLOCKED 0x0000400
-#endif
-
-void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) {
- /* IOhannes */
- int orig, param, fd = dev->fd, wantformat;
- int nchannels = dev->nchannels;
- audio_buf_info ainfo;
- /* IOhannes : pd is very likely to crash if different formats are used on multiple soundcards */
- /* set resolution - first try 4 byte samples */
- if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) && (param & AFMT_S32_BLOCKED)) {
- wantformat = AFMT_S32_BLOCKED;
- dev->bytespersamp = 4;
- } else {
- wantformat = AFMT_S16_NE;
- dev->bytespersamp = 2;
- }
- param = wantformat;
-
- if (sys_verbose) post("bytes per sample = %d", dev->bytespersamp);
- if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1) error("OSS: Could not set DSP format");
- else if (wantformat != param) error("OSS: DSP format: wanted %d, got %d", wantformat, param);
- /* sample rate */
- orig = param = srate;
- if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1) error("OSS: Could not set sampling rate for device");
- else if (orig != param) error("OSS: sampling rate: wanted %d, got %d", orig, param );
-
- if (oss_blockmode && !skipblocksize) {
- int fragbytes, logfragsize, nfragment;
- /* setting fragment count and size. */
- linux_fragsize = sys_blocksize;
- if (!linux_fragsize) {
- linux_fragsize = OSS_DEFFRAGSIZE;
- while (linux_fragsize > sys_dacblocksize && linux_fragsize * 6 > sys_advance_samples)
- linux_fragsize = linux_fragsize/2;
- }
- /* post("adv_samples %d", sys_advance_samples); */
- nfragment = int(sys_schedadvance * 44100.e-6 / linux_fragsize);
- fragbytes = linux_fragsize * (dev->bytespersamp * nchannels);
- logfragsize = ilog2(fragbytes);
- if (fragbytes != (1 << logfragsize))
- post("warning: OSS takes only power of 2 blocksize; using %d", (1<<logfragsize)/(dev->bytespersamp*nchannels));
- if (sys_verbose) post("setting nfrags = %d, fragsize %d", nfragment, fragbytes);
-
- param = orig = (nfragment<<16) + logfragsize;
- if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1) error("OSS: Could not set or read fragment size");
- if (param != orig) {
- nfragment = ((param >> 16) & 0xffff);
- logfragsize = (param & 0xffff);
- post("warning: actual fragments %d, blocksize %d", nfragment, 1<<logfragsize);
- }
- if (sys_verbose) post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
- }
-
- if (dac) {
- /* use "free space" to learn the buffer size. Normally you
- should set this to your own desired value; but this seems not
- to be implemented uniformly across different sound cards. LATER
- we should figure out what to do if the requested scheduler advance
- is greater than this buffer size; for now, we just print something
- out. */
- if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) error("OSS: ioctl on output device failed");
- dev->bufsize = ainfo.bytes;
- int defect = sys_advance_samples*(dev->bytespersamp*nchannels) - dev->bufsize - OSS_XFERSIZE(nchannels, dev->bytespersamp);
- if (defect>0) {
- if (sys_verbose || defect > (dev->bufsize >> 2))
- error("OSS: requested audio buffer size %d limited to %d",
- sys_advance_samples*(dev->bytespersamp*nchannels), dev->bufsize);
- sys_advance_samples = (dev->bufsize-OSS_XFERSAMPS(nchannels)) / (dev->bytespersamp*nchannels);
- }
- }
-}
-
-static int oss_setchannels(int fd, int wantchannels, char *devname) {
- /* IOhannes */
- int param = wantchannels;
- while (param > 1) {
- int save = param;
- if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
- else if (param == save) return param;
- param = save - 1;
- }
- return 0;
-}
-
-#define O_AUDIOFLAG O_NDELAY
-/* what's the deal with (!O_NDELAY) ? does it make sense to you? */
-
-ssize_t read2(int fd, void *buf, size_t count) {
- ssize_t r = read(fd,buf,count);
- if (r<0) error("can't read: %s",strerror(errno));
- if (r<(ssize_t)count) error("incomplete read");
- return r;
-}
-ssize_t write2(int fd, const void *buf, size_t count) {
- ssize_t r = write(fd,buf,count);
- if (r<0) error("can't write: %s",strerror(errno));
- if (r<(ssize_t)count) error("incomplete write");
- return r;
-}
-
-int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
- int noutdev, int *outdev, int nchout, int *chout, int rate, int bogus)
-{ /* IOhannes */
- int capabilities = 0;
- int inchannels = 0, outchannels = 0;
- char devname[20];
- int fd, flags;
- char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
- linux_nindevs = linux_noutdevs = 0;
- /* mark devices unopened */
- for (int i=0; i<OSS_MAXDEV; i++) linux_adcs[i].fd = linux_dacs[i].fd = -1;
- /* open output devices */
- int wantmore=0;
- if (noutdev < 0 || nindev < 0) bug("linux_open_audio");
- for (int n=0; n<noutdev; n++) {
- int gotchans, inindex = -1;
- int thisdevice = (outdev[n] >= 0 ? outdev[n] : 0);
- int wantchannels = (nchout>n) ? chout[n] : wantmore;
- fd = -1;
- if (!wantchannels) goto end_out_loop;
- if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp");
- /* search for input request for same device. Succeed only if the number of channels matches. */
- for (int j=0; j<nindev; j++) if (indev[j] == thisdevice && chin[j] == wantchannels) inindex = j;
- /* if the same device is requested for input and output, try to open it read/write */
- if (inindex >= 0) {
- sys_setalarm(1000000);
- if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1) {
- post("%s (read/write): %s", devname, strerror(errno));
- post("(now will try write-only...)");
- } else {
- if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
- if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
- else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
- if (sys_verbose) post("opened %s for reading and writing", devname);
- linux_adcs[inindex].fd = fd;
- }
- }
- /* if that didn't happen or if it failed, try write-only */
- if (fd == -1) {
- sys_setalarm(1000000);
- if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1) {
- post("%s (writeonly): %s", devname, strerror(errno));
- break;
- }
- if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
- if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
- else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
- if (sys_verbose) post("opened %s for writing only", devname);
- }
- if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
- gotchans = oss_setchannels(fd, (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, devname);
- if (sys_verbose) post("opened audio output on %s; got %d channels", devname, gotchans);
- if (gotchans < 2) {
- close(fd); /* can't even do stereo? just give up. */
- } else {
- linux_dacs[linux_noutdevs].nchannels = gotchans;
- linux_dacs[linux_noutdevs].fd = fd;
- oss_configure(&linux_dacs[linux_noutdevs], rate, 1, 0);
- linux_noutdevs++;
- outchannels += gotchans;
- if (inindex >= 0) {
- linux_adcs[inindex].nchannels = gotchans;
- chin[inindex] = gotchans;
- }
- }
- /* LATER think about spreading large numbers of channels over various dsp's and vice-versa */
- wantmore = wantchannels - gotchans;
- end_out_loop: ;
- }
- /* open input devices */
- wantmore = 0;
- for (int n=0; n<nindev; n++) {
- int gotchans=0;
- int thisdevice = (indev[n] >= 0 ? indev[n] : 0);
- int wantchannels = (nchin>n)?chin[n]:wantmore;
- int alreadyopened = 0;
- if (!wantchannels) goto end_in_loop;
- if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp");
- sys_setalarm(1000000);
- /* perhaps it's already open from the above? */
- if (linux_dacs[n].fd >= 0) {
- fd = linux_adcs[n].fd;
- alreadyopened = 1;
- } else {
- /* otherwise try to open it here. */
- if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1) {
- post("%s (readonly): %s", devname, strerror(errno));
- goto end_in_loop;
- }
- if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
- if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
- else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
- if (sys_verbose) post("opened %s for reading only", devname);
- }
- linux_adcs[linux_nindevs].fd = fd;
- gotchans = oss_setchannels(fd, (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, devname);
- if (sys_verbose) post("opened audio input device %s; got %d channels", devname, gotchans);
- if (gotchans < 1) {
- close(fd);
- goto end_in_loop;
- }
- linux_adcs[linux_nindevs].nchannels = gotchans;
- oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
- inchannels += gotchans;
- linux_nindevs++;
- wantmore = wantchannels-gotchans;
- /* LATER think about spreading large numbers of channels over various dsp's and vice-versa */
- end_in_loop: ;
- }
- /* We have to do a read to start the engine. This is necessary because sys_send_dacs waits until the input
- buffer is filled and only reads on a filled buffer. This is good, because it's a way to make sure that we
- will not block. But I wonder why we only have to read from one of the devices and not all of them??? */
- if (linux_nindevs) {
- if (sys_verbose) post("OSS: issuing first ADC 'read'...");
- read2(linux_adcs[0].fd, buf, linux_adcs[0].bytespersamp * linux_adcs[0].nchannels * sys_dacblocksize);
- if (sys_verbose) post("...done.");
- }
- /* now go and fill all the output buffers. */
- for (int i=0; i<linux_noutdevs; i++) {
- t_oss_dev &d = linux_dacs[i];
- memset(buf, 0, d.bytespersamp * d.nchannels * sys_dacblocksize);
- for (int j=0; j<sys_advance_samples/sys_dacblocksize; j++)
- write2(d.fd, buf, d.bytespersamp * d.nchannels * sys_dacblocksize);
- }
- sys_setalarm(0);
- sys_inchannels = inchannels;
- sys_outchannels = outchannels;
- return 0;
-}
-
-void oss_close_audio() {
- for (int i=0;i<linux_nindevs ;i++) close(linux_adcs[i].fd);
- for (int i=0;i<linux_noutdevs;i++) close(linux_dacs[i].fd);
- linux_nindevs = linux_noutdevs = 0;
-}
-
-static int linux_dacs_write(int fd,void *buf,long bytes) {return write(fd, buf, bytes);}
-static int linux_adcs_read (int fd,void *buf,long bytes) {return read(fd, buf, bytes);}
-
- /* query audio devices for "available" data size. */
-static void oss_calcspace() {
- audio_buf_info ainfo;
- for (int dev=0; dev<linux_noutdevs; dev++) {
- if (ioctl(linux_dacs[dev].fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
- error("OSS: ioctl on output device %d failed (fd=%d)", dev, linux_dacs[dev].fd);
- linux_dacs[dev].space = ainfo.bytes;
- }
- for (int dev=0; dev<linux_nindevs; dev++) {
- if (ioctl(linux_adcs[dev].fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
- error("OSS: ioctl on input device %d failed (fd=%d)", dev, linux_adcs[dev].fd);
- linux_adcs[dev].space = ainfo.bytes;
- }
-}
-
-/* this call resyncs audio output and input which will cause discontinuities
-in audio output and/or input. */
-
-static void oss_doresync() {
- int zeroed = 0;
- char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
- audio_buf_info ainfo;
- /* 1. if any input devices are ahead (have more than 1 buffer stored), drop one or more buffers worth */
- for (int dev=0; dev<linux_nindevs; dev++) {
- t_oss_dev d = linux_adcs[dev];
- if (d.space == 0) {
- linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
- } else while (d.space > OSS_XFERSIZE(d.nchannels, d.bytespersamp)) {
- linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
- if (ioctl(d.fd, SOUND_PCM_GETISPACE, &ainfo) < 0) { error("OSS: ioctl on input device %d, fd %d failed",dev,d.fd); break;}
- d.space = ainfo.bytes;
- }
- }
- /* 2. if any output devices are behind, feed them zeros to catch them up */
- for (int dev=0; dev<linux_noutdevs; dev++) {
- t_oss_dev d = linux_dacs[dev];
- while (d.space > d.bufsize - sys_advance_samples*d.nchannels*d.bytespersamp) {
- if (!zeroed) {
- for (unsigned int i=0; i<OSS_XFERSAMPS(d.nchannels); i++) buf[i] = 0;
- zeroed = 1;
- }
- linux_dacs_write(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
- if (ioctl(d.fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) {error("OSS: ioctl on output device %d, fd %d failed",dev,d.fd); break;}
- d.space = ainfo.bytes;
- }
- }
- /* 3. if any DAC devices are too far ahead, plan to drop the number of frames which will let the others catch up. */
- for (int dev=0; dev<linux_noutdevs; dev++) {
- t_oss_dev d = linux_dacs[dev];
- if (d.space > d.bufsize - (sys_advance_samples - 1) * d.nchannels * d.bytespersamp) {
- d.dropcount = sys_advance_samples - 1 - (d.space - d.bufsize) / (d.nchannels * d.bytespersamp);
- } else d.dropcount = 0;
- }
-}
-
-int oss_send_dacs() {
- float *fp1, *fp2;
- int rtnval = SENDDACS_YES;
- char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
- /* the maximum number of samples we should have in the ADC buffer */
- int idle = 0;
- double timeref, timenow;
- if (!linux_nindevs && !linux_noutdevs) return SENDDACS_NO;
- if (!oss_blockmode) {
- /* determine whether we're idle. This is true if either (1)
- some input device has less than one buffer to read or (2) some
- output device has fewer than (sys_advance_samples) blocks buffered already. */
- oss_calcspace();
- for (int dev=0; dev<linux_noutdevs; dev++) {
- t_oss_dev d = linux_dacs[dev];
- if (d.dropcount || (d.bufsize - d.space > sys_advance_samples * d.bytespersamp * d.nchannels)) idle = 1;
- }
- for (int dev=0; dev<linux_nindevs; dev++) {
- t_oss_dev d = linux_adcs[dev];
- if (d.space < OSS_XFERSIZE(d.nchannels, d.bytespersamp)) idle = 1;
- }
- }
- if (idle && !oss_blockmode) {
- /* sometimes---rarely---when the ADC available-byte-count is zero, it's genuine, but usually it's because we're so
- late that the ADC has overrun its entire kernel buffer. We distinguish between the two by waiting 2 msec and
- asking again. There should be an error flag we could check instead; look for this someday... */
- for (int dev=0; dev<linux_nindevs; dev++) if (linux_adcs[dev].space == 0) {
- sys_microsleep(sys_sleepgrain); /* tb: changed to sys_sleepgrain */
- oss_calcspace();
- if (linux_adcs[dev].space != 0) continue;
- /* here's the bad case. Give up and resync. */
- sys_log_error(ERR_DATALATE);
- oss_doresync();
- return SENDDACS_NO;
- }
- /* check for slippage between devices, either because data got lost in the driver from a previous late condition,
- or because the devices aren't synced. When we're idle, no input device should have more than one buffer readable
- and no output device should have less than sys_advance_samples-1 */
- for (int dev=0; dev<linux_noutdevs; dev++) {
- t_oss_dev d = linux_dacs[dev];
- if (!d.dropcount && (d.bufsize - d.space < (sys_advance_samples - 2)*d.bytespersamp*d.nchannels)) goto badsync;
- }
- for (int dev=0; dev<linux_nindevs; dev++)
- if (linux_adcs[dev].space > 3 * OSS_XFERSIZE(linux_adcs[dev].nchannels, linux_adcs[dev].bytespersamp)) goto badsync;
- /* return zero to tell the scheduler we're idle. */
- return SENDDACS_NO;
- badsync:
- sys_log_error(ERR_RESYNC);
- oss_doresync();
- return SENDDACS_NO;
- }
- /* do output */
- timeref = sys_getrealtime();
- t_oss_int16 *sp;
- t_oss_int32 *lp;
- for (int dev=0, thischan = 0; dev < linux_noutdevs; dev++) {
- t_oss_dev d = linux_dacs[dev];
- int nchannels = d.nchannels;
- if (d.dropcount) d.dropcount--;
- else {
- fp1 = sys_soundout + sys_dacblocksize*thischan;
- if (d.bytespersamp == 4) {
- lp = (t_oss_int32 *)buf;
- for (int i=sys_dacblocksize * nchannels; i--; fp1++, lp++) *lp = int(clip(*fp1*2147483648.,-2147483648.,2147483647.));
- } else {
- sp = (t_oss_int16 *)buf;
- for (int i=sys_dacblocksize; i--; fp1++, sp += nchannels) {
- fp2 = fp1;
- for (int j=0; j<nchannels; j++, fp2 += sys_dacblocksize) sp[j] = clip(int(*fp2*32767.),-32768,32767);
- }
- }
- linux_dacs_write(d.fd, buf, OSS_XFERSIZE(nchannels, d.bytespersamp));
- if ((timenow = sys_getrealtime()) - timeref > 0.002) {
- if (!oss_blockmode) sys_log_error(ERR_DACSLEPT); else rtnval = SENDDACS_SLEPT;
- }
- timeref = timenow;
- }
- thischan += nchannels;
- }
- memset(sys_soundout, 0, sys_outchannels * (sizeof(float) * sys_dacblocksize));
- for (int dev=0, thischan = 0; dev < linux_nindevs; dev++) {
- int nchannels = linux_adcs[dev].nchannels;
- linux_adcs_read(linux_adcs[dev].fd, buf, OSS_XFERSIZE(nchannels, linux_adcs[dev].bytespersamp));
- if ((timenow = sys_getrealtime()) - timeref > 0.002) {
- if (!oss_blockmode) sys_log_error(ERR_ADCSLEPT); else rtnval = SENDDACS_SLEPT;
- }
- timeref = timenow;
- fp1 = sys_soundin + thischan*sys_dacblocksize;
- if (linux_adcs[dev].bytespersamp == 4) {
- lp = (t_oss_int32 *)buf;
- for (int i=sys_dacblocksize*nchannels; i--; fp1++, lp++)
- *fp1 = float(*lp)*float(1./2147483648.);
- } else {
- sp = (t_oss_int16 *)buf;
- for (int i=sys_dacblocksize; i--; fp1++, sp += nchannels)
- for (int j=0; j<nchannels; j++) fp1[j*sys_dacblocksize] = (float)sp[j]*(float)3.051850e-05;
- }
- thischan += nchannels;
- }
- return rtnval;
-}
-
-void oss_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
- int ndev = min(oss_ndev,maxndev);
- *canmulti = 2; /* supports multiple devices */
- for (int i=0; i<ndev; i++) {
- sprintf(indevlist + i*devdescsize, "OSS device #%d", i+1);
- sprintf(outdevlist + i*devdescsize, "OSS device #%d", i+1);
- }
- *nindevs = *noutdevs = ndev;
-}
-
-struct t_audioapi oss_api = {
- oss_open_audio,
- oss_close_audio,
- oss_send_dacs,
- oss_getdevs,
-};