Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / s_audio_oss.c
blobde11f66243aef893c798e2e463572a0f3e0c6ca7
1 /* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
2 * Winfried Ritsch, Karl MacMillan, and others.
3 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
6 /* this file inputs and outputs audio using the OSS API available on linux. */
8 #ifdef USEAPI_OSS
10 #include <linux/soundcard.h>
12 #include "m_pd.h"
13 #include "s_stuff.h"
14 #include <errno.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/stat.h>
22 #include <sys/ioctl.h>
23 #include <fcntl.h>
24 #include <sched.h>
25 #include <sys/mman.h>
28 /* Defines */
29 #define DEBUG(x) x
30 #define DEBUG2(x) {x;}
32 #define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
33 #define OSS_MAXDEV 4 /* maximum number of input or output devices */
34 #define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
35 #define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
36 #define OSS_DEFAULTCH 2
37 #define RME_DEFAULTCH 8 /* need this even if RME undefined */
38 typedef int16_t t_oss_int16;
39 typedef int32_t t_oss_int32;
40 #define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
41 #define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
42 #define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
43 #define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
45 /* GLOBALS */
46 static int linux_meters; /* true if we're metering */
47 static float linux_inmax; /* max input amplitude */
48 static float linux_outmax; /* max output amplitude */
49 static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
51 /* our device handles */
53 typedef struct _oss_dev
55 int d_fd;
56 unsigned int d_space; /* bytes available for writing/reading */
57 int d_bufsize; /* total buffer size in blocks for this device */
58 int d_dropcount; /* # of buffers to drop for resync (output only) */
59 unsigned int d_nchannels; /* number of channels for this device */
60 unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
61 } t_oss_dev;
63 static t_oss_dev linux_dacs[OSS_MAXDEV];
64 static t_oss_dev linux_adcs[OSS_MAXDEV];
65 static int linux_noutdevs = 0;
66 static int linux_nindevs = 0;
68 /* exported variables */
69 float sys_dacsr;
70 t_sample *sys_soundout;
71 t_sample *sys_soundin;
73 /* OSS-specific private variables */
74 static int oss_blockmode = 1; /* flag to use "blockmode" */
75 static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
76 static char ossdsp[] = "/dev/dsp%d";
78 /* don't assume we can turn all 31 bits when doing float-to-fix;
79 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
80 #define FMAX 0x7ffff000
81 #define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
84 /* ------------- private routines for all APIS ------------------- */
86 static void linux_flush_all_underflows_to_zero(void)
89 TODO: Implement similar thing for linux (GGeiger)
91 One day we will figure this out, I hope, because it
92 costs CPU time dearly on Intel - LT
94 /* union fpc_csr f;
95 f.fc_word = get_fpc_csr();
96 f.fc_struct.flush = 1;
97 set_fpc_csr(f.fc_word);
101 static int oss_ndev = 0;
103 /* find out how many OSS devices we have. Since this has to
104 open the devices to find out if they're there, we have
105 to be called before audio is actually started up. So we
106 cache the results, which in effect are the number of available
107 devices. */
108 void oss_init(void)
110 int fd, i;
111 static int countedthem = 0;
112 if (countedthem)
113 return;
114 for (i = 0; i < 10; i++)
116 char devname[100];
117 if (i == 0)
118 strcpy(devname, "/dev/dsp");
119 else sprintf(devname, "/dev/dsp%d", i);
120 if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1)
122 oss_ndev++;
123 close(fd);
125 else break;
127 countedthem = 1;
131 void oss_set32bit( void)
133 oss_32bit = 1;
137 typedef struct _multidev {
138 int fd;
139 int channels;
140 int format;
141 } t_multidev;
143 int oss_reset(int fd) {
144 int err;
145 if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
146 error("OSS: Could not reset");
147 return err;
150 /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
151 but is proposed by Guenter Geiger to support extending OSS to handle
152 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
153 I'm not clear why this isn't called AFMT_S32_[SLN]E... */
155 #ifndef AFMT_S32_BLOCKED
156 #define AFMT_S32_BLOCKED 0x0000400
157 #endif
159 void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
160 { /* IOhannes */
161 int orig, param, nblk, fd = dev->d_fd, wantformat;
162 int nchannels = dev->d_nchannels;
163 int advwas = sys_schedadvance;
165 audio_buf_info ainfo;
167 /* IOhannes :
168 * pd is very likely to crash if different formats are used on
169 multiple soundcards
172 /* set resolution - first try 4 byte samples */
173 if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
174 (param & AFMT_S32_BLOCKED))
176 wantformat = AFMT_S32_BLOCKED;
177 dev->d_bytespersamp = 4;
179 else
181 wantformat = AFMT_S16_NE;
182 dev->d_bytespersamp = 2;
184 param = wantformat;
186 if (sys_verbose)
187 post("bytes per sample = %d", dev->d_bytespersamp);
188 if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
189 fprintf(stderr,"OSS: Could not set DSP format\n");
190 else if (wantformat != param)
191 fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
192 wantformat, param);
194 /* sample rate */
195 orig = param = srate;
196 if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
197 fprintf(stderr,"OSS: Could not set sampling rate for device\n");
198 else if( orig != param )
199 fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
200 orig, param );
202 if (oss_blockmode && !skipblocksize)
204 int fragbytes, logfragsize, nfragment;
205 /* setting fragment count and size. */
206 if (!linux_fragsize)
208 linux_fragsize = OSS_DEFFRAGSIZE;
209 while (linux_fragsize > DEFDACBLKSIZE
210 && linux_fragsize * 4 > sys_advance_samples)
211 linux_fragsize = linux_fragsize/2;
214 /* post("adv_samples %d", sys_advance_samples); */
215 nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
217 fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
218 logfragsize = ilog2(fragbytes);
220 if (fragbytes != (1 << logfragsize))
221 post("warning: OSS takes only power of 2 blocksize; using %d",
222 (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
223 if (sys_verbose)
224 post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
226 param = orig = (nfragment<<16) + logfragsize;
227 if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
228 error("OSS: Could not set or read fragment size\n");
229 if (param != orig)
231 nfragment = ((param >> 16) & 0xffff);
232 logfragsize = (param & 0xffff);
233 post("warning: actual fragments %d, blocksize %d",
234 nfragment, (1 << logfragsize));
236 if (sys_verbose)
237 post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
239 if (dac)
241 /* use "free space" to learn the buffer size. Normally you
242 should set this to your own desired value; but this seems not
243 to be implemented uniformly across different sound cards. LATER
244 we should figure out what to do if the requested scheduler advance
245 is greater than this buffer size; for now, we just print something
246 out. */
248 int defect;
249 if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
250 fprintf(stderr,"OSS: ioctl on output device failed");
251 dev->d_bufsize = ainfo.bytes;
253 defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
254 - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
255 if (defect > 0)
257 if (sys_verbose || defect > (dev->d_bufsize >> 2))
258 fprintf(stderr,
259 "OSS: requested audio buffer size %d limited to %d\n",
260 sys_advance_samples * (dev->d_bytespersamp * nchannels),
261 dev->d_bufsize);
262 sys_advance_samples =
263 (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
264 (dev->d_bytespersamp *nchannels);
269 static int oss_setchannels(int fd, int wantchannels, char *devname)
270 { /* IOhannes */
271 int param = wantchannels;
273 while (param>1) {
274 int save = param;
275 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
276 error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
277 } else {
278 if (param == save) return (param);
280 param=save-1;
283 return (0);
286 #define O_AUDIOFLAG 0 /* O_NDELAY */
288 int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
289 int noutdev, int *outdev, int nchout, int *chout, int rate)
290 { /* IOhannes */
291 int capabilities = 0;
292 int inchannels = 0, outchannels = 0;
293 char devname[20];
294 int n, i, fd;
295 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
296 int num_devs = 0;
297 int wantmore=0;
298 int spread = 0;
299 audio_buf_info ainfo;
301 linux_nindevs = linux_noutdevs = 0;
304 /* mark input devices unopened */
305 for (i = 0; i < OSS_MAXDEV; i++)
306 linux_adcs[i].d_fd = -1;
308 /* open output devices */
309 wantmore=0;
310 if (noutdev < 0 || nindev < 0)
311 bug("linux_open_audio");
313 for (n = 0; n < noutdev; n++)
315 int gotchans, j, inindex = -1;
316 int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
317 int wantchannels = (nchout>n) ? chout[n] : wantmore;
318 fd = -1;
319 if (!wantchannels)
320 goto end_out_loop;
322 if (thisdevice > 1)
323 sprintf(devname, "/dev/dsp%d", thisdevice-1);
324 else sprintf(devname, "/dev/dsp");
326 /* search for input request for same device. Succeed only
327 if the number of channels matches. */
328 for (j = 0; j < nindev; j++)
329 if (indev[j] == thisdevice && chin[j] == wantchannels)
330 inindex = j;
332 /* if the same device is requested for input and output,
333 try to open it read/write */
334 if (inindex >= 0)
336 sys_setalarm(1000000);
337 if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
339 post("%s (read/write): %s", devname, strerror(errno));
340 post("(now will try write-only...)");
342 else
344 if (sys_verbose)
345 post("opened %s for reading and writing\n", devname);
346 linux_adcs[inindex].d_fd = fd;
349 /* if that didn't happen or if it failed, try write-only */
350 if (fd == -1)
352 sys_setalarm(1000000);
353 if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
355 post("%s (writeonly): %s",
356 devname, strerror(errno));
357 break;
359 if (sys_verbose)
360 post("opened %s for writing only\n", devname);
362 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
363 error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
365 gotchans = oss_setchannels(fd,
366 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
367 devname);
369 if (sys_verbose)
370 post("opened audio output on %s; got %d channels",
371 devname, gotchans);
373 if (gotchans < 2)
375 /* can't even do stereo? just give up. */
376 close(fd);
378 else
380 linux_dacs[linux_noutdevs].d_nchannels = gotchans;
381 linux_dacs[linux_noutdevs].d_fd = fd;
382 oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
384 linux_noutdevs++;
385 outchannels += gotchans;
386 if (inindex >= 0)
388 linux_adcs[inindex].d_nchannels = gotchans;
389 chin[inindex] = gotchans;
392 /* LATER think about spreading large numbers of channels over
393 various dsp's and vice-versa */
394 wantmore = wantchannels - gotchans;
395 end_out_loop: ;
398 /* open input devices */
399 wantmore = 0;
400 for (n = 0; n < nindev; n++)
402 int gotchans=0;
403 int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
404 int wantchannels = (nchin>n)?chin[n]:wantmore;
405 int alreadyopened = 0;
406 if (!wantchannels)
407 goto end_in_loop;
409 if (thisdevice > 1)
410 sprintf(devname, "/dev/dsp%d", thisdevice - 1);
411 else sprintf(devname, "/dev/dsp");
413 sys_setalarm(1000000);
415 /* perhaps it's already open from the above? */
416 if (linux_dacs[n].d_fd >= 0)
418 fd = linux_dacs[n].d_fd;
419 alreadyopened = 1;
421 else
423 /* otherwise try to open it here. */
424 if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
426 post("%s (readonly): %s", devname, strerror(errno));
427 goto end_in_loop;
429 if (sys_verbose)
430 post("opened %s for reading only\n", devname);
432 linux_adcs[linux_nindevs].d_fd = fd;
433 gotchans = oss_setchannels(fd,
434 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
435 devname);
436 if (sys_verbose)
437 post("opened audio input device %s; got %d channels",
438 devname, gotchans);
440 if (gotchans < 1)
442 close(fd);
443 goto end_in_loop;
446 linux_adcs[linux_nindevs].d_nchannels = gotchans;
448 oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
450 inchannels += gotchans;
451 linux_nindevs++;
453 wantmore = wantchannels-gotchans;
454 /* LATER think about spreading large numbers of channels over
455 various dsp's and vice-versa */
456 end_in_loop: ;
459 /* We have to do a read to start the engine. This is
460 necessary because sys_send_dacs waits until the input
461 buffer is filled and only reads on a filled buffer.
462 This is good, because it's a way to make sure that we
463 will not block. But I wonder why we only have to read
464 from one of the devices and not all of them??? */
466 if (linux_nindevs)
468 if (sys_verbose)
469 fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
470 read(linux_adcs[0].d_fd, buf,
471 linux_adcs[0].d_bytespersamp *
472 linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
473 if (sys_verbose)
474 fprintf(stderr, "...done.\n");
476 sys_setalarm(0);
477 return (0);
480 void oss_close_audio( void)
482 int i;
483 for (i=0;i<linux_nindevs;i++)
484 close(linux_adcs[i].d_fd);
486 for (i=0;i<linux_noutdevs;i++)
487 close(linux_dacs[i].d_fd);
489 linux_nindevs = linux_noutdevs = 0;
492 static int linux_dacs_write(int fd,void* buf,long bytes)
494 return write(fd, buf, bytes);
497 static int linux_adcs_read(int fd,void* buf,long bytes)
499 return read(fd, buf, bytes);
502 /* query audio devices for "available" data size. */
503 static void oss_calcspace(void)
505 int dev;
506 audio_buf_info ainfo;
507 for (dev=0; dev < linux_noutdevs; dev++)
509 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
510 fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
511 linux_dacs[dev].d_space = ainfo.bytes;
514 for (dev = 0; dev < linux_nindevs; dev++)
516 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
517 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
518 dev, linux_adcs[dev].d_fd);
519 linux_adcs[dev].d_space = ainfo.bytes;
523 void linux_audiostatus(void)
525 int dev;
526 if (!oss_blockmode)
528 oss_calcspace();
529 for (dev=0; dev < linux_noutdevs; dev++)
530 fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
532 for (dev = 0; dev < linux_nindevs; dev++)
533 fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
538 /* this call resyncs audio output and input which will cause discontinuities
539 in audio output and/or input. */
541 static void oss_doresync( void)
543 int dev, zeroed = 0, wantsize;
544 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
545 audio_buf_info ainfo;
547 /* 1. if any input devices are ahead (have more than 1 buffer stored),
548 drop one or more buffers worth */
549 for (dev = 0; dev < linux_nindevs; dev++)
551 if (linux_adcs[dev].d_space == 0)
553 linux_adcs_read(linux_adcs[dev].d_fd, buf,
554 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
555 linux_adcs[dev].d_bytespersamp));
557 else while (linux_adcs[dev].d_space >
558 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
559 linux_adcs[dev].d_bytespersamp))
561 linux_adcs_read(linux_adcs[dev].d_fd, buf,
562 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
563 linux_adcs[dev].d_bytespersamp));
564 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
566 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
567 dev, linux_adcs[dev].d_fd);
568 break;
570 linux_adcs[dev].d_space = ainfo.bytes;
574 /* 2. if any output devices are behind, feed them zeros to catch them
575 up */
576 for (dev = 0; dev < linux_noutdevs; dev++)
578 while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
579 sys_advance_samples * (linux_dacs[dev].d_nchannels *
580 linux_dacs[dev].d_bytespersamp))
582 if (!zeroed)
584 unsigned int i;
585 for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
586 i++)
587 buf[i] = 0;
588 zeroed = 1;
590 linux_dacs_write(linux_dacs[dev].d_fd, buf,
591 OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
592 linux_dacs[dev].d_bytespersamp));
593 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
595 fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
596 dev, linux_dacs[dev].d_fd);
597 break;
599 linux_dacs[dev].d_space = ainfo.bytes;
602 /* 3. if any DAC devices are too far ahead, plan to drop the
603 number of frames which will let the others catch up. */
604 for (dev = 0; dev < linux_noutdevs; dev++)
606 if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
607 (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
608 linux_dacs[dev].d_bytespersamp)
610 linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
611 (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
612 (linux_dacs[dev].d_nchannels *
613 linux_dacs[dev].d_bytespersamp) ;
615 else linux_dacs[dev].d_dropcount = 0;
619 int oss_send_dacs(void)
621 t_sample *fp1, *fp2;
622 long fill;
623 int i, j, dev, rtnval = SENDDACS_YES;
624 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
625 t_oss_int16 *sp;
626 t_oss_int32 *lp;
627 /* the maximum number of samples we should have in the ADC buffer */
628 int idle = 0;
629 int thischan;
630 t_time timeref, timenow;
632 if (!linux_nindevs && !linux_noutdevs)
633 return (SENDDACS_NO);
635 if (!oss_blockmode)
637 /* determine whether we're idle. This is true if either (1)
638 some input device has less than one buffer to read or (2) some
639 output device has fewer than (sys_advance_samples) blocks buffered
640 already. */
641 oss_calcspace();
643 for (dev=0; dev < linux_noutdevs; dev++)
644 if (linux_dacs[dev].d_dropcount ||
645 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
646 sys_advance_samples * linux_dacs[dev].d_bytespersamp *
647 linux_dacs[dev].d_nchannels))
648 idle = 1;
649 for (dev=0; dev < linux_nindevs; dev++)
650 if (linux_adcs[dev].d_space <
651 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
652 linux_adcs[dev].d_bytespersamp))
653 idle = 1;
656 if (idle && !oss_blockmode)
658 /* sometimes---rarely---when the ADC available-byte-count is
659 zero, it's genuine, but usually it's because we're so
660 late that the ADC has overrun its entire kernel buffer. We
661 distinguish between the two by waiting 2 msec and asking again.
662 There should be an error flag we could check instead; look for this
663 someday... */
664 for (dev = 0;dev < linux_nindevs; dev++)
665 if (linux_adcs[dev].d_space == 0)
667 audio_buf_info ainfo;
668 sys_microsleep(2000);
669 oss_calcspace();
670 if (linux_adcs[dev].d_space != 0) continue;
672 /* here's the bad case. Give up and resync. */
673 sys_log_error(ERR_DATALATE);
674 oss_doresync();
675 return (SENDDACS_NO);
677 /* check for slippage between devices, either because
678 data got lost in the driver from a previous late condition, or
679 because the devices aren't synced. When we're idle, no
680 input device should have more than one buffer readable and
681 no output device should have less than sys_advance_samples-1
684 for (dev=0; dev < linux_noutdevs; dev++)
685 if (!linux_dacs[dev].d_dropcount &&
686 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
687 (sys_advance_samples - 2) *
688 (linux_dacs[dev].d_bytespersamp *
689 linux_dacs[dev].d_nchannels)))
690 goto badsync;
691 for (dev=0; dev < linux_nindevs; dev++)
692 if (linux_adcs[dev].d_space > 3 *
693 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
694 linux_adcs[dev].d_bytespersamp))
695 goto badsync;
697 /* return zero to tell the scheduler we're idle. */
698 return (SENDDACS_NO);
699 badsync:
700 sys_log_error(ERR_RESYNC);
701 oss_doresync();
702 return (SENDDACS_NO);
707 /* do output */
709 timeref = sys_getrealtime();
710 for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
712 int nchannels = linux_dacs[dev].d_nchannels;
713 if (linux_dacs[dev].d_dropcount)
714 linux_dacs[dev].d_dropcount--;
715 else
717 if (linux_dacs[dev].d_bytespersamp == 4)
719 for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
720 DEFDACBLKSIZE*thischan,
721 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
723 t_sample f = SCALE32(*fp1);
724 *lp = (f >= 2147483647 ? 2147483647 :
725 (f < -2147483647 ? -2147483647 : f));
728 else
730 for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
731 DEFDACBLKSIZE*thischan,
732 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
734 for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
736 int s = SCALE16(*fp2);
737 if (s > 32767) s = 32767;
738 else if (s < -32767) s = -32767;
739 sp[j] = s;
745 #if 0
746 #define PR_S "%8d"
748 int nm = 64;
749 int* sp1 = buf;
750 post("dac:");
751 while (nm > 0)
753 post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S,
754 sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]);
755 nm -= 8;
756 sp1 += 8;
759 #endif
760 linux_dacs_write(linux_dacs[dev].d_fd, buf,
761 OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
763 #if 0
764 if ((timenow = sys_getrealtime()) - timeref > 200)
766 post("dacslept %d",sys_getrealtime() - timeref);
767 if (!oss_blockmode)
768 sys_log_error(ERR_DACSLEPT);
769 else rtnval = SENDDACS_SLEPT;
771 #endif
772 timeref = timenow;
774 thischan += nchannels;
776 memset(sys_soundout, 0,
777 sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
779 /* do input */
781 for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
783 int nchannels = linux_adcs[dev].d_nchannels;
784 linux_adcs_read(linux_adcs[dev].d_fd, buf,
785 OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
787 #if 0
788 if ((timenow = sys_getrealtime()) - timeref > 200)
790 if (!oss_blockmode)
791 sys_log_error(ERR_ADCSLEPT);
792 else
793 rtnval = SENDDACS_SLEPT;
795 #endif
796 timeref = timenow;
798 if (linux_adcs[dev].d_bytespersamp == 4)
800 for (i = DEFDACBLKSIZE*nchannels,
801 fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
802 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
804 *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
807 else
809 for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
810 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
812 for (j=0;j<sys_inchannels;j++)
813 fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
816 thischan += nchannels;
818 if (thischan != sys_inchannels)
819 bug("inchannels");
820 return (rtnval);
823 void oss_listdevs( void)
825 post("device listing not implemented in OSS yet\n");
828 void oss_getdevs(char *indevlist, int *nindevs,
829 char *outdevlist, int *noutdevs, int *canmulti,
830 int maxndev, int devdescsize)
832 int i, ndev;
833 *canmulti = 2; /* supports multiple devices */
834 if ((ndev = oss_ndev) > maxndev)
835 ndev = maxndev;
836 for (i = 0; i < ndev; i++)
838 sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
839 sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
841 *nindevs = *noutdevs = ndev;
844 #endif