summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/s_audio_oss.c
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
commit513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch)
tree10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/s_audio_oss.c
parent95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff)
downloadrockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio_oss.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_oss.c1688
1 files changed, 1688 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_oss.c b/apps/plugins/pdbox/PDa/src/s_audio_oss.c
new file mode 100644
index 0000000000..efb15d1bc1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_oss.c
@@ -0,0 +1,1688 @@
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. */
5
6/* this file inputs and outputs audio using the OSS API available on linux. */
7
8#ifdef USEAPI_OSS
9
10#include <linux/soundcard.h>
11
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>
26
27
28/* Defines */
29#define DEBUG(x) x
30#define DEBUG2(x) {x;}
31
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 */
38typedef int16_t t_oss_int16;
39typedef 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))
44
45/* GLOBALS */
46static int linux_meters; /* true if we're metering */
47static float linux_inmax; /* max input amplitude */
48static float linux_outmax; /* max output amplitude */
49static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
50
51/* our device handles */
52
53typedef struct _oss_dev
54{
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;
62
63static t_oss_dev linux_dacs[OSS_MAXDEV];
64static t_oss_dev linux_adcs[OSS_MAXDEV];
65static int linux_noutdevs = 0;
66static int linux_nindevs = 0;
67
68 /* exported variables */
69float sys_dacsr;
70t_sample *sys_soundout;
71t_sample *sys_soundin;
72
73 /* OSS-specific private variables */
74static int oss_blockmode = 1; /* flag to use "blockmode" */
75static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
76static char ossdsp[] = "/dev/dsp%d";
77
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))
82
83
84/* ------------- private routines for all APIS ------------------- */
85
86static void linux_flush_all_underflows_to_zero(void)
87{
88/*
89 TODO: Implement similar thing for linux (GGeiger)
90
91 One day we will figure this out, I hope, because it
92 costs CPU time dearly on Intel - LT
93 */
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);
98 */
99}
100
101static int oss_ndev = 0;
102
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. */
108void oss_init(void)
109{
110 int fd, i;
111 static int countedthem = 0;
112 if (countedthem)
113 return;
114 for (i = 0; i < 10; i++)
115 {
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)
121 {
122 oss_ndev++;
123 close(fd);
124 }
125 else break;
126 }
127 countedthem = 1;
128}
129
130
131void oss_set32bit( void)
132{
133 oss_32bit = 1;
134}
135
136
137typedef struct _multidev {
138 int fd;
139 int channels;
140 int format;
141} t_multidev;
142
143int 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;
148}
149
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... */
154
155#ifndef AFMT_S32_BLOCKED
156#define AFMT_S32_BLOCKED 0x0000400
157#endif
158
159void 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;
164
165 audio_buf_info ainfo;
166
167 /* IOhannes :
168 * pd is very likely to crash if different formats are used on
169 multiple soundcards
170 */
171
172 /* set resolution - first try 4 byte samples */
173 if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
174 (param & AFMT_S32_BLOCKED))
175 {
176 wantformat = AFMT_S32_BLOCKED;
177 dev->d_bytespersamp = 4;
178 }
179 else
180 {
181 wantformat = AFMT_S16_NE;
182 dev->d_bytespersamp = 2;
183 }
184 param = wantformat;
185
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);
193
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 );
201
202 if (oss_blockmode && !skipblocksize)
203 {
204 int fragbytes, logfragsize, nfragment;
205 /* setting fragment count and size. */
206 if (!linux_fragsize)
207 {
208 linux_fragsize = OSS_DEFFRAGSIZE;
209 while (linux_fragsize > DEFDACBLKSIZE
210 && linux_fragsize * 4 > sys_advance_samples)
211 linux_fragsize = linux_fragsize/2;
212 }
213
214 /* post("adv_samples %d", sys_advance_samples); */
215 nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
216
217 fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
218 logfragsize = ilog2(fragbytes);
219
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);
225
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)
230 {
231 nfragment = ((param >> 16) & 0xffff);
232 logfragsize = (param & 0xffff);
233 post("warning: actual fragments %d, blocksize %d",
234 nfragment, (1 << logfragsize));
235 }
236 if (sys_verbose)
237 post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
238 }
239 if (dac)
240 {
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. */
247
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;
252
253 defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
254 - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
255 if (defect > 0)
256 {
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);
265 }
266 }
267}
268
269static int oss_setchannels(int fd, int wantchannels, char *devname)
270{ /* IOhannes */
271 int param = wantchannels;
272
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);
279 }
280 param=save-1;
281 }
282
283 return (0);
284}
285
286#define O_AUDIOFLAG 0 /* O_NDELAY */
287
288int 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;
300
301 linux_nindevs = linux_noutdevs = 0;
302
303
304 /* mark input devices unopened */
305 for (i = 0; i < OSS_MAXDEV; i++)
306 linux_adcs[i].d_fd = -1;
307
308 /* open output devices */
309 wantmore=0;
310 if (noutdev < 0 || nindev < 0)
311 bug("linux_open_audio");
312
313 for (n = 0; n < noutdev; n++)
314 {
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;
321
322 if (thisdevice > 1)
323 sprintf(devname, "/dev/dsp%d", thisdevice-1);
324 else sprintf(devname, "/dev/dsp");
325
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;
331
332 /* if the same device is requested for input and output,
333 try to open it read/write */
334 if (inindex >= 0)
335 {
336 sys_setalarm(1000000);
337 if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
338 {
339 post("%s (read/write): %s", devname, strerror(errno));
340 post("(now will try write-only...)");
341 }
342 else
343 {
344 if (sys_verbose)
345 post("opened %s for reading and writing\n", devname);
346 linux_adcs[inindex].d_fd = fd;
347 }
348 }
349 /* if that didn't happen or if it failed, try write-only */
350 if (fd == -1)
351 {
352 sys_setalarm(1000000);
353 if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
354 {
355 post("%s (writeonly): %s",
356 devname, strerror(errno));
357 break;
358 }
359 if (sys_verbose)
360 post("opened %s for writing only\n", devname);
361 }
362 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
363 error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
364
365 gotchans = oss_setchannels(fd,
366 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
367 devname);
368
369 if (sys_verbose)
370 post("opened audio output on %s; got %d channels",
371 devname, gotchans);
372
373 if (gotchans < 2)
374 {
375 /* can't even do stereo? just give up. */
376 close(fd);
377 }
378 else
379 {
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);
383
384 linux_noutdevs++;
385 outchannels += gotchans;
386 if (inindex >= 0)
387 {
388 linux_adcs[inindex].d_nchannels = gotchans;
389 chin[inindex] = gotchans;
390 }
391 }
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: ;
396 }
397
398 /* open input devices */
399 wantmore = 0;
400 for (n = 0; n < nindev; n++)
401 {
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;
408
409 if (thisdevice > 1)
410 sprintf(devname, "/dev/dsp%d", thisdevice - 1);
411 else sprintf(devname, "/dev/dsp");
412
413 sys_setalarm(1000000);
414
415 /* perhaps it's already open from the above? */
416 if (linux_dacs[n].d_fd >= 0)
417 {
418 fd = linux_dacs[n].d_fd;
419 alreadyopened = 1;
420 }
421 else
422 {
423 /* otherwise try to open it here. */
424 if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
425 {
426 post("%s (readonly): %s", devname, strerror(errno));
427 goto end_in_loop;
428 }
429 if (sys_verbose)
430 post("opened %s for reading only\n", devname);
431 }
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);
439
440 if (gotchans < 1)
441 {
442 close(fd);
443 goto end_in_loop;
444 }
445
446 linux_adcs[linux_nindevs].d_nchannels = gotchans;
447
448 oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
449
450 inchannels += gotchans;
451 linux_nindevs++;
452
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: ;
457 }
458
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??? */
465
466 if (linux_nindevs)
467 {
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");
475 }
476 sys_setalarm(0);
477 return (0);
478}
479
480void oss_close_audio( void)
481{
482 int i;
483 for (i=0;i<linux_nindevs;i++)
484 close(linux_adcs[i].d_fd);
485
486 for (i=0;i<linux_noutdevs;i++)
487 close(linux_dacs[i].d_fd);
488
489 linux_nindevs = linux_noutdevs = 0;
490}
491
492static int linux_dacs_write(int fd,void* buf,long bytes)
493{
494 return write(fd, buf, bytes);
495}
496
497static int linux_adcs_read(int fd,void* buf,long bytes)
498{
499 return read(fd, buf, bytes);
500}
501
502 /* query audio devices for "available" data size. */
503static void oss_calcspace(void)
504{
505 int dev;
506 audio_buf_info ainfo;
507 for (dev=0; dev < linux_noutdevs; dev++)
508 {
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;
512 }
513
514 for (dev = 0; dev < linux_nindevs; dev++)
515 {
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;
520 }
521}
522
523void linux_audiostatus(void)
524{
525 int dev;
526 if (!oss_blockmode)
527 {
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);
531
532 for (dev = 0; dev < linux_nindevs; dev++)
533 fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
534
535 }
536}
537
538/* this call resyncs audio output and input which will cause discontinuities
539in audio output and/or input. */
540
541static void oss_doresync( void)
542{
543 int dev, zeroed = 0, wantsize;
544 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
545 audio_buf_info ainfo;
546
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++)
550 {
551 if (linux_adcs[dev].d_space == 0)
552 {
553 linux_adcs_read(linux_adcs[dev].d_fd, buf,
554 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
555 linux_adcs[dev].d_bytespersamp));
556 }
557 else while (linux_adcs[dev].d_space >
558 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
559 linux_adcs[dev].d_bytespersamp))
560 {
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)
565 {
566 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
567 dev, linux_adcs[dev].d_fd);
568 break;
569 }
570 linux_adcs[dev].d_space = ainfo.bytes;
571 }
572 }
573
574 /* 2. if any output devices are behind, feed them zeros to catch them
575 up */
576 for (dev = 0; dev < linux_noutdevs; dev++)
577 {
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))
581 {
582 if (!zeroed)
583 {
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;
589 }
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)
594 {
595 fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
596 dev, linux_dacs[dev].d_fd);
597 break;
598 }
599 linux_dacs[dev].d_space = ainfo.bytes;
600 }
601 }
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++)
605 {
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)
609 {
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) ;
614 }
615 else linux_dacs[dev].d_dropcount = 0;
616 }
617}
618
619int oss_send_dacs(void)
620{
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;
631
632 if (!linux_nindevs && !linux_noutdevs)
633 return (SENDDACS_NO);
634
635 if (!oss_blockmode)
636 {
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();
642
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;
654 }
655
656 if (idle && !oss_blockmode)
657 {
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)
666 {
667 audio_buf_info ainfo;
668 sys_microsleep(2000);
669 oss_calcspace();
670 if (linux_adcs[dev].d_space != 0) continue;
671
672 /* here's the bad case. Give up and resync. */
673 sys_log_error(ERR_DATALATE);
674 oss_doresync();
675 return (SENDDACS_NO);
676 }
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
682 */
683
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;
696
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);
703
704 }
705
706
707 /* do output */
708
709 timeref = sys_getrealtime();
710 for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
711 {
712 int nchannels = linux_dacs[dev].d_nchannels;
713 if (linux_dacs[dev].d_dropcount)
714 linux_dacs[dev].d_dropcount--;
715 else
716 {
717 if (linux_dacs[dev].d_bytespersamp == 4)
718 {
719 for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
720 DEFDACBLKSIZE*thischan,
721 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
722 {
723 t_sample f = SCALE32(*fp1);
724 *lp = (f >= 2147483647 ? 2147483647 :
725 (f < -2147483647 ? -2147483647 : f));
726 }
727 }
728 else
729 {
730 for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
731 DEFDACBLKSIZE*thischan,
732 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
733 {
734 for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
735 {
736 int s = SCALE16(*fp2);
737 if (s > 32767) s = 32767;
738 else if (s < -32767) s = -32767;
739 sp[j] = s;
740 }
741 }
742 }
743
744
745#if 0
746#define PR_S "%8d"
747 {
748 int nm = 64;
749 int* sp1 = buf;
750 post("dac:");
751 while (nm > 0)
752 {
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;
757 }
758 }
759#endif
760 linux_dacs_write(linux_dacs[dev].d_fd, buf,
761 OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
762
763#if 0
764 if ((timenow = sys_getrealtime()) - timeref > 200)
765 {
766 post("dacslept %d",sys_getrealtime() - timeref);
767 if (!oss_blockmode)
768 sys_log_error(ERR_DACSLEPT);
769 else rtnval = SENDDACS_SLEPT;
770 }
771#endif
772 timeref = timenow;
773 }
774 thischan += nchannels;
775 }
776 memset(sys_soundout, 0,
777 sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
778
779 /* do input */
780
781 for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
782 {
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));
786
787#if 0
788 if ((timenow = sys_getrealtime()) - timeref > 200)
789 {
790 if (!oss_blockmode)
791 sys_log_error(ERR_ADCSLEPT);
792 else
793 rtnval = SENDDACS_SLEPT;
794 }
795#endif
796 timeref = timenow;
797
798 if (linux_adcs[dev].d_bytespersamp == 4)
799 {
800 for (i = DEFDACBLKSIZE*nchannels,
801 fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
802 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
803 {
804 *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
805 }
806 }
807 else
808 {
809 for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
810 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
811 {
812 for (j=0;j<sys_inchannels;j++)
813 fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
814 }
815 }
816 thischan += nchannels;
817 }
818 if (thischan != sys_inchannels)
819 bug("inchannels");
820 return (rtnval);
821}
822
823void oss_listdevs( void)
824{
825 post("device listing not implemented in OSS yet\n");
826}
827
828void oss_getdevs(char *indevlist, int *nindevs,
829 char *outdevlist, int *noutdevs, int *canmulti,
830 int maxndev, int devdescsize)
831{
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++)
837 {
838 sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
839 sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
840 }
841 *nindevs = *noutdevs = ndev;
842}
843
844#endif
845/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
846* Winfried Ritsch, Karl MacMillan, and others.
847* For information on usage and redistribution, and for a DISCLAIMER OF ALL
848* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
849
850/* this file inputs and outputs audio using the OSS API available on linux. */
851
852#ifdef USEAPI_OSS
853
854#include <linux/soundcard.h>
855
856#include "m_pd.h"
857#include "s_stuff.h"
858#include <errno.h>
859#include <stdio.h>
860#include <unistd.h>
861#include <stdlib.h>
862#include <string.h>
863#include <sys/types.h>
864#include <sys/time.h>
865#include <sys/stat.h>
866#include <sys/ioctl.h>
867#include <fcntl.h>
868#include <sched.h>
869#include <sys/mman.h>
870
871
872/* Defines */
873#define DEBUG(x) x
874#define DEBUG2(x) {x;}
875
876#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
877#define OSS_MAXDEV 4 /* maximum number of input or output devices */
878#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
879#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
880#define OSS_DEFAULTCH 2
881#define RME_DEFAULTCH 8 /* need this even if RME undefined */
882typedef int16_t t_oss_int16;
883typedef int32_t t_oss_int32;
884#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
885#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
886#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
887#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
888
889/* GLOBALS */
890static int linux_meters; /* true if we're metering */
891static float linux_inmax; /* max input amplitude */
892static float linux_outmax; /* max output amplitude */
893static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
894
895/* our device handles */
896
897typedef struct _oss_dev
898{
899 int d_fd;
900 unsigned int d_space; /* bytes available for writing/reading */
901 int d_bufsize; /* total buffer size in blocks for this device */
902 int d_dropcount; /* # of buffers to drop for resync (output only) */
903 unsigned int d_nchannels; /* number of channels for this device */
904 unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
905} t_oss_dev;
906
907static t_oss_dev linux_dacs[OSS_MAXDEV];
908static t_oss_dev linux_adcs[OSS_MAXDEV];
909static int linux_noutdevs = 0;
910static int linux_nindevs = 0;
911
912 /* exported variables */
913float sys_dacsr;
914t_sample *sys_soundout;
915t_sample *sys_soundin;
916
917 /* OSS-specific private variables */
918static int oss_blockmode = 1; /* flag to use "blockmode" */
919static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
920static char ossdsp[] = "/dev/dsp%d";
921
922 /* don't assume we can turn all 31 bits when doing float-to-fix;
923 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
924#define FMAX 0x7ffff000
925#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
926
927
928/* ------------- private routines for all APIS ------------------- */
929
930static void linux_flush_all_underflows_to_zero(void)
931{
932/*
933 TODO: Implement similar thing for linux (GGeiger)
934
935 One day we will figure this out, I hope, because it
936 costs CPU time dearly on Intel - LT
937 */
938 /* union fpc_csr f;
939 f.fc_word = get_fpc_csr();
940 f.fc_struct.flush = 1;
941 set_fpc_csr(f.fc_word);
942 */
943}
944
945static int oss_ndev = 0;
946
947 /* find out how many OSS devices we have. Since this has to
948 open the devices to find out if they're there, we have
949 to be called before audio is actually started up. So we
950 cache the results, which in effect are the number of available
951 devices. */
952void oss_init(void)
953{
954 int fd, i;
955 static int countedthem = 0;
956 if (countedthem)
957 return;
958 for (i = 0; i < 10; i++)
959 {
960 char devname[100];
961 if (i == 0)
962 strcpy(devname, "/dev/dsp");
963 else sprintf(devname, "/dev/dsp%d", i);
964 if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1)
965 {
966 oss_ndev++;
967 close(fd);
968 }
969 else break;
970 }
971 countedthem = 1;
972}
973
974
975void oss_set32bit( void)
976{
977 oss_32bit = 1;
978}
979
980
981typedef struct _multidev {
982 int fd;
983 int channels;
984 int format;
985} t_multidev;
986
987int oss_reset(int fd) {
988 int err;
989 if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
990 error("OSS: Could not reset");
991 return err;
992}
993
994 /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
995 but is proposed by Guenter Geiger to support extending OSS to handle
996 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
997 I'm not clear why this isn't called AFMT_S32_[SLN]E... */
998
999#ifndef AFMT_S32_BLOCKED
1000#define AFMT_S32_BLOCKED 0x0000400
1001#endif
1002
1003void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
1004{ /* IOhannes */
1005 int orig, param, nblk, fd = dev->d_fd, wantformat;
1006 int nchannels = dev->d_nchannels;
1007 int advwas = sys_schedadvance;
1008
1009 audio_buf_info ainfo;
1010
1011 /* IOhannes :
1012 * pd is very likely to crash if different formats are used on
1013 multiple soundcards
1014 */
1015
1016 /* set resolution - first try 4 byte samples */
1017 if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
1018 (param & AFMT_S32_BLOCKED))
1019 {
1020 wantformat = AFMT_S32_BLOCKED;
1021 dev->d_bytespersamp = 4;
1022 }
1023 else
1024 {
1025 wantformat = AFMT_S16_NE;
1026 dev->d_bytespersamp = 2;
1027 }
1028 param = wantformat;
1029
1030 if (sys_verbose)
1031 post("bytes per sample = %d", dev->d_bytespersamp);
1032 if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
1033 fprintf(stderr,"OSS: Could not set DSP format\n");
1034 else if (wantformat != param)
1035 fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
1036 wantformat, param);
1037
1038 /* sample rate */
1039 orig = param = srate;
1040 if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
1041 fprintf(stderr,"OSS: Could not set sampling rate for device\n");
1042 else if( orig != param )
1043 fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
1044 orig, param );
1045
1046 if (oss_blockmode && !skipblocksize)
1047 {
1048 int fragbytes, logfragsize, nfragment;
1049 /* setting fragment count and size. */
1050 if (!linux_fragsize)
1051 {
1052 linux_fragsize = OSS_DEFFRAGSIZE;
1053 while (linux_fragsize > DEFDACBLKSIZE
1054 && linux_fragsize * 4 > sys_advance_samples)
1055 linux_fragsize = linux_fragsize/2;
1056 }
1057
1058 /* post("adv_samples %d", sys_advance_samples); */
1059 nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
1060
1061 fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
1062 logfragsize = ilog2(fragbytes);
1063
1064 if (fragbytes != (1 << logfragsize))
1065 post("warning: OSS takes only power of 2 blocksize; using %d",
1066 (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
1067 if (sys_verbose)
1068 post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
1069
1070 param = orig = (nfragment<<16) + logfragsize;
1071 if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
1072 error("OSS: Could not set or read fragment size\n");
1073 if (param != orig)
1074 {
1075 nfragment = ((param >> 16) & 0xffff);
1076 logfragsize = (param & 0xffff);
1077 post("warning: actual fragments %d, blocksize %d",
1078 nfragment, (1 << logfragsize));
1079 }
1080 if (sys_verbose)
1081 post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
1082 }
1083 if (dac)
1084 {
1085 /* use "free space" to learn the buffer size. Normally you
1086 should set this to your own desired value; but this seems not
1087 to be implemented uniformly across different sound cards. LATER
1088 we should figure out what to do if the requested scheduler advance
1089 is greater than this buffer size; for now, we just print something
1090 out. */
1091
1092 int defect;
1093 if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
1094 fprintf(stderr,"OSS: ioctl on output device failed");
1095 dev->d_bufsize = ainfo.bytes;
1096
1097 defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
1098 - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
1099 if (defect > 0)
1100 {
1101 if (sys_verbose || defect > (dev->d_bufsize >> 2))
1102 fprintf(stderr,
1103 "OSS: requested audio buffer size %d limited to %d\n",
1104 sys_advance_samples * (dev->d_bytespersamp * nchannels),
1105 dev->d_bufsize);
1106 sys_advance_samples =
1107 (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
1108 (dev->d_bytespersamp *nchannels);
1109 }
1110 }
1111}
1112
1113static int oss_setchannels(int fd, int wantchannels, char *devname)
1114{ /* IOhannes */
1115 int param = wantchannels;
1116
1117 while (param>1) {
1118 int save = param;
1119 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
1120 error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
1121 } else {
1122 if (param == save) return (param);
1123 }
1124 param=save-1;
1125 }
1126
1127 return (0);
1128}
1129
1130#define O_AUDIOFLAG 0 /* O_NDELAY */
1131
1132int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
1133 int noutdev, int *outdev, int nchout, int *chout, int rate)
1134{ /* IOhannes */
1135 int capabilities = 0;
1136 int inchannels = 0, outchannels = 0;
1137 char devname[20];
1138 int n, i, fd;
1139 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1140 int num_devs = 0;
1141 int wantmore=0;
1142 int spread = 0;
1143 audio_buf_info ainfo;
1144
1145 linux_nindevs = linux_noutdevs = 0;
1146
1147
1148 /* mark input devices unopened */
1149 for (i = 0; i < OSS_MAXDEV; i++)
1150 linux_adcs[i].d_fd = -1;
1151
1152 /* open output devices */
1153 wantmore=0;
1154 if (noutdev < 0 || nindev < 0)
1155 bug("linux_open_audio");
1156
1157 for (n = 0; n < noutdev; n++)
1158 {
1159 int gotchans, j, inindex = -1;
1160 int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
1161 int wantchannels = (nchout>n) ? chout[n] : wantmore;
1162 fd = -1;
1163 if (!wantchannels)
1164 goto end_out_loop;
1165
1166 if (thisdevice > 1)
1167 sprintf(devname, "/dev/dsp%d", thisdevice-1);
1168 else sprintf(devname, "/dev/dsp");
1169
1170 /* search for input request for same device. Succeed only
1171 if the number of channels matches. */
1172 for (j = 0; j < nindev; j++)
1173 if (indev[j] == thisdevice && chin[j] == wantchannels)
1174 inindex = j;
1175
1176 /* if the same device is requested for input and output,
1177 try to open it read/write */
1178 if (inindex >= 0)
1179 {
1180 sys_setalarm(1000000);
1181 if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
1182 {
1183 post("%s (read/write): %s", devname, strerror(errno));
1184 post("(now will try write-only...)");
1185 }
1186 else
1187 {
1188 if (sys_verbose)
1189 post("opened %s for reading and writing\n", devname);
1190 linux_adcs[inindex].d_fd = fd;
1191 }
1192 }
1193 /* if that didn't happen or if it failed, try write-only */
1194 if (fd == -1)
1195 {
1196 sys_setalarm(1000000);
1197 if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
1198 {
1199 post("%s (writeonly): %s",
1200 devname, strerror(errno));
1201 break;
1202 }
1203 if (sys_verbose)
1204 post("opened %s for writing only\n", devname);
1205 }
1206 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
1207 error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
1208
1209 gotchans = oss_setchannels(fd,
1210 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
1211 devname);
1212
1213 if (sys_verbose)
1214 post("opened audio output on %s; got %d channels",
1215 devname, gotchans);
1216
1217 if (gotchans < 2)
1218 {
1219 /* can't even do stereo? just give up. */
1220 close(fd);
1221 }
1222 else
1223 {
1224 linux_dacs[linux_noutdevs].d_nchannels = gotchans;
1225 linux_dacs[linux_noutdevs].d_fd = fd;
1226 oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
1227
1228 linux_noutdevs++;
1229 outchannels += gotchans;
1230 if (inindex >= 0)
1231 {
1232 linux_adcs[inindex].d_nchannels = gotchans;
1233 chin[inindex] = gotchans;
1234 }
1235 }
1236 /* LATER think about spreading large numbers of channels over
1237 various dsp's and vice-versa */
1238 wantmore = wantchannels - gotchans;
1239 end_out_loop: ;
1240 }
1241
1242 /* open input devices */
1243 wantmore = 0;
1244 for (n = 0; n < nindev; n++)
1245 {
1246 int gotchans=0;
1247 int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
1248 int wantchannels = (nchin>n)?chin[n]:wantmore;
1249 int alreadyopened = 0;
1250 if (!wantchannels)
1251 goto end_in_loop;
1252
1253 if (thisdevice > 1)
1254 sprintf(devname, "/dev/dsp%d", thisdevice - 1);
1255 else sprintf(devname, "/dev/dsp");
1256
1257 sys_setalarm(1000000);
1258
1259 /* perhaps it's already open from the above? */
1260 if (linux_dacs[n].d_fd >= 0)
1261 {
1262 fd = linux_dacs[n].d_fd;
1263 alreadyopened = 1;
1264 }
1265 else
1266 {
1267 /* otherwise try to open it here. */
1268 if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
1269 {
1270 post("%s (readonly): %s", devname, strerror(errno));
1271 goto end_in_loop;
1272 }
1273 if (sys_verbose)
1274 post("opened %s for reading only\n", devname);
1275 }
1276 linux_adcs[linux_nindevs].d_fd = fd;
1277 gotchans = oss_setchannels(fd,
1278 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
1279 devname);
1280 if (sys_verbose)
1281 post("opened audio input device %s; got %d channels",
1282 devname, gotchans);
1283
1284 if (gotchans < 1)
1285 {
1286 close(fd);
1287 goto end_in_loop;
1288 }
1289
1290 linux_adcs[linux_nindevs].d_nchannels = gotchans;
1291
1292 oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
1293
1294 inchannels += gotchans;
1295 linux_nindevs++;
1296
1297 wantmore = wantchannels-gotchans;
1298 /* LATER think about spreading large numbers of channels over
1299 various dsp's and vice-versa */
1300 end_in_loop: ;
1301 }
1302
1303 /* We have to do a read to start the engine. This is
1304 necessary because sys_send_dacs waits until the input
1305 buffer is filled and only reads on a filled buffer.
1306 This is good, because it's a way to make sure that we
1307 will not block. But I wonder why we only have to read
1308 from one of the devices and not all of them??? */
1309
1310 if (linux_nindevs)
1311 {
1312 if (sys_verbose)
1313 fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
1314 read(linux_adcs[0].d_fd, buf,
1315 linux_adcs[0].d_bytespersamp *
1316 linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
1317 if (sys_verbose)
1318 fprintf(stderr, "...done.\n");
1319 }
1320 sys_setalarm(0);
1321 return (0);
1322}
1323
1324void oss_close_audio( void)
1325{
1326 int i;
1327 for (i=0;i<linux_nindevs;i++)
1328 close(linux_adcs[i].d_fd);
1329
1330 for (i=0;i<linux_noutdevs;i++)
1331 close(linux_dacs[i].d_fd);
1332
1333 linux_nindevs = linux_noutdevs = 0;
1334}
1335
1336static int linux_dacs_write(int fd,void* buf,long bytes)
1337{
1338 return write(fd, buf, bytes);
1339}
1340
1341static int linux_adcs_read(int fd,void* buf,long bytes)
1342{
1343 return read(fd, buf, bytes);
1344}
1345
1346 /* query audio devices for "available" data size. */
1347static void oss_calcspace(void)
1348{
1349 int dev;
1350 audio_buf_info ainfo;
1351 for (dev=0; dev < linux_noutdevs; dev++)
1352 {
1353 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
1354 fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
1355 linux_dacs[dev].d_space = ainfo.bytes;
1356 }
1357
1358 for (dev = 0; dev < linux_nindevs; dev++)
1359 {
1360 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
1361 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
1362 dev, linux_adcs[dev].d_fd);
1363 linux_adcs[dev].d_space = ainfo.bytes;
1364 }
1365}
1366
1367void linux_audiostatus(void)
1368{
1369 int dev;
1370 if (!oss_blockmode)
1371 {
1372 oss_calcspace();
1373 for (dev=0; dev < linux_noutdevs; dev++)
1374 fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
1375
1376 for (dev = 0; dev < linux_nindevs; dev++)
1377 fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
1378
1379 }
1380}
1381
1382/* this call resyncs audio output and input which will cause discontinuities
1383in audio output and/or input. */
1384
1385static void oss_doresync( void)
1386{
1387 int dev, zeroed = 0, wantsize;
1388 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1389 audio_buf_info ainfo;
1390
1391 /* 1. if any input devices are ahead (have more than 1 buffer stored),
1392 drop one or more buffers worth */
1393 for (dev = 0; dev < linux_nindevs; dev++)
1394 {
1395 if (linux_adcs[dev].d_space == 0)
1396 {
1397 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1398 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1399 linux_adcs[dev].d_bytespersamp));
1400 }
1401 else while (linux_adcs[dev].d_space >
1402 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1403 linux_adcs[dev].d_bytespersamp))
1404 {
1405 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1406 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1407 linux_adcs[dev].d_bytespersamp));
1408 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
1409 {
1410 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
1411 dev, linux_adcs[dev].d_fd);
1412 break;
1413 }
1414 linux_adcs[dev].d_space = ainfo.bytes;
1415 }
1416 }
1417
1418 /* 2. if any output devices are behind, feed them zeros to catch them
1419 up */
1420 for (dev = 0; dev < linux_noutdevs; dev++)
1421 {
1422 while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
1423 sys_advance_samples * (linux_dacs[dev].d_nchannels *
1424 linux_dacs[dev].d_bytespersamp))
1425 {
1426 if (!zeroed)
1427 {
1428 unsigned int i;
1429 for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
1430 i++)
1431 buf[i] = 0;
1432 zeroed = 1;
1433 }
1434 linux_dacs_write(linux_dacs[dev].d_fd, buf,
1435 OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
1436 linux_dacs[dev].d_bytespersamp));
1437 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
1438 {
1439 fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
1440 dev, linux_dacs[dev].d_fd);
1441 break;
1442 }
1443 linux_dacs[dev].d_space = ainfo.bytes;
1444 }
1445 }
1446 /* 3. if any DAC devices are too far ahead, plan to drop the
1447 number of frames which will let the others catch up. */
1448 for (dev = 0; dev < linux_noutdevs; dev++)
1449 {
1450 if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
1451 (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
1452 linux_dacs[dev].d_bytespersamp)
1453 {
1454 linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
1455 (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
1456 (linux_dacs[dev].d_nchannels *
1457 linux_dacs[dev].d_bytespersamp) ;
1458 }
1459 else linux_dacs[dev].d_dropcount = 0;
1460 }
1461}
1462
1463int oss_send_dacs(void)
1464{
1465 t_sample *fp1, *fp2;
1466 long fill;
1467 int i, j, dev, rtnval = SENDDACS_YES;
1468 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1469 t_oss_int16 *sp;
1470 t_oss_int32 *lp;
1471 /* the maximum number of samples we should have in the ADC buffer */
1472 int idle = 0;
1473 int thischan;
1474 t_time timeref, timenow;
1475
1476 if (!linux_nindevs && !linux_noutdevs)
1477 return (SENDDACS_NO);
1478
1479 if (!oss_blockmode)
1480 {
1481 /* determine whether we're idle. This is true if either (1)
1482 some input device has less than one buffer to read or (2) some
1483 output device has fewer than (sys_advance_samples) blocks buffered
1484 already. */
1485 oss_calcspace();
1486
1487 for (dev=0; dev < linux_noutdevs; dev++)
1488 if (linux_dacs[dev].d_dropcount ||
1489 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
1490 sys_advance_samples * linux_dacs[dev].d_bytespersamp *
1491 linux_dacs[dev].d_nchannels))
1492 idle = 1;
1493 for (dev=0; dev < linux_nindevs; dev++)
1494 if (linux_adcs[dev].d_space <
1495 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1496 linux_adcs[dev].d_bytespersamp))
1497 idle = 1;
1498 }
1499
1500 if (idle && !oss_blockmode)
1501 {
1502 /* sometimes---rarely---when the ADC available-byte-count is
1503 zero, it's genuine, but usually it's because we're so
1504 late that the ADC has overrun its entire kernel buffer. We
1505 distinguish between the two by waiting 2 msec and asking again.
1506 There should be an error flag we could check instead; look for this
1507 someday... */
1508 for (dev = 0;dev < linux_nindevs; dev++)
1509 if (linux_adcs[dev].d_space == 0)
1510 {
1511 audio_buf_info ainfo;
1512 sys_microsleep(2000);
1513 oss_calcspace();
1514 if (linux_adcs[dev].d_space != 0) continue;
1515
1516 /* here's the bad case. Give up and resync. */
1517 sys_log_error(ERR_DATALATE);
1518 oss_doresync();
1519 return (SENDDACS_NO);
1520 }
1521 /* check for slippage between devices, either because
1522 data got lost in the driver from a previous late condition, or
1523 because the devices aren't synced. When we're idle, no
1524 input device should have more than one buffer readable and
1525 no output device should have less than sys_advance_samples-1
1526 */
1527
1528 for (dev=0; dev < linux_noutdevs; dev++)
1529 if (!linux_dacs[dev].d_dropcount &&
1530 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
1531 (sys_advance_samples - 2) *
1532 (linux_dacs[dev].d_bytespersamp *
1533 linux_dacs[dev].d_nchannels)))
1534 goto badsync;
1535 for (dev=0; dev < linux_nindevs; dev++)
1536 if (linux_adcs[dev].d_space > 3 *
1537 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1538 linux_adcs[dev].d_bytespersamp))
1539 goto badsync;
1540
1541 /* return zero to tell the scheduler we're idle. */
1542 return (SENDDACS_NO);
1543 badsync:
1544 sys_log_error(ERR_RESYNC);
1545 oss_doresync();
1546 return (SENDDACS_NO);
1547
1548 }
1549
1550
1551 /* do output */
1552
1553 timeref = sys_getrealtime();
1554 for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
1555 {
1556 int nchannels = linux_dacs[dev].d_nchannels;
1557 if (linux_dacs[dev].d_dropcount)
1558 linux_dacs[dev].d_dropcount--;
1559 else
1560 {
1561 if (linux_dacs[dev].d_bytespersamp == 4)
1562 {
1563 for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
1564 DEFDACBLKSIZE*thischan,
1565 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
1566 {
1567 t_sample f = SCALE32(*fp1);
1568 *lp = (f >= 2147483647 ? 2147483647 :
1569 (f < -2147483647 ? -2147483647 : f));
1570 }
1571 }
1572 else
1573 {
1574 for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
1575 DEFDACBLKSIZE*thischan,
1576 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
1577 {
1578 for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
1579 {
1580 int s = SCALE16(*fp2);
1581 if (s > 32767) s = 32767;
1582 else if (s < -32767) s = -32767;
1583 sp[j] = s;
1584 }
1585 }
1586 }
1587
1588
1589#if 0
1590#define PR_S "%8d"
1591 {
1592 int nm = 64;
1593 int* sp1 = buf;
1594 post("dac:");
1595 while (nm > 0)
1596 {
1597 post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S,
1598 sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]);
1599 nm -= 8;
1600 sp1 += 8;
1601 }
1602 }
1603#endif
1604 linux_dacs_write(linux_dacs[dev].d_fd, buf,
1605 OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
1606
1607#if 0
1608 if ((timenow = sys_getrealtime()) - timeref > 200)
1609 {
1610 post("dacslept %d",sys_getrealtime() - timeref);
1611 if (!oss_blockmode)
1612 sys_log_error(ERR_DACSLEPT);
1613 else rtnval = SENDDACS_SLEPT;
1614 }
1615#endif
1616 timeref = timenow;
1617 }
1618 thischan += nchannels;
1619 }
1620 memset(sys_soundout, 0,
1621 sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
1622
1623 /* do input */
1624
1625 for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
1626 {
1627 int nchannels = linux_adcs[dev].d_nchannels;
1628 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1629 OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
1630
1631#if 0
1632 if ((timenow = sys_getrealtime()) - timeref > 200)
1633 {
1634 if (!oss_blockmode)
1635 sys_log_error(ERR_ADCSLEPT);
1636 else
1637 rtnval = SENDDACS_SLEPT;
1638 }
1639#endif
1640 timeref = timenow;
1641
1642 if (linux_adcs[dev].d_bytespersamp == 4)
1643 {
1644 for (i = DEFDACBLKSIZE*nchannels,
1645 fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
1646 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
1647 {
1648 *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
1649 }
1650 }
1651 else
1652 {
1653 for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
1654 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
1655 {
1656 for (j=0;j<sys_inchannels;j++)
1657 fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
1658 }
1659 }
1660 thischan += nchannels;
1661 }
1662 if (thischan != sys_inchannels)
1663 bug("inchannels");
1664 return (rtnval);
1665}
1666
1667void oss_listdevs( void)
1668{
1669 post("device listing not implemented in OSS yet\n");
1670}
1671
1672void oss_getdevs(char *indevlist, int *nindevs,
1673 char *outdevlist, int *noutdevs, int *canmulti,
1674 int maxndev, int devdescsize)
1675{
1676 int i, ndev;
1677 *canmulti = 2; /* supports multiple devices */
1678 if ((ndev = oss_ndev) > maxndev)
1679 ndev = maxndev;
1680 for (i = 0; i < ndev; i++)
1681 {
1682 sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
1683 sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
1684 }
1685 *nindevs = *noutdevs = ndev;
1686}
1687
1688#endif