Compare commits

...

22 Commits

Author SHA1 Message Date
Lars Immisch
d3aa602a04 Setup PCM device in constructor. 2020-04-02 23:24:48 +02:00
Lars Immisch
046e7c4e87 Get rid of warnings, adjust CHANGES 2020-04-01 22:47:11 +02:00
Lars Immisch
a4c4c7cb62 Consistent indentation and some code style changes (whould be ws only) 2020-03-09 22:28:08 +01:00
Lars Immisch
f478797f6f Merge branch 'dev/card-detail' of https://github.com/jdstmporter/pyalsaaudio into jdstmporter-dev/card-detail 2020-03-09 22:07:23 +01:00
Lars Immisch
12f807698a Merge #80 2020-03-09 22:05:50 +01:00
Julian Porter
fc011b5ea6 restored gitignore! 2020-03-06 20:21:47 +00:00
Julian Porter
f244a70111 tidied up 2020-03-06 20:06:59 +00:00
Julian Porter
a056a90c61 modified version of pyalsaaudio module 2020-03-06 19:59:04 +00:00
Julian Porter
be1b3e131d demo 2020-03-05 00:50:30 +00:00
Danny
8abf06bedf Prevent hang on close after capturing audio
Currently, after recording audio using pyalsaaudio, the client is unable to close the device.

The reason is that PulseAudio client tries to drain the pipe to the PulseAudio server (presumably in order to prevent Broken Pipe error) on closing. That will never finish since new data will always arrive in the pipe.

Worse, the __del__ handler was auto-closing and thus auto-hanging.

Therefore, pause before de-allocating.
2019-12-02 21:39:44 +00:00
Lars Immisch
dcc831e607 Merge pull request #44 from Oranos25/contribution
add support for snd_pcm_drop function
2019-11-14 13:24:36 +01:00
Lars Immisch
e587df9143 Merge pull request #55 from moham96/patch-1
update playwav.py for python 3
2019-11-14 13:20:12 +01:00
Lars Immisch
82febd3f7e Merge pull request #67 from pdericson/master
Update pyalsaaudio.rst
2018-11-16 12:50:52 +01:00
Peter Ericson
1695066c11 Update pyalsaaudio.rst 2018-11-16 16:51:05 +08:00
Lars Immisch
25717020ef Transactional semantics for the alsapcm_set* calls 2018-02-28 09:52:53 +00:00
Lars Immisch
1aae655d24 Update periodsize only after alsapcm_setup succeeded 2018-02-28 00:35:26 +01:00
MOHAMMAD RASIM
c1c8362eb2 update playwav.py for python 3
use int division for periodsize to be compatible with python 3
2018-02-24 19:40:45 +03:00
Lars Immisch
723eff3887 Prepare next release 2018-02-20 12:18:44 +01:00
Lars Immisch
aa9867de18 Document changes, i.e. #53. 2018-02-20 12:10:20 +01:00
Lars Immisch
58f4522769 Merge pull request #53 from jcea/jcea/read_period_size
Unlimited setperiod buffer size when reading frames
2018-02-20 12:05:37 +01:00
Jesus Cea
f2fb61d324 Unlimited setperiod buffer size when reading frames 2018-02-20 11:52:47 +01:00
Anthony Piau
9e79494a95 add support for snd_pcm_drop function 2017-12-28 16:30:32 +00:00
5 changed files with 378 additions and 241 deletions

29
CHANGES
View File

@@ -1,3 +1,32 @@
Version 0.8.6:
- Added four methods to the 'PCM' class to allow users to get detailed information about the device:
- 'getformats()' returns a dictionary of name / value pairs, one for each of the card's
supported formats - e.g. '{"U8": 1, "S16_LE": 2}',
- 'getchannels()' returns a list of the supported channel numbers, e.g. '[1, 2]',
- 'getrates()' returns supported sample rates for the device, e.g. '[48000]',
- 'getratebounds()' returns the device's official minimum and maximum supported
sample rates as a tuple, e.g. '(4000, 48000)'.
(#82 contributed by @jdstmporter)
- Prevent hang on close after capturing audio (#80 contributed by @daym)
Version 0.8.5:
- Return an empty string/bytestring when 'read()' detects an
overrun. Previously the returned data was undefined (contributed by @jcea)
- Unlimited setperiod buffer size when reading frames (contributed by @jcea)
Version 0.8.4:
- Fix Python3 API usage broken in 0.8.3
Version 0.8.3:
- Add DSD sample formats (contributed by @lintweaker)
- Add Mixer.handleevents() to acknowledge events identified by select.poll (contributed by @PaulSD)
- Add functions for listing cards and their names (contributed by @chrisdiamand)
- Add a method for setting enums (contributed by @chrisdiamand)
Version 0.8.2:
- fix #3 (we cannot get the revision from git for pip installs)

View File

@@ -29,6 +29,65 @@
#include <alsa/version.h>
#include <stdio.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof *(a))
static const snd_pcm_format_t ALSAFormats[] = {
SND_PCM_FORMAT_S8,
SND_PCM_FORMAT_U8,
SND_PCM_FORMAT_S16_LE,
SND_PCM_FORMAT_S16_BE,
SND_PCM_FORMAT_U16_LE,
SND_PCM_FORMAT_U16_BE,
SND_PCM_FORMAT_S24_LE,
SND_PCM_FORMAT_S24_BE,
SND_PCM_FORMAT_U24_LE,
SND_PCM_FORMAT_U24_BE,
SND_PCM_FORMAT_S32_LE,
SND_PCM_FORMAT_S32_BE,
SND_PCM_FORMAT_U32_LE,
SND_PCM_FORMAT_U32_BE,
SND_PCM_FORMAT_FLOAT_LE,
SND_PCM_FORMAT_FLOAT_BE,
SND_PCM_FORMAT_FLOAT64_LE,
SND_PCM_FORMAT_FLOAT64_BE,
SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
SND_PCM_FORMAT_MU_LAW,
SND_PCM_FORMAT_A_LAW,
SND_PCM_FORMAT_IMA_ADPCM,
SND_PCM_FORMAT_MPEG,
SND_PCM_FORMAT_GSM,
SND_PCM_FORMAT_SPECIAL,
SND_PCM_FORMAT_S24_3LE,
SND_PCM_FORMAT_S24_3BE,
SND_PCM_FORMAT_U24_3LE,
SND_PCM_FORMAT_U24_3BE,
SND_PCM_FORMAT_S20_3LE,
SND_PCM_FORMAT_S20_3BE,
SND_PCM_FORMAT_U20_3LE,
SND_PCM_FORMAT_U20_3BE,
SND_PCM_FORMAT_S18_3LE,
SND_PCM_FORMAT_S18_3BE,
SND_PCM_FORMAT_U18_3LE,
SND_PCM_FORMAT_U18_3BE
};
static const unsigned ALSARates[] = {
4000,
5512,
8000,
11025,
16000,
22050,
32000,
44100,
48000,
64000,
88200,
96000,
176400,
192000
};
PyDoc_STRVAR(alsaaudio_module_doc,
"This modules provides support for the ALSA audio API.\n"
"\n"
@@ -299,74 +358,26 @@ PyDoc_STRVAR(pcms_doc,
\n\
List the available PCM devices");
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;
PyObject *pcmtypeobj = NULL;
long pcmtype;
int pcmmode = 0;
unsigned int rate = 48000;
unsigned int channels = 2;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
char *device = "default";
char *card = NULL;
int cardidx = -1;
char hw_device[128];
char *kw[] = { "type", "mode", "device", "cardindex", "card", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiz", kw,
int latency = 200;
char *kw[] = { "type", "mode", "device", "cardindex", "card", "format", "rate", "channels", "latency", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiziiii", kw,
&pcmtypeobj, &pcmmode, &device,
&cardidx, &card))
&cardidx, &card, &rate, &format, &channels, &latency))
return NULL;
if (cardidx >= 0) {
@@ -399,29 +410,9 @@ alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
if (pcmmode < 0 || pcmmode > SND_PCM_ASYNC) {
PyErr_SetString(ALSAAudioError, "Invalid PCM mode");
return NULL;
}
if (!(self = (alsapcm_t *)PyObject_New(alsapcm_t, &ALSAPCMType)))
return NULL;
self->handle = 0;
self->pcmtype = pcmtype;
self->pcmmode = pcmmode;
self->channels = 2;
self->rate = 44100;
self->format = SND_PCM_FORMAT_S16_LE;
self->periodsize = 32;
res = snd_pcm_open(&(self->handle), device, self->pcmtype,
self->pcmmode);
if (res >= 0) {
res = alsapcm_setup(self);
}
if (res >= 0) {
self->cardname = strdup(device);
}
@@ -440,6 +431,7 @@ alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static void alsapcm_dealloc(alsapcm_t *self)
{
if (self->handle) {
snd_pcm_pause(self->handle, 1);
snd_pcm_drain(self->handle);
snd_pcm_close(self->handle);
}
@@ -572,6 +564,184 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args)
return Py_None;
}
// auxiliary function
static PyObject *
alsapcm_getformats(alsapcm_t *self, PyObject *args)
{
snd_pcm_t *pcm = self->handle;
if (!pcm) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
int err = snd_pcm_hw_params_any(pcm, params);
if (err < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
return NULL;
}
PyObject *fmts = PyDict_New();
for (size_t i = 0; i < ARRAY_SIZE(ALSAFormats); ++i) {
snd_pcm_format_t format = ALSAFormats[i];
if (!snd_pcm_hw_params_test_format(pcm, params, format)) {
const char *name = snd_pcm_format_name(format);
PyObject *pname=PyUnicode_FromString(name);
PyObject *value=PyLong_FromLong((long)format);
PyDict_SetItem(fmts,pname,value);
}
}
return fmts;
}
PyDoc_STRVAR(getformats_doc,
"getformats() -> [str:int]\n\
\n\
Returns dictionary of supported format codes keyed by their standard ALSA names.");
static PyObject *
alsapcm_getratemaxmin(alsapcm_t *self, PyObject *args)
{
snd_pcm_t *pcm = self->handle;
if (!pcm) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
int err = snd_pcm_hw_params_any(pcm, params);
if (err < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
return NULL;
}
unsigned min,max;
if (snd_pcm_hw_params_get_rate_min(params, &min,NULL)<0) {
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate");
return NULL;
}
if (snd_pcm_hw_params_get_rate_max(params, &max,NULL)<0) {
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported bitrate");
return NULL;
}
PyObject *minp=PyLong_FromLong(min);
PyObject *maxp=PyLong_FromLong(max);
return PyTuple_Pack(2, minp, maxp);
}
PyDoc_STRVAR(getratebounds_doc,
"getratebounds() -> (int,int)\n\
\n\
Returns the card's minimum and maximum supported sample rates as a tuple.");
static PyObject *
alsapcm_getrates(alsapcm_t *self, PyObject *args)
{
snd_pcm_t *pcm = self->handle;
if (!pcm) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
int err = snd_pcm_hw_params_any(pcm, params);
if (err < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
return NULL;
}
unsigned min, max;
if (snd_pcm_hw_params_get_rate_min(params, &min, NULL) <0 ) {
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate");
return NULL;
}
if (snd_pcm_hw_params_get_rate_max(params, &max, NULL) < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported bitrate");
return NULL;
}
if (min == max) {
return PyLong_FromLong(min);
}
else if (!snd_pcm_hw_params_test_rate(pcm, params, min + 1, 0)) {
PyObject *minp=PyLong_FromLong(min);
PyObject *maxp=PyLong_FromLong(max);
return PyTuple_Pack(2,minp,maxp);
}
else {
PyObject *rates=PyList_New(0);
for (size_t i=0; i<ARRAY_SIZE(ALSARates); i++) {
unsigned rate = ALSARates[i];
if (!snd_pcm_hw_params_test_rate(pcm, params, rate, 0)) {
PyObject *prate=PyLong_FromLong(rate);
PyList_Append(rates,prate);
}
}
return rates;
}
}
PyDoc_STRVAR(getrates_doc,
"getrates() -> obj\n\
\n\
Returns the sample rates supported by the device.\
Returned value can be one of three types, depending on the card's properties.\
There are three cases:\n\
\n\
- Card supports only a single rate: returns the rate\n\
- Card supports a continuous range of rates: returns a tuple of the range's lower and upper bounds (inclusive)\n\
- Card supports a collection of well-known rates: returns a list of the supported rates");
static PyObject *
alsapcm_getchannels(alsapcm_t *self,PyObject *args)
{
snd_pcm_t *pcm = self->handle;
if (!pcm) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
int err = snd_pcm_hw_params_any(pcm, params);
if (err < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
return NULL;
}
unsigned min, max;
if (snd_pcm_hw_params_get_channels_min(params, &min) < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported number of channels");
return NULL;
}
if (snd_pcm_hw_params_get_channels_max(params, &max) < 0) {
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported number of channels");
return NULL;
}
PyObject *out = PyList_New(0);
for (unsigned ch=min;ch<=max;++ch) {
if (!snd_pcm_hw_params_test_channels(pcm, params, ch)) {
PyObject *pch=PyLong_FromLong(ch);
PyList_Append(out,pch);
}
}
return out;
}
PyDoc_STRVAR(getchannels_doc,
"getchannels() -> [int]\n\
\n\
Returns list of supported channel numbers.");
static PyObject *
alsapcm_pcmtype(alsapcm_t *self, PyObject *args)
{
@@ -634,147 +804,13 @@ PyDoc_STRVAR(cardname_doc,
\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_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
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_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
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_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
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_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
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;
}
int size = self->framesize * self->periodsize;
PyObject *buffer_obj, *tuple_obj, *res_obj;
char *buffer;
if (!PyArg_ParseTuple(args,":read"))
return NULL;
@@ -791,6 +827,18 @@ alsapcm_read(alsapcm_t *self, PyObject *args)
return NULL;
}
#if PY_MAJOR_VERSION < 3
buffer_obj = PyString_FromStringAndSize(NULL, size);
if (!buffer_obj)
return NULL;
buffer = PyString_AS_STRING(buffer_obj);
#else
buffer_obj = PyBytes_FromStringAndSize(NULL, size);
if (!buffer_obj)
return NULL;
buffer = PyBytes_AS_STRING(buffer_obj);
#endif
Py_BEGIN_ALLOW_THREADS
res = snd_pcm_readi(self->handle, buffer, self->periodsize);
if (res == -EPIPE)
@@ -810,15 +858,39 @@ alsapcm_read(alsapcm_t *self, PyObject *args)
PyErr_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
Py_DECREF(buffer_obj);
return NULL;
}
}
if (res <= 0) {
#if PY_MAJOR_VERSION < 3
return Py_BuildValue("is#", res, buffer, res*self->framesize);
/* If the following fails, it will free the object */
if (_PyString_Resize(&buffer_obj, 0))
return NULL;
#else
return Py_BuildValue("iy#", res, buffer, res*self->framesize);
/* If the following fails, it will free the object */
if (_PyBytes_Resize(&buffer_obj, 0))
return NULL;
#endif
}
res_obj = PyLong_FromLong(res);
if (!res_obj) {
Py_DECREF(buffer_obj);
return NULL;
}
tuple_obj = PyTuple_New(2);
if (!tuple_obj) {
Py_DECREF(buffer_obj);
Py_DECREF(res_obj);
return NULL;
}
/* Steal reference counts */
PyTuple_SET_ITEM(tuple_obj, 0, res_obj);
PyTuple_SET_ITEM(tuple_obj, 1, buffer_obj);
return tuple_obj;
}
PyDoc_STRVAR(read_doc,
@@ -950,6 +1022,43 @@ PyDoc_STRVAR(pause_doc,
If enable is 1, playback or capture is paused. If enable is 0,\n\
playback/capture is resumed.");
static PyObject *alsapcm_drop(alsapcm_t *self)
{
int res;
if (!self->handle) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
res = snd_pcm_drop(self->handle);
if (res < 0)
{
PyErr_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
return NULL;
}
res = snd_pcm_prepare(self->handle);
if (res < 0)
{
PyErr_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
self->cardname);
return NULL;
}
return PyLong_FromLong(res);
}
PyDoc_STRVAR(drop_doc,
"drop(enable=1)\n\
\n\
stop current read and drop residual packet");
static PyObject *
alsapcm_polldescriptors(alsapcm_t *self, PyObject *args)
{
@@ -1013,16 +1122,15 @@ 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},
{"getformats", (PyCFunction)alsapcm_getformats, METH_VARARGS, getformats_doc},
{"getratebounds", (PyCFunction)alsapcm_getratemaxmin, METH_VARARGS, getratebounds_doc},
{"getrates", (PyCFunction)alsapcm_getrates, METH_VARARGS, getrates_doc},
{"getchannels", (PyCFunction)alsapcm_getchannels, METH_VARARGS, getchannels_doc},
{"read", (PyCFunction)alsapcm_read, METH_VARARGS, read_doc},
{"write", (PyCFunction)alsapcm_write, METH_VARARGS, write_doc},
{"pause", (PyCFunction)alsapcm_pause, METH_VARARGS, pause_doc},
{"drop", (PyCFunction)alsapcm_drop, METH_VARARGS, drop_doc},
{"close", (PyCFunction)alsapcm_close, METH_VARARGS, pcm_close_doc},
{"polldescriptors", (PyCFunction)alsapcm_polldescriptors, METH_VARARGS,
pcm_polldescriptors_doc},
@@ -1072,14 +1180,14 @@ static PyTypeObject ALSAPCMType = {
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 */
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 */
};
@@ -2354,14 +2462,14 @@ static PyTypeObject ALSAMixerType = {
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 */
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 */
};

View File

@@ -75,7 +75,7 @@ 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
PyAlsaAudio has 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

View File

@@ -30,7 +30,7 @@ def play(device, f):
else:
raise ValueError('Unsupported format')
periodsize = f.getframerate() / 8
periodsize = f.getframerate() // 8
device.setperiodsize(periodsize)

View File

@@ -8,7 +8,7 @@ from setuptools import setup
from setuptools.extension import Extension
from sys import version
pyalsa_version = '0.8.4'
pyalsa_version = '0.8.6'
if __name__ == '__main__':
setup(