Class around PixMap objects that allows more python-like access. By Joe Strout.
[python/dscho.git] / Modules / sunaudiodev.c
blob71c152e2535ae5d53981570099f6f02c278f7205
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission.
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* Sad objects */
34 #include "Python.h"
35 #include "structmember.h"
37 #ifdef HAVE_SYS_AUDIOIO_H
38 #define SOLARIS
39 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
45 #ifdef HAVE_FCNTL_H
46 #include <fcntl.h>
47 #endif
49 #include <stropts.h>
50 #include <sys/ioctl.h>
51 #ifdef SOLARIS
52 #include <sys/audioio.h>
53 #else
54 #include <sun/audioio.h>
55 #endif
57 /* #define offsetof(str,mem) ((int)(((str *)0)->mem)) */
59 typedef struct {
60 PyObject_HEAD
61 int x_fd; /* The open file */
62 int x_icount; /* # samples read */
63 int x_ocount; /* # samples written */
64 int x_isctl; /* True if control device */
66 } sadobject;
68 typedef struct {
69 PyObject_HEAD
70 audio_info_t ai;
71 } sadstatusobject;
73 staticforward PyTypeObject Sadtype;
74 staticforward PyTypeObject Sadstatustype;
75 static sadstatusobject *sads_alloc(); /* Forward */
77 static PyObject *SunAudioError;
79 #define is_sadobject(v) ((v)->ob_type == &Sadtype)
80 #define is_sadstatusobject(v) ((v)->ob_type == &Sadstatustype)
83 static sadobject *
84 newsadobject(arg)
85 PyObject *arg;
87 sadobject *xp;
88 int fd;
89 char *mode;
90 int imode;
91 char* basedev;
92 char* ctldev;
93 char* opendev;
95 /* Check arg for r/w/rw */
96 if (!PyArg_Parse(arg, "s", &mode))
97 return NULL;
98 if (strcmp(mode, "r") == 0)
99 imode = 0;
100 else if (strcmp(mode, "w") == 0)
101 imode = 1;
102 else if (strcmp(mode, "rw") == 0)
103 imode = 2;
104 else if (strcmp(mode, "control") == 0)
105 imode = -1;
106 else {
107 PyErr_SetString(SunAudioError,
108 "Mode should be one of 'r', 'w', 'rw' or 'control'");
109 return NULL;
112 /* Open the correct device. The base device name comes from the
113 * AUDIODEV environment variable first, then /dev/audio. The
114 * control device tacks "ctl" onto the base device name.
116 basedev = getenv("AUDIODEV");
117 if (!basedev)
118 basedev = "/dev/audio";
119 ctldev = PyMem_NEW(char, strlen(basedev) + 4);
120 if (!ctldev) {
121 PyErr_NoMemory();
122 return NULL;
124 strcpy(ctldev, basedev);
125 strcat(ctldev, "ctl");
127 if (imode < 0) {
128 opendev = ctldev;
129 fd = open(ctldev, 2);
131 else {
132 opendev = basedev;
133 fd = open(basedev, imode);
135 if (fd < 0) {
136 PyErr_SetFromErrnoWithFilename(SunAudioError, opendev);
137 return NULL;
139 PyMem_DEL(ctldev);
141 /* Create and initialize the object */
142 xp = PyObject_NEW(sadobject, &Sadtype);
143 if (xp == NULL) {
144 close(fd);
145 return NULL;
147 xp->x_fd = fd;
148 xp->x_icount = xp->x_ocount = 0;
149 xp->x_isctl = (imode < 0);
151 return xp;
154 /* Sad methods */
156 static void
157 sad_dealloc(xp)
158 sadobject *xp;
160 close(xp->x_fd);
161 PyMem_DEL(xp);
164 static PyObject *
165 sad_read(self, args)
166 sadobject *self;
167 PyObject *args;
169 int size, count;
170 char *cp;
171 PyObject *rv;
173 if (!PyArg_Parse(args, "i", &size))
174 return NULL;
175 rv = PyString_FromStringAndSize(NULL, size);
176 if (rv == NULL)
177 return NULL;
179 if (!(cp = PyString_AsString(rv)))
180 goto finally;
182 count = read(self->x_fd, cp, size);
183 if (count < 0) {
184 PyErr_SetFromErrno(SunAudioError);
185 goto finally;
187 #if 0
188 /* TBD: why print this message if you can handle the condition?
189 * assume it's debugging info which we can just as well get rid
190 * of. in any case this message should *not* be using printf!
192 if (count != size)
193 printf("sunaudio: funny read rv %d wtd %d\n", count, size);
194 #endif
195 self->x_icount += count;
196 return rv;
198 finally:
199 Py_DECREF(rv);
200 return NULL;
203 static PyObject *
204 sad_write(self, args)
205 sadobject *self;
206 PyObject *args;
208 char *cp;
209 int count, size;
211 if (!PyArg_Parse(args, "s#", &cp, &size))
212 return NULL;
214 count = write(self->x_fd, cp, size);
215 if (count < 0) {
216 PyErr_SetFromErrno(SunAudioError);
217 return NULL;
219 #if 0
220 if (count != size)
221 printf("sunaudio: funny write rv %d wanted %d\n", count, size);
222 #endif
223 self->x_ocount += count;
225 Py_INCREF(Py_None);
226 return Py_None;
229 static PyObject *
230 sad_getinfo(self, args)
231 sadobject *self;
232 PyObject *args;
234 sadstatusobject *rv;
236 if (!PyArg_Parse(args, ""))
237 return NULL;
238 if (!(rv = sads_alloc()))
239 return NULL;
241 if (ioctl(self->x_fd, AUDIO_GETINFO, &rv->ai) < 0) {
242 PyErr_SetFromErrno(SunAudioError);
243 Py_DECREF(rv);
244 return NULL;
246 return (PyObject *)rv;
249 static PyObject *
250 sad_setinfo(self, arg)
251 sadobject *self;
252 sadstatusobject *arg;
254 if (!is_sadstatusobject(arg)) {
255 PyErr_SetString(PyExc_TypeError,
256 "Must be sun audio status object");
257 return NULL;
259 if (ioctl(self->x_fd, AUDIO_SETINFO, &arg->ai) < 0) {
260 PyErr_SetFromErrno(SunAudioError);
261 return NULL;
263 Py_INCREF(Py_None);
264 return Py_None;
267 static PyObject *
268 sad_ibufcount(self, args)
269 sadobject *self;
270 PyObject *args;
272 audio_info_t ai;
274 if (!PyArg_Parse(args, ""))
275 return NULL;
276 if (ioctl(self->x_fd, AUDIO_GETINFO, &ai) < 0) {
277 PyErr_SetFromErrno(SunAudioError);
278 return NULL;
280 return PyInt_FromLong(ai.record.samples - self->x_icount);
283 static PyObject *
284 sad_obufcount(self, args)
285 sadobject *self;
286 PyObject *args;
288 audio_info_t ai;
290 if (!PyArg_Parse(args, ""))
291 return NULL;
292 if (ioctl(self->x_fd, AUDIO_GETINFO, &ai) < 0) {
293 PyErr_SetFromErrno(SunAudioError);
294 return NULL;
296 /* x_ocount is in bytes, wheras play.samples is in frames */
297 /* we want frames */
298 return PyInt_FromLong(self->x_ocount / (ai.play.channels *
299 ai.play.precision / 8) -
300 ai.play.samples);
303 static PyObject *
304 sad_drain(self, args)
305 sadobject *self;
306 PyObject *args;
309 if (!PyArg_Parse(args, ""))
310 return NULL;
311 if (ioctl(self->x_fd, AUDIO_DRAIN, 0) < 0) {
312 PyErr_SetFromErrno(SunAudioError);
313 return NULL;
315 Py_INCREF(Py_None);
316 return Py_None;
319 #ifdef SOLARIS
320 static PyObject *
321 sad_getdev(self, args)
322 sadobject *self;
323 PyObject *args;
325 struct audio_device ad;
327 if (!PyArg_Parse(args, ""))
328 return NULL;
329 if (ioctl(self->x_fd, AUDIO_GETDEV, &ad) < 0) {
330 PyErr_SetFromErrno(SunAudioError);
331 return NULL;
333 return Py_BuildValue("(sss)", ad.name, ad.version, ad.config);
335 #endif
337 static PyObject *
338 sad_flush(self, args)
339 sadobject *self;
340 PyObject *args;
343 if (!PyArg_Parse(args, ""))
344 return NULL;
345 if (ioctl(self->x_fd, I_FLUSH, FLUSHW) < 0) {
346 PyErr_SetFromErrno(SunAudioError);
347 return NULL;
349 Py_INCREF(Py_None);
350 return Py_None;
353 static PyObject *
354 sad_close(self, args)
355 sadobject *self;
356 PyObject *args;
359 if (!PyArg_Parse(args, ""))
360 return NULL;
361 if (self->x_fd >= 0) {
362 close(self->x_fd);
363 self->x_fd = -1;
365 Py_INCREF(Py_None);
366 return Py_None;
369 static PyObject *
370 sad_fileno(self, args)
371 sadobject *self;
372 PyObject *args;
374 if (!PyArg_Parse(args, ""))
375 return NULL;
377 return PyInt_FromLong(self->x_fd);
381 static PyMethodDef sad_methods[] = {
382 { "read", (PyCFunction)sad_read },
383 { "write", (PyCFunction)sad_write },
384 { "ibufcount", (PyCFunction)sad_ibufcount },
385 { "obufcount", (PyCFunction)sad_obufcount },
386 #define CTL_METHODS 4
387 { "getinfo", (PyCFunction)sad_getinfo },
388 { "setinfo", (PyCFunction)sad_setinfo },
389 { "drain", (PyCFunction)sad_drain },
390 { "flush", (PyCFunction)sad_flush },
391 #ifdef SOLARIS
392 { "getdev", (PyCFunction)sad_getdev },
393 #endif
394 { "close", (PyCFunction)sad_close },
395 { "fileno", (PyCFunction)sad_fileno },
396 {NULL, NULL} /* sentinel */
399 static PyObject *
400 sad_getattr(xp, name)
401 sadobject *xp;
402 char *name;
404 if (xp->x_isctl)
405 return Py_FindMethod(sad_methods+CTL_METHODS,
406 (PyObject *)xp, name);
407 else
408 return Py_FindMethod(sad_methods, (PyObject *)xp, name);
411 /* ----------------------------------------------------------------- */
413 static sadstatusobject *
414 sads_alloc() {
415 return PyObject_NEW(sadstatusobject, &Sadstatustype);
418 static void
419 sads_dealloc(xp)
420 sadstatusobject *xp;
422 PyMem_DEL(xp);
425 #define OFF(x) offsetof(audio_info_t,x)
426 static struct memberlist sads_ml[] = {
427 { "i_sample_rate", T_UINT, OFF(record.sample_rate) },
428 { "i_channels", T_UINT, OFF(record.channels) },
429 { "i_precision", T_UINT, OFF(record.precision) },
430 { "i_encoding", T_UINT, OFF(record.encoding) },
431 { "i_gain", T_UINT, OFF(record.gain) },
432 { "i_port", T_UINT, OFF(record.port) },
433 { "i_samples", T_UINT, OFF(record.samples) },
434 { "i_eof", T_UINT, OFF(record.eof) },
435 { "i_pause", T_UBYTE, OFF(record.pause) },
436 { "i_error", T_UBYTE, OFF(record.error) },
437 { "i_waiting", T_UBYTE, OFF(record.waiting) },
438 { "i_open", T_UBYTE, OFF(record.open) , RO},
439 { "i_active", T_UBYTE, OFF(record.active) , RO},
440 #ifdef SOLARIS
441 { "i_buffer_size", T_UINT, OFF(record.buffer_size) },
442 { "i_balance", T_UBYTE, OFF(record.balance) },
443 { "i_avail_ports", T_UINT, OFF(record.avail_ports) },
444 #endif
446 { "o_sample_rate", T_UINT, OFF(play.sample_rate) },
447 { "o_channels", T_UINT, OFF(play.channels) },
448 { "o_precision", T_UINT, OFF(play.precision) },
449 { "o_encoding", T_UINT, OFF(play.encoding) },
450 { "o_gain", T_UINT, OFF(play.gain) },
451 { "o_port", T_UINT, OFF(play.port) },
452 { "o_samples", T_UINT, OFF(play.samples) },
453 { "o_eof", T_UINT, OFF(play.eof) },
454 { "o_pause", T_UBYTE, OFF(play.pause) },
455 { "o_error", T_UBYTE, OFF(play.error) },
456 { "o_waiting", T_UBYTE, OFF(play.waiting) },
457 { "o_open", T_UBYTE, OFF(play.open) , RO},
458 { "o_active", T_UBYTE, OFF(play.active) , RO},
459 #ifdef SOLARIS
460 { "o_buffer_size", T_UINT, OFF(play.buffer_size) },
461 { "o_balance", T_UBYTE, OFF(play.balance) },
462 { "o_avail_ports", T_UINT, OFF(play.avail_ports) },
463 #endif
465 { "monitor_gain", T_UINT, OFF(monitor_gain) },
466 { NULL, 0, 0},
469 static PyObject *
470 sads_getattr(xp, name)
471 sadstatusobject *xp;
472 char *name;
474 return PyMember_Get((char *)&xp->ai, sads_ml, name);
477 static int
478 sads_setattr(xp, name, v)
479 sadstatusobject *xp;
480 char *name;
481 PyObject *v;
484 if (v == NULL) {
485 PyErr_SetString(PyExc_TypeError,
486 "can't delete sun audio status attributes");
487 return -1;
489 return PyMember_Set((char *)&xp->ai, sads_ml, name, v);
492 /* ------------------------------------------------------------------- */
495 static PyTypeObject Sadtype = {
496 PyObject_HEAD_INIT(&PyType_Type)
497 0, /*ob_size*/
498 "sun_audio_device", /*tp_name*/
499 sizeof(sadobject), /*tp_size*/
500 0, /*tp_itemsize*/
501 /* methods */
502 (destructor)sad_dealloc, /*tp_dealloc*/
503 0, /*tp_print*/
504 (getattrfunc)sad_getattr, /*tp_getattr*/
505 0, /*tp_setattr*/
506 0, /*tp_compare*/
507 0, /*tp_repr*/
510 static PyTypeObject Sadstatustype = {
511 PyObject_HEAD_INIT(&PyType_Type)
512 0, /*ob_size*/
513 "sun_audio_device_status", /*tp_name*/
514 sizeof(sadstatusobject), /*tp_size*/
515 0, /*tp_itemsize*/
516 /* methods */
517 (destructor)sads_dealloc, /*tp_dealloc*/
518 0, /*tp_print*/
519 (getattrfunc)sads_getattr, /*tp_getattr*/
520 (setattrfunc)sads_setattr, /*tp_setattr*/
521 0, /*tp_compare*/
522 0, /*tp_repr*/
524 /* ------------------------------------------------------------------- */
526 static PyObject *
527 sadopen(self, args)
528 PyObject *self;
529 PyObject *args;
531 return (PyObject *)newsadobject(args);
534 static PyMethodDef sunaudiodev_methods[] = {
535 { "open", sadopen },
536 { 0, 0 },
539 void
540 initsunaudiodev()
542 PyObject *m, *d;
544 m = Py_InitModule("sunaudiodev", sunaudiodev_methods);
545 d = PyModule_GetDict(m);
546 SunAudioError = PyErr_NewException("sunaudiodev.error", NULL, NULL);
547 if (SunAudioError)
548 PyDict_SetItemString(d, "error", SunAudioError);