diff --git a/CHANGES b/CHANGES index d528334..63798b3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Version 0.4: +- Support for Python 3.0 +- Documentation in reStructuredText; use Sphinx instead of LaTeX. - added mixer.getenum() -- small documentation improvements + Version 0.3: - wrapped blocking calls with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS diff --git a/README b/README index cb8dceb..84799cb 100644 --- a/README +++ b/README @@ -41,7 +41,7 @@ And then as root: 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 distribution. diff --git a/alsaaudio.c b/alsaaudio.c index c96fe05..89ec8c3 100644 --- a/alsaaudio.c +++ b/alsaaudio.c @@ -5,7 +5,7 @@ * The standard audio API for Linux since kernel 2.6 * * 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 * @@ -14,7 +14,10 @@ */ #include "Python.h" +#if PY_MAJOR_VERSION < 3 #include "stringobject.h" +#define PyUnicode_FromString PyString_FromString +#endif #include #include @@ -237,8 +240,8 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) { val = snd_pcm_hw_params_get_sbits(hwparams); printf("significant bits = %d\n", val); - snd_pcm_hw_params_get_tick_time(hwparams, &val, &dir); - printf("tick time = %d us\n", val); + snd_pcm_hw_params_get_period_time(hwparams, &val, &dir); + printf("period time = %d us\n", val); val = snd_pcm_hw_params_is_batch(hwparams); printf("is batch = %d\n", val); @@ -305,7 +308,7 @@ Returns the mode of the PCM object. One of:\n\ static PyObject * alsapcm_cardname(alsapcm_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":cardname")) return NULL; - return PyString_FromString(self->cardname); + return PyUnicode_FromString(self->cardname); } PyDoc_STRVAR(cardname_doc, @@ -429,12 +432,16 @@ alsapcm_read(alsapcm_t *self, PyObject *args) { res = 0; } else if (res < 0) { - PyErr_SetString(ALSAAudioError,snd_strerror(res)); + PyErr_SetString(ALSAAudioError, snd_strerror(res)); 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, @@ -443,19 +450,33 @@ PyDoc_STRVAR(read_doc, 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\ 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\ -periodsize*framesize bytes.\n\ +frames as bytes (or a string in Python 2.x). The length of the returned data\n\ + will be periodsize*framesize bytes.\n\ \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."); static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) { - char *data; - int datalen; + int res; - if (!PyArg_ParseTuple(args,"s#:write",&data,&datalen)) return NULL; - if (datalen%self->framesize) { + int datalen; + 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, "Data size must be a multiple of framesize"); return NULL; @@ -548,8 +569,12 @@ alsapcm_getattr(alsapcm_t *self, char *name) { #endif static PyTypeObject ALSAPCMType = { +#if PY_MAJOR_VERSION < 3 PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ +#else + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#endif "alsaaudio.PCM", /* tp_name */ sizeof(alsapcm_t), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -647,7 +672,7 @@ alsamixer_list(PyObject *self, PyObject *args) { { PyObject *mixer; 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); Py_DECREF(mixer); } @@ -788,7 +813,7 @@ static void alsamixer_dealloc(alsamixer_t *self) { static PyObject * alsamixer_cardname(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":cardname")) return NULL; - return PyString_FromString(self->cardname); + return PyUnicode_FromString(self->cardname); } PyDoc_STRVAR(mixer_cardname_doc, @@ -800,7 +825,7 @@ Returns the name of the sound card used by this Mixer object."); static PyObject * alsamixer_mixer(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":mixer")) return NULL; - return PyString_FromString(self->controlname); + return PyUnicode_FromString(self->controlname); } PyDoc_STRVAR(mixer_doc, @@ -828,17 +853,17 @@ alsamixer_volumecap(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":volumecap")) return NULL; result = PyList_New(0); 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) - PyList_Append(result,PyString_FromString("Joined Volume")); + PyList_Append(result,PyUnicode_FromString("Joined Volume")); 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) - PyList_Append(result,PyString_FromString("Joined Playback Volume")); + PyList_Append(result,PyUnicode_FromString("Joined Playback Volume")); 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) - PyList_Append(result,PyString_FromString("Joined Capture Volume")); + PyList_Append(result,PyUnicode_FromString("Joined Capture Volume")); return result; } @@ -862,19 +887,19 @@ alsamixer_switchcap(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":switchcap")) return NULL; result = PyList_New(0); 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) - PyList_Append(result,PyString_FromString("Joined Mute")); + PyList_Append(result,PyUnicode_FromString("Joined Mute")); 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) - PyList_Append(result,PyString_FromString("Joined Playback Mute")); + PyList_Append(result,PyUnicode_FromString("Joined Playback Mute")); 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) - PyList_Append(result,PyString_FromString("Joined Capture Mute")); + PyList_Append(result,PyUnicode_FromString("Joined Capture Mute")); if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE) - PyList_Append(result,PyString_FromString("Capture Exclusive")); + PyList_Append(result,PyUnicode_FromString("Capture Exclusive")); return result; } @@ -1064,7 +1089,7 @@ alsamixer_getenum(alsamixer_t *self, PyObject *args) { return NULL; } - PyTuple_SetItem(result, 0, PyString_FromString(name)); + PyTuple_SetItem(result, 0, PyUnicode_FromString(name)); elems = PyList_New(count); if (!elems) @@ -1082,7 +1107,7 @@ alsamixer_getenum(alsamixer_t *self, PyObject *args) { return NULL; } - PyList_SetItem(elems, i, PyString_FromString(name)); + PyList_SetItem(elems, i, PyUnicode_FromString(name)); } PyTuple_SetItem(result, 1, elems); @@ -1339,8 +1364,12 @@ alsamixer_getattr(alsapcm_t *self, char *name) { #endif static PyTypeObject ALSAMixerType = { +#if PY_MAJOR_VERSION < 3 PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ +#else + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#endif "alsaaudio.Mixer", /* tp_name */ sizeof(alsamixer_t), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1390,32 +1419,73 @@ static PyMethodDef alsaaudio_methods[] = { { 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) \ 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; ALSAPCMType.tp_new = alsapcm_new; ALSAMixerType.tp_new = alsamixer_new; 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); - if (ALSAAudioError) { - /* Each call to PyModule_AddObject decrefs it; compensate: */ + if (!ALSAAudioError) +#if PY_MAJOR_VERSION < 3 + return; +#else + return NULL; +#endif - Py_INCREF(&ALSAPCMType); - PyModule_AddObject(m,"PCM",(PyObject *)&ALSAPCMType); + /* Each call to PyModule_AddObject decrefs it; compensate: */ - Py_INCREF(&ALSAMixerType); - PyModule_AddObject(m,"Mixer",(PyObject *)&ALSAMixerType); - - Py_INCREF(ALSAAudioError); - PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError); - } + Py_INCREF(&ALSAPCMType); + PyModule_AddObject(m, "PCM", (PyObject *)&ALSAPCMType); + + Py_INCREF(&ALSAMixerType); + 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_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_MONO", SND_MIXER_SCHN_MONO); #endif + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif } diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..e01e8b8 --- /dev/null +++ b/doc/Makefile @@ -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 ' where 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 diff --git a/doc/about.html b/doc/about.html deleted file mode 100644 index cd7bf76..0000000 --- a/doc/about.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - -About this document ... - - - - - -

-About this document ... -

- PyAlsaAudio -

This document was generated using the - LaTeX2HTML translator. -

- -

- LaTeX2HTML is Copyright © - 1993, 1994, 1995, 1996, 1997, Nikos - Drakos, Computer Based Learning Unit, University of - Leeds, and Copyright © 1997, 1998, Ross - Moore, Mathematics Department, Macquarie University, - Sydney. -

- -

The application of - LaTeX2HTML to the Python - documentation has been heavily tailored by Fred L. Drake, - Jr. Original navigation icons were contributed by Christopher - Petrilli. -

- - - - - - diff --git a/doc/blank.gif b/doc/blank.gif deleted file mode 100644 index 2e31f4e..0000000 Binary files a/doc/blank.gif and /dev/null differ diff --git a/doc/blank.png b/doc/blank.png deleted file mode 100644 index 2af5639..0000000 Binary files a/doc/blank.png and /dev/null differ diff --git a/doc/contents.gif b/doc/contents.gif deleted file mode 100644 index 6d299c4..0000000 Binary files a/doc/contents.gif and /dev/null differ diff --git a/doc/contents.html b/doc/contents.html deleted file mode 100644 index 5852aa3..0000000 --- a/doc/contents.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - - -Contents - - - - -

-Contents -

- - - - -

- -

- - - - diff --git a/doc/contents.png b/doc/contents.png deleted file mode 100644 index 3429be0..0000000 Binary files a/doc/contents.png and /dev/null differ diff --git a/doc/front.html b/doc/front.html deleted file mode 100644 index 4941ef5..0000000 --- a/doc/front.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - - - -Front Matter - - - - - -

-
-Front Matter -

- -

-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. - -

- -

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. - -

-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. -

-

- -

- -

- - - - diff --git a/doc/index.gif b/doc/index.gif deleted file mode 100644 index 32eecfb..0000000 Binary files a/doc/index.gif and /dev/null differ diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index 7a4dcea..0000000 --- a/doc/index.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - -PyAlsaAudio - - - - - -
-
-

PyAlsaAudio

-

Casper Wilstrup

-

cwi@aves.dk

-

-
-
- -

- -



- - - - - - - diff --git a/doc/index.png b/doc/index.png deleted file mode 100644 index cd918af..0000000 Binary files a/doc/index.png and /dev/null differ diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..b89500d --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,25 @@ +alsaaudio documentation +======================= + +.. toctree:: + :maxdepth: 2 + + pyalsaaudio + libalsaaudio + + +SourceForge pages +================= + +* `Project page `_ +* `Download `_ +* `Bug tracker `_ + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/libalsaaudio.rst b/doc/libalsaaudio.rst new file mode 100644 index 0000000..93fd7dc --- /dev/null +++ b/doc/libalsaaudio.rst @@ -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 +.. moduleauthor:: Lars Immisch + + +.. % 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. + diff --git a/doc/modules.gif b/doc/modules.gif deleted file mode 100644 index f5860b6..0000000 Binary files a/doc/modules.gif and /dev/null differ diff --git a/doc/modules.png b/doc/modules.png deleted file mode 100644 index 8fa8b75..0000000 Binary files a/doc/modules.png and /dev/null differ diff --git a/doc/next.gif b/doc/next.gif deleted file mode 100644 index 5dcaff8..0000000 Binary files a/doc/next.gif and /dev/null differ diff --git a/doc/next.png b/doc/next.png deleted file mode 100644 index cfe5e51..0000000 Binary files a/doc/next.png and /dev/null differ diff --git a/doc/previous.gif b/doc/previous.gif deleted file mode 100644 index de1da16..0000000 Binary files a/doc/previous.gif and /dev/null differ diff --git a/doc/previous.png b/doc/previous.png deleted file mode 100644 index 497def4..0000000 Binary files a/doc/previous.png and /dev/null differ diff --git a/doc/pyalsaaudio.css b/doc/pyalsaaudio.css deleted file mode 100644 index 06a613c..0000000 --- a/doc/pyalsaaudio.css +++ /dev/null @@ -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
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; } - } diff --git a/doc/pyalsaaudio.rst b/doc/pyalsaaudio.rst new file mode 100644 index 0000000..0cda8e0 --- /dev/null +++ b/doc/pyalsaaudio.rst @@ -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 +``_ + + +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 diff --git a/doc/pyfav.gif b/doc/pyfav.gif deleted file mode 100644 index 58271ed..0000000 Binary files a/doc/pyfav.gif and /dev/null differ diff --git a/doc/pyfav.png b/doc/pyfav.png deleted file mode 100644 index d2d8669..0000000 Binary files a/doc/pyfav.png and /dev/null differ diff --git a/doc/src/Makefile b/doc/src/Makefile deleted file mode 100644 index 0536f40..0000000 --- a/doc/src/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/doc/src/libalsaaudio.tex b/doc/src/libalsaaudio.tex deleted file mode 100644 index 784834e..0000000 --- a/doc/src/libalsaaudio.tex +++ /dev/null @@ -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. diff --git a/doc/src/pyalsaaudio.tex b/doc/src/pyalsaaudio.tex deleted file mode 100644 index bfb0a54..0000000 --- a/doc/src/pyalsaaudio.tex +++ /dev/null @@ -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} diff --git a/doc/src/sffixup.py b/doc/src/sffixup.py deleted file mode 100644 index 4a8a635..0000000 --- a/doc/src/sffixup.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env/python - -# This is a hack and totally brittle. Let's not talk about it. - -import sys - -sfnotes = '''''' - -if len(sys.argv) <= 1: - print "usage: sffixup.py " - sys.exit(2) - -f = open(sys.argv[1], 'r') -lines = f.readlines() -f.close() - -try: - index = lines.index('\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() diff --git a/doc/up.gif b/doc/up.gif deleted file mode 100644 index a9d3e13..0000000 Binary files a/doc/up.gif and /dev/null differ diff --git a/doc/up.png b/doc/up.png deleted file mode 100644 index a90e028..0000000 Binary files a/doc/up.png and /dev/null differ diff --git a/playbacktest.py b/playbacktest.py index 06e0fe9..af7e2cf 100644 --- a/playbacktest.py +++ b/playbacktest.py @@ -1,4 +1,4 @@ -## recordtest.py +## playbacktest.py ## ## This is an example of a simple sound playback script. ## diff --git a/playwav.py b/playwav.py new file mode 100755 index 0000000..d8a3a5f --- /dev/null +++ b/playwav.py @@ -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 ') + sys.exit(2) + + f = open(sys.argv[1], 'rb') + device = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK) + + play(device, f) + + f.close()