mirror of
https://github.com/larsimmisch/pyalsaaudio.git
synced 2026-06-01 19:07:02 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d3aa602a04 |
@@ -4,8 +4,6 @@ MANIFEST
|
|||||||
doc/gh-pages/
|
doc/gh-pages/
|
||||||
doc/html/
|
doc/html/
|
||||||
doc/doctrees/
|
doc/doctrees/
|
||||||
doc/_build/
|
|
||||||
gh-pages/
|
gh-pages/
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
.vscode/
|
|
||||||
+15
-263
@@ -1,4 +1,4 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: t -*- */
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture).
|
* alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture).
|
||||||
@@ -107,7 +107,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Configurable parameters
|
// Configurable parameters
|
||||||
int channels;
|
int channels;
|
||||||
unsigned int rate;
|
int rate;
|
||||||
int format;
|
int format;
|
||||||
snd_pcm_uframes_t periodsize;
|
snd_pcm_uframes_t periodsize;
|
||||||
int framesize;
|
int framesize;
|
||||||
@@ -358,81 +358,26 @@ PyDoc_STRVAR(pcms_doc,
|
|||||||
\n\
|
\n\
|
||||||
List the available PCM devices");
|
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;
|
|
||||||
unsigned int periods = 4;
|
|
||||||
snd_pcm_hw_params_set_rate_near(self->handle, hwparams, &self->rate, &dir);
|
|
||||||
snd_pcm_hw_params_set_period_size_near(self->handle, hwparams,
|
|
||||||
&self->periodsize, &dir);
|
|
||||||
snd_pcm_hw_params_set_periods_near(self->handle, hwparams, &periods, &dir);
|
|
||||||
|
|
||||||
/* 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 *
|
static PyObject *
|
||||||
alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
alsapcm_t *self;
|
alsapcm_t *self;
|
||||||
PyObject *pcmtypeobj = NULL;
|
PyObject *pcmtypeobj = NULL;
|
||||||
long pcmtype;
|
long pcmtype;
|
||||||
int pcmmode = 0;
|
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 *device = "default";
|
||||||
char *card = NULL;
|
char *card = NULL;
|
||||||
int cardidx = -1;
|
int cardidx = -1;
|
||||||
char hw_device[128];
|
char hw_device[128];
|
||||||
int rate = 44100;
|
int latency = 200;
|
||||||
int channels = 2;
|
char *kw[] = { "type", "mode", "device", "cardindex", "card", "format", "rate", "channels", "latency", NULL };
|
||||||
int format = SND_PCM_FORMAT_S16_LE;
|
|
||||||
int periodsize = 32;
|
|
||||||
|
|
||||||
char *kw[] = { "type", "mode", "device", "cardindex", "card", "rate", "channels", "format", "periodsize", NULL };
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiziiii", kw,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiziiii", kw,
|
||||||
&pcmtypeobj, &pcmmode, &device,
|
&pcmtypeobj, &pcmmode, &device,
|
||||||
&cardidx, &card, &rate, &channels, &format, &periodsize))
|
&cardidx, &card, &rate, &format, &channels, &latency))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (cardidx >= 0) {
|
if (cardidx >= 0) {
|
||||||
@@ -465,29 +410,9 @@ alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||||||
return NULL;
|
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 = channels;
|
|
||||||
self->rate = rate;
|
|
||||||
self->format = format;
|
|
||||||
self->periodsize = periodsize;
|
|
||||||
|
|
||||||
res = snd_pcm_open(&(self->handle), device, self->pcmtype,
|
res = snd_pcm_open(&(self->handle), device, self->pcmtype,
|
||||||
self->pcmmode);
|
self->pcmmode);
|
||||||
|
|
||||||
if (res >= 0) {
|
|
||||||
res = alsapcm_setup(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
self->cardname = strdup(device);
|
self->cardname = strdup(device);
|
||||||
}
|
}
|
||||||
@@ -879,173 +804,6 @@ PyDoc_STRVAR(cardname_doc,
|
|||||||
\n\
|
\n\
|
||||||
Returns the name of the sound card used by this PCM object.");
|
Returns the name of the sound card used by this PCM object.");
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
alsapcm_setchannels(alsapcm_t *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int channels, saved;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,"i:setchannels", &channels))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!self->handle) {
|
|
||||||
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
||||||
"This function is deprecated. "
|
|
||||||
"Please use the named parameter `channels` to `PCM()` instead", 1);
|
|
||||||
|
|
||||||
saved = self->channels;
|
|
||||||
self->channels = channels;
|
|
||||||
res = alsapcm_setup(self);
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
self->channels = saved;
|
|
||||||
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\
|
|
||||||
Deprecated since 0.9\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, saved;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,"i:setrate", &rate))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!self->handle)
|
|
||||||
{
|
|
||||||
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
||||||
"This function is deprecated. "
|
|
||||||
"Please use the named parameter `rate` to `PCM()` instead", 1);
|
|
||||||
|
|
||||||
saved = self->rate;
|
|
||||||
self->rate = rate;
|
|
||||||
res = alsapcm_setup(self);
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
self->rate = saved;
|
|
||||||
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\
|
|
||||||
Deprecated since 0.9\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, saved;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,"i:setformat", &format))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!self->handle)
|
|
||||||
{
|
|
||||||
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
||||||
"This function is deprecated. "
|
|
||||||
"Please use the named parameter `format` to `PCM()` instead", 1);
|
|
||||||
|
|
||||||
saved = self->format;
|
|
||||||
self->format = format;
|
|
||||||
res = alsapcm_setup(self);
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
self->format = saved;
|
|
||||||
PyErr_Format(ALSAAudioError, "%s [%s]", snd_strerror(res),
|
|
||||||
self->cardname);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return PyLong_FromLong(self->format);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(setformat_doc,
|
|
||||||
"setformat(rate)\n\
|
|
||||||
\n\
|
|
||||||
Deprecated since 0.9");
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
alsapcm_setperiodsize(alsapcm_t *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int periodsize, saved;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,"i:setperiodsize", &periodsize))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!self->handle)
|
|
||||||
{
|
|
||||||
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
||||||
"This function is deprecated. "
|
|
||||||
"Please use the named parameter `periodsize` to `PCM()` instead", 1);
|
|
||||||
|
|
||||||
saved = self->periodsize;
|
|
||||||
self->periodsize = periodsize;
|
|
||||||
res = alsapcm_setup(self);
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
self->periodsize = saved;
|
|
||||||
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\
|
|
||||||
Deprecated since 0.9\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 *
|
static PyObject *
|
||||||
alsapcm_read(alsapcm_t *self, PyObject *args)
|
alsapcm_read(alsapcm_t *self, PyObject *args)
|
||||||
{
|
{
|
||||||
@@ -1364,12 +1122,6 @@ static PyMethodDef alsapcm_methods[] = {
|
|||||||
{"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS, pcmtype_doc},
|
{"pcmtype", (PyCFunction)alsapcm_pcmtype, METH_VARARGS, pcmtype_doc},
|
||||||
{"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS, pcmmode_doc},
|
{"pcmmode", (PyCFunction)alsapcm_pcmmode, METH_VARARGS, pcmmode_doc},
|
||||||
{"cardname", (PyCFunction)alsapcm_cardname, METH_VARARGS, cardname_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},
|
{"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS},
|
||||||
{"getformats", (PyCFunction)alsapcm_getformats, METH_VARARGS, getformats_doc},
|
{"getformats", (PyCFunction)alsapcm_getformats, METH_VARARGS, getformats_doc},
|
||||||
{"getratebounds", (PyCFunction)alsapcm_getratemaxmin, METH_VARARGS, getratebounds_doc},
|
{"getratebounds", (PyCFunction)alsapcm_getratemaxmin, METH_VARARGS, getratebounds_doc},
|
||||||
@@ -1862,43 +1614,43 @@ alsamixer_switchcap(alsamixer_t *self, PyObject *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = PyList_New(0);
|
result = PyList_New(0);
|
||||||
if (self->switch_cap & MIXER_CAP_SWITCH)
|
if (self->volume_cap & MIXER_CAP_SWITCH)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Mute");
|
item = PyUnicode_FromString("Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_SWITCH_JOINED)
|
if (self->volume_cap & MIXER_CAP_SWITCH_JOINED)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Joined Mute");
|
item = PyUnicode_FromString("Joined Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_PSWITCH)
|
if (self->volume_cap & MIXER_CAP_PSWITCH)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Playback Mute");
|
item = PyUnicode_FromString("Playback Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_PSWITCH_JOINED)
|
if (self->volume_cap & MIXER_CAP_PSWITCH_JOINED)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Joined Playback Mute");
|
item = PyUnicode_FromString("Joined Playback Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_CSWITCH)
|
if (self->volume_cap & MIXER_CAP_CSWITCH)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Capture Mute");
|
item = PyUnicode_FromString("Capture Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_CSWITCH_JOINED)
|
if (self->volume_cap & MIXER_CAP_CSWITCH_JOINED)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Joined Capture Mute");
|
item = PyUnicode_FromString("Joined Capture Mute");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
if (self->switch_cap & MIXER_CAP_CSWITCH_EXCLUSIVE)
|
if (self->volume_cap & MIXER_CAP_CSWITCH_EXCLUSIVE)
|
||||||
{
|
{
|
||||||
item = PyUnicode_FromString("Capture Exclusive");
|
item = PyUnicode_FromString("Capture Exclusive");
|
||||||
PyList_Append(result, item);
|
PyList_Append(result, item);
|
||||||
|
|||||||
@@ -1,22 +1,3 @@
|
|||||||
# Make a new release
|
|
||||||
|
|
||||||
Update the version in setup.py
|
|
||||||
|
|
||||||
pyalsa_version = '0.9.0'
|
|
||||||
|
|
||||||
Commit and push the update.
|
|
||||||
|
|
||||||
Create and push a tag naming the version (i.e. 0.9.0):
|
|
||||||
|
|
||||||
git tag 0.9.0
|
|
||||||
git push origin 0.9.0
|
|
||||||
|
|
||||||
Upload the package:
|
|
||||||
|
|
||||||
python3 setup.py sdist
|
|
||||||
|
|
||||||
Don't forget to update the documentation.
|
|
||||||
|
|
||||||
# Publish the documentation
|
# Publish the documentation
|
||||||
|
|
||||||
The documentation is published through the `gh-pages` branch.
|
The documentation is published through the `gh-pages` branch.
|
||||||
|
|||||||
+73
-62
@@ -63,6 +63,7 @@ The :mod:`alsaaudio` module defines functions and classes for using ALSA.
|
|||||||
useful. If you want to see a list of available PCM devices, use :func:`pcms`
|
useful. If you want to see a list of available PCM devices, use :func:`pcms`
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
|
|
||||||
.. function:: mixers(cardindex=-1, device='default')
|
.. function:: mixers(cardindex=-1, device='default')
|
||||||
|
|
||||||
List the available mixers. The arguments are:
|
List the available mixers. The arguments are:
|
||||||
@@ -107,7 +108,7 @@ PCM objects in :mod:`alsaaudio` can play or capture (record) PCM
|
|||||||
sound through speakers or a microphone. The PCM constructor takes the
|
sound through speakers or a microphone. The PCM constructor takes the
|
||||||
following arguments:
|
following arguments:
|
||||||
|
|
||||||
.. class:: PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, rate=44100, channels=2, format=PCM_FORMAT_S16_LE, periodsize=32, device='default', cardindex=-1)
|
.. class:: PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, device='default', cardindex=-1)
|
||||||
|
|
||||||
This class is used to represent a PCM device (either for playback and
|
This class is used to represent a PCM device (either for playback and
|
||||||
recording). The arguments are:
|
recording). The arguments are:
|
||||||
@@ -116,11 +117,72 @@ following arguments:
|
|||||||
(default).
|
(default).
|
||||||
* *mode* - can be either :const:`PCM_NONBLOCK`, or :const:`PCM_NORMAL`
|
* *mode* - can be either :const:`PCM_NONBLOCK`, or :const:`PCM_NORMAL`
|
||||||
(default).
|
(default).
|
||||||
* *rate* - the sampling rate in Hz. Typical values are ``8000``
|
* *device* - the name of the PCM device that should be used (for example
|
||||||
(mainly used for telephony), ``16000``, ``44100`` (default), ``48000`` and ``96000``.
|
a value from the output of :func:`pcms`). The default value is
|
||||||
* *channels* - the number of channels. The default value is 2 (stereo).
|
``'default'``.
|
||||||
* *format* - the data format. This controls how the PCM device interprets data for playback, and how data is encoded in captures.
|
* *cardindex* - the card index. If this argument is given, the device name
|
||||||
The default value is :const:`PCM_FORMAT_S16_LE`.
|
is constructed as 'hw:*cardindex*' and
|
||||||
|
the `device` keyword argument is ignored.
|
||||||
|
``0`` is the first hardware sound card.
|
||||||
|
|
||||||
|
This will construct a PCM object with these default settings:
|
||||||
|
|
||||||
|
* Sample format: :const:`PCM_FORMAT_S16_LE`
|
||||||
|
* Rate: 44100 Hz
|
||||||
|
* Channels: 2
|
||||||
|
* Period size: 32 frames
|
||||||
|
|
||||||
|
*Changed in 0.8:*
|
||||||
|
|
||||||
|
- The `card` keyword argument is still supported,
|
||||||
|
but deprecated. Please use `device` instead.
|
||||||
|
|
||||||
|
- The keyword argument `cardindex` was added.
|
||||||
|
|
||||||
|
The `card` keyword is deprecated because it guesses the real ALSA
|
||||||
|
name of the card. This was always fragile and broke some legitimate usecases.
|
||||||
|
|
||||||
|
|
||||||
|
PCM objects have the following methods:
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.pcmtype()
|
||||||
|
|
||||||
|
Returns the type of PCM object. Either :const:`PCM_CAPTURE` or
|
||||||
|
:const:`PCM_PLAYBACK`.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.pcmmode()
|
||||||
|
|
||||||
|
Return the mode of the PCM object. One of :const:`PCM_NONBLOCK`,
|
||||||
|
:const:`PCM_ASYNC`, or :const:`PCM_NORMAL`
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.cardname()
|
||||||
|
|
||||||
|
Return the name of the sound card used by this PCM object.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.setchannels(nchannels)
|
||||||
|
|
||||||
|
Used to set the number of capture or playback channels. Common
|
||||||
|
values are: ``1`` = mono, ``2`` = stereo, and ``6`` = full 6 channel audio.
|
||||||
|
Few sound cards support more than 2 channels
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.setrate(rate)
|
||||||
|
|
||||||
|
Set the sample rate in Hz for the device. Typical values are ``8000``
|
||||||
|
(mainly used for telephony), ``16000``, ``44100`` (CD quality),
|
||||||
|
``48000`` and ``96000``.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: PCM.setformat(format)
|
||||||
|
|
||||||
|
The sound *format* of the device. Sound format controls how the PCM device
|
||||||
|
interpret data for playback, and how data is encoded in captures.
|
||||||
|
|
||||||
|
The following formats are provided by ALSA:
|
||||||
|
|
||||||
========================= ===============
|
========================= ===============
|
||||||
Format Description
|
Format Description
|
||||||
@@ -154,65 +216,14 @@ following arguments:
|
|||||||
``PCM_FORMAT_U24_3BE`` Unsigned 24 bit samples for each channel (Big Endian byte order in 3 bytes)
|
``PCM_FORMAT_U24_3BE`` Unsigned 24 bit samples for each channel (Big Endian byte order in 3 bytes)
|
||||||
========================= ===============
|
========================= ===============
|
||||||
|
|
||||||
* *periodsize* - the period size in frames. Each write should consist of *periodsize* frames. The default value is 32.
|
|
||||||
* *device* - the name of the PCM device that should be used (for example
|
|
||||||
a value from the output of :func:`pcms`). The default value is
|
|
||||||
``'default'``.
|
|
||||||
* *cardindex* - the card index. If this argument is given, the device name
|
|
||||||
is constructed as 'hw:*cardindex*' and
|
|
||||||
the `device` keyword argument is ignored.
|
|
||||||
``0`` is the first hardware sound card.
|
|
||||||
|
|
||||||
This will construct a PCM object with the given settings.
|
|
||||||
|
|
||||||
*Changed in 0.9:*
|
|
||||||
|
|
||||||
- Added the optional named parameters `rate`, `channels`, `format` and `periodsize`.
|
|
||||||
|
|
||||||
*Changed in 0.8:*
|
|
||||||
|
|
||||||
- The `card` keyword argument is still supported,
|
|
||||||
but deprecated. Please use `device` instead.
|
|
||||||
|
|
||||||
- The keyword argument `cardindex` was added.
|
|
||||||
|
|
||||||
The `card` keyword is deprecated because it guesses the real ALSA
|
|
||||||
name of the card. This was always fragile and broke some legitimate usecases.
|
|
||||||
|
|
||||||
|
|
||||||
PCM objects have the following methods:
|
|
||||||
|
|
||||||
.. method:: PCM.pcmtype()
|
|
||||||
|
|
||||||
Returns the type of PCM object. Either :const:`PCM_CAPTURE` or
|
|
||||||
:const:`PCM_PLAYBACK`.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: PCM.pcmmode()
|
|
||||||
|
|
||||||
Return the mode of the PCM object. One of :const:`PCM_NONBLOCK`,
|
|
||||||
:const:`PCM_ASYNC`, or :const:`PCM_NORMAL`
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: PCM.cardname()
|
|
||||||
|
|
||||||
Return the name of the sound card used by this PCM object.
|
|
||||||
|
|
||||||
.. method:: PCM.setchannels(nchannels)
|
|
||||||
|
|
||||||
.. deprecated:: 0.9 Use the `channels` named argument to :func:`PCM`.
|
|
||||||
|
|
||||||
.. method:: PCM.setrate(rate)
|
|
||||||
|
|
||||||
.. deprecated:: 0.9 Use the `rate` named argument to :func:`PCM`.
|
|
||||||
|
|
||||||
.. method:: PCM.setformat(format)
|
|
||||||
|
|
||||||
.. deprecated:: 0.9 Use the `format` named argument to :func:`PCM`.
|
|
||||||
|
|
||||||
.. method:: PCM.setperiodsize(period)
|
.. method:: PCM.setperiodsize(period)
|
||||||
|
|
||||||
.. deprecated:: 0.9 Use the `periodsize` named argument to :func:`PCM`.
|
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 :const:`PCM_NONBLOCK` mode, in
|
||||||
|
which case it may return nothing at all)
|
||||||
|
|
||||||
|
|
||||||
.. method:: PCM.read()
|
.. method:: PCM.read()
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ class SinePlayer(Thread):
|
|||||||
def __init__(self, frequency = 440.0):
|
def __init__(self, frequency = 440.0):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.setDaemon(True)
|
self.setDaemon(True)
|
||||||
self.device = alsaaudio.PCM(channels=channels, format=format, rate=sampling_rate)
|
self.device = alsaaudio.PCM()
|
||||||
|
self.device.setchannels(channels)
|
||||||
|
self.device.setformat(format)
|
||||||
|
self.device.setrate(sampling_rate)
|
||||||
self.queue = Queue()
|
self.queue = Queue()
|
||||||
self.change(frequency)
|
self.change(frequency)
|
||||||
|
|
||||||
|
|||||||
+10
-4
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
|
|
||||||
|
|
||||||
## playbacktest.py
|
## playbacktest.py
|
||||||
##
|
##
|
||||||
@@ -39,11 +38,18 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
f = open(args[0], 'rb')
|
f = open(args[0], 'rb')
|
||||||
|
|
||||||
# Open the device in playback mode in Mono, 44100 Hz, 16 bit little endian frames
|
# Open the device in playback mode.
|
||||||
|
out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, device=device)
|
||||||
|
|
||||||
|
# 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 period size controls the internal number of frames per period.
|
||||||
# The significance of this parameter is documented in the ALSA api.
|
# The significance of this parameter is documented in the ALSA api.
|
||||||
|
out.setperiodsize(160)
|
||||||
|
|
||||||
out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, channels=1, rate=44100, format=alsaaudio.PCM_FORMAT_S16_LE, periodsize=160, device=device)
|
|
||||||
# Read data from stdin
|
# Read data from stdin
|
||||||
data = f.read(320)
|
data = f.read(320)
|
||||||
while data:
|
while data:
|
||||||
|
|||||||
+16
-14
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
|
|
||||||
|
|
||||||
# Simple test script that plays (some) wav files
|
# Simple test script that plays (some) wav files
|
||||||
|
|
||||||
@@ -12,29 +11,28 @@ import alsaaudio
|
|||||||
|
|
||||||
def play(device, f):
|
def play(device, f):
|
||||||
|
|
||||||
format = None
|
print('%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
|
# 8bit is unsigned in wav files
|
||||||
if f.getsampwidth() == 1:
|
if f.getsampwidth() == 1:
|
||||||
format = alsaaudio.PCM_FORMAT_U8
|
device.setformat(alsaaudio.PCM_FORMAT_U8)
|
||||||
# Otherwise we assume signed data, little endian
|
# Otherwise we assume signed data, little endian
|
||||||
elif f.getsampwidth() == 2:
|
elif f.getsampwidth() == 2:
|
||||||
format = alsaaudio.PCM_FORMAT_S16_LE
|
device.setformat(alsaaudio.PCM_FORMAT_S16_LE)
|
||||||
elif f.getsampwidth() == 3:
|
elif f.getsampwidth() == 3:
|
||||||
format = alsaaudio.PCM_FORMAT_S24_3LE
|
device.setformat(alsaaudio.PCM_FORMAT_S24_3LE)
|
||||||
elif f.getsampwidth() == 4:
|
elif f.getsampwidth() == 4:
|
||||||
format = alsaaudio.PCM_FORMAT_S32_LE
|
device.setformat(alsaaudio.PCM_FORMAT_S32_LE)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unsupported format')
|
raise ValueError('Unsupported format')
|
||||||
|
|
||||||
periodsize = f.getframerate() // 8
|
periodsize = f.getframerate() // 8
|
||||||
|
|
||||||
print('%d channels, %d sampling rate, format %d, periodsize %d\n' % (f.getnchannels(),
|
device.setperiodsize(periodsize)
|
||||||
f.getframerate(),
|
|
||||||
format,
|
|
||||||
periodsize))
|
|
||||||
|
|
||||||
device = alsaaudio.PCM(channels=f.getnchannels(), rate=f.getframerate(), format=format, periodsize=periodsize, device=device)
|
|
||||||
|
|
||||||
data = f.readframes(periodsize)
|
data = f.readframes(periodsize)
|
||||||
while data:
|
while data:
|
||||||
@@ -59,5 +57,9 @@ if __name__ == '__main__':
|
|||||||
if not args:
|
if not args:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
with wave.open(args[0], 'rb') as f:
|
f = wave.open(args[0], 'rb')
|
||||||
|
device = alsaaudio.PCM(device=device)
|
||||||
|
|
||||||
play(device, f)
|
play(device, f)
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
|||||||
+12
-7
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
|
|
||||||
|
|
||||||
## recordtest.py
|
## recordtest.py
|
||||||
##
|
##
|
||||||
@@ -40,8 +39,16 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
f = open(args[0], 'wb')
|
f = open(args[0], 'wb')
|
||||||
|
|
||||||
# Open the device in nonblocking capture mode in mono, with a sampling rate of 44100 Hz
|
# Open the device in nonblocking capture mode. The last argument could
|
||||||
# and 16 bit little endian samples
|
# 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, device=device)
|
||||||
|
|
||||||
|
# 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 period size controls the internal number of frames per period.
|
||||||
# The significance of this parameter is documented in the ALSA api.
|
# The significance of this parameter is documented in the ALSA api.
|
||||||
# For our purposes, it is suficcient to know that reads from the device
|
# For our purposes, it is suficcient to know that reads from the device
|
||||||
@@ -49,9 +56,7 @@ if __name__ == '__main__':
|
|||||||
# This means that the reads below will return either 320 bytes of data
|
# 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
|
# or 0 bytes of data. The latter is possible because we are in nonblocking
|
||||||
# mode.
|
# mode.
|
||||||
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NONBLOCK,
|
inp.setperiodsize(160)
|
||||||
channels=1, rate=44100, format=alsaaudio.PCM_FORMAT_S16_LE,
|
|
||||||
periodsize=160, device=device)
|
|
||||||
|
|
||||||
loops = 1000000
|
loops = 1000000
|
||||||
while loops > 0:
|
while loops > 0:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from setuptools import setup
|
|||||||
from setuptools.extension import Extension
|
from setuptools.extension import Extension
|
||||||
from sys import version
|
from sys import version
|
||||||
|
|
||||||
pyalsa_version = '0.9.0'
|
pyalsa_version = '0.8.6'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
setup(
|
setup(
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
|
|
||||||
|
|
||||||
# These are internal tests. They shouldn't fail, but they don't cover all
|
# These are internal tests. They shouldn't fail, but they don't cover all
|
||||||
# of the ALSA API. Most importantly PCM.read and PCM.write are missing.
|
# of the ALSA API. Most importantly PCM.read and PCM.write are missing.
|
||||||
@@ -13,18 +12,13 @@ import alsaaudio
|
|||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
# we can't test read and write well - these are tested otherwise
|
# we can't test read and write well - these are tested otherwise
|
||||||
PCMMethods = [
|
PCMMethods = [('pcmtype', None),
|
||||||
('pcmtype', None),
|
|
||||||
('pcmmode', None),
|
('pcmmode', None),
|
||||||
('cardname', None)
|
('cardname', None),
|
||||||
]
|
|
||||||
|
|
||||||
PCMDeprecatedMethods = [
|
|
||||||
('setchannels', (2,)),
|
('setchannels', (2,)),
|
||||||
('setrate', (44100,)),
|
('setrate', (44100,)),
|
||||||
('setformat', (alsaaudio.PCM_FORMAT_S8,)),
|
('setformat', (alsaaudio.PCM_FORMAT_S8,)),
|
||||||
('setperiodsize', (320,))
|
('setperiodsize', (320,))]
|
||||||
]
|
|
||||||
|
|
||||||
# A clever test would look at the Mixer capabilities and selectively run the
|
# A clever test would look at the Mixer capabilities and selectively run the
|
||||||
# omitted tests, but I am too tired for that.
|
# omitted tests, but I am too tired for that.
|
||||||
@@ -135,26 +129,8 @@ class PCMTest(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Verify we got a DepreciationWarning
|
# Verify we got a DepreciationWarning
|
||||||
self.assertEqual(len(w), 1, "PCM(card='default') expected a warning" )
|
assert len(w) == 1
|
||||||
self.assertTrue(issubclass(w[-1].category, DeprecationWarning), "PCM(card='default') expected a DeprecationWarning")
|
assert issubclass(w[-1].category, DeprecationWarning)
|
||||||
|
|
||||||
for m, a in PCMDeprecatedMethods:
|
|
||||||
with warnings.catch_warnings(record=True) as w:
|
|
||||||
# Cause all warnings to always be triggered.
|
|
||||||
warnings.simplefilter("always")
|
|
||||||
|
|
||||||
pcm = alsaaudio.PCM()
|
|
||||||
|
|
||||||
f = alsaaudio.PCM.__dict__[m]
|
|
||||||
if a is None:
|
|
||||||
f(pcm)
|
|
||||||
else:
|
|
||||||
f(pcm, *a)
|
|
||||||
|
|
||||||
# Verify we got a DepreciationWarning
|
|
||||||
method = "%s%s" % (m, str(a))
|
|
||||||
self.assertEqual(len(w), 1, method + " expected a warning")
|
|
||||||
self.assertTrue(issubclass(w[-1].category, DeprecationWarning), method + " expected a DeprecationWarning")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user