From 70667fa55a865675e7bed33c830e39972508c79f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 11 Jul 2007 10:09:31 +0200 Subject: [PATCH] added alsacontrol module (not finished) - added more attributes for alsa-lib's simple mixer layer --- pyalsa/alsacontrol.c | 250 ++++++++++++++++++++++++++++++++++++++++++ pyalsa/alsahcontrol.c | 46 ++++++-- setup.py | 5 + 3 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 pyalsa/alsacontrol.c diff --git a/pyalsa/alsacontrol.c b/pyalsa/alsacontrol.c new file mode 100644 index 0000000..9bbde53 --- /dev/null +++ b/pyalsa/alsacontrol.c @@ -0,0 +1,250 @@ +/* + * Python binding for the ALSA library - Universal Control Layer + * Copyright (c) 2007 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "Python.h" +#include "structmember.h" +#include "frameobject.h" +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#include "stdlib.h" +#include "alsa/asoundlib.h" + +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif + +static PyObject *module; +#if 0 +static PyObject *buildin; +#endif + +/* + * + */ + +#define PYCTL(v) (((v) == Py_None) ? NULL : \ + ((struct pyalsacontrol *)(v))) + +struct pyalsacontrol { + PyObject_HEAD + snd_ctl_t *handle; +}; + +static inline PyObject *get_bool(int val) +{ + if (val) { + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } +} + +PyDoc_STRVAR(cardinfo__doc__, +"cardInfo() -- Return a dictionary with card specific information."); + +static PyObject * +pyalsacontrol_cardinfo(struct pyalsacontrol *self, PyObject *args) +{ + snd_ctl_card_info_t *info; + PyObject *d; + + snd_ctl_card_info_alloca(&info); + int err = snd_ctl_card_info(self->handle, info); + if (err < 0) { + PyErr_Format(PyExc_IOError, + "Control card info error: %s", strerror(-err)); + Py_RETURN_NONE; + } else { + + } + d = PyDict_New(); + if (d) { + PyDict_SetItem(d, PyString_FromString("card"), PyInt_FromLong(snd_ctl_card_info_get_card(info))); + PyDict_SetItem(d, PyString_FromString("id"), PyString_FromString(snd_ctl_card_info_get_id(info))); + PyDict_SetItem(d, PyString_FromString("driver"), PyString_FromString(snd_ctl_card_info_get_driver(info))); + PyDict_SetItem(d, PyString_FromString("name"), PyString_FromString(snd_ctl_card_info_get_driver(info))); + PyDict_SetItem(d, PyString_FromString("longname"), PyString_FromString(snd_ctl_card_info_get_longname(info))); + PyDict_SetItem(d, PyString_FromString("mixername"), PyString_FromString(snd_ctl_card_info_get_mixername(info))); + PyDict_SetItem(d, PyString_FromString("components"), PyString_FromString(snd_ctl_card_info_get_components(info))); + } + return d; +} + +PyDoc_STRVAR(alsacontrolinit__doc__, +"Control([name='default'],[mode=0])\n" +" -- Open an ALSA Control device.\n"); + +static int +pyalsacontrol_init(struct pyalsacontrol *pyctl, PyObject *args, PyObject *kwds) +{ + char *name = "default"; + int mode = 0, err; + + static char * kwlist[] = { "name", "mode", NULL }; + + pyctl->handle = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si", kwlist, &name, &mode)) + return -1; + + err = snd_ctl_open(&pyctl->handle, name, mode); + if (err < 0) { + PyErr_Format(PyExc_IOError, + "Control open error: %s", strerror(-err)); + return -1; + } + + return 0; +} + +static void +pyalsacontrol_dealloc(struct pyalsacontrol *self) +{ + if (self->handle != NULL) + snd_ctl_close(self->handle); + + self->ob_type->tp_free(self); +} + +static PyGetSetDef pyalsacontrol_getseters[] = { + + {NULL} +}; + +static PyMethodDef pyalsacontrol_methods[] = { + + {"cardInfo", (PyCFunction)pyalsacontrol_cardinfo, METH_NOARGS, cardinfo__doc__}, + {NULL} +}; + +static PyTypeObject pyalsacontrol_type = { + PyObject_HEAD_INIT(0) + tp_name: "alsacontrol.Control", + tp_basicsize: sizeof(struct pyalsacontrol), + tp_dealloc: (destructor)pyalsacontrol_dealloc, + tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + tp_doc: alsacontrolinit__doc__, + tp_getset: pyalsacontrol_getseters, + tp_init: (initproc)pyalsacontrol_init, + tp_alloc: PyType_GenericAlloc, + tp_new: PyType_GenericNew, + tp_free: PyObject_Del, + tp_methods: pyalsacontrol_methods, +}; + +/* + * + */ + +static PyMethodDef pyalsacontrolparse_methods[] = { + {NULL} +}; + +PyMODINIT_FUNC +initalsacontrol(void) +{ + PyObject *d, *d1, *l1, *o; + int i; + + if (PyType_Ready(&pyalsacontrol_type) < 0) + return; + + module = Py_InitModule3("alsacontrol", pyalsacontrolparse_methods, "libasound control wrapper"); + if (module == NULL) + return; + +#if 0 + buildin = PyImport_AddModule("__buildin__"); + if (buildin == NULL) + return; + if (PyObject_SetAttrString(module, "__buildins__", buildin) < 0) + return; +#endif + + Py_INCREF(&pyalsacontrol_type); + PyModule_AddObject(module, "Control", (PyObject *)&pyalsacontrol_type); + + d = PyModule_GetDict(module); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space1(pname, name) { \ + o = PyInt_FromLong(SND_CTL_ELEM_IFACE_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space1("Card", CARD); + add_space1("HwDep", HWDEP); + add_space1("Mixer", MIXER); + add_space1("PCM", PCM); + add_space1("RawMidi", RAWMIDI); + add_space1("Timer", TIMER); + add_space1("Sequencer", SEQUENCER); + add_space1("Last", LAST); + + PyDict_SetItemString(d, "InterfaceId", d1); + Py_DECREF(d1); + + /* ---- */ + + l1 = PyList_New(0); + + for (i = 0; i <= SND_CTL_ELEM_IFACE_LAST; i++) { + o = PyString_FromString(snd_ctl_elem_iface_name(i)); + PyList_Append(l1, o); + Py_DECREF(o); + } + + PyDict_SetItemString(d, "InterfaceName", l1); + Py_DECREF(l1); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space5(pname, name) { \ + o = PyInt_FromLong(SND_CTL_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space5("NonBlock", NONBLOCK); + add_space5("Async", ASYNC); + add_space5("ReadOnly", READONLY); + + PyDict_SetItemString(d, "OpenMode", d1); + Py_DECREF(d1); + + /* ---- */ + + if (PyErr_Occurred()) + Py_FatalError("Cannot initialize module alsacontrol"); +} diff --git a/pyalsa/alsahcontrol.c b/pyalsa/alsahcontrol.c index beb22bd..c7387e7 100644 --- a/pyalsa/alsahcontrol.c +++ b/pyalsa/alsahcontrol.c @@ -136,6 +136,12 @@ pyalsahcontrol_getcount(struct pyalsahcontrol *self, void *priv) return PyLong_FromLong(snd_hctl_get_count(self->handle)); } +static PyObject * +pyalsahcontrol_getChctl(struct pyalsahcontrol *self, void *priv) +{ + return PyInt_FromLong((long)self->handle); +} + PyDoc_STRVAR(handlevents__doc__, "handleEvents() -- Process waiting hcontrol events (and call appropriate callbacks)."); @@ -349,13 +355,13 @@ static int pyalsahcontrol_init(struct pyalsahcontrol *pyhctl, PyObject *args, PyObject *kwds) { char *name = "default"; - int mode = 0, err; + int mode = 0, load = 1, err; - static char * kwlist[] = { "name", "mode", NULL }; + static char * kwlist[] = { "name", "mode", "load", NULL }; pyhctl->handle = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si", kwlist, &name, &mode)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii", kwlist, &name, &mode, &load)) return -1; err = snd_hctl_open(&pyhctl->handle, name, mode); @@ -365,13 +371,15 @@ pyalsahcontrol_init(struct pyalsahcontrol *pyhctl, PyObject *args, PyObject *kwd return -1; } - err = snd_hctl_load(pyhctl->handle); - if (err < 0) { - snd_hctl_close(pyhctl->handle); - pyhctl->handle = NULL; - PyErr_Format(PyExc_IOError, - "HControl load error: %s", strerror(-err)); - return -1; + if (load) { + err = snd_hctl_load(pyhctl->handle); + if (err < 0) { + snd_hctl_close(pyhctl->handle); + pyhctl->handle = NULL; + PyErr_Format(PyExc_IOError, + "HControl load error: %s", strerror(-err)); + return -1; + } } return 0; @@ -389,6 +397,7 @@ pyalsahcontrol_dealloc(struct pyalsahcontrol *self) static PyGetSetDef pyalsahcontrol_getseters[] = { {"count", (getter)pyalsahcontrol_getcount, NULL, "hcontrol element count", NULL}, + {"get_C_hctl", (getter)pyalsahcontrol_getChctl, NULL, "hcontrol C pointer (internal)", NULL}, {NULL} }; @@ -449,6 +458,12 @@ pyalsahcontrolelement_uint(struct pyalsahcontrolelement *pyhelem, void *fcn) return PyInt_FromLong(((fcn1)fcn)(pyhelem->elem)); } +static PyObject * +pyalsahcontrolelement_getChelem(struct pyalsahcontrolelement *self, void *priv) +{ + return PyInt_FromLong((long)self->elem); +} + PyDoc_STRVAR(elock__doc__, "lock() -- Lock this element.\n"); @@ -521,6 +536,8 @@ pyalsahcontrolelement_init(struct pyalsahcontrolelement *pyhelem, PyObject *args int numid = 0, iface = 0, device = 0, subdevice = 0, index = 0; snd_ctl_elem_id_t *id; static char *kwlist1[] = { "hctl", "interface", "device", "subdevice", "name", "index" }; + long helem = 0; + float f = 0; snd_ctl_elem_id_alloca(&id); pyhelem->pyhandle = NULL; @@ -532,7 +549,10 @@ pyalsahcontrolelement_init(struct pyalsahcontrolelement *pyhelem, PyObject *args return -1; } first = PyTuple_GetItem(args, 1); - if (PyInt_Check(first)) { + if (PyFloat_Check(first)) { + if (!PyArg_ParseTuple(args, "Ofi", &hctl, &f, &helem)) + return -1; + } else if (PyInt_Check(first)) { if (!PyArg_ParseTuple(args, "Oi", &hctl, &numid)) return -1; snd_ctl_elem_id_set_numid(id, numid); @@ -562,7 +582,8 @@ pyalsahcontrolelement_init(struct pyalsahcontrolelement *pyhelem, PyObject *args Py_INCREF(hctl); pyhelem->handle = PYHCTL(hctl)->handle; - pyhelem->elem = snd_hctl_find_elem(pyhelem->handle, id); + pyhelem->elem = helem > 0 ? (snd_hctl_elem_t *)helem : + snd_hctl_find_elem(pyhelem->handle, id); if (pyhelem->elem == NULL) { if (numid == 0) PyErr_Format(PyExc_IOError, "cannot find hcontrol element %i,%i,%i,'%s',%i", iface, device, subdevice, name, index); @@ -596,6 +617,7 @@ static PyGetSetDef pyalsahcontrolelement_getseters[] = { {"subdevice", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element subdevice", snd_hctl_elem_get_subdevice}, {"name", (getter)pyalsahcontrolelement_getname, NULL, "hcontrol element name", NULL}, {"index", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element index", snd_hctl_elem_get_index}, + {"get_C_helem", (getter)pyalsahcontrolelement_getChelem, NULL, "hcontrol element C pointer (internal)", NULL }, {NULL} }; diff --git a/setup.py b/setup.py index e1f51aa..afc5a01 100755 --- a/setup.py +++ b/setup.py @@ -30,6 +30,11 @@ setup( include_dirs=[], library_dirs=[], libraries=['asound']), + Extension('pyalsa.alsacontrol', + ['pyalsa/alsacontrol.c'], + include_dirs=[], + library_dirs=[], + libraries=['asound']), Extension('pyalsa.alsahcontrol', ['pyalsa/alsahcontrol.c'], include_dirs=[], -- 2.47.1