diff --git a/CHANGES b/CHANGES index bd3f954..d528334 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +Version 0.4: +- added mixer.getenum() +- small documentation improvements + Version 0.3: - wrapped blocking calls with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS - added pause diff --git a/README b/README index 179cb79..cb8dceb 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ PyAlsaAudio =========== -Author: Casper Wilstrup (cwi@unispeed.dk) +Author: Casper Wilstrup (cwi@aves.dk) This package contains wrappers for accessing the ALSA api from Python. It is currently fairly complete for PCM devices. My next goal is to have @@ -52,4 +52,4 @@ stdin 'recordtest.py' which captures sound from the microphone at writes it raw to stdout. -'mixertest.py' which can be used to manipulate the mixers +'mixertest.py' which can be used to manipulate the mixers. diff --git a/alsaaudio.c b/alsaaudio.c index 0313332..7eddf47 100644 --- a/alsaaudio.c +++ b/alsaaudio.c @@ -191,7 +191,7 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) { snd_pcm_hw_params_current(self->handle,hwparams); - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":dumpinfo")) return NULL; printf("PCM handle name = '%s'\n", snd_pcm_name(self->handle)); printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(self->handle))); @@ -276,7 +276,7 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) { static PyObject * alsapcm_pcmtype(alsapcm_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":pcmtype")) return NULL; return PyInt_FromLong(self->pcmtype); } @@ -288,7 +288,7 @@ Returns either PCM_CAPTURE or PCM_PLAYBACK."); static PyObject * alsapcm_pcmmode(alsapcm_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,"pcmmode")) return NULL; return PyInt_FromLong(self->pcmmode); } @@ -303,7 +303,7 @@ Returns the mode of the PCM object. One of:\n\ static PyObject * alsapcm_cardname(alsapcm_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":cardname")) return NULL; return PyString_FromString(self->cardname); } @@ -317,7 +317,7 @@ static PyObject * alsapcm_setchannels(alsapcm_t *self, PyObject *args) { int channels; int res; - if (!PyArg_ParseTuple(args,"i",&channels)) return NULL; + if (!PyArg_ParseTuple(args,"i:setchannels",&channels)) return NULL; self->channels = channels; res = alsapcm_setup(self); if (res < 0) { @@ -340,7 +340,7 @@ static PyObject * alsapcm_setrate(alsapcm_t *self, PyObject *args) { int rate; int res; - if (!PyArg_ParseTuple(args,"i",&rate)) return NULL; + if (!PyArg_ParseTuple(args,"i:setrate",&rate)) return NULL; self->rate = rate; res = alsapcm_setup(self); if (res < 0) { @@ -361,7 +361,7 @@ static PyObject * alsapcm_setformat(alsapcm_t *self, PyObject *args) { int format; int res; - if (!PyArg_ParseTuple(args,"i",&format)) return NULL; + if (!PyArg_ParseTuple(args,"i:setformat",&format)) return NULL; self->format = format; res = alsapcm_setup(self); if (res < 0) { @@ -379,7 +379,7 @@ static PyObject * alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) { int periodsize; int res; - if (!PyArg_ParseTuple(args,"i",&periodsize)) return NULL; + if (!PyArg_ParseTuple(args,"i:setperiodsize",&periodsize)) return NULL; self->periodsize = periodsize; res = alsapcm_setup(self); if (res < 0) { @@ -408,7 +408,7 @@ alsapcm_read(alsapcm_t *self, PyObject *args) { return NULL; } - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":read")) return NULL; if (self->pcmtype != SND_PCM_STREAM_CAPTURE) { PyErr_SetString(ALSAAudioError,"Cannot read from playback PCM"); return NULL; @@ -453,7 +453,7 @@ static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) { char *data; int datalen; int res; - if (!PyArg_ParseTuple(args,"s#",&data,&datalen)) return NULL; + if (!PyArg_ParseTuple(args,"s#:write",&data,&datalen)) return NULL; if (datalen%self->framesize) { PyErr_SetString(ALSAAudioError, "Data size must be a multiple of framesize"); @@ -500,7 +500,7 @@ written at a later time."); static PyObject *alsapcm_pause(alsapcm_t *self, PyObject *args) { int enabled=1, res; - if (!PyArg_ParseTuple(args,"|i",&enabled)) return NULL; + if (!PyArg_ParseTuple(args,"|i:pause",&enabled)) return NULL; Py_BEGIN_ALLOW_THREADS res = snd_pcm_pause(self->handle, enabled); @@ -632,7 +632,7 @@ alsamixer_list(PyObject *self, PyObject *args) { char *cardname = "default"; PyObject *result = PyList_New(0); - if (!PyArg_ParseTuple(args,"|s",&cardname)) return NULL; + if (!PyArg_ParseTuple(args,"|s:mixers",&cardname)) return NULL; snd_mixer_selem_id_alloca(&sid); err = alsamixer_gethandle(cardname,&handle); @@ -751,8 +751,9 @@ alsamixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { 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; + if (snd_mixer_selem_has_playback_channel(elem, channel)) + self->pchannels++; + else break; } } } @@ -762,8 +763,9 @@ alsamixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { 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; + if (snd_mixer_selem_has_capture_channel(elem, channel)) + self->cchannels++; + else break; } } } @@ -784,7 +786,7 @@ static void alsamixer_dealloc(alsamixer_t *self) { static PyObject * alsamixer_cardname(alsamixer_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":cardname")) return NULL; return PyString_FromString(self->cardname); } @@ -796,7 +798,7 @@ Returns the name of the sound card used by this Mixer object."); static PyObject * alsamixer_mixer(alsamixer_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":mixer")) return NULL; return PyString_FromString(self->controlname); } @@ -809,7 +811,7 @@ for example 'Master' or 'PCM'"); static PyObject * alsamixer_mixerid(alsamixer_t *self, PyObject *args) { - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":mixerid")) return NULL; return PyInt_FromLong(self->controlid); } @@ -822,7 +824,7 @@ Returns the ID of the ALSA mixer controlled by this object."); static PyObject * alsamixer_volumecap(alsamixer_t *self, PyObject *args) { PyObject *result; - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":volumecap")) return NULL; result = PyList_New(0); if (self->volume_cap&MIXER_CAP_VOLUME) PyList_Append(result,PyString_FromString("Volume")); @@ -856,7 +858,7 @@ Possible values in this list are:\n\ static PyObject * alsamixer_switchcap(alsamixer_t *self, PyObject *args) { PyObject *result; - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":switchcap")) return NULL; result = PyList_New(0); if (self->volume_cap&MIXER_CAP_SWITCH) PyList_Append(result,PyString_FromString("Mute")); @@ -920,7 +922,7 @@ alsamixer_getvolume(alsamixer_t *self, PyObject *args) { char *dirstr = 0; PyObject *result; - if (!PyArg_ParseTuple(args,"|s",&dirstr)) return NULL; + if (!PyArg_ParseTuple(args,"|s:getvolume",&dirstr)) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); @@ -948,8 +950,8 @@ alsamixer_getvolume(alsamixer_t *self, PyObject *args) { && snd_mixer_selem_has_capture_volume(elem)) { snd_mixer_selem_get_capture_volume(elem, channel, &ival); PyList_Append( - result,PyInt_FromLong(alsamixer_getpercentage(self->cmin, - self->cmax, ival))); + result, PyInt_FromLong(alsamixer_getpercentage(self->cmin, + self->cmax, ival))); } } return result; @@ -972,9 +974,8 @@ alsamixer_getrange(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; int direction; char *dirstr = 0; - PyObject *result; - if (!PyArg_ParseTuple(args,"|s",&dirstr)) return NULL; + if (!PyArg_ParseTuple(args,"|s:getrange",&dirstr)) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); @@ -985,20 +986,31 @@ alsamixer_getrange(alsamixer_t *self, PyObject *args) { else if (strcasecmp(dirstr,"playback")==0) direction = 0; else if (strcasecmp(dirstr,"capture")==0) direction = 1; else { - PyErr_SetString(ALSAAudioError,"Invalid direction argument for direction"); + PyErr_SetString(ALSAAudioError,"Invalid argument for direction"); return NULL; } - result = PyList_New(0); - if (direction == 0 && snd_mixer_selem_has_playback_channel(elem, 0)) { - PyList_Append(result,PyInt_FromLong(self->pmin)); - PyList_Append(result,PyInt_FromLong(self->pmax)); + if (direction == 0) { + if (snd_mixer_selem_has_playback_channel(elem, 0)) { + return Py_BuildValue("[ii]", self->pmin, self->pmax); } - else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, 0) - && snd_mixer_selem_has_capture_volume(elem)) { - PyList_Append(result,PyInt_FromLong(self->cmin)); - PyList_Append(result,PyInt_FromLong(self->cmax)); + + PyErr_SetString(ALSAAudioError, "Mixer has no playback channel"); + return NULL; + } + else if (direction == 1) { + if (snd_mixer_selem_has_capture_channel(elem, 0) + && snd_mixer_selem_has_capture_volume(elem)) { + return Py_BuildValue("[ii]", self->cmin, self->cmax); } - return result; + + PyErr_SetString(ALSAAudioError, "Mixer has no capture channel " + "or capture volume"); + return NULL; + } + + // Unreached statement + PyErr_SetString(ALSAAudioError,"Huh?"); + return NULL; } PyDoc_STRVAR(getrange_doc, @@ -1015,40 +1027,73 @@ if the mixer has this capability, otherwise 'capture'"); static PyObject * alsamixer_getenum(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; + PyObject *elems; + int i, count, rc; unsigned int index; char name[32]; - int res; PyObject *result; - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args, ":getenum")) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_is_enumerated(elem)) { - PyErr_SetString(ALSAAudioError,"Mixer is no enumerated control"); - return NULL; - } + // Not an enumerated control, return an empty tuple + return PyTuple_New(0); + } - res=snd_mixer_selem_get_enum_item(elem, 0, &index); - if(res) { - PyErr_SetString(ALSAAudioError, snd_strerror(res)); + count = snd_mixer_selem_get_enum_items(elem); + if (count < 0) { + PyErr_SetString(ALSAAudioError, snd_strerror(count)); return NULL; } - res=snd_mixer_selem_get_enum_item_name(elem, index, sizeof(name)-1, name); - if(res) { - PyErr_SetString(ALSAAudioError, snd_strerror(res)); + + result = PyTuple_New(2); + if (!result) + return NULL; + + rc = snd_mixer_selem_get_enum_item(elem, 0, &index); + if(rc) { + PyErr_SetString(ALSAAudioError, snd_strerror(rc)); return NULL; - } else { - result = PyList_New(0); - PyList_Append(result,PyString_FromString(name)); } + rc = snd_mixer_selem_get_enum_item_name(elem, index, sizeof(name)-1, name); + if (rc) { + Py_DECREF(result); + PyErr_SetString(ALSAAudioError, snd_strerror(rc)); + return NULL; + } + + PyTuple_SetItem(result, 0, PyString_FromString(name)); + + elems = PyList_New(count); + if (!elems) + { + Py_DECREF(result); + return NULL; + } + + for (i = 0; i < count; ++i) { + rc = snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name); + if (rc) { + Py_DECREF(elems); + Py_DECREF(result); + PyErr_SetString(ALSAAudioError, snd_strerror(rc)); + return NULL; + } + + PyList_SetItem(elems, i, PyString_FromString(name)); + } + + PyTuple_SetItem(result, 1, elems); + return result; } PyDoc_STRVAR(getenum_doc, -"getenum([direction]) -> List of enumerated controls (string)\n\ +"getenum() -> Tuple of (string, list of strings)\n\ \n\ -Returns a list of strings with the enumerated controls."); - +Returns a a tuple. The first element is name of the active enumerated item, \n\ +the second a list available enumerated items."); static PyObject * alsamixer_getmute(alsamixer_t *self, PyObject *args) { @@ -1056,7 +1101,7 @@ alsamixer_getmute(alsamixer_t *self, PyObject *args) { int i; int ival; PyObject *result; - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":getmute")) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_has_playback_switch(elem)) { @@ -1088,7 +1133,7 @@ alsamixer_getrec(alsamixer_t *self, PyObject *args) { int i; int ival; PyObject *result; - if (!PyArg_ParseTuple(args,"")) return NULL; + if (!PyArg_ParseTuple(args,":getrec")) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_has_capture_switch(elem)) { @@ -1124,7 +1169,9 @@ alsamixer_setvolume(alsamixer_t *self, PyObject *args) { int channel = MIXER_CHANNEL_ALL; int done = 0; - if (!PyArg_ParseTuple(args,"l|is",&volume,&channel,&dirstr)) return NULL; + if (!PyArg_ParseTuple(args,"l|is:setvolume",&volume,&channel,&dirstr)) + return NULL; + if (volume < 0 || volume > 100) { PyErr_SetString(ALSAAudioError,"Volume must be between 0 and 100"); return NULL; @@ -1146,16 +1193,16 @@ alsamixer_setvolume(alsamixer_t *self, PyObject *args) { 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)) { - physvolume = alsamixer_getphysvolume(self->pmin,self->pmax,volume); - snd_mixer_selem_set_playback_volume(elem, i, physvolume); - done++; + physvolume = alsamixer_getphysvolume(self->pmin,self->pmax,volume); + snd_mixer_selem_set_playback_volume(elem, i, physvolume); + done++; } else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, channel) && snd_mixer_selem_has_capture_volume(elem)) { - physvolume = alsamixer_getphysvolume(self->cmin,self->cmax,volume); - snd_mixer_selem_set_capture_volume(elem, i, physvolume); - done++; + physvolume = alsamixer_getphysvolume(self->cmin,self->cmax,volume); + snd_mixer_selem_set_capture_volume(elem, i, physvolume); + done++; } } } @@ -1190,7 +1237,7 @@ alsamixer_setmute(alsamixer_t *self, PyObject *args) { int mute = 0; int done = 0; int channel = MIXER_CHANNEL_ALL; - if (!PyArg_ParseTuple(args,"i|i",&mute,&channel)) return NULL; + if (!PyArg_ParseTuple(args,"i|i:setmute",&mute,&channel)) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_has_playback_switch(elem)) { @@ -1200,8 +1247,8 @@ alsamixer_setmute(alsamixer_t *self, PyObject *args) { 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++; + snd_mixer_selem_set_playback_switch(elem, i, !mute); + done++; } } } @@ -1231,7 +1278,7 @@ alsamixer_setrec(alsamixer_t *self, PyObject *args) { int rec = 0; int done = 0; int channel = MIXER_CHANNEL_ALL; - if (!PyArg_ParseTuple(args,"i|i",&rec,&channel)) return NULL; + if (!PyArg_ParseTuple(args,"i|i:setrec",&rec,&channel)) return NULL; elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_has_capture_switch(elem)) { @@ -1369,39 +1416,52 @@ void initalsaaudio(void) { } - _EXPORT_INT(m,"PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK); - _EXPORT_INT(m,"PCM_CAPTURE",SND_PCM_STREAM_CAPTURE); + _EXPORT_INT(m, "PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK); + _EXPORT_INT(m, "PCM_CAPTURE",SND_PCM_STREAM_CAPTURE); - _EXPORT_INT(m,"PCM_NORMAL",0); - _EXPORT_INT(m,"PCM_NONBLOCK",SND_PCM_NONBLOCK); - _EXPORT_INT(m,"PCM_ASYNC",SND_PCM_ASYNC); + _EXPORT_INT(m, "PCM_NORMAL",0); + _EXPORT_INT(m, "PCM_NONBLOCK",SND_PCM_NONBLOCK); + _EXPORT_INT(m, "PCM_ASYNC",SND_PCM_ASYNC); /* PCM Formats */ - _EXPORT_INT(m,"PCM_FORMAT_S8",SND_PCM_FORMAT_S8); - _EXPORT_INT(m,"PCM_FORMAT_U8",SND_PCM_FORMAT_U8); - _EXPORT_INT(m,"PCM_FORMAT_S16_LE",SND_PCM_FORMAT_S16_LE); - _EXPORT_INT(m,"PCM_FORMAT_S16_BE",SND_PCM_FORMAT_S16_BE); - _EXPORT_INT(m,"PCM_FORMAT_U16_LE",SND_PCM_FORMAT_U16_LE); - _EXPORT_INT(m,"PCM_FORMAT_U16_BE",SND_PCM_FORMAT_U16_BE); - _EXPORT_INT(m,"PCM_FORMAT_S24_LE",SND_PCM_FORMAT_S24_LE); - _EXPORT_INT(m,"PCM_FORMAT_S24_BE",SND_PCM_FORMAT_S24_BE); - _EXPORT_INT(m,"PCM_FORMAT_U24_LE",SND_PCM_FORMAT_U24_LE); - _EXPORT_INT(m,"PCM_FORMAT_U24_BE",SND_PCM_FORMAT_U24_BE); - _EXPORT_INT(m,"PCM_FORMAT_S32_LE",SND_PCM_FORMAT_S32_LE); - _EXPORT_INT(m,"PCM_FORMAT_S32_BE",SND_PCM_FORMAT_S32_BE); - _EXPORT_INT(m,"PCM_FORMAT_U32_LE",SND_PCM_FORMAT_U32_LE); - _EXPORT_INT(m,"PCM_FORMAT_U32_BE",SND_PCM_FORMAT_U32_BE); - _EXPORT_INT(m,"PCM_FORMAT_FLOAT_LE",SND_PCM_FORMAT_FLOAT_LE); - _EXPORT_INT(m,"PCM_FORMAT_FLOAT_BE",SND_PCM_FORMAT_FLOAT_BE); - _EXPORT_INT(m,"PCM_FORMAT_FLOAT64_LE",SND_PCM_FORMAT_FLOAT64_LE); - _EXPORT_INT(m,"PCM_FORMAT_FLOAT64_BE",SND_PCM_FORMAT_FLOAT64_BE); - _EXPORT_INT(m,"PCM_FORMAT_MU_LAW",SND_PCM_FORMAT_MU_LAW); - _EXPORT_INT(m,"PCM_FORMAT_A_LAW",SND_PCM_FORMAT_A_LAW); - _EXPORT_INT(m,"PCM_FORMAT_IMA_ADPCM",SND_PCM_FORMAT_IMA_ADPCM); - _EXPORT_INT(m,"PCM_FORMAT_MPEG",SND_PCM_FORMAT_MPEG); - _EXPORT_INT(m,"PCM_FORMAT_GSM",SND_PCM_FORMAT_GSM); + _EXPORT_INT(m, "PCM_FORMAT_S8",SND_PCM_FORMAT_S8); + _EXPORT_INT(m, "PCM_FORMAT_U8",SND_PCM_FORMAT_U8); + _EXPORT_INT(m, "PCM_FORMAT_S16_LE",SND_PCM_FORMAT_S16_LE); + _EXPORT_INT(m, "PCM_FORMAT_S16_BE",SND_PCM_FORMAT_S16_BE); + _EXPORT_INT(m, "PCM_FORMAT_U16_LE",SND_PCM_FORMAT_U16_LE); + _EXPORT_INT(m, "PCM_FORMAT_U16_BE",SND_PCM_FORMAT_U16_BE); + _EXPORT_INT(m, "PCM_FORMAT_S24_LE",SND_PCM_FORMAT_S24_LE); + _EXPORT_INT(m, "PCM_FORMAT_S24_BE",SND_PCM_FORMAT_S24_BE); + _EXPORT_INT(m, "PCM_FORMAT_U24_LE",SND_PCM_FORMAT_U24_LE); + _EXPORT_INT(m, "PCM_FORMAT_U24_BE",SND_PCM_FORMAT_U24_BE); + _EXPORT_INT(m, "PCM_FORMAT_S32_LE",SND_PCM_FORMAT_S32_LE); + _EXPORT_INT(m, "PCM_FORMAT_S32_BE",SND_PCM_FORMAT_S32_BE); + _EXPORT_INT(m, "PCM_FORMAT_U32_LE",SND_PCM_FORMAT_U32_LE); + _EXPORT_INT(m, "PCM_FORMAT_U32_BE",SND_PCM_FORMAT_U32_BE); + _EXPORT_INT(m, "PCM_FORMAT_FLOAT_LE",SND_PCM_FORMAT_FLOAT_LE); + _EXPORT_INT(m, "PCM_FORMAT_FLOAT_BE",SND_PCM_FORMAT_FLOAT_BE); + _EXPORT_INT(m, "PCM_FORMAT_FLOAT64_LE",SND_PCM_FORMAT_FLOAT64_LE); + _EXPORT_INT(m, "PCM_FORMAT_FLOAT64_BE",SND_PCM_FORMAT_FLOAT64_BE); + _EXPORT_INT(m, "PCM_FORMAT_MU_LAW",SND_PCM_FORMAT_MU_LAW); + _EXPORT_INT(m, "PCM_FORMAT_A_LAW",SND_PCM_FORMAT_A_LAW); + _EXPORT_INT(m, "PCM_FORMAT_IMA_ADPCM",SND_PCM_FORMAT_IMA_ADPCM); + _EXPORT_INT(m, "PCM_FORMAT_MPEG",SND_PCM_FORMAT_MPEG); + _EXPORT_INT(m, "PCM_FORMAT_GSM",SND_PCM_FORMAT_GSM); /* Mixer stuff */ - _EXPORT_INT(m,"MIXER_CHANNEL_ALL",MIXER_CHANNEL_ALL); + _EXPORT_INT(m, "MIXER_CHANNEL_ALL", MIXER_CHANNEL_ALL); +#if 0 // Omit for now - use case unknown + _EXPORT_INT(m, "MIXER_SCHN_UNKNOWN", SND_MIXER_SCHN_UNKNOWN); + _EXPORT_INT(m, "MIXER_SCHN_FRONT_LEFT", SND_MIXER_SCHN_FRONT_LEFT); + _EXPORT_INT(m, "MIXER_SCHN_FRONT_RIGHT", SND_MIXER_SCHN_FRONT_RIGHT); + _EXPORT_INT(m, "MIXER_SCHN_REAR_LEFT", SND_MIXER_SCHN_REAR_LEFT); + _EXPORT_INT(m, "MIXER_SCHN_REAR_RIGHT", SND_MIXER_SCHN_REAR_RIGHT); + _EXPORT_INT(m, "MIXER_SCHN_FRONT_CENTER", SND_MIXER_SCHN_FRONT_CENTER); + _EXPORT_INT(m, "MIXER_SCHN_WOOFER", SND_MIXER_SCHN_WOOFER); + _EXPORT_INT(m, "MIXER_SCHN_SIDE_LEFT", SND_MIXER_SCHN_SIDE_LEFT); + _EXPORT_INT(m, "MIXER_SCHN_SIDE_RIGHT", SND_MIXER_SCHN_SIDE_RIGHT); + _EXPORT_INT(m, "MIXER_SCHN_REAR_CENTER", SND_MIXER_SCHN_REAR_CENTER); + _EXPORT_INT(m, "MIXER_SCHN_MONO", SND_MIXER_SCHN_MONO); +#endif } diff --git a/doc/about.html b/doc/about.html index 494951a..cd7bf76 100644 --- a/doc/about.html +++ b/doc/about.html @@ -103,7 +103,7 @@ About this document ...
-Release 0.3. +Release 0.4. diff --git a/doc/contents.html b/doc/contents.html index 389b3c5..5852aa3 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -99,7 +99,7 @@ Contents
-Release 0.3. +Release 0.4. diff --git a/doc/front.html b/doc/front.html index c8e6f47..4941ef5 100644 --- a/doc/front.html +++ b/doc/front.html @@ -65,15 +65,16 @@ whatsoever.

Abstract:

-This package contains wrappers for accessing the ALSA API from Python. It -is currently fairly complete for PCM devices and Mixer access. MIDI sequencer -support is low on my priority list, but volunteers are welcome. +This package contains wrappers for accessing the ALSA API from Python. +It is currently fairly complete for PCM devices and Mixer access. MIDI +sequencer support is low on my priority list, but volunteers are +welcome.

-If you find bugs in the wrappers please use the SourceForge bug tracker. Please -don't send bug reports regarding ALSA specifically. There are several -bugs in this API, and those should be reported to the ALSA team - not -me. +If you find bugs in the wrappers please use the SourceForge bug +tracker. Please don't send bug reports regarding ALSA specifically. +There are several bugs in this API, and those should be reported to +the ALSA team - not me.

@@ -112,7 +113,7 @@ me.


-Release 0.3. +Release 0.4. diff --git a/doc/index.html b/doc/index.html index 947dcb8..7a4dcea 100644 --- a/doc/index.html +++ b/doc/index.html @@ -44,6 +44,7 @@

PyAlsaAudio

Casper Wilstrup

+

cwi@aves.dk

@@ -109,7 +110,7 @@
-Release 0.3. +Release 0.4. diff --git a/doc/mixer-objects.html b/doc/mixer-objects.html index 6f3c144..3da7473 100644 --- a/doc/mixer-objects.html +++ b/doc/mixer-objects.html @@ -60,19 +60,23 @@ Mixer objects provides access to the ALSA mixer API.

- -
class Mixer([control], [id], [cardname])
+ class Mixer( + [control], [id], + [cardname])
-control - specifies which control to manipulate using this mixer object. The list -of available controls can be found with the alsaaudio.mixers function. -The default value is 'Master' - other common controls include 'Master Mono', 'PCM', 'Line', etc. + control - specifies which control to manipulate using this + mixer object. The list of available controls can be found with the + alsaaudio.mixers function. The default value is + 'Master' - other common controls include 'Master Mono', 'PCM', + 'Line', etc.

id - the id of the mixer control. Default is 0

-cardname - specifies which card should be used (this is only relevant -if you have more than one sound card). Omit to use the default sound card +cardname - specifies which card should be used (this is only + relevant if you have more than one sound card). Omit to use the + default sound card

@@ -80,36 +84,36 @@ Mixer objects have the following methods:

- +
cardname(cardname( )
-Return the name of the sound card used by this Mixer object + Return the name of the sound card used by this Mixer object

- +
mixer(mixer( )
-Return the name of the specific mixer controlled by this object, For example 'Master' -or 'PCM' + Return the name of the specific mixer controlled by this object, For + example 'Master' or 'PCM'

- +
mixerid(mixerid( )
-Return the ID of the ALSA mixer controlled by this object. + Return the ID of the ALSA mixer controlled by this object.

- +
switchcap(switchcap( )
-Returns a list of the switches which are defined by this specific mixer. Possible values in -this list are: + Returns a list of the switches which are defined by this specific + mixer. Possible values in this list are:

@@ -137,16 +141,17 @@ this list are:

-To manipulate these swithes use the setrec or setmute methods +To manipulate these swithes use the setrec or +setmute methods

- +
volumecap(volumecap( )
-Returns a list of the volume control capabilities of this mixer. Possible values in -the list are: + Returns a list of the volume control capabilities of this mixer. + Possible values in the list are:

@@ -160,15 +165,18 @@ the list are: - + - + - +
'Volume' This mixer can control volume
'Joined Volume'This mixer can control volume for all channels at the same time
This mixer can control volume for all channels at + the same time
'Playback Volume' This mixer can manipulate the playback volume
'Joined Playback Volume'Manipulate playback volumne for all channels at the same time
Manipulate playback volumne for all + channels at the same time
'Capture Volume' Manipulate sound capture volume
'Joined Capture Volume'Manipulate sound capture volume for all channels at a time
Manipulate sound capture volume for all + channels at a time

@@ -176,34 +184,40 @@ the list are:

- -
getrange([direction])
+ getenum( + )
-Return the volume range of the ALSA mixer controlled by this object. + For enumerated controls, return the currently selected item and + the list of items available.

-The optional direction argument can be either 'playback' or 'capture', -which is relevant if the mixer can control both playback and capture volume. -The default value is 'playback' if the mixer has this capability, otherwise -'capture' +Returns a tuple (string, list of strings).

-

+For example, my soundcard has a Mixer called Mono Output Select. + Using amixer, I get:

-

- -
getvolume([direction])
-
-Returns a list with the current volume settings for each channel. The list elements -are integer percentages. +
+$ amixer get "Mono Output Select"
+Simple mixer control 'Mono Output Select',0
+  Capabilities: enum
+  Items: 'Mix' 'Mic'
+  Item0: 'Mix'
+

-The optional direction argument can be either 'playback' or 'capture', which is relevant -if the mixer can control both playback and capture volume. The default value is 'playback' -if the mixer has this capability, otherwise 'capture' +Using alsaaudio, one could do: +

+>>> import alsaaudio
+>>> m = alsaaudio.Mixer('Mono Output Select')
+>>> m.getenum()
+('Mix', ['Mix', 'Mic'])
+

+This method will return an empty tuple if the mixer is not an + enumerated control.

@@ -211,52 +225,95 @@ if the mixer has this capability, otherwise 'capture' getmute( )

-Return a list indicating the current mute setting for each channel. 0 means not muted, 1 means muted. + Return a list indicating the current mute setting for each channel. + 0 means not muted, 1 means muted.

-This method will fail if the mixer has no playback switch capabilities. +This method will fail if the mixer has no playback switch + capabilities.

- + +
getrec(getrange([direction])
+
+ Return the volume range of the ALSA mixer controlled by this object. + +

+The optional direction argument can be either 'playback' or + 'capture', which is relevant if the mixer can control both playback + and capture volume. The default value is 'playback' if the mixer + has this capability, otherwise 'capture' + +

+

+ +

+

+
getrec( )
-Return a list indicating the current record mute setting for each channel. 0 means not recording, 1 -means not recording. + Return a list indicating the current record mute setting for each + channel. 0 means not recording, 1 means recording.

-This method will fail if the mixer has no capture switch capabilities. +This method will fail if the mixer has no capture switch + capabilities.

- -
setvolume(volume,[channel],[direction])
+ getvolume( + [direction])
-Change the current volume settings for this mixer. The volume argument controls -the new volume setting as an integer percentage. + Returns a list with the current volume settings for each channel. + The list elements are integer percentages.

-If the optional argument channel is present, the volume is set only for this channel. This -assumes that the mixer can control the volume for the channels independently. +The optional direction argument can be either 'playback' or + 'capture', which is relevant if the mixer can control both playback + and capture volume. The default value is 'playback' if the mixer has + this capability, otherwise 'capture'

-The optional direction argument can be either 'playback' or 'capture' is relevant if the mixer -has independent playback and capture volume capabilities, and controls which of the volumes -if changed. The default is 'playback' if the mixer has this capability, otherwise 'capture'.

- + +
setmute(setvolume(volume,[channel], + [direction])
+
+ +

+Change the current volume settings for this mixer. The volume + argument controls the new volume setting as an integer percentage. + +

+If the optional argument channel is present, the volume is set + only for this channel. This assumes that the mixer can control the + volume for the channels independently. + +

+The optional direction argument can be either 'playback' or + 'capture' is relevant if the mixer has independent playback and + capture volume capabilities, and controls which of the volumes if + changed. The default is 'playback' if the mixer has this capability, + otherwise 'capture'. +

+ +

+

+
setmute( mute, [channel])
-Sets the mute flag to a new value. The mute argument is either 0 for not muted, or 1 for muted. + Sets the mute flag to a new value. The mute argument is either + 0 for not muted, or 1 for muted.

-The optional channel argument controls which channel is muted. The default is to set the mute flag -for all channels. +The optional channel argument controls which channel is muted. + The default is to set the mute flag for all channels.

This method will fail if the mixer has no playback mute capabilities @@ -264,42 +321,48 @@ This method will fail if the mixer has no playback mute capabilities

- +
setrec(setrec( capture,[channel])
-Sets the capture mute flag to a new value. The capture argument is either 0 for no capture, -or 1 for capture. + Sets the capture mute flag to a new value. The capture + argument is either 0 for no capture, or 1 for capture.

-The optional channel argument controls which channel is changed. The default is to set the capture flag -for all channels. +The optional channel argument controls which channel is + changed. The default is to set the capture flag for all channels.

-This method will fail if the mixer has no capture switch capabilities +This method will fail if the mixer has no capture switch + capabilities.

A Note on the ALSA Mixer API

-The ALSA mixer API is extremely complicated - and hardly documented at all. alsaaudio implements -a much simplified way to access this API. In designing the API I've had to make some choices which -may limit what can and cannot be controlled through the API. However, If I had chosen to implement the -full API, I would have reexposed the horrible complexity/documentation ratio of the underlying API. -At least the alsaaudio API is easy to understand and use. +The ALSA mixer API is extremely complicated - and hardly documented at +all. alsaaudio implements a much simplified way to access +this API. In designing the API I've had to make some choices which may +limit what can and cannot be controlled through the API. However, If I +had chosen to implement the full API, I would have reexposed the +horrible complexity/documentation ratio of the underlying API. At +least the alsaaudio API is easy to understand and use.

-If my design choises prevents you from doing something that the underlying API would have allowed, -please let me know, so I can incorporate these need into future versions. +If my design choises prevents you from doing something that the +underlying API would have allowed, please let me know, so I can +incorporate these need into future versions.

-If the current state of affairs annoy you, the best you can do is to write a HOWTO on the API and -make this available on the net. Until somebody does this, the availability of ALSA mixer capable -devices will stay quite limited. +If the current state of affairs annoy you, the best you can do is to +write a HOWTO on the API and make this available on the net. Until +somebody does this, the availability of ALSA mixer capable devices +will stay quite limited.

-Unfortunately, I'm not able to create such a HOWTO myself, since I only understand half of the API, -and that which I do understand has come from a painful trial and error process. +Unfortunately, I'm not able to create such a HOWTO myself, since I +only understand half of the API, and that which I do understand has +come from a painful trial and error process.

@@ -336,7 +399,7 @@ and that which I do understand has come from a painful trial and error process.


-Release 0.3. +Release 0.4. diff --git a/doc/module-alsaaudio.html b/doc/module-alsaaudio.html index 849d2e6..e96d838 100644 --- a/doc/module-alsaaudio.html +++ b/doc/module-alsaaudio.html @@ -60,8 +60,7 @@ class="platform">Linux.

-tex2html_comment_mark>15 - +

@@ -83,12 +82,14 @@ sound card). Omit to use the default sound card. class PCM( [type], [mode], [cardname])

-This class is used to represent a PCM device (both playback and capture devices). -The arguments are: -
type - can be either PCM_CAPTURE or PCM_PLAYBACK (default). -
mode - can be either PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL (the default). -
cardname - specifies which card should be used (this is only relevant -if you have more than one sound card). Omit to use the default sound card + This class is used to represent a PCM device (both playback and + capture devices). + The arguments are: +
type - can be either PCM_CAPTURE or PCM_PLAYBACK (default). +
mode - can be either PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL (the default). +
cardname - specifies which card should be used (this is only + relevant if you have more than one sound card). Omit to use the + default sound card

@@ -99,7 +100,7 @@ if you have more than one sound card). Omit to use the default sound card This class is used to access a specific ALSA mixer. The arguments are:
control - Name of the chosen mixed (default is Master). -
id - id of mixer (default is 0) - More explaniation needed here +
id - id of mixer (default is 0) - More explanation needed here
cardname specifies which card should be used (this is only relevant if you have more than one sound card). Omit to use the default sound card @@ -107,9 +108,9 @@ if you have more than one sound card). Omit to use the default sound card

exception ALSAAudioError
-Exception raised when an operation fails for a ALSA specific reason. -The exception argument is a string describing the reason of the -failure. + Exception raised when an operation fails for a ALSA specific reason. + The exception argument is a string describing the reason of the + failure.

@@ -161,7 +162,7 @@ failure.


-Release 0.3. +Release 0.4. diff --git a/doc/node3.html b/doc/node3.html index dbe208d..22c3c01 100644 --- a/doc/node3.html +++ b/doc/node3.html @@ -55,7 +55,7 @@

The Advanced Linux Sound Architecture (ALSA) provides audio and MIDI -functionality to the Linux operating system. +functionality to the Linux operating system.

Logically ALSA consists of these components: @@ -113,7 +113,7 @@ More information about ALSA may be found on the project homepage


-Release 0.3. +Release 0.4. diff --git a/doc/node4.html b/doc/node4.html index 05473ca..178e031 100644 --- a/doc/node4.html +++ b/doc/node4.html @@ -54,27 +54,29 @@

-The older Linux sound API (OSS) which is now deprecated is well supported -from the standard Python library, through the ossaudiodev module. No native -ALSA support exists in the standard library (yet). +The older Linux sound API (OSS) which is now deprecated is well +supported from the standard Python library, through the ossaudiodev +module. No native ALSA support exists in the standard library (yet).

-There are a few other ``ALSA for Python'' projects available, including at -least two different projects called pyAlsa. Neither of these seem to be under -active development at the time - and neither are very feature complete. +There are a few other ``ALSA for Python'' projects available, +including at least two different projects called pyAlsa. Neither of +these seem to be under active development at the time - and neither +are very feature complete.

-I wrote PyAlsaAudio to fill this gap. My long term goal is to have the module -included in the standard Python library, but that is probably a while of yet. +I wrote PyAlsaAudio to fill this gap. My long term goal is to have the +module included in the standard Python library, but that is probably a +while off yet.

-PyAlsaAudio hass full support for sound capture, playback of sound, as well as -the ALSA Mixer API. +PyAlsaAudio hass full support for sound capture, playback of sound, as +well as the ALSA Mixer API.

-MIDI support is not available, and since I don't own any MIDI hardware, it's -difficult for me to implement it. Volunteers to work on this would be greatly -appreciated +MIDI support is not available, and since I don't own any MIDI +hardware, it's difficult for me to implement it. Volunteers to work on +this would be greatly appreciated


-Release 0.3. +Release 0.4. diff --git a/doc/node5.html b/doc/node5.html index 1bd779c..49507bb 100644 --- a/doc/node5.html +++ b/doc/node5.html @@ -55,11 +55,18 @@

Note: the wrappers link with the alsasound library (from the alsa-lib -package). Verify that this is installed by looking for /usr/lib/libasound.so -before building. Naturally you also need to use a kernel with proper ALSA -support. This is the default in Linux kernel 2.6 and later. If you are using -kernel version 2.4 you may need to install the ALSA patches yourself - although -most distributions ship with ALSA kernels. +package) and need the ALSA headers for compilation. Verify that you +have /usr/lib/libasound.so and /usr/include/alsa (or +similar paths) before building. + +

+On Debian (and probably Ubuntu), make sure you have libasound2-dev installed. + +

+Naturally you also need to use a kernel with proper ALSA support. This +is the default in Linux kernel 2.6 and later. If you are using kernel +version 2.4 you may need to install the ALSA patches yourself - +although most distributions ship with ALSA kernels.

To install, execute the following: @@ -108,7 +115,7 @@ And then as root:


-Release 0.3. +Release 0.4. diff --git a/doc/node7.html b/doc/node7.html index 2ce84d6..0dc008a 100644 --- a/doc/node7.html +++ b/doc/node7.html @@ -60,72 +60,86 @@ terminology.

Sample
-
PCM audio, whether it is input or output, consists at the lowest level -of a number of single samples. A sample represents the sound in a single channel in -a brief interval. If more than one channel is in use, more than one sample is required -for each interval to describe the sound. Samples can be of many different sizes, ranging -from 8 bit to 64 bit presition. The specific format of each sample can also vary - they -can be big endian byte order, little endian byte order, or even floats. +
PCM audio, whether it is input or output, consists at + the lowest level of a number of single samples. A sample represents + the sound in a single channel in a brief interval. If more than one + channel is in use, more than one sample is required for each + interval to describe the sound. Samples can be of many different + sizes, ranging from 8 bit to 64 bit presition. The specific format + of each sample can also vary - they can be big endian byte order, + little endian byte order, or even floats.

Frame
-
A frame consists of exactly one sample per channel. If there is only one -channel (Mono sound) a frame is simply a single sample. If the sound is stereo, each frame -consists of two samples, etc. +
A frame consists of exactly one sample per channel. If + there is only one channel (Mono sound) a frame is simply a single + sample. If the sound is stereo, each frame consists of two samples, + etc.

Frame size
-
This is the size in bytes of each frame. This can vary a lot: if each sample is -8 bits, and we're handling mono sound, the frame size is one byte. Similarly in 6 channel audio with -64 bit floating point samples, the frame size is 48 bytes +
This is the size in bytes of each frame. This can + vary a lot: if each sample is 8 bits, and we're handling mono sound, + the frame size is one byte. Similarly in 6 channel audio with 64 bit + floating point samples, the frame size is 48 bytes

Rate
-
PCM sound consists of a flow of sound frames. The sound rate controls how often -the current frame is replaced. For example, a rate of 8000 Hz means that a new frame is played -or captured 8000 times per second. +
PCM sound consists of a flow of sound frames. The sound + rate controls how often the current frame is replaced. For example, + a rate of 8000 Hz means that a new frame is played or captured 8000 + times per second.

Data rate
-
This is the number of bytes, which must be recorded or provided per second -at a certain frame size and rate. +
This is the number of bytes, which must be recorded + or provided per second at a certain frame size and rate.

-8000 Hz mono sound with 8 bit (1 byte) samples has a data rate of 8000 * 1 * 1 = 8 kb/s +8000 Hz mono sound with 8 bit (1 byte) samples has a data rate of + 8000 * 1 * 1 = 8 kb/s

-At the other end of the scale, 96000 Hz, 6 channel sound with 64 bit (8 bytes) samples -has a data rate of 96000 * 6 * 8 = 4608 kb/s (almost 5 Mb sound data per second) +At the other end of the scale, 96000 Hz, 6 channel sound with 64 bit + (8 bytes) samples has a data rate of 96000 * 6 * 8 = 4608 kb/s + (almost 5 Mb sound data per second)

Period
-
When the hardware processes data this is done in chunks of frames. The time interval -between each processing (A/D or D/A conversion) is known as the period. The size of the period has -direct implication on the latency of the sound input or output. For low-latency the period size should -be very small, while low CPU resource usage would usually demand larger period sizes. With ALSA, the -CPU utilization is not impacted much by the period size, since the kernel layer buffers multiple -periods internally, so each period generates an interrupt and a memory copy, but userspace can be -slower and read or write multiple periods at the same time. +
When the hardware processes data this is done in chunks + of frames. The time interval between each processing (A/D or D/A + conversion) is known as the period. The size of the period has + direct implication on the latency of the sound input or output. For + low-latency the period size should be very small, while low CPU + resource usage would usually demand larger period sizes. With ALSA, + the CPU utilization is not impacted much by the period size, since + the kernel layer buffers multiple periods internally, so each period + generates an interrupt and a memory copy, but userspace can be + slower and read or write multiple periods at the same time.

Period size
-
This is the size of each period in Hz. Not bytes, but Hz!. In alsaaudio -the period size is set directly, and it is therefore important to understand the significance of this -number. If the period size is configured to for example 32, each write should contain exactly 32 frames -of sound data, and each read will return either 32 frames of data or nothing at all. +
This is the size of each period in Hz. Not + bytes, but Hz!. In alsaaudio the period size is set + directly, and it is therefore important to understand the + significance of this number. If the period size is configured to for + example 32, each write should contain exactly 32 frames of sound + data, and each read will return either 32 frames of data or nothing + at all.

-Once you understand these concepts, you will be ready to actually utilize PCM API. Read on. +Once you understand these concepts, you will be ready to use the PCM +API. Read on.

@@ -162,7 +176,7 @@ Once you understand these concepts, you will be ready to actually utilize PCM AP


-Release 0.3. +Release 0.4. diff --git a/doc/pcm-example.html b/doc/pcm-example.html index a16d62e..917f370 100644 --- a/doc/pcm-example.html +++ b/doc/pcm-example.html @@ -54,8 +54,9 @@

-For now, the only examples available are the 'playbacktest.py' and the 'recordtest.py' programs included. -This will change in a future version. +For now, the only examples available are the 'playbacktest.py' and the +'recordtest.py' programs included. This will change in a future +version.

@@ -92,7 +93,7 @@ This will change in a future version.


-Release 0.3. +Release 0.4. diff --git a/doc/pcm-objects.html b/doc/pcm-objects.html index 65737a1..bd53687 100644 --- a/doc/pcm-objects.html +++ b/doc/pcm-objects.html @@ -56,13 +56,15 @@

-The acronym PCM is short for Pulse Code Modulation and is the method used in ALSA -and many other places to handle playback and capture of sampled sound data. +The acronym PCM is short for Pulse Code Modulation and is the method +used in ALSA and many other places to handle playback and capture of +sampled sound data.

-PCM objects in alsaaudio are used to do exactly that, either play sample based -sound or capture sound from some input source (perhaps a microphone). The PCM object -constructor takes the following arguments: +PCM objects in alsaaudio are used to do exactly that, either +play sample based sound or capture sound from some input source +(probably a microphone). The PCM object constructor takes the following +arguments:

@@ -74,18 +76,21 @@ constructor takes the following arguments: type - can be either PCM_CAPTURE or PCM_PLAYBACK (default).

-mode - can be either PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL (the default). -In PCM_NONBLOCK mode, calls to read will return immediately independent of wether -there is any actual data to read. Similarly, write calls will return immediately -without actually writing anything to the playout buffer if the buffer is full. +mode - can be either PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL (the +default). In PCM_NONBLOCK mode, calls to read will return immediately +independent of wether there is any actual data to read. Similarly, +write calls will return immediately without actually writing anything +to the playout buffer if the buffer is full.

-In the current version of alsaaudio PCM_ASYNC is useless, since it relies -on a callback procedure, which can't be specified from Python. +In the current version of alsaaudio PCM_ASYNC is useless, +since it relies on a callback procedure, which can't be specified through +this API yet.

-cardname - specifies which card should be used (this is only relevant -if you have more than one sound card). Omit to use the default sound card +cardname - specifies which card should be used (this is only +relevant if you have more than one sound card). Omit to use the +default sound card

This will construct a PCM object with default settings: @@ -108,7 +113,7 @@ PCM objects have the following methods:

pcmtype( )
-Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK. + Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK.

@@ -116,7 +121,8 @@ Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK. pcmmode( )

-Return the mode of the PCM object. One of PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL + Return the mode of the PCM object. One of PCM_NONBLOCK, PCM_ASYNC, + or PCM_NORMAL

@@ -124,7 +130,7 @@ Return the mode of the PCM object. One of PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL cardname( )

-Return the name of the sound card used by this PCM object. + Return the name of the sound card used by this PCM object.

@@ -132,8 +138,9 @@ Return the name of the sound card used by this PCM object. setchannels( nchannels)

-Used to set the number of capture or playback channels. Common values are: 1 = mono, 2 = stereo, -and 6 = full 6 channel audio. Few sound cards support more than 2 channels + Used to set the number of capture or playback channels. Common + values are: 1 = mono, 2 = stereo, and 6 = full 6 channel audio. Few + sound cards support more than 2 channels

@@ -141,17 +148,18 @@ and 6 = full 6 channel audio. Few sound cards support more than 2 channels setrate( rate)

-Set the sample rate in Hz for the device. Typical values are 8000 (poor sound), 16000, 44100 (cd quality), -and 96000 + Set the sample rate in Hz for the device. Typical values are 8000 + (poor sound), 16000, 44100 (cd quality), and 96000

-
setformat()
+ format)
-The sound format of the device. Sound format controls how the PCM device interpret data for playback, -and how data is encoded in captures. + The sound format of the device. Sound format controls how the PCM + device interpret data for playback, and how data is encoded in + captures.

The following formats are provided by ALSA: @@ -168,47 +176,66 @@ The following formats are provided by ALSA: PCM_FORMAT_U8 Signed 8 bit samples for each channel PCM_FORMAT_S16_LE - Signed 16 bit samples for each channel (Little Endian byte order) + Signed 16 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_S16_BE - Signed 16 bit samples for each channel (Big Endian byte order) + Signed 16 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_U16_LE - Unsigned 16 bit samples for each channel (Little Endian byte order) + Unsigned 16 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_U16_BE - Unsigned 16 bit samples for each channel (Big Endian byte order) + Unsigned 16 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_S24_LE - Signed 24 bit samples for each channel (Little Endian byte order) + Signed 24 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_S24_BE - Signed 24 bit samples for each channel (Big Endian byte order) + Signed 24 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_U24_LE - Unsigned 24 bit samples for each channel (Little Endian byte order) + Unsigned 24 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_U24_BE - Unsigned 24 bit samples for each channel (Big Endian byte order) + Unsigned 24 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_S32_LE - Signed 32 bit samples for each channel (Little Endian byte order) + Signed 32 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_S32_BE - Signed 32 bit samples for each channel (Big Endian byte order) + Signed 32 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_U32_LE - Unsigned 32 bit samples for each channel (Little Endian byte order) + Unsigned 32 bit samples for each channel + (Little Endian byte order) PCM_FORMAT_U32_BE - Unsigned 32 bit samples for each channel (Big Endian byte order) + Unsigned 32 + bit samples for each channel (Big Endian byte order) PCM_FORMAT_FLOAT_LE - 32 bit samples encoded as float. (Little Endian byte order) + 32 bit samples encoded as float. + (Little Endian byte order) PCM_FORMAT_FLOAT_BE - 32 bit samples encoded as float (Big Endian byte order) + 32 bit + samples encoded as float (Big Endian byte order) PCM_FORMAT_FLOAT64_LE - 64 bit samples encoded as float. (Little Endian byte order) + 64 bit samples encoded as float. + (Little Endian byte order) PCM_FORMAT_FLOAT64_BE - 64 bit samples encoded as float. (Big Endian byte order) + 64 bit + samples encoded as float. (Big Endian byte order) PCM_FORMAT_MU_LAW - A logarithmic encoding (used by Sun .au files) + A logarithmic encoding (used by Sun .au + files) PCM_FORMAT_A_LAW Another logarithmic encoding PCM_FORMAT_IMA_ADPCM - a 4:1 compressed format defined by the Interactive Multimedia Association + a 4:1 compressed format defined by the + Interactive Multimedia Association PCM_FORMAT_MPEG - MPEG encoded audio? + MPEG + encoded audio? PCM_FORMAT_GSM - 9600 constant rate encoding well suitet for speech + 9600 bits/s constant rate encoding for speech

@@ -219,9 +246,10 @@ The following formats are provided by ALSA: setperiodsize( period)

-Sets the actual period size in frames. Each write should consist of exactly this number of frames, and -each read will return this number of frames (unless the device is in PCM_NONBLOCK mode, in which case -it may return nothing at all) + Sets the actual period size in frames. Each write should consist of + exactly this number of frames, and each read will return this number + of frames (unless the device is in PCM_NONBLOCK mode, in which case + it may return nothing at all)

@@ -229,14 +257,16 @@ it may return nothing at all) read( )

-In PCM_NORMAL mode, this function blocks until a full period is available, and then returns a -tuple (length,data) where length is the size in bytes of the captured data, and data -is the captured sound frames as a string. The length of the returned data will be periodsize*framesize -bytes. + In PCM_NORMAL mode, this function blocks until a full period is + available, and then returns a tuple (length,data) where + length is the number of frames of captured data, and + data is the captured sound frames as a string. The length of + the returned data will be periodsize*framesize bytes.

-In PCM_NONBLOCK mode, the call will not block, but will return (0,'') if no new period -has become available since the last call to read. +In PCM_NONBLOCK mode, the call will not block, but will return + (0,'') if no new period has become available since the last + call to read.

@@ -244,50 +274,67 @@ has become available since the last call to read. write( data)

-Writes (plays) the sound in data. The length of data must be a multiple of the frame size, and -should be exactly the size of a period. If less than 'period size' frames are provided, the actual -playout will not happen until more data is written. + Writes (plays) the sound in data. The length of data must be + a multiple of the frame size, and should be exactly the size + of a period. If less than 'period size' frames are provided, the + actual playout will not happen until more data is written.

-If the device is not in PCM_NONBLOCK mode, this call will block if the kernel buffer is full, and -until enough sound has been played to allow the sound data to be buffered. The call always returns -the size of the data provided +If the device is not in PCM_NONBLOCK mode, this call will block if + the kernel buffer is full, and until enough sound has been played to + allow the sound data to be buffered. The call always returns the + size of the data provided

-In PCM_NONBLOCK mode, the call will return immediately, with a return value of zero, if the buffer is -full. In this case, the data should be written at a later time. +In PCM_NONBLOCK mode, the call will return immediately, with a + return value of zero, if the buffer is full. In this case, the data + should be written at a later time. +

+

+ +
pause([enable=1])
+
+ If enable is 1, playback or capture is paused. If enable is 0, + playback/capture is resumed.

A few hints on using PCM devices for playback

-The most common reason for problems with playback of PCM audio, is that the people don't properly understand -that writes to PCM devices must match exactly the data rate of the device. +The most common reason for problems with playback of PCM audio, is +that the people don't properly understand that writes to PCM devices +must match exactly the data rate of the device.

-If too little data is written to the device, it will underrun, and ugly clicking sounds will occur. Conversely, -of too much data is written to the device, the write function will either block (PCM_NORMAL mode) or return zero -(PCM_NONBLOCK mode). +If too little data is written to the device, it will underrun, and +ugly clicking sounds will occur. Conversely, of too much data is +written to the device, the write function will either block +(PCM_NORMAL mode) or return zero (PCM_NONBLOCK mode).

-If your program does nothing, but play sound, the easiest way is to put the device in PCM_NORMAL mode, and just -write as much data to the device as possible. This strategy can also be achieved by using a separate thread -with the sole task of playing out sound. +If your program does nothing, but play sound, the easiest way is to +put the device in PCM_NORMAL mode, and just write as much data to the +device as possible. This strategy can also be achieved by using a +separate thread with the sole task of playing out sound.

-In GUI programs, however, it may be a better strategy to setup the device, preload the buffer with a few -periods by calling write a couple of times, and then use some timer method to write one period size of data to -the device every period. The purpose of the preloading is to avoid underrun clicks if the used timer -doesn't expire exactly on time. +In GUI programs, however, it may be a better strategy to setup the +device, preload the buffer with a few periods by calling write a +couple of times, and then use some timer method to write one period +size of data to the device every period. The purpose of the preloading +is to avoid underrun clicks if the used timer doesn't expire exactly +on time.

-Also note, that most timer APIs that you can find for Python will cummulate time delays: If you set the timer -to expire after 1/10'th of a second, the actual timeout will happen slightly later, which will accumulate to -quite a lot after a few seconds. Hint: use time.time() to check how much time has really passed, and add -extra writes as nessecary. +Also note, that most timer APIs that you can find for Python will +cummulate time delays: If you set the timer to expire after 1/10'th of +a second, the actual timeout will happen slightly later, which will +accumulate to quite a lot after a few seconds. Hint: use time.time() +to check how much time has really passed, and add extra writes as +nessecary.

@@ -324,7 +371,7 @@ extra writes as nessecary.


-Release 0.3. +Release 0.4. diff --git a/doc/pyalsaaudio.html b/doc/pyalsaaudio.html index d3fb373..bb14cee 100644 --- a/doc/pyalsaaudio.html +++ b/doc/pyalsaaudio.html @@ -44,6 +44,7 @@

PyAlsaAudio

Casper Wilstrup

+

cwi@aves.dk

@@ -102,7 +103,7 @@
-Release 0.3. +Release 0.4. diff --git a/doc/src/libalsaaudio.tex b/doc/src/libalsaaudio.tex index 3d35561..784834e 100644 --- a/doc/src/libalsaaudio.tex +++ b/doc/src/libalsaaudio.tex @@ -383,6 +383,43 @@ To manipulate these swithes use the \method{setrec} or \end{methoddesc} +\begin{methoddesc}[Mixer]{getenum}{} + For enumerated controls, return the currently selected item and + the list of items available. + + Returns a tuple \textit{(string, list of strings)}. + + For example, my soundcard has a Mixer called \textit{Mono Output Select}. + Using \textit{amixer}, I get: + +\begin{verbatim} +$ amixer get "Mono Output Select" +Simple mixer control 'Mono Output Select',0 + Capabilities: enum + Items: 'Mix' 'Mic' + Item0: 'Mix' +\end{verbatim} + + Using \module{alsaaudio}, one could do: +\begin{verbatim} +>>> import alsaaudio +>>> m = alsaaudio.Mixer('Mono Output Select') +>>> m.getenum() +('Mix', ['Mix', 'Mic']) +\end{verbatim} + + This method will return an empty tuple if the mixer is not an + enumerated control. +\end{methoddesc} + +\begin{methoddesc}[Mixer]{getmute}{} + Return a list indicating the current mute setting for each channel. + 0 means not muted, 1 means muted. + + This method will fail if the mixer has no playback switch + capabilities. +\end{methoddesc} + \begin{methoddesc}[Mixer]{getrange}{\optional{direction}} Return the volume range of the ALSA mixer controlled by this object. @@ -393,6 +430,14 @@ To manipulate these swithes use the \method{setrec} or \end{methoddesc} +\begin{methoddesc}[Mixer]{getrec}{} + Return a list indicating the current record mute setting for each + channel. 0 means not recording, 1 means recording. + + This method will fail if the mixer has no capture switch + capabilities. +\end{methoddesc} + \begin{methoddesc}[Mixer]{getvolume}{\optional{direction}} Returns a list with the current volume settings for each channel. The list elements are integer percentages. @@ -404,22 +449,6 @@ To manipulate these swithes use the \method{setrec} or \end{methoddesc} -\begin{methoddesc}[Mixer]{getmute}{} - Return a list indicating the current mute setting for each channel. - 0 means not muted, 1 means muted. - - This method will fail if the mixer has no playback switch - capabilities. -\end{methoddesc} - -\begin{methoddesc}[Mixer]{getrec}{} - Return a list indicating the current record mute setting for each - channel. 0 means not recording, 1 means recording. - - This method will fail if the mixer has no capture switch - capabilities. -\end{methoddesc} - \begin{methoddesc}[Mixer]{setvolume}{volume,\optional{channel}, \optional{direction}} diff --git a/doc/src/pyalsaaudio.tex b/doc/src/pyalsaaudio.tex index 9fc94a2..bfb0a54 100644 --- a/doc/src/pyalsaaudio.tex +++ b/doc/src/pyalsaaudio.tex @@ -2,7 +2,7 @@ \title{PyAlsaAudio} -\release{0.3} +\release{0.4} % At minimum, give your name and an email address. You can include a % snail-mail address if you like. diff --git a/setup.py b/setup.py index 9b3b26a..41e34c9 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ if version < '2.2.3': setup( name = 'pyalsaaudio', - version = '0.3', + version = '0.4', description = 'ALSA bindings', long_description = __doc__, author = 'Casper Wilstrup',