forked from auracaster/pyalsaaudio
Import from divmod. Original log message:
r833 | casper | 2004-10-05 21:43:58 +0200 (Tue, 05 Oct 2004) | 1 line Completed mixer read/write support. Docs to follow git-svn-id: svn://svn.code.sf.net/p/pyalsaaudio/code/trunk@4 ec2f30ec-7544-0410-870e-f70ca00c83f0
This commit is contained in:
4
TODO
4
TODO
@@ -1,3 +1,5 @@
|
||||
- Implement the Mixer API
|
||||
|
||||
- Write documentation
|
||||
- Better example code (aplay workalike for instance)
|
||||
- Implement MIDI/sequencer support.
|
||||
|
||||
|
||||
586
alsaaudio.c
586
alsaaudio.c
@@ -1,14 +1,11 @@
|
||||
/*
|
||||
* alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture).
|
||||
* The standard audio API for Linux since kernel 2.0
|
||||
* The standard audio API for Linux since kernel 2.6
|
||||
*
|
||||
* Contributed by Unispeed A/S (http://www.unispeed.com)
|
||||
* Primary author: Casper Wilstup (cwi@unispeed.dk)
|
||||
* Author: Casper Wilstup (cwi@unispeed.dk)
|
||||
*
|
||||
*
|
||||
* (c) 2004 by Unispeed A/S. All rights reserved.
|
||||
*
|
||||
* License: CRNI's Python 1.6 license (or any later version of the same)
|
||||
* License: Python Software Foundation License
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -21,7 +18,7 @@ typedef struct {
|
||||
PyObject_HEAD;
|
||||
int pcmtype;
|
||||
int pcmmode;
|
||||
char *pcmname;
|
||||
char *cardname;
|
||||
|
||||
snd_pcm_t *handle;
|
||||
|
||||
@@ -34,10 +31,33 @@ typedef struct {
|
||||
|
||||
} alsapcm_t;
|
||||
|
||||
static PyTypeObject ALSAAudioType;
|
||||
typedef struct {
|
||||
PyObject_HEAD;
|
||||
|
||||
/* Mixer identification */
|
||||
char *cardname;
|
||||
char *controlname;
|
||||
int controlid;
|
||||
|
||||
/* Capabilities */
|
||||
unsigned int volume_cap;
|
||||
unsigned int switch_cap;
|
||||
unsigned int pchannels;
|
||||
unsigned int cchannels;
|
||||
|
||||
snd_mixer_t *handle;
|
||||
|
||||
} alsamixer_t;
|
||||
|
||||
static PyObject *ALSAAudioError;
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* PCM object wrapper */
|
||||
/******************************************/
|
||||
|
||||
static PyTypeObject ALSAPCMType;
|
||||
|
||||
static int alsapcm_setup(alsapcm_t *self) {
|
||||
int res,dir;
|
||||
unsigned int val;
|
||||
@@ -48,7 +68,7 @@ static int alsapcm_setup(alsapcm_t *self) {
|
||||
snd_pcm_close(self->handle);
|
||||
self->handle = 0;
|
||||
}
|
||||
res = snd_pcm_open(&(self->handle),self->pcmname,self->pcmtype,self->pcmmode);
|
||||
res = snd_pcm_open(&(self->handle),self->cardname,self->pcmtype,self->pcmmode);
|
||||
if (res < 0) return res;
|
||||
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
@@ -73,16 +93,15 @@ static int alsapcm_setup(alsapcm_t *self) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ALSA PCM Object members */
|
||||
static alsapcm_t *
|
||||
newalsapcmobject(PyObject *args) {
|
||||
static PyObject *
|
||||
alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
|
||||
int res;
|
||||
alsapcm_t *self;
|
||||
int pcmtype=0;
|
||||
int pcmmode=0;
|
||||
char *pcmname = "default";
|
||||
if (!PyArg_ParseTuple(args,"|iis",&pcmtype,&pcmmode,&pcmname)) return NULL;
|
||||
if (!(self = (alsapcm_t *)PyObject_New(struct alsa_audio, &ALSAAudioType))) return NULL;
|
||||
char *cardname = "default";
|
||||
if (!PyArg_ParseTuple(args,"|iis",&pcmtype,&pcmmode,&cardname)) return NULL;
|
||||
if (!(self = (alsapcm_t *)PyObject_New(alsapcm_t, &ALSAPCMType))) return NULL;
|
||||
|
||||
if (pcmtype != SND_PCM_STREAM_PLAYBACK && pcmtype != SND_PCM_STREAM_CAPTURE) {
|
||||
PyErr_SetString(ALSAAudioError, "PCM type must be PCM_PLAYBACK (0) or PCM_CAPTUPE (1)");
|
||||
@@ -94,7 +113,7 @@ newalsapcmobject(PyObject *args) {
|
||||
}
|
||||
self->pcmtype = pcmtype;
|
||||
self->pcmmode = pcmmode;
|
||||
self->pcmname = strdup(pcmname);
|
||||
self->cardname = strdup(cardname);
|
||||
|
||||
self->channels = 2;
|
||||
self->rate = 44100;
|
||||
@@ -111,7 +130,7 @@ newalsapcmobject(PyObject *args) {
|
||||
PyErr_SetString(ALSAAudioError, snd_strerror(res));
|
||||
return NULL;
|
||||
}
|
||||
return self;
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static void alsapcm_dealloc(alsapcm_t *self) {
|
||||
@@ -119,6 +138,7 @@ static void alsapcm_dealloc(alsapcm_t *self) {
|
||||
snd_pcm_drain(self->handle);
|
||||
snd_pcm_close(self->handle);
|
||||
}
|
||||
free(self->cardname);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
@@ -228,9 +248,9 @@ alsapcm_pcmmode(alsapcm_t *self, PyObject *args) {
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsapcm_pcmname(alsapcm_t *self, PyObject *args) {
|
||||
alsapcm_cardname(alsapcm_t *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
return PyString_FromString(self->pcmname);
|
||||
return PyString_FromString(self->cardname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@@ -350,20 +370,13 @@ static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) {
|
||||
return PyInt_FromLong(datalen);
|
||||
}
|
||||
|
||||
/* Module functions */
|
||||
|
||||
static PyObject *
|
||||
alsa_openpcm(PyObject *self, PyObject *args) {
|
||||
return (PyObject *)newalsapcmobject(args);
|
||||
}
|
||||
|
||||
|
||||
/* ALSA PCM Object Bureaucracy */
|
||||
|
||||
static PyMethodDef alsapcm_methods[] = {
|
||||
{"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS},
|
||||
{"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS},
|
||||
{"pcmname", (PyCFunction)alsapcm_pcmname, METH_VARARGS},
|
||||
{"cardname", (PyCFunction)alsapcm_cardname, METH_VARARGS},
|
||||
{"setchannels", (PyCFunction)alsapcm_setchannels, METH_VARARGS},
|
||||
{"setrate", (PyCFunction)alsapcm_setrate, METH_VARARGS},
|
||||
{"setformat", (PyCFunction)alsapcm_setformat, METH_VARARGS},
|
||||
@@ -382,45 +395,528 @@ alsapcm_getattr(alsapcm_t *self, char *name) {
|
||||
return Py_FindMethod(alsapcm_methods, (PyObject *)self, name);
|
||||
}
|
||||
|
||||
static PyTypeObject ALSAAudioType = {
|
||||
static PyTypeObject ALSAPCMType = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"alsaaudio.pcm",
|
||||
sizeof(alsapcm_t),
|
||||
0,
|
||||
/* methods */
|
||||
(destructor) alsapcm_dealloc,
|
||||
0,
|
||||
(getattrfunc)alsapcm_getattr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, /*ob_size*/
|
||||
"alsaaudio.pcm", /*tp_name*/
|
||||
sizeof(alsapcm_t), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor) alsapcm_dealloc, /*tp_dealloc*/
|
||||
0, /*print*/
|
||||
(getattrfunc)alsapcm_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
"ALSA PCM device", /*tp_doc*/
|
||||
};
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* Mixer object wrapper */
|
||||
/******************************************/
|
||||
|
||||
/* Initialization */
|
||||
static PyTypeObject ALSAMixerType;
|
||||
|
||||
#define MIXER_CAP_VOLUME 0x0001
|
||||
#define MIXER_CAP_VOLUME_JOINED 0x0002
|
||||
#define MIXER_CAP_PVOLUME 0x0004
|
||||
#define MIXER_CAP_PVOLUME_JOINED 0x0008
|
||||
#define MIXER_CAP_CVOLUME 0x0010
|
||||
#define MIXER_CAP_CVOLUME_JOINED 0x0020
|
||||
|
||||
#define MIXER_CAP_SWITCH 0x0001
|
||||
#define MIXER_CAP_SWITCH_JOINED 0x0002
|
||||
#define MIXER_CAP_PSWITCH 0x0004
|
||||
#define MIXER_CAP_PSWITCH_JOINED 0x0008
|
||||
#define MIXER_CAP_CSWITCH 0x0010
|
||||
#define MIXER_CAP_CSWITCH_JOINED 0x0020
|
||||
#define MIXER_CAP_CSWITCH_EXCLUSIVE 0x0040
|
||||
|
||||
#define MIXER_CHANNEL_ALL -1
|
||||
|
||||
int
|
||||
alsamixer_gethandle(char *cardname, snd_mixer_t **handle) {
|
||||
int err;
|
||||
if ((err = snd_mixer_open(handle, 0)) < 0) return err;
|
||||
if ((err = snd_mixer_attach(*handle, cardname)) < 0) return err;
|
||||
if ((err = snd_mixer_selem_register(*handle, NULL, NULL)) < 0) return err;
|
||||
if ((err = snd_mixer_load(*handle)) < 0) return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_list(PyObject *self, PyObject *args) {
|
||||
snd_mixer_t *handle;
|
||||
snd_mixer_selem_id_t *sid;
|
||||
snd_mixer_elem_t *elem;
|
||||
int err;
|
||||
char *cardname = "default";
|
||||
PyObject *result = PyList_New(0);
|
||||
|
||||
if (!PyArg_ParseTuple(args,"|s",&cardname)) return NULL;
|
||||
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
err = alsamixer_gethandle(cardname,&handle);
|
||||
if (err < 0) {
|
||||
PyErr_SetString(ALSAAudioError,snd_strerror(err));
|
||||
snd_mixer_close(handle);
|
||||
return NULL;
|
||||
}
|
||||
for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
|
||||
PyObject *mixer;
|
||||
snd_mixer_selem_get_id(elem, sid);
|
||||
mixer = PyString_FromString(snd_mixer_selem_id_get_name(sid));
|
||||
PyList_Append(result,mixer);
|
||||
Py_DECREF(mixer);
|
||||
}
|
||||
snd_mixer_close(handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static snd_mixer_elem_t *
|
||||
alsamixer_find_elem(snd_mixer_t *handle, char *control, int id) {
|
||||
snd_mixer_selem_id_t *sid;
|
||||
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
snd_mixer_selem_id_set_index(sid, id);
|
||||
snd_mixer_selem_id_set_name(sid, control);
|
||||
return snd_mixer_find_selem(handle, sid);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
|
||||
alsamixer_t *self;
|
||||
int err;
|
||||
char *cardname = "default";
|
||||
char *control = "Master";
|
||||
int id = 0;
|
||||
snd_mixer_elem_t *elem;
|
||||
int channel;
|
||||
|
||||
if (!PyArg_ParseTuple(args,"|sis",&control,&id,&cardname)) return NULL;
|
||||
if (!(self = (alsamixer_t *)PyObject_New(alsamixer_t, &ALSAMixerType))) return NULL;
|
||||
|
||||
err = alsamixer_gethandle(cardname,&self->handle);
|
||||
if (err<0) {
|
||||
PyErr_SetString(ALSAAudioError,snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
self->cardname = strdup(cardname);
|
||||
self->controlname = strdup(control);
|
||||
self->controlid = id;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,control,id);
|
||||
if (!elem) {
|
||||
char errtext[128];
|
||||
sprintf(errtext,"Unable to find mixer control '%s',%i",self->controlname,self->controlid);
|
||||
snd_mixer_close(self->handle);
|
||||
PyErr_SetString(ALSAAudioError,errtext);
|
||||
return NULL;
|
||||
}
|
||||
/* Determine mixer capabilities */
|
||||
self->volume_cap = self->switch_cap = 0;
|
||||
if (snd_mixer_selem_has_common_volume(elem)) {
|
||||
self->volume_cap |= MIXER_CAP_VOLUME;
|
||||
if (snd_mixer_selem_has_playback_volume_joined(elem)) self->volume_cap |= MIXER_CAP_VOLUME_JOINED;
|
||||
}
|
||||
else {
|
||||
if (snd_mixer_selem_has_playback_volume(elem)) {
|
||||
self->volume_cap |= MIXER_CAP_PVOLUME;
|
||||
if (snd_mixer_selem_has_playback_volume_joined(elem)) self->volume_cap |= MIXER_CAP_PVOLUME_JOINED;
|
||||
}
|
||||
if (snd_mixer_selem_has_capture_volume(elem)) {
|
||||
self->volume_cap |= MIXER_CAP_CVOLUME;
|
||||
if (snd_mixer_selem_has_capture_volume_joined(elem)) self->volume_cap |= MIXER_CAP_CVOLUME_JOINED;
|
||||
}
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_has_common_switch(elem)) {
|
||||
self->switch_cap |= MIXER_CAP_SWITCH;
|
||||
if (snd_mixer_selem_has_playback_switch_joined(elem)) self->switch_cap |= MIXER_CAP_SWITCH_JOINED;
|
||||
}
|
||||
else {
|
||||
if (snd_mixer_selem_has_playback_switch(elem)) {
|
||||
self->switch_cap |= MIXER_CAP_PSWITCH;
|
||||
if (snd_mixer_selem_has_playback_switch_joined(elem)) self->switch_cap |= MIXER_CAP_PSWITCH_JOINED;
|
||||
}
|
||||
if (snd_mixer_selem_has_capture_switch(elem)) {
|
||||
self->switch_cap |= MIXER_CAP_CSWITCH;
|
||||
if (snd_mixer_selem_has_capture_switch_joined(elem)) self->switch_cap |= MIXER_CAP_CSWITCH_JOINED;
|
||||
if (snd_mixer_selem_has_capture_switch_exclusive(elem)) self->switch_cap |= MIXER_CAP_CSWITCH_EXCLUSIVE;
|
||||
}
|
||||
}
|
||||
self->pchannels = 0;
|
||||
if (self->volume_cap | MIXER_CAP_PVOLUME || self->switch_cap | MIXER_CAP_PSWITCH) {
|
||||
if (snd_mixer_selem_is_playback_mono(elem)) self->pchannels = 1;
|
||||
else {
|
||||
for (channel=0; channel <= SND_MIXER_SCHN_LAST; channel++) {
|
||||
if (snd_mixer_selem_has_playback_channel(elem, channel)) self->pchannels++;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->cchannels = 0;
|
||||
if (self->volume_cap | MIXER_CAP_CVOLUME || self->switch_cap | MIXER_CAP_CSWITCH) {
|
||||
if (snd_mixer_selem_is_capture_mono(elem)) self->cchannels = 1;
|
||||
else {
|
||||
for (channel=0; channel <= SND_MIXER_SCHN_LAST; channel++) {
|
||||
if (snd_mixer_selem_has_capture_channel(elem, channel)) self->cchannels++;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static void alsamixer_dealloc(alsamixer_t *self) {
|
||||
if (self->handle) {
|
||||
snd_mixer_close(self->handle);
|
||||
free(self->cardname);
|
||||
free(self->controlname);
|
||||
self->handle = 0;
|
||||
}
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_cardname(alsamixer_t *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
return PyString_FromString(self->cardname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_mixer(alsamixer_t *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
return PyString_FromString(self->controlname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_mixerid(alsamixer_t *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
return PyInt_FromLong(self->controlid);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_volumecap(alsamixer_t *self, PyObject *args) {
|
||||
PyObject *result;
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
result = PyList_New(0);
|
||||
if (self->volume_cap&MIXER_CAP_VOLUME)
|
||||
PyList_Append(result,PyString_FromString("Volume"));
|
||||
if (self->volume_cap&MIXER_CAP_VOLUME_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Volume"));
|
||||
if (self->volume_cap&MIXER_CAP_PVOLUME)
|
||||
PyList_Append(result,PyString_FromString("Playback Volume"));
|
||||
if (self->volume_cap&MIXER_CAP_PVOLUME_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Playback Volume"));
|
||||
if (self->volume_cap&MIXER_CAP_CVOLUME)
|
||||
PyList_Append(result,PyString_FromString("Capture Volume"));
|
||||
if (self->volume_cap&MIXER_CAP_CVOLUME_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Capture Volume"));
|
||||
|
||||
return result;
|
||||
}
|
||||
static PyObject *
|
||||
alsamixer_switchcap(alsamixer_t *self, PyObject *args) {
|
||||
PyObject *result;
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
result = PyList_New(0);
|
||||
if (self->volume_cap&MIXER_CAP_SWITCH)
|
||||
PyList_Append(result,PyString_FromString("Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_SWITCH_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_PSWITCH)
|
||||
PyList_Append(result,PyString_FromString("Playback Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_PSWITCH_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Playback Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_CSWITCH)
|
||||
PyList_Append(result,PyString_FromString("Capture Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_CSWITCH_JOINED)
|
||||
PyList_Append(result,PyString_FromString("Joined Capture Mute"));
|
||||
if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE)
|
||||
PyList_Append(result,PyString_FromString("Capture Exclusive"));
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_getvolume(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int direction;
|
||||
int channel;
|
||||
long ival;
|
||||
char *dirstr = 0;
|
||||
PyObject *result;
|
||||
|
||||
if (!PyArg_ParseTuple(args,"|s",&dirstr)) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
|
||||
if (!dirstr) {
|
||||
if (self->pchannels) direction = 0;
|
||||
else direction = 1;
|
||||
}
|
||||
else if (strcasecmp(dirstr,"playback")==0) direction = 0;
|
||||
else if (strcasecmp(dirstr,"capture")==0) direction = 1;
|
||||
else {
|
||||
PyErr_SetString(ALSAAudioError,"Invalid direction argument for mixer");
|
||||
return NULL;
|
||||
}
|
||||
result = PyList_New(0);
|
||||
for (channel = 0; channel <= SND_MIXER_SCHN_LAST; channel++) {
|
||||
if (direction == 0 && snd_mixer_selem_has_playback_channel(elem, channel)) {
|
||||
snd_mixer_selem_get_playback_volume(elem, channel, &ival);
|
||||
PyList_Append(result,PyInt_FromLong(ival));
|
||||
}
|
||||
else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, channel)
|
||||
&& snd_mixer_selem_has_capture_volume(elem)) {
|
||||
snd_mixer_selem_get_capture_volume(elem, channel, &ival);
|
||||
PyList_Append(result,PyInt_FromLong(ival));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_getmute(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int i;
|
||||
int ival;
|
||||
PyObject *result;
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
if (!snd_mixer_selem_has_playback_switch(elem)) {
|
||||
PyErr_SetString(ALSAAudioError,"Mixer has no mute switch");
|
||||
return NULL;
|
||||
}
|
||||
result = PyList_New(0);
|
||||
for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (snd_mixer_selem_has_playback_channel(elem, i)) {
|
||||
snd_mixer_selem_get_playback_switch(elem, i, &ival);
|
||||
PyList_Append(result,PyInt_FromLong(!ival));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_getrec(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int i;
|
||||
int ival;
|
||||
PyObject *result;
|
||||
if (!PyArg_ParseTuple(args,"")) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
if (!snd_mixer_selem_has_capture_switch(elem)) {
|
||||
PyErr_SetString(ALSAAudioError,"Mixer has no mute switch");
|
||||
return NULL;
|
||||
}
|
||||
result = PyList_New(0);
|
||||
for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (snd_mixer_selem_has_capture_channel(elem, i)) {
|
||||
snd_mixer_selem_get_capture_switch(elem, i, &ival);
|
||||
PyList_Append(result,PyInt_FromLong(!ival));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_setvolume(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int direction;
|
||||
int i;
|
||||
int volume;
|
||||
char *dirstr = 0;
|
||||
int channel = MIXER_CHANNEL_ALL;
|
||||
int done = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args,"i|is",&volume,&channel,&dirstr)) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
|
||||
if (!dirstr) {
|
||||
if (self->pchannels) direction = 0;
|
||||
else direction = 1;
|
||||
}
|
||||
else if (strcasecmp(dirstr,"playback")==0) direction = 0;
|
||||
else if (strcasecmp(dirstr,"capture")==0) direction = 1;
|
||||
else {
|
||||
PyErr_SetString(ALSAAudioError,"Invalid direction argument. Use 'playback' or 'capture'");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (channel == -1 || channel == i) {
|
||||
if (direction == 0 && snd_mixer_selem_has_playback_channel(elem, i)) {
|
||||
snd_mixer_selem_set_playback_volume(elem, i, volume);
|
||||
done++;
|
||||
}
|
||||
else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, channel)
|
||||
&& snd_mixer_selem_has_capture_volume(elem)) {
|
||||
snd_mixer_selem_set_capture_volume(elem, i, volume);
|
||||
done++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!done) {
|
||||
PyErr_SetString(ALSAAudioError,"No such channel");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_setmute(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int i;
|
||||
int mute = 0;
|
||||
int done = 0;
|
||||
int channel = MIXER_CHANNEL_ALL;
|
||||
if (!PyArg_ParseTuple(args,"i|i",&mute,&channel)) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
if (!snd_mixer_selem_has_playback_switch(elem)) {
|
||||
PyErr_SetString(ALSAAudioError,"Mixer has no mute switch");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (channel == MIXER_CHANNEL_ALL || channel == i) {
|
||||
if (snd_mixer_selem_has_playback_channel(elem, i)) {
|
||||
snd_mixer_selem_set_playback_switch(elem, i, !mute);
|
||||
done++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
PyErr_SetString(ALSAAudioError,"Invalid channel number");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
alsamixer_setrec(alsamixer_t *self, PyObject *args) {
|
||||
snd_mixer_elem_t *elem;
|
||||
int i;
|
||||
int rec = 0;
|
||||
int done = 0;
|
||||
int channel = MIXER_CHANNEL_ALL;
|
||||
if (!PyArg_ParseTuple(args,"i|i",&rec,&channel)) return NULL;
|
||||
|
||||
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
|
||||
if (!snd_mixer_selem_has_capture_switch(elem)) {
|
||||
PyErr_SetString(ALSAAudioError,"Mixer has no record switch");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (channel == MIXER_CHANNEL_ALL || channel == i) {
|
||||
if (snd_mixer_selem_has_capture_channel(elem, i)) {
|
||||
snd_mixer_selem_set_playback_switch(elem, i, rec);
|
||||
done++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
PyErr_SetString(ALSAAudioError,"Invalid channel number");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef alsamixer_methods[] = {
|
||||
{"cardname", (PyCFunction)alsamixer_cardname, METH_VARARGS},
|
||||
{"mixer", (PyCFunction)alsamixer_mixer, METH_VARARGS},
|
||||
{"mixerid", (PyCFunction)alsamixer_mixerid, METH_VARARGS},
|
||||
{"switchcap", (PyCFunction)alsamixer_switchcap, METH_VARARGS},
|
||||
{"volumecap", (PyCFunction)alsamixer_volumecap, METH_VARARGS},
|
||||
{"getvolume", (PyCFunction)alsamixer_getvolume, METH_VARARGS},
|
||||
{"getmute", (PyCFunction)alsamixer_getmute, METH_VARARGS},
|
||||
{"getrec", (PyCFunction)alsamixer_getrec, METH_VARARGS},
|
||||
{"setvolume", (PyCFunction)alsamixer_setvolume, METH_VARARGS},
|
||||
{"setmute", (PyCFunction)alsamixer_setmute, METH_VARARGS},
|
||||
{"setrec", (PyCFunction)alsamixer_setrec, METH_VARARGS},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyObject *
|
||||
alsamixer_getattr(alsapcm_t *self, char *name) {
|
||||
return Py_FindMethod(alsamixer_methods, (PyObject *)self, name);
|
||||
}
|
||||
|
||||
static PyTypeObject ALSAMixerType = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /*ob_size*/
|
||||
"alsaaudio.mixer", /*tp_name*/
|
||||
sizeof(alsamixer_t), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor) alsamixer_dealloc, /*tp_dealloc*/
|
||||
0, /*print*/
|
||||
(getattrfunc)alsamixer_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
"ALSA Mixer Control", /*tp_doc*/
|
||||
};
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* Module initialization */
|
||||
/******************************************/
|
||||
|
||||
static PyMethodDef alsaaudio_methods[] = {
|
||||
{ "openpcm", alsa_openpcm, METH_VARARGS },
|
||||
{ "mixers", alsamixer_list, METH_VARARGS },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
#define _EXPORT_CONSTANT(mod, name) \
|
||||
if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return;
|
||||
#define _EXPORT_INT(mod, name, value) \
|
||||
if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return;
|
||||
|
||||
void initalsaaudio(void) {
|
||||
PyObject *m;
|
||||
ALSAPCMType.tp_new = alsapcm_new;
|
||||
ALSAMixerType.tp_new = alsamixer_new;
|
||||
m = Py_InitModule("alsaaudio",alsaaudio_methods);
|
||||
|
||||
ALSAAudioError = PyErr_NewException("alsaaudio.ALSAAudioError", NULL, NULL);
|
||||
if (ALSAAudioError) {
|
||||
/* Each call to PyModule_AddObject decrefs it; compensate: */
|
||||
|
||||
Py_INCREF(&ALSAPCMType);
|
||||
PyModule_AddObject(m,"PCM",(PyObject *)&ALSAPCMType);
|
||||
|
||||
Py_INCREF(&ALSAMixerType);
|
||||
PyModule_AddObject(m,"Mixer",(PyObject *)&ALSAMixerType);
|
||||
|
||||
Py_INCREF(ALSAAudioError);
|
||||
Py_INCREF(ALSAAudioError);
|
||||
PyModule_AddObject(m, "error", ALSAAudioError);
|
||||
PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import sys
|
||||
import time
|
||||
|
||||
# Open the device in playback mode.
|
||||
out = alsaaudio.openpcm(alsaaudio.PCM_PLAYBACK)
|
||||
out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK)
|
||||
|
||||
# Set attributes: Mono, 8000 Hz, 16 bit little endian frames
|
||||
out.setchannels(1)
|
||||
|
||||
@@ -17,7 +17,7 @@ import time
|
||||
# Open the device in nonblocking capture mode. The last argument could
|
||||
# just as well have been zero for blocking mode. Then we could have
|
||||
# left out the sleep call in the bottom of the loop
|
||||
inp = alsaaudio.openpcm(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
|
||||
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
|
||||
|
||||
# Set attributes: Mono, 8000 Hz, 16 bit little endian samples
|
||||
inp.setchannels(1)
|
||||
|
||||
Reference in New Issue
Block a user