1 /*
2 * ossaudiodev -- Python interface to the OSS (Open Sound System) API.
3 * This is the standard audio API for Linux and some
4 * flavours of BSD [XXX which ones?]; it is also available
5 * for a wide range of commercial Unices.
6 *
7 * Originally written by Peter Bosch, March 2000, as linuxaudiodev.
8 *
9 * Renamed to ossaudiodev and rearranged/revised/hacked up
10 * by Greg Ward <gward@python.net>, November 2002.
11 * Mixer interface by Nicholas FitzRoy-Dale <wzdd@lardcave.net>, Dec 2002.
12 *
13 * (c) 2000 Peter Bosch. All Rights Reserved.
14 * (c) 2002 Gregory P. Ward. All Rights Reserved.
15 * (c) 2002 Python Software Foundation. All Rights Reserved.
16 *
17 * $Id$
18 */
19
20 #define PY_SSIZE_T_CLEAN
21 #include "Python.h"
22 #include "structmember.h" // PyMemberDef
23
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #else
27 #define O_RDONLY 00
28 #define O_WRONLY 01
29 #endif
30
31 #include <sys/ioctl.h>
32 #ifdef __ANDROID__
33 #include <linux/soundcard.h>
34 #else
35 #include <sys/soundcard.h>
36 #endif
37
38 #ifdef __linux__
39
40 #ifndef HAVE_STDINT_H
41 typedef unsigned long uint32_t;
42 #endif
43
44 #elif defined(__FreeBSD__)
45
46 # ifndef SNDCTL_DSP_CHANNELS
47 # define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS
48 # endif
49
50 #endif
51
52 typedef struct {
53 PyObject_HEAD
54 const char *devicename; /* name of the device file */
55 int fd; /* file descriptor */
56 int mode; /* file mode (O_RDONLY, etc.) */
57 Py_ssize_t icount; /* input count */
58 Py_ssize_t ocount; /* output count */
59 uint32_t afmts; /* audio formats supported by hardware */
60 } oss_audio_t;
61
62 typedef struct {
63 PyObject_HEAD
64 int fd; /* The open mixer device */
65 } oss_mixer_t;
66
67
68 static PyTypeObject OSSAudioType;
69 static PyTypeObject OSSMixerType;
70
71 static PyObject *OSSAudioError;
72
73
74 /* ----------------------------------------------------------------------
75 * DSP object initialization/deallocation
76 */
77
78 static oss_audio_t *
newossobject(PyObject * arg)79 newossobject(PyObject *arg)
80 {
81 oss_audio_t *self;
82 int fd, afmts, imode;
83 const char *devicename = NULL;
84 const char *mode = NULL;
85
86 /* Two ways to call open():
87 open(device, mode) (for consistency with builtin open())
88 open(mode) (for backwards compatibility)
89 because the *first* argument is optional, parsing args is
90 a wee bit tricky. */
91 if (!PyArg_ParseTuple(arg, "s|s:open", &devicename, &mode))
92 return NULL;
93 if (mode == NULL) { /* only one arg supplied */
94 mode = devicename;
95 devicename = NULL;
96 }
97
98 if (strcmp(mode, "r") == 0)
99 imode = O_RDONLY;
100 else if (strcmp(mode, "w") == 0)
101 imode = O_WRONLY;
102 else if (strcmp(mode, "rw") == 0)
103 imode = O_RDWR;
104 else {
105 PyErr_SetString(OSSAudioError, "mode must be 'r', 'w', or 'rw'");
106 return NULL;
107 }
108
109 /* Open the correct device: either the 'device' argument,
110 or the AUDIODEV environment variable, or "/dev/dsp". */
111 if (devicename == NULL) { /* called with one arg */
112 devicename = getenv("AUDIODEV");
113 if (devicename == NULL) /* $AUDIODEV not set */
114 devicename = "/dev/dsp";
115 }
116
117 /* Open with O_NONBLOCK to avoid hanging on devices that only allow
118 one open at a time. This does *not* affect later I/O; OSS
119 provides a special ioctl() for non-blocking read/write, which is
120 exposed via oss_nonblock() below. */
121 fd = _Py_open(devicename, imode|O_NONBLOCK);
122 if (fd == -1)
123 return NULL;
124
125 /* And (try to) put it back in blocking mode so we get the
126 expected write() semantics. */
127 if (fcntl(fd, F_SETFL, 0) == -1) {
128 close(fd);
129 PyErr_SetFromErrnoWithFilename(PyExc_OSError, devicename);
130 return NULL;
131 }
132
133 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) {
134 close(fd);
135 PyErr_SetFromErrnoWithFilename(PyExc_OSError, devicename);
136 return NULL;
137 }
138 /* Create and initialize the object */
139 if ((self = PyObject_New(oss_audio_t, &OSSAudioType)) == NULL) {
140 close(fd);
141 return NULL;
142 }
143 self->devicename = devicename;
144 self->fd = fd;
145 self->mode = imode;
146 self->icount = self->ocount = 0;
147 self->afmts = afmts;
148 return self;
149 }
150
151 static void
oss_dealloc(oss_audio_t * self)152 oss_dealloc(oss_audio_t *self)
153 {
154 /* if already closed, don't reclose it */
155 if (self->fd != -1)
156 close(self->fd);
157 PyObject_Free(self);
158 }
159
160
161 /* ----------------------------------------------------------------------
162 * Mixer object initialization/deallocation
163 */
164
165 static oss_mixer_t *
newossmixerobject(PyObject * arg)166 newossmixerobject(PyObject *arg)
167 {
168 const char *devicename = NULL;
169 int fd;
170 oss_mixer_t *self;
171
172 if (!PyArg_ParseTuple(arg, "|s", &devicename)) {
173 return NULL;
174 }
175
176 if (devicename == NULL) {
177 devicename = getenv("MIXERDEV");
178 if (devicename == NULL) /* MIXERDEV not set */
179 devicename = "/dev/mixer";
180 }
181
182 fd = _Py_open(devicename, O_RDWR);
183 if (fd == -1)
184 return NULL;
185
186 if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) {
187 close(fd);
188 return NULL;
189 }
190
191 self->fd = fd;
192
193 return self;
194 }
195
196 static void
oss_mixer_dealloc(oss_mixer_t * self)197 oss_mixer_dealloc(oss_mixer_t *self)
198 {
199 /* if already closed, don't reclose it */
200 if (self->fd != -1)
201 close(self->fd);
202 PyObject_Free(self);
203 }
204
205
206 /* Methods to wrap the OSS ioctls. The calling convention is pretty
207 simple:
208 nonblock() -> ioctl(fd, SNDCTL_DSP_NONBLOCK)
209 fmt = setfmt(fmt) -> ioctl(fd, SNDCTL_DSP_SETFMT, &fmt)
210 etc.
211 */
212
213
214 /* ----------------------------------------------------------------------
215 * Helper functions
216 */
217
218 /* Check if a given file descriptor is valid (i.e. hasn't been closed).
219 * If true, return 1. Otherwise, raise ValueError and return 0.
220 */
_is_fd_valid(int fd)221 static int _is_fd_valid(int fd)
222 {
223 /* the FD is set to -1 in oss_close()/oss_mixer_close() */
224 if (fd >= 0) {
225 return 1;
226 } else {
227 PyErr_SetString(PyExc_ValueError,
228 "Operation on closed OSS device.");
229 return 0;
230 }
231 }
232
233 /* _do_ioctl_1() is a private helper function used for the OSS ioctls --
234 SNDCTL_DSP_{SETFMT,CHANNELS,SPEED} -- that are called from C
235 like this:
236 ioctl(fd, SNDCTL_DSP_cmd, &arg)
237
238 where arg is the value to set, and on return the driver sets arg to
239 the value that was actually set. Mapping this to Python is obvious:
240 arg = dsp.xxx(arg)
241 */
242 static PyObject *
_do_ioctl_1(int fd,PyObject * args,char * fname,unsigned long cmd)243 _do_ioctl_1(int fd, PyObject *args, char *fname, unsigned long cmd)
244 {
245 char argfmt[33] = "i:";
246 int arg;
247
248 assert(strlen(fname) <= 30);
249 strncat(argfmt, fname, 30);
250 if (!PyArg_ParseTuple(args, argfmt, &arg))
251 return NULL;
252
253 if (ioctl(fd, cmd, &arg) == -1)
254 return PyErr_SetFromErrno(PyExc_OSError);
255 return PyLong_FromLong(arg);
256 }
257
258
259 /* _do_ioctl_1_internal() is a wrapper for ioctls that take no inputs
260 but return an output -- ie. we need to pass a pointer to a local C
261 variable so the driver can write its output there, but from Python
262 all we see is the return value. For example,
263 SOUND_MIXER_READ_DEVMASK returns a bitmask of available mixer
264 devices, but does not use the value of the parameter passed-in in any
265 way.
266 */
267 static PyObject *
_do_ioctl_1_internal(int fd,PyObject * args,char * fname,unsigned long cmd)268 _do_ioctl_1_internal(int fd, PyObject *args, char *fname, unsigned long cmd)
269 {
270 char argfmt[32] = ":";
271 int arg = 0;
272
273 assert(strlen(fname) <= 30);
274 strncat(argfmt, fname, 30);
275 if (!PyArg_ParseTuple(args, argfmt, &arg))
276 return NULL;
277
278 if (ioctl(fd, cmd, &arg) == -1)
279 return PyErr_SetFromErrno(PyExc_OSError);
280 return PyLong_FromLong(arg);
281 }
282
283
284
285 /* _do_ioctl_0() is a private helper for the no-argument ioctls:
286 SNDCTL_DSP_{SYNC,RESET,POST}. */
287 static PyObject *
_do_ioctl_0(int fd,PyObject * args,char * fname,unsigned long cmd)288 _do_ioctl_0(int fd, PyObject *args, char *fname, unsigned long cmd)
289 {
290 char argfmt[32] = ":";
291 int rv;
292
293 assert(strlen(fname) <= 30);
294 strncat(argfmt, fname, 30);
295 if (!PyArg_ParseTuple(args, argfmt))
296 return NULL;
297
298 /* According to hannu@opensound.com, all three of the ioctls that
299 use this function can block, so release the GIL. This is
300 especially important for SYNC, which can block for several
301 seconds. */
302 Py_BEGIN_ALLOW_THREADS
303 rv = ioctl(fd, cmd, 0);
304 Py_END_ALLOW_THREADS
305
306 if (rv == -1)
307 return PyErr_SetFromErrno(PyExc_OSError);
308 Py_RETURN_NONE;
309 }
310
311
312 /* ----------------------------------------------------------------------
313 * Methods of DSP objects (OSSAudioType)
314 */
315
316 static PyObject *
oss_nonblock(oss_audio_t * self,PyObject * unused)317 oss_nonblock(oss_audio_t *self, PyObject *unused)
318 {
319 if (!_is_fd_valid(self->fd))
320 return NULL;
321
322 /* Hmmm: it doesn't appear to be possible to return to blocking
323 mode once we're in non-blocking mode! */
324 if (ioctl(self->fd, SNDCTL_DSP_NONBLOCK, NULL) == -1)
325 return PyErr_SetFromErrno(PyExc_OSError);
326 Py_RETURN_NONE;
327 }
328
329 static PyObject *
oss_setfmt(oss_audio_t * self,PyObject * args)330 oss_setfmt(oss_audio_t *self, PyObject *args)
331 {
332 if (!_is_fd_valid(self->fd))
333 return NULL;
334
335 return _do_ioctl_1(self->fd, args, "setfmt", SNDCTL_DSP_SETFMT);
336 }
337
338 static PyObject *
oss_getfmts(oss_audio_t * self,PyObject * unused)339 oss_getfmts(oss_audio_t *self, PyObject *unused)
340 {
341 int mask;
342
343 if (!_is_fd_valid(self->fd))
344 return NULL;
345
346 if (ioctl(self->fd, SNDCTL_DSP_GETFMTS, &mask) == -1)
347 return PyErr_SetFromErrno(PyExc_OSError);
348 return PyLong_FromLong(mask);
349 }
350
351 static PyObject *
oss_channels(oss_audio_t * self,PyObject * args)352 oss_channels(oss_audio_t *self, PyObject *args)
353 {
354 if (!_is_fd_valid(self->fd))
355 return NULL;
356
357 return _do_ioctl_1(self->fd, args, "channels", SNDCTL_DSP_CHANNELS);
358 }
359
360 static PyObject *
oss_speed(oss_audio_t * self,PyObject * args)361 oss_speed(oss_audio_t *self, PyObject *args)
362 {
363 if (!_is_fd_valid(self->fd))
364 return NULL;
365
366 return _do_ioctl_1(self->fd, args, "speed", SNDCTL_DSP_SPEED);
367 }
368
369 static PyObject *
oss_sync(oss_audio_t * self,PyObject * args)370 oss_sync(oss_audio_t *self, PyObject *args)
371 {
372 if (!_is_fd_valid(self->fd))
373 return NULL;
374
375 return _do_ioctl_0(self->fd, args, "sync", SNDCTL_DSP_SYNC);
376 }
377
378 static PyObject *
oss_reset(oss_audio_t * self,PyObject * args)379 oss_reset(oss_audio_t *self, PyObject *args)
380 {
381 if (!_is_fd_valid(self->fd))
382 return NULL;
383
384 return _do_ioctl_0(self->fd, args, "reset", SNDCTL_DSP_RESET);
385 }
386
387 static PyObject *
oss_post(oss_audio_t * self,PyObject * args)388 oss_post(oss_audio_t *self, PyObject *args)
389 {
390 if (!_is_fd_valid(self->fd))
391 return NULL;
392
393 return _do_ioctl_0(self->fd, args, "post", SNDCTL_DSP_POST);
394 }
395
396
397 /* Regular file methods: read(), write(), close(), etc. as well
398 as one convenience method, writeall(). */
399
400 static PyObject *
oss_read(oss_audio_t * self,PyObject * args)401 oss_read(oss_audio_t *self, PyObject *args)
402 {
403 Py_ssize_t size, count;
404 PyObject *rv;
405
406 if (!_is_fd_valid(self->fd))
407 return NULL;
408
409 if (!PyArg_ParseTuple(args, "n:read", &size))
410 return NULL;
411
412 rv = PyBytes_FromStringAndSize(NULL, size);
413 if (rv == NULL)
414 return NULL;
415
416 count = _Py_read(self->fd, PyBytes_AS_STRING(rv), size);
417 if (count == -1) {
418 Py_DECREF(rv);
419 return NULL;
420 }
421
422 self->icount += count;
423 _PyBytes_Resize(&rv, count);
424 return rv;
425 }
426
427 static PyObject *
oss_write(oss_audio_t * self,PyObject * args)428 oss_write(oss_audio_t *self, PyObject *args)
429 {
430 Py_buffer data;
431 Py_ssize_t rv;
432
433 if (!_is_fd_valid(self->fd))
434 return NULL;
435
436 if (!PyArg_ParseTuple(args, "y*:write", &data)) {
437 return NULL;
438 }
439
440 rv = _Py_write(self->fd, data.buf, data.len);
441 PyBuffer_Release(&data);
442 if (rv == -1)
443 return NULL;
444
445 self->ocount += rv;
446 return PyLong_FromLong(rv);
447 }
448
449 static PyObject *
oss_writeall(oss_audio_t * self,PyObject * args)450 oss_writeall(oss_audio_t *self, PyObject *args)
451 {
452 Py_buffer data;
453 const char *cp;
454 Py_ssize_t size;
455 Py_ssize_t rv;
456 fd_set write_set_fds;
457 int select_rv;
458
459 /* NB. writeall() is only useful in non-blocking mode: according to
460 Guenter Geiger <geiger@xdv.org> on the linux-audio-dev list
461 (http://eca.cx/lad/2002/11/0380.html), OSS guarantees that
462 write() in blocking mode consumes the whole buffer. In blocking
463 mode, the behaviour of write() and writeall() from Python is
464 indistinguishable. */
465
466 if (!_is_fd_valid(self->fd))
467 return NULL;
468
469 if (!PyArg_ParseTuple(args, "y*:writeall", &data))
470 return NULL;
471
472 if (!_PyIsSelectable_fd(self->fd)) {
473 PyErr_SetString(PyExc_ValueError,
474 "file descriptor out of range for select");
475 PyBuffer_Release(&data);
476 return NULL;
477 }
478 /* use select to wait for audio device to be available */
479 FD_ZERO(&write_set_fds);
480 FD_SET(self->fd, &write_set_fds);
481 cp = (const char *)data.buf;
482 size = data.len;
483
484 while (size > 0) {
485 Py_BEGIN_ALLOW_THREADS
486 select_rv = select(self->fd+1, NULL, &write_set_fds, NULL, NULL);
487 Py_END_ALLOW_THREADS
488
489 assert(select_rv != 0); /* no timeout, can't expire */
490 if (select_rv == -1) {
491 PyBuffer_Release(&data);
492 return PyErr_SetFromErrno(PyExc_OSError);
493 }
494
495 rv = _Py_write(self->fd, cp, Py_MIN(size, INT_MAX));
496 if (rv == -1) {
497 /* buffer is full, try again */
498 if (errno == EAGAIN) {
499 PyErr_Clear();
500 continue;
501 }
502 /* it's a real error */
503 PyBuffer_Release(&data);
504 return NULL;
505 }
506
507 /* wrote rv bytes */
508 self->ocount += rv;
509 size -= rv;
510 cp += rv;
511 }
512 PyBuffer_Release(&data);
513 Py_RETURN_NONE;
514 }
515
516 static PyObject *
oss_close(oss_audio_t * self,PyObject * unused)517 oss_close(oss_audio_t *self, PyObject *unused)
518 {
519 if (self->fd >= 0) {
520 Py_BEGIN_ALLOW_THREADS
521 close(self->fd);
522 Py_END_ALLOW_THREADS
523 self->fd = -1;
524 }
525 Py_RETURN_NONE;
526 }
527
528 static PyObject *
oss_self(PyObject * self,PyObject * unused)529 oss_self(PyObject *self, PyObject *unused)
530 {
531 Py_INCREF(self);
532 return self;
533 }
534
535 static PyObject *
oss_exit(PyObject * self,PyObject * unused)536 oss_exit(PyObject *self, PyObject *unused)
537 {
538 _Py_IDENTIFIER(close);
539
540 PyObject *ret = _PyObject_CallMethodIdNoArgs(self, &PyId_close);
541 if (!ret)
542 return NULL;
543 Py_DECREF(ret);
544 Py_RETURN_NONE;
545 }
546
547 static PyObject *
oss_fileno(oss_audio_t * self,PyObject * unused)548 oss_fileno(oss_audio_t *self, PyObject *unused)
549 {
550 if (!_is_fd_valid(self->fd))
551 return NULL;
552
553 return PyLong_FromLong(self->fd);
554 }
555
556
557 /* Convenience methods: these generally wrap a couple of ioctls into one
558 common task. */
559
560 static PyObject *
oss_setparameters(oss_audio_t * self,PyObject * args)561 oss_setparameters(oss_audio_t *self, PyObject *args)
562 {
563 int wanted_fmt, wanted_channels, wanted_rate, strict=0;
564 int fmt, channels, rate;
565
566 if (!_is_fd_valid(self->fd))
567 return NULL;
568
569 if (!PyArg_ParseTuple(args, "iii|i:setparameters",
570 &wanted_fmt, &wanted_channels, &wanted_rate,
571 &strict))
572 return NULL;
573
574 fmt = wanted_fmt;
575 if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) == -1) {
576 return PyErr_SetFromErrno(PyExc_OSError);
577 }
578 if (strict && fmt != wanted_fmt) {
579 return PyErr_Format
580 (OSSAudioError,
581 "unable to set requested format (wanted %d, got %d)",
582 wanted_fmt, fmt);
583 }
584
585 channels = wanted_channels;
586 if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
587 return PyErr_SetFromErrno(PyExc_OSError);
588 }
589 if (strict && channels != wanted_channels) {
590 return PyErr_Format
591 (OSSAudioError,
592 "unable to set requested channels (wanted %d, got %d)",
593 wanted_channels, channels);
594 }
595
596 rate = wanted_rate;
597 if (ioctl(self->fd, SNDCTL_DSP_SPEED, &rate) == -1) {
598 return PyErr_SetFromErrno(PyExc_OSError);
599 }
600 if (strict && rate != wanted_rate) {
601 return PyErr_Format
602 (OSSAudioError,
603 "unable to set requested rate (wanted %d, got %d)",
604 wanted_rate, rate);
605 }
606
607 /* Construct the return value: a (fmt, channels, rate) tuple that
608 tells what the audio hardware was actually set to. */
609 return Py_BuildValue("(iii)", fmt, channels, rate);
610 }
611
612 static int
_ssize(oss_audio_t * self,int * nchannels,int * ssize)613 _ssize(oss_audio_t *self, int *nchannels, int *ssize)
614 {
615 int fmt;
616
617 fmt = 0;
618 if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
619 return -errno;
620
621 switch (fmt) {
622 case AFMT_MU_LAW:
623 case AFMT_A_LAW:
624 case AFMT_U8:
625 case AFMT_S8:
626 *ssize = 1; /* 8 bit formats: 1 byte */
627 break;
628 case AFMT_S16_LE:
629 case AFMT_S16_BE:
630 case AFMT_U16_LE:
631 case AFMT_U16_BE:
632 *ssize = 2; /* 16 bit formats: 2 byte */
633 break;
634 case AFMT_MPEG:
635 case AFMT_IMA_ADPCM:
636 default:
637 return -EOPNOTSUPP;
638 }
639 if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, nchannels) < 0)
640 return -errno;
641 return 0;
642 }
643
644
645 /* bufsize returns the size of the hardware audio buffer in number
646 of samples */
647 static PyObject *
oss_bufsize(oss_audio_t * self,PyObject * unused)648 oss_bufsize(oss_audio_t *self, PyObject *unused)
649 {
650 audio_buf_info ai;
651 int nchannels=0, ssize=0;
652
653 if (!_is_fd_valid(self->fd))
654 return NULL;
655
656 if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
657 PyErr_SetFromErrno(PyExc_OSError);
658 return NULL;
659 }
660 if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
661 PyErr_SetFromErrno(PyExc_OSError);
662 return NULL;
663 }
664 return PyLong_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize));
665 }
666
667 /* obufcount returns the number of samples that are available in the
668 hardware for playing */
669 static PyObject *
oss_obufcount(oss_audio_t * self,PyObject * unused)670 oss_obufcount(oss_audio_t *self, PyObject *unused)
671 {
672 audio_buf_info ai;
673 int nchannels=0, ssize=0;
674
675 if (!_is_fd_valid(self->fd))
676 return NULL;
677
678 if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
679 PyErr_SetFromErrno(PyExc_OSError);
680 return NULL;
681 }
682 if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
683 PyErr_SetFromErrno(PyExc_OSError);
684 return NULL;
685 }
686 return PyLong_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) /
687 (ssize * nchannels));
688 }
689
690 /* obufcount returns the number of samples that can be played without
691 blocking */
692 static PyObject *
oss_obuffree(oss_audio_t * self,PyObject * unused)693 oss_obuffree(oss_audio_t *self, PyObject *unused)
694 {
695 audio_buf_info ai;
696 int nchannels=0, ssize=0;
697
698 if (!_is_fd_valid(self->fd))
699 return NULL;
700
701 if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
702 PyErr_SetFromErrno(PyExc_OSError);
703 return NULL;
704 }
705 if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
706 PyErr_SetFromErrno(PyExc_OSError);
707 return NULL;
708 }
709 return PyLong_FromLong(ai.bytes / (ssize * nchannels));
710 }
711
712 static PyObject *
oss_getptr(oss_audio_t * self,PyObject * unused)713 oss_getptr(oss_audio_t *self, PyObject *unused)
714 {
715 count_info info;
716 int req;
717
718 if (!_is_fd_valid(self->fd))
719 return NULL;
720
721 if (self->mode == O_RDONLY)
722 req = SNDCTL_DSP_GETIPTR;
723 else
724 req = SNDCTL_DSP_GETOPTR;
725 if (ioctl(self->fd, req, &info) == -1) {
726 PyErr_SetFromErrno(PyExc_OSError);
727 return NULL;
728 }
729 return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr);
730 }
731
732
733 /* ----------------------------------------------------------------------
734 * Methods of mixer objects (OSSMixerType)
735 */
736
737 static PyObject *
oss_mixer_close(oss_mixer_t * self,PyObject * unused)738 oss_mixer_close(oss_mixer_t *self, PyObject *unused)
739 {
740 if (self->fd >= 0) {
741 close(self->fd);
742 self->fd = -1;
743 }
744 Py_RETURN_NONE;
745 }
746
747 static PyObject *
oss_mixer_fileno(oss_mixer_t * self,PyObject * unused)748 oss_mixer_fileno(oss_mixer_t *self, PyObject *unused)
749 {
750 if (!_is_fd_valid(self->fd))
751 return NULL;
752
753 return PyLong_FromLong(self->fd);
754 }
755
756 /* Simple mixer interface methods */
757
758 static PyObject *
oss_mixer_controls(oss_mixer_t * self,PyObject * args)759 oss_mixer_controls(oss_mixer_t *self, PyObject *args)
760 {
761 if (!_is_fd_valid(self->fd))
762 return NULL;
763
764 return _do_ioctl_1_internal(self->fd, args, "controls",
765 SOUND_MIXER_READ_DEVMASK);
766 }
767
768 static PyObject *
oss_mixer_stereocontrols(oss_mixer_t * self,PyObject * args)769 oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args)
770 {
771 if (!_is_fd_valid(self->fd))
772 return NULL;
773
774 return _do_ioctl_1_internal(self->fd, args, "stereocontrols",
775 SOUND_MIXER_READ_STEREODEVS);
776 }
777
778 static PyObject *
oss_mixer_reccontrols(oss_mixer_t * self,PyObject * args)779 oss_mixer_reccontrols(oss_mixer_t *self, PyObject *args)
780 {
781 if (!_is_fd_valid(self->fd))
782 return NULL;
783
784 return _do_ioctl_1_internal(self->fd, args, "reccontrols",
785 SOUND_MIXER_READ_RECMASK);
786 }
787
788 static PyObject *
oss_mixer_get(oss_mixer_t * self,PyObject * args)789 oss_mixer_get(oss_mixer_t *self, PyObject *args)
790 {
791 int channel, volume;
792
793 if (!_is_fd_valid(self->fd))
794 return NULL;
795
796 /* Can't use _do_ioctl_1 because of encoded arg thingy. */
797 if (!PyArg_ParseTuple(args, "i:get", &channel))
798 return NULL;
799
800 if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
801 PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
802 return NULL;
803 }
804
805 if (ioctl(self->fd, MIXER_READ(channel), &volume) == -1)
806 return PyErr_SetFromErrno(PyExc_OSError);
807
808 return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
809 }
810
811 static PyObject *
oss_mixer_set(oss_mixer_t * self,PyObject * args)812 oss_mixer_set(oss_mixer_t *self, PyObject *args)
813 {
814 int channel, volume, leftVol, rightVol;
815
816 if (!_is_fd_valid(self->fd))
817 return NULL;
818
819 /* Can't use _do_ioctl_1 because of encoded arg thingy. */
820 if (!PyArg_ParseTuple(args, "i(ii):set", &channel, &leftVol, &rightVol))
821 return NULL;
822
823 if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
824 PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
825 return NULL;
826 }
827
828 if (leftVol < 0 || rightVol < 0 || leftVol > 100 || rightVol > 100) {
829 PyErr_SetString(OSSAudioError, "Volumes must be between 0 and 100.");
830 return NULL;
831 }
832
833 volume = (rightVol << 8) | leftVol;
834
835 if (ioctl(self->fd, MIXER_WRITE(channel), &volume) == -1)
836 return PyErr_SetFromErrno(PyExc_OSError);
837
838 return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
839 }
840
841 static PyObject *
oss_mixer_get_recsrc(oss_mixer_t * self,PyObject * args)842 oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args)
843 {
844 if (!_is_fd_valid(self->fd))
845 return NULL;
846
847 return _do_ioctl_1_internal(self->fd, args, "get_recsrc",
848 SOUND_MIXER_READ_RECSRC);
849 }
850
851 static PyObject *
oss_mixer_set_recsrc(oss_mixer_t * self,PyObject * args)852 oss_mixer_set_recsrc(oss_mixer_t *self, PyObject *args)
853 {
854 if (!_is_fd_valid(self->fd))
855 return NULL;
856
857 return _do_ioctl_1(self->fd, args, "set_recsrc",
858 SOUND_MIXER_WRITE_RECSRC);
859 }
860
861
862 /* ----------------------------------------------------------------------
863 * Method tables and other bureaucracy
864 */
865
866 static PyMethodDef oss_methods[] = {
867 /* Regular file methods */
868 { "read", (PyCFunction)oss_read, METH_VARARGS },
869 { "write", (PyCFunction)oss_write, METH_VARARGS },
870 { "writeall", (PyCFunction)oss_writeall, METH_VARARGS },
871 { "close", (PyCFunction)oss_close, METH_NOARGS },
872 { "fileno", (PyCFunction)oss_fileno, METH_NOARGS },
873
874 /* Simple ioctl wrappers */
875 { "nonblock", (PyCFunction)oss_nonblock, METH_NOARGS },
876 { "setfmt", (PyCFunction)oss_setfmt, METH_VARARGS },
877 { "getfmts", (PyCFunction)oss_getfmts, METH_NOARGS },
878 { "channels", (PyCFunction)oss_channels, METH_VARARGS },
879 { "speed", (PyCFunction)oss_speed, METH_VARARGS },
880 { "sync", (PyCFunction)oss_sync, METH_VARARGS },
881 { "reset", (PyCFunction)oss_reset, METH_VARARGS },
882 { "post", (PyCFunction)oss_post, METH_VARARGS },
883
884 /* Convenience methods -- wrap a couple of ioctls together */
885 { "setparameters", (PyCFunction)oss_setparameters, METH_VARARGS },
886 { "bufsize", (PyCFunction)oss_bufsize, METH_NOARGS },
887 { "obufcount", (PyCFunction)oss_obufcount, METH_NOARGS },
888 { "obuffree", (PyCFunction)oss_obuffree, METH_NOARGS },
889 { "getptr", (PyCFunction)oss_getptr, METH_NOARGS },
890
891 /* Aliases for backwards compatibility */
892 { "flush", (PyCFunction)oss_sync, METH_VARARGS },
893
894 /* Support for the context management protocol */
895 { "__enter__", oss_self, METH_NOARGS },
896 { "__exit__", oss_exit, METH_VARARGS },
897
898 { NULL, NULL} /* sentinel */
899 };
900
901 static PyMethodDef oss_mixer_methods[] = {
902 /* Regular file method - OSS mixers are ioctl-only interface */
903 { "close", (PyCFunction)oss_mixer_close, METH_NOARGS },
904 { "fileno", (PyCFunction)oss_mixer_fileno, METH_NOARGS },
905
906 /* Support for the context management protocol */
907 { "__enter__", oss_self, METH_NOARGS },
908 { "__exit__", oss_exit, METH_VARARGS },
909
910 /* Simple ioctl wrappers */
911 { "controls", (PyCFunction)oss_mixer_controls, METH_VARARGS },
912 { "stereocontrols", (PyCFunction)oss_mixer_stereocontrols, METH_VARARGS},
913 { "reccontrols", (PyCFunction)oss_mixer_reccontrols, METH_VARARGS},
914 { "get", (PyCFunction)oss_mixer_get, METH_VARARGS },
915 { "set", (PyCFunction)oss_mixer_set, METH_VARARGS },
916 { "get_recsrc", (PyCFunction)oss_mixer_get_recsrc, METH_VARARGS },
917 { "set_recsrc", (PyCFunction)oss_mixer_set_recsrc, METH_VARARGS },
918
919 { NULL, NULL}
920 };
921
922 static PyMemberDef oss_members[] = {
923 {"name", T_STRING, offsetof(oss_audio_t, devicename), READONLY, NULL},
924 {NULL}
925 };
926
927 static PyObject *
oss_closed_getter(oss_audio_t * self,void * closure)928 oss_closed_getter(oss_audio_t *self, void *closure)
929 {
930 return PyBool_FromLong(self->fd == -1);
931 }
932
933 static PyObject *
oss_mode_getter(oss_audio_t * self,void * closure)934 oss_mode_getter(oss_audio_t *self, void *closure)
935 {
936 switch(self->mode) {
937 case O_RDONLY:
938 return PyUnicode_FromString("r");
939 break;
940 case O_RDWR:
941 return PyUnicode_FromString("rw");
942 break;
943 case O_WRONLY:
944 return PyUnicode_FromString("w");
945 break;
946 default:
947 /* From newossobject(), self->mode can only be one
948 of these three values. */
949 Py_UNREACHABLE();
950 }
951 }
952
953 static PyGetSetDef oss_getsetlist[] = {
954 {"closed", (getter)oss_closed_getter, (setter)NULL, NULL},
955 {"mode", (getter)oss_mode_getter, (setter)NULL, NULL},
956 {NULL},
957 };
958
959 static PyTypeObject OSSAudioType = {
960 PyVarObject_HEAD_INIT(&PyType_Type, 0)
961 "ossaudiodev.oss_audio_device", /*tp_name*/
962 sizeof(oss_audio_t), /*tp_basicsize*/
963 0, /*tp_itemsize*/
964 /* methods */
965 (destructor)oss_dealloc, /*tp_dealloc*/
966 0, /*tp_vectorcall_offset*/
967 0, /*tp_getattr*/
968 0, /*tp_setattr*/
969 0, /*tp_as_async*/
970 0, /*tp_repr*/
971 0, /*tp_as_number*/
972 0, /*tp_as_sequence*/
973 0, /*tp_as_mapping*/
974 0, /*tp_hash*/
975 0, /*tp_call*/
976 0, /*tp_str*/
977 0, /*tp_getattro*/
978 0, /*tp_setattro*/
979 0, /*tp_as_buffer*/
980 Py_TPFLAGS_DEFAULT, /*tp_flags*/
981 0, /*tp_doc*/
982 0, /*tp_traverse*/
983 0, /*tp_clear*/
984 0, /*tp_richcompare*/
985 0, /*tp_weaklistoffset*/
986 0, /*tp_iter*/
987 0, /*tp_iternext*/
988 oss_methods, /*tp_methods*/
989 oss_members, /*tp_members*/
990 oss_getsetlist, /*tp_getset*/
991 };
992
993 static PyTypeObject OSSMixerType = {
994 PyVarObject_HEAD_INIT(&PyType_Type, 0)
995 "ossaudiodev.oss_mixer_device", /*tp_name*/
996 sizeof(oss_mixer_t), /*tp_basicsize*/
997 0, /*tp_itemsize*/
998 /* methods */
999 (destructor)oss_mixer_dealloc, /*tp_dealloc*/
1000 0, /*tp_vectorcall_offset*/
1001 0, /*tp_getattr*/
1002 0, /*tp_setattr*/
1003 0, /*tp_as_async*/
1004 0, /*tp_repr*/
1005 0, /*tp_as_number*/
1006 0, /*tp_as_sequence*/
1007 0, /*tp_as_mapping*/
1008 0, /*tp_hash*/
1009 0, /*tp_call*/
1010 0, /*tp_str*/
1011 0, /*tp_getattro*/
1012 0, /*tp_setattro*/
1013 0, /*tp_as_buffer*/
1014 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1015 0, /*tp_doc*/
1016 0, /*tp_traverse*/
1017 0, /*tp_clear*/
1018 0, /*tp_richcompare*/
1019 0, /*tp_weaklistoffset*/
1020 0, /*tp_iter*/
1021 0, /*tp_iternext*/
1022 oss_mixer_methods, /*tp_methods*/
1023 };
1024
1025
1026 static PyObject *
ossopen(PyObject * self,PyObject * args)1027 ossopen(PyObject *self, PyObject *args)
1028 {
1029 return (PyObject *)newossobject(args);
1030 }
1031
1032 static PyObject *
ossopenmixer(PyObject * self,PyObject * args)1033 ossopenmixer(PyObject *self, PyObject *args)
1034 {
1035 return (PyObject *)newossmixerobject(args);
1036 }
1037
1038 static PyMethodDef ossaudiodev_methods[] = {
1039 { "open", ossopen, METH_VARARGS },
1040 { "openmixer", ossopenmixer, METH_VARARGS },
1041 { 0, 0 },
1042 };
1043
1044
1045 #define _EXPORT_INT(mod, name) \
1046 if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return NULL;
1047
1048
1049 static char *control_labels[] = SOUND_DEVICE_LABELS;
1050 static char *control_names[] = SOUND_DEVICE_NAMES;
1051
1052
1053 static int
build_namelists(PyObject * module)1054 build_namelists (PyObject *module)
1055 {
1056 PyObject *labels;
1057 PyObject *names;
1058 PyObject *s;
1059 int num_controls;
1060 int i;
1061
1062 num_controls = Py_ARRAY_LENGTH(control_labels);
1063 assert(num_controls == Py_ARRAY_LENGTH(control_names));
1064
1065 labels = PyList_New(num_controls);
1066 names = PyList_New(num_controls);
1067 if (labels == NULL || names == NULL)
1068 goto error2;
1069 for (i = 0; i < num_controls; i++) {
1070 s = PyUnicode_FromString(control_labels[i]);
1071 if (s == NULL)
1072 goto error2;
1073 PyList_SET_ITEM(labels, i, s);
1074
1075 s = PyUnicode_FromString(control_names[i]);
1076 if (s == NULL)
1077 goto error2;
1078 PyList_SET_ITEM(names, i, s);
1079 }
1080
1081 if (PyModule_AddObject(module, "control_labels", labels) == -1)
1082 goto error2;
1083 if (PyModule_AddObject(module, "control_names", names) == -1)
1084 goto error1;
1085
1086 return 0;
1087
1088 error2:
1089 Py_XDECREF(labels);
1090 error1:
1091 Py_XDECREF(names);
1092 return -1;
1093 }
1094
1095
1096 static struct PyModuleDef ossaudiodevmodule = {
1097 PyModuleDef_HEAD_INIT,
1098 "ossaudiodev",
1099 NULL,
1100 -1,
1101 ossaudiodev_methods,
1102 NULL,
1103 NULL,
1104 NULL,
1105 NULL
1106 };
1107
1108 PyMODINIT_FUNC
PyInit_ossaudiodev(void)1109 PyInit_ossaudiodev(void)
1110 {
1111 PyObject *m;
1112
1113 if (PyType_Ready(&OSSAudioType) < 0)
1114 return NULL;
1115
1116 if (PyType_Ready(&OSSMixerType) < 0)
1117 return NULL;
1118
1119 m = PyModule_Create(&ossaudiodevmodule);
1120 if (m == NULL)
1121 return NULL;
1122
1123 OSSAudioError = PyErr_NewException("ossaudiodev.OSSAudioError",
1124 NULL, NULL);
1125 if (OSSAudioError) {
1126 /* Each call to PyModule_AddObject decrefs it; compensate: */
1127 Py_INCREF(OSSAudioError);
1128 Py_INCREF(OSSAudioError);
1129 PyModule_AddObject(m, "error", OSSAudioError);
1130 PyModule_AddObject(m, "OSSAudioError", OSSAudioError);
1131 }
1132
1133 /* Build 'control_labels' and 'control_names' lists and add them
1134 to the module. */
1135 if (build_namelists(m) == -1) /* XXX what to do here? */
1136 return NULL;
1137
1138 /* Expose the audio format numbers -- essential! */
1139 _EXPORT_INT(m, AFMT_QUERY);
1140 _EXPORT_INT(m, AFMT_MU_LAW);
1141 _EXPORT_INT(m, AFMT_A_LAW);
1142 _EXPORT_INT(m, AFMT_IMA_ADPCM);
1143 _EXPORT_INT(m, AFMT_U8);
1144 _EXPORT_INT(m, AFMT_S16_LE);
1145 _EXPORT_INT(m, AFMT_S16_BE);
1146 _EXPORT_INT(m, AFMT_S8);
1147 _EXPORT_INT(m, AFMT_U16_LE);
1148 _EXPORT_INT(m, AFMT_U16_BE);
1149 _EXPORT_INT(m, AFMT_MPEG);
1150 #ifdef AFMT_AC3
1151 _EXPORT_INT(m, AFMT_AC3);
1152 #endif
1153 #ifdef AFMT_S16_NE
1154 _EXPORT_INT(m, AFMT_S16_NE);
1155 #endif
1156 #ifdef AFMT_U16_NE
1157 _EXPORT_INT(m, AFMT_U16_NE);
1158 #endif
1159 #ifdef AFMT_S32_LE
1160 _EXPORT_INT(m, AFMT_S32_LE);
1161 #endif
1162 #ifdef AFMT_S32_BE
1163 _EXPORT_INT(m, AFMT_S32_BE);
1164 #endif
1165 #ifdef AFMT_MPEG
1166 _EXPORT_INT(m, AFMT_MPEG);
1167 #endif
1168
1169 /* Expose the sound mixer device numbers. */
1170 _EXPORT_INT(m, SOUND_MIXER_NRDEVICES);
1171 _EXPORT_INT(m, SOUND_MIXER_VOLUME);
1172 _EXPORT_INT(m, SOUND_MIXER_BASS);
1173 _EXPORT_INT(m, SOUND_MIXER_TREBLE);
1174 _EXPORT_INT(m, SOUND_MIXER_SYNTH);
1175 _EXPORT_INT(m, SOUND_MIXER_PCM);
1176 _EXPORT_INT(m, SOUND_MIXER_SPEAKER);
1177 _EXPORT_INT(m, SOUND_MIXER_LINE);
1178 _EXPORT_INT(m, SOUND_MIXER_MIC);
1179 _EXPORT_INT(m, SOUND_MIXER_CD);
1180 _EXPORT_INT(m, SOUND_MIXER_IMIX);
1181 _EXPORT_INT(m, SOUND_MIXER_ALTPCM);
1182 _EXPORT_INT(m, SOUND_MIXER_RECLEV);
1183 _EXPORT_INT(m, SOUND_MIXER_IGAIN);
1184 _EXPORT_INT(m, SOUND_MIXER_OGAIN);
1185 _EXPORT_INT(m, SOUND_MIXER_LINE1);
1186 _EXPORT_INT(m, SOUND_MIXER_LINE2);
1187 _EXPORT_INT(m, SOUND_MIXER_LINE3);
1188 #ifdef SOUND_MIXER_DIGITAL1
1189 _EXPORT_INT(m, SOUND_MIXER_DIGITAL1);
1190 #endif
1191 #ifdef SOUND_MIXER_DIGITAL2
1192 _EXPORT_INT(m, SOUND_MIXER_DIGITAL2);
1193 #endif
1194 #ifdef SOUND_MIXER_DIGITAL3
1195 _EXPORT_INT(m, SOUND_MIXER_DIGITAL3);
1196 #endif
1197 #ifdef SOUND_MIXER_PHONEIN
1198 _EXPORT_INT(m, SOUND_MIXER_PHONEIN);
1199 #endif
1200 #ifdef SOUND_MIXER_PHONEOUT
1201 _EXPORT_INT(m, SOUND_MIXER_PHONEOUT);
1202 #endif
1203 #ifdef SOUND_MIXER_VIDEO
1204 _EXPORT_INT(m, SOUND_MIXER_VIDEO);
1205 #endif
1206 #ifdef SOUND_MIXER_RADIO
1207 _EXPORT_INT(m, SOUND_MIXER_RADIO);
1208 #endif
1209 #ifdef SOUND_MIXER_MONITOR
1210 _EXPORT_INT(m, SOUND_MIXER_MONITOR);
1211 #endif
1212
1213 /* Expose all the ioctl numbers for masochists who like to do this
1214 stuff directly. */
1215 _EXPORT_INT(m, SNDCTL_COPR_HALT);
1216 _EXPORT_INT(m, SNDCTL_COPR_LOAD);
1217 _EXPORT_INT(m, SNDCTL_COPR_RCODE);
1218 _EXPORT_INT(m, SNDCTL_COPR_RCVMSG);
1219 _EXPORT_INT(m, SNDCTL_COPR_RDATA);
1220 _EXPORT_INT(m, SNDCTL_COPR_RESET);
1221 _EXPORT_INT(m, SNDCTL_COPR_RUN);
1222 _EXPORT_INT(m, SNDCTL_COPR_SENDMSG);
1223 _EXPORT_INT(m, SNDCTL_COPR_WCODE);
1224 _EXPORT_INT(m, SNDCTL_COPR_WDATA);
1225 #ifdef SNDCTL_DSP_BIND_CHANNEL
1226 _EXPORT_INT(m, SNDCTL_DSP_BIND_CHANNEL);
1227 #endif
1228 _EXPORT_INT(m, SNDCTL_DSP_CHANNELS);
1229 _EXPORT_INT(m, SNDCTL_DSP_GETBLKSIZE);
1230 _EXPORT_INT(m, SNDCTL_DSP_GETCAPS);
1231 #ifdef SNDCTL_DSP_GETCHANNELMASK
1232 _EXPORT_INT(m, SNDCTL_DSP_GETCHANNELMASK);
1233 #endif
1234 _EXPORT_INT(m, SNDCTL_DSP_GETFMTS);
1235 _EXPORT_INT(m, SNDCTL_DSP_GETIPTR);
1236 _EXPORT_INT(m, SNDCTL_DSP_GETISPACE);
1237 #ifdef SNDCTL_DSP_GETODELAY
1238 _EXPORT_INT(m, SNDCTL_DSP_GETODELAY);
1239 #endif
1240 _EXPORT_INT(m, SNDCTL_DSP_GETOPTR);
1241 _EXPORT_INT(m, SNDCTL_DSP_GETOSPACE);
1242 #ifdef SNDCTL_DSP_GETSPDIF
1243 _EXPORT_INT(m, SNDCTL_DSP_GETSPDIF);
1244 #endif
1245 _EXPORT_INT(m, SNDCTL_DSP_GETTRIGGER);
1246 _EXPORT_INT(m, SNDCTL_DSP_MAPINBUF);
1247 _EXPORT_INT(m, SNDCTL_DSP_MAPOUTBUF);
1248 _EXPORT_INT(m, SNDCTL_DSP_NONBLOCK);
1249 _EXPORT_INT(m, SNDCTL_DSP_POST);
1250 #ifdef SNDCTL_DSP_PROFILE
1251 _EXPORT_INT(m, SNDCTL_DSP_PROFILE);
1252 #endif
1253 _EXPORT_INT(m, SNDCTL_DSP_RESET);
1254 _EXPORT_INT(m, SNDCTL_DSP_SAMPLESIZE);
1255 _EXPORT_INT(m, SNDCTL_DSP_SETDUPLEX);
1256 _EXPORT_INT(m, SNDCTL_DSP_SETFMT);
1257 _EXPORT_INT(m, SNDCTL_DSP_SETFRAGMENT);
1258 #ifdef SNDCTL_DSP_SETSPDIF
1259 _EXPORT_INT(m, SNDCTL_DSP_SETSPDIF);
1260 #endif
1261 _EXPORT_INT(m, SNDCTL_DSP_SETSYNCRO);
1262 _EXPORT_INT(m, SNDCTL_DSP_SETTRIGGER);
1263 _EXPORT_INT(m, SNDCTL_DSP_SPEED);
1264 _EXPORT_INT(m, SNDCTL_DSP_STEREO);
1265 _EXPORT_INT(m, SNDCTL_DSP_SUBDIVIDE);
1266 _EXPORT_INT(m, SNDCTL_DSP_SYNC);
1267 _EXPORT_INT(m, SNDCTL_FM_4OP_ENABLE);
1268 _EXPORT_INT(m, SNDCTL_FM_LOAD_INSTR);
1269 _EXPORT_INT(m, SNDCTL_MIDI_INFO);
1270 _EXPORT_INT(m, SNDCTL_MIDI_MPUCMD);
1271 _EXPORT_INT(m, SNDCTL_MIDI_MPUMODE);
1272 _EXPORT_INT(m, SNDCTL_MIDI_PRETIME);
1273 _EXPORT_INT(m, SNDCTL_SEQ_CTRLRATE);
1274 _EXPORT_INT(m, SNDCTL_SEQ_GETINCOUNT);
1275 _EXPORT_INT(m, SNDCTL_SEQ_GETOUTCOUNT);
1276 #ifdef SNDCTL_SEQ_GETTIME
1277 _EXPORT_INT(m, SNDCTL_SEQ_GETTIME);
1278 #endif
1279 _EXPORT_INT(m, SNDCTL_SEQ_NRMIDIS);
1280 _EXPORT_INT(m, SNDCTL_SEQ_NRSYNTHS);
1281 _EXPORT_INT(m, SNDCTL_SEQ_OUTOFBAND);
1282 _EXPORT_INT(m, SNDCTL_SEQ_PANIC);
1283 _EXPORT_INT(m, SNDCTL_SEQ_PERCMODE);
1284 _EXPORT_INT(m, SNDCTL_SEQ_RESET);
1285 _EXPORT_INT(m, SNDCTL_SEQ_RESETSAMPLES);
1286 _EXPORT_INT(m, SNDCTL_SEQ_SYNC);
1287 _EXPORT_INT(m, SNDCTL_SEQ_TESTMIDI);
1288 _EXPORT_INT(m, SNDCTL_SEQ_THRESHOLD);
1289 #ifdef SNDCTL_SYNTH_CONTROL
1290 _EXPORT_INT(m, SNDCTL_SYNTH_CONTROL);
1291 #endif
1292 #ifdef SNDCTL_SYNTH_ID
1293 _EXPORT_INT(m, SNDCTL_SYNTH_ID);
1294 #endif
1295 _EXPORT_INT(m, SNDCTL_SYNTH_INFO);
1296 _EXPORT_INT(m, SNDCTL_SYNTH_MEMAVL);
1297 #ifdef SNDCTL_SYNTH_REMOVESAMPLE
1298 _EXPORT_INT(m, SNDCTL_SYNTH_REMOVESAMPLE);
1299 #endif
1300 _EXPORT_INT(m, SNDCTL_TMR_CONTINUE);
1301 _EXPORT_INT(m, SNDCTL_TMR_METRONOME);
1302 _EXPORT_INT(m, SNDCTL_TMR_SELECT);
1303 _EXPORT_INT(m, SNDCTL_TMR_SOURCE);
1304 _EXPORT_INT(m, SNDCTL_TMR_START);
1305 _EXPORT_INT(m, SNDCTL_TMR_STOP);
1306 _EXPORT_INT(m, SNDCTL_TMR_TEMPO);
1307 _EXPORT_INT(m, SNDCTL_TMR_TIMEBASE);
1308 return m;
1309 }
1310