Import from divmod. Original log message:

r820 | anthony | 2004-10-04 15:28:33 +0200 (Mon, 04 Oct 2004) | 2 lines

Import of PyAlsaAudio, by Casper Wilstrup (cwi@unispeed.dk)



git-svn-id: svn://svn.code.sf.net/p/pyalsaaudio/code/trunk@2 ec2f30ec-7544-0410-870e-f70ca00c83f0
This commit is contained in:
larsimmisch
2008-01-24 11:20:35 +00:00
parent 335500fc1d
commit 47795bcc72
6 changed files with 605 additions and 0 deletions

50
README Normal file
View File

@@ -0,0 +1,50 @@
PyAlsaAudio
===========
Author: Casper Wilstrup (cwi@unispeed.dk)
This package contains wrappers for acessing 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. 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 - althoug
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 are two 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.
In a future version, I'll include documentation with the package, but
for now, you're stuck with the examples.

3
TODO Normal file
View File

@@ -0,0 +1,3 @@
- Implement the Mixer API
- Implement MIDI/sequencer support.

459
alsaaudio.c Normal file
View File

@@ -0,0 +1,459 @@
/*
* alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture).
* The standard audio API for Linux since kernel 2.0
*
* Contributed by Unispeed A/S (http://www.unispeed.com)
* Primary author: Casper Wilstup (cwi@unispeed.dk)
*
*
* (c) 2004 by Unispeed A/S. All rights reserved.
*
* License: CRNI's Python 1.6 license (or any later version of the same)
*
*/
#include "Python.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
typedef struct {
PyObject_HEAD;
int pcmtype;
int pcmmode;
char *pcmname;
snd_pcm_t *handle;
// Configurable parameters
int channels;
int rate;
int format;
snd_pcm_uframes_t periodsize;
int framesize;
} alsapcm_t;
static PyTypeObject ALSAAudioType;
static PyObject *ALSAAudioError;
static int alsapcm_setup(alsapcm_t *self) {
int res,dir;
unsigned int val;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t frames;
if (self->handle) {
snd_pcm_close(self->handle);
self->handle = 0;
}
res = snd_pcm_open(&(self->handle),self->pcmname,self->pcmtype,self->pcmmode);
if (res < 0) return res;
snd_pcm_hw_params_alloca(&hwparams);
res = snd_pcm_hw_params_any(self->handle, hwparams);
if (res < 0) return res;
snd_pcm_hw_params_alloca(&hwparams);
/* Fill it in with default values. */
snd_pcm_hw_params_any(self->handle, hwparams);
snd_pcm_hw_params_set_access(self->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(self->handle, hwparams, self->format);
snd_pcm_hw_params_set_channels(self->handle, hwparams, self->channels);
dir = 0;
snd_pcm_hw_params_set_rate(self->handle, hwparams, self->rate, dir);
snd_pcm_hw_params_set_period_size(self->handle, hwparams, self->periodsize, dir);
snd_pcm_hw_params_set_periods(self->handle,hwparams,4,0);
res = snd_pcm_hw_params(self->handle, hwparams);
self->framesize = self->channels * snd_pcm_hw_params_get_sbits(hwparams)/8;
return res;
}
/* ALSA PCM Object members */
static alsapcm_t *
newalsapcmobject(PyObject *args) {
int res;
alsapcm_t *self;
int pcmtype=0;
int pcmmode=0;
char *pcmname = "default";
if (!PyArg_ParseTuple(args,"|iis",&pcmtype,&pcmmode,&pcmname)) return NULL;
if (!(self = (alsapcm_t *)PyObject_New(struct alsa_audio, &ALSAAudioType))) return NULL;
if (pcmtype != SND_PCM_STREAM_PLAYBACK && pcmtype != SND_PCM_STREAM_CAPTURE) {
PyErr_SetString(ALSAAudioError, "PCM type must be PCM_PLAYBACK (0) or PCM_CAPTUPE (1)");
return NULL;
}
if (pcmmode < 0 || pcmmode > SND_PCM_ASYNC) {
PyErr_SetString(ALSAAudioError, "Invalid PCM mode");
return NULL;
}
self->pcmtype = pcmtype;
self->pcmmode = pcmmode;
self->pcmname = strdup(pcmname);
self->channels = 2;
self->rate = 44100;
self->format = SND_PCM_FORMAT_S16_LE;
self->periodsize = 32;
self->handle = 0;
res = alsapcm_setup(self);
if (res < 0) {
if (self->handle) {
snd_pcm_close(self->handle);
self->handle = 0;
}
PyErr_SetString(ALSAAudioError, snd_strerror(res));
return NULL;
}
return self;
}
static void alsapcm_dealloc(alsapcm_t *self) {
if (self->handle) {
snd_pcm_drain(self->handle);
snd_pcm_close(self->handle);
}
PyObject_Del(self);
}
static PyObject *
alsapcm_dumpinfo(alsapcm_t *self, PyObject *args) {
unsigned int val,val2;
int dir;
snd_pcm_uframes_t frames;
snd_pcm_hw_params_t *hwparams;
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_hw_params_current(self->handle,hwparams);
if (!PyArg_ParseTuple(args,"")) return NULL;
printf("PCM handle name = '%s'\n", snd_pcm_name(self->handle));
printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(self->handle)));
snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
printf("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
snd_pcm_hw_params_get_format(hwparams, &val);
printf("format = '%s' (%s)\n",
snd_pcm_format_name((snd_pcm_format_t)val),
snd_pcm_format_description((snd_pcm_format_t)val));
snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
printf("subformat = '%s' (%s)\n",
snd_pcm_subformat_name((snd_pcm_subformat_t)val),
snd_pcm_subformat_description((snd_pcm_subformat_t)val));
snd_pcm_hw_params_get_channels(hwparams, &val);
printf("channels = %d\n", val);
snd_pcm_hw_params_get_rate(hwparams, &val, &dir);
printf("rate = %d bps\n", val);
snd_pcm_hw_params_get_period_time(hwparams, &val, &dir);
printf("period time = %d us\n", val);
snd_pcm_hw_params_get_period_size(hwparams, &frames, &dir);
printf("period size = %d frames\n", (int)frames);
snd_pcm_hw_params_get_buffer_time(hwparams, &val, &dir);
printf("buffer time = %d us\n", val);
snd_pcm_hw_params_get_buffer_size(hwparams, (snd_pcm_uframes_t *) &val);
printf("buffer size = %d frames\n", val);
snd_pcm_hw_params_get_periods(hwparams, &val, &dir);
printf("periods per buffer = %d frames\n", val);
snd_pcm_hw_params_get_rate_numden(hwparams, &val, &val2);
printf("exact rate = %d/%d bps\n", val, val2);
val = snd_pcm_hw_params_get_sbits(hwparams);
printf("significant bits = %d\n", val);
snd_pcm_hw_params_get_tick_time(hwparams, &val, &dir);
printf("tick time = %d us\n", val);
val = snd_pcm_hw_params_is_batch(hwparams);
printf("is batch = %d\n", val);
val = snd_pcm_hw_params_is_block_transfer(hwparams);
printf("is block transfer = %d\n", val);
val = snd_pcm_hw_params_is_double(hwparams);
printf("is double = %d\n", val);
val = snd_pcm_hw_params_is_half_duplex(hwparams);
printf("is half duplex = %d\n", val);
val = snd_pcm_hw_params_is_joint_duplex(hwparams);
printf("is joint duplex = %d\n", val);
val = snd_pcm_hw_params_can_overrange(hwparams);
printf("can overrange = %d\n", val);
val = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
printf("can mmap = %d\n", val);
val = snd_pcm_hw_params_can_pause(hwparams);
printf("can pause = %d\n", val);
val = snd_pcm_hw_params_can_resume(hwparams);
printf("can resume = %d\n", val);
val = snd_pcm_hw_params_can_sync_start(hwparams);
printf("can sync start = %d\n", val);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
alsapcm_pcmtype(alsapcm_t *self, PyObject *args) {
if (!PyArg_ParseTuple(args,"")) return NULL;
return PyInt_FromLong(self->pcmtype);
}
static PyObject *
alsapcm_pcmmode(alsapcm_t *self, PyObject *args) {
if (!PyArg_ParseTuple(args,"")) return NULL;
return PyInt_FromLong(self->pcmmode);
}
static PyObject *
alsapcm_pcmname(alsapcm_t *self, PyObject *args) {
if (!PyArg_ParseTuple(args,"")) return NULL;
return PyString_FromString(self->pcmname);
}
static PyObject *
alsapcm_setchannels(alsapcm_t *self, PyObject *args) {
int channels;
int res;
if (!PyArg_ParseTuple(args,"i",&channels)) return NULL;
self->channels = channels;
res = alsapcm_setup(self);
if (res < 0) {
PyErr_SetString(ALSAAudioError, snd_strerror(res));
return NULL;
}
return PyInt_FromLong(channels);
}
static PyObject *
alsapcm_setrate(alsapcm_t *self, PyObject *args) {
int rate;
int res;
if (!PyArg_ParseTuple(args,"i",&rate)) return NULL;
self->rate = rate;
res = alsapcm_setup(self);
if (res < 0) {
PyErr_SetString(ALSAAudioError, snd_strerror(res));
return NULL;
}
return PyInt_FromLong(self->rate);
}
static PyObject *
alsapcm_setformat(alsapcm_t *self, PyObject *args) {
int format;
int res;
if (!PyArg_ParseTuple(args,"i",&format)) return NULL;
self->format = format;
res = alsapcm_setup(self);
if (res < 0) {
PyErr_SetString(ALSAAudioError, snd_strerror(res));
return NULL;
}
return PyInt_FromLong(self->format);
}
static PyObject *
alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) {
int periodsize;
int res;
if (!PyArg_ParseTuple(args,"i",&periodsize)) return NULL;
self->periodsize = periodsize;
res = alsapcm_setup(self);
if (res < 0) {
PyErr_SetString(ALSAAudioError, snd_strerror(res));
return NULL;
}
return PyInt_FromLong(self->periodsize);
}
static PyObject *
alsapcm_read(alsapcm_t *self, PyObject *args) {
int res;
int val,dir;
char buffer[8000];
snd_pcm_hw_params_t *hwparams;
if (self->framesize * self->periodsize > 8000) {
PyErr_SetString(ALSAAudioError,"Capture data too large. Try decreasing period size");
return NULL;
}
if (!PyArg_ParseTuple(args,"")) return NULL;
if (self->pcmtype != SND_PCM_STREAM_CAPTURE) {
PyErr_SetString(ALSAAudioError,"Cannot read from playback PCM");
return NULL;
}
res = snd_pcm_readi(self->handle, buffer, self->periodsize);
if (res == -EPIPE) {
/* EPIPE means overrun */
snd_pcm_prepare(self->handle);
}
else if (res == -EAGAIN) {
res = 0;
}
else if (res < 0) {
PyErr_SetString(ALSAAudioError,snd_strerror(res));
return NULL;
}
return Py_BuildValue("is#",res,buffer,res*self->framesize);
}
static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) {
char *data;
int datalen;
int res;
if (!PyArg_ParseTuple(args,"s#",&data,&datalen)) return NULL;
if (datalen%self->framesize) {
PyErr_SetString(ALSAAudioError,"Data size must be a multipla of framesize");
return NULL;
}
res = snd_pcm_writei(self->handle, data, datalen/self->framesize);
if (res == -EPIPE) {
/* EPIPE means underrun */
snd_pcm_prepare(self->handle);
snd_pcm_writei(self->handle, data, datalen/self->framesize);
snd_pcm_writei(self->handle, data, datalen/self->framesize);
}
else if (res == -EAGAIN) {
return PyInt_FromLong(0);
}
else if (res < 0) {
PyErr_SetString(ALSAAudioError,snd_strerror(res));
return NULL;
}
return PyInt_FromLong(datalen);
}
/* Module functions */
static PyObject *
alsa_openpcm(PyObject *self, PyObject *args) {
return (PyObject *)newalsapcmobject(args);
}
/* ALSA PCM Object Bureaucracy */
static PyMethodDef alsapcm_methods[] = {
{"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS},
{"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS},
{"pcmname", (PyCFunction)alsapcm_pcmname, METH_VARARGS},
{"setchannels", (PyCFunction)alsapcm_setchannels, METH_VARARGS},
{"setrate", (PyCFunction)alsapcm_setrate, METH_VARARGS},
{"setformat", (PyCFunction)alsapcm_setformat, METH_VARARGS},
{"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS},
{"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS},
{"read", (PyCFunction)alsapcm_read, METH_VARARGS},
{"write", (PyCFunction)alsapcm_write, METH_VARARGS},
{NULL, NULL}
};
static PyObject *
alsapcm_getattr(alsapcm_t *self, char *name) {
return Py_FindMethod(alsapcm_methods, (PyObject *)self, name);
}
static PyTypeObject ALSAAudioType = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"alsaaudio.pcm",
sizeof(alsapcm_t),
0,
/* methods */
(destructor) alsapcm_dealloc,
0,
(getattrfunc)alsapcm_getattr,
0,
0,
0,
};
/* Initialization */
static PyMethodDef alsaaudio_methods[] = {
{ "openpcm", alsa_openpcm, METH_VARARGS },
{ 0, 0 },
};
#define _EXPORT_CONSTANT(mod, name) \
if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return;
#define _EXPORT_INT(mod, name, value) \
if (PyModule_AddIntConstant(mod, name, (long) value) == -1) return;
void initalsaaudio(void) {
PyObject *m;
m = Py_InitModule("alsaaudio",alsaaudio_methods);
ALSAAudioError = PyErr_NewException("alsaaudio.ALSAAudioError", NULL, NULL);
if (ALSAAudioError) {
/* Each call to PyModule_AddObject decrefs it; compensate: */
Py_INCREF(ALSAAudioError);
Py_INCREF(ALSAAudioError);
PyModule_AddObject(m, "error", 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_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);
}

34
playbacktest.py Normal file
View File

@@ -0,0 +1,34 @@
## recordtest.py
##
## This is an example of a simple sound playback script.
##
## The script opens an ALSA pcm for sound playback. Set
## various attributes of the device. It then reads data
## from stdin and writes it to the device.
##
## To test it out do the following:
## python recordtest.py > out.raw # talk to the microphone
## python playbacktest.py < out.raw
import alsaaudio
import sys
import time
# Open the device in playback mode.
out = alsaaudio.openpcm(alsaaudio.PCM_PLAYBACK)
# Set attributes: Mono, 8000 Hz, 16 bit little endian frames
out.setchannels(1)
out.setrate(8000)
out.setformat(alsaaudio.PCM_FORMAT_S16_LE)
# The period size controls the internal number of frames per period.
# The significance of this parameter is documented in the ALSA api.
out.setperiodsize(160)
loops = 10000
while loops > 0:
loops -= 1
# Read data from stdin
data = sys.stdin.read(320)
out.write(data)

45
recordtest.py Normal file
View File

@@ -0,0 +1,45 @@
## recordtest.py
##
## This is an example of a simple sound capture script.
##
## The script opens an ALSA pcm forsound capture. Set
## various attributes of the capture, and reads in a loop,
## writing the data to standard out.
##
## To test it out do the following:
## python recordtest.py > out.raw # talk to the microphone
## aplay -r 8000 -f S16_LE -c 1 out.raw
import alsaaudio
import sys
import time
# Open the device in nonblocking capture mode. The last argument could
# just as well have been zero for blocking mode. Then we could have
# left out the sleep call in the bottom of the loop
inp = alsaaudio.openpcm(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
# Set attributes: Mono, 8000 Hz, 16 bit little endian samples
inp.setchannels(1)
inp.setrate(8000)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
# The period size controls the internal number of frames per period.
# The significance of this parameter is documented in the ALSA api.
# For our purposes, it is suficcient to know that reads from the device
# will return this many frames. Each frame being 2 bytes long.
# This means that the reads below will return either 320 bytes of data
# or 0 bytes of data. The latter is possible because we are in nonblocking
# mode.
inp.setperiodsize(160)
loops = 10000
while loops > 0:
loops -= 1
# Read data from device
l,data = inp.read()
if l:
# actual data read. Write it to stdout
sys.stdout.write(data)
time.sleep(.001)

14
setup.py Normal file
View File

@@ -0,0 +1,14 @@
from distutils.core import setup
from distutils.extension import Extension
setup(
name = "alsaaudio",
version = "0.1",
description = "alsa bindings",
author = "Casper Wilstrup",
author_email="cwi@unispeed.com",
ext_modules=[Extension("alsaaudio",["alsaaudio.c"],libraries=['asound'])
]
)