pyalsaaudio-0.7/0000755000175000017500000000000011620311641013612 5ustar larslars00000000000000pyalsaaudio-0.7/TODO0000644000175000017500000000015011144302601014273 0ustar larslars00000000000000- Better example code (aplay,arecord,amixer workalike for example) - Implement MIDI/sequencer support. pyalsaaudio-0.7/isine.py0000755000175000017500000000402111620307105015273 0ustar larslars00000000000000''' Use this example from an interactive python session, for example: >>> from isine import change >>> change(880) ''' from threading import Thread from Queue import Queue, Empty from math import pi, sin import struct import alsaaudio sampling_rate = 44100 format = alsaaudio.PCM_FORMAT_S16_LE framesize = 2 # bytes per frame for the values above def digitize(s): if s > 1.0 or s < -1.0: raise ValueError return struct.pack('h', int(s * 32767)) def generate(frequency): # generate a buffer with a sine wave of frequency size = int(sampling_rate / frequency) buffer = '' for i in range(size): buffer = buffer + digitize(sin(i/(2 * pi))) return buffer class SinePlayer(Thread): def __init__(self, frequency = 440.0): Thread.__init__(self) self.setDaemon(True) self.device = alsaaudio.PCM() self.device.setchannels(1) self.device.setformat(format) self.device.setrate(sampling_rate) self.queue = Queue() self.change(frequency) def change(self, frequency): '''This is called outside of the player thread''' # we generate the buffer in the calling thread for less # latency when switching frequencies # More than 100 writes/s are pushing it - play multiple buffers # for higher frequencies factor = int(frequency/100.0) if factor == 0: factor = 1 buf = generate(frequency) * factor print 'factor: %d, frames: %d' % (factor, len(buf) / framesize) self.queue.put( buf) def run(self): buffer = None while True: try: buffer = self.queue.get(False) self.device.setperiodsize(len(buffer) / framesize) self.device.write(buffer) except Empty: if buffer: self.device.write(buffer) isine = SinePlayer() isine.start() def change(f): isine.change(f) pyalsaaudio-0.7/playbacktest.py0000755000175000017500000000300711144302601016652 0ustar larslars00000000000000#!/usr/bin/env python ## playbacktest.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 # Footnote: I'd normally use print instead of sys.std(out|err).write, # but we're in the middle of the conversion between python 2 and 3 # and this code runs on both versions without conversion import sys import time import getopt import alsaaudio def usage(): sys.stderr.write('usage: playbacktest.py [-c ] \n') sys.exit(2) if __name__ == '__main__': card = 'default' opts, args = getopt.getopt(sys.argv[1:], 'c:') for o, a in opts: if o == '-c': card = a if not args: usage() f = open(args[0], 'rb') # Open the device in playback mode. out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, card=card) # Set attributes: Mono, 44100 Hz, 16 bit little endian frames out.setchannels(1) out.setrate(44100) 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) # Read data from stdin data = f.read(320) while data: out.write(data) data = f.read(320) pyalsaaudio-0.7/mixertest.py0000755000175000017500000000730711203115751016223 0ustar larslars00000000000000#!/usr/bin/env python ## 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 [un]mute # [un]mute the master mixer ## python mixertest.py Capture [un]rec # [dis/en]able capture ## python mixertest.py Master 0,[un]mute # [un]mute channel 0 ## python mixertest.py Capture 0,[un]rec # [dis/en]able capture on channel 0 # Footnote: I'd normally use print instead of sys.std(out|err).write, # but we're in the middle of the conversion between python 2 and 3 # and this code runs on both versions without conversion import sys import getopt import alsaaudio def list_mixers(idx=0): sys.stdout.write("Available mixer controls:\n") for m in alsaaudio.mixers(idx): sys.stdout.write(" '%s'\n" % m) def show_mixer(name, idx=0): # Demonstrates how mixer settings are queried. try: mixer = alsaaudio.Mixer(name, cardindex=idx) except alsaaudio.ALSAAudioError: sys.stderr.write("No such mixer\n") sys.exit(1) sys.stdout.write("Mixer name: '%s'\n" % mixer.mixer()) sys.stdout.write("Capabilities: %s %s\n" % (' '.join(mixer.volumecap()), ' '.join(mixer.switchcap()))) volumes = mixer.getvolume() for i in range(len(volumes)): sys.stdout.write("Channel %i volume: %i%%\n" % (i,volumes[i])) try: mutes = mixer.getmute() for i in range(len(mutes)): if mutes[i]: sys.stdout.write("Channel %i is muted\n" % i) except alsaaudio.ALSAAudioError: # May not support muting pass try: recs = mixer.getrec() for i in range(len(recs)): if recs[i]: sys.stdout.write("Channel %i is recording\n" % i) except alsaaudio.ALSAAudioError: # May not support recording pass def set_mixer(name, args, idx=0): # Demonstrates how to set mixer settings try: mixer = alsaaudio.Mixer(name, cardindex=idx) except alsaaudio.ALSAAudioError: sys.stderr.write("No such mixer") sys.exit(1) if args.find(',') != -1: args_array = args.split(',') channel = int(args_array[0]) args = ','.join(args_array[1:]) else: channel = alsaaudio.MIXER_CHANNEL_ALL if args in ['mute', 'unmute']: # Mute/unmute the mixer if args == 'mute': mixer.setmute(1, channel) else: mixer.setmute(0, channel) elif args in ['rec','unrec']: # Enable/disable recording if args == 'rec': mixer.setrec(1, channel) else: mixer.setrec(0, channel) else: # Set volume for specified channel. MIXER_CHANNEL_ALL means set # volume for all channels volume = int(args) mixer.setvolume(volume, channel) def usage(): sys.stderr.write('usage: mixertest.py [-c ] ' \ '[ [,]]\n') sys.exit(2) if __name__ == '__main__': cardindex = 0 opts, args = getopt.getopt(sys.argv[1:], 'c:?h') for o, a in opts: if o == '-c': cardindex = int(a) else: usage() if not len(args): list_mixers(cardindex) elif len(args) == 1: show_mixer(args[0], cardindex) else: set_mixer(args[0], args[1], cardindex) pyalsaaudio-0.7/playwav.py0000755000175000017500000000311711311655137015664 0ustar larslars00000000000000#!/usr/bin/env python # Simple test script that plays (some) wav files # Footnote: I'd normally use print instead of sys.std(out|err).write, # but this version runs on python 2 and python 3 without conversion import sys import wave import getopt import alsaaudio def play(device, f): sys.stdout.write('%d channels, %d sampling rate\n' % (f.getnchannels(), f.getframerate())) # Set attributes device.setchannels(f.getnchannels()) device.setrate(f.getframerate()) # 8bit is unsigned in wav files if f.getsampwidth() == 1: device.setformat(alsaaudio.PCM_FORMAT_U8) # Otherwise we assume signed data, little endian elif f.getsampwidth() == 2: device.setformat(alsaaudio.PCM_FORMAT_S16_LE) elif f.getsampwidth() == 3: device.setformat(alsaaudio.PCM_FORMAT_S24_LE) elif f.getsampwidth() == 4: device.setformat(alsaaudio.PCM_FORMAT_S32_LE) else: raise ValueError('Unsupported format') device.setperiodsize(320) data = f.readframes(320) while data: # Read data from stdin device.write(data) data = f.readframes(320) def usage(): sys.stderr.write('usage: playwav.py [-c ] \n') sys.exit(2) if __name__ == '__main__': card = 'default' opts, args = getopt.getopt(sys.argv[1:], 'c:') for o, a in opts: if o == '-c': card = a if not args: usage() f = wave.open(args[0], 'rb') device = alsaaudio.PCM(card=card) play(device, f) f.close() pyalsaaudio-0.7/README0000644000175000017500000000357411144302601014500 0ustar larslars00000000000000PyAlsaAudio =========== Author: Casper Wilstrup (cwi@aves.dk) This package contains wrappers for accessing the ALSA api from Python. It is currently fairly complete for PCM devices. My next goal is to have 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 useful 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. pyalsaaudio-0.7/setup.py0000755000175000017500000000327311620311200015323 0ustar larslars00000000000000#!/usr/bin/env python '''This package contains wrappers for accessing the ALSA API from Python. It is fairly complete for PCM devices and Mixer access. ''' from distutils.core import setup from distutils.extension import Extension from sys import version pyalsa_version = '0.7' # patch distutils if it's too old to cope with the "classifiers" or # "download_url" keywords from sys import version if version < '2.2.3': from distutils.dist import DistributionMetadata DistributionMetadata.classifiers = None DistributionMetadata.download_url = None if __name__ == '__main__': setup( name = 'pyalsaaudio', version = pyalsa_version, description = 'ALSA bindings', long_description = __doc__, author = 'Casper Wilstrup', author_email='cwi@aves.dk', maintainer = 'Lars Immisch', maintainer_email = 'lars@ibp.de', license='PSF', platforms=['posix'], url='http://pyalsaaudio.sourceforge.net/', classifiers = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Python Software Foundation License', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Topic :: Multimedia :: Sound/Audio', 'Topic :: Multimedia :: Sound/Audio :: Mixers', 'Topic :: Multimedia :: Sound/Audio :: Players', 'Topic :: Multimedia :: Sound/Audio :: Capture/Recording', ], ext_modules=[Extension('alsaaudio',['alsaaudio.c'], libraries=['asound'])] ) pyalsaaudio-0.7/recordtest.py0000755000175000017500000000405311144302601016344 0ustar larslars00000000000000#!/usr/bin/env python ## 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 # Footnote: I'd normally use print instead of sys.std(out|err).write, # but we're in the middle of the conversion between python 2 and 3 # and this code runs on both versions without conversion import sys import time import getopt import alsaaudio def usage(): sys.stderr.write('usage: recordtest.py [-c ] \n') sys.exit(2) if __name__ == '__main__': card = 'default' opts, args = getopt.getopt(sys.argv[1:], 'c:') for o, a in opts: if o == '-c': card = a if not args: usage() f = open(args[0], 'wb') # 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, card) # Set attributes: Mono, 44100 Hz, 16 bit little endian samples inp.setchannels(1) inp.setrate(44100) 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: f.write(data) time.sleep(.001) pyalsaaudio-0.7/playpoll.py0000755000175000017500000000316111620307577016041 0ustar larslars00000000000000#!/usr/bin/env python # Simple test script that plays (some) wav files # Footnote: I'd normally use print instead of sys.std(out|err).write, # but this version runs on python 2 and python 3 without conversion import sys import wave import getopt import alsaaudio def play(device, f): sys.stdout.write('%d channels, %d sampling rate\n' % (f.getnchannels(), f.getframerate())) # Set attributes device.setchannels(f.getnchannels()) device.setrate(f.getframerate()) # 8bit is unsigned in wav files if f.getsampwidth() == 1: device.setformat(alsaaudio.PCM_FORMAT_U8) # Otherwise we assume signed data, little endian elif f.getsampwidth() == 2: device.setformat(alsaaudio.PCM_FORMAT_S16_LE) elif f.getsampwidth() == 3: device.setformat(alsaaudio.PCM_FORMAT_S24_LE) elif f.getsampwidth() == 4: device.setformat(alsaaudio.PCM_FORMAT_S32_LE) else: raise ValueError('Unsupported format') device.setperiodsize(320) print device.polldescriptors() data = f.readframes(320) while data: # Read data from stdin device.write(data) data = f.readframes(320) def usage(): sys.stderr.write('usage: playwav.py [-c ] \n') sys.exit(2) if __name__ == '__main__': card = 'default' opts, args = getopt.getopt(sys.argv[1:], 'c:') for o, a in opts: if o == '-c': card = a if not args: usage() f = wave.open(args[0], 'rb') device = alsaaudio.PCM(card=card) play(device, f) f.close() pyalsaaudio-0.7/LICENSE0000644000175000017500000000473611144302601014626 0ustar larslars00000000000000PyAlsaAudio 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. pyalsaaudio-0.7/test.py0000755000175000017500000000677211312774651015176 0ustar larslars00000000000000#!/usr/bin/env python # These are internal test. They shouldn't fail, but they don't cover all # of the ALSA API. Most of all PCM.read and PCM.write are missing. # These need to be tested by playbacktest.py and recordtest.py # In case of a problem, run these tests. If they fail, file a bug report on # http://sourceforge.net/projects/pyalsaaudio import unittest import alsaaudio # we can't test read and write well - these are tested otherwise PCMMethods = [('pcmtype', None), ('pcmmode', None), ('cardname', None), ('setchannels', (2,)), ('setrate', (44100,)), ('setformat', (alsaaudio.PCM_FORMAT_S8,)), ('setperiodsize', (320,))] # A clever test would look at the Mixer capabilities and selectively run the # omitted tests, but I am too tired for that. MixerMethods = [('cardname', None), ('mixer', None), ('mixerid', None), ('switchcap', None), ('volumecap', None), ('getvolume', None), ('getrange', None), ('getenum', None), # ('getmute', None), # ('getrec', None), # ('setvolume', (60,)), # ('setmute', (0,)) # ('setrec', (0')), ] class MixerTest(unittest.TestCase): """Test Mixer objects""" def testMixer(self): """Open a Mixer on every card""" # Mixers are addressed by index, not name for i in range(len(alsaaudio.cards())): mixers = alsaaudio.mixers(i) for m in mixers: mixer = alsaaudio.Mixer(m, cardindex=i) mixer.close() def testMixerAll(self): "Run common Mixer methods on an open object" mixers = alsaaudio.mixers() mixer = alsaaudio.Mixer(mixers[0]) for m, a in MixerMethods: f = alsaaudio.Mixer.__dict__[m] if a is None: f(mixer) else: f(mixer, *a) mixer.close() def testMixerClose(self): """Run common Mixer methods on a closed object and verify it raises an error""" mixers = alsaaudio.mixers() mixer = alsaaudio.Mixer(mixers[0]) mixer.close() for m, a in MixerMethods: f = alsaaudio.Mixer.__dict__[m] if a is None: self.assertRaises(alsaaudio.ALSAAudioError, f, mixer) else: self.assertRaises(alsaaudio.ALSAAudioError, f, mixer, *a) class PCMTest(unittest.TestCase): """Test PCM objects""" def testPCM(self): "Open a PCM object on every card" for i in range(len(alsaaudio.cards())): pcm = alsaaudio.PCM(i) pcm.close() def testPCMAll(self): "Run all PCM methods on an open object" pcm = alsaaudio.PCM() for m, a in PCMMethods: f = alsaaudio.PCM.__dict__[m] if a is None: f(pcm) else: f(pcm, *a) pcm.close() def testPCMClose(self): "Run all PCM methods on a closed object and verify it raises an error" pcm = alsaaudio.PCM() pcm.close() for m, a in PCMMethods: f = alsaaudio.PCM.__dict__[m] if a is None: self.assertRaises(alsaaudio.ALSAAudioError, f, pcm) else: self.assertRaises(alsaaudio.ALSAAudioError, f, pcm, *a) if __name__ == '__main__': unittest.main() pyalsaaudio-0.7/alsaaudio.c0000644000175000017500000017035711620302575015743 0ustar larslars00000000000000/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * 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@aves.dk) * * Bug fixes and maintenance by Lars Immisch * * License: Python Software Foundation License * */ #include "Python.h" #if PY_MAJOR_VERSION < 3 && PY_MINOR_VERSION < 6 #include "stringobject.h" #define PyUnicode_FromString PyString_FromString #endif #include #include 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; /* Translate a card id to a ALSA cardname Returns a newly allocated string. */ char *translate_cardname(char *name) { static char dflt[] = "default"; char *full = NULL; if (!name || !strcmp(name, dflt)) return strdup(dflt); // If we find a colon, we assume it is a real ALSA cardname if (strchr(name, ':')) return strdup(name); full = malloc(strlen("default:CARD=") + strlen(name) + 1); sprintf(full, "default:CARD=%s", name); return full; } /* Translate a card index to a ALSA cardname Returns a newly allocated string. */ char *translate_cardidx(int idx) { char name[32]; sprintf(name, "hw:%d", idx); return strdup(name); } /******************************************/ /* PCM object wrapper */ /******************************************/ static PyTypeObject ALSAPCMType; static PyObject *ALSAAudioError; static PyObject * alsacard_list(PyObject *self, PyObject *args) { int rc; int card = -1; snd_ctl_card_info_t *info; snd_ctl_t *handle; PyObject *result = NULL; if (!PyArg_ParseTuple(args,":cards")) return NULL; snd_ctl_card_info_alloca(&info); result = PyList_New(0); for (rc = snd_card_next(&card); !rc && (card >= 0); rc = snd_card_next(&card)) { char name[32]; int err; PyObject *item; /* One would be tempted to think that snd_card_get_name returns a name that is actually meaningful for any further operations. Not in ALSA land. Here we need the id, not the name */ sprintf(name, "hw:%d", card); if ((err = snd_ctl_open(&handle, name, 0)) < 0) { PyErr_SetString(ALSAAudioError,snd_strerror(err)); return NULL; } if ((err = snd_ctl_card_info(handle, info)) < 0) { PyErr_SetString(ALSAAudioError,snd_strerror(err)); snd_ctl_close(handle); Py_DECREF(result); return NULL; } item = PyUnicode_FromString(snd_ctl_card_info_get_id(info)); PyList_Append(result, item); Py_DECREF(item); snd_ctl_close(handle); } return result; } PyDoc_STRVAR(cards_doc, "cards()\n\ \n\ List the available card ids."); static int alsapcm_setup(alsapcm_t *self) { int res,dir; unsigned int val; snd_pcm_format_t fmt; snd_pcm_uframes_t frames; snd_pcm_hw_params_t *hwparams; /* Allocate a hwparam structure on the stack, and fill it 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 with default values. We don't care if any of this fails - we'll read the actual values back out. */ 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); /* 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, &fmt); self->format = fmt; 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 = SND_PCM_STREAM_PLAYBACK; int pcmmode = 0; char *kw[] = { "type", "mode", "card", NULL }; char *cardname = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiz", kw, &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_CAPTURE (1)"); return NULL; } if (pcmmode < 0 || pcmmode > SND_PCM_ASYNC) { PyErr_SetString(ALSAAudioError, "Invalid PCM mode"); return NULL; } self->handle = 0; self->pcmtype = pcmtype; self->pcmmode = pcmmode; self->cardname = translate_cardname(cardname); self->channels = 2; self->rate = 44100; self->format = SND_PCM_FORMAT_S16_LE; self->periodsize = 32; res = snd_pcm_open(&(self->handle), self->cardname, self->pcmtype, self->pcmmode); if (res >= 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_close(alsapcm_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":close")) return NULL; if (self->handle) { Py_BEGIN_ALLOW_THREADS snd_pcm_drain(self->handle); snd_pcm_close(self->handle); Py_END_ALLOW_THREADS self->handle = 0; } Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(pcm_close_doc, "close() -> None\n\ \n\ Close a PCM device."); static PyObject * alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) { unsigned int val,val2; snd_pcm_format_t fmt; 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,":dumpinfo")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); 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, &fmt); printf("format = '%s' (%s)\n", snd_pcm_format_name(fmt), snd_pcm_format_description(fmt)); 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_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); 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,":pcmtype")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } return PyLong_FromLong(self->pcmtype); } PyDoc_STRVAR(pcmtype_doc, "pcmtype() -> int\n\ \n\ Returns either PCM_CAPTURE or PCM_PLAYBACK."); static PyObject * alsapcm_pcmmode(alsapcm_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":pcmmode")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } return PyLong_FromLong(self->pcmmode); } PyDoc_STRVAR(pcmmode_doc, "pcmmode() -> int\n\ \n\ Returns the mode of the PCM object. One of:\n\ - PCM_NONBLOCK\n\ - PCM_ASYNC\n\ - PCM_NORMAL."); static PyObject * alsapcm_cardname(alsapcm_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":cardname")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } return PyUnicode_FromString(self->cardname); } PyDoc_STRVAR(cardname_doc, "cardname() -> string\n\ \n\ Returns the name of the sound card used by this PCM object."); static PyObject * alsapcm_setchannels(alsapcm_t *self, PyObject *args) { int channels; int res; if (!PyArg_ParseTuple(args,"i:setchannels",&channels)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } self->channels = channels; res = alsapcm_setup(self); if (res < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(res)); return NULL; } return PyLong_FromLong(self->channels); } PyDoc_STRVAR(setchannels_doc, "setchannels(numchannels)\n\ \n\ Used to set the number of capture or playback channels. Common values\n\ are: 1 = mono, 2 = stereo, and 6 = full 6 channel audio.\n\ \n\ Few sound cards support more than 2 channels."); static PyObject * alsapcm_setrate(alsapcm_t *self, PyObject *args) { int rate; int res; if (!PyArg_ParseTuple(args,"i:setrate",&rate)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } self->rate = rate; res = alsapcm_setup(self); if (res < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(res)); return NULL; } return PyLong_FromLong(self->rate); } PyDoc_STRVAR(setrate_doc, "setrate(rate)\n\ \n\ Set the sample rate in Hz for the device. Typical values are\n\ 8000 (telephony), 11025, 44100 (CD), 48000 (DVD audio) and 96000"); static PyObject * alsapcm_setformat(alsapcm_t *self, PyObject *args) { int format; int res; if (!PyArg_ParseTuple(args,"i:setformat",&format)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } self->format = format; res = alsapcm_setup(self); if (res < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(res)); return NULL; } return PyLong_FromLong(self->format); } PyDoc_STRVAR(setformat_doc, "setformat(rate)\n"); static PyObject * alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) { int periodsize; int res; if (!PyArg_ParseTuple(args,"i:setperiodsize",&periodsize)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } self->periodsize = periodsize; res = alsapcm_setup(self); if (res < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(res)); return NULL; } return PyLong_FromLong(self->periodsize); } PyDoc_STRVAR(setperiodsize_doc, "setperiodsize(period) -> int\n\ \n\ Sets the actual period size in frames. Each write should consist of\n\ exactly this number of frames, and each read will return this number of\n\ frames (unless the device is in PCM_NONBLOCK mode, in which case it\n\ may return nothing at all)."); 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,":read")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } if (self->pcmtype != SND_PCM_STREAM_CAPTURE) { PyErr_SetString(ALSAAudioError,"Cannot read from playback PCM"); return NULL; } Py_BEGIN_ALLOW_THREADS res = snd_pcm_readi(self->handle, buffer, self->periodsize); if (res == -EPIPE) { /* EPIPE means overrun */ snd_pcm_prepare(self->handle); } Py_END_ALLOW_THREADS if (res != -EPIPE) { if (res == -EAGAIN) { res = 0; } else if (res < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(res)); return NULL; } } #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, "read() -> (size, data)\n\ \n\ In PCM_NORMAL mode, this function blocks until a full period is\n\ available, and then returns a tuple (length,data) where length is\n\ the number of frames of the captured data, and data is the captured sound\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) { int res; 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 (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } if (datalen % self->framesize) { PyErr_SetString(ALSAAudioError, "Data size must be a multiple of framesize"); return NULL; } Py_BEGIN_ALLOW_THREADS res = snd_pcm_writei(self->handle, data, datalen/self->framesize); if (res == -EPIPE) { /* EPIPE means underrun */ res = snd_pcm_recover(self->handle, res, 1); if (res >= 0) res = snd_pcm_writei(self->handle, data, datalen/self->framesize); } Py_END_ALLOW_THREADS if (res == -EAGAIN) return PyLong_FromLong(0); else if (res < 0) { PyErr_SetString(ALSAAudioError,snd_strerror(res)); return NULL; } return PyLong_FromLong(res); } PyDoc_STRVAR(write_doc, "write(data) -> bytes written\n\ \n\ Writes (plays) the sound in data. The length of data must be a multiple\n\ of the frame size, and should be exactly the size of a period. If less\n\ than 'period size' frames are provided, the actual playout will not\n\ happen until more data is written.\n\ If the device is not in PCM_NONBLOCK mode, this call will block if the\n\ kernel buffer is full, and until enough sound has been played to allow\n\ the sound data to be buffered. The call always returns the size of the\n\ data provided.\n\ \n\ In PCM_NONBLOCK mode, the call will return immediately, with a return\n\ value of zero, if the buffer is full. In this case, the data should be\n\ written at a later time."); static PyObject *alsapcm_pause(alsapcm_t *self, PyObject *args) { int enabled=1, res; if (!PyArg_ParseTuple(args,"|i:pause",&enabled)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } Py_BEGIN_ALLOW_THREADS res = snd_pcm_pause(self->handle, enabled); Py_END_ALLOW_THREADS if (res < 0) { PyErr_SetString(ALSAAudioError,snd_strerror(res)); return NULL; } return PyLong_FromLong(res); } PyDoc_STRVAR(pause_doc, "pause(enable=1)\n\ \n\ If enable is 1, playback or capture is paused. If enable is 0,\n\ playback/capture is resumed."); static PyObject * alsapcm_polldescriptors(alsapcm_t *self, PyObject *args) { int i, count, rc; PyObject *result; struct pollfd *fds; if (!PyArg_ParseTuple(args,":polldescriptors")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "PCM device is closed"); return NULL; } count = snd_pcm_poll_descriptors_count(self->handle); if (count < 0) { PyErr_SetString(ALSAAudioError,"Can't get poll descriptor count"); return NULL; } fds = (struct pollfd*)calloc(count, sizeof(struct pollfd)); if (!fds) { PyErr_SetString(PyExc_MemoryError, "Out of memory"); return NULL; } result = PyList_New(count); rc = snd_pcm_poll_descriptors(self->handle, fds, (unsigned int)count); if (rc != count) { PyErr_SetString(ALSAAudioError,"Can't get poll descriptors"); return NULL; } for (i = 0; i < count; ++i) { PyList_SetItem(result, i, Py_BuildValue("II", fds[i].fd, fds[i].events)); } return result; } PyDoc_STRVAR(pcm_polldescriptors_doc, "polldescriptors() -> List of tuples (fd, eventmask).\n\ \n\ Return a list of file descriptors and event masks\n\ suitable for use with poll."); /* ALSA PCM Object Bureaucracy */ static PyMethodDef alsapcm_methods[] = { {"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS, pcmtype_doc}, {"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS, pcmmode_doc}, {"cardname", (PyCFunction)alsapcm_cardname, METH_VARARGS, cardname_doc}, {"setchannels", (PyCFunction)alsapcm_setchannels, METH_VARARGS, setchannels_doc }, {"setrate", (PyCFunction)alsapcm_setrate, METH_VARARGS, setrate_doc}, {"setformat", (PyCFunction)alsapcm_setformat, METH_VARARGS, setformat_doc}, {"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS, setperiodsize_doc}, {"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS}, {"read", (PyCFunction)alsapcm_read, METH_VARARGS, read_doc}, {"write", (PyCFunction)alsapcm_write, METH_VARARGS, write_doc}, {"pause", (PyCFunction)alsapcm_pause, METH_VARARGS, pause_doc}, {"close", (PyCFunction)alsapcm_close, METH_VARARGS, pcm_close_doc}, {"polldescriptors", (PyCFunction)alsapcm_polldescriptors, METH_VARARGS, pcm_polldescriptors_doc}, {NULL, NULL} }; #if PY_VERSION_HEX < 0x02020000 static PyObject * alsapcm_getattr(alsapcm_t *self, char *name) { return Py_FindMethod(alsapcm_methods, (PyObject *)self, 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 */ /* methods */ (destructor) alsapcm_dealloc, /* tp_dealloc */ 0, /* print */ #if PY_VERSION_HEX < 0x02020000 (getattrfunc)alsapcm_getattr, /* tp_getattr */ #else 0, /* tp_getattr */ #endif 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 */ #if PY_VERSION_HEX >= 0x02020000 PyObject_GenericGetAttr, /* tp_getattro */ #else 0, /* tp_getattro */ #endif 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ "ALSA PCM device.", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ alsapcm_methods, /* tp_methods */ 0, /* tp_members */ }; /******************************************/ /* 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; int cardidx = 0; char cardname[32]; PyObject *result; if (!PyArg_ParseTuple(args,"|i:mixers",&cardidx)) return NULL; sprintf(cardname, "hw:%d", cardidx); 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; } result = PyList_New(0); for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { PyObject *mixer; snd_mixer_selem_get_id(elem, sid); mixer = PyUnicode_FromString(snd_mixer_selem_id_get_name(sid)); PyList_Append(result,mixer); Py_DECREF(mixer); } snd_mixer_close(handle); return result; } PyDoc_STRVAR(mixers_doc, "mixers([cardname])\n\ \n\ List the available mixers. The optional cardname specifies\n\ which card should be queried (this is only relevant if you\n\ have more than one sound card). Omit to use the default sound card."); 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; int cardindex = 0; char *control = "Master"; int id = 0; snd_mixer_elem_t *elem; int channel; char *kw[] = { "control", "id", "cardindex", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii", kw, &control, &id, &cardindex)) return NULL; if (!(self = (alsamixer_t *)PyObject_New(alsamixer_t, &ALSAMixerType))) return NULL; self->handle = 0; self->cardname = translate_cardidx(cardindex); err = alsamixer_gethandle(self->cardname, &self->handle); if (err<0) { PyErr_SetString(ALSAAudioError,snd_strerror(err)); free(self->cardname); return NULL; } 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_close(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":close")) return NULL; snd_mixer_close(self->handle); free(self->cardname); free(self->controlname); self->handle = 0; Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(mixer_close_doc, "close() -> None\n\ \n\ Close a Mixer."); static PyObject * alsamixer_cardname(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":cardname")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } return PyUnicode_FromString(self->cardname); } PyDoc_STRVAR(mixer_cardname_doc, "cardname() -> string\n\ \n\ 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; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } return PyUnicode_FromString(self->controlname); } PyDoc_STRVAR(mixer_doc, "mixer() -> string\n\ \n\ Returns the name of the specific mixer controlled by this object,\n\ for example 'Master' or 'PCM'"); static PyObject * alsamixer_mixerid(alsamixer_t *self, PyObject *args) { if (!PyArg_ParseTuple(args,":mixerid")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } return PyLong_FromLong(self->controlid); } PyDoc_STRVAR(mixerid_doc, "mixerid() -> int\n\ \n\ Returns the ID of the ALSA mixer controlled by this object."); static PyObject * alsamixer_volumecap(alsamixer_t *self, PyObject *args) { PyObject *result; PyObject *item; if (!PyArg_ParseTuple(args,":volumecap")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } result = PyList_New(0); if (self->volume_cap&MIXER_CAP_VOLUME) { item = PyUnicode_FromString("Volume"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_VOLUME_JOINED) { item = PyUnicode_FromString("Joined Volume"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_PVOLUME) { item = PyUnicode_FromString("Playback Volume"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_PVOLUME_JOINED) { item = PyUnicode_FromString("Joined Playback Volume"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_CVOLUME) { item = PyUnicode_FromString("Capture Volume"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_CVOLUME_JOINED) { item = PyUnicode_FromString("Joined Capture Volume"); PyList_Append(result, item); Py_DECREF(item); } return result; } PyDoc_STRVAR(volumecap_doc, "volumecap() -> List of volume capabilities (string)\n\ \n\ Returns a list of the volume control capabilities of this mixer.\n\ Possible values in this list are:\n\ - 'Volume'\n\ - 'Joined Volume'\n\ - 'Playback Volume'\n\ - 'Joined Playback Mute'\n\ - 'Capture Volume'\n\ - 'Joined Capture Volume'"); static PyObject * alsamixer_switchcap(alsamixer_t *self, PyObject *args) { PyObject *result; PyObject *item; if (!PyArg_ParseTuple(args,":switchcap")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } result = PyList_New(0); if (self->volume_cap&MIXER_CAP_SWITCH) { item = PyUnicode_FromString("Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_SWITCH_JOINED) { item = PyUnicode_FromString("Joined Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_PSWITCH) { item = PyUnicode_FromString("Playback Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_PSWITCH_JOINED) { item = PyUnicode_FromString("Joined Playback Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_CSWITCH) { item = PyUnicode_FromString("Capture Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_CSWITCH_JOINED) { item = PyUnicode_FromString("Joined Capture Mute"); PyList_Append(result, item); Py_DECREF(item); } if (self->volume_cap&MIXER_CAP_CSWITCH_EXCLUSIVE) { item = PyUnicode_FromString("Capture Exclusive"); PyList_Append(result, item); Py_DECREF(item); } return result; } PyDoc_STRVAR(switchcap_doc, "switchcap() -> List of switch capabilities (string)\n\ \n\ Returns a list of the switches which are defined by this mixer.\n\ \n\ Possible values in this list are:\n\ - 'Mute'\n\ - 'Joined Mute'\n\ - 'Playback Mute'\n\ - 'Joined Playback Mute'\n\ - 'Capture Mute'\n\ - 'Joined Capture Mute'\n\ - 'Capture Exclusive'\n"); 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; PyObject *item; if (!PyArg_ParseTuple(args,"|s:getvolume",&dirstr)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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); item = PyLong_FromLong(alsamixer_getpercentage(self->pmin, self->pmax, ival)); PyList_Append(result, item); Py_DECREF(item); } 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); item = PyLong_FromLong(alsamixer_getpercentage(self->cmin, self->cmax, ival)); PyList_Append(result, item); Py_DECREF(item); } } return result; } PyDoc_STRVAR(getvolume_doc, "getvolume([direction]) -> List of volume settings (int)\n\ \n\ Returns a list with the current volume settings for each channel.\n\ The list elements are integer percentages.\n\ \n\ The optional 'direction' argument can be either 'playback' or\n\ 'capture', which is relevant if the mixer can control both\n\ playback and capture volume. The default value is 'playback'\n\ if the mixer has this capability, otherwise 'capture'"); static PyObject * alsamixer_getrange(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; int direction; char *dirstr = 0; if (!PyArg_ParseTuple(args,"|s:getrange",&dirstr)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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 argument for direction"); return NULL; } if (direction == 0) { if (snd_mixer_selem_has_playback_channel(elem, 0)) { return Py_BuildValue("[ii]", self->pmin, self->pmax); } PyErr_SetString(ALSAAudioError, "Mixer has no playback channel"); return NULL; } else if (direction == 1) { if (snd_mixer_selem_has_capture_channel(elem, 0) && snd_mixer_selem_has_capture_volume(elem)) { return Py_BuildValue("[ii]", self->cmin, self->cmax); } PyErr_SetString(ALSAAudioError, "Mixer has no capture channel " "or capture volume"); return NULL; } // Unreached statement PyErr_SetString(ALSAAudioError,"Huh?"); return NULL; } PyDoc_STRVAR(getrange_doc, "getrange([direction]) -> List of (min_volume, max_volume)\n\ \n\ Returns a list of tuples with the volume range (ints).\n\ \n\ The optional 'direction' argument can be either 'playback' or\n\ 'capture', which is relevant if the mixer can control both\n\ playback and capture volume. The default value is 'playback'\n\ if the mixer has this capability, otherwise 'capture'"); static PyObject * alsamixer_getenum(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; PyObject *elems; int i, count, rc; unsigned int index; char name[32]; PyObject *result; if (!PyArg_ParseTuple(args, ":getenum")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid); if (!snd_mixer_selem_is_enumerated(elem)) { // Not an enumerated control, return an empty tuple return PyTuple_New(0); } count = snd_mixer_selem_get_enum_items(elem); if (count < 0) { PyErr_SetString(ALSAAudioError, snd_strerror(count)); return NULL; } result = PyTuple_New(2); if (!result) return NULL; rc = snd_mixer_selem_get_enum_item(elem, 0, &index); if(rc) { PyErr_SetString(ALSAAudioError, snd_strerror(rc)); return NULL; } rc = snd_mixer_selem_get_enum_item_name(elem, index, sizeof(name)-1, name); if (rc) { Py_DECREF(result); PyErr_SetString(ALSAAudioError, snd_strerror(rc)); return NULL; } PyTuple_SetItem(result, 0, PyUnicode_FromString(name)); elems = PyList_New(count); if (!elems) { Py_DECREF(result); return NULL; } for (i = 0; i < count; ++i) { rc = snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name); if (rc) { Py_DECREF(elems); Py_DECREF(result); PyErr_SetString(ALSAAudioError, snd_strerror(rc)); return NULL; } PyList_SetItem(elems, i, PyUnicode_FromString(name)); } PyTuple_SetItem(result, 1, elems); return result; } PyDoc_STRVAR(getenum_doc, "getenum() -> Tuple of (string, list of strings)\n\ \n\ Returns a a tuple. The first element is name of the active enumerated item, \n\ the second a list available enumerated items."); static PyObject * alsamixer_getmute(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; int i; int ival; PyObject *result; PyObject *item; if (!PyArg_ParseTuple(args,":getmute")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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); item = PyLong_FromLong(!ival); PyList_Append(result, item); Py_DECREF(item); } } return result; } PyDoc_STRVAR(getmute_doc, "getmute() -> List of mute settings (int)\n\ \n\ Return a list indicating the current mute setting for each channel.\n\ 0 means not muted, 1 means muted.\n\ \n\ This method will fail if the mixer has no playback switch capabilities."); static PyObject * alsamixer_getrec(alsamixer_t *self, PyObject *args) { snd_mixer_elem_t *elem; int i; int ival; PyObject *result; PyObject *item; if (!PyArg_ParseTuple(args,":getrec")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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); item = PyLong_FromLong(ival); PyList_Append(result, item); Py_DECREF(item); } } return result; } PyDoc_STRVAR(getrec_doc, "getrec() -> List of record mute settings (int)\n\ \n\ Return a list indicating the current record mute setting for each\n\ channel. 0 means not recording, 1 means recording.\n\ This method will fail if the mixer has no capture switch capabilities."); 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:setvolume",&volume,&channel,&dirstr)) return NULL; if (volume < 0 || volume > 100) { PyErr_SetString(ALSAAudioError,"Volume must be between 0 and 100"); return NULL; } if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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; } PyDoc_STRVAR(setvolume_doc, "setvolume(volume[[, channel] [, direction]])\n\ \n\ Change the current volume settings for this mixer. The volume argument\n\ controls the new volume setting as an integer percentage.\n\ If the optional argument channel is present, the volume is set only for\n\ this channel. This assumes that the mixer can control the volume for the\n\ channels independently.\n\ \n\ The optional direction argument can be either 'playback' or 'capture'.\n\ It is relevant if the mixer has independent playback and capture volume\n\ capabilities, and controls which of the volumes will be changed.\n\ The default is 'playback' if the mixer has this capability, otherwise\n\ 'capture'."); 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:setmute",&mute,&channel)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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; } PyDoc_STRVAR(setmute_doc, "setmute(mute [, channel])\n\ \n\ Sets the mute flag to a new value. The mute argument is either 0 for\n\ not muted, or 1 for muted.\n\ The optional channel argument controls which channel is muted.\n\ If omitted, the mute flag is set for for all channels.\n\ \n\ This method will fail if the mixer has no playback mute capabilities"); 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:setrec",&rec,&channel)) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); 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_capture_switch(elem, i, rec); done++; } } } if (!done) { PyErr_SetString(ALSAAudioError,"Invalid channel number"); return NULL; } Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(setrec_doc, "setrec(capture [, channel])\n\ \n\ Sets the capture mute flag to a new value. The capture argument is\n\ either 0 for no capture, or 1 for capture.\n\ The optional channel argument controls which channel is changed.\n\ If omitted, the capture flag is set for all channels.\n\ \n\ This method will fail if the mixer has no capture switch capabilities"); static PyObject * alsamixer_polldescriptors(alsamixer_t *self, PyObject *args) { int i, count, rc; PyObject *result; struct pollfd *fds; if (!PyArg_ParseTuple(args,":polldescriptors")) return NULL; if (!self->handle) { PyErr_SetString(ALSAAudioError, "Mixer is closed"); return NULL; } count = snd_mixer_poll_descriptors_count(self->handle); if (count < 0) { PyErr_SetString(ALSAAudioError,"Can't get poll descriptor count"); return NULL; } fds = (struct pollfd*)calloc(count, sizeof(struct pollfd)); if (!fds) { PyErr_SetString(PyExc_MemoryError, "Out of memory"); return NULL; } result = PyList_New(count); rc = snd_mixer_poll_descriptors(self->handle, fds, (unsigned int)count); if (rc != count) { PyErr_SetString(ALSAAudioError,"Can't get poll descriptors"); return NULL; } for (i = 0; i < count; ++i) { PyList_SetItem(result, i, Py_BuildValue("II", fds[i].fd, fds[i].events)); } return result; } PyDoc_STRVAR(polldescriptors_doc, "polldescriptors() -> List of tuples (fd, eventmask).\n\ \n\ Return a list of file descriptors and event masks\n\ suitable for use with poll to monitor changes on this mixer."); static PyMethodDef alsamixer_methods[] = { {"cardname", (PyCFunction)alsamixer_cardname, METH_VARARGS, mixer_cardname_doc}, {"close", (PyCFunction)alsamixer_close, METH_VARARGS, mixer_close_doc}, {"mixer", (PyCFunction)alsamixer_mixer, METH_VARARGS, mixer_doc}, {"mixerid", (PyCFunction)alsamixer_mixerid, METH_VARARGS, mixerid_doc}, {"switchcap", (PyCFunction)alsamixer_switchcap, METH_VARARGS, switchcap_doc}, {"volumecap", (PyCFunction)alsamixer_volumecap, METH_VARARGS, volumecap_doc}, {"getvolume", (PyCFunction)alsamixer_getvolume, METH_VARARGS, getvolume_doc}, {"getrange", (PyCFunction)alsamixer_getrange, METH_VARARGS, getrange_doc}, {"getenum", (PyCFunction)alsamixer_getenum, METH_VARARGS, getenum_doc}, {"getmute", (PyCFunction)alsamixer_getmute, METH_VARARGS, getmute_doc}, {"getrec", (PyCFunction)alsamixer_getrec, METH_VARARGS, getrec_doc}, {"setvolume", (PyCFunction)alsamixer_setvolume, METH_VARARGS, setvolume_doc}, {"setmute", (PyCFunction)alsamixer_setmute, METH_VARARGS, setmute_doc}, {"setrec", (PyCFunction)alsamixer_setrec, METH_VARARGS, setrec_doc}, {"polldescriptors", (PyCFunction)alsamixer_polldescriptors, METH_VARARGS, polldescriptors_doc}, {NULL, NULL} }; #if PY_VERSION_HEX < 0x02020000 static PyObject * alsamixer_getattr(alsapcm_t *self, char *name) { return Py_FindMethod(alsamixer_methods, (PyObject *)self, 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 */ /* methods */ (destructor) alsamixer_dealloc, /* tp_dealloc */ 0, /* print */ #if PY_VERSION_HEX < 0x02020000 (getattrfunc)alsamixer_getattr, /* tp_getattr */ #else 0, /* tp_getattr */ #endif 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 */ #if PY_VERSION_HEX >= 0x02020000 PyObject_GenericGetAttr, /* tp_getattro*/ #else 0, /* tp_getattro*/ #endif 0, /* tp_setattro*/ 0, /* tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /* tp_flags */ "ALSA Mixer Control.", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ alsamixer_methods, /* tp_methods */ 0, /* tp_members */ }; /******************************************/ /* Module initialization */ /******************************************/ static PyMethodDef alsaaudio_methods[] = { { "cards", alsacard_list, METH_VARARGS, cards_doc}, { "mixers", alsamixer_list, METH_VARARGS, mixers_doc}, { 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; #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(); #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) #if PY_MAJOR_VERSION < 3 return; #else return NULL; #endif /* 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); #if 0 // Omit for now - use case unknown _EXPORT_INT(m, "MIXER_SCHN_UNKNOWN", SND_MIXER_SCHN_UNKNOWN); _EXPORT_INT(m, "MIXER_SCHN_FRONT_LEFT", SND_MIXER_SCHN_FRONT_LEFT); _EXPORT_INT(m, "MIXER_SCHN_FRONT_RIGHT", SND_MIXER_SCHN_FRONT_RIGHT); _EXPORT_INT(m, "MIXER_SCHN_REAR_LEFT", SND_MIXER_SCHN_REAR_LEFT); _EXPORT_INT(m, "MIXER_SCHN_REAR_RIGHT", SND_MIXER_SCHN_REAR_RIGHT); _EXPORT_INT(m, "MIXER_SCHN_FRONT_CENTER", SND_MIXER_SCHN_FRONT_CENTER); _EXPORT_INT(m, "MIXER_SCHN_WOOFER", SND_MIXER_SCHN_WOOFER); _EXPORT_INT(m, "MIXER_SCHN_SIDE_LEFT", SND_MIXER_SCHN_SIDE_LEFT); _EXPORT_INT(m, "MIXER_SCHN_SIDE_RIGHT", SND_MIXER_SCHN_SIDE_RIGHT); _EXPORT_INT(m, "MIXER_SCHN_REAR_CENTER", SND_MIXER_SCHN_REAR_CENTER); _EXPORT_INT(m, "MIXER_SCHN_MONO", SND_MIXER_SCHN_MONO); #endif #if PY_MAJOR_VERSION >= 3 return m; #endif } pyalsaaudio-0.7/doc/0000755000175000017500000000000011620311641014357 5ustar larslars00000000000000pyalsaaudio-0.7/doc/html/0000755000175000017500000000000011620311641015323 5ustar larslars00000000000000pyalsaaudio-0.7/doc/html/modindex.html0000644000175000017500000000712111313010625020016 0ustar larslars00000000000000 Global Module Index — alsaaudio v0.6 documentation

Global Module Index

A
 
A
alsaaudio (Linux)
pyalsaaudio-0.7/doc/html/searchindex.js0000644000175000017500000001657211620311215020166 0ustar larslars00000000000000Search.setIndex({objects:{"":{alsaaudio:[1,0,0]},"alsaaudio.PCM":{pause:[1,1,1],setrate:[1,1,1],cardname:[1,1,1],setformat:[1,1,1],write:[1,1,1],read:[1,1,1],pcmmode:[1,1,1],setchannels:[1,1,1],pcmtype:[1,1,1],setperiodsize:[1,1,1]},"alsaaudio.Mixer":{getmute:[1,1,1],getrange:[1,1,1],setmute:[1,1,1],cardname:[1,1,1],switchcap:[1,1,1],mixer:[1,1,1],volumecap:[1,1,1],getenum:[1,1,1],getrec:[1,1,1],polldescriptors:[1,1,1],mixerid:[1,1,1],setrec:[1,1,1],getvolume:[1,1,1],setvolume:[1,1,1]},alsaaudio:{cards:[1,2,1],mixers:[1,2,1],ALSAAudioError:[1,4,1],Mixer:[1,3,1],PCM:[1,3,1]}},terms:{all:[1,2,3],concept:[0,2],queri:1,oss:3,alsaaudio:[0,1,2],signific:2,code:[],follow:[1,3],underrun:1,send:3,program:1,pcm_playback:1,those:3,under:3,aux:1,"case":1,libasound:3,liter:1,everi:[1,2],string:1,util:2,volum:1,failur:1,veri:[2,3],relev:1,level:3,gui:1,list:[1,3],item:1,team:3,small:[2,3],pleas:[1,3],prevent:1,slower:2,natur:3,direct:[1,2],sign:1,second:[1,2],design:1,pcm_nonblock:1,download:0,click:1,even:3,index:0,what:[0,1,3],mpeg:1,microphon:[1,3],sun:1,item0:1,multimedia:1,abl:1,current:[1,2,3],version:[1,3],"new":[1,2],net:1,method:1,full:[1,3],gener:2,error:1,here:1,let:1,address:[],path:3,becom:1,sinc:[1,2,3],interpret:1,hass:3,search:0,convers:[1,2],larger:2,precis:2,trial:1,ctl:[1,3],extrem:1,typic:[1,2],mix:1,volunt:3,extra:1,modul:[0,1,3],filenam:[1,3],api:[1,2,3],setperiods:1,instal:[0,3],soundcard:[1,3],select:1,from:[1,2,3],describ:1,would:[1,2,3],memori:2,two:[1,2,3],implic:2,few:[1,3],call:[1,3],usr:3,taken:2,scope:[],type:1,until:1,more:[1,3],wrapper:3,ital:[],notic:[],getvolum:1,flag:1,accept:1,polldescriptor:1,known:2,must:[1,2],logarithm:1,join:1,player:1,cardnam:1,setup:[1,3],work:3,pcm_format_s16_l:1,dev:3,annoi:1,descriptor:1,paragraph:[],can:[1,2,3],endian:[1,2],purpos:[1,3],root:3,volumecap:1,control:[1,2],give:[],process:[1,2],paus:1,backslash:[],indic:[0,1],minimum:[],libasound2:3,unsign:1,occur:1,delai:1,alwai:1,multipl:[1,2],goal:3,anoth:1,pcm_format_float64_l:1,write:[1,2],how:[1,2],playback:[1,3],aplai:1,verifi:3,simpl:1,pcm_format_float64_b:1,resourc:2,after:1,befor:3,mai:[1,3],end:2,associ:1,lar:3,element:1,inform:3,"switch":1,amix:1,allow:1,exclus:1,order:[1,2],mute:1,major:3,report:3,comma:[],setrat:1,mainli:1,dynam:2,paramet:1,chosen:1,better:1,platform:1,html:[],requir:3,curli:[],pcm:[0,1,2,3],mail:[],therefor:2,might:1,pcm_format_a_law:1,"return":[1,2],thei:2,python:[0,1,3],mention:[],somebodi:1,terminolog:[0,2],half:1,interrupt:[1,2,3],now:3,introduct:[0,3],pcm_format_s24_b:1,term:3,name:1,anyth:[1,3],pcm_format_s24_l:1,separ:1,chois:1,achiev:1,mode:1,timeout:1,each:[1,2],found:[1,3],difficult:3,mean:[1,2],compil:3,resum:1,individu:2,realli:1,frames:1,our:3,happen:1,cardindex:1,space:3,getrang:1,footnot:1,fairli:3,suitabl:1,hardwar:[2,3],insid:[],advanc:3,manipul:[1,3],standard:3,reason:1,put:1,org:3,"byte":[1,2],card:1,thread:1,midi:3,could:1,timer:1,length:1,resproduc:2,licens:3,first:[1,3],oper:[1,3],softwar:3,rang:[1,2],directli:2,onc:2,independ:1,qualiti:1,number:[1,2],yourself:3,rant:1,unlik:3,done:2,least:[1,3],horribl:1,size:[1,2],prioriti:3,differ:[2,3],data:[1,2],interact:1,system:3,construct:1,master:1,too:1,statement:[],similarli:[1,2],low:[2,3],option:1,copi:2,specifi:1,pcm_format_u32_l:1,part:[],enclos:[],mostli:3,exactli:[1,2],than:1,pcm_format_u32_b:1,provid:[1,2,3],rate:[1,2],project:[0,3],pcm_captur:1,pre:1,pass:1,argument:1,quietest:2,raw:1,expir:1,have:[1,3],tabl:0,need:[1,3],seem:3,probabl:3,squar:[],zero:1,mic:1,note:[1,3],also:[1,2,3],builtin:[],without:1,take:1,which:[1,2,3],brace:[],noth:[1,2],channel:[1,2],alsa:[0,1,2,3],simplifi:[1,3],sure:1,unless:1,incorpor:1,setformat:1,object:[0,1],compress:1,pcm_format_u8:1,most:[1,3],plai:[1,2,3],pair:[],mixerid:1,homepag:3,"class":1,pcm_format_ima_adpcm:1,stereo:[1,2],don:3,later:[1,3],flow:2,doe:1,getmut:1,pcm_format_u16_l:1,bracket:[],determin:[1,2],nchannel:1,pcm_format_u16_b:1,affair:1,find:[1,3],playbacktest:[1,3],impact:2,access:[1,3],onli:[1,2],ratio:1,execut:3,copyright:[],music:2,configur:2,activ:3,state:1,should:[1,2,3],latenc:2,getenum:1,getrec:1,get:1,familiar:2,pcm_format_s32_b:1,nativ:3,cannot:1,pcm_async:1,pcm_format_s32_l:1,enabl:1,headphon:1,recordtest:[1,3],patch:3,"default":[1,3],common:1,contain:[2,3],userspac:[2,3],through:[1,3],where:1,wrote:3,kernel:[1,2,3],set:[1,2,3],commandlin:1,frame:[1,2],respons:3,fail:[1,3],whatsoev:3,best:1,vari:2,someth:1,enumer:1,wilstrup:3,enough:1,setchannel:1,between:2,"import":[1,2],neither:3,email:[],appreci:3,sole:1,setvolum:1,come:1,both:1,last:1,eventmask:1,howev:1,alon:1,etc:[1,2],inconsist:1,logic:3,mani:2,simpli:2,pcm_format_gsm:1,point:2,within:3,ubuntu:3,period:[1,2],header:3,written:1,colon:1,linux:[1,3],poll:1,assum:1,speak:[1,3],quit:1,coupl:1,devic:[1,2,3],been:[1,3],compon:3,accumul:1,much:[1,2],valu:1,basic:3,wait:1,strategi:1,wish:3,speaker:1,ani:[1,3],understand:[1,2],demand:2,present:1,sound:[1,2,3],ugli:1,myself:1,look:[1,3],packag:3,replac:2,mixertest:1,sourceforg:[0,3],defin:1,"while":2,mono:[1,2],exist:3,immisch:3,telephoni:[1,2],layer:2,nessecari:1,almost:2,pyalsaaudio:3,physic:3,accummul:1,pcm_format_mu_law:1,"64kbit":2,sever:3,develop:3,welcom:3,author:3,perform:3,make:1,same:[1,2,3],handl:[2,3],complex:1,speech:1,ossaudiodev:3,document:[0,1],complet:3,http:3,snail:[],psf:3,pcm_format_s16_b:1,driver:3,capabl:[1,3],rais:1,user:3,chang:1,task:1,lib:3,older:3,entri:[],well:3,know:1,exampl:[0,1,2],playout:1,thi:[1,2,3],audio:[1,2,3],usual:2,explan:1,declaremodul:[],just:1,less:1,casper:3,yet:1,alsasound:3,easi:1,hint:1,had:1,except:1,littl:[1,2],add:1,valid:1,funcdesc:[],input:2,match:1,build:3,applic:3,around:[],format:[1,2],read:[1,2],big:[1,2],howto:1,pcmmode:1,alsaaudioerror:1,bit:[1,2],pcm_format_s8:1,rear:1,pcm_format_u24_b:1,like:1,specif:[1,2,3],deprec:3,docutil:1,signal:2,pcm_format_u24_l:1,integ:[1,2],necessari:2,either:[1,2],choic:1,output:[1,2],page:0,underli:1,www:3,often:2,captur:[1,2,3],interv:2,some:[1,2],back:[1,3],percentag:1,intern:2,sampl:[1,2],proper:3,pain:1,librari:3,distribut:3,scale:2,setmut:1,avoid:1,per:2,buffer:[1,2],tracker:[0,3],leav:1,commerci:3,complic:1,preload:1,run:[1,3],"enum":1,usag:2,loudest:2,although:3,pyalsa:3,about:3,actual:[1,2],greatli:3,slightli:1,mixer:[0,1,3],unfortun:1,constructor:1,pcmtype:1,block:1,own:3,hardli:1,"float":[1,2],encod:1,automat:[],warranti:3,empti:1,pcm_normal:1,playwav:1,your:[1,3],span:1,wai:1,support:[1,3],"long":3,avail:[1,3],start:1,singl:[1,2],includ:[1,3],lot:[1,2],suit:3,"var":[],wav:1,chunk:2,"function":[1,3],tupl:1,regard:3,reexpos:1,link:3,line:1,volumn:1,bug:[0,3],immedi:1,consist:[1,2,3],possibl:1,whether:[1,2],setrec:1,displai:1,record:[1,2,3],limit:1,otherwis:1,problem:1,similar:3,featur:3,constant:1,creat:1,certain:2,"abstract":3,doesn:1,repres:[1,2],implement:[1,3],periods:1,file:[1,3],ship:3,check:1,fill:3,readi:2,when:[1,2],switchcap:1,other:[1,2,3],futur:1,test:[0,1,3],you:[1,2,3],out:1,architectur:3,pcm_format_mpeg:1,sequenc:3,amplitud:2,gap:3,debian:3,stai:1,descript:1,pcm_format_float_b:1,time:[1,2,3],cpu:2,pcm_format_float_l:1},objtypes:{"0":"py:module","1":"py:method","2":"py:function","3":"py:class","4":"py:exception"},titles:["alsaaudio documentation","alsaaudio","PCM Terminology and Concepts","Introduction"],objnames:{"0":"Python module","1":"Python method","2":"Python function","3":"Python class","4":"Python exception"},filenames:["index","libalsaaudio","terminology","pyalsaaudio"]})pyalsaaudio-0.7/doc/html/libalsaaudio.html0000644000175000017500000011331511620311215020643 0ustar larslars00000000000000 alsaaudio — alsaaudio v0.7 documentation

alsaaudio¶

Platforms: Linux

The alsaaudio module defines functions and classes for using ALSA.

alsaaudio.cards()¶

List the available cards by name (suitable for PCM objects).

alsaaudio.mixers([cardindex])¶

List the available mixers. The optional cardindex specifies which card should be queried. The default is 0.

class alsaaudio.PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, card='default')¶

This class is used to represent a PCM device (both for playback and recording - capture). The arguments are:

  • type - can be either PCM_CAPTURE or PCM_PLAYBACK (default).
  • mode - can be either PCM_NONBLOCK, or PCM_NORMAL (default).
  • card - specifies the name of the card that should be used.
class alsaaudio.Mixer(control='Master', id=0, cardindex=0)¶

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 – More explanation needed here
  • cardindex specifies which card should be used.
exception alsaaudio.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 in alsaaudio can play or capture (record) PCM sound through speakers or a microphone. The PCM constructor takes the following arguments:

class alsaaudio.PCM(type=PCM_CAPTURE, mode=PCM_NORMAL, card='default')

type - can be either PCM_CAPTURE or PCM_PLAYBACK (default).

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

card - specifies which card should be used. This can be a string like ‘default’ or a name that was returned from the cards() function.

This will construct a PCM object with these default settings:

  • Sample format: PCM_FORMAT_S16_LE
  • Rate: 44100 Hz
  • Channels: 2
  • Period size: 32 frames

PCM objects have the following methods:

PCM.pcmtype()¶

Returns the type of PCM object. Either PCM_CAPTURE or PCM_PLAYBACK.

PCM.pcmmode()¶

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

PCM.cardname()¶

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

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

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.

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

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.

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.

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 writes to PCM devices must exactly match 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 best strategy 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 accummulate 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 provides access to the ALSA mixer API.

class alsaaudio.Mixer(control='Master', id=0, cardindex=0)

control - specifies which control to manipulate using this mixer object. The list of available controls can be found with the alsaaudio.mixers() function. The default value is ‘Master’ - other common controls include ‘Master Mono’, ‘PCM’, ‘Line’, etc.

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

cardindex - specifies which card should be used [3]. 0 is the first sound card.

Note: For a list of available controls, you can also use amixer:

amixer

Mixer objects have the following methods:

Mixer.cardname()¶

Return the name of the sound card used by this Mixer object

Mixer.mixer()¶

Return the name of the specific mixer controlled by this object, For example ‘Master’ or ‘PCM’

Mixer.mixerid()¶

Return the ID of the ALSA mixer controlled by this object.

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 switches use the setrec() or setmute() methods

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

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.

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’

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.

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’

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

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

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.

Mixer.polldescriptors()¶

Returns a tuple of (file descriptor, eventmask) that can be used to wait for changes on the mixer with select.poll.

A rant on the ALSA Mixer API

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

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.

Examples¶

The following example are provided:

  • playwav.py
  • recordtest.py
  • playbacktest.py
  • mixertest.py

All examples (except mixertest.py) accept the commandline option -c <cardname>.

To determine a valid card name, use the commandline ALSA player:

$ aplay -L

or:

$ python

>>> import alsaaudio
>>> alsaaudio.cards()

mixertest.py accepts the commandline option -c <cardindex>. Card indices start at 0.

playwav.py¶

playwav.py plays a wav file.

To test PCM playback (on your default soundcard), run:

$ python playwav.py <wav file>

recordtest.py and playbacktest.py¶

recordtest.py and playbacktest.py will record and play a raw sound file in CD quality.

To test PCM recordings (on your default soundcard), run:

$ python recordtest.py <filename>

Speak into the microphone, and interrupt the recording at any time with Ctl-C.

Play back the recording with:

$ python playbacktest.py <filename>

mixertest.py¶

Without arguments, mixertest.py will list all available controls. The output might look like this:

$ ./mixertest.py
Available mixer controls:
  'Master'
  'Master Mono'
  'Headphone'
  'PCM'
  'Line'
  'Line In->Rear Out'
  'CD'
  'Mic'
  'PC Speaker'
  'Aux'
  'Mono Output Select'
  'Capture'
  'Mix'
  'Mix Mono'

With a single argument - the control, it will display the settings of that control; for example:

$ ./mixertest.py Master
Mixer name: 'Master'
Capabilities: Playback Volume Playback Mute
Channel 0 volume: 61%
Channel 1 volume: 61%

With two arguments, the control and a parameter, it will set the parameter on the mixer:

$ ./mixertest.py Master mute

This will mute the Master mixer.

Or:

$ ./mixertest.py Master 40

This sets the volume to 40% on all channels.

Footnotes

[1]ALSA also allows PCM_ASYNC, but this is not supported yet.
[2]alsaaudio will leave any name alone that has a ‘:’ (colon) in it.
[3]This is inconsistent with the PCM objects, which use names, but it is consistent with aplay and amixer.

Table Of Contents

Previous topic

PCM Terminology and Concepts

This Page

pyalsaaudio-0.7/doc/html/py-modindex.html0000644000175000017500000000707011620311215020447 0ustar larslars00000000000000 Python Module Index — alsaaudio v0.7 documentation

Python Module Index

a
 
a
alsaaudio (Linux)
pyalsaaudio-0.7/doc/html/search.html0000644000175000017500000000652011620311215017456 0ustar larslars00000000000000 Search — alsaaudio v0.7 documentation

Search

Please activate JavaScript to enable the search functionality.

From here you can search these documents. Enter your search words into the box below and click "search". Note that the search function will automatically search for all of the words. Pages containing fewer words won't appear in the result list.

pyalsaaudio-0.7/doc/html/index.html0000644000175000017500000001423411620311215017321 0ustar larslars00000000000000 alsaaudio documentation — alsaaudio v0.7 documentation

Table Of Contents

Next topic

Introduction

This Page

pyalsaaudio-0.7/doc/html/terminology.html0000644000175000017500000001732311620311215020564 0ustar larslars00000000000000 PCM Terminology and Concepts — alsaaudio v0.7 documentation

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

Previous topic

Introduction

Next topic

alsaaudio

This Page

pyalsaaudio-0.7/doc/html/genindex.html0000644000175000017500000001757411620311215020025 0ustar larslars00000000000000 Index — alsaaudio v0.7 documentation pyalsaaudio-0.7/doc/html/pyalsaaudio.html0000644000175000017500000002316311620311215020526 0ustar larslars00000000000000 Introduction — alsaaudio v0.7 documentation

Introduction¶

Author:Casper Wilstrup
Author:Lars Immisch

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 our priority list, but volunteers are welcome.

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

What is ALSA¶

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

Logically ALSA consists of these components:

  • A set of kernel drivers. — These drivers are responsible for handling the physical sound hardware from within the Linux kernel, and have been the standard sound implementation in Linux since kernel version 2.5
  • A kernel level API for manipulating the ALSA devices.
  • A user-space C library for simplified access to the sound hardware from userspace applications. This library is called libasound and is required by all ALSA capable applications.

More information about ALSA may be found on the project homepage http://www.alsa-project.org

ALSA and Python¶

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

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

I wrote PyAlsaAudio to fill this gap. My long term goal is to have the module included in the standard Python library, but that looks currently unlikely.

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

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

Installation¶

Note: the wrappers link with the alsasound library (from the alsa-lib package) and need the ALSA headers for compilation. Verify that you have /usr/lib/libasound.so and /usr/include/alsa (or similar paths) before building.

On Debian (and probably Ubuntu), install libasound2-dev.

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

Testing¶

First of all, run:

$ python test.py

This is a small test suite that mostly performs consistency tests. If it fails, please file a bug report.

To test PCM recordings (on your default soundcard), verify your microphone works, then do:

$ python recordtest.py <filename>

Speak into the microphone, and interrupt the recording at any time with Ctl-C.

Play back the recording with:

$ python playbacktest.py <filename>

Table Of Contents

Previous topic

alsaaudio documentation

Next topic

PCM Terminology and Concepts

This Page

pyalsaaudio-0.7/doc/html/_static/0000755000175000017500000000000011620311641016751 5ustar larslars00000000000000pyalsaaudio-0.7/doc/html/_static/underscore.js0000644000175000017500000002001511423243317021463 0ustar larslars00000000000000(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)}); return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length); var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false; if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length== 0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&& a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g, " ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments); o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})(); pyalsaaudio-0.7/doc/html/_static/doctools.js0000644000175000017500000001532711423243317021152 0ustar larslars00000000000000/* * doctools.js * ~~~~~~~~~~~ * * Sphinx JavaScript utilties for all documentation. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /** * select a different prefix for underscore */ $u = _.noConflict(); /** * make the code below compatible with browsers without * an installed firebug like debugger if (!window.console || !console.firebug) { var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; window.console = {}; for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {}; } */ /** * small helper function to urldecode strings */ jQuery.urldecode = function(x) { return decodeURIComponent(x).replace(/\+/g, ' '); } /** * small helper function to urlencode strings */ jQuery.urlencode = encodeURIComponent; /** * This function returns the parsed url parameters of the * current request. Multiple values per key are supported, * it will always return arrays of strings for the value parts. */ jQuery.getQueryParameters = function(s) { if (typeof s == 'undefined') s = document.location.search; var parts = s.substr(s.indexOf('?') + 1).split('&'); var result = {}; for (var i = 0; i < parts.length; i++) { var tmp = parts[i].split('=', 2); var key = jQuery.urldecode(tmp[0]); var value = jQuery.urldecode(tmp[1]); if (key in result) result[key].push(value); else result[key] = [value]; } return result; }; /** * small function to check if an array contains * a given item. */ jQuery.contains = function(arr, item) { for (var i = 0; i < arr.length; i++) { if (arr[i] == item) return true; } return false; }; /** * highlight a given string on a jquery object by wrapping it in * span elements with the given class name. */ jQuery.fn.highlightText = function(text, className) { function highlight(node) { if (node.nodeType == 3) { var val = node.nodeValue; var pos = val.toLowerCase().indexOf(text); if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { var span = document.createElement("span"); span.className = className; span.appendChild(document.createTextNode(val.substr(pos, text.length))); node.parentNode.insertBefore(span, node.parentNode.insertBefore( document.createTextNode(val.substr(pos + text.length)), node.nextSibling)); node.nodeValue = val.substr(0, pos); } } else if (!jQuery(node).is("button, select, textarea")) { jQuery.each(node.childNodes, function() { highlight(this); }); } } return this.each(function() { highlight(this); }); }; /** * Small JavaScript module for the documentation. */ var Documentation = { init : function() { this.fixFirefoxAnchorBug(); this.highlightSearchWords(); this.initIndexTable(); }, /** * i18n support */ TRANSLATIONS : {}, PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, LOCALE : 'unknown', // gettext and ngettext don't access this so that the functions // can safely bound to a different name (_ = Documentation.gettext) gettext : function(string) { var translated = Documentation.TRANSLATIONS[string]; if (typeof translated == 'undefined') return string; return (typeof translated == 'string') ? translated : translated[0]; }, ngettext : function(singular, plural, n) { var translated = Documentation.TRANSLATIONS[singular]; if (typeof translated == 'undefined') return (n == 1) ? singular : plural; return translated[Documentation.PLURALEXPR(n)]; }, addTranslations : function(catalog) { for (var key in catalog.messages) this.TRANSLATIONS[key] = catalog.messages[key]; this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); this.LOCALE = catalog.locale; }, /** * add context elements like header anchor links */ addContextElements : function() { $('div[id] > :header:first').each(function() { $('\u00B6'). attr('href', '#' + this.id). attr('title', _('Permalink to this headline')). appendTo(this); }); $('dt[id]').each(function() { $('\u00B6'). attr('href', '#' + this.id). attr('title', _('Permalink to this definition')). appendTo(this); }); }, /** * workaround a firefox stupidity */ fixFirefoxAnchorBug : function() { if (document.location.hash && $.browser.mozilla) window.setTimeout(function() { document.location.href += ''; }, 10); }, /** * highlight the search words provided in the url in the text */ highlightSearchWords : function() { var params = $.getQueryParameters(); var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; if (terms.length) { var body = $('div.body'); window.setTimeout(function() { $.each(terms, function() { body.highlightText(this.toLowerCase(), 'highlighted'); }); }, 10); $('') .appendTo($('.sidebar .this-page-menu')); } }, /** * init the domain index toggle buttons */ initIndexTable : function() { var togglers = $('img.toggler').click(function() { var src = $(this).attr('src'); var idnum = $(this).attr('id').substr(7); $('tr.cg-' + idnum).toggle(); if (src.substr(-9) == 'minus.png') $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); else $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); }).css('display', ''); if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { togglers.click(); } }, /** * helper function to hide the search marks again */ hideSearchWords : function() { $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); $('span.highlighted').removeClass('highlighted'); }, /** * make the url absolute */ makeURL : function(relativeURL) { return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; }, /** * get the current relative url */ getCurrentURL : function() { var path = document.location.pathname; var parts = path.split(/\//); $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { if (this == '..') parts.pop(); }); var url = parts.join('/'); return path.substring(url.lastIndexOf('/') + 1, path.length - 1); } }; // quick alias for translations _ = Documentation.gettext; $(document).ready(function() { Documentation.init(); }); pyalsaaudio-0.7/doc/html/_static/plus.png0000644000175000017500000000030711423243317020447 0ustar larslars00000000000000‰PNG  IHDR &Îàq pHYs  šœtIME× 1l9tEXtCommentöÌ–¿RIDATÓczô(BÅñãÇáÒpö¿ÿ¨èˆip»‘¹P÷îÝÃc· ¸ |¶IEND®B`‚pyalsaaudio-0.7/doc/html/_static/default.css0000644000175000017500000000770711620311215021117 0ustar larslars00000000000000/* * default.css_t * ~~~~~~~~~~~~~ * * Sphinx stylesheet -- default theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: sans-serif; font-size: 100%; background-color: #11303d; color: #000; margin: 0; padding: 0; } div.document { background-color: #1c4e63; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } div.body { background-color: #ffffff; color: #000000; padding: 0 20px 30px 20px; } div.footer { color: #ffffff; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: #ffffff; text-decoration: underline; } div.related { background-color: #133f52; line-height: 30px; color: #ffffff; } div.related a { color: #ffffff; } div.sphinxsidebar { } div.sphinxsidebar h3 { font-family: 'Trebuchet MS', sans-serif; color: #ffffff; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h3 a { color: #ffffff; } div.sphinxsidebar h4 { font-family: 'Trebuchet MS', sans-serif; color: #ffffff; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: #ffffff; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; color: #ffffff; } div.sphinxsidebar a { color: #98dbcc; } div.sphinxsidebar input { border: 1px solid #98dbcc; font-family: sans-serif; font-size: 1em; } /* -- hyperlink styles ------------------------------------------------------ */ a { color: #355f7c; text-decoration: none; } a:visited { color: #355f7c; text-decoration: none; } a:hover { text-decoration: underline; } /* -- body styles ----------------------------------------------------------- */ div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Trebuchet MS', sans-serif; background-color: #f2f2f2; font-weight: normal; color: #20435c; border-bottom: 1px solid #ccc; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } a.headerlink:hover { background-color: #c60f0f; color: white; } div.body p, div.body dd, div.body li { text-align: justify; line-height: 130%; } div.admonition p.admonition-title + p { display: inline; } div.admonition p { margin-bottom: 5px; } div.admonition pre { margin-bottom: 5px; } div.admonition ul, div.admonition ol { margin-bottom: 5px; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre { padding: 5px; background-color: #eeffcc; color: #333333; line-height: 120%; border: 1px solid #ac9; border-left: none; border-right: none; } tt { background-color: #ecf0f3; padding: 0 1px 0 1px; font-size: 0.95em; } th { background-color: #ede; } .warning tt { background: #efc2c2; } .note tt { background: #d6d6d6; } .viewcode-back { font-family: sans-serif; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; }pyalsaaudio-0.7/doc/html/_static/file.png0000644000175000017500000000061011423243317020400 0ustar larslars00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  )¶TIDAT8Ë­‘±JÄ@†¿Ir('[ "&xØÙYZ ‚Xø0‚!i|†_@±Ô÷•t§ÓDÄæÏ] ¹#¹Äxÿjv˜ùç› Y–ÐN‡ažE‘i«(ŠÌÄÉ™yž£µ@D¦£&±ˆ`Û6®ë–P¦Zk’$)5%"ôz½Ê.NñA#Aœba‘`Vsø¾_3ñc°,«™àä2m¼Ýñþjó [kŸìlv¹y|!IÕ´ðþyô;ÀðvÈé "Œß®°—a©?ŸAúðÄ7Œ`ô˜ñÇc^énôk?¸²Bg}»TЙ¹D#ÁÑÞ "R¹D1÷£çyüEŽRê*ŽãÝ6MJ©3þK_U«t8F~ÇIEND®B`‚pyalsaaudio-0.7/doc/html/_static/minus.png0000644000175000017500000000030711423243317020617 0ustar larslars00000000000000‰PNG  IHDR &Îàq pHYs  šœtIME× <®8åtEXtCommentöÌ–¿RIDATÓc -1) start = i; }); start = Math.max(start - 120, 0); var excerpt = ((start > 0) ? '...' : '') + $.trim(text.substr(start, 240)) + ((start + 240 - text.length) ? '...' : ''); var rv = $('
').text(excerpt); $.each(hlwords, function() { rv = rv.highlightText(this, 'highlighted'); }); return rv; } /** * Porter Stemmer */ var PorterStemmer = function() { var step2list = { ational: 'ate', tional: 'tion', enci: 'ence', anci: 'ance', izer: 'ize', bli: 'ble', alli: 'al', entli: 'ent', eli: 'e', ousli: 'ous', ization: 'ize', ation: 'ate', ator: 'ate', alism: 'al', iveness: 'ive', fulness: 'ful', ousness: 'ous', aliti: 'al', iviti: 'ive', biliti: 'ble', logi: 'log' }; var step3list = { icate: 'ic', ative: '', alize: 'al', iciti: 'ic', ical: 'ic', ful: '', ness: '' }; var c = "[^aeiou]"; // consonant var v = "[aeiouy]"; // vowel var C = c + "[^aeiouy]*"; // consonant sequence var V = v + "[aeiou]*"; // vowel sequence var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 var s_v = "^(" + C + ")?" + v; // vowel in stem this.stemWord = function (w) { var stem; var suffix; var firstch; var origword = w; if (w.length < 3) return w; var re; var re2; var re3; var re4; firstch = w.substr(0,1); if (firstch == "y") w = firstch.toUpperCase() + w.substr(1); // Step 1a re = /^(.+?)(ss|i)es$/; re2 = /^(.+?)([^s])s$/; if (re.test(w)) w = w.replace(re,"$1$2"); else if (re2.test(w)) w = w.replace(re2,"$1$2"); // Step 1b re = /^(.+?)eed$/; re2 = /^(.+?)(ed|ing)$/; if (re.test(w)) { var fp = re.exec(w); re = new RegExp(mgr0); if (re.test(fp[1])) { re = /.$/; w = w.replace(re,""); } } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1]; re2 = new RegExp(s_v); if (re2.test(stem)) { w = stem; re2 = /(at|bl|iz)$/; re3 = new RegExp("([^aeiouylsz])\\1$"); re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re2.test(w)) w = w + "e"; else if (re3.test(w)) { re = /.$/; w = w.replace(re,""); } else if (re4.test(w)) w = w + "e"; } } // Step 1c re = /^(.+?)y$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(s_v); if (re.test(stem)) w = stem + "i"; } // Step 2 re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step2list[suffix]; } // Step 3 re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step3list[suffix]; } // Step 4 re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; re2 = /^(.+?)(s|t)(ion)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); if (re.test(stem)) w = stem; } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1] + fp[2]; re2 = new RegExp(mgr1); if (re2.test(stem)) w = stem; } // Step 5 re = /^(.+?)e$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); re2 = new RegExp(meq1); re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) w = stem; } re = /ll$/; re2 = new RegExp(mgr1); if (re.test(w) && re2.test(w)) { re = /.$/; w = w.replace(re,""); } // and turn initial Y back to y if (firstch == "y") w = firstch.toLowerCase() + w.substr(1); return w; } } /** * Search Module */ var Search = { _index : null, _queued_query : null, _pulse_status : -1, init : function() { var params = $.getQueryParameters(); if (params.q) { var query = params.q[0]; $('input[name="q"]')[0].value = query; this.performSearch(query); } }, loadIndex : function(url) { $.ajax({type: "GET", url: url, data: null, success: null, dataType: "script", cache: true}); }, setIndex : function(index) { var q; this._index = index; if ((q = this._queued_query) !== null) { this._queued_query = null; Search.query(q); } }, hasIndex : function() { return this._index !== null; }, deferQuery : function(query) { this._queued_query = query; }, stopPulse : function() { this._pulse_status = 0; }, startPulse : function() { if (this._pulse_status >= 0) return; function pulse() { Search._pulse_status = (Search._pulse_status + 1) % 4; var dotString = ''; for (var i = 0; i < Search._pulse_status; i++) dotString += '.'; Search.dots.text(dotString); if (Search._pulse_status > -1) window.setTimeout(pulse, 500); }; pulse(); }, /** * perform a search for something */ performSearch : function(query) { // create the required interface elements this.out = $('#search-results'); this.title = $('

' + _('Searching') + '

').appendTo(this.out); this.dots = $('').appendTo(this.title); this.status = $('

').appendTo(this.out); this.output = $('