Ported to Python3.0
Converted documentation to Sphinx. Added playwav.py git-svn-id: svn://svn.code.sf.net/p/pyalsaaudio/code/trunk@25 ec2f30ec-7544-0410-870e-f70ca00c83f0
@@ -1,6 +1,8 @@
|
|||||||
Version 0.4:
|
Version 0.4:
|
||||||
|
- Support for Python 3.0
|
||||||
|
- Documentation in reStructuredText; use Sphinx instead of LaTeX.
|
||||||
- added mixer.getenum()
|
- added mixer.getenum()
|
||||||
- small documentation improvements
|
|
||||||
|
|
||||||
Version 0.3:
|
Version 0.3:
|
||||||
- wrapped blocking calls with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS
|
- wrapped blocking calls with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ And then as root:
|
|||||||
|
|
||||||
Using the API
|
Using the API
|
||||||
=============
|
=============
|
||||||
There is a reasonably usefull API documentation included in the module
|
There is a reasonably useful API documentation included in the module
|
||||||
documentation, which can be found in the doc subdirectory of the source
|
documentation, which can be found in the doc subdirectory of the source
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* The standard audio API for Linux since kernel 2.6
|
* The standard audio API for Linux since kernel 2.6
|
||||||
*
|
*
|
||||||
* Contributed by Unispeed A/S (http://www.unispeed.com)
|
* Contributed by Unispeed A/S (http://www.unispeed.com)
|
||||||
* Author: Casper Wilstup (cwi@unispeed.dk)
|
* Author: Casper Wilstup (cwi@aves.dk)
|
||||||
*
|
*
|
||||||
* Bug fixes and maintenance by Lars Immisch <lars@ibp.de>
|
* Bug fixes and maintenance by Lars Immisch <lars@ibp.de>
|
||||||
*
|
*
|
||||||
@@ -14,7 +14,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
#include "stringobject.h"
|
#include "stringobject.h"
|
||||||
|
#define PyUnicode_FromString PyString_FromString
|
||||||
|
#endif
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -237,8 +240,8 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) {
|
|||||||
val = snd_pcm_hw_params_get_sbits(hwparams);
|
val = snd_pcm_hw_params_get_sbits(hwparams);
|
||||||
printf("significant bits = %d\n", val);
|
printf("significant bits = %d\n", val);
|
||||||
|
|
||||||
snd_pcm_hw_params_get_tick_time(hwparams, &val, &dir);
|
snd_pcm_hw_params_get_period_time(hwparams, &val, &dir);
|
||||||
printf("tick time = %d us\n", val);
|
printf("period time = %d us\n", val);
|
||||||
|
|
||||||
val = snd_pcm_hw_params_is_batch(hwparams);
|
val = snd_pcm_hw_params_is_batch(hwparams);
|
||||||
printf("is batch = %d\n", val);
|
printf("is batch = %d\n", val);
|
||||||
@@ -305,7 +308,7 @@ Returns the mode of the PCM object. One of:\n\
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
alsapcm_cardname(alsapcm_t *self, PyObject *args) {
|
alsapcm_cardname(alsapcm_t *self, PyObject *args) {
|
||||||
if (!PyArg_ParseTuple(args,":cardname")) return NULL;
|
if (!PyArg_ParseTuple(args,":cardname")) return NULL;
|
||||||
return PyString_FromString(self->cardname);
|
return PyUnicode_FromString(self->cardname);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(cardname_doc,
|
PyDoc_STRVAR(cardname_doc,
|
||||||
@@ -429,12 +432,16 @@ alsapcm_read(alsapcm_t *self, PyObject *args) {
|
|||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
else if (res < 0) {
|
else if (res < 0) {
|
||||||
PyErr_SetString(ALSAAudioError,snd_strerror(res));
|
PyErr_SetString(ALSAAudioError, snd_strerror(res));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Py_BuildValue("is#",res,buffer,res*self->framesize);
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
return Py_BuildValue("is#", res, buffer, res*self->framesize);
|
||||||
|
#else
|
||||||
|
return Py_BuildValue("iy#", res, buffer, res*self->framesize);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(read_doc,
|
PyDoc_STRVAR(read_doc,
|
||||||
@@ -443,19 +450,33 @@ PyDoc_STRVAR(read_doc,
|
|||||||
In PCM_NORMAL mode, this function blocks until a full period is\n\
|
In PCM_NORMAL mode, this function blocks until a full period is\n\
|
||||||
available, and then returns a tuple (length,data) where length is\n\
|
available, and then returns a tuple (length,data) where length is\n\
|
||||||
the number of frames of the captured data, and data is the captured sound\n\
|
the number of frames of the captured data, and data is the captured sound\n\
|
||||||
frames as a string. The length of the returned data will be\n\
|
frames as bytes (or a string in Python 2.x). The length of the returned data\n\
|
||||||
periodsize*framesize bytes.\n\
|
will be periodsize*framesize bytes.\n\
|
||||||
\n\
|
\n\
|
||||||
In PCM_NONBLOCK mode, the call will not block, but will return (0,'')\n\
|
In PCM_NONBLOCK mode, the call will not block, but will return (0,'')\n\
|
||||||
if no new period has become available since the last call to read.");
|
if no new period has become available since the last call to read.");
|
||||||
|
|
||||||
|
|
||||||
static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) {
|
static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) {
|
||||||
char *data;
|
|
||||||
int datalen;
|
|
||||||
int res;
|
int res;
|
||||||
if (!PyArg_ParseTuple(args,"s#:write",&data,&datalen)) return NULL;
|
int datalen;
|
||||||
if (datalen%self->framesize) {
|
char *data;
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
if (!PyArg_ParseTuple(args,"s#:write",&data,&datalen))
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
Py_buffer buf;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args,"y*:write",&buf))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data = buf.buf;
|
||||||
|
datalen = buf.len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (datalen % self->framesize) {
|
||||||
PyErr_SetString(ALSAAudioError,
|
PyErr_SetString(ALSAAudioError,
|
||||||
"Data size must be a multiple of framesize");
|
"Data size must be a multiple of framesize");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -548,8 +569,12 @@ alsapcm_getattr(alsapcm_t *self, char *name) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyTypeObject ALSAPCMType = {
|
static PyTypeObject ALSAPCMType = {
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
|
#else
|
||||||
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
#endif
|
||||||
"alsaaudio.PCM", /* tp_name */
|
"alsaaudio.PCM", /* tp_name */
|
||||||
sizeof(alsapcm_t), /* tp_basicsize */
|
sizeof(alsapcm_t), /* tp_basicsize */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */
|
||||||
@@ -647,7 +672,7 @@ alsamixer_list(PyObject *self, PyObject *args) {
|
|||||||
{
|
{
|
||||||
PyObject *mixer;
|
PyObject *mixer;
|
||||||
snd_mixer_selem_get_id(elem, sid);
|
snd_mixer_selem_get_id(elem, sid);
|
||||||
mixer = PyString_FromString(snd_mixer_selem_id_get_name(sid));
|
mixer = PyUnicode_FromString(snd_mixer_selem_id_get_name(sid));
|
||||||
PyList_Append(result,mixer);
|
PyList_Append(result,mixer);
|
||||||
Py_DECREF(mixer);
|
Py_DECREF(mixer);
|
||||||
}
|
}
|
||||||
@@ -788,7 +813,7 @@ static void alsamixer_dealloc(alsamixer_t *self) {
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
alsamixer_cardname(alsamixer_t *self, PyObject *args) {
|
alsamixer_cardname(alsamixer_t *self, PyObject *args) {
|
||||||
if (!PyArg_ParseTuple(args,":cardname")) return NULL;
|
if (!PyArg_ParseTuple(args,":cardname")) return NULL;
|
||||||
return PyString_FromString(self->cardname);
|
return PyUnicode_FromString(self->cardname);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(mixer_cardname_doc,
|
PyDoc_STRVAR(mixer_cardname_doc,
|
||||||
@@ -800,7 +825,7 @@ Returns the name of the sound card used by this Mixer object.");
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
alsamixer_mixer(alsamixer_t *self, PyObject *args) {
|
alsamixer_mixer(alsamixer_t *self, PyObject *args) {
|
||||||
if (!PyArg_ParseTuple(args,":mixer")) return NULL;
|
if (!PyArg_ParseTuple(args,":mixer")) return NULL;
|
||||||
return PyString_FromString(self->controlname);
|
return PyUnicode_FromString(self->controlname);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(mixer_doc,
|
PyDoc_STRVAR(mixer_doc,
|
||||||
@@ -828,17 +853,17 @@ alsamixer_volumecap(alsamixer_t *self, PyObject *args) {
|
|||||||
if (!PyArg_ParseTuple(args,":volumecap")) return NULL;
|
if (!PyArg_ParseTuple(args,":volumecap")) return NULL;
|
||||||
result = PyList_New(0);
|
result = PyList_New(0);
|
||||||
if (self->volume_cap&MIXER_CAP_VOLUME)
|
if (self->volume_cap&MIXER_CAP_VOLUME)
|
||||||
PyList_Append(result,PyString_FromString("Volume"));
|
PyList_Append(result,PyUnicode_FromString("Volume"));
|
||||||
if (self->volume_cap&MIXER_CAP_VOLUME_JOINED)
|
if (self->volume_cap&MIXER_CAP_VOLUME_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Volume"));
|
PyList_Append(result,PyUnicode_FromString("Joined Volume"));
|
||||||
if (self->volume_cap&MIXER_CAP_PVOLUME)
|
if (self->volume_cap&MIXER_CAP_PVOLUME)
|
||||||
PyList_Append(result,PyString_FromString("Playback Volume"));
|
PyList_Append(result,PyUnicode_FromString("Playback Volume"));
|
||||||
if (self->volume_cap&MIXER_CAP_PVOLUME_JOINED)
|
if (self->volume_cap&MIXER_CAP_PVOLUME_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Playback Volume"));
|
PyList_Append(result,PyUnicode_FromString("Joined Playback Volume"));
|
||||||
if (self->volume_cap&MIXER_CAP_CVOLUME)
|
if (self->volume_cap&MIXER_CAP_CVOLUME)
|
||||||
PyList_Append(result,PyString_FromString("Capture Volume"));
|
PyList_Append(result,PyUnicode_FromString("Capture Volume"));
|
||||||
if (self->volume_cap&MIXER_CAP_CVOLUME_JOINED)
|
if (self->volume_cap&MIXER_CAP_CVOLUME_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Capture Volume"));
|
PyList_Append(result,PyUnicode_FromString("Joined Capture Volume"));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -862,19 +887,19 @@ alsamixer_switchcap(alsamixer_t *self, PyObject *args) {
|
|||||||
if (!PyArg_ParseTuple(args,":switchcap")) return NULL;
|
if (!PyArg_ParseTuple(args,":switchcap")) return NULL;
|
||||||
result = PyList_New(0);
|
result = PyList_New(0);
|
||||||
if (self->volume_cap&MIXER_CAP_SWITCH)
|
if (self->volume_cap&MIXER_CAP_SWITCH)
|
||||||
PyList_Append(result,PyString_FromString("Mute"));
|
PyList_Append(result,PyUnicode_FromString("Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_SWITCH_JOINED)
|
if (self->volume_cap&MIXER_CAP_SWITCH_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Mute"));
|
PyList_Append(result,PyUnicode_FromString("Joined Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_PSWITCH)
|
if (self->volume_cap&MIXER_CAP_PSWITCH)
|
||||||
PyList_Append(result,PyString_FromString("Playback Mute"));
|
PyList_Append(result,PyUnicode_FromString("Playback Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_PSWITCH_JOINED)
|
if (self->volume_cap&MIXER_CAP_PSWITCH_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Playback Mute"));
|
PyList_Append(result,PyUnicode_FromString("Joined Playback Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_CSWITCH)
|
if (self->volume_cap&MIXER_CAP_CSWITCH)
|
||||||
PyList_Append(result,PyString_FromString("Capture Mute"));
|
PyList_Append(result,PyUnicode_FromString("Capture Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_CSWITCH_JOINED)
|
if (self->volume_cap&MIXER_CAP_CSWITCH_JOINED)
|
||||||
PyList_Append(result,PyString_FromString("Joined Capture Mute"));
|
PyList_Append(result,PyUnicode_FromString("Joined Capture Mute"));
|
||||||
if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE)
|
if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE)
|
||||||
PyList_Append(result,PyString_FromString("Capture Exclusive"));
|
PyList_Append(result,PyUnicode_FromString("Capture Exclusive"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1064,7 +1089,7 @@ alsamixer_getenum(alsamixer_t *self, PyObject *args) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTuple_SetItem(result, 0, PyString_FromString(name));
|
PyTuple_SetItem(result, 0, PyUnicode_FromString(name));
|
||||||
|
|
||||||
elems = PyList_New(count);
|
elems = PyList_New(count);
|
||||||
if (!elems)
|
if (!elems)
|
||||||
@@ -1082,7 +1107,7 @@ alsamixer_getenum(alsamixer_t *self, PyObject *args) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyList_SetItem(elems, i, PyString_FromString(name));
|
PyList_SetItem(elems, i, PyUnicode_FromString(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTuple_SetItem(result, 1, elems);
|
PyTuple_SetItem(result, 1, elems);
|
||||||
@@ -1339,8 +1364,12 @@ alsamixer_getattr(alsapcm_t *self, char *name) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyTypeObject ALSAMixerType = {
|
static PyTypeObject ALSAMixerType = {
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
|
#else
|
||||||
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
#endif
|
||||||
"alsaaudio.Mixer", /* tp_name */
|
"alsaaudio.Mixer", /* tp_name */
|
||||||
sizeof(alsamixer_t), /* tp_basicsize */
|
sizeof(alsamixer_t), /* tp_basicsize */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */
|
||||||
@@ -1390,32 +1419,73 @@ static PyMethodDef alsaaudio_methods[] = {
|
|||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
|
||||||
|
#define _EXPORT_INT(mod, name, value) \
|
||||||
|
if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return NULL;
|
||||||
|
|
||||||
|
static struct PyModuleDef alsaaudio_module = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"alsaaudio",
|
||||||
|
alsaaudio_module_doc,
|
||||||
|
-1,
|
||||||
|
alsaaudio_methods,
|
||||||
|
0, /* m_reload */
|
||||||
|
0, /* m_traverse */
|
||||||
|
0, /* m_clear */
|
||||||
|
0, /* m_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#define _EXPORT_INT(mod, name, value) \
|
#define _EXPORT_INT(mod, name, value) \
|
||||||
if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return;
|
if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return;
|
||||||
|
|
||||||
void initalsaaudio(void) {
|
#endif // 3.0
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
void initalsaaudio(void)
|
||||||
|
#else
|
||||||
|
PyObject *PyInit_alsaaudio(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
PyObject *m;
|
PyObject *m;
|
||||||
ALSAPCMType.tp_new = alsapcm_new;
|
ALSAPCMType.tp_new = alsapcm_new;
|
||||||
ALSAMixerType.tp_new = alsamixer_new;
|
ALSAMixerType.tp_new = alsamixer_new;
|
||||||
|
|
||||||
PyEval_InitThreads();
|
PyEval_InitThreads();
|
||||||
|
|
||||||
m = Py_InitModule3("alsaaudio",alsaaudio_methods,alsaaudio_module_doc);
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
m = Py_InitModule3("alsaaudio", alsaaudio_methods, alsaaudio_module_doc);
|
||||||
|
if (!m)
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
|
||||||
|
m = PyModule_Create(&alsaaudio_module);
|
||||||
|
if (!m)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
ALSAAudioError = PyErr_NewException("alsaaudio.ALSAAudioError", NULL, NULL);
|
ALSAAudioError = PyErr_NewException("alsaaudio.ALSAAudioError", NULL, NULL);
|
||||||
if (ALSAAudioError) {
|
if (!ALSAAudioError)
|
||||||
/* Each call to PyModule_AddObject decrefs it; compensate: */
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
Py_INCREF(&ALSAPCMType);
|
/* Each call to PyModule_AddObject decrefs it; compensate: */
|
||||||
PyModule_AddObject(m,"PCM",(PyObject *)&ALSAPCMType);
|
|
||||||
|
|
||||||
Py_INCREF(&ALSAMixerType);
|
Py_INCREF(&ALSAPCMType);
|
||||||
PyModule_AddObject(m,"Mixer",(PyObject *)&ALSAMixerType);
|
PyModule_AddObject(m, "PCM", (PyObject *)&ALSAPCMType);
|
||||||
|
|
||||||
Py_INCREF(ALSAAudioError);
|
Py_INCREF(&ALSAMixerType);
|
||||||
PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError);
|
PyModule_AddObject(m, "Mixer", (PyObject *)&ALSAMixerType);
|
||||||
}
|
|
||||||
|
|
||||||
|
Py_INCREF(ALSAAudioError);
|
||||||
|
PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError);
|
||||||
|
|
||||||
_EXPORT_INT(m, "PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK);
|
_EXPORT_INT(m, "PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK);
|
||||||
_EXPORT_INT(m, "PCM_CAPTURE",SND_PCM_STREAM_CAPTURE);
|
_EXPORT_INT(m, "PCM_CAPTURE",SND_PCM_STREAM_CAPTURE);
|
||||||
@@ -1465,4 +1535,8 @@ void initalsaaudio(void) {
|
|||||||
_EXPORT_INT(m, "MIXER_SCHN_REAR_CENTER", SND_MIXER_SCHN_REAR_CENTER);
|
_EXPORT_INT(m, "MIXER_SCHN_REAR_CENTER", SND_MIXER_SCHN_REAR_CENTER);
|
||||||
_EXPORT_INT(m, "MIXER_SCHN_MONO", SND_MIXER_SCHN_MONO);
|
_EXPORT_INT(m, "MIXER_SCHN_MONO", SND_MIXER_SCHN_MONO);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
return m;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d .build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
|
SFUSER = larsimmisch
|
||||||
|
|
||||||
|
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck install
|
||||||
|
|
||||||
|
all: html
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " pickle to make pickle files (usable by e.g. sphinx-web)"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " changes to make an overview over all changed/added/deprecated items"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -rf .build/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
mkdir -p .build/html .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) .build/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in .build/html."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
mkdir -p .build/pickle .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) .build/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files or run"
|
||||||
|
@echo " sphinx-web .build/pickle"
|
||||||
|
@echo "to start the sphinx-web server."
|
||||||
|
|
||||||
|
web: pickle
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
mkdir -p .build/htmlhelp .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) .build/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in .build/htmlhelp."
|
||||||
|
|
||||||
|
latex:
|
||||||
|
mkdir -p .build/latex .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) .build/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in .build/latex."
|
||||||
|
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||||
|
"run these through (pdf)latex."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
mkdir -p .build/changes .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) .build/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in .build/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
mkdir -p .build/linkcheck .build/doctrees
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) .build/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in .build/linkcheck/output.txt."
|
||||||
|
|
||||||
|
install:
|
||||||
|
scp -r .build/html/* $(SFUSER),pyalsaaudio@web.sourceforge.net:htdocs
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="STYLESHEET" href="pyalsaaudio.css" type='text/css' />
|
|
||||||
<link rel="first" href="pyalsaaudio.html" title='PyAlsaAudio' />
|
|
||||||
<link rel='contents' href='contents.html' title="Contents" />
|
|
||||||
<link rel='last' href='about.html' title='About this document...' />
|
|
||||||
<link rel='help' href='about.html' title='About this document...' />
|
|
||||||
<link rel="prev" href="contents.html" />
|
|
||||||
<link rel="parent" href="pyalsaaudio.html" />
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name='aesop' content='information' />
|
|
||||||
<title>About this document ...</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navigation">
|
|
||||||
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="4.4 alsa Examples"
|
|
||||||
href="pcm-example.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="pcm-example.html">4.4 ALSA Examples</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
</div>
|
|
||||||
<hr /></div>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
<h1><a name="SECTION003000000000000000000">
|
|
||||||
About this document ...</a>
|
|
||||||
</h1>
|
|
||||||
<strong>PyAlsaAudio</strong>
|
|
||||||
<p> This document was generated using the <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> translator.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright ©
|
|
||||||
1993, 1994, 1995, 1996, 1997, <a
|
|
||||||
href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos
|
|
||||||
Drakos</a>, Computer Based Learning Unit, University of
|
|
||||||
Leeds, and Copyright © 1997, 1998, <a
|
|
||||||
href="http://www.maths.mq.edu.au/~ross/">Ross
|
|
||||||
Moore</a>, Mathematics Department, Macquarie University,
|
|
||||||
Sydney.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> The application of <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python
|
|
||||||
documentation has been heavily tailored by Fred L. Drake,
|
|
||||||
Jr. Original navigation icons were contributed by Christopher
|
|
||||||
Petrilli.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="navigation">
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<p></p><hr />
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="4.4 alsa Examples"
|
|
||||||
href="pcm-example.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="pcm-example.html">4.4 ALSA Examples</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<span class="release-info">Release 0.4.</span>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 438 B |
@@ -1,107 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="STYLESHEET" href="pyalsaaudio.css" type='text/css' />
|
|
||||||
<link rel="first" href="pyalsaaudio.html" title='PyAlsaAudio' />
|
|
||||||
<link rel='contents' href='contents.html' title="Contents" />
|
|
||||||
<link rel='last' href='about.html' title='About this document...' />
|
|
||||||
<link rel='help' href='about.html' title='About this document...' />
|
|
||||||
<link rel="next" href="about.html" />
|
|
||||||
<link rel="prev" href="front.html" />
|
|
||||||
<link rel="parent" href="pyalsaaudio.html" />
|
|
||||||
<link rel="next" href="node3.html" />
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name='aesop' content='information' />
|
|
||||||
<title>Contents</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navigation">
|
|
||||||
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="Front Matter"
|
|
||||||
href="front.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="1 what is ALSA"
|
|
||||||
href="node3.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="front.html">Front Matter</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="node3.html">1 What is ALSA</a>
|
|
||||||
</div>
|
|
||||||
<hr /></div>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
<br><h2><a name="SECTION002000000000000000000">
|
|
||||||
Contents</a>
|
|
||||||
</h2>
|
|
||||||
<!--Table of Contents-->
|
|
||||||
|
|
||||||
<ul class="TofC">
|
|
||||||
<li><ul>
|
|
||||||
<li><a href="node3.html">1 What is ALSA</a>
|
|
||||||
<li><a href="node4.html">2 ALSA and Python</a>
|
|
||||||
<li><a href="node5.html">3 Installation</a>
|
|
||||||
<li><a href="module-alsaaudio.html">4 alsaaudio</a>
|
|
||||||
<ul>
|
|
||||||
<li><a href="node7.html">4.1 PCM Terminology and Concepts</a>
|
|
||||||
<li><a href="pcm-objects.html">4.2 PCM Objects</a>
|
|
||||||
<li><a href="mixer-objects.html">4.3 Mixer Objects</a>
|
|
||||||
<li><a href="pcm-example.html">4.4 ALSA Examples</a>
|
|
||||||
</ul></ul></ul>
|
|
||||||
<!--End of Table of Contents-->
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<div class="navigation">
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<p></p><hr />
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="Front Matter"
|
|
||||||
href="front.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="1 what is ALSA"
|
|
||||||
href="node3.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="front.html">Front Matter</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="node3.html">1 What is ALSA</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<span class="release-info">Release 0.4.</span>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 649 B |
@@ -1,121 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="STYLESHEET" href="pyalsaaudio.css" type='text/css' />
|
|
||||||
<link rel="first" href="pyalsaaudio.html" title='PyAlsaAudio' />
|
|
||||||
<link rel='contents' href='contents.html' title="Contents" />
|
|
||||||
<link rel='last' href='about.html' title='About this document...' />
|
|
||||||
<link rel='help' href='about.html' title='About this document...' />
|
|
||||||
<link rel="next" href="contents.html" />
|
|
||||||
<link rel="prev" href="pyalsaaudio.html" />
|
|
||||||
<link rel="parent" href="pyalsaaudio.html" />
|
|
||||||
<link rel="next" href="contents.html" />
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name='aesop' content='information' />
|
|
||||||
<title>Front Matter</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navigation">
|
|
||||||
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="Contents"
|
|
||||||
href="contents.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="contents.html">Contents</a>
|
|
||||||
</div>
|
|
||||||
<hr /></div>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
<h1><a name="SECTION001000000000000000000"></a><a name="front"></a>
|
|
||||||
<br>
|
|
||||||
Front Matter
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This software is licensed under the PSF license - the same one used
|
|
||||||
by the majority of the python distribution. Basically you can use it
|
|
||||||
for anything you wish (even commercial purposes). There is no warranty
|
|
||||||
whatsoever.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<h3>Abstract:</h3>
|
|
||||||
<div class="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.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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.
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<div class="navigation">
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<p></p><hr />
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><a rel="prev" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="parent" title="PyAlsaAudio"
|
|
||||||
href="pyalsaaudio.html"><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="Contents"
|
|
||||||
href="contents.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Previous:</b>
|
|
||||||
<a class="sectref" rel="prev" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Up:</b>
|
|
||||||
<a class="sectref" rel="parent" href="pyalsaaudio.html">PyAlsaAudio</a>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="contents.html">Contents</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<span class="release-info">Release 0.4.</span>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 289 B |
@@ -1,118 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="STYLESHEET" href="pyalsaaudio.css" type='text/css' />
|
|
||||||
<link rel="first" href="pyalsaaudio.html" title='PyAlsaAudio' />
|
|
||||||
<link rel='contents' href='contents.html' title="Contents" />
|
|
||||||
<link rel='last' href='about.html' title='About this document...' />
|
|
||||||
<link rel='help' href='about.html' title='About this document...' />
|
|
||||||
<link rel="next" href="front.html" />
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name='aesop' content='information' />
|
|
||||||
<title>PyAlsaAudio</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navigation">
|
|
||||||
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="Front Matter"
|
|
||||||
href="front.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="front.html">Front Matter</a>
|
|
||||||
</div>
|
|
||||||
<hr /></div>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
<div class="titlepage">
|
|
||||||
<div class='center'>
|
|
||||||
<h1>PyAlsaAudio</h1>
|
|
||||||
<p><b><font size="+2">Casper Wilstrup</font></b></p>
|
|
||||||
<p>cwi@aves.dk</p>
|
|
||||||
<p></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<p><br /></p><hr class='online-navigation' />
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<!--Table of Child-Links-->
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://sourceforge.net/">SourceForge</li>
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://sourceforge.net/projects/pyalsaaudio/">Summary page</a>
|
|
||||||
<li><a href="http://sourceforge.net/project/showfiles.php?group_id=120651">Download</a>
|
|
||||||
<li><a href="http://sourceforge.net/tracker/?group_id=120651">Bug Tracker</a>
|
|
||||||
</ul>
|
|
||||||
</ul><a name="CHILD_LINKS"></a>
|
|
||||||
|
|
||||||
<ul class="ChildLinks">
|
|
||||||
<li><a href="front.html">Front Matter</a>
|
|
||||||
<li><a href="contents.html">Contents</a>
|
|
||||||
<ul>
|
|
||||||
<li><a href="node3.html">1 What is ALSA</a>
|
|
||||||
<li><a href="node4.html">2 ALSA and Python</a>
|
|
||||||
<li><a href="node5.html">3 Installation</a>
|
|
||||||
<li><a href="module-alsaaudio.html">4 <tt class="module">alsaaudio</tt></a>
|
|
||||||
<ul>
|
|
||||||
<li><a href="node7.html">4.1 PCM Terminology and Concepts</a>
|
|
||||||
<li><a href="pcm-objects.html">4.2 PCM Objects</a>
|
|
||||||
<li><a href="mixer-objects.html">4.3 Mixer Objects</a>
|
|
||||||
<li><a href="pcm-example.html">4.4 ALSA Examples</a>
|
|
||||||
</ul>
|
|
||||||
</ul>
|
|
||||||
<li><a href="about.html">About this document ...</a>
|
|
||||||
</ul>
|
|
||||||
<!--End of Table of Child-Links-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navigation">
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<p></p><hr />
|
|
||||||
<table align="center" width="100%" cellpadding="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td class='online-navigation'><img src='previous.png'
|
|
||||||
border='0' height='32' alt='Previous Page' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='up.png'
|
|
||||||
border='0' height='32' alt='Up one Level' width='32' /></td>
|
|
||||||
<td class='online-navigation'><a rel="next" title="Front Matter"
|
|
||||||
href="front.html"><img src='next.png'
|
|
||||||
border='0' height='32' alt='Next Page' width='32' /></a></td>
|
|
||||||
<td align="center" width="100%">PyAlsaAudio</td>
|
|
||||||
<td class='online-navigation'><a rel="contents" title="Table of Contents"
|
|
||||||
href="contents.html"><img src='contents.png'
|
|
||||||
border='0' height='32' alt='Contents' width='32' /></a></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
<td class='online-navigation'><img src='blank.png'
|
|
||||||
border='0' height='32' alt='' width='32' /></td>
|
|
||||||
</tr></table>
|
|
||||||
<div class='online-navigation'>
|
|
||||||
<b class="navlabel">Next:</b>
|
|
||||||
<a class="sectref" rel="next" href="front.html">Front Matter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<span class="release-info">Release 0.4.</span>
|
|
||||||
</div>
|
|
||||||
<!--End of Navigation Panel-->
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 529 B |
@@ -0,0 +1,25 @@
|
|||||||
|
alsaaudio documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
pyalsaaudio
|
||||||
|
libalsaaudio
|
||||||
|
|
||||||
|
|
||||||
|
SourceForge pages
|
||||||
|
=================
|
||||||
|
|
||||||
|
* `Project page <http://sourceforge.net/projects/pyalsaaudio/>`_
|
||||||
|
* `Download <http://sourceforge.net/project/showfiles.php?group_id=120651">`_
|
||||||
|
* `Bug tracker <http://sourceforge.net/tracker/?group_id=120651>`_
|
||||||
|
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
@@ -0,0 +1,533 @@
|
|||||||
|
****************************
|
||||||
|
PCM Terminology and Concepts
|
||||||
|
****************************
|
||||||
|
|
||||||
|
In order to use PCM devices it is useful to be familiar with some concepts and
|
||||||
|
terminology.
|
||||||
|
|
||||||
|
Sample
|
||||||
|
PCM audio, whether it is input or output, consists of *samples*.
|
||||||
|
A single sample represents the amplitude of one channel of sound
|
||||||
|
at a certain point in time. A lot of individual samples are
|
||||||
|
necessary to represent actual sound; for CD audio, 44100 samples
|
||||||
|
are taken every second.
|
||||||
|
|
||||||
|
Samples can be of many different sizes, ranging from 8 bit to 64
|
||||||
|
bit precision. The specific format of each sample can also vary -
|
||||||
|
they can be big endian byte integers, little endian byte integers, or
|
||||||
|
floating point numbers.
|
||||||
|
|
||||||
|
Musically, the sample size determines the dynamic range. The
|
||||||
|
dynamic range is the difference between the quietest and the
|
||||||
|
loudest signal that can be resproduced.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Data 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 or 64kbit/s. This is typically used for telephony.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Period size
|
||||||
|
This is the size of each period in Hz. *Not bytes, but Hz!.* In
|
||||||
|
:mod:`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 use the PCM API. Read
|
||||||
|
on.
|
||||||
|
|
||||||
|
|
||||||
|
********************
|
||||||
|
Module documentation
|
||||||
|
********************
|
||||||
|
|
||||||
|
:mod:`alsaaudio`
|
||||||
|
================
|
||||||
|
|
||||||
|
.. module:: alsaaudio
|
||||||
|
:platform: Linux
|
||||||
|
|
||||||
|
|
||||||
|
.. % \declaremodule{builtin}{alsaaudio} % standard library, in C
|
||||||
|
.. % not standard, in C
|
||||||
|
|
||||||
|
.. moduleauthor:: Casper Wilstrup <cwi@aves.dk>
|
||||||
|
.. moduleauthor:: Lars Immisch <lars@ibp.de>
|
||||||
|
|
||||||
|
|
||||||
|
.. % Author of the module code;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The :mod:`alsaaudio` module defines functions and classes for using ALSA.
|
||||||
|
|
||||||
|
.. % ---- 3.1. ----
|
||||||
|
.. % For each function, use a ``funcdesc'' block. This has exactly two
|
||||||
|
.. % parameters (each parameters is contained in a set of curly braces):
|
||||||
|
.. % the first parameter is the function name (this automatically
|
||||||
|
.. % generates an index entry); the second parameter is the function's
|
||||||
|
.. % argument list. If there are no arguments, use an empty pair of
|
||||||
|
.. % curly braces. If there is more than one argument, separate the
|
||||||
|
.. % arguments with backslash-comma. Optional parts of the parameter
|
||||||
|
.. % list are contained in \optional{...} (this generates a set of square
|
||||||
|
.. % brackets around its parameter). Arguments are automatically set in
|
||||||
|
.. % italics in the parameter list. Each argument should be mentioned at
|
||||||
|
.. % least once in the description; each usage (even inside \code{...})
|
||||||
|
.. % should be enclosed in \var{...}.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: mixers([cardname])
|
||||||
|
|
||||||
|
List the available mixers. The optional *cardname* specifies which card
|
||||||
|
should be queried (this is only relevant if you have more than one 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
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: Mixer([control], [id], [cardname])
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. _pcm-objects:
|
||||||
|
|
||||||
|
PCM Objects
|
||||||
|
-----------
|
||||||
|
|
||||||
|
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 :mod:`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:
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: PCM([type], [mode], [cardname])
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
|
In the current version of :mod:`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.
|
||||||
|
|
||||||
|
This will construct a PCM object with default settings:
|
||||||
|
|
||||||
|
Sample format: PCM_FORMAT_S16_LE --- Rate: 8000 Hz --- Channels: 2 ---
|
||||||
|
Period size: 32 frames ---
|
||||||
|
|
||||||
|
PCM objects have the following methods:
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.pcmtype()
|
||||||
|
|
||||||
|
Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.pcmmode()
|
||||||
|
|
||||||
|
Return the mode of the PCM object. One of PCM_NONBLOCK, PCM_ASYNC,
|
||||||
|
or PCM_NORMAL
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.cardname()
|
||||||
|
|
||||||
|
Return the name of the sound card used by this PCM object.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.setrate(rate)
|
||||||
|
|
||||||
|
Set the sample rate in Hz for the device. Typical values are 8000
|
||||||
|
(mainly used for telephony), 16000, 44100 (CD quality), and 96000.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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 following formats are provided by ALSA:
|
||||||
|
|
||||||
|
===================== ===============
|
||||||
|
Format Description
|
||||||
|
===================== ===============
|
||||||
|
PCM_FORMAT_S8 Signed 8 bit samples for each channel
|
||||||
|
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)
|
||||||
|
PCM_FORMAT_S16_BE 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)
|
||||||
|
PCM_FORMAT_U16_BE 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)
|
||||||
|
PCM_FORMAT_S24_BE 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)
|
||||||
|
PCM_FORMAT_U24_BE 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)
|
||||||
|
PCM_FORMAT_S32_BE 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)
|
||||||
|
PCM_FORMAT_U32_BE 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)
|
||||||
|
PCM_FORMAT_FLOAT_BE 32 bit samples encoded as float (Big Endian byte order)
|
||||||
|
PCM_FORMAT_FLOAT64_LE 64 bit samples encoded as float (Little Endian byte order)
|
||||||
|
PCM_FORMAT_FLOAT64_BE 64 bit samples encoded as float (Big Endian byte order)
|
||||||
|
PCM_FORMAT_MU_LAW A logarithmic encoding (used by Sun .au files and telephony)
|
||||||
|
PCM_FORMAT_A_LAW Another logarithmic encoding
|
||||||
|
PCM_FORMAT_IMA_ADPCM A 4:1 compressed format defined by the Interactive Multimedia Association.
|
||||||
|
PCM_FORMAT_MPEG MPEG encoded audio?
|
||||||
|
PCM_FORMAT_GSM 9600 bits/s constant rate encoding for speech
|
||||||
|
===================== ===============
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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)
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
acummulate 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. _mixer-objects:
|
||||||
|
|
||||||
|
Mixer Objects
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Mixer objects provides access to the ALSA mixer API.
|
||||||
|
|
||||||
|
|
||||||
|
.. 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
|
||||||
|
:mod:`alsaaudio`.\ :func:`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.
|
||||||
|
|
||||||
|
Mixer objects have the following methods:
|
||||||
|
|
||||||
|
.. method:: Mixer.cardname()
|
||||||
|
|
||||||
|
Return the name of the sound card used by this Mixer object
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.mixer()
|
||||||
|
|
||||||
|
Return the name of the specific mixer controlled by this object, For example
|
||||||
|
'Master' or 'PCM'
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.mixerid()
|
||||||
|
|
||||||
|
Return the ID of the ALSA mixer controlled by this object.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.switchcap()
|
||||||
|
|
||||||
|
Returns a list of the switches which are defined by this specific mixer.
|
||||||
|
Possible values in this list are:
|
||||||
|
|
||||||
|
==================== ================
|
||||||
|
Switch Description
|
||||||
|
==================== ================
|
||||||
|
Mute This mixer can mute
|
||||||
|
Joined Mute This mixer can mute all channels at the same time
|
||||||
|
Playback Mute This mixer can mute the playback output
|
||||||
|
Joined Playback Mute Mute playback for all channels at the same time}
|
||||||
|
Capture Mute Mute sound capture
|
||||||
|
Joined Capture Mute Mute sound capture for all channels at a time}
|
||||||
|
Capture Exclusive Not quite sure what this is
|
||||||
|
==================== ================
|
||||||
|
|
||||||
|
To manipulate these swithes use the :meth:`setrec` or
|
||||||
|
:meth:`setmute` methods
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.volumecap()
|
||||||
|
|
||||||
|
Returns a list of the volume control capabilities of this
|
||||||
|
mixer. Possible values in the list are:
|
||||||
|
|
||||||
|
====================== ================
|
||||||
|
Capability Description
|
||||||
|
====================== ================
|
||||||
|
Volume This mixer can control volume
|
||||||
|
Joined Volume This mixer can control volume for all channels at the same time
|
||||||
|
Playback Volume This mixer can manipulate the playback output
|
||||||
|
Joined Playback Volume 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
|
||||||
|
====================== ================
|
||||||
|
|
||||||
|
.. method:: Mixer.getenum()
|
||||||
|
|
||||||
|
For enumerated controls, return the currently selected item and the list of
|
||||||
|
items available.
|
||||||
|
|
||||||
|
Returns a tuple *(string, list of strings)*.
|
||||||
|
|
||||||
|
For example, my soundcard has a Mixer called *Mono Output Select*. Using
|
||||||
|
*amixer*, I get::
|
||||||
|
|
||||||
|
$ amixer get "Mono Output Select"
|
||||||
|
Simple mixer control 'Mono Output Select',0
|
||||||
|
Capabilities: enum
|
||||||
|
Items: 'Mix' 'Mic'
|
||||||
|
Item0: 'Mix'
|
||||||
|
|
||||||
|
Using :mod:`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.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.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'
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: 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.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.getvolume([direction])
|
||||||
|
|
||||||
|
Returns a list with the current volume settings for each channel. The list
|
||||||
|
elements are integer percentages.
|
||||||
|
|
||||||
|
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'
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.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'.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.setmute(mute, [channel])
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
This method will fail if the mixer has no playback mute capabilities
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Mixer.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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
**A Note on the ALSA Mixer API**
|
||||||
|
|
||||||
|
The ALSA mixer API is extremely complicated - and hardly documented at all.
|
||||||
|
:mod:`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 :mod:`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 needs into
|
||||||
|
future versions.
|
||||||
|
|
||||||
|
If the current state of affairs annoys 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.
|
||||||
|
|
||||||
|
.. % ==== 4. ====
|
||||||
|
|
||||||
|
|
||||||
|
.. _pcm-example:
|
||||||
|
|
||||||
|
ALSA Examples
|
||||||
|
-------------
|
||||||
|
|
||||||
|
For now, the only examples available are the 'playbacktest.py' and the
|
||||||
|
'recordtest.py' programs included. This will change in a future version.
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 598 B |
|
Before Width: | Height: | Size: 253 B |
|
Before Width: | Height: | Size: 511 B |
|
Before Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 511 B |
@@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
* The first part of this is the standard CSS generated by LaTeX2HTML,
|
|
||||||
* with the "empty" declarations removed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
|
|
||||||
.math { font-family: "Century Schoolbook", serif; }
|
|
||||||
.math i { font-family: "Century Schoolbook", serif;
|
|
||||||
font-weight: bold }
|
|
||||||
.boldmath { font-family: "Century Schoolbook", serif;
|
|
||||||
font-weight: bold }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implement both fixed-size and relative sizes.
|
|
||||||
*
|
|
||||||
* I think these can be safely removed, as it doesn't appear that
|
|
||||||
* LaTeX2HTML ever generates these, even though these are carried
|
|
||||||
* over from the LaTeX2HTML stylesheet.
|
|
||||||
*/
|
|
||||||
small.xtiny { font-size : xx-small; }
|
|
||||||
small.tiny { font-size : x-small; }
|
|
||||||
small.scriptsize { font-size : smaller; }
|
|
||||||
small.footnotesize { font-size : small; }
|
|
||||||
big.xlarge { font-size : large; }
|
|
||||||
big.xxlarge { font-size : x-large; }
|
|
||||||
big.huge { font-size : larger; }
|
|
||||||
big.xhuge { font-size : xx-large; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Document-specific styles come next;
|
|
||||||
* these are added for the Python documentation.
|
|
||||||
*
|
|
||||||
* Note that the size specifications for the H* elements are because
|
|
||||||
* Netscape on Solaris otherwise doesn't get it right; they all end up
|
|
||||||
* the normal text size.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body { color: #000000;
|
|
||||||
background-color: #ffffff; }
|
|
||||||
|
|
||||||
a:link:active { color: #ff0000; }
|
|
||||||
a:link:hover { background-color: #bbeeff; }
|
|
||||||
a:visited:hover { background-color: #bbeeff; }
|
|
||||||
a:visited { color: #551a8b; }
|
|
||||||
a:link { color: #0000bb; }
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif;
|
|
||||||
font-weight: bold; }
|
|
||||||
h1 { font-size: 180%; }
|
|
||||||
h2 { font-size: 150%; }
|
|
||||||
h3, h4 { font-size: 120%; }
|
|
||||||
|
|
||||||
/* These are section titles used in navigation links, so make sure we
|
|
||||||
* match the section header font here, even it not the weight.
|
|
||||||
*/
|
|
||||||
.sectref { font-family: avantgarde, sans-serif; }
|
|
||||||
/* And the label before the titles in navigation: */
|
|
||||||
.navlabel { font-size: 85%; }
|
|
||||||
|
|
||||||
|
|
||||||
/* LaTeX2HTML insists on inserting <br> elements into headers which
|
|
||||||
* are marked with \label. This little bit of CSS magic ensures that
|
|
||||||
* these elements don't cause spurious whitespace to be added.
|
|
||||||
*/
|
|
||||||
h1>br, h2>br, h3>br,
|
|
||||||
h4>br, h5>br, h6>br { display: none; }
|
|
||||||
|
|
||||||
code, tt { font-family: "lucida typewriter", lucidatypewriter,
|
|
||||||
monospace; }
|
|
||||||
var { font-family: times, serif;
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
|
|
||||||
.Unix { font-variant: small-caps; }
|
|
||||||
|
|
||||||
.typelabel { font-family: lucida, sans-serif; }
|
|
||||||
|
|
||||||
.navigation td { background-color: #99ccff;
|
|
||||||
font-weight: bold;
|
|
||||||
font-family: avantgarde, sans-serif;
|
|
||||||
font-size: 110%; }
|
|
||||||
|
|
||||||
div.warning { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 1em;
|
|
||||||
margin-left: 2em;
|
|
||||||
margin-right: 2em; }
|
|
||||||
|
|
||||||
div.warning .label { font-family: sans-serif;
|
|
||||||
font-size: 110%;
|
|
||||||
margin-right: 0.5em; }
|
|
||||||
|
|
||||||
div.note { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 1em;
|
|
||||||
margin-left: 2em;
|
|
||||||
margin-right: 2em; }
|
|
||||||
|
|
||||||
div.note .label { margin-right: 0.5em;
|
|
||||||
font-family: sans-serif; }
|
|
||||||
|
|
||||||
address { font-size: 80%; }
|
|
||||||
.release-info { font-style: italic;
|
|
||||||
font-size: 80%; }
|
|
||||||
|
|
||||||
.titlegraphic { vertical-align: top; }
|
|
||||||
|
|
||||||
.verbatim pre { color: #00008b;
|
|
||||||
font-family: "lucida typewriter", lucidatypewriter,
|
|
||||||
monospace;
|
|
||||||
font-size: 90%; }
|
|
||||||
.verbatim { margin-left: 2em; }
|
|
||||||
.verbatim .footer { padding: 0.05in;
|
|
||||||
font-size: 85%;
|
|
||||||
background-color: #99ccff;
|
|
||||||
margin-right: 0.5in; }
|
|
||||||
|
|
||||||
.grammar { background-color: #99ccff;
|
|
||||||
margin-right: 0.5in;
|
|
||||||
padding: 0.05in; }
|
|
||||||
.grammar-footer { padding: 0.05in;
|
|
||||||
font-size: 85%; }
|
|
||||||
.grammartoken { font-family: "lucida typewriter", lucidatypewriter,
|
|
||||||
monospace; }
|
|
||||||
|
|
||||||
.productions { background-color: #bbeeff; }
|
|
||||||
.productions a:active { color: #ff0000; }
|
|
||||||
.productions a:link:hover { background-color: #99ccff; }
|
|
||||||
.productions a:visited:hover { background-color: #99ccff; }
|
|
||||||
.productions a:visited { color: #551a8b; }
|
|
||||||
.productions a:link { color: #0000bb; }
|
|
||||||
.productions table { vertical-align: baseline;
|
|
||||||
empty-cells: show; }
|
|
||||||
.productions > table td,
|
|
||||||
.productions > table th { padding: 2px; }
|
|
||||||
.productions > table td:first-child,
|
|
||||||
.productions > table td:last-child {
|
|
||||||
font-family: "lucida typewriter",
|
|
||||||
lucidatypewriter,
|
|
||||||
monospace;
|
|
||||||
}
|
|
||||||
/* same as the second selector above, but expressed differently for Opera */
|
|
||||||
.productions > table td:first-child + td + td {
|
|
||||||
font-family: "lucida typewriter",
|
|
||||||
lucidatypewriter,
|
|
||||||
monospace;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
.productions > table td:first-child + td {
|
|
||||||
padding-left: 1em;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
.productions > table tr { vertical-align: baseline; }
|
|
||||||
|
|
||||||
.email { font-family: avantgarde, sans-serif; }
|
|
||||||
.mailheader { font-family: avantgarde, sans-serif; }
|
|
||||||
.mimetype { font-family: avantgarde, sans-serif; }
|
|
||||||
.newsgroup { font-family: avantgarde, sans-serif; }
|
|
||||||
.url { font-family: avantgarde, sans-serif; }
|
|
||||||
.file { font-family: avantgarde, sans-serif; }
|
|
||||||
.guilabel { font-family: avantgarde, sans-serif; }
|
|
||||||
|
|
||||||
.realtable { border-collapse: collapse;
|
|
||||||
border-color: black;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 0px 0px 2px 0px;
|
|
||||||
empty-cells: show;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
padding-left: 0.4em;
|
|
||||||
padding-right: 0.4em;
|
|
||||||
}
|
|
||||||
.realtable tbody { vertical-align: baseline; }
|
|
||||||
.realtable tfoot { display: table-footer-group; }
|
|
||||||
.realtable thead { background-color: #99ccff;
|
|
||||||
border-width: 0px 0px 2px 1px;
|
|
||||||
display: table-header-group;
|
|
||||||
font-family: avantgarde, sans-serif;
|
|
||||||
font-weight: bold;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
.realtable thead :first-child {
|
|
||||||
border-width: 0px 0px 2px 0px;
|
|
||||||
}
|
|
||||||
.realtable thead th { border-width: 0px 0px 2px 1px }
|
|
||||||
.realtable td,
|
|
||||||
.realtable th { border-color: black;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 0px 0px 1px 1px;
|
|
||||||
padding-left: 0.4em;
|
|
||||||
padding-right: 0.4em;
|
|
||||||
}
|
|
||||||
.realtable td:first-child,
|
|
||||||
.realtable th:first-child {
|
|
||||||
border-left-width: 0px;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
.center { text-align: center; }
|
|
||||||
.left { text-align: left; }
|
|
||||||
.right { text-align: right; }
|
|
||||||
|
|
||||||
.refcount-info { font-style: italic; }
|
|
||||||
.refcount-info .value { font-weight: bold;
|
|
||||||
color: #006600; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some decoration for the "See also:" blocks, in part inspired by some of
|
|
||||||
* the styling on Lars Marius Garshol's XSA pages.
|
|
||||||
* (The blue in the navigation bars is #99CCFF.)
|
|
||||||
*/
|
|
||||||
.seealso { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 0pt 1em 4pt 1em; }
|
|
||||||
|
|
||||||
.seealso > .heading { font-size: 110%;
|
|
||||||
font-weight: bold; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class 'availability' is used for module availability statements at
|
|
||||||
* the top of modules.
|
|
||||||
*/
|
|
||||||
.availability .platform { font-weight: bold; }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Additional styles for the distutils package.
|
|
||||||
*/
|
|
||||||
.du-command { font-family: monospace; }
|
|
||||||
.du-option { font-family: avantgarde, sans-serif; }
|
|
||||||
.du-filevar { font-family: avantgarde, sans-serif;
|
|
||||||
font-style: italic; }
|
|
||||||
.du-xxx:before { content: "** ";
|
|
||||||
font-weight: bold; }
|
|
||||||
.du-xxx:after { content: " **";
|
|
||||||
font-weight: bold; }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some specialization for printed output.
|
|
||||||
*/
|
|
||||||
@media print {
|
|
||||||
.online-navigation { display: none; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
***************
|
||||||
|
PyAlsaAudio
|
||||||
|
***************
|
||||||
|
|
||||||
|
:Author: Casper Wilstrup
|
||||||
|
:Author: Lars Immisch
|
||||||
|
|
||||||
|
.. |release| replace:: 0.4
|
||||||
|
|
||||||
|
.. % At minimum, give your name and an email address. You can include a
|
||||||
|
.. % snail-mail address if you like.
|
||||||
|
|
||||||
|
.. % This makes the Abstract go on a separate page in the HTML version;
|
||||||
|
.. % if a copyright notice is used, it should go immediately after this.
|
||||||
|
.. %
|
||||||
|
|
||||||
|
|
||||||
|
.. _front:
|
||||||
|
|
||||||
|
This software is licensed under the PSF license - the same one used by the
|
||||||
|
majority of the python distribution. Basically you can use it for anything you
|
||||||
|
wish (even commercial purposes). There is no warranty whatsoever.
|
||||||
|
|
||||||
|
.. % Copyright statement should go here, if needed.
|
||||||
|
|
||||||
|
.. % The abstract should be a paragraph or two long, and describe the
|
||||||
|
.. % scope of the document.
|
||||||
|
|
||||||
|
|
||||||
|
.. topic:: 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 our 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.
|
||||||
|
|
||||||
|
|
||||||
|
************
|
||||||
|
What is ALSA
|
||||||
|
************
|
||||||
|
|
||||||
|
The Advanced Linux Sound Architecture (ALSA) provides audio and MIDI
|
||||||
|
functionality to the Linux operating system.
|
||||||
|
|
||||||
|
Logically ALSA consists of these components:
|
||||||
|
|
||||||
|
* A set of kernel drivers. --- These drivers are responsible for handling the
|
||||||
|
physical sound hardware from within the Linux kernel, and have been the
|
||||||
|
standard sound implementation in Linux since kernel version 2.5
|
||||||
|
|
||||||
|
* A kernel level API for manipulating the ALSA devices.
|
||||||
|
|
||||||
|
* A user-space C library for simplified access to the sound hardware from
|
||||||
|
userspace applications. This library is called *libasound* and is required by
|
||||||
|
all ALSA capable applications.
|
||||||
|
|
||||||
|
More information about ALSA may be found on the project homepage
|
||||||
|
`<http://www.alsa-project.org>`_
|
||||||
|
|
||||||
|
|
||||||
|
ALSA and Python
|
||||||
|
===============
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 looks currently unlikely.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
************
|
||||||
|
Installation
|
||||||
|
************
|
||||||
|
|
||||||
|
Note: the wrappers link with the alsasound library (from the alsa-lib 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: --- ::
|
||||||
|
|
||||||
|
$ python setup.py build
|
||||||
|
|
||||||
|
And then as root: --- ::
|
||||||
|
|
||||||
|
# python setup.py install
|
||||||
|
Before Width: | Height: | Size: 125 B |
|
Before Width: | Height: | Size: 240 B |
@@ -1,23 +0,0 @@
|
|||||||
# Makefile for PyAlsaAudio documentation
|
|
||||||
#
|
|
||||||
# In order to use this you need an unpacked version of the
|
|
||||||
# Python source available. Set the source path below
|
|
||||||
#
|
|
||||||
# You also need a working latex installation, and the latex2html
|
|
||||||
# tool installed.
|
|
||||||
PYTHONSOURCE = /usr/local/src/Python-2.5.1/
|
|
||||||
SFUSER = larsimmisch
|
|
||||||
|
|
||||||
# Shouldn't need to change anything below here!
|
|
||||||
|
|
||||||
MKHOWTO = $(PYTHONSOURCE)/Doc/tools/mkhowto
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(MKHOWTO) --dir .. --html pyalsaaudio.tex
|
|
||||||
python sffixup.py ../index.html
|
|
||||||
|
|
||||||
text:
|
|
||||||
$(MKHOWTO) --dir .. --text pyalsaaudio.tex
|
|
||||||
|
|
||||||
install:
|
|
||||||
scp ../*.html ../*.gif ../*.png $(SFUSER)@shell.sourceforge.net:/home/groups/p/py/pyalsaaudio/htdocs
|
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
\section{\module{alsaaudio}}
|
|
||||||
|
|
||||||
%\declaremodule{builtin}{alsaaudio} % standard library, in C
|
|
||||||
\declaremodule{extension}{alsaaudio} % not standard, in C
|
|
||||||
|
|
||||||
\platform{Linux}
|
|
||||||
|
|
||||||
\moduleauthor{Casper Wilstrup}{cwi@aves.dk} % Author of the module code;
|
|
||||||
|
|
||||||
|
|
||||||
\modulesynopsis{ALSA sound support}
|
|
||||||
|
|
||||||
|
|
||||||
The \module{alsaaudio} module defines functions and classes for using
|
|
||||||
ALSA.
|
|
||||||
|
|
||||||
% ---- 3.1. ----
|
|
||||||
% For each function, use a ``funcdesc'' block. This has exactly two
|
|
||||||
% parameters (each parameters is contained in a set of curly braces):
|
|
||||||
% the first parameter is the function name (this automatically
|
|
||||||
% generates an index entry); the second parameter is the function's
|
|
||||||
% argument list. If there are no arguments, use an empty pair of
|
|
||||||
% curly braces. If there is more than one argument, separate the
|
|
||||||
% arguments with backslash-comma. Optional parts of the parameter
|
|
||||||
% list are contained in \optional{...} (this generates a set of square
|
|
||||||
% brackets around its parameter). Arguments are automatically set in
|
|
||||||
% italics in the parameter list. Each argument should be mentioned at
|
|
||||||
% least once in the description; each usage (even inside \code{...})
|
|
||||||
% should be enclosed in \var{...}.
|
|
||||||
|
|
||||||
\begin{funcdesc}{mixers}{\optional{cardname}}
|
|
||||||
List the available mixers. The optional \var{cardname} specifies which
|
|
||||||
card should be queried (this is only relevant if you have more than one
|
|
||||||
sound card). Omit to use the default sound card.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{classdesc}{PCM}{\optional{type}, \optional{mode}, \optional{cardname}}
|
|
||||||
This class is used to represent a PCM device (both playback and
|
|
||||||
capture devices).
|
|
||||||
The arguments are: \\
|
|
||||||
\var{type} - can be either PCM_CAPTURE or PCM_PLAYBACK (default). \\
|
|
||||||
\var{mode} - can be either PCM_NONBLOCK, PCM_ASYNC, or PCM_NORMAL (the default).\\
|
|
||||||
\var{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
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
\begin{classdesc}{Mixer}{\optional{control}, \optional{id}, \optional{cardname}}
|
|
||||||
This class is used to access a specific ALSA mixer.
|
|
||||||
The arguments are: \\
|
|
||||||
\var{control} - Name of the chosen mixed (default is Master). \\
|
|
||||||
\var{id} - id of mixer (default is 0) -- More explanation needed here\\
|
|
||||||
\var{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
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\begin{excdesc}{ALSAAudioError}
|
|
||||||
Exception raised when an operation fails for a ALSA specific reason.
|
|
||||||
The exception argument is a string describing the reason of the
|
|
||||||
failure.
|
|
||||||
\end{excdesc}
|
|
||||||
|
|
||||||
\subsection{PCM Terminology and Concepts}
|
|
||||||
|
|
||||||
In order to use PCM devices it is useful to be familiar with some concepts and
|
|
||||||
terminology.
|
|
||||||
|
|
||||||
\begin{description}
|
|
||||||
\item[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.
|
|
||||||
|
|
||||||
\item[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.
|
|
||||||
|
|
||||||
\item[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
|
|
||||||
|
|
||||||
\item[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.
|
|
||||||
|
|
||||||
\item[Data 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
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
\item[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.
|
|
||||||
|
|
||||||
\item[Period size] This is the size of each period in Hz. \emph{Not
|
|
||||||
bytes, but Hz!.} In \module{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.
|
|
||||||
|
|
||||||
\end{description}
|
|
||||||
|
|
||||||
Once you understand these concepts, you will be ready to use the PCM
|
|
||||||
API. Read on.
|
|
||||||
|
|
||||||
\subsection{PCM Objects}
|
|
||||||
\label{pcm-objects}
|
|
||||||
|
|
||||||
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 \module{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:
|
|
||||||
|
|
||||||
\begin{classdesc}{PCM}{\optional{type}, \optional{mode}, \optional{cardname}}
|
|
||||||
|
|
||||||
\var{type} - can be either PCM_CAPTURE or PCM_PLAYBACK (default).
|
|
||||||
|
|
||||||
\var{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 \module{alsaaudio} PCM_ASYNC is useless,
|
|
||||||
since it relies on a callback procedure, which can't be specified through
|
|
||||||
this API yet.
|
|
||||||
|
|
||||||
\var{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:
|
|
||||||
|
|
||||||
Sample format: PCM_FORMAT_S16_LE \\
|
|
||||||
Rate: 8000 Hz \\
|
|
||||||
Channels: 2 \\
|
|
||||||
Period size: 32 frames \\
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
PCM objects have the following methods:
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{pcmtype}{}
|
|
||||||
Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{pcmmode}{}
|
|
||||||
Return the mode of the PCM object. One of PCM_NONBLOCK, PCM_ASYNC,
|
|
||||||
or PCM_NORMAL
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{cardname}{}
|
|
||||||
Return the name of the sound card used by this PCM object.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{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
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{setrate}{rate}
|
|
||||||
Set the sample rate in Hz for the device. Typical values are 8000
|
|
||||||
(poor sound), 16000, 44100 (cd quality), and 96000
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{setformat}{format}
|
|
||||||
The sound \var{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:
|
|
||||||
\begin{tableii}{l|l}{Formats}{Format}{Description}
|
|
||||||
\lineii{PCM_FORMAT_S8}{Signed 8 bit samples for each channel}
|
|
||||||
\lineii{PCM_FORMAT_U8}{Signed 8 bit samples for each channel}
|
|
||||||
\lineii{PCM_FORMAT_S16_LE}{Signed 16 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_S16_BE}{Signed 16
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U16_LE}{Unsigned 16 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U16_BE}{Unsigned 16
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_S24_LE}{Signed 24 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_S24_BE}{Signed 24
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U24_LE}{Unsigned 24 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U24_BE}{Unsigned 24
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_S32_LE}{Signed 32 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_S32_BE}{Signed 32
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U32_LE}{Unsigned 32 bit samples for each channel
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_U32_BE}{Unsigned 32
|
|
||||||
bit samples for each channel (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_FLOAT_LE}{32 bit samples encoded as float.
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_FLOAT_BE}{32 bit
|
|
||||||
samples encoded as float (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_FLOAT64_LE}{64 bit samples encoded as float.
|
|
||||||
(Little Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_FLOAT64_BE}{64 bit
|
|
||||||
samples encoded as float. (Big Endian byte order)}
|
|
||||||
\lineii{PCM_FORMAT_MU_LAW}{A logarithmic encoding (used by Sun .au
|
|
||||||
files)}
|
|
||||||
\lineii{PCM_FORMAT_A_LAW}{Another logarithmic encoding}
|
|
||||||
\lineii{PCM_FORMAT_IMA_ADPCM}{a 4:1 compressed format defined by the
|
|
||||||
Interactive Multimedia Association} \lineii{PCM_FORMAT_MPEG}{MPEG
|
|
||||||
encoded audio?}
|
|
||||||
\lineii{PCM_FORMAT_GSM}{9600 bits/s constant rate encoding for speech}
|
|
||||||
\end{tableii}
|
|
||||||
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{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)
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{read}{}
|
|
||||||
In PCM_NORMAL mode, this function blocks until a full period is
|
|
||||||
available, and then returns a tuple (length,data) where
|
|
||||||
\emph{length} is the number of frames of captured data, and
|
|
||||||
\emph{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
|
|
||||||
\code{(0,'')} if no new period has become available since the last
|
|
||||||
call to read.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{write}{data}
|
|
||||||
Writes (plays) the sound in data. The length of data \emph{must} be
|
|
||||||
a multiple of the frame size, and \emph{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
|
|
||||||
|
|
||||||
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.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[PCM]{pause}{\optional{enable=1}}
|
|
||||||
If \var{enable} is 1, playback or capture is paused. If \var{enable} is 0,
|
|
||||||
playback/capture is resumed.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\strong{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 \emph{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 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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
\subsection{Mixer Objects}
|
|
||||||
\label{mixer-objects}
|
|
||||||
|
|
||||||
Mixer objects provides access to the ALSA mixer API.
|
|
||||||
|
|
||||||
\begin{classdesc}{Mixer}{\optional{control}, \optional{id},
|
|
||||||
\optional{cardname}}
|
|
||||||
\var{control} - specifies which control to manipulate using this
|
|
||||||
mixer object. The list of available controls can be found with the
|
|
||||||
\module{alsaaudio}.\function{mixers} function. The default value is
|
|
||||||
'Master' - other common controls include 'Master Mono', 'PCM',
|
|
||||||
'Line', etc.
|
|
||||||
|
|
||||||
\var{id} - the id of the mixer control. Default is 0
|
|
||||||
|
|
||||||
\var{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
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
Mixer objects have the following methods:
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{cardname}{}
|
|
||||||
Return the name of the sound card used by this Mixer object
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{mixer}{}
|
|
||||||
Return the name of the specific mixer controlled by this object, For
|
|
||||||
example 'Master' or 'PCM'
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{mixerid}{}
|
|
||||||
Return the ID of the ALSA mixer controlled by this object.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{switchcap}{}
|
|
||||||
Returns a list of the switches which are defined by this specific
|
|
||||||
mixer. Possible values in this list are:
|
|
||||||
|
|
||||||
\begin{tableii}{l|l}{Switches}{Switch}{Description}
|
|
||||||
\lineii{'Mute'}{This mixer can be muted}
|
|
||||||
\lineii{'Joined Mute'}{This mixer can mute all channels at the same time}
|
|
||||||
\lineii{'Playback Mute'}{This mixer can mute the playback output}
|
|
||||||
\lineii{'Joined Playback Mute'}
|
|
||||||
{Mute playback for all channels at the same time}
|
|
||||||
\lineii{'Capture Mute'}{Mute sound capture}
|
|
||||||
\lineii{'Joined Capture Mute'}{Mute sound capture for all channels at a time}
|
|
||||||
\lineii{'Capture Exclusive'}{Not quite sure what this is}
|
|
||||||
\end{tableii}
|
|
||||||
|
|
||||||
To manipulate these swithes use the \method{setrec} or
|
|
||||||
\method{setmute} methods
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{volumecap}{}
|
|
||||||
Returns a list of the volume control capabilities of this mixer.
|
|
||||||
Possible values in the list are:
|
|
||||||
|
|
||||||
\begin{tableii}{l|l}{Volume Capabilities}{Capability}{Description}
|
|
||||||
\lineii{'Volume'}{This mixer can control volume}
|
|
||||||
\lineii{'Joined Volume'}{This mixer can control volume for all channels at
|
|
||||||
the same time}
|
|
||||||
\lineii{'Playback Volume'}{This mixer can manipulate the playback volume}
|
|
||||||
\lineii{'Joined Playback Volume'}{Manipulate playback volumne for all
|
|
||||||
channels at the same time}
|
|
||||||
\lineii{'Capture Volume'}{Manipulate sound capture volume}
|
|
||||||
\lineii{'Joined Capture Volume'}{Manipulate sound capture volume for all
|
|
||||||
channels at a time}
|
|
||||||
\end{tableii}
|
|
||||||
|
|
||||||
\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.
|
|
||||||
|
|
||||||
The optional \var{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'
|
|
||||||
|
|
||||||
\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.
|
|
||||||
|
|
||||||
The optional \var{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'
|
|
||||||
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{setvolume}{volume,\optional{channel},
|
|
||||||
\optional{direction}}
|
|
||||||
|
|
||||||
Change the current volume settings for this mixer. The \var{volume}
|
|
||||||
argument controls the new volume setting as an integer percentage.
|
|
||||||
|
|
||||||
If the optional argument \var{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 \var{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'.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{setmute}{mute, \optional{channel}}
|
|
||||||
Sets the mute flag to a new value. The \var{mute} argument is either
|
|
||||||
0 for not muted, or 1 for muted.
|
|
||||||
|
|
||||||
The optional \var{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
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[Mixer]{setrec}{capture,\optional{channel}}
|
|
||||||
Sets the capture mute flag to a new value. The \var{capture}
|
|
||||||
argument is either 0 for no capture, or 1 for capture.
|
|
||||||
|
|
||||||
The optional \var{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.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
|
|
||||||
\textbf{A Note on the ALSA Mixer API}
|
|
||||||
|
|
||||||
The ALSA mixer API is extremely complicated - and hardly documented at
|
|
||||||
all. \module{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 \module{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 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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
% ==== 4. ====
|
|
||||||
\subsection{ALSA Examples \label{pcm-example}}
|
|
||||||
|
|
||||||
For now, the only examples available are the 'playbacktest.py' and the
|
|
||||||
'recordtest.py' programs included. This will change in a future
|
|
||||||
version.
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
\documentclass{howto}
|
|
||||||
|
|
||||||
\title{PyAlsaAudio}
|
|
||||||
|
|
||||||
\release{0.4}
|
|
||||||
|
|
||||||
% At minimum, give your name and an email address. You can include a
|
|
||||||
% snail-mail address if you like.
|
|
||||||
\author{Casper Wilstrup}
|
|
||||||
\authoraddress{cwi@aves.dk}
|
|
||||||
|
|
||||||
\begin{document}
|
|
||||||
\maketitle
|
|
||||||
|
|
||||||
% This makes the Abstract go on a separate page in the HTML version;
|
|
||||||
% if a copyright notice is used, it should go immediately after this.
|
|
||||||
%
|
|
||||||
\ifhtml
|
|
||||||
\chapter*{Front Matter\label{front}}
|
|
||||||
\fi
|
|
||||||
|
|
||||||
% Copyright statement should go here, if needed.
|
|
||||||
This software is licensed under the PSF license - the same one used
|
|
||||||
by the majority of the python distribution. Basically you can use it
|
|
||||||
for anything you wish (even commercial purposes). There is no warranty
|
|
||||||
whatsoever.
|
|
||||||
|
|
||||||
% The abstract should be a paragraph or two long, and describe the
|
|
||||||
% scope of the document.
|
|
||||||
\begin{abstract}
|
|
||||||
\noindent
|
|
||||||
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.
|
|
||||||
\end{abstract}
|
|
||||||
|
|
||||||
\tableofcontents
|
|
||||||
|
|
||||||
\section{What is ALSA}
|
|
||||||
|
|
||||||
The Advanced Linux Sound Architecture (ALSA) provides audio and MIDI
|
|
||||||
functionality to the Linux operating system.
|
|
||||||
|
|
||||||
Logically ALSA consists of these components:
|
|
||||||
\begin{itemize}
|
|
||||||
\item A set of kernel drivers.\\
|
|
||||||
These drivers are responsible for handling the physical sound
|
|
||||||
hardware from within the Linux kernel, and have been the standard
|
|
||||||
sound implementation in Linux since kernel version 2.5
|
|
||||||
\item A kernel level API for manipulating the ALSA devices.
|
|
||||||
\item A user-space C library for simplified access to the sound hardware
|
|
||||||
from userspace applications. This library is called \textit{libasound}
|
|
||||||
and is required by all ALSA capable applications.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
More information about ALSA may be found on the project homepage
|
|
||||||
\url{http://www.alsa-project.org}
|
|
||||||
|
|
||||||
\section{ALSA and Python}
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
\section{Installation}
|
|
||||||
|
|
||||||
Note: the wrappers link with the alsasound library (from the alsa-lib
|
|
||||||
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: \\
|
|
||||||
\begin{verbatim}
|
|
||||||
$ python setup.py build
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
And then as root: \\
|
|
||||||
\begin{verbatim}
|
|
||||||
# python setup.py install
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
\input{libalsaaudio}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\end{document}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/usr/bin/env/python
|
|
||||||
|
|
||||||
# This is a hack and totally brittle. Let's not talk about it.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sfnotes = '''<ul>
|
|
||||||
<li><a href="http://sourceforge.net/">SourceForge</li>
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://sourceforge.net/projects/pyalsaaudio/">Summary page</a>
|
|
||||||
<li><a href="http://sourceforge.net/project/showfiles.php?group_id=120651">Download</a>
|
|
||||||
<li><a href="http://sourceforge.net/tracker/?group_id=120651">Bug Tracker</a>
|
|
||||||
</ul>
|
|
||||||
</ul>'''
|
|
||||||
|
|
||||||
if len(sys.argv) <= 1:
|
|
||||||
print "usage: sffixup.py <file>"
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
f = open(sys.argv[1], 'r')
|
|
||||||
lines = f.readlines()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
index = lines.index('<a name="CHILD_LINKS"></a>\n')
|
|
||||||
except ValueError:
|
|
||||||
print "Cannot find child links. SourceForge links will not appear on index.html."
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
lines.insert(index, sfnotes)
|
|
||||||
|
|
||||||
f = open(sys.argv[1], 'w')
|
|
||||||
for l in lines:
|
|
||||||
f.write(l)
|
|
||||||
f.close()
|
|
||||||
|
Before Width: | Height: | Size: 316 B |
|
Before Width: | Height: | Size: 577 B |
@@ -1,4 +1,4 @@
|
|||||||
## recordtest.py
|
## playbacktest.py
|
||||||
##
|
##
|
||||||
## This is an example of a simple sound playback script.
|
## This is an example of a simple sound playback script.
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Simple test script that plays (some) wav files
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
import alsaaudio
|
||||||
|
|
||||||
|
# this is all a bit simplified, and won't cope with any wav extensions
|
||||||
|
# or multiple data chunks, but it's good enough here
|
||||||
|
|
||||||
|
WAV_FORMAT_PCM = 1
|
||||||
|
WAV_FORMAT_ALAW = 6
|
||||||
|
WAV_FORMAT_MULAW = 7
|
||||||
|
WAV_HEADER = '<4sl4s4slhhllhh4sl'
|
||||||
|
WAV_HEADER_SIZE = struct.calcsize(WAV_HEADER)
|
||||||
|
|
||||||
|
def _b(s):
|
||||||
|
'Helper for 3.0 compatibility'
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
return bytes(s, 'UTF-8')
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def wav_header_unpack(data):
|
||||||
|
(riff, riffsize, wave, fmt, fmtsize, format, nchannels, framerate,
|
||||||
|
datarate, blockalign, bitspersample, data, datalength) \
|
||||||
|
= struct.unpack(WAV_HEADER, data)
|
||||||
|
|
||||||
|
print(data)
|
||||||
|
|
||||||
|
if riff != _b('RIFF') or fmtsize != 16 or fmt != _b('fmt ') \
|
||||||
|
or data != _b('data'):
|
||||||
|
raise ValueError('wav header too complicated')
|
||||||
|
|
||||||
|
return (format, nchannels, framerate, bitspersample, datalength)
|
||||||
|
|
||||||
|
def play(device, f):
|
||||||
|
header = f.read(WAV_HEADER_SIZE)
|
||||||
|
format, nchannels, framerate, bitspersample, datalength \
|
||||||
|
= wav_header_unpack(header)
|
||||||
|
|
||||||
|
# Set attributes
|
||||||
|
device.setchannels(nchannels)
|
||||||
|
device.setrate(framerate)
|
||||||
|
|
||||||
|
# We assume signed data, little endian
|
||||||
|
if format == WAV_FORMAT_PCM:
|
||||||
|
if bitspersample == 8:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_S8)
|
||||||
|
elif bitspersample == 16:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_S16_LE)
|
||||||
|
elif bitspersample == 24:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_S24_LE)
|
||||||
|
elif bitspersample == 32:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_S32_LE)
|
||||||
|
elif format == WAV_FORMAT_ALAW:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_A_LAW)
|
||||||
|
elif format == WAV_FORMAT_MULAW:
|
||||||
|
device.setformat(alsaaudio.PCM_FORMAT_MU_LAW)
|
||||||
|
else:
|
||||||
|
raise ValueError('Unsupported format %d' % format)
|
||||||
|
|
||||||
|
# The period size controls the internal number of frames per period.
|
||||||
|
# The significance of this parameter is documented in the ALSA api.
|
||||||
|
|
||||||
|
# rs = framerate / 25
|
||||||
|
# out.setperiodsize(rs)
|
||||||
|
|
||||||
|
data = f.read()
|
||||||
|
while data:
|
||||||
|
# Read data from stdin
|
||||||
|
device.write(data)
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print('usage: playwav.py <file>')
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
f = open(sys.argv[1], 'rb')
|
||||||
|
device = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK)
|
||||||
|
|
||||||
|
play(device, f)
|
||||||
|
|
||||||
|
f.close()
|
||||||