diff options
Diffstat (limited to 'arch_src/pyalsaaudio-0.2/.svn')
35 files changed, 1482 insertions, 0 deletions
diff --git a/arch_src/pyalsaaudio-0.2/.svn/README.txt b/arch_src/pyalsaaudio-0.2/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/arch_src/pyalsaaudio-0.2/.svn/dir-wcprops b/arch_src/pyalsaaudio-0.2/.svn/dir-wcprops new file mode 100644 index 0000000..3a0f0d0 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/dir-wcprops @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/Shtoom/!svn/ver/1322/trunk/audio/pyalsaaudio +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/empty-file b/arch_src/pyalsaaudio-0.2/.svn/empty-file new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/empty-file diff --git a/arch_src/pyalsaaudio-0.2/.svn/entries b/arch_src/pyalsaaudio-0.2/.svn/entries new file mode 100644 index 0000000..d3f4356 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/entries @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?> +<wc-entries + xmlns="svn:"> +<entry + committed-rev="1322" + name="" + committed-date="2005-03-30T20:44:55.828503Z" + url="http://casperr@divmod.org/svn/Shtoom/trunk/audio/pyalsaaudio" + last-author="casper" + kind="dir" + uuid="0b994b0e-dcd6-0310-80a8-c5aa5be65e87" + revision="1584"/> +<entry + committed-rev="1585" + name="LICENSE" + text-time="2005-07-09T21:02:54.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="1a3b161aa0fcec32a0c8907a2219ad9d" + last-author="casper" + kind="file" + revision="1585"/> +<entry + committed-rev="1585" + name="alsaaudio.c" + text-time="2005-07-07T13:49:38.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="e72939bb5f268025aff2154d77b96201" + last-author="casper" + kind="file" + prop-time="2005-03-30T19:37:29.000000Z" + revision="1585"/> +<entry + committed-rev="1585" + name="TODO" + text-time="2005-07-09T21:13:24.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="4bda164e9f66fbab7b8c102ef5dbcdca" + last-author="casper" + kind="file" + prop-time="2004-10-05T08:43:24.000000Z" + revision="1585"/> +<entry + committed-rev="1585" + name="recordtest.py" + text-time="2005-07-09T20:46:17.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="36fd98bef1a4e935dfd404f8896cbc80" + last-author="casper" + kind="file" + prop-time="2004-10-05T08:43:24.000000Z" + revision="1585"/> +<entry + name="doc" + kind="dir"/> +<entry + committed-rev="820" + name="setup.py" + text-time="2005-07-07T13:49:38.000000Z" + committed-date="2004-10-04T13:28:33.537193Z" + checksum="3a808cedfedf7ee095bf912c4a9dc0c9" + last-author="anthony" + kind="file" + prop-time="2004-10-05T08:43:24.000000Z"/> +<entry + committed-rev="1585" + name="CHANGES" + text-time="2005-07-09T21:10:57.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="6018069ddf6e383385a283cf25218c1f" + last-author="casper" + kind="file" + revision="1585"/> +<entry + committed-rev="835" + name="mixertest.py" + text-time="2005-07-07T13:49:38.000000Z" + committed-date="2004-10-05T21:43:58.007506Z" + checksum="a7c859a05658506b14bbdb3367c2f490" + last-author="casper" + kind="file"/> +<entry + committed-rev="1585" + name="playbacktest.py" + text-time="2005-07-09T21:23:10.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="9e47bb9e5f3a0d7a00d23f82fce377be" + last-author="casper" + kind="file" + prop-time="2004-10-05T08:43:24.000000Z" + revision="1585"/> +<entry + committed-rev="1585" + name="README" + text-time="2005-07-09T21:20:32.000000Z" + committed-date="2005-07-09T21:26:15.500773Z" + checksum="2a402227ae1fb28f39d59f143df562dc" + last-author="casper" + kind="file" + prop-time="2004-10-05T08:43:24.000000Z" + revision="1585"/> +</wc-entries> diff --git a/arch_src/pyalsaaudio-0.2/.svn/format b/arch_src/pyalsaaudio-0.2/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/format @@ -0,0 +1 @@ +4 diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/README.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/README.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/README.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/TODO.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/TODO.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/TODO.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/alsaaudio.c.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/alsaaudio.c.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/alsaaudio.c.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/playbacktest.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/playbacktest.py.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/playbacktest.py.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/recordtest.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/recordtest.py.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/recordtest.py.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/prop-base/setup.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/prop-base/setup.py.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/prop-base/setup.py.svn-base @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/README.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/README.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/README.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/TODO.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/TODO.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/TODO.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/alsaaudio.c.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/alsaaudio.c.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/alsaaudio.c.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/playbacktest.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/playbacktest.py.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/playbacktest.py.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/recordtest.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/recordtest.py.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/recordtest.py.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/props/setup.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/props/setup.py.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/props/setup.py.svn-work @@ -0,0 +1 @@ +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/CHANGES.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/CHANGES.svn-base new file mode 100644 index 0000000..6ce8463 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/CHANGES.svn-base @@ -0,0 +1,8 @@ +VERSION 0.1 +- Initial version + + +VERSION 0.2 +- Many bugfixes related to playback in particular +- Module documentation in the doc subdirectory + diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/LICENSE.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/LICENSE.svn-base new file mode 100644 index 0000000..8aa69f7 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/LICENSE.svn-base @@ -0,0 +1,54 @@ +PyAlsaAudio is released under the same conditions as Python itself. +The original wording of this license can be found below. + + +PSF LICENSE AGREEMENT FOR PYTHON 2.4 +------------------------------------ + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using Python 2.4 software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 2.4 +alone or in any derivative version, provided, however, that PSF's +License Agreement and PSF's notice of copyright, i.e., "Copyright (c) +2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved" +are retained in Python 2.4 alone or in any derivative version prepared +by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 2.4 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 2.4. + +4. PSF is making Python 2.4 available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.4 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +2.4 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.4, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python 2.4, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/README.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/README.svn-base new file mode 100644 index 0000000..179cb79 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/README.svn-base @@ -0,0 +1,55 @@ +PyAlsaAudio +=========== + +Author: Casper Wilstrup (cwi@unispeed.dk) + +This package contains wrappers for accessing the ALSA api from Python. It +is currently fairly complete for PCM devices. My next goal is to have +complete mixer supports as well. MIDI sequencer support is low on my +priority list, but volunteers are welcome. + +If you find bugs in the wrappers please notify me on email. 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. + +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. + + +Installation +============ + +Note: the wrappers link with the alsasound library alsa (from the alsa-lib +package). Verify that this is installed by looking for /usr/lib/libasound.so +before building. The libasound development files are also neccesary. On debian +and derivatives, this is achieved by installing the alsalib-dev package. + +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 + + +Using the API +============= +There is a reasonably usefull API documentation included in the module +documentation, which can be found in the doc subdirectory of the source +distribution. + +There are also three example programs included with the source: +'playbacktest.py' which plays back raw sound data read from +stdin + +'recordtest.py' which captures sound from the microphone at writes +it raw to stdout. + +'mixertest.py' which can be used to manipulate the mixers diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/TODO.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/TODO.svn-base new file mode 100644 index 0000000..710a8a3 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/TODO.svn-base @@ -0,0 +1,3 @@ +- Better example code (aplay,arecord,amixer workalike for example) +- Implement MIDI/sequencer support. + diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/alsaaudio.c.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/alsaaudio.c.svn-base new file mode 100644 index 0000000..1828148 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/alsaaudio.c.svn-base @@ -0,0 +1,1013 @@ +/* + * alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture). + * 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) + * + * License: Python Software Foundation License + * + */ + +#include "Python.h" +#include <alsa/asoundlib.h> +#include <stdio.h> + +PyDoc_STRVAR(alsaaudio_module_doc, + "This modules provides support for the ALSA audio API.\n" + "\n" + "To control the PCM device, use the PCM class, Mixers\n" + "are controlled using the Mixer class.\n" + "\n" + "The following functions are also provided:\n" + "mixers() -- Return a list of available mixer names\n" + ); + +typedef struct { + PyObject_HEAD; + int pcmtype; + int pcmmode; + char *cardname; + + snd_pcm_t *handle; + + // Configurable parameters + int channels; + int rate; + int format; + snd_pcm_uframes_t periodsize; + int framesize; + +} alsapcm_t; + +typedef struct { + PyObject_HEAD; + + /* Mixer identification */ + char *cardname; + char *controlname; + int controlid; + + /* Capabilities */ + unsigned int volume_cap; + unsigned int switch_cap; + unsigned int pchannels; + unsigned int cchannels; + + /* min and max values for playback and capture volumes */ + long pmin; + long pmax; + long cmin; + long cmax; + snd_mixer_t *handle; + +} alsamixer_t; + +static PyObject *ALSAAudioError; + + +/******************************************/ +/* PCM object wrapper */ +/******************************************/ + +static PyTypeObject ALSAPCMType; + +static int alsapcm_setup(alsapcm_t *self) { + int res,dir; + unsigned int val; + snd_pcm_uframes_t frames; + snd_pcm_hw_params_t *hwparams; + + if (self->handle) { + snd_pcm_close(self->handle); + self->handle = 0; + } + res = snd_pcm_open(&(self->handle),self->cardname,self->pcmtype,self->pcmmode); + if (res < 0) return res; + + /* Allocate a hwparam structure, and fill it in with configuration space */ + snd_pcm_hw_params_alloca(&hwparams); + res = snd_pcm_hw_params_any(self->handle, hwparams); + if (res < 0) return res; + + /* Fill it in with default values. */ + snd_pcm_hw_params_any(self->handle, hwparams); + snd_pcm_hw_params_set_access(self->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format(self->handle, hwparams, self->format); + snd_pcm_hw_params_set_channels(self->handle, hwparams, self->channels); + dir = 0; + snd_pcm_hw_params_set_rate(self->handle, hwparams, self->rate, dir); + snd_pcm_hw_params_set_period_size(self->handle, hwparams, self->periodsize, dir); + snd_pcm_hw_params_set_periods(self->handle,hwparams,4,0); + + /* Write it to the device */ + res = snd_pcm_hw_params(self->handle, hwparams); + if (res) return res; + + /* Query current settings. These may differ from the requested values, + which should therefore be sync'ed with actual values */ + snd_pcm_hw_params_current(self->handle,hwparams); + + snd_pcm_hw_params_get_format(hwparams,&val); self->format = val; + snd_pcm_hw_params_get_channels(hwparams,&val); self->channels = val; + snd_pcm_hw_params_get_rate(hwparams,&val,&dir); self->rate = val; + snd_pcm_hw_params_get_period_size(hwparams,&frames,&dir); self->periodsize = (int) frames; + + self->framesize = self->channels * snd_pcm_hw_params_get_sbits(hwparams)/8; + return res; +} + +static PyObject * +alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + int res; + alsapcm_t *self; + int pcmtype=0; + int pcmmode=0; + char *cardname = "default"; + if (!PyArg_ParseTuple(args,"|iis",&pcmtype,&pcmmode,&cardname)) return NULL; + if (!(self = (alsapcm_t *)PyObject_New(alsapcm_t, &ALSAPCMType))) return NULL; + + if (pcmtype != SND_PCM_STREAM_PLAYBACK && pcmtype != SND_PCM_STREAM_CAPTURE) { + PyErr_SetString(ALSAAudioError, "PCM type must be PCM_PLAYBACK (0) or PCM_CAPTUPE (1)"); + return NULL; + } + if (pcmmode < 0 || pcmmode > SND_PCM_ASYNC) { + PyErr_SetString(ALSAAudioError, "Invalid PCM mode"); + return NULL; + } + self->pcmtype = pcmtype; + self->pcmmode = pcmmode; + self->cardname = strdup(cardname); + + self->channels = 2; + self->rate = 44100; + self->format = SND_PCM_FORMAT_S16_LE; + self->periodsize = 32; + + self->handle = 0; + res = alsapcm_setup(self); + + if (res < 0) { + if (self->handle) { + snd_pcm_close(self->handle); + self->handle = 0; + } + PyErr_SetString(ALSAAudioError, snd_strerror(res)); + return NULL; + } + return (PyObject *)self; +} + +static void alsapcm_dealloc(alsapcm_t *self) { + if (self->handle) { + snd_pcm_drain(self->handle); + snd_pcm_close(self->handle); + } + free(self->cardname); + PyObject_Del(self); +} + +static PyObject * +alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) { + unsigned int val,val2; + int dir; + snd_pcm_uframes_t frames; + snd_pcm_hw_params_t *hwparams; + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_current(self->handle,hwparams); + + + if (!PyArg_ParseTuple(args,"")) return NULL; + + printf("PCM handle name = '%s'\n", snd_pcm_name(self->handle)); + printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(self->handle))); + + snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val); + printf("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val)); + + snd_pcm_hw_params_get_format(hwparams, &val); + printf("format = '%s' (%s)\n", + snd_pcm_format_name((snd_pcm_format_t)val), + snd_pcm_format_description((snd_pcm_format_t)val)); + + snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val); + printf("subformat = '%s' (%s)\n", + snd_pcm_subformat_name((snd_pcm_subformat_t)val), + snd_pcm_subformat_description((snd_pcm_subformat_t)val)); + + snd_pcm_hw_params_get_channels(hwparams, &val); + printf("channels = %d\n", val); + + snd_pcm_hw_params_get_rate(hwparams, &val, &dir); + printf("rate = %d bps\n", val); + + snd_pcm_hw_params_get_period_time(hwparams, &val, &dir); + printf("period time = %d us\n", val); + + snd_pcm_hw_params_get_period_size(hwparams, &frames, &dir); + printf("period size = %d frames\n", (int)frames); + + snd_pcm_hw_params_get_buffer_time(hwparams, &val, &dir); + printf("buffer time = %d us\n", val); + + snd_pcm_hw_params_get_buffer_size(hwparams, (snd_pcm_uframes_t *) &val); + printf("buffer size = %d frames\n", val); + + snd_pcm_hw_params_get_periods(hwparams, &val, &dir); + printf("periods per buffer = %d frames\n", val); + + snd_pcm_hw_params_get_rate_numden(hwparams, &val, &val2); + printf("exact rate = %d/%d bps\n", val, val2); + + 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); + + val = snd_pcm_hw_params_is_batch(hwparams); + printf("is batch = %d\n", val); + + val = snd_pcm_hw_params_is_block_transfer(hwparams); + printf("is block transfer = %d\n", val); + + val = snd_pcm_hw_params_is_double(hwparams); + printf("is double = %d\n", val); + + val = snd_pcm_hw_params_is_half_duplex(hwparams); + printf("is half duplex = %d\n", val); + + val = snd_pcm_hw_params_is_joint_duplex(hwparams); + printf("is joint duplex = %d\n", val); + + val = snd_pcm_hw_params_can_overrange(hwparams); + printf("can overrange = %d\n", val); + + val = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams); + printf("can mmap = %d\n", val); + + val = snd_pcm_hw_params_can_pause(hwparams); + printf("can pause = %d\n", val); + + val = snd_pcm_hw_params_can_resume(hwparams); + printf("can resume = %d\n", val); + + val = snd_pcm_hw_params_can_sync_start(hwparams); + printf("can sync start = %d\n", val); + + Py_INCREF(Py_None); + return Py_None; + +} + +static PyObject * +alsapcm_pcmtype(alsapcm_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyInt_FromLong(self->pcmtype); +} + +static PyObject * +alsapcm_pcmmode(alsapcm_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyInt_FromLong(self->pcmmode); +} + +static PyObject * +alsapcm_cardname(alsapcm_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyString_FromString(self->cardname); +} + +static PyObject * +alsapcm_setchannels(alsapcm_t *self, PyObject *args) { + int channels; + int res; + if (!PyArg_ParseTuple(args,"i",&channels)) return NULL; + self->channels = channels; + res = alsapcm_setup(self); + if (res < 0) { + PyErr_SetString(ALSAAudioError, snd_strerror(res)); + return NULL; + } + return PyInt_FromLong(self->channels); +} + +static PyObject * +alsapcm_setrate(alsapcm_t *self, PyObject *args) { + int rate; + int res; + if (!PyArg_ParseTuple(args,"i",&rate)) return NULL; + self->rate = rate; + res = alsapcm_setup(self); + if (res < 0) { + PyErr_SetString(ALSAAudioError, snd_strerror(res)); + return NULL; + } + return PyInt_FromLong(self->rate); +} + +static PyObject * +alsapcm_setformat(alsapcm_t *self, PyObject *args) { + int format; + int res; + if (!PyArg_ParseTuple(args,"i",&format)) return NULL; + self->format = format; + res = alsapcm_setup(self); + if (res < 0) { + PyErr_SetString(ALSAAudioError, snd_strerror(res)); + return NULL; + } + return PyInt_FromLong(self->format); +} + +static PyObject * +alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) { + int periodsize; + int res; + if (!PyArg_ParseTuple(args,"i",&periodsize)) return NULL; + self->periodsize = periodsize; + res = alsapcm_setup(self); + if (res < 0) { + PyErr_SetString(ALSAAudioError, snd_strerror(res)); + return NULL; + } + return PyInt_FromLong(self->periodsize); +} + + +static PyObject * +alsapcm_read(alsapcm_t *self, PyObject *args) { + int res; + char buffer[8000]; + + if (self->framesize * self->periodsize > 8000) { + PyErr_SetString(ALSAAudioError,"Capture data too large. Try decreasing period size"); + return NULL; + } + + if (!PyArg_ParseTuple(args,"")) return NULL; + if (self->pcmtype != SND_PCM_STREAM_CAPTURE) { + PyErr_SetString(ALSAAudioError,"Cannot read from playback PCM"); + return NULL; + } + + res = snd_pcm_readi(self->handle, buffer, self->periodsize); + if (res == -EPIPE) { + /* EPIPE means overrun */ + snd_pcm_prepare(self->handle); + } + else if (res == -EAGAIN) { + res = 0; + } + else if (res < 0) { + PyErr_SetString(ALSAAudioError,snd_strerror(res)); + return NULL; + } + + return Py_BuildValue("is#",res,buffer,res*self->framesize); +} + +static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) { + char *data; + int datalen; + int res; + if (!PyArg_ParseTuple(args,"s#",&data,&datalen)) return NULL; + if (datalen%self->framesize) { + PyErr_SetString(ALSAAudioError,"Data size must be a multiple of framesize"); + return NULL; + } + res = snd_pcm_writei(self->handle, data, datalen/self->framesize); + if (res == -EPIPE) { + /* EPIPE means underrun */ + snd_pcm_prepare(self->handle); + snd_pcm_writei(self->handle, data, datalen/self->framesize); + snd_pcm_writei(self->handle, data, datalen/self->framesize); + } + else if (res == -EAGAIN) { + return PyInt_FromLong(0); + } + else if (res < 0) { + PyErr_SetString(ALSAAudioError,snd_strerror(res)); + return NULL; + } + return PyInt_FromLong(res); +} + + +/* ALSA PCM Object Bureaucracy */ + +static PyMethodDef alsapcm_methods[] = { + {"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS}, + {"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS}, + {"cardname", (PyCFunction)alsapcm_cardname, METH_VARARGS}, + {"setchannels", (PyCFunction)alsapcm_setchannels, METH_VARARGS}, + {"setrate", (PyCFunction)alsapcm_setrate, METH_VARARGS}, + {"setformat", (PyCFunction)alsapcm_setformat, METH_VARARGS}, + {"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS}, + + {"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS}, + + {"read", (PyCFunction)alsapcm_read, METH_VARARGS}, + {"write", (PyCFunction)alsapcm_write, METH_VARARGS}, + + {NULL, NULL} +}; + +static PyObject * +alsapcm_getattr(alsapcm_t *self, char *name) { + return Py_FindMethod(alsapcm_methods, (PyObject *)self, name); +} + +static PyTypeObject ALSAPCMType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "alsaaudio.pcm", /*tp_name*/ + sizeof(alsapcm_t), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) alsapcm_dealloc, /*tp_dealloc*/ + 0, /*print*/ + (getattrfunc)alsapcm_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "ALSA PCM device", /*tp_doc*/ +}; + + +/******************************************/ +/* Mixer object wrapper */ +/******************************************/ + +static PyTypeObject ALSAMixerType; + +#define MIXER_CAP_VOLUME 0x0001 +#define MIXER_CAP_VOLUME_JOINED 0x0002 +#define MIXER_CAP_PVOLUME 0x0004 +#define MIXER_CAP_PVOLUME_JOINED 0x0008 +#define MIXER_CAP_CVOLUME 0x0010 +#define MIXER_CAP_CVOLUME_JOINED 0x0020 + +#define MIXER_CAP_SWITCH 0x0001 +#define MIXER_CAP_SWITCH_JOINED 0x0002 +#define MIXER_CAP_PSWITCH 0x0004 +#define MIXER_CAP_PSWITCH_JOINED 0x0008 +#define MIXER_CAP_CSWITCH 0x0010 +#define MIXER_CAP_CSWITCH_JOINED 0x0020 +#define MIXER_CAP_CSWITCH_EXCLUSIVE 0x0040 + +#define MIXER_CHANNEL_ALL -1 + +int +alsamixer_gethandle(char *cardname, snd_mixer_t **handle) { + int err; + if ((err = snd_mixer_open(handle, 0)) < 0) return err; + if ((err = snd_mixer_attach(*handle, cardname)) < 0) return err; + if ((err = snd_mixer_selem_register(*handle, NULL, NULL)) < 0) return err; + if ((err = snd_mixer_load(*handle)) < 0) return err; + + return 0; +} + +static PyObject * +alsamixer_list(PyObject *self, PyObject *args) { + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + snd_mixer_elem_t *elem; + int err; + char *cardname = "default"; + PyObject *result = PyList_New(0); + + if (!PyArg_ParseTuple(args,"|s",&cardname)) return NULL; + + snd_mixer_selem_id_alloca(&sid); + err = alsamixer_gethandle(cardname,&handle); + if (err < 0) { + PyErr_SetString(ALSAAudioError,snd_strerror(err)); + snd_mixer_close(handle); + return NULL; + } + for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { + PyObject *mixer; + snd_mixer_selem_get_id(elem, sid); + mixer = PyString_FromString(snd_mixer_selem_id_get_name(sid)); + PyList_Append(result,mixer); + Py_DECREF(mixer); + } + snd_mixer_close(handle); + + return result; +} + +static snd_mixer_elem_t * +alsamixer_find_elem(snd_mixer_t *handle, char *control, int id) { + snd_mixer_selem_id_t *sid; + + snd_mixer_selem_id_alloca(&sid); + snd_mixer_selem_id_set_index(sid, id); + snd_mixer_selem_id_set_name(sid, control); + return snd_mixer_find_selem(handle, sid); +} + +static PyObject * +alsamixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + alsamixer_t *self; + int err; + char *cardname = "default"; + char *control = "Master"; + int id = 0; + snd_mixer_elem_t *elem; + int channel; + + if (!PyArg_ParseTuple(args,"|sis",&control,&id,&cardname)) return NULL; + if (!(self = (alsamixer_t *)PyObject_New(alsamixer_t, &ALSAMixerType))) return NULL; + + err = alsamixer_gethandle(cardname,&self->handle); + if (err<0) { + PyErr_SetString(ALSAAudioError,snd_strerror(err)); + return NULL; + } + self->cardname = strdup(cardname); + self->controlname = strdup(control); + self->controlid = id; + + elem = alsamixer_find_elem(self->handle,control,id); + if (!elem) { + char errtext[128]; + sprintf(errtext,"Unable to find mixer control '%s',%i",self->controlname,self->controlid); + snd_mixer_close(self->handle); + PyErr_SetString(ALSAAudioError,errtext); + return NULL; + } + /* Determine mixer capabilities */ + self->volume_cap = self->switch_cap = 0; + if (snd_mixer_selem_has_common_volume(elem)) { + self->volume_cap |= MIXER_CAP_VOLUME; + if (snd_mixer_selem_has_playback_volume_joined(elem)) self->volume_cap |= MIXER_CAP_VOLUME_JOINED; + } + else { + if (snd_mixer_selem_has_playback_volume(elem)) { + self->volume_cap |= MIXER_CAP_PVOLUME; + if (snd_mixer_selem_has_playback_volume_joined(elem)) self->volume_cap |= MIXER_CAP_PVOLUME_JOINED; + } + if (snd_mixer_selem_has_capture_volume(elem)) { + self->volume_cap |= MIXER_CAP_CVOLUME; + if (snd_mixer_selem_has_capture_volume_joined(elem)) self->volume_cap |= MIXER_CAP_CVOLUME_JOINED; + } + } + + if (snd_mixer_selem_has_common_switch(elem)) { + self->switch_cap |= MIXER_CAP_SWITCH; + if (snd_mixer_selem_has_playback_switch_joined(elem)) self->switch_cap |= MIXER_CAP_SWITCH_JOINED; + } + else { + if (snd_mixer_selem_has_playback_switch(elem)) { + self->switch_cap |= MIXER_CAP_PSWITCH; + if (snd_mixer_selem_has_playback_switch_joined(elem)) self->switch_cap |= MIXER_CAP_PSWITCH_JOINED; + } + if (snd_mixer_selem_has_capture_switch(elem)) { + self->switch_cap |= MIXER_CAP_CSWITCH; + if (snd_mixer_selem_has_capture_switch_joined(elem)) self->switch_cap |= MIXER_CAP_CSWITCH_JOINED; + if (snd_mixer_selem_has_capture_switch_exclusive(elem)) self->switch_cap |= MIXER_CAP_CSWITCH_EXCLUSIVE; + } + } + self->pchannels = 0; + if (self->volume_cap | MIXER_CAP_PVOLUME || self->switch_cap | MIXER_CAP_PSWITCH) { + if (snd_mixer_selem_is_playback_mono(elem)) self->pchannels = 1; + else { + for (channel=0; channel <= SND_MIXER_SCHN_LAST; channel++) { + if (snd_mixer_selem_has_playback_channel(elem, channel)) self->pchannels++; + else break; + } + } + } + self->cchannels = 0; + if (self->volume_cap | MIXER_CAP_CVOLUME || self->switch_cap | MIXER_CAP_CSWITCH) { + if (snd_mixer_selem_is_capture_mono(elem)) self->cchannels = 1; + else { + for (channel=0; channel <= SND_MIXER_SCHN_LAST; channel++) { + if (snd_mixer_selem_has_capture_channel(elem, channel)) self->cchannels++; + else break; + } + } + } + snd_mixer_selem_get_playback_volume_range(elem, &self->pmin, &self->pmax); + snd_mixer_selem_get_capture_volume_range(elem, &self->cmin, &self->cmax); + return (PyObject *)self; +} + +static void alsamixer_dealloc(alsamixer_t *self) { + if (self->handle) { + snd_mixer_close(self->handle); + free(self->cardname); + free(self->controlname); + self->handle = 0; + } + PyObject_Del(self); +} + +static PyObject * +alsamixer_cardname(alsamixer_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyString_FromString(self->cardname); +} + +static PyObject * +alsamixer_mixer(alsamixer_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyString_FromString(self->controlname); +} + +static PyObject * +alsamixer_mixerid(alsamixer_t *self, PyObject *args) { + if (!PyArg_ParseTuple(args,"")) return NULL; + return PyInt_FromLong(self->controlid); +} + +static PyObject * +alsamixer_volumecap(alsamixer_t *self, PyObject *args) { + PyObject *result; + if (!PyArg_ParseTuple(args,"")) return NULL; + result = PyList_New(0); + if (self->volume_cap&MIXER_CAP_VOLUME) + PyList_Append(result,PyString_FromString("Volume")); + if (self->volume_cap&MIXER_CAP_VOLUME_JOINED) + PyList_Append(result,PyString_FromString("Joined Volume")); + if (self->volume_cap&MIXER_CAP_PVOLUME) + PyList_Append(result,PyString_FromString("Playback Volume")); + if (self->volume_cap&MIXER_CAP_PVOLUME_JOINED) + PyList_Append(result,PyString_FromString("Joined Playback Volume")); + if (self->volume_cap&MIXER_CAP_CVOLUME) + PyList_Append(result,PyString_FromString("Capture Volume")); + if (self->volume_cap&MIXER_CAP_CVOLUME_JOINED) + PyList_Append(result,PyString_FromString("Joined Capture Volume")); + + return result; +} +static PyObject * +alsamixer_switchcap(alsamixer_t *self, PyObject *args) { + PyObject *result; + if (!PyArg_ParseTuple(args,"")) return NULL; + result = PyList_New(0); + if (self->volume_cap&MIXER_CAP_SWITCH) + PyList_Append(result,PyString_FromString("Mute")); + if (self->volume_cap&MIXER_CAP_SWITCH_JOINED) + PyList_Append(result,PyString_FromString("Joined Mute")); + if (self->volume_cap&MIXER_CAP_PSWITCH) + PyList_Append(result,PyString_FromString("Playback Mute")); + if (self->volume_cap&MIXER_CAP_PSWITCH_JOINED) + PyList_Append(result,PyString_FromString("Joined Playback Mute")); + if (self->volume_cap&MIXER_CAP_CSWITCH) + PyList_Append(result,PyString_FromString("Capture Mute")); + if (self->volume_cap&MIXER_CAP_CSWITCH_JOINED) + PyList_Append(result,PyString_FromString("Joined Capture Mute")); + if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE) + PyList_Append(result,PyString_FromString("Capture Exclusive")); + return result; +} + +static int alsamixer_getpercentage(long min, long max, long value) { + /* Convert from number in range to percentage */ + int range = max - min; + int tmp; + + if (range == 0) return 0; + value -= min; + tmp = rint((double)value/(double)range * 100); + return tmp; + +} + +static long alsamixer_getphysvolume(long min, long max, int percentage) { + /* Convert from percentage to number in range */ + int range = max - min; + int tmp; + + if (range == 0) return 0; + tmp = rint((double)range * ((double)percentage*.01)) + min; + return tmp; +} + +static PyObject * +alsamixer_getvolume(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int direction; + int channel; + long ival; + char *dirstr = 0; + PyObject *result; + + if (!PyArg_ParseTuple(args,"|s",&dirstr)) return NULL; + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + + if (!dirstr) { + if (self->pchannels) direction = 0; + else direction = 1; + } + else if (strcasecmp(dirstr,"playback")==0) direction = 0; + else if (strcasecmp(dirstr,"capture")==0) direction = 1; + else { + PyErr_SetString(ALSAAudioError,"Invalid direction argument for mixer"); + return NULL; + } + result = PyList_New(0); + for (channel = 0; channel <= SND_MIXER_SCHN_LAST; channel++) { + if (direction == 0 && snd_mixer_selem_has_playback_channel(elem, channel)) { + snd_mixer_selem_get_playback_volume(elem, channel, &ival); + PyList_Append(result,PyInt_FromLong(alsamixer_getpercentage(self->pmin,self->pmax,ival))); + } + else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, channel) + && snd_mixer_selem_has_capture_volume(elem)) { + snd_mixer_selem_get_capture_volume(elem, channel, &ival); + PyList_Append(result,PyInt_FromLong(alsamixer_getpercentage(self->cmin,self->cmax,ival))); + } + } + return result; +} + +static PyObject * +alsamixer_getmute(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int i; + int ival; + PyObject *result; + if (!PyArg_ParseTuple(args,"")) return NULL; + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + if (!snd_mixer_selem_has_playback_switch(elem)) { + PyErr_SetString(ALSAAudioError,"Mixer has no mute switch"); + return NULL; + } + result = PyList_New(0); + for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) { + if (snd_mixer_selem_has_playback_channel(elem, i)) { + snd_mixer_selem_get_playback_switch(elem, i, &ival); + PyList_Append(result,PyInt_FromLong(!ival)); + } + } + return result; +} + +static PyObject * +alsamixer_getrec(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int i; + int ival; + PyObject *result; + if (!PyArg_ParseTuple(args,"")) return NULL; + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + if (!snd_mixer_selem_has_capture_switch(elem)) { + PyErr_SetString(ALSAAudioError,"Mixer has no record switch"); + return NULL; + } + result = PyList_New(0); + for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) { + if (snd_mixer_selem_has_capture_channel(elem, i)) { + snd_mixer_selem_get_capture_switch(elem, i, &ival); + PyList_Append(result,PyInt_FromLong(!ival)); + } + } + return result; +} + +static PyObject * +alsamixer_setvolume(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int direction; + int i; + long volume; + int physvolume; + char *dirstr = 0; + int channel = MIXER_CHANNEL_ALL; + int done = 0; + + if (!PyArg_ParseTuple(args,"l|is",&volume,&channel,&dirstr)) return NULL; + if (volume < 0 || volume > 100) { + PyErr_SetString(ALSAAudioError,"Volume must be between 0 and 100"); + return NULL; + } + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + + if (!dirstr) { + if (self->pchannels) direction = 0; + else direction = 1; + } + else if (strcasecmp(dirstr,"playback")==0) direction = 0; + else if (strcasecmp(dirstr,"capture")==0) direction = 1; + else { + PyErr_SetString(ALSAAudioError,"Invalid direction argument. Use 'playback' or 'capture'"); + return NULL; + } + for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) { + if (channel == -1 || channel == i) { + if (direction == 0 && snd_mixer_selem_has_playback_channel(elem, i)) { + physvolume = alsamixer_getphysvolume(self->pmin,self->pmax,volume); + snd_mixer_selem_set_playback_volume(elem, i, physvolume); + done++; + } + else if (direction == 1 && snd_mixer_selem_has_capture_channel(elem, channel) + && snd_mixer_selem_has_capture_volume(elem)) { + physvolume = alsamixer_getphysvolume(self->cmin,self->cmax,volume); + snd_mixer_selem_set_capture_volume(elem, i, physvolume); + done++; + } + } + } + if(!done) { + PyErr_SetString(ALSAAudioError,"No such channel"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alsamixer_setmute(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int i; + int mute = 0; + int done = 0; + int channel = MIXER_CHANNEL_ALL; + if (!PyArg_ParseTuple(args,"i|i",&mute,&channel)) return NULL; + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + if (!snd_mixer_selem_has_playback_switch(elem)) { + PyErr_SetString(ALSAAudioError,"Mixer has no mute switch"); + return NULL; + } + for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) { + if (channel == MIXER_CHANNEL_ALL || channel == i) { + if (snd_mixer_selem_has_playback_channel(elem, i)) { + snd_mixer_selem_set_playback_switch(elem, i, !mute); + done++; + } + } + } + if (!done) { + PyErr_SetString(ALSAAudioError,"Invalid channel number"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alsamixer_setrec(alsamixer_t *self, PyObject *args) { + snd_mixer_elem_t *elem; + int i; + int rec = 0; + int done = 0; + int channel = MIXER_CHANNEL_ALL; + if (!PyArg_ParseTuple(args,"i|i",&rec,&channel)) return NULL; + + elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); + if (!snd_mixer_selem_has_capture_switch(elem)) { + PyErr_SetString(ALSAAudioError,"Mixer has no record switch"); + return NULL; + } + for (i = 0; i <= SND_MIXER_SCHN_LAST; i++) { + if (channel == MIXER_CHANNEL_ALL || channel == i) { + if (snd_mixer_selem_has_capture_channel(elem, i)) { + snd_mixer_selem_set_playback_switch(elem, i, rec); + done++; + } + } + } + if (!done) { + PyErr_SetString(ALSAAudioError,"Invalid channel number"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef alsamixer_methods[] = { + {"cardname", (PyCFunction)alsamixer_cardname, METH_VARARGS}, + {"mixer", (PyCFunction)alsamixer_mixer, METH_VARARGS}, + {"mixerid", (PyCFunction)alsamixer_mixerid, METH_VARARGS}, + {"switchcap", (PyCFunction)alsamixer_switchcap, METH_VARARGS}, + {"volumecap", (PyCFunction)alsamixer_volumecap, METH_VARARGS}, + {"getvolume", (PyCFunction)alsamixer_getvolume, METH_VARARGS}, + {"getmute", (PyCFunction)alsamixer_getmute, METH_VARARGS}, + {"getrec", (PyCFunction)alsamixer_getrec, METH_VARARGS}, + {"setvolume", (PyCFunction)alsamixer_setvolume, METH_VARARGS}, + {"setmute", (PyCFunction)alsamixer_setmute, METH_VARARGS}, + {"setrec", (PyCFunction)alsamixer_setrec, METH_VARARGS}, + {NULL, NULL} +}; + + +static PyObject * +alsamixer_getattr(alsapcm_t *self, char *name) { + return Py_FindMethod(alsamixer_methods, (PyObject *)self, name); +} + +static PyTypeObject ALSAMixerType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "alsaaudio.mixer", /*tp_name*/ + sizeof(alsamixer_t), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) alsamixer_dealloc, /*tp_dealloc*/ + 0, /*print*/ + (getattrfunc)alsamixer_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "ALSA Mixer Control", /*tp_doc*/ +}; + + +/******************************************/ +/* Module initialization */ +/******************************************/ + +static PyMethodDef alsaaudio_methods[] = { + { "mixers", alsamixer_list, METH_VARARGS }, + { 0, 0 }, +}; + +#define _EXPORT_INT(mod, name, value) \ + if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return; + +void initalsaaudio(void) { + PyObject *m; + ALSAPCMType.tp_new = alsapcm_new; + ALSAMixerType.tp_new = alsamixer_new; + m = Py_InitModule3("alsaaudio",alsaaudio_methods,alsaaudio_module_doc); + + ALSAAudioError = PyErr_NewException("alsaaudio.ALSAAudioError", NULL, NULL); + if (ALSAAudioError) { + /* Each call to PyModule_AddObject decrefs it; compensate: */ + + Py_INCREF(&ALSAPCMType); + PyModule_AddObject(m,"PCM",(PyObject *)&ALSAPCMType); + + Py_INCREF(&ALSAMixerType); + PyModule_AddObject(m,"Mixer",(PyObject *)&ALSAMixerType); + + Py_INCREF(ALSAAudioError); + PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError); + } + + + _EXPORT_INT(m,"PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK); + _EXPORT_INT(m,"PCM_CAPTURE",SND_PCM_STREAM_CAPTURE); + + _EXPORT_INT(m,"PCM_NORMAL",0); + _EXPORT_INT(m,"PCM_NONBLOCK",SND_PCM_NONBLOCK); + _EXPORT_INT(m,"PCM_ASYNC",SND_PCM_ASYNC); + + /* PCM Formats */ + _EXPORT_INT(m,"PCM_FORMAT_S8",SND_PCM_FORMAT_S8); + _EXPORT_INT(m,"PCM_FORMAT_U8",SND_PCM_FORMAT_U8); + _EXPORT_INT(m,"PCM_FORMAT_S16_LE",SND_PCM_FORMAT_S16_LE); + _EXPORT_INT(m,"PCM_FORMAT_S16_BE",SND_PCM_FORMAT_S16_BE); + _EXPORT_INT(m,"PCM_FORMAT_U16_LE",SND_PCM_FORMAT_U16_LE); + _EXPORT_INT(m,"PCM_FORMAT_U16_BE",SND_PCM_FORMAT_U16_BE); + _EXPORT_INT(m,"PCM_FORMAT_S24_LE",SND_PCM_FORMAT_S24_LE); + _EXPORT_INT(m,"PCM_FORMAT_S24_BE",SND_PCM_FORMAT_S24_BE); + _EXPORT_INT(m,"PCM_FORMAT_U24_LE",SND_PCM_FORMAT_U24_LE); + _EXPORT_INT(m,"PCM_FORMAT_U24_BE",SND_PCM_FORMAT_U24_BE); + _EXPORT_INT(m,"PCM_FORMAT_S32_LE",SND_PCM_FORMAT_S32_LE); + _EXPORT_INT(m,"PCM_FORMAT_S32_BE",SND_PCM_FORMAT_S32_BE); + _EXPORT_INT(m,"PCM_FORMAT_U32_LE",SND_PCM_FORMAT_U32_LE); + _EXPORT_INT(m,"PCM_FORMAT_U32_BE",SND_PCM_FORMAT_U32_BE); + _EXPORT_INT(m,"PCM_FORMAT_FLOAT_LE",SND_PCM_FORMAT_FLOAT_LE); + _EXPORT_INT(m,"PCM_FORMAT_FLOAT_BE",SND_PCM_FORMAT_FLOAT_BE); + _EXPORT_INT(m,"PCM_FORMAT_FLOAT64_LE",SND_PCM_FORMAT_FLOAT64_LE); + _EXPORT_INT(m,"PCM_FORMAT_FLOAT64_BE",SND_PCM_FORMAT_FLOAT64_BE); + _EXPORT_INT(m,"PCM_FORMAT_MU_LAW",SND_PCM_FORMAT_MU_LAW); + _EXPORT_INT(m,"PCM_FORMAT_A_LAW",SND_PCM_FORMAT_A_LAW); + _EXPORT_INT(m,"PCM_FORMAT_IMA_ADPCM",SND_PCM_FORMAT_IMA_ADPCM); + _EXPORT_INT(m,"PCM_FORMAT_MPEG",SND_PCM_FORMAT_MPEG); + _EXPORT_INT(m,"PCM_FORMAT_GSM",SND_PCM_FORMAT_GSM); + + /* Mixer stuff */ + _EXPORT_INT(m,"MIXER_CHANNEL_ALL",MIXER_CHANNEL_ALL); + +} diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/mixertest.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/mixertest.py.svn-base new file mode 100644 index 0000000..642ae10 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/mixertest.py.svn-base @@ -0,0 +1,88 @@ +## mixertest.py +## +## This is an example of using the ALSA mixer API +## +## The script will set the volume or mute switch of the specified Mixer +## depending on command line options. +## +## Examples: +## python mixertest.py # list available mixers +## python mixertest.py Master # show Master mixer settings +## python mixertest.py Master 80 # set the master volume to 80% +## python mixertest.py Master 1,90 # set channel 1 volume to 90% +## python mixertest.py Master mute # mute the master mixer +## python mixertest.py Master unmute # unmute the master mixer + +import alsaaudio +import sys + +if len(sys.argv) == 1: + # Demonstrates how to read the available mixers + print "Available mixer controls:" + for m in alsaaudio.mixers(): + print " '%s'" % m + +if len(sys.argv) == 2: + # Demonstrates how mixer settings are queried. + name = sys.argv[1] + try: + mixer = alsaaudio.Mixer(name) + except alsaaudio.ALSAAudioError: + print "No such mixer" + sys.exit(1) + + print "Mixer name: '%s'"%mixer.mixer() + print "Capabilities",mixer.volumecap()+mixer.switchcap() + volumes = mixer.getvolume() + for i in range(len(volumes)): + print "Channel %i volume: %i%%"%(i,volumes[i]) + + try: + mutes = mixer.getmute() + for i in range(len(mutes)): + if mutes[i]: print "Channel %i is muted"%i + except alsaaudio.ALSAAudioError: + # May not support muting + pass + + try: + recs = mixer.getrec() + for i in range(len(recs)): + if recs[i]: print "Channel %i is recording"%i + except alsaaudio.ALSAAudioError: + # May not support recording + pass + +if (len(sys.argv)) == 3: + # Demonstrates how to set mixer settings + name = sys.argv[1] + try: + mixer = alsaaudio.Mixer(name) + except alsaaudio.ALSAAudioError: + print "No such mixer" + sys.exit(1) + + args = sys.argv[2] + if args in ['mute','unmute']: + # Mute/unmute the mixer + if args == 'mute': mixer.setmute(1) + else: mixer.setmute(0) + sys.exit(0) + if args in ['rec','unrec']: + # Enable/disable recording + if args == 'rec': mixer.setrec(1) + else: mixer.setrec(0) + sys.exit(0) + + + if args.find(',')!=-1: + channel,volume = map(int,args.split(',')) + else: + channel = alsaaudio.MIXER_CHANNEL_ALL + volume = int(args) + # Set volume for specified channel. MIXER_CHANNEL_ALL means set + # volume for all channels + mixer.setvolume(volume,channel) + + + diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/playbacktest.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/playbacktest.py.svn-base new file mode 100644 index 0000000..06e0fe9 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/playbacktest.py.svn-base @@ -0,0 +1,36 @@ +## recordtest.py +## +## This is an example of a simple sound playback script. +## +## The script opens an ALSA pcm for sound playback. Set +## various attributes of the device. It then reads data +## from stdin and writes it to the device. +## +## To test it out do the following: +## python recordtest.py > out.raw # talk to the microphone +## python playbacktest.py < out.raw +## +## If you have Gnome, you could also just test by doing something like: +## python playbacktest.py < /usr/share/sounds/gnibbles/laughter.wav +import alsaaudio +import sys +import time + +# Open the device in playback mode. +out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK) + +# Set attributes: Mono, 8000 Hz, 16 bit little endian frames +out.setchannels(1) +out.setrate(8000) +out.setformat(alsaaudio.PCM_FORMAT_S16_LE) + +# The period size controls the internal number of frames per period. +# The significance of this parameter is documented in the ALSA api. +out.setperiodsize(160) + +loops = 10000 +while loops > 0: + loops -= 1 + # Read data from stdin + data = sys.stdin.read(320) + out.write(data) diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/recordtest.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/recordtest.py.svn-base new file mode 100644 index 0000000..216d627 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/recordtest.py.svn-base @@ -0,0 +1,45 @@ +## recordtest.py +## +## This is an example of a simple sound capture script. +## +## The script opens an ALSA pcm forsound capture. Set +## various attributes of the capture, and reads in a loop, +## writing the data to standard out. +## +## To test it out do the following: +## python recordtest.py > out.raw # talk to the microphone +## aplay -r 8000 -f S16_LE -c 1 out.raw + +import alsaaudio +import sys +import time + +# Open the device in nonblocking capture mode. The last argument could +# just as well have been zero for blocking mode. Then we could have +# left out the sleep call in the bottom of the loop +inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK) + +# Set attributes: Mono, 8000 Hz, 16 bit little endian samples +inp.setchannels(1) +inp.setrate(8000) +inp.setformat(alsaaudio.PCM_FORMAT_S16_LE) + +# The period size controls the internal number of frames per period. +# The significance of this parameter is documented in the ALSA api. +# For our purposes, it is suficcient to know that reads from the device +# will return this many frames. Each frame being 2 bytes long. +# This means that the reads below will return either 320 bytes of data +# or 0 bytes of data. The latter is possible because we are in nonblocking +# mode. +inp.setperiodsize(160) + +loops = 1000000 +while loops > 0: + loops -= 1 + # Read data from device + l,data = inp.read() + + if l: + # actual data read. Write it to stdout + sys.stdout.write(data) + time.sleep(.001) diff --git a/arch_src/pyalsaaudio-0.2/.svn/text-base/setup.py.svn-base b/arch_src/pyalsaaudio-0.2/.svn/text-base/setup.py.svn-base new file mode 100644 index 0000000..d2534a7 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/text-base/setup.py.svn-base @@ -0,0 +1,14 @@ +from distutils.core import setup +from distutils.extension import Extension + +setup( + name = "alsaaudio", + version = "0.1", + description = "alsa bindings", + author = "Casper Wilstrup", + author_email="cwi@unispeed.com", + ext_modules=[Extension("alsaaudio",["alsaaudio.c"],libraries=['asound']) + ] + ) + + diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/CHANGES.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/CHANGES.svn-work new file mode 100644 index 0000000..6859ec8 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/CHANGES.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/CHANGES +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/LICENSE.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/LICENSE.svn-work new file mode 100644 index 0000000..ca474ba --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/LICENSE.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/LICENSE +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/README.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/README.svn-work new file mode 100644 index 0000000..31f6d9b --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/README.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/README +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/TODO.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/TODO.svn-work new file mode 100644 index 0000000..5182281 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/TODO.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 54 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/TODO +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/alsaaudio.c.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/alsaaudio.c.svn-work new file mode 100644 index 0000000..00079a1 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/alsaaudio.c.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 61 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/alsaaudio.c +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/mixertest.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/mixertest.py.svn-work new file mode 100644 index 0000000..45321b3 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/mixertest.py.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 61 +/svn/Shtoom/!svn/ver/835/trunk/audio/pyalsaaudio/mixertest.py +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/playbacktest.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/playbacktest.py.svn-work new file mode 100644 index 0000000..5ca8d71 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/playbacktest.py.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 65 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/playbacktest.py +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/recordtest.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/recordtest.py.svn-work new file mode 100644 index 0000000..53db42e --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/recordtest.py.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 63 +/svn/Shtoom/!svn/ver/1585/trunk/audio/pyalsaaudio/recordtest.py +END diff --git a/arch_src/pyalsaaudio-0.2/.svn/wcprops/setup.py.svn-work b/arch_src/pyalsaaudio-0.2/.svn/wcprops/setup.py.svn-work new file mode 100644 index 0000000..f428267 --- /dev/null +++ b/arch_src/pyalsaaudio-0.2/.svn/wcprops/setup.py.svn-work @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/Shtoom/!svn/ver/820/trunk/audio/pyalsaaudio/setup.py +END |