[alsa-devel] [PATCH] pyalsa sequencer binding - 1/3
Aldrin Martoq
amartoq at dcc.uchile.cl
Thu Jan 24 09:27:46 CET 2008
Hi hackers again,
I'm sending second PATCH for pyalsa sequencer binding. Major new features:
- documentation of all python API
- more info on subscription listing
- subscribe/unsubscribe
- events (SeqEvent class)
- send/receive/modify events
- creating and managing queues
I've already ported some existing applications to python versions:
- aconnect.py
- aplaymidi.py
- aseqdump.py
There are also 3 samples of code seqtest[1-3].py included in the patch.
It's been a long and tedious work (16 days); please tell me anyhow to
improve and get this done and finished. Thanks again!!!
-------
Signed-off-by: Aldrin Martoq <amartoq at dcc.uchile.cl>
diff -r 02b11d9f243d pyalsa/alsaseq.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyalsa/alsaseq.c Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,3818 @@
+/*
+ * Python binding for the ALSA library - sequencer
+ * Copyright (c) 2008 by Aldrin Martoq <amartoq at dcc.uchile.cl>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "Python.h"
+#include <alsa/asoundlib.h>
+#include <stdio.h>
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// some helper #define go here...
+//////////////////////////////////////////////////////////////////////////////
+
+/* temporal debug (will be deleted in last patch, promise!) */
+#if 1
+#define ddebug(x, args...) fprintf(stderr, x "\n",##args);
+#else
+#define ddebug(x, args...)
+#endif
+
+/* checks if passed argument is an integer and can't be deleted.
+ returns -1 if fails and raises TypeError or AttributeError. */
+#define SETCHECKPYINT(attr, val) \
+ if (val == NULL) { \
+ PyErr_SetString(PyExc_AttributeError, \
+ "attribute " attr " can't be deleted!"); \
+ return -1; \
+ } \
+ if (!PyInt_Check(val)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "integer value expected for " attr); \
+ return -1; \
+ }
+
+/* checks if passed argument is a string and can't be deleted.
+ returns -1 if fails and raises TypeError or AttributeError. */
+#define SETCHECKPYSTR(attr, val) \
+ if (val == NULL) { \
+ PyErr_SetString(PyExc_AttributeError, \
+ "attribute " attr " can't be deleted!"); \
+ return -1; \
+ } \
+ if (!PyString_Check(val)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "string value expected for " attr); \
+ return -1; \
+ }
+
+/* checks if passed argument is a list and can't be deleted.
+ returns -1 if fails and raises TypeError or AttributeError. */
+#define SETCHECKPYLIST(attr, val) \
+ if (val == NULL) { \
+ PyErr_SetString(PyExc_AttributeError, \
+ "attribute " attr " can't be deleted!"); \
+ return -1; \
+ } \
+ if (!PyList_Check(val)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "list value expected for " attr); \
+ return -1; \
+ }
+
+/* frees only if pointer is not NULL. */
+#define FREECHECKED(name, pointer) \
+ if (pointer != NULL) { \
+ free(pointer); \
+ pointer = NULL; \
+ }
+
+/* raises SequencerError with the specified string */
+#define RAISESTR(str, args...) \
+ PyErr_Format(SequencerError, str,##args);
+
+/* raises SequencerError with the specified string and appends
+ the alsaaudio error as string */
+#define RAISESND(ret, str, args...) \
+ PyErr_Format(SequencerError, str ": %s",##args, snd_strerror(ret));
+
+/* the C variable of a constant dict */
+#define TDICT(subtype) _dictPYALSASEQ_CONST_##subtype
+
+/* the C enumeration of a constant dict */
+#define TTYPE(subtype) PYALSASEQ_CONST_##subtype
+
+/* defines constant dict by type */
+#define TCONSTDICT(subtype) \
+ static PyObject * TDICT(subtype);
+
+/* adds constant dict to module */
+#define TCONSTDICTADD(module, subtype, name) \
+ _dictPYALSASEQ_CONST_##subtype = PyDict_New(); \
+ if (TDICT(subtype) == NULL) { \
+ return; \
+ } \
+ if (PyModule_AddObject(module, name, TDICT(subtype)) < 0) { \
+ return; \
+ }
+
+/* creates a typed constant and add it to the module and dictionary */
+#define TCONSTADD(module, subtype, name, value) { \
+ PyObject *tmp = \
+ Constant_create(name, value, TTYPE(subtype)); \
+ if (tmp == NULL) { \
+ return; \
+ } \
+ if (PyModule_AddObject(module, name, tmp) < 0) { \
+ return; \
+ } \
+ PyDict_SetItem(TDICT(subtype), PyInt_FromLong(value), tmp); \
+ }
+
+#define TCONSTRETURN(subtype, value) { \
+ PyObject *key = PyInt_FromLong(value); \
+ ConstantObject *constantObject = (ConstantObject *) \
+ PyDict_GetItem(TDICT(subtype), key); \
+ if (constantObject == NULL) { \
+ return key; \
+ } else { \
+ Py_DECREF(key); \
+ Py_INCREF(constantObject); \
+ return (PyObject *)constantObject; \
+ } \
+ }
+
+#define TCONSTASSIGN(subtype, value, param) { \
+ PyObject *key = PyInt_FromLong(value); \
+ ConstantObject *constantObject = (ConstantObject *) \
+ PyDict_GetItem(TDICT(subtype), key); \
+ if (constantObject == NULL) { \
+ param = key; \
+ } else { \
+ Py_DECREF(key); \
+ Py_INCREF(constantObject); \
+ param = (PyObject *)constantObject; \
+ } \
+ }
+
+
+/* num protocol support for binary Constant operations */
+#define NUMPROTOCOL2(name, oper) \
+ static PyObject * \
+ Constant_##name (PyObject *v, PyObject *w) { \
+ int type = 0; \
+ long val = 0; \
+ /* both have to be a int */ \
+ if (!PyInt_Check(v) || !PyInt_Check(w)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ val = PyInt_AS_LONG(v) oper PyInt_AS_LONG(w); \
+ /* always asume left will be the type */ \
+ if (PyObject_TypeCheck(v, &ConstantType)) { \
+ type = ((ConstantObject *) v)->type; \
+ } else if (PyObject_TypeCheck(w, &ConstantType)) { \
+ type = ((ConstantObject *) w)->type; \
+ } \
+ PyObject *self = Constant_create(#oper, val, type); \
+ return self; \
+ }
+
+/* num protocol support for unary Constant operations */
+#define NUMPROTOCOL1(name, oper) \
+ static PyObject * \
+ Constant_##name (PyObject *v) { \
+ int type = 0; \
+ long val = 0; \
+ if (!PyInt_Check(v)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ val = oper PyInt_AS_LONG(v); \
+ if (PyObject_TypeCheck(v, &ConstantType)) { \
+ type = ((ConstantObject *) v)->type; \
+ } \
+ PyObject *self = Constant_create(#oper, val, type); \
+ return self; \
+ }
+
+/* sets the object into the dict */
+#define SETDICTOBJ(name, object) \
+ PyDict_SetItemString(dict, name, object)
+
+/* sets a integer into the dict */
+#define SETDICTINT(name, value) \
+ PyDict_SetItemString(dict, name, PyInt_FromLong(value))
+
+/* sets note info dict (used by SeqEvent_get_data) */
+#define SETDICT_NOTE3 { \
+ snd_seq_ev_note_t *data = &(event->data.note); \
+ SETDICTINT("note.channel", data->channel); \
+ SETDICTINT("note.note", data->note); \
+ SETDICTINT("note.velocity", data->velocity); \
+ }
+
+/* sets note info dict (used by SeqEvent_get_data) */
+#define SETDICT_NOTE5 { \
+ snd_seq_ev_note_t *data = &(event->data.note); \
+ SETDICTINT("note.channel", data->channel); \
+ SETDICTINT("note.note", data->note); \
+ SETDICTINT("note.velocity", data->velocity); \
+ SETDICTINT("note.off_velocity", data->off_velocity); \
+ SETDICTINT("note.duration", data->duration); \
+ }
+
+
+
+/* sets control info dict (used by SeqEvent_get_data) */
+#define SETDICT_CTRL1 { \
+ snd_seq_ev_ctrl_t *data = &(event->data.control); \
+ SETDICTINT("control.value", data->value); \
+ }
+
+/* sets control info dict (used by SeqEvent_get_data) */
+#define SETDICT_CTRL2 { \
+ snd_seq_ev_ctrl_t *data = &(event->data.control); \
+ SETDICTINT("control.channel", data->channel); \
+ SETDICTINT("control.value", data->value); \
+ }
+
+/* sets control info dict (used by SeqEvent_get_data) */
+#define SETDICT_CTRL3 { \
+ snd_seq_ev_ctrl_t *data = &(event->data.control); \
+ SETDICTINT("control.channel", data->channel); \
+ SETDICTINT("control.param", data->param); \
+ SETDICTINT("control.value", data->value); \
+ }
+
+/* sets queue info dict (used by SeqEvent_get_data) */
+#define SETDICT_QUEU1 { \
+ snd_seq_ev_queue_control_t *data = &(event->data.queue); \
+ SETDICTINT("queue.queue", data->queue); \
+ }
+
+/* sets addr info dict (used by SeqEvent_get_data) */
+#define SETDICT_ADDR1 { \
+ snd_seq_addr_t *data = &(event->data.addr); \
+ SETDICTINT("addr.client", data->client); \
+ }
+
+/* sets addr info dict (used by SeqEvent_get_data) */
+#define SETDICT_ADDR2 { \
+ snd_seq_addr_t *data = &(event->data.addr); \
+ SETDICTINT("addr.client", data->client); \
+ SETDICTINT("addr.port", data->port); \
+ }
+
+/* sets connect info dict (used by SeqEvent_get_data) */
+#define SETDICT_CONN4 { \
+ snd_seq_connect_t *data = &(event->data.connect); \
+ SETDICTINT("connect.sender.client", data->sender.client); \
+ SETDICTINT("connect.sender.port", data->sender.port); \
+ SETDICTINT("connect.dest.client", data->dest.client); \
+ SETDICTINT("connect.dest.port", data->dest.port); \
+ }
+
+/* sets result info dict (used by SeqEvent_get_data) */
+#define SETDICT_RESU2 { \
+ snd_seq_result_t *data = &(event->data.result); \
+ SETDICTINT("result.event", data->event); \
+ SETDICTINT("result.result", data->result); \
+ }
+
+/* sets ext info dict (used by SeqEvent_get_data) */
+#define SETDICT_EXT { \
+ snd_seq_ev_ext_t *data = &(event->data.ext); \
+ PyObject *list = PyList_New(data->len); \
+ int i = 0; \
+ unsigned char *t = (unsigned char *) data->ptr; \
+ for (i = 0; i < data->len; i++) { \
+ PyList_Append(list, PyInt_FromLong(t[i])); \
+ } \
+ SETDICTOBJ("ext", list); \
+ }
+
+/* gets integer from python param */
+#define GETDICTINT(name, param) { \
+ PyObject *value = PyDict_GetItemString(dict, name); \
+ if (value != NULL) { \
+ if (!PyInt_Check(value)) { \
+ PyErr_SetString(PyExc_TypeError, name " must be a integer"); \
+ return NULL; \
+ } \
+ param = PyInt_AsLong(value); \
+ } \
+ }
+
+/* gets float from python param */
+#define GETDICTFLOAT(name, param1, param2) { \
+ PyObject *value = PyDict_GetItemString(dict, name); \
+ if (value != NULL) { \
+ if (PyInt_Check(value)) { \
+ param2 = 0; \
+ param1 = PyInt_AsLong(value); \
+ } else if (PyFloat_Check(value)) { \
+ double d = PyFloat_AsDouble(value); \
+ unsigned int i = d; \
+ d -= i; \
+ param2 = d * 1000000; \
+ param1 = i; \
+ } else { \
+ PyErr_SetString(PyExc_TypeError, \
+ name " must be a integer or float"); \
+ return NULL; \
+ } \
+ } \
+ }
+
+/* gets ext data from python list */
+#define GETDICTEXT(name) { \
+ PyObject *list = PyDict_GetItemString(dict, name); \
+ if (list != NULL) { \
+ if (!PyList_Check(list)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ name " must be a list of integers"); \
+ return NULL; \
+ } \
+ FREECHECKED("buff", self->buff); \
+ int len = PyList_Size(list); \
+ self->event->data.ext.len = len; \
+ if (len > 0) { \
+ int i; \
+ self->buff = malloc(len); \
+ for (i = 0; i < len; i++) { \
+ PyObject *item = PyList_GetItem(list, i); \
+ if (!PyInt_Check(item)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ name " must be a list of integers"); \
+ return NULL; \
+ } \
+ self->buff[i] = PyInt_AsLong(item); \
+ } \
+ } \
+ } \
+ }
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// alsaseq.Constant implementation
+//////////////////////////////////////////////////////////////////////////////
+
+/* alsaseq.Constant->type enumeration */
+enum {
+ PYALSASEQ_CONST_STREAMS,
+ PYALSASEQ_CONST_MODE,
+ PYALSASEQ_CONST_QUEUE,
+ PYALSASEQ_CONST_CLIENT_TYPE,
+ PYALSASEQ_CONST_PORT_CAP,
+ PYALSASEQ_CONST_PORT_TYPE,
+ PYALSASEQ_CONST_EVENT_TYPE,
+ PYALSASEQ_CONST_EVENT_TIMESTAMP,
+ PYALSASEQ_CONST_EVENT_TIMEMODE,
+ PYALSASEQ_CONST_ADDR_CLIENT,
+ PYALSASEQ_CONST_ADDR_PORT,
+};
+
+// constants dictionaries
+
+TCONSTDICT(STREAMS);
+TCONSTDICT(MODE);
+TCONSTDICT(QUEUE);
+TCONSTDICT(CLIENT_TYPE);
+TCONSTDICT(PORT_CAP);
+TCONSTDICT(PORT_TYPE);
+TCONSTDICT(EVENT_TYPE);
+TCONSTDICT(EVENT_TIMESTAMP);
+TCONSTDICT(EVENT_TIMEMODE);
+TCONSTDICT(ADDR_CLIENT);
+TCONSTDICT(ADDR_PORT);
+
+
+/** alsaseq.Constant __doc__ */
+const char Constant__doc__ [] =
+ "Constant() -> Constant object\n"
+ "\n"
+ "Represents one of the many integer constants from the\n"
+ "libasound sequencer API.\n"
+ "\n"
+ "This class serves the following purposes:\n"
+ " a. wrap the SND_SEQ* constants to a python int;\n"
+ " b. provide a string representation of the constant;\n"
+ "\n"
+ "For a), this class is a subclass of the python int. Example:\n"
+ " >>> import alsaseq\n"
+ " >>> print alsaseq.SEQ_EVENT_NOTE\n"
+ " 5\n"
+ " >>> event = alsaseq.SeqEvent(alsaseq.SEQ_EVENT_NOTE)\n"
+ " >>> print event.queue\n"
+ " 253\n"
+ " >>> print event.dest\n"
+ " (0, 0)\n"
+ "\n"
+ "For b), you can get the name of the constant by calling the appropiate\n"
+ "method (__str__ or __repr__). Example:\n"
+ " >>> print str(event.queue), repr(event.queue)\n"
+ " SEQ_QUEUE_DIRECT SEQ_QUEUE_DIRECT(0xfd)\n"
+ " >>> print str(event.dest)\n"
+ " (SEQ_CLIENT_SYSTEM(0x0), SEQ_PORT_SYSTEM_TIMER(0x0))\n"
+ "\n"
+ "This class implements some of the bitwise operations from the\n"
+ "Python number protocol."
+ ;
+
+/** alsaseq.Constant object structure type */
+typedef struct {
+ PyObject_HEAD
+ ;
+
+ /* value of constant */
+ unsigned int value;
+ /* name of constant */
+ const char *name;
+ /* type of constant */
+ int type;
+} ConstantObject;
+
+/** alsaseq.Constant type (initialized later...) */
+static PyTypeObject ConstantType;
+
+/** alsaseq.Constant internal create */
+static PyObject *
+Constant_create(const char *name, long value, int type) {
+ ConstantObject *self = PyObject_New(ConstantObject, &ConstantType);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->value = value;
+ self->name = name;
+ self->type = type;
+
+ return (PyObject *)self;
+}
+
+/** alsaseq.Constant tp_repr */
+static PyObject *
+Constant_repr(ConstantObject *self) {
+ return PyString_FromFormat("%s(0x%x)",
+ self->name,
+ self->value);
+}
+
+/** alsaseq.Constant tp_str */
+static PyObject *
+Constant_str(ConstantObject *self) {
+ return PyString_FromFormat("%s",
+ self->name);
+}
+
+/** alsaseq.Constant Number protocol support (note: not all ops supported) */
+NUMPROTOCOL2(Add, +)
+NUMPROTOCOL2(Subtract, -)
+NUMPROTOCOL2(Xor, ^)
+NUMPROTOCOL2(Or, |)
+NUMPROTOCOL2(And, &)
+NUMPROTOCOL1(Invert, ~)
+
+/** alsaseq.Constant number protocol methods */
+static PyNumberMethods Constant_as_number = {
+ nb_add: (binaryfunc)Constant_Add,
+ nb_subtract: (binaryfunc)Constant_Subtract,
+ nb_xor: (binaryfunc)Constant_Xor,
+ nb_or: (binaryfunc)Constant_Or,
+ nb_and: (binaryfunc)Constant_And,
+ nb_invert: (unaryfunc)Constant_Invert
+};
+
+/** alsaseq.Constant type */
+static PyTypeObject ConstantType = {
+ PyObject_HEAD_INIT(NULL)
+ tp_name: "alsaseq.Constant",
+ tp_base: &PyInt_Type,
+ tp_basicsize: sizeof(ConstantObject),
+ tp_flags:
+ Py_TPFLAGS_HAVE_GETCHARBUFFER
+ | Py_TPFLAGS_HAVE_CLASS
+ | Py_TPFLAGS_CHECKTYPES,
+ tp_doc: Constant__doc__,
+ tp_as_number: &Constant_as_number,
+ tp_free: PyObject_Del,
+ tp_str: (reprfunc)Constant_str,
+ tp_repr: (reprfunc)Constant_repr
+};
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// alsaseq.SequencerError implementation
+//////////////////////////////////////////////////////////////////////////////
+
+/** alsaseq.SequencerError instance (initialized in initalsaseq) */
+static PyObject *SequencerError;
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// alsaseq.SeqEvent implementation
+//////////////////////////////////////////////////////////////////////////////
+
+/** alsaseq.SeqEvent __doc__ */
+const char SeqEvent__doc__ [] =
+ "SeqEvent(type[, timestamp[,timemode]]) -> SeqEvent object\n"
+ "\n"
+ "Creates an Alsa Sequencer Event object. The type must be one of the\n"
+ "alsaseq.SEQ_EVENT_* constants. The timestamp specifies if tick (midi)\n"
+ "or real time is used, must be alsaseq.SEQ_TIME_STAMP_TICK or\n"
+ "alsaseq.SEQ_TIME_STAMP_REAL. The timemode specifies if the time will\n"
+ "be absolute or relative, must be alsaseq.SEQ_TIME_MODE_ABS or\n"
+ "alsaseq.SEQ_TIME_MODE_REL.\n"
+ "\n"
+ "The timestamp and timemode defaults to SEQ_TIME_STAMP_TICK and\n"
+ "SEQ_TIME_MODE_ABS when they are not specified.\n"
+ "\n"
+ "SeqEvent objects are received or sent using a Sequencer object. The\n"
+ "data of the event can be set or retrieved using the set_data() or\n"
+ "get_data() methods; both use a dictionary. The rest of properties of\n"
+ "a SeqEvent can be accesed and changed using the SeqEvent attributes.\n"
+ "\n"
+ "The attributes and defaults values are:\n"
+ "type -- event type.\n"
+ "timestamp -- tick(midi) or real(nanoseconds). Default:
SEQ_TIME_STAMP_TICK.\n"
+ "timemode -- relative or absolute. Default: SEQ_TIME_MODE_ABS.\n"
+ "queue -- queue id. Default: SEQ_QUEUE_DIRECT\n"
+ "time -- time of this event. Default: 0.\n"
+ "source -- source address tuple (client,port). Default: (0, 0).\n"
+ "dest -- dest address tuple (client, port). Default: (0, 0).\n"
+ "\n"
+ "There are dictionaries available as attributes, that contains\n"
+ "alsaseq.SEQ* constants that can be used for each attribute:\n"
+ "_dtype -- event type constants.\n"
+ "_dtimestamp -- event timestamp constants.\n"
+ "_dtimemode -- event timemode constants.\n"
+ "_dqueue -- queue id's.\n"
+ "_dclient -- client address (for source an dest).\n"
+ "_dport -- port address (for source an dest).\n"
+ ;
+
+/** alsaseq.SeqEvent object structure type */
+typedef struct {
+ PyObject_HEAD
+ ;
+
+ /* alsa event */
+ snd_seq_event_t *event;
+
+ /* pointer copied/created from/for variable length events */
+ unsigned char *buff;
+} SeqEventObject;
+
+/** alsaseq.SeqEvent type (initialized later...) */
+static PyTypeObject SeqEventType;
+
+/** internal use: set type and update flags based on event type */
+static int
+_SeqEvent_set_type(SeqEventObject *self,
+ long type) {
+ self->event->type = type;
+
+ /* clean previous buff... */
+ FREECHECKED("buff", self->buff);
+ memset(&(self->event->data), '\0', sizeof(self->event->data));
+
+ /* update flags */
+ if (snd_seq_ev_is_variable_type(self->event)) {
+ snd_seq_ev_set_variable(self->event, 0, NULL);
+ } else if (snd_seq_ev_is_varusr_type(self->event)) {
+ snd_seq_ev_set_varusr(self->event, 0, NULL);
+ } else if (snd_seq_ev_is_fixed_type(self->event)) {
+ snd_seq_ev_set_fixed(self->event);
+ } else {
+ PyErr_SetString(PyExc_ValueError,
+ "Invalid value for type; "
+ "use one of alsaseq.SEQ_EVENT_* constants.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** internal use: set timestamp flag */
+static int
+_SeqEvent_set_timestamp(SeqEventObject *self,
+ long timestamp) {
+ if (timestamp == SND_SEQ_TIME_STAMP_TICK) {
+ self->event->flags &= ~(SND_SEQ_TIME_STAMP_MASK);
+ self->event->flags |= SND_SEQ_TIME_STAMP_TICK;
+ } else if (timestamp == SND_SEQ_TIME_STAMP_REAL) {
+ self->event->flags &= ~(SND_SEQ_TIME_STAMP_MASK);
+ self->event->flags |= SND_SEQ_TIME_STAMP_REAL;
+ } else {
+ PyErr_SetString(PyExc_ValueError,
+ "Invalid value for timestamp; "
+ "use alsaseq.SEQ_TIME_STAMP_TICK or "
+ "alsaseq.SEQ_TIME_STAMP_REAL.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** internal use: set timemode flag */
+static int
+_SeqEvent_set_timemode(SeqEventObject *self,
+ long timemode) {
+ if (timemode == SND_SEQ_TIME_MODE_ABS) {
+ self->event->flags &= ~(SND_SEQ_TIME_MODE_MASK);
+ self->event->flags |= SND_SEQ_TIME_MODE_ABS;
+ } else if (timemode == SND_SEQ_TIME_MODE_REL) {
+ self->event->flags &= ~(SND_SEQ_TIME_MODE_MASK);
+ self->event->flags |= SND_SEQ_TIME_MODE_REL;
+ } else {
+ PyErr_SetString(PyExc_ValueError,
+ "Invalid value for timemode; "
+ "use alsaseq.SEQ_TIME_MODE_ABS or "
+ "alsaseq.SEQ_TIME_MODE_REL.");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/** alsaseq.SeqEvent tp_init */
+static int
+SeqEvent_init(SeqEventObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ int type = 0;
+ int timestamp = SND_SEQ_TIME_STAMP_TICK;
+ int timemode = SND_SEQ_TIME_MODE_ABS;
+ char *kwlist [] = {"type", "timestamp", "timemode", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwlist, &type,
+ ×tamp, &timemode)) {
+ return -1;
+ }
+
+ if (_SeqEvent_set_type(self, type) !=0 ) {
+ return -1;
+ }
+ if (_SeqEvent_set_timestamp(self, timestamp) != 0) {
+ return -1;
+ }
+ if (_SeqEvent_set_timemode(self, timemode) != 0) {
+ return -1;
+ }
+
+ snd_seq_ev_set_direct(self->event);
+ snd_seq_ev_set_subs(self->event);
+
+ return 0;
+}
+
+
+
+/** internal use: create a alsaseq.SeqEvent from a snd_seq_event_t structure */
+static PyObject *
+SeqEvent_create(snd_seq_event_t *event) {
+ SeqEventObject *self = PyObject_New(SeqEventObject, &SeqEventType);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->event = malloc(sizeof(snd_seq_event_t));
+ if (self->event == NULL) {
+ PyObject_Del(self);
+ return PyErr_NoMemory();
+ }
+
+ memcpy(self->event, event, sizeof(snd_seq_event_t));
+ if (snd_seq_ev_is_variable_type(self->event)) {
+ self->buff = malloc(self->event->data.ext.len);
+ memcpy(self->event->data.ext.ptr, self->buff, self->event->data.ext.len);
+ self->event->data.ext.ptr = self->buff;
+ } else {
+ self->buff = NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+/** alsaseq.SeqEvent tp_new */
+static PyObject *
+SeqEvent_new(PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwds) {
+ SeqEventObject *self;
+
+ self = (SeqEventObject *)type->tp_alloc(type, 0);
+
+ self->event = malloc(sizeof(snd_seq_event_t));
+ if (self->event == NULL) {
+ type->tp_free(self);
+ return PyErr_NoMemory();
+ }
+ snd_seq_ev_clear(self->event);
+ self->buff = NULL;
+
+ return (PyObject *) self;
+}
+
+/** alsaseq.SeqEvent tp_dealloc */
+static void
+SeqEvent_dealloc(SeqEventObject *self) {
+ FREECHECKED("event", self->event);
+ FREECHECKED("buff", self->buff);
+
+ self->ob_type->tp_free(self);
+}
+
+/** alsaseq.SeqEvent type attribute: __doc__ */
+const char SeqEvent_type__doc__ [] =
+ "type -> Constant object\n"
+ "\n"
+ "The type of this alsaseq.SeqEvent; Use one of the\n"
+ "alsaseq.SEQ_EVENT_* constants.\n\n"
+ "Note: changing a SeqEvent type will *ERASE* AND *CLEAN* its data!!"
+ ;
+
+/** alsaseq.SeqEvent type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_type(SeqEventObject *self) {
+ TCONSTRETURN(EVENT_TYPE, self->event->type);
+}
+
+/** alsaseq.SeqEvent type attribute: tp_getset setter() */
+static int
+SeqEvent_set_type(SeqEventObject *self,
+ PyObject *val) {
+ SETCHECKPYINT("type", val);
+
+ return _SeqEvent_set_type(self, PyInt_AsLong(val));
+}
+
+/** alsaseq.SeqEvent tag attribute: __doc__ */
+const char SeqEvent_tag__doc__ [] =
+ "tag -> int\n"
+ "\n"
+ "The tag of this alsaseq.SeqEvent (range:0-255)."
+ ;
+
+/** alsaseq.SeqEvent tag attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_tag(SeqEventObject *self) {
+ return PyInt_FromLong(self->event->tag);
+}
+
+/** alsaseq.SeqEvent tag attribute: tp_getset setter() */
+static int
+SeqEvent_set_tag(SeqEventObject *self,
+ PyObject *val) {
+ long tag;
+
+ SETCHECKPYINT("tag", val);
+
+ tag = PyInt_AsLong(val);
+ if (tag < 0 || tag > 255) {
+ PyErr_Format(PyExc_ValueError,
+ "invalid value '%ld'; allowed range: 0 - 255",
+ tag);
+ return -1;
+ }
+ self->event->tag = tag;
+ return 0;
+}
+
+/** alsaseq.seqEvent timestamp attribute: __doc__ */
+const char SeqEvent_timestamp__doc__ [] =
+ "timestamp -> Constant object\n"
+ "\n"
+ "The time stamp flag of this alsaseq.SeqEvent;\n"
+ "use alsaseq.SEQ_TIME_STAMP_TICK or alsaseq.SEQ_TIME_STAMP_REAL."
+ ;
+
+/** alsaseq.SeqEvent timestamp attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_timestamp(SeqEventObject *self) {
+ if (snd_seq_ev_is_tick(self->event)) {
+ TCONSTRETURN(EVENT_TIMESTAMP, SND_SEQ_TIME_STAMP_TICK);
+ } else if (snd_seq_ev_is_real(self->event)) {
+ TCONSTRETURN(EVENT_TIMESTAMP, SND_SEQ_TIME_STAMP_REAL);
+ }
+
+ /* should never get here ... */
+ return NULL;
+}
+
+/** alsaseq.SeqEvent timestamp attribute: tp_getset setter() */
+static int
+SeqEvent_set_timestamp(SeqEventObject *self,
+ PyObject *val) {
+ SETCHECKPYINT("timestamp", val);
+
+ return _SeqEvent_set_timestamp(self, PyInt_AsLong(val));
+}
+
+/** alsaseq.SeqEvent timemode attribute: __doc__ */
+const char SeqEvent_timemode__doc__ [] =
+ "timemode -> Constant object\n"
+ "\n"
+ "The time mode flag of this alsaseq.SeqEvent;\n"
+ "use alsaseq.SEQ_TIME_MODE_ABS or alsaseq.SEQ_TIME_MODE_REL."
+ ;
+
+/** alsaseq.SeqEvent timemode attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_timemode(SeqEventObject *self) {
+ if (snd_seq_ev_is_abstime(self->event)) {
+ TCONSTRETURN(EVENT_TIMEMODE, SND_SEQ_TIME_MODE_ABS);
+ } else if (snd_seq_ev_is_reltime(self->event)) {
+ TCONSTRETURN(EVENT_TIMEMODE, SND_SEQ_TIME_MODE_REL);
+ }
+
+ /* should never get here ... */
+ return NULL;
+}
+
+/** alsaseq.SeqEvent timemode attribute: tp_getset setter() */
+static int
+SeqEvent_set_timemode(SeqEventObject *self,
+ PyObject *val) {
+ SETCHECKPYINT("timemode", val);
+
+ return _SeqEvent_set_timemode(self, PyInt_AsLong(val));
+}
+
+/** alsaseq.SeqEvent queue attribute: __doc__ */
+const char SeqEvent_queue__doc__ [] =
+ "queue -> int\n"
+ "\n"
+ "The send queue id of this alsaseq.SeqEvent."
+ ;
+
+/** alsaseq.SeqEvent queue: tp_getset getter() */
+static PyObject *
+SeqEvent_get_queue(SeqEventObject *self) {
+ TCONSTRETURN(QUEUE, self->event->queue);
+}
+
+/** alsaseq.SeqEvent queue attribute: tp_getset setter() */
+static int
+SeqEvent_set_queue(SeqEventObject *self,
+ PyObject *val) {
+ SETCHECKPYINT("queue", val);
+
+ self->event->queue = PyInt_AsLong(val);
+ return 0;
+}
+
+/** alsaseq.SeqEvent time attribute: __doc__ */
+const char SeqEvent_time__doc__ [] =
+ "time -> int or float\n"
+ "\n"
+ "The send time of this alsaseq.SeqEvent.\n"
+ "If the timestamp of the SeqEvent is SEQ_TIME_STAMP_TICK, an\n"
+ "integer value is used which represents the midi tick time; \n"
+ "if the timestamp is SEQ_TIME_STAMP_REAL, a float value is used\n"
+ "which represents seconds the same way Python time module.\n"
+ ;
+
+/** alsaseq.SeqEvent time attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_time(SeqEventObject *self) {
+ if (snd_seq_ev_is_real(self->event)) {
+ double time = self->event->time.time.tv_sec;
+ time += self->event->time.time.tv_nsec * 0.000001;
+ return PyFloat_FromDouble(time);
+ } else if (snd_seq_ev_is_tick(self->event)) {
+ long tick = self->event->time.tick;
+ return PyInt_FromLong(tick);
+ }
+
+ /* should never get here... */
+ return NULL;
+}
+
+/** alsaseq.SeqEvent time attribute: tp_getset setter() */
+static int
+SeqEvent_set_time(SeqEventObject *self,
+ PyObject *val) {
+ int is_int = PyInt_Check(val);
+ int is_float = PyFloat_Check(val);
+
+ if (!(is_int || is_float)) {
+ PyErr_Format(PyExc_TypeError,
+ "integer or float expected");
+ return -1;
+ }
+
+ if (snd_seq_ev_is_real(self->event)) {
+ if (is_int) {
+ double time = PyInt_AsLong(val);
+ self->event->time.time.tv_sec = time;
+ self->event->time.time.tv_nsec = 0;
+ } else {
+ double time = PyFloat_AsDouble(val);
+ self->event->time.time.tv_sec = (unsigned int)time;
+ time -= self->event->time.time.tv_sec;
+ self->event->time.time.tv_nsec = time * 1000000;
+ }
+ } else if (snd_seq_ev_is_tick(self->event)) {
+ if (is_int) {
+ self->event->time.tick = PyInt_AsLong(val);
+ } else {
+ self->event->time.tick = PyFloat_AsDouble(val);
+ }
+ } else {
+ /* should never get here... */
+ return -1;
+ }
+ return 0;
+}
+
+/** alsaseq.SeqEvent source attribute: __doc __ */
+const char SeqEvent_source__doc__ [] =
+ "source -> tuple (client_id, port_id)\n"
+ "\n"
+ "Tuple representing the send source address of this alsaseq.SeqEvent.\n"
+ "The tuple is (client_id, port_id). If the client or port id are known,\n"
+ "the appropiate constant may be used, otherwise integers are expected."
+ ;
+
+/** alsaseq.SeqEvent source attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_source(SeqEventObject *self) {
+ int source_client = self->event->source.client;
+ int source_port = self->event->source.port;
+ PyObject *client, *port;
+ PyObject *tuple = PyTuple_New(2);
+
+ TCONSTASSIGN(ADDR_CLIENT, source_client, client);
+ TCONSTASSIGN(ADDR_PORT, source_port, port);
+
+ PyTuple_SetItem(tuple, 0, client);
+ PyTuple_SetItem(tuple, 1, port);
+
+ return tuple;
+}
+
+/** alsaseq.SeqEvent source attribute: tp_getset setter() */
+static int
+SeqEvent_set_source(SeqEventObject *self,
+ PyObject *val) {
+ PyObject *client;
+ PyObject *port;
+
+ if (!PyTuple_Check(val) || PyTuple_Size(val) != 2) {
+ PyErr_SetString(PyExc_TypeError, "expected tuple (client,port)");
+ return -1;
+ }
+
+ client = PyTuple_GetItem(val, 0);
+ port = PyTuple_GetItem(val, 1);
+ SETCHECKPYINT("source client", client);
+ SETCHECKPYINT("source port", port);
+
+ self->event->source.client = PyInt_AsLong(client);
+ self->event->source.port = PyInt_AsLong(port);
+
+ return 0;
+}
+
+/** alsaseq.SeqEvent dest attribute: __doc __ */
+const char SeqEvent_dest__doc__ [] =
+ "dest -> tuple (client_id, port_id)\n"
+ "\n"
+ "Tuple representing the destination address of this alsaseq.SeqEvent.\n"
+ "The tuple is (client_id, port_id). If the client or port id are known,\n"
+ "the appropiate constant may be used, otherwise integers are expected."
+ ;
+
+/** alsaseq.SeqEvent dest attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_get_dest(SeqEventObject *self) {
+ int dest_client = self->event->dest.client;
+ int dest_port = self->event->dest.port;
+ PyObject *client, *port;
+ PyObject *tuple = PyTuple_New(2);
+
+ TCONSTASSIGN(ADDR_CLIENT, dest_client, client);
+ TCONSTASSIGN(ADDR_PORT, dest_port, port);
+
+ PyTuple_SetItem(tuple, 0, client);
+ PyTuple_SetItem(tuple, 1, port);
+
+ return tuple;
+}
+
+/** alsaseq.SeqEvent dest attribute: tp_getset setter() */
+static int
+SeqEvent_set_dest(SeqEventObject *self,
+ PyObject *val) {
+ PyObject *client;
+ PyObject *port;
+
+ if (!PyTuple_Check(val) || PyTuple_Size(val) != 2) {
+ PyErr_SetString(PyExc_TypeError, "expected tuple (client,port)");
+ return -1;
+ }
+
+ client = PyTuple_GetItem(val, 0);
+ port = PyTuple_GetItem(val, 1);
+ SETCHECKPYINT("dest client", client);
+ SETCHECKPYINT("dest port", port);
+
+ self->event->dest.client = PyInt_AsLong(client);
+ self->event->dest.port = PyInt_AsLong(port);
+
+ return 0;
+}
+
+/** alsaseq.SeqEvent is_result_type attribute: __doc__ */
+const char SeqEvent_is_result_type__doc__ [] =
+ "is_result_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type result (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+
+/** alsaseq.SeqEvent is_result_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_result_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_result_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_note_type attribute: __doc__ */
+const char SeqEvent_is_note_type__doc__ [] =
+ "is_note_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type note (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_note_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_note_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_note_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_control_type attribute: __doc__ */
+const char SeqEvent_is_control_type__doc__ [] =
+ "is_control_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type control (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_note_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_control_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_control_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_channel_type attribute: __doc__ */
+const char SeqEvent_is_channel_type__doc__ [] =
+ "is_channel_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type channel (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_channel_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_channel_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_channel_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_queue_type attribute: __doc__ */
+const char SeqEvent_is_queue_type__doc__ [] =
+ "is_queue_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is a queue event (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_queue_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_queue_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_queue_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_message_type attribute: __doc__ */
+const char SeqEvent_is_message_type__doc__ [] =
+ "is_message_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type message (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_message_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_message_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_message_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_subscribe_type attribute: __doc__ */
+const char SeqEvent_is_subscribe_type__doc__ [] =
+ "is_subscribe_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type subscribe (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_subscribe_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_subscribe_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_subscribe_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_sample_type attribute: __doc__ */
+const char SeqEvent_is_sample_type__doc__ [] =
+ "is_sample_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type sample (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_sample_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_sample_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_sample_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_user_type attribute: __doc__ */
+const char SeqEvent_is_user_type__doc__ [] =
+ "is_user_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type user (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_user_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_user_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_user_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_instr_type attribute: __doc__ */
+const char SeqEvent_is_instr_type__doc__ [] =
+ "is_instr_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type instr (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_instr_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_instr_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_instr_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_fixed_type attribute: __doc__ */
+const char SeqEvent_is_fixed_type__doc__ [] =
+ "is_fixed_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type fixed (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_fixed_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_fixed_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_fixed_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_variable_type attribute: __doc__ */
+const char SeqEvent_is_variable_type__doc__ [] =
+ "is_variable_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type variable (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_variable_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_variable_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_variable_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_varusr_type attribute: __doc__ */
+const char SeqEvent_is_varusr_type__doc__ [] =
+ "is_message_type -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is of type varusr (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_varusr_type attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_varusr_type(SeqEventObject *self) {
+ if (snd_seq_ev_is_varusr_type(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_reserved attribute: __doc__ */
+const char SeqEvent_is_reserved__doc__ [] =
+ "is_reserved -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is reserved (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_reserved attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_reserved(SeqEventObject *self) {
+ if (snd_seq_ev_is_reserved(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_prior attribute: __doc__ */
+const char SeqEvent_is_prior__doc__ [] =
+ "is_prior -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is prior (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_prior attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_prior(SeqEventObject *self) {
+ if (snd_seq_ev_is_prior(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_fixed attribute: __doc__ */
+const char SeqEvent_is_fixed__doc__ [] =
+ "is_fixed -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is fixed (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_fixed attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_fixed(SeqEventObject *self) {
+ if (snd_seq_ev_is_fixed(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_variable attribute: __doc__ */
+const char SeqEvent_is_variable__doc__ [] =
+ "is_variable -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is variable (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_variable attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_variable(SeqEventObject *self) {
+ if (snd_seq_ev_is_variable(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_varusr attribute: __doc__ */
+const char SeqEvent_is_varusr__doc__ [] =
+ "is_varusr -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is varusr (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_varusr attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_varusr(SeqEventObject *self) {
+ if (snd_seq_ev_is_varusr(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_tick attribute: __doc__ */
+const char SeqEvent_is_tick__doc__ [] =
+ "is_tick -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is tick timed (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_tick attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_tick(SeqEventObject *self) {
+ if (snd_seq_ev_is_tick(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_real attribute: __doc__ */
+const char SeqEvent_is_real__doc__ [] =
+ "is_real -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is real timed (True) or not (False).\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_real attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_real(SeqEventObject *self) {
+ if (snd_seq_ev_is_real(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_abstime attribute: __doc__ */
+const char SeqEvent_is_abstime__doc__ [] =
+ "is_abstime -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is abstime timed (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_abstime attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_abstime(SeqEventObject *self) {
+ if (snd_seq_ev_is_abstime(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_reltime attribute: __doc__ */
+const char SeqEvent_is_reltime__doc__ [] =
+ "is_reltime -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is a reltime timed (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_reltime attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_reltime(SeqEventObject *self) {
+ if (snd_seq_ev_is_reltime(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent is_direct attribute: __doc__ */
+const char SeqEvent_is_direct__doc__ [] =
+ "is_direct -> boolean\n"
+ "\n"
+ "Indicates if this alsaseq.SeqEvent is sent directly (True) or not\n"
+ "(False). Note: read-only attribute."
+ ;
+
+/** alsaseq.SeqEvent is_direct attribute: tp_getset getter() */
+static PyObject *
+SeqEvent_is_direct(SeqEventObject *self) {
+ if (snd_seq_ev_is_direct(self->event)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+/** alsaseq.SeqEvent _dtype attribute: __doc__ */
+const char SeqEvent__dtype__doc__ [] =
+ "_dtype -> dictionary\n"
+ "\n"
+ "Dictionary will available event type constants."
+ ;
+
+/** alsaseq.Seqevent _dtype attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dtype(SeqEventObject *self) {
+ Py_INCREF(_dictPYALSASEQ_CONST_EVENT_TYPE);
+ return _dictPYALSASEQ_CONST_EVENT_TYPE;
+}
+
+/** alsaseq.SeqEvent _dtimestamp attribute: __doc__ */
+const char SeqEvent__dtimestamp__doc__ [] =
+ "_dtimestamp -> dictionary\n"
+ "\n"
+ "Dictionary will available event timestamp constants."
+ ;
+
+/** alsaseq.Seqevent _dtimestamp attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dtimestamp(SeqEventObject *self) {
+ Py_INCREF(_dictPYALSASEQ_CONST_EVENT_TIMESTAMP);
+ return _dictPYALSASEQ_CONST_EVENT_TIMESTAMP;
+}
+
+/** alsaseq.SeqEvent _dtimemode attribute: __doc__ */
+const char SeqEvent__dtimemode__doc__ [] =
+ "_dtimemode -> dictionary\n"
+ "\n"
+ "Dictionary of available event timemode constants."
+ ;
+
+/** alsaseq.Seqevent _dtimemode attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dtimemode(SeqEventObject *self) {
+ Py_INCREF(_dictPYALSASEQ_CONST_EVENT_TIMEMODE);
+ return _dictPYALSASEQ_CONST_EVENT_TIMEMODE;
+}
+
+/** alsaseq.SeqEvent _dqueue attribute: __doc__ */
+const char SeqEvent__dqueue__doc__ [] =
+ "_dqueue -> dictionary\n"
+ "\n"
+ "Dictionary of known queue id constants."
+ ;
+
+/** alsaseq.Seqevent _dqueue attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dqueue(SeqEventObject *self) {
+ Py_INCREF(_dictPYALSASEQ_CONST_QUEUE);
+ return _dictPYALSASEQ_CONST_QUEUE;
+}
+
+/** alsaseq.SeqEvent _dclient attribute: __doc__ */
+const char SeqEvent__dclient__doc__ [] =
+ "_dclient -> dictionary\n"
+ "\n"
+ "Dictionary of known client addresses constants."
+ ;
+
+/** alsaseq.Seqevent _dclient attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dclient(SeqEventObject *self) {
+ Py_INCREF(TDICT(ADDR_CLIENT));
+ return TDICT(ADDR_CLIENT);
+}
+
+/** alsaseq.SeqEvent _dport attribute: __doc__ */
+const char SeqEvent__dport__doc__ [] =
+ "_dport -> dictionary\n"
+ "\n"
+ "Dictionary of known port addresses constants."
+ ;
+
+/** alsaseq.Seqevent _dport attribute: tp_getset getter() */
+static PyObject *
+SeqEvent__dport(SeqEventObject *self) {
+ Py_INCREF(TDICT(ADDR_PORT));
+ return TDICT(ADDR_PORT);
+}
+
+
+/** alsaseq.SeqEvent tp_getset list */
+static PyGetSetDef SeqEvent_getset[] = {
+ {"type",
+ (getter) SeqEvent_get_type,
+ (setter) SeqEvent_set_type,
+ (char *) SeqEvent_type__doc__,
+ NULL},
+ {"timestamp",
+ (getter) SeqEvent_get_timestamp,
+ (setter) SeqEvent_set_timestamp,
+ (char *) SeqEvent_timestamp__doc__,
+ NULL},
+ {"timemode",
+ (getter) SeqEvent_get_timemode,
+ (setter) SeqEvent_set_timemode,
+ (char *) SeqEvent_timemode__doc__,
+ NULL},
+ {"tag",
+ (getter) SeqEvent_get_tag,
+ (setter) SeqEvent_set_tag,
+ (char *) SeqEvent_tag__doc__,
+ NULL},
+ {"queue",
+ (getter) SeqEvent_get_queue,
+ (setter) SeqEvent_set_queue,
+ (char *) SeqEvent_queue__doc__,
+ NULL},
+ {"time",
+ (getter) SeqEvent_get_time,
+ (setter) SeqEvent_set_time,
+ (char *) SeqEvent_time__doc__,
+ NULL},
+ {"source",
+ (getter) SeqEvent_get_source,
+ (setter) SeqEvent_set_source,
+ (char *) SeqEvent_source__doc__,
+ NULL},
+ {"dest",
+ (getter) SeqEvent_get_dest,
+ (setter) SeqEvent_set_dest,
+ (char *) SeqEvent_dest__doc__,
+ NULL},
+ {"is_result_type",
+ (getter) SeqEvent_is_result_type,
+ NULL,
+ (char *) SeqEvent_is_result_type__doc__,
+ NULL},
+ {"is_note_type",
+ (getter) SeqEvent_is_note_type,
+ NULL,
+ (char *) SeqEvent_is_note_type__doc__,
+ NULL},
+ {"is_control_type",
+ (getter) SeqEvent_is_control_type,
+ NULL,
+ (char *) SeqEvent_is_control_type__doc__,
+ NULL},
+ {"is_channel_type",
+ (getter) SeqEvent_is_channel_type,
+ NULL,
+ (char *) SeqEvent_is_channel_type__doc__,
+ NULL},
+ {"is_queue_type",
+ (getter) SeqEvent_is_queue_type,
+ NULL,
+ (char *) SeqEvent_is_queue_type__doc__,
+ NULL},
+ {"is_message_type",
+ (getter) SeqEvent_is_message_type,
+ NULL,
+ (char *) SeqEvent_is_message_type__doc__,
+ NULL},
+ {"is_subscribe_type",
+ (getter) SeqEvent_is_subscribe_type,
+ NULL,
+ (char *) SeqEvent_is_subscribe_type__doc__,
+ NULL},
+ {"is_sample_type",
+ (getter) SeqEvent_is_sample_type,
+ NULL,
+ (char *) SeqEvent_is_sample_type__doc__,
+ NULL},
+ {"is_user_type",
+ (getter) SeqEvent_is_user_type,
+ NULL,
+ (char *) SeqEvent_is_user_type__doc__,
+ NULL},
+ {"is_instr_type",
+ (getter) SeqEvent_is_instr_type,
+ NULL,
+ (char *) SeqEvent_is_instr_type__doc__,
+ NULL},
+ {"is_fixed_type",
+ (getter) SeqEvent_is_fixed_type,
+ NULL,
+ (char *) SeqEvent_is_fixed_type__doc__,
+ NULL},
+ {"is_variable_type",
+ (getter) SeqEvent_is_variable_type,
+ NULL,
+ (char *) SeqEvent_is_variable_type__doc__,
+ NULL},
+ {"is_varusr_type",
+ (getter) SeqEvent_is_varusr_type,
+ NULL,
+ (char *) SeqEvent_is_varusr_type__doc__,
+ NULL},
+ {"is_reserved",
+ (getter) SeqEvent_is_reserved,
+ NULL,
+ (char *) SeqEvent_is_reserved__doc__,
+ NULL},
+ {"is_prior",
+ (getter) SeqEvent_is_prior,
+ NULL,
+ (char *) SeqEvent_is_prior__doc__,
+ NULL},
+ {"is_fixed",
+ (getter) SeqEvent_is_fixed,
+ NULL,
+ (char *) SeqEvent_is_fixed__doc__,
+ NULL},
+ {"is_variable",
+ (getter) SeqEvent_is_variable,
+ NULL,
+ (char *) SeqEvent_is_variable__doc__,
+ NULL},
+ {"is_varusr",
+ (getter) SeqEvent_is_varusr,
+ NULL,
+ (char *) SeqEvent_is_varusr__doc__,
+ NULL},
+ {"is_tick",
+ (getter) SeqEvent_is_tick,
+ NULL,
+ (char *) SeqEvent_is_tick__doc__,
+ NULL},
+ {"is_real",
+ (getter) SeqEvent_is_real,
+ NULL,
+ (char *) SeqEvent_is_real__doc__,
+ NULL},
+ {"is_abstime",
+ (getter) SeqEvent_is_abstime,
+ NULL,
+ (char *) SeqEvent_is_abstime__doc__,
+ NULL},
+ {"is_reltime",
+ (getter) SeqEvent_is_reltime,
+ NULL,
+ (char *) SeqEvent_is_reltime__doc__,
+ NULL},
+ {"is_direct",
+ (getter) SeqEvent_is_direct,
+ NULL,
+ (char *) SeqEvent_is_direct__doc__,
+ NULL},
+ {"_dtype",
+ (getter) SeqEvent__dtype,
+ NULL,
+ (char *) SeqEvent__dtype__doc__,
+ NULL},
+ {"_dtimestamp",
+ (getter) SeqEvent__dtimestamp,
+ NULL,
+ (char *) SeqEvent__dtimestamp__doc__,
+ NULL},
+ {"_dtimemode",
+ (getter) SeqEvent__dtimemode,
+ NULL,
+ (char *) SeqEvent__dtimemode__doc__,
+ NULL},
+ {"_dqueue",
+ (getter) SeqEvent__dqueue,
+ NULL,
+ (char *) SeqEvent__dqueue__doc__,
+ NULL},
+ {"_dclient",
+ (getter) SeqEvent__dclient,
+ NULL,
+ (char *) SeqEvent__dclient__doc__,
+ NULL},
+ {"_dport",
+ (getter) SeqEvent__dport,
+ NULL,
+ (char *) SeqEvent__dport__doc__,
+ NULL},
+ {NULL}
+};
+
+/** alsaseq.SeqEvent tp_repr */
+static PyObject *
+SeqEvent_repr(SeqEventObject *self) {
+ PyObject *key = PyInt_FromLong(self->event->type);
+ ConstantObject *constObject = (ConstantObject *)
+ PyDict_GetItem(TDICT(EVENT_TYPE), key);
+ const char *typestr = "UNKNOWN";
+ const char *timemode = "";
+ unsigned int dtime = 0;
+ unsigned int ntime = 0;
+ Py_DECREF(key);
+ if (constObject != NULL) {
+ typestr = constObject->name;
+ }
+
+ if (snd_seq_ev_is_real(self->event)) {
+ timemode = "real";
+ dtime = self->event->time.time.tv_sec;
+ ntime += self->event->time.time.tv_nsec * 0.000001;
+ } else {
+ timemode = "tick";
+ dtime = self->event->time.tick;
+ }
+
+ return PyString_FromFormat("<alsaseq.SeqEvent type=%s(%d) flags=%d tag=%d "
+ "queue=%d time=%s(%u.%u) from=%d:%d to=%d:%d "
+ "at 0x%p>",
+ typestr,
+ self->event->type, self->event->flags,
+ self->event->tag, self->event->queue,
+ timemode, dtime, ntime,
+ (self->event->source).client,
+ (self->event->source).port,
+ (self->event->dest).client,
+ (self->event->dest).port, self);
+}
+
+/** alsaseq.SeqEvent get_data() method: __doc__ */
+const char SeqEvent_get_data__doc__ [] =
+ "get_data() -> dict\n"
+ "\n"
+ "Returns a new dictionary with the data of this SeqEvent.\n"
+ "Changes to the returned dictionary will not change this SeqEvent data,\n"
+ "for changing an event data use the set_data() method.\n"
+ "\n"
+ "The dictionary items are key: value; where key is the name of the\n"
+ "data structure from alsa API and value is an integer or a list of them.\n"
+ "\n"
+ "The following name of structures are available:\n"
+ " 'note.channel' -> int\n"
+ " 'note.note' -> int\n"
+ " 'note.velocity' -> int\n"
+ " 'note.off_velocity' -> int\n"
+ " 'note.duration' -> int\n"
+ " 'control.channel' -> int\n"
+ " 'control.value' -> int\n"
+ " 'control.param' -> int\n"
+ " 'queue.queue' -> int\n"
+ " 'addr.client' -> int\n"
+ " 'addr.port' -> int\n"
+ " 'connect.sender.client' -> int\n"
+ " 'connect.sender.port' -> int\n"
+ " 'connect.dest.client' -> int\n"
+ " 'connect.dest.port' -> int\n"
+ " 'result.event' -> int\n"
+ " 'result.result' -> int\n"
+ " 'ext' -> list of int with sysex or variable data\n"
+ "\n"
+ "The exact items returned dependens on the event type of this SeqEvent.\n"
+ "For a control event, only 'control.*' may be returned; for a sysex \n"
+ "event, only 'ext' may be returned; for a note event, only 'note.*' may \n"
+ "be returned and so on."
+ ;
+
+/** alsaseq.SeqEvent get_data() method */
+static PyObject *
+SeqEvent_get_data(SeqEventObject *self,
+ PyObject *args) {
+ PyObject *dict = PyDict_New();
+ snd_seq_event_t *event = self->event;
+
+ switch (event->type) {
+ case SND_SEQ_EVENT_SYSTEM:
+ case SND_SEQ_EVENT_RESULT:
+ SETDICT_RESU2;
+ break;
+
+ case SND_SEQ_EVENT_NOTE:
+ SETDICT_NOTE5;
+ break;
+
+ case SND_SEQ_EVENT_NOTEON:
+ case SND_SEQ_EVENT_NOTEOFF:
+ case SND_SEQ_EVENT_KEYPRESS:
+ SETDICT_NOTE3;
+ break;
+
+ case SND_SEQ_EVENT_CONTROLLER:
+ SETDICT_CTRL3;
+ break;
+
+ case SND_SEQ_EVENT_PGMCHANGE:
+ case SND_SEQ_EVENT_CHANPRESS:
+ case SND_SEQ_EVENT_PITCHBEND:
+ SETDICT_CTRL2;
+ break;
+
+ case SND_SEQ_EVENT_CONTROL14:
+ case SND_SEQ_EVENT_NONREGPARAM:
+ case SND_SEQ_EVENT_REGPARAM:
+ SETDICT_CTRL3;
+ break;
+
+ case SND_SEQ_EVENT_SONGPOS:
+ case SND_SEQ_EVENT_SONGSEL:
+ case SND_SEQ_EVENT_QFRAME:
+ case SND_SEQ_EVENT_TIMESIGN:
+ case SND_SEQ_EVENT_KEYSIGN:
+ SETDICT_CTRL1;
+ break;
+
+ case SND_SEQ_EVENT_START:
+ case SND_SEQ_EVENT_CONTINUE:
+ case SND_SEQ_EVENT_STOP:
+ case SND_SEQ_EVENT_SETPOS_TICK:
+ case SND_SEQ_EVENT_TEMPO:
+ SETDICT_QUEU1;
+ break;
+
+ case SND_SEQ_EVENT_CLOCK:
+ case SND_SEQ_EVENT_TICK:
+ break;
+
+ case SND_SEQ_EVENT_QUEUE_SKEW:
+ SETDICT_QUEU1;
+ break;
+
+ case SND_SEQ_EVENT_TUNE_REQUEST:
+ case SND_SEQ_EVENT_RESET:
+ case SND_SEQ_EVENT_SENSING:
+ break;
+
+ case SND_SEQ_EVENT_CLIENT_START:
+ case SND_SEQ_EVENT_CLIENT_EXIT:
+ case SND_SEQ_EVENT_CLIENT_CHANGE:
+ SETDICT_ADDR1;
+ break;
+
+ case SND_SEQ_EVENT_PORT_START:
+ case SND_SEQ_EVENT_PORT_EXIT:
+ case SND_SEQ_EVENT_PORT_CHANGE:
+ SETDICT_ADDR2;
+ break;
+
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+ SETDICT_CONN4;
+ break;
+
+ case SND_SEQ_EVENT_SYSEX:
+ SETDICT_EXT;
+ break;
+ }
+
+ return dict;
+}
+
+/** alsaseq.SeqEvent set_data() method: __doc__ */
+const char SeqEvent_set_data__doc__ [] =
+ "set_data(dict)"
+ "\n"
+ "Changes the data of this SeqEvent, updating internal data structure \n"
+ "from the given dictionary.\n"
+ "\n"
+ "The dictionary items should be the same as described in the get_data() \n"
+ "method and be the appropiate for this SeqEvent type.\n"
+ "\n"
+ "This method does not check if a given structure correspond to is valid \n"
+ "for this SeqEvent type; so setting the 'control.param' or the 'ext' \n"
+ "structures for a NOTE SeqEvent may change another data structure \n"
+ "or will simple have no effect once sent."
+ ;
+
+/** alsaseq.SeqEvent set_data() method */
+static PyObject *
+SeqEvent_set_data(SeqEventObject *self,
+ PyObject *args) {
+ PyObject *dict = NULL;
+ snd_seq_event_t *event = self->event;
+
+ if (!PyArg_ParseTuple(args, "O",
+ &dict)) {
+ return NULL;
+ }
+
+ if (!PyDict_Check(dict)) {
+ PyErr_SetString(PyExc_TypeError, "must be a dictionary");
+ return NULL;
+ }
+
+ GETDICTINT("note.channel", event->data.note.channel);
+ GETDICTINT("note.note", event->data.note.note);
+ GETDICTINT("note.velocity", event->data.note.velocity);
+ GETDICTINT("note.off_velocity", event->data.note.off_velocity);
+ GETDICTINT("note.duration", event->data.note.duration);
+
+ GETDICTINT("control.channel", event->data.control.channel);
+ GETDICTINT("control.param", event->data.control.param);
+ GETDICTINT("control.value", event->data.control.value);
+
+ GETDICTEXT("ext");
+
+ GETDICTINT("queue.queue", event->data.queue.queue);
+ GETDICTINT("queue.param.value", event->data.queue.param.value);
+
+ GETDICTINT("addr.client", event->data.addr.client);
+ GETDICTINT("addr.port", event->data.addr.port);
+
+ GETDICTINT("connect.sender.client", event->data.connect.sender.client);
+ GETDICTINT("connect.sender.port", event->data.connect.sender.port);
+ GETDICTINT("connect.dest.client", event->data.connect.dest.client);
+ GETDICTINT("connect.dest.port", event->data.connect.dest.port);
+
+ GETDICTINT("result.event", event->data.result.event);
+ GETDICTINT("result.result", event->data.result.result);
+
+ Py_RETURN_NONE;
+}
+
+
+/** alsaseq.SeqEvent tp_methods */
+static PyMethodDef SeqEvent_methods[] = {
+ {"get_data",
+ (PyCFunction) SeqEvent_get_data,
+ METH_VARARGS,
+ SeqEvent_get_data__doc__},
+ {"set_data",
+ (PyCFunction) SeqEvent_set_data,
+ METH_VARARGS,
+ SeqEvent_set_data__doc__},
+ {NULL}
+};
+
+/** alsaseq.SeEvent type */
+static PyTypeObject SeqEventType = {
+ PyObject_HEAD_INIT(NULL)
+ tp_name: "alsaseq.SeqEvent",
+ tp_basicsize: sizeof(SeqEventObject),
+ tp_dealloc: (destructor) SeqEvent_dealloc,
+ tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ tp_doc: SeqEvent__doc__,
+ tp_init: (initproc)SeqEvent_init,
+ tp_new : SeqEvent_new,
+ tp_alloc: PyType_GenericAlloc,
+ tp_free: PyObject_Del,
+ tp_methods: SeqEvent_methods,
+ tp_getset: SeqEvent_getset,
+ tp_repr: (reprfunc)SeqEvent_repr,
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// alsaseq.Sequencer implementation
+//////////////////////////////////////////////////////////////////////////////
+
+/** alsaseq.Sequencer __doc__ */
+const char Sequencer__doc__[] =
+ "Sequencer([name, clientname, streams, mode, maxreceiveevents]) "
+ "-> Sequencer object\n"
+ "\n"
+ "Creates and opens an ALSA sequencer. The features of the Sequencer are:\n"
+ "- send/receive events (as SeqEvent objects)\n"
+ "- create ports\n"
+ "- list all ALSA clients and their port connections\n"
+ "- connect/disconnect arbitrary ports\n"
+ "- create and control queues\n"
+ "- get info about a port or a client\n"
+ "\n"
+ "The name must correspond to the special ALSA name (for example: 'hw'); \n"
+ "if not specified, 'default' is used. The clientname is the name of this \n"
+ "client; if not specified, 'pyalsa-PID' is used.\n"
+ "\n"
+ "The streams specifies if you want to receive, send or both; use \n"
+ "SEQ_OPEN_INPUT, SEQ_OPEN_OUTPUT or SEQ_OPEN_DUPLEX. If not specified, \n"
+ "SEQ_OPEN_DUPLEX is used."
+ "\n"
+ "The mode specifies if this client should block or not, use SEQ_BLOCK or \n"
+ "SEQ_NONBLOCK. If not specified, SEQ_NONBLOCK is used."
+ "\n"
+ "The maxreceiveevents is a number that represents how many SeqEvent \n"
+ "objects are returned by the receive() method. If not specified, the \n"
+ "default is 4. \n"
+ "\n"
+ "There is no method for closing the sequencer, it will remain open as \n"
+ "long as the Sequencer object exists. For closing the sequencer you \n"
+ "must explicitly del() the returned object."
+ ;
+
+/** alsaseq.Sequencer object structure type */
+typedef struct {
+ PyObject_HEAD
+
+ /* streams */
+ int streams;
+ /* mode */
+ int mode;
+
+ /* alsa handler */
+ snd_seq_t *handle;
+ /* max fd's */
+ int receive_max;
+ /* receive poll fd's */
+ struct pollfd *receive_fds;
+ /* max events for returning in receive_events() */
+ int receive_max_events;
+ /* remaining bytes from input */
+ int receive_bytes;
+} SequencerObject;
+
+/** alsaseq.Sequencer type (initialized later...) */
+static PyTypeObject SequencerType;
+
+/** alsaseq.Sequencer: tp_init */
+static int
+Sequencer_init(SequencerObject *self,
+ PyObject *args, PyObject *kwds) {
+ int ret;
+ /* defaults */
+ char *name = "default";
+ char *clientname = NULL;
+ char tmpclientname[1024];
+
+ self->streams = SND_SEQ_OPEN_DUPLEX;
+ self->mode = SND_SEQ_NONBLOCK;
+ int maxreceiveevents = 4;
+
+ char *kwlist[] = { "name", "clientname", "streams", "mode",
+ "maxreceiveevents", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssiii", kwlist, &name,
+ &clientname, &self->streams,
+ &self->mode, &maxreceiveevents)) {
+ return -1;
+ }
+
+ if (clientname == NULL) {
+ tmpclientname[0] = 0;
+ sprintf(tmpclientname, "pyalsa-%d", getpid());
+ clientname = tmpclientname;
+ }
+
+ self->receive_fds = NULL;
+ self->receive_max = 0;
+ self->receive_bytes = 0;
+ self->receive_max_events = maxreceiveevents;
+
+
+ ret = snd_seq_open(&(self->handle), name, self->streams,
+ self->mode);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to create sequencer");
+ return -1;
+ }
+ ret = snd_seq_set_client_name(self->handle, clientname);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to set client name");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** alsaseq.Sequencer: tp_dealloc */
+static void
+Sequencer_dealloc(SequencerObject *self) {
+ FREECHECKED("receive_fds", self->receive_fds);
+
+ if (self->handle) {
+ snd_seq_close(self->handle);
+ self->handle = NULL;
+ }
+
+ self->ob_type->tp_free(self);
+}
+
+/** alsaseq.Sequencer name attribute: __doc__ */
+const char Sequencer_name__doc__ [] =
+ "name -> string\n"
+ "\n"
+ "The alsa device name of this alsaseq.Sequencer.\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.Sequencer name attribute: tp_getset getter() */
+static PyObject *
+Sequencer_get_name(SequencerObject *self) {
+ return PyString_FromString(snd_seq_name(self->handle));
+}
+
+/** alsaseq.Sequencer clientname attribute: __doc__ */
+const char Sequencer_clientname__doc__ [] =
+ "clientname -> string\n"
+ "\n"
+ "The client name of this alsaseq.Sequencer\n"
+ ;
+
+/** alsaseq.Sequencer clientname attribute: tp_getset getter() */
+static PyObject *
+Sequencer_get_clientname(SequencerObject *self) {
+ snd_seq_client_info_t *cinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_get_client_info(self->handle, cinfo);
+
+ return PyString_FromString(snd_seq_client_info_get_name(cinfo));
+}
+
+/** alsaseq.Sequencer clientname attribute: tp_getset setter() */
+static int
+Sequencer_set_clientname(SequencerObject *self,
+ PyObject *val) {
+ char *buff;
+
+ SETCHECKPYSTR("clientname", val);
+
+ buff = PyString_AsString(val);
+
+ snd_seq_set_client_name(self->handle, PyString_AsString(val));
+
+ return 0;
+}
+
+/** alsaseq.Sequencer streams attribute: __doc__ */
+const char Sequencer_streams__doc__ [] =
+ "streams -> Constant object\n"
+ "\n"
+ "The streams of this alsaseq.Sequencer. Posible values:\n"
+ "alsaseq.SEQ_OPEN_OUTPUT, alsaseq.SEQ_OPEN_INPUT, \n"
+ "alsaseq.SEQ_OPEN_DUPLEX.\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.Sequencer streams attribute: tp_getset getter() */
+static PyObject *
+Sequencer_get_streams(SequencerObject *self) {
+ TCONSTRETURN(STREAMS, self->streams);
+}
+
+/** alsaseq.Sequencer mode attribute: __doc__ */
+const char Sequencer_mode__doc__ [] =
+ "mode -> Constant object\n"
+ "\n"
+ "The blocking mode of this alsaseq.Sequencer. Use\n"
+ "alsaseq.SEQ_BLOCK, alsaseq.SEQ_NONBLOCK."
+ ;
+
+/** alsaseq.Sequencer mode attribute: tp_getset getter() */
+static PyObject *Sequencer_get_mode(SequencerObject *self) {
+ TCONSTRETURN(MODE, self->mode);
+}
+
+/** alsaseq.Sequencer mode attribute: tp_getset setter() */
+static int
+Sequencer_set_mode(SequencerObject *self,
+ PyObject *val) {
+ int ret, mode;
+
+ SETCHECKPYINT("mode", val);
+
+ mode = (int) PyInt_AsLong(val);
+
+ if (mode != 0 && mode != SND_SEQ_NONBLOCK) {
+ PyErr_SetString(PyExc_ValueError, "Invalid value for mode.");
+ return -1;
+ }
+
+ ret = snd_seq_nonblock(self->handle, mode);
+ if (ret == 0) {
+ self->mode = mode;
+ } else {
+ RAISESND(ret, "Failed to set mode");
+ return -1;
+ }
+ return 0;
+}
+
+/** alsaseq.Sequencer client_id attribute: __doc__ */
+const char Sequencer_client_id__doc__ [] =
+ "client_id -> int\n"
+ "\n"
+ "The client id of this alsaseq.Sequencer.\n"
+ "Note: read-only attribute."
+ ;
+
+/** alsaseq.Sequencer client_id attribute: tp_getset getter() */
+static PyObject *
+Sequencer_get_client_id(SequencerObject *self) {
+ snd_seq_client_info_t *cinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_get_client_info(self->handle, cinfo);
+ return PyInt_FromLong(snd_seq_client_info_get_client(cinfo));
+}
+
+/** alsaseq.Sequencer: tp_getset list*/
+static PyGetSetDef Sequencer_getset[] = {
+ {"name",
+ (getter) Sequencer_get_name,
+ NULL,
+ (char *) Sequencer_name__doc__,
+ NULL},
+ {"clientname",
+ (getter) Sequencer_get_clientname,
+ (setter) Sequencer_set_clientname,
+ (char *) Sequencer_clientname__doc__,
+ NULL},
+ {"streams",
+ (getter) Sequencer_get_streams,
+ NULL,
+ (char *) Sequencer_streams__doc__,
+ NULL},
+ {"mode",
+ (getter) Sequencer_get_mode,
+ (setter) Sequencer_set_mode,
+ (char *) Sequencer_mode__doc__,
+ NULL},
+ {"client_id",
+ (getter) Sequencer_get_client_id,
+ NULL,
+ (char *) Sequencer_client_id__doc__,
+ NULL},
+ {NULL}
+};
+
+/** alsaseq.Sequencer: tp_repr */
+static PyObject *
+Sequencer_repr(SequencerObject *self) {
+ snd_seq_client_info_t *cinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_get_client_info(self->handle, cinfo);
+
+ return PyString_FromFormat("<alsaseq.Sequencer name=%s client_id=%d "
+ "clientname=%s streams=%d mode=%d at 0x%p>",
+ snd_seq_name(self->handle),
+ snd_seq_client_info_get_client(cinfo),
+ snd_seq_client_info_get_name(cinfo),
+ self->streams,
+ self->mode,
+ self
+ );
+}
+
+/** alsaseq.Sequencer create_simple_port() method: __doc__ */
+const char Sequencer_create_simple_port__doc__ [] =
+ "create_simple_port(name, type, caps=0) -> int"
+ "\n"
+ "Creates a port for receiving or sending events.\n"
+ "\n"
+ "Parameters:\n"
+ " name -- name of the port\n"
+ " type -- type of port (use one of the alsaseq.SEQ_PORT_TYPE_*\n"
+ " constants)\n"
+ " caps -- capabilites of the port (use bitwise alsaseq.SEQ_PORT_CAP_*\n"
+ " constants). Default=0\n"
+ "Returns:\n"
+ " the port id.\n"
+ "Raises:\n"
+ " TypeError: if an invalid type was used in a parameter\n"
+ " ValueError: if an invalid value was used in a parameter\n"
+ " SequencerError: if ALSA can't create the port"
+ ;
+
+
+/** alsaseq.Sequencer create_simple_port() method */
+static PyObject *
+Sequencer_create_simple_port(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *name;
+ unsigned int type;
+ unsigned int caps=0;
+ char *kwlist[] = { "name", "type", "caps", NULL };
+ int port;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sI|I", kwlist,
+ &name, &type, &caps)) {
+ return NULL;
+ }
+
+ port = snd_seq_create_simple_port(self->handle, name, caps, type);
+ if (port < 0) {
+ RAISESND(port, "Failed to create simple port");
+ return NULL;
+ }
+
+ return PyInt_FromLong(port);
+}
+
+/** alsaseq.Sequencer connection_list() method: __doc__ */
+const char Sequencer_connection_list__doc__ [] =
+ "connection_list() -> list\n"
+ "\n"
+ "List all clients and their ports connections.\n"
+ "\n"
+ "Returns:\n"
+ " (list) a list of tuples: client_name, client_id, port_list:.\n"
+ " client_name -- the client's name.\n"
+ " client_id -- the client's id.\n"
+ " port_list -- a list of tuples: port_name, port_id, connection_list:\n"
+ " port_name -- the name of the port.\n"
+ " port_id -- the port id.\n"
+ " connection_list -- a list of tuples: read_conn, write_conn:\n"
+ " read_conn -- a list of (client_id, port_id, info) tuples this\n"
+ " port is connected to (sends events);\n"
+ " info is the same of the get_connect_info() method.\n"
+ " write_conn -- a list of (client_id, port_id, info) tuples this\n"
+ " port is connected from (receives events);\n"
+ " info is the same of the get_connect_info() method.\n"
+ ;
+
+
+static PyObject *
+_query_connections_list(snd_seq_t *handle,
+ snd_seq_query_subscribe_t *query,
+ int type) {
+
+ PyObject *list = PyList_New(0);
+ int index = 0;
+ long tmplong;
+ snd_seq_query_subscribe_set_type(query, type);
+ snd_seq_query_subscribe_set_index(query, index);
+ while (snd_seq_query_port_subscribers(handle, query) >= 0) {
+ const snd_seq_addr_t *addr =
+ snd_seq_query_subscribe_get_addr(query);
+
+ PyObject *dict = PyDict_New();
+
+ tmplong = snd_seq_query_subscribe_get_queue(query);
+ PyDict_SetItemString(dict, "queue", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_query_subscribe_get_exclusive(query);
+ PyDict_SetItemString(dict, "exclusive", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_query_subscribe_get_time_update(query);
+ PyDict_SetItemString(dict, "time_update", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_query_subscribe_get_time_real(query);
+ PyDict_SetItemString(dict, "time_real", PyInt_FromLong(tmplong));
+
+
+ PyObject *tuple = PyTuple_New(3);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(addr->client));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(addr->port));
+ PyTuple_SetItem(tuple, 2, dict);
+
+ PyList_Append(list, tuple);
+ snd_seq_query_subscribe_set_index(query, ++index);
+ }
+ return list;
+}
+
+static PyObject *
+_query_connections(snd_seq_t *handle,
+ const snd_seq_addr_t *addr) {
+ snd_seq_query_subscribe_t *query;
+ snd_seq_query_subscribe_alloca(&query);
+ snd_seq_query_subscribe_set_root(query, addr);
+
+ // create tuple for read,write lists
+ PyObject *tuple = PyTuple_New(2);
+ PyObject *readlist = _query_connections_list(handle, query,
+ SND_SEQ_QUERY_SUBS_READ);
+ PyObject *writelist = _query_connections_list(handle, query,
+ SND_SEQ_QUERY_SUBS_WRITE);
+ PyTuple_SetItem(tuple, 0, readlist);
+ PyTuple_SetItem(tuple, 1, writelist);
+
+ return tuple;
+}
+
+/** alsaseq.Sequencer connection_list() method */
+static PyObject *
+Sequencer_connection_list(SequencerObject *self,
+ PyObject *args) {
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+ PyObject *client, *port, *name;
+ PyObject *list = PyList_New(0);
+
+ if (list == NULL) {
+ return NULL;
+ }
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(self->handle, cinfo) >= 0) {
+ /* reset query info */
+ snd_seq_port_info_set_client(pinfo,
+ snd_seq_client_info_get_client(cinfo));
+ snd_seq_port_info_set_port(pinfo, -1);
+
+ /* create tuple for client info */
+ PyObject *tuple = PyTuple_New(3);
+ PyObject *portlist = PyList_New(0);
+
+ name = PyString_FromFormat("%s", snd_seq_client_info_get_name(cinfo));
+ client = PyInt_FromLong(snd_seq_client_info_get_client(cinfo));
+ PyTuple_SetItem(tuple, 0, name);
+ PyTuple_SetItem(tuple, 1, client);
+
+ while (snd_seq_query_next_port(self->handle, pinfo) >= 0) {
+ /* create tuple for port info */
+ PyObject *porttuple = PyTuple_New(3);
+
+ name = PyString_FromFormat("%s", snd_seq_port_info_get_name(pinfo));
+ port = PyInt_FromLong(snd_seq_port_info_get_port(pinfo));
+
+ PyTuple_SetItem(porttuple, 0, name);
+ PyTuple_SetItem(porttuple, 1, port);
+
+ /* create tuple for read,write connections */
+ PyObject *conntuple =
+ _query_connections(self->handle, snd_seq_port_info_get_addr(pinfo));
+ PyTuple_SetItem(porttuple, 2, conntuple);
+
+ PyList_Append(portlist, porttuple);
+ }
+ PyTuple_SetItem(tuple, 2, portlist);
+
+ /* append list of port tuples */
+ PyList_Append(list, tuple);
+ }
+
+ return list;
+}
+
+/** alsaseq.Sequencer get_client_info() method: __doc__ */
+const char Sequencer_get_client_info__doc__ [] =
+ "get_client_info(client_id = self.client_id) -> dictionary\n"
+ "\n"
+ "Retrieve info about an existing client.\n"
+ "\n"
+ "Parameters:\n"
+ " client_id -- the client id (defaults to: self.client_id)\n"
+ "Returns:\n"
+ " (dict) a dictionary with the following values:\n"
+ " id -- id of client.\n"
+ " type -- type of client (SEQ_USER_CLIENT or SEQ_KERNEL_CLIENT).\n"
+ " name -- name of client.\n"
+ " broadcast_filter -- broadcast filter flag of client as int.\n"
+ " error_bounce -- error bounce of client as int.\n"
+ " event_filter -- event filter of client as string.\n"
+ " num_ports -- number of opened ports of client.\n"
+ " event_lost -- number of lost events of client.\n"
+ "Raises:\n"
+ " SequencerError: ALSA error occurred."
+ ;
+
+/** alsaseq.Sequencer get_client_info() method */
+static PyObject *
+Sequencer_get_client_info(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ snd_seq_client_info_t *cinfo;
+ int client_id = -1;
+ int ret;
+ PyObject *tmpobj;
+ long tmplong;
+ const char * tmpchar;
+ char *kwlist[] = { "client_id", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
+ &client_id)) {
+ return NULL;
+ }
+
+ snd_seq_client_info_alloca(&cinfo);
+ if (client_id == -1) {
+ ret = snd_seq_get_client_info(self->handle, cinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to retrieve client info for self.client_id");
+ return NULL;
+ }
+ client_id = snd_seq_client_info_get_client(cinfo);
+ } else {
+ ret = snd_seq_get_any_client_info(self->handle, client_id, cinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to retrieve client info for '%d'", client_id);
+ return NULL;
+ }
+ }
+
+ PyObject *dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+ TCONSTASSIGN(ADDR_CLIENT, client_id, tmpobj);
+ PyDict_SetItemString(dict, "id", tmpobj);
+
+ tmplong = snd_seq_client_info_get_type(cinfo);
+ TCONSTASSIGN(CLIENT_TYPE, tmplong, tmpobj);
+ PyDict_SetItemString(dict, "type", tmpobj);
+
+ tmpchar = snd_seq_client_info_get_name(cinfo);
+ tmpchar = (tmpchar == NULL ? "" : tmpchar);
+ PyDict_SetItemString(dict, "name", PyString_FromString(tmpchar));
+
+ tmplong = snd_seq_client_info_get_broadcast_filter(cinfo);
+ PyDict_SetItemString(dict, "broadcast_filter", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_client_info_get_error_bounce(cinfo);
+ PyDict_SetItemString(dict, "error_bounce", PyInt_FromLong(tmplong));
+
+ tmpchar = (const char *)snd_seq_client_info_get_event_filter(cinfo);
+ tmpchar = (tmpchar == NULL ? "" : tmpchar);
+ PyDict_SetItemString(dict, "event_filter", PyString_FromString(tmpchar));
+
+ tmplong = snd_seq_client_info_get_num_ports(cinfo);
+ PyDict_SetItemString(dict, "num_ports", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_client_info_get_event_lost(cinfo);
+ PyDict_SetItemString(dict, "event_lost", PyInt_FromLong(tmplong));
+
+ return dict;
+}
+
+/** alsaseq.Sequencer get_port_info() method: __doc__ */
+const char Sequencer_get_port_info__doc__ [] =
+ "get_port_info(port_id, client_id = self.client_id) -> dictionary\n"
+ "\n"
+ "Retrieve info about an existing client's port.\n"
+ "\n"
+ "Parameters:\n"
+ " port_id -- the port id\n"
+ " client_id -- the client id (defaults to: self.client_id)\n"
+ "Returns:\n"
+ " (dict) a dictionary with the following values:\n"
+ " name -- the port name\n"
+ " type -- the port type bit flags\n"
+ " capability -- the port capability bit flags as integer\n"
+ "Raises:\n"
+ " SequencerError: ALSA error occurred."
+ ;
+
+/** alsaseq.Sequencer get_port_info() method */
+static PyObject *
+Sequencer_get_port_info(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ snd_seq_port_info_t *pinfo;
+ snd_seq_client_info_t *cinfo;
+ int port_id;
+ int client_id;
+ const char *tmpchar;
+ long tmplong;
+ int ret;
+ char *kwlist[] = { "port_id", "client_id", NULL };
+
+ snd_seq_client_info_alloca(&cinfo);
+ ret = snd_seq_get_client_info(self->handle, cinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to determine self.client_id");
+ return NULL;
+ }
+ client_id = snd_seq_client_info_get_client(cinfo);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwlist,
+ &port_id, &client_id)) {
+ return NULL;
+ }
+
+ PyObject *dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+ snd_seq_port_info_alloca(&pinfo);
+ ret = snd_seq_get_any_port_info(self->handle, client_id,
+ port_id, pinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to get port info for %d:%d", client_id, port_id);
+ return NULL;
+ }
+
+ tmpchar = snd_seq_port_info_get_name(pinfo);
+ tmpchar = (tmpchar == NULL ? "" : tmpchar);
+ PyDict_SetItemString(dict, "name", PyString_FromString(tmpchar));
+
+ tmplong = snd_seq_port_info_get_capability(pinfo);
+ PyDict_SetItemString(dict, "capability", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_port_info_get_type(pinfo);
+ PyDict_SetItemString(dict, "type", PyInt_FromLong(tmplong));
+
+ return dict;
+}
+
+/** alsaseq.Sequencer connect_ports() method: __doc__ */
+const char Sequencer_connect_ports__doc__ [] =
+ "connect_ports(srcaddr,dstaddr,queue,exclusive,time_update,time_real)\n"
+ "\n"
+ "Connect the ports specified by srcaddr and dstaddr.\n"
+ "\n"
+ "Parameters:\n"
+ " srcaddr -- (tuple) the (client_id, port_id) tuple for the source\n"
+ " port (the port sending events)\n"
+ " dstaddr -- (tuple) the (client_id, port_id) tuple for the destination\n"
+ " port (the port receiveng events)\n"
+ " queue -- the queue of the connection.\n"
+ " If not specified, defaults to 0.\n"
+ " exclusive -- 1 if the connection is exclusive, 0 otherwise.\n"
+ " If not specified, defaults to 0.\n"
+ " time_update -- 1 if the connection should update time, 0 otherwise.\n"
+ " If not specified, defaults to 0.\n"
+ " time_real -- 1 if the update time is in real, 0 if is in tick.\n"
+ " If not specified, defaults to 0.\n"
+ "Raises:\n"
+ " SequenceError: if ALSA can't connect the ports"
+ ;
+
+/** alsaseq.Sequencer connect_ports() method */
+static PyObject *
+Sequencer_connect_ports(SequencerObject *self,
+ PyObject *args) {
+ snd_seq_addr_t sender, dest;
+ snd_seq_port_subscribe_t *sinfo;
+ int ret;
+ int queue = 0;
+ int exclusive = 0;
+ int time_update = 0;
+ int time_real = 0;
+
+ if (!PyArg_ParseTuple(args, "(BB)(BB)|iiii", &(sender.client),
+ &(sender.port), &(dest.client), &(dest.port),
+ &queue, &exclusive, &time_update, &time_real)) {
+ return NULL;
+ }
+
+ snd_seq_port_subscribe_alloca(&sinfo);
+ snd_seq_port_subscribe_set_sender(sinfo, &sender);
+ snd_seq_port_subscribe_set_dest(sinfo, &dest);
+ snd_seq_port_subscribe_set_queue(sinfo, queue);
+ snd_seq_port_subscribe_set_exclusive(sinfo, exclusive);
+ snd_seq_port_subscribe_set_time_update(sinfo, time_update);
+ snd_seq_port_subscribe_set_time_real(sinfo, time_real);
+
+ ret = snd_seq_subscribe_port(self->handle, sinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to connect ports %d:%d -> %d:%d",
+ sender.client, sender.port, dest.client, dest.port);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/** alsaseq.Sequencer disconnect_ports() method: __doc__ */
+const char Sequencer_disconnect_ports__doc__ [] =
+ "disconnect_ports(srcaddr, destaddr)\n"
+ "\n"
+ "Disconnect the ports specified by srcaddr and dstaddr.\n"
+ "\n"
+ "Parameters:\n"
+ " srcaddr -- (tuple) the client_id, port_id tuple for the source\n"
+ " port (the port sending events)\n"
+ " dstaddr -- (tuple) the client_id, port_id tuple for the destination\n"
+ " port (the port receiveng events)\n"
+ "Raises:\n"
+ " SequenceError: if ALSA can't disconnect the port"
+ ;
+
+/** alsaseq.Sequencer disconnect_ports() method */
+static PyObject *
+Sequencer_disconnect_ports(SequencerObject *self,
+ PyObject *args) {
+ snd_seq_addr_t sender, dest;
+ snd_seq_port_subscribe_t *sinfo;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "(BB)(BB)", &(sender.client),
+ &(sender.port), &(dest.client), &(dest.port))) {
+ return NULL;
+ }
+
+ snd_seq_port_subscribe_alloca(&sinfo);
+ snd_seq_port_subscribe_set_sender(sinfo, &sender);
+ snd_seq_port_subscribe_set_dest(sinfo, &dest);
+
+ ret = snd_seq_unsubscribe_port(self->handle, sinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to disconnect ports: %d:%d --> %d:%d",
+ sender.client, sender.port, dest.client, dest.port);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/** alsaseq.Sequencer get_connect_info() method: __doc__ */
+const char Sequencer_get_connect_info__doc__ [] =
+ "get_connect_info(srcaddr, dstaddr) -> dictionary\n"
+ "\n"
+ "Retrieve the subscribe info of the specified connection.\n"
+ "\n"
+ "Parameters:\n"
+ " srcaddr -- (tuple) the client_id, port_id tuple for the source\n"
+ " port (the port sending events)\n"
+ " dstaddr -- (tuple) the client_id, port_id tuple for the destination\n"
+ " port (the port receiveng events)\n"
+ "Returns:\n"
+ " (dict) a dictionary with the following values:\n"
+ " queue -- \n"
+ " exclusive -- \n"
+ " time_update -- \n"
+ " time_real --- \n"
+ "Raises:\n"
+ " SequenceError: if ALSA can't retrieve the connection or the\n"
+ " connection doesn't exists."
+ ;
+
+
+static PyObject*
+Sequencer_get_connect_info(SequencerObject *self,
+ PyObject *args) {
+ snd_seq_addr_t sender, dest;
+ snd_seq_port_subscribe_t *sinfo;
+ int ret;
+ long tmplong;
+
+ if (!PyArg_ParseTuple(args, "(BB)(BB)", &(sender.client),
+ &(sender.port), &(dest.client), &(dest.port))) {
+ return NULL;
+ }
+
+ snd_seq_port_subscribe_alloca(&sinfo);
+ snd_seq_port_subscribe_set_sender(sinfo, &sender);
+ snd_seq_port_subscribe_set_dest(sinfo, &dest);
+
+ ret = snd_seq_get_port_subscription(self->handle, sinfo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to get port subscript: %d:%d --> %d:%d",
+ sender.client, sender.port, dest.client, dest.port);
+ return NULL;
+ }
+
+ PyObject *dict = PyDict_New();
+
+ tmplong = snd_seq_port_subscribe_get_queue(sinfo);
+ PyDict_SetItemString(dict, "queue", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_port_subscribe_get_exclusive(sinfo);
+ PyDict_SetItemString(dict, "exclusive", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_port_subscribe_get_time_update(sinfo);
+ PyDict_SetItemString(dict, "time_update", PyInt_FromLong(tmplong));
+
+ tmplong = snd_seq_port_subscribe_get_time_real(sinfo);
+ PyDict_SetItemString(dict, "time_real", PyInt_FromLong(tmplong));
+
+ return dict;
+}
+
+/** alsaseq.Sequencer receive_events() method: __doc__ */
+const char Sequencer_receive_events__doc__ [] =
+ "receive_events(timeout = 0, maxevents = self.receive_maxevents) -> list\n"
+ "\n"
+ "Receive events.\n"
+ "\n"
+ "Parameters:\n"
+ " timeout -- (int) time for wating for events in miliseconds\n"
+ " maxevents -- (int) max events to be returned\n"
+ "Returns:\n"
+ " (list) a list of alsaseq.SeqEvent objects\n"
+ "Raises:\n"
+ " TypeError: if an invalid type was used in a parameter\n"
+ " SequencerError: if ALSA error occurs."
+ ;
+
+/** alsaseq.Sequencer receive_events() method */
+static PyObject *
+Sequencer_receive_events(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ int maxevents = self->receive_max_events;
+ snd_seq_event_t *event = NULL;
+ int timeout = 0;
+ int ret;
+
+ char *kwlist[] = {"timeout", "maxevents", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &timeout,
+ &maxevents)) {
+ return NULL;
+ }
+
+ if (self->receive_fds == NULL) {
+ self->receive_max = snd_seq_poll_descriptors_count(self->handle, POLLOUT);
+ self->receive_fds = malloc(sizeof(struct pollfd) * self->receive_max);
+ }
+
+ PyObject *list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+
+
+ if (self->receive_bytes <= 0 && timeout != 0) {
+ snd_seq_poll_descriptors(self->handle, self->receive_fds,
+ self->receive_max, POLLIN);
+ ret = poll(self->receive_fds, self->receive_max, timeout);
+ if (ret == 0) {
+ return list;
+ } else if (ret < 0) {
+ RAISESTR("Failed to poll from receive: %s", strerror(-ret));
+ return NULL;
+ }
+ }
+
+ do {
+ ret = snd_seq_event_input(self->handle, &event);
+ self->receive_bytes = ret;
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ }
+ break;
+ }
+
+
+ PyObject *SeqEventObject = SeqEvent_create(event);
+ if (SeqEventObject == NULL) {
+ RAISESTR("Error creating event!");
+ return NULL;
+ }
+
+ PyList_Append(list, SeqEventObject);
+
+ maxevents --;
+
+ } while (maxevents > 0 && ret > 0);
+
+ return list;
+}
+
+/** alsaseq.Sequencer output_event() method: __doc__ */
+const char Sequencer_output_event__doc__ [] =
+ "output_event(event)\n"
+ "\n"
+ "Put the the given event in the outputbuffer. This actually will enqueue\n"
+ "the event, to make sure it's sent, use the drain_output() method.\n"
+ "\n"
+ "Parameters:\n"
+ " event -- a SeqEvent object\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't send the event"
+ ;
+
+/** alsaseq.Sequencer output_event() method */
+static PyObject *
+Sequencer_output_event(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ SeqEventObject *seqevent;
+ char *kwlist[] = {"event", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist,
+ &seqevent)) {
+ return NULL;
+ }
+
+ if (!PyObject_TypeCheck(seqevent, &SeqEventType)) {
+ PyErr_SetString(PyExc_TypeError, "alsaseq.SeqEvent expected");
+ return NULL;
+ }
+
+ snd_seq_event_output(self->handle, seqevent->event);
+
+ Py_RETURN_NONE;
+}
+
+/** alsaseq.Sequencer drain_output() method: __doc__ */
+const char Sequencer_drain_output__doc__ [] =
+ "drain_output()\n"
+ "\n"
+ "Drain the output, making sure all events int the buffer are sent.\n"
+ "The events sent may remain unprocessed, to make sure they are\n"
+ "processed, call the sync_output_queue() method.\n"
+ "\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't drain the output"
+ ;
+
+/** alsaseq.Sequencer drain_output() method */
+static PyObject *Sequencer_drain_output(SequencerObject *self,
+ PyObject *args) {
+ int ret;
+
+ ret = snd_seq_drain_output(self->handle);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to drain output");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/** alsaseq.Sequencer sync_output_queue() method: __doc__ */
+const char Sequencer_sync_output_queue__doc__ [] =
+ "sync_output_queue()\n"
+ "\n"
+ "Waits until all events of this clients are processed.\n"
+ "\n"
+ "Raises:\n"
+ " SequencerError: if an ALSA error occurs."
+ ;
+
+/** alsaseq.Sequencer sync_output_queue() method */
+static PyObject *
+Sequencer_sync_output_queue(SequencerObject *self,
+ PyObject *args) {
+ int ret;
+
+ ret = snd_seq_sync_output_queue(self->handle);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to sync output queue");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+/** alsaseq.Sequencer parse_address() method: __doc__ */
+const char Sequencer_parse_address__doc__ [] =
+ "parse_address(string) -> tuple\n"
+ "\n"
+ "Parses the given string as an ALSA client:port. You can use client,\n"
+ "port id's or names.\n"
+ "\n"
+ "Parameters:\n"
+ " string -- the address in the format client:port.\n"
+ "Returns:\n"
+ " the tuple (client_id, port_id).\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't parse the given address"
+ ;
+
+/** alsaseq.Sequencer parse_address() method */
+static PyObject *
+Sequencer_parse_address(SequencerObject *self,
+ PyObject *args) {
+ snd_seq_addr_t addr;
+ char *str = NULL;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "s", &(str))) {
+ return NULL;
+ }
+
+ ret = snd_seq_parse_address(self->handle, &addr, str);
+ if (ret < 0) {
+ RAISESND(ret, "Invalid client:port specification '%s'", str);
+ return NULL;
+ }
+
+ PyObject *tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(addr.client));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(addr.port));
+
+ return tuple;
+}
+
+/** alsaseq.Sequencer create_queue() method: __doc__ */
+const char Sequencer_create_queue__doc__ [] =
+ "create_queue(name=None)-> int\n"
+ "\n"
+ "Creates a queue with the optional given name.\n"
+ "\n"
+ "Parameters:\n"
+ " name -- the name of the queue.\n"
+ "Returns:\n"
+ " the queue id.\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't create the queue"
+ ;
+
+/** alsaseq.Sequencer create_queue() method */
+static PyObject *
+Sequencer_create_queue(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *kwlist[] = {"name", NULL};
+ char *queue_name = NULL;
+ int ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
+ &queue_name)) {
+ return NULL;
+ }
+
+ if (queue_name != NULL) {
+ ret = snd_seq_alloc_named_queue(self->handle, queue_name);
+ } else {
+ ret = snd_seq_alloc_queue(self->handle);
+ }
+
+ if (ret < 0) {
+ RAISESND(ret, "Failed to create queue");
+ return NULL;
+ }
+
+ return PyInt_FromLong(ret);
+}
+
+/** alsaseq.Sequencer delete_queue() method: __doc__ */
+const char Sequencer_delete_queue__doc__ [] =
+ "delete_queue(queue)\n"
+ "\n"
+ "Deletes (frees) a queue.\n"
+ "\n"
+ "Parameters:\n"
+ " queue -- the queue id.\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't delete the queue."
+ ;
+
+/** alsaseq.Sequencer delete_queue() method */
+static PyObject *
+Sequencer_delete_queue(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *kwlist[] = {"queue", NULL};
+ int queue_id;
+ int ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist,
+ &queue_id)) {
+ return NULL;
+ }
+
+ ret = snd_seq_free_queue(self->handle, queue_id);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to create queue");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+/** alsaseq.Sequencer queue_tempo() method: __doc__ */
+const char Sequencer_queue_tempo__doc__ [] =
+ "queue_tempo(queue, tempo=None, ppq=None) -> tuple"
+ "\n"
+ "Query and changes the queue tempo. For querying (not changing) the queue\n"
+ "tempo, pass only the queue id.\n"
+ "\n"
+ "Parameters:\n"
+ " queue -- the queue id.\n"
+ " tempo -- the new queue tempo or None for keeping the current tempo.\n"
+ " ppq -- the new queue ppq or None for keeping the current tempo.\n"
+ "Returns:\n"
+ " a tuple (tempo, ppq) with the current or changed tempo.\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't change the queue tempo or an invalid\n"
+ " queue was specified."
+ ;
+
+/** alsaseq.Sequencer queue_tempo() method */
+static PyObject *
+Sequencer_queue_tempo(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *kwlist[] = {"queue", "tempo", "ppq", NULL};
+ int queueid, tempo=-1, ppq=-1;
+ int ret;
+ snd_seq_queue_tempo_t *queue_tempo;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwlist,
+ &queueid, &tempo, &ppq)) {
+ return NULL;
+ }
+
+ snd_seq_queue_tempo_alloca(&queue_tempo);
+ ret = snd_seq_get_queue_tempo(self->handle, queueid, queue_tempo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to retrieve current queue tempo");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwlist,
+ &queueid, &tempo, &ppq)) {
+ return NULL;
+ }
+
+ if (tempo != -1) {
+ snd_seq_queue_tempo_set_tempo(queue_tempo, tempo);
+ }
+ if (ppq != -1) {
+ snd_seq_queue_tempo_set_ppq(queue_tempo, ppq);
+ }
+
+ if (tempo != -1 && ppq != -1) {
+ ret = snd_seq_set_queue_tempo(self->handle, queueid, queue_tempo);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to set queue tempo");
+ return NULL;
+ }
+ }
+
+ tempo = snd_seq_queue_tempo_get_tempo(queue_tempo);
+ ppq = snd_seq_queue_tempo_get_ppq(queue_tempo);
+
+ PyObject *tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(tempo));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(ppq));
+
+ return tuple;
+}
+
+/** alsaseq.Sequencer start_queue() method: __doc__ */
+const char Sequencer_start_queue__doc__ [] =
+ "start_queue(queue)\n"
+ "\n"
+ "Starts the specified queue.\n"
+ "\n"
+ "Parameters:\n"
+ " queue -- the queue id.\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't start the queue."
+ ;
+
+/** alsaseq.Sequencer start_queue() method */
+static PyObject *
+Sequencer_start_queue(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *kwlist[] = {"queue", NULL};
+ int queueid;
+ int ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist,
+ &queueid)) {
+ return NULL;
+ }
+
+ ret = snd_seq_start_queue(self->handle, queueid, NULL);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to start queue");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/** alsaseq.Sequencer stop_queue() method: __doc__ */
+const char Sequencer_stop_queue__doc__ [] =
+ "stop_queue(queue)\n"
+ "\n"
+ "Stops the specified queue.\n"
+ "\n"
+ "Parameters:\n"
+ " queue -- the queue id.\n"
+ "Raises:\n"
+ " SequencerError: if ALSA can't stop the queue."
+ ;
+
+/** alsaseq.Sequencer stop_queue() method */
+static PyObject *
+Sequencer_stop_queue(SequencerObject *self,
+ PyObject *args,
+ PyObject *kwds) {
+ char *kwlist[] = {"queue", NULL};
+ int queueid;
+ int ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist,
+ &queueid)) {
+ return NULL;
+ }
+
+ ret = snd_seq_stop_queue(self->handle, queueid, NULL);
+ if (ret < 0) {
+ RAISESND(ret, "Failed to stop queue");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+
+
+/** alsaseq.Sequencer tp_methods */
+static PyMethodDef Sequencer_methods[] = {
+ {"create_simple_port",
+ (PyCFunction) Sequencer_create_simple_port,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_create_simple_port__doc__ },
+ {"connection_list",
+ (PyCFunction) Sequencer_connection_list,
+ METH_VARARGS,
+ Sequencer_connection_list__doc__ },
+ {"get_client_info",
+ (PyCFunction) Sequencer_get_client_info,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_get_client_info__doc__ },
+ {"get_port_info",
+ (PyCFunction) Sequencer_get_port_info,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_get_port_info__doc__ },
+ {"connect_ports",
+ (PyCFunction) Sequencer_connect_ports,
+ METH_VARARGS,
+ Sequencer_connect_ports__doc__ },
+ {"disconnect_ports",
+ (PyCFunction) Sequencer_disconnect_ports,
+ METH_VARARGS,
+ Sequencer_disconnect_ports__doc__ },
+ {"get_connect_info",
+ (PyCFunction) Sequencer_get_connect_info,
+ METH_VARARGS,
+ Sequencer_get_connect_info__doc__},
+ {"receive_events",
+ (PyCFunction) Sequencer_receive_events,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_receive_events__doc__},
+ {"output_event",
+ (PyCFunction) Sequencer_output_event,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_output_event__doc__},
+ {"drain_output",
+ (PyCFunction) Sequencer_drain_output,
+ METH_VARARGS,
+ Sequencer_drain_output__doc__},
+ {"sync_output_queue",
+ (PyCFunction) Sequencer_sync_output_queue,
+ METH_VARARGS,
+ Sequencer_sync_output_queue__doc__},
+ {"parse_address",
+ (PyCFunction) Sequencer_parse_address,
+ METH_VARARGS,
+ Sequencer_parse_address__doc__},
+ {"create_queue",
+ (PyCFunction) Sequencer_create_queue,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_create_queue__doc__},
+ {"delete_queue",
+ (PyCFunction) Sequencer_delete_queue,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_delete_queue__doc__},
+ {"queue_tempo",
+ (PyCFunction) Sequencer_queue_tempo,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_queue_tempo__doc__},
+ {"start_queue",
+ (PyCFunction) Sequencer_start_queue,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_start_queue__doc__},
+ {"stop_queue",
+ (PyCFunction) Sequencer_stop_queue,
+ METH_VARARGS | METH_KEYWORDS,
+ Sequencer_stop_queue__doc__},
+ {NULL}
+};
+
+/** alsaseq.Sequencer type */
+static PyTypeObject SequencerType = {
+ PyObject_HEAD_INIT(NULL)
+ tp_name: "alsaseq.Sequencer",
+ tp_basicsize: sizeof(SequencerObject),
+ tp_dealloc: (destructor) Sequencer_dealloc,
+ tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ tp_doc: Sequencer__doc__,
+ tp_init: (initproc) Sequencer_init,
+ tp_new: PyType_GenericNew,
+ tp_alloc: PyType_GenericAlloc,
+ tp_free: PyObject_Del,
+ tp_repr: (reprfunc) Sequencer_repr,
+ tp_methods: Sequencer_methods,
+ tp_getset: Sequencer_getset
+};
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// alsaseq module implementation
+//////////////////////////////////////////////////////////////////////////////
+
+/** alsaseq module: __doc__ */
+const char alsaseq__doc__ [] =
+ "libasound alsaseq wrapper"
+ ;
+
+/** alsaseq module methods */
+static PyMethodDef alsaseq_methods[] = {
+ { NULL },
+};
+
+PyMODINIT_FUNC
+initalsaseq(void) {
+ PyObject *module;
+
+ if (PyType_Ready(&ConstantType) < 0) {
+ return;
+ }
+
+ if (PyType_Ready(&SeqEventType) < 0) {
+ return;
+ }
+
+ if (PyType_Ready(&SequencerType) < 0) {
+ return;
+ }
+
+ module = Py_InitModule3("alsaseq", alsaseq_methods, alsaseq__doc__);
+
+ if (module == NULL) {
+ return;
+ }
+
+ SequencerError = PyErr_NewException("alsaseq.SequencerError", NULL, NULL);
+ if (SequencerError == NULL) {
+ return;
+ }
+
+ Py_INCREF(SequencerError);
+ PyModule_AddObject(module, "SequencerError", SequencerError);
+
+ Py_INCREF(&SeqEventType);
+ PyModule_AddObject(module, "SeqEvent", (PyObject *) &SeqEventType);
+
+ Py_INCREF(&SequencerType);
+ PyModule_AddObject(module, "Sequencer", (PyObject *) &SequencerType);
+
+ Py_INCREF(&ConstantType);
+ PyModule_AddObject(module, "Constant", (PyObject *) &ConstantType);
+
+ /* misc constants */
+ PyModule_AddStringConstant(module,
+ "SEQ_LIB_VERSION_STR",
+ SND_LIB_VERSION_STR);
+
+ /* add Constant dictionaries to module */
+ TCONSTDICTADD(module, STREAMS,
+ "_dstreams");
+ TCONSTDICTADD(module, MODE,
+ "_dmode");
+ TCONSTDICTADD(module, QUEUE,
+ "_dqueue");
+ TCONSTDICTADD(module, CLIENT_TYPE,
+ "_dclienttype");
+ TCONSTDICTADD(module, PORT_CAP,
+ "_dportcap");
+ TCONSTDICTADD(module, PORT_TYPE,
+ "_dporttype");
+ TCONSTDICTADD(module, EVENT_TYPE,
+ "_deventtype");
+ TCONSTDICTADD(module, EVENT_TIMESTAMP,
+ "_deventtimestamp");
+ TCONSTDICTADD(module, EVENT_TIMEMODE,
+ "_deventtimemode");
+ TCONSTDICTADD(module, ADDR_CLIENT,
+ "_dclient");
+ TCONSTDICTADD(module, ADDR_PORT,
+ "_dport");
+
+ /* Sequencer streams */
+ TCONSTADD(module, STREAMS,
+ "SEQ_OPEN_OUTPUT",
+ SND_SEQ_OPEN_OUTPUT);
+ TCONSTADD(module, STREAMS,
+ "SEQ_OPEN_INPUT",
+ SND_SEQ_OPEN_INPUT);
+ TCONSTADD(module, STREAMS,
+ "SEQ_OPEN_DUPLEX",
+ SND_SEQ_OPEN_DUPLEX);
+
+ /* Sequencer blocking mode */
+ TCONSTADD(module, MODE,
+ "SEQ_BLOCK",
+ 0);
+ TCONSTADD(module, MODE,
+ "SEQ_NONBLOCK",
+ SND_SEQ_NONBLOCK);
+
+ /* Known queue id */
+ TCONSTADD(module, QUEUE,
+ "SEQ_QUEUE_DIRECT",
+ SND_SEQ_QUEUE_DIRECT);
+
+ /* client types */
+ TCONSTADD(module, CLIENT_TYPE,
+ "SEQ_USER_CLIENT",
+ SND_SEQ_USER_CLIENT);
+ TCONSTADD(module, CLIENT_TYPE,
+ "SEQ_KERNEL_CLIENT",
+ SND_SEQ_KERNEL_CLIENT);
+
+ /* Sequencer port cap */
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_NONE",
+ 0);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_WRITE",
+ SND_SEQ_PORT_CAP_WRITE);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_SYNC_WRITE",
+ SND_SEQ_PORT_CAP_SYNC_WRITE);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_SYNC_READ",
+ SND_SEQ_PORT_CAP_SYNC_READ);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_SUBS_WRITE",
+ SND_SEQ_PORT_CAP_SUBS_WRITE);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_SUBS_READ",
+ SND_SEQ_PORT_CAP_SUBS_READ);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_READ",
+ SND_SEQ_PORT_CAP_READ);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_NO_EXPORT",
+ SND_SEQ_PORT_CAP_NO_EXPORT);
+ TCONSTADD(module, PORT_CAP,
+ "SEQ_PORT_CAP_DUPLEX",
+ SND_SEQ_PORT_CAP_DUPLEX);
+
+ /* Sequencer port type */
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_SYNTHESIZER",
+ SND_SEQ_PORT_TYPE_SYNTHESIZER);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_SYNTH",
+ SND_SEQ_PORT_TYPE_SYNTH);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_SPECIFIC",
+ SND_SEQ_PORT_TYPE_SPECIFIC);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_SOFTWARE",
+ SND_SEQ_PORT_TYPE_SOFTWARE);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_SAMPLE",
+ SND_SEQ_PORT_TYPE_SAMPLE);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_PORT",
+ SND_SEQ_PORT_TYPE_PORT);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_XG",
+ SND_SEQ_PORT_TYPE_MIDI_XG);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_MT32",
+ SND_SEQ_PORT_TYPE_MIDI_MT32);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_GS",
+ SND_SEQ_PORT_TYPE_MIDI_GS);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_GM2",
+ SND_SEQ_PORT_TYPE_MIDI_GM2);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_GM",
+ SND_SEQ_PORT_TYPE_MIDI_GM);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_MIDI_GENERIC",
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_HARDWARE",
+ SND_SEQ_PORT_TYPE_HARDWARE);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_DIRECT_SAMPLE",
+ SND_SEQ_PORT_TYPE_DIRECT_SAMPLE);
+ TCONSTADD(module, PORT_TYPE,
+ "SEQ_PORT_TYPE_APPLICATION",
+ SND_SEQ_PORT_TYPE_APPLICATION);
+
+ /* SeqEvent event type */
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SYSTEM",
+ SND_SEQ_EVENT_SYSTEM);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_RESULT",
+ SND_SEQ_EVENT_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_NOTE",
+ SND_SEQ_EVENT_NOTE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_NOTEON",
+ SND_SEQ_EVENT_NOTEON);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_NOTEOFF",
+ SND_SEQ_EVENT_NOTEOFF);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_KEYPRESS",
+ SND_SEQ_EVENT_KEYPRESS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CONTROLLER",
+ SND_SEQ_EVENT_CONTROLLER);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PGMCHANGE",
+ SND_SEQ_EVENT_PGMCHANGE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CHANPRESS",
+ SND_SEQ_EVENT_CHANPRESS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PITCHBEND",
+ SND_SEQ_EVENT_PITCHBEND);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CONTROL14",
+ SND_SEQ_EVENT_CONTROL14);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_NONREGPARAM",
+ SND_SEQ_EVENT_NONREGPARAM);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_REGPARAM",
+ SND_SEQ_EVENT_REGPARAM);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SONGPOS",
+ SND_SEQ_EVENT_SONGPOS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SONGSEL",
+ SND_SEQ_EVENT_SONGSEL);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_QFRAME",
+ SND_SEQ_EVENT_QFRAME);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_TIMESIGN",
+ SND_SEQ_EVENT_TIMESIGN);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_KEYSIGN",
+ SND_SEQ_EVENT_KEYSIGN);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_START",
+ SND_SEQ_EVENT_START);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CONTINUE",
+ SND_SEQ_EVENT_CONTINUE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_STOP",
+ SND_SEQ_EVENT_STOP);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SETPOS_TICK",
+ SND_SEQ_EVENT_SETPOS_TICK);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SETPOS_TIME",
+ SND_SEQ_EVENT_SETPOS_TIME);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_TEMPO",
+ SND_SEQ_EVENT_TEMPO);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CLOCK",
+ SND_SEQ_EVENT_CLOCK);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_TICK",
+ SND_SEQ_EVENT_TICK);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_QUEUE_SKEW",
+ SND_SEQ_EVENT_QUEUE_SKEW);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SYNC_POS",
+ SND_SEQ_EVENT_SYNC_POS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_TUNE_REQUEST",
+ SND_SEQ_EVENT_TUNE_REQUEST);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_RESET",
+ SND_SEQ_EVENT_RESET);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SENSING",
+ SND_SEQ_EVENT_SENSING);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_ECHO",
+ SND_SEQ_EVENT_ECHO);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_OSS",
+ SND_SEQ_EVENT_OSS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CLIENT_START",
+ SND_SEQ_EVENT_CLIENT_START);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CLIENT_EXIT",
+ SND_SEQ_EVENT_CLIENT_EXIT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_CLIENT_CHANGE",
+ SND_SEQ_EVENT_CLIENT_CHANGE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PORT_START",
+ SND_SEQ_EVENT_PORT_START);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PORT_EXIT",
+ SND_SEQ_EVENT_PORT_EXIT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PORT_CHANGE",
+ SND_SEQ_EVENT_PORT_CHANGE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PORT_SUBSCRIBED",
+ SND_SEQ_EVENT_PORT_SUBSCRIBED);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_PORT_UNSUBSCRIBED",
+ SND_SEQ_EVENT_PORT_UNSUBSCRIBED);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE",
+ SND_SEQ_EVENT_SAMPLE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_CLUSTER",
+ SND_SEQ_EVENT_SAMPLE_CLUSTER);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_START",
+ SND_SEQ_EVENT_SAMPLE_START);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_STOP",
+ SND_SEQ_EVENT_SAMPLE_STOP);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_FREQ",
+ SND_SEQ_EVENT_SAMPLE_FREQ);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_VOLUME",
+ SND_SEQ_EVENT_SAMPLE_VOLUME);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_LOOP",
+ SND_SEQ_EVENT_SAMPLE_LOOP);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_POSITION",
+ SND_SEQ_EVENT_SAMPLE_POSITION);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SAMPLE_PRIVATE1",
+ SND_SEQ_EVENT_SAMPLE_PRIVATE1);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR0",
+ SND_SEQ_EVENT_USR0);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR1",
+ SND_SEQ_EVENT_USR1);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR2",
+ SND_SEQ_EVENT_USR2);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR3",
+ SND_SEQ_EVENT_USR3);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR4",
+ SND_SEQ_EVENT_USR4);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR5",
+ SND_SEQ_EVENT_USR5);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR6",
+ SND_SEQ_EVENT_USR6);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR7",
+ SND_SEQ_EVENT_USR7);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR8",
+ SND_SEQ_EVENT_USR8);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR9",
+ SND_SEQ_EVENT_USR9);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_BEGIN",
+ SND_SEQ_EVENT_INSTR_BEGIN);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_END",
+ SND_SEQ_EVENT_INSTR_END);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_INFO",
+ SND_SEQ_EVENT_INSTR_INFO);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_INFO_RESULT",
+ SND_SEQ_EVENT_INSTR_INFO_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_FINFO",
+ SND_SEQ_EVENT_INSTR_FINFO);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_FINFO_RESULT",
+ SND_SEQ_EVENT_INSTR_FINFO_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_RESET",
+ SND_SEQ_EVENT_INSTR_RESET);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_STATUS",
+ SND_SEQ_EVENT_INSTR_STATUS);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_STATUS_RESULT",
+ SND_SEQ_EVENT_INSTR_STATUS_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_PUT",
+ SND_SEQ_EVENT_INSTR_PUT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_GET",
+ SND_SEQ_EVENT_INSTR_GET);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_GET_RESULT",
+ SND_SEQ_EVENT_INSTR_GET_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_FREE",
+ SND_SEQ_EVENT_INSTR_FREE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_LIST",
+ SND_SEQ_EVENT_INSTR_LIST);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_LIST_RESULT",
+ SND_SEQ_EVENT_INSTR_LIST_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_CLUSTER",
+ SND_SEQ_EVENT_INSTR_CLUSTER);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_CLUSTER_GET",
+ SND_SEQ_EVENT_INSTR_CLUSTER_GET);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_CLUSTER_RESULT",
+ SND_SEQ_EVENT_INSTR_CLUSTER_RESULT);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_INSTR_CHANGE",
+ SND_SEQ_EVENT_INSTR_CHANGE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_SYSEX",
+ SND_SEQ_EVENT_SYSEX);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_BOUNCE",
+ SND_SEQ_EVENT_BOUNCE);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR_VAR0",
+ SND_SEQ_EVENT_USR_VAR0);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR_VAR1",
+ SND_SEQ_EVENT_USR_VAR1);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR_VAR2",
+ SND_SEQ_EVENT_USR_VAR2);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR_VAR3",
+ SND_SEQ_EVENT_USR_VAR3);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_USR_VAR4",
+ SND_SEQ_EVENT_USR_VAR4);
+ TCONSTADD(module, EVENT_TYPE,
+ "SEQ_EVENT_NONE",
+ SND_SEQ_EVENT_NONE);
+
+
+ /* SeqEvent event timestamp flags */
+ TCONSTADD(module, EVENT_TIMESTAMP,
+ "SEQ_TIME_STAMP_TICK",
+ SND_SEQ_TIME_STAMP_TICK);
+ TCONSTADD(module, EVENT_TIMESTAMP,
+ "SEQ_TIME_STAMP_REAL",
+ SND_SEQ_TIME_STAMP_REAL);
+
+ /* SeqEvent event timemode flags */
+ TCONSTADD(module, EVENT_TIMEMODE,
+ "SEQ_TIME_MODE_ABS",
+ SND_SEQ_TIME_MODE_ABS);
+ TCONSTADD(module, EVENT_TIMEMODE,
+ "SEQ_TIME_MODE_REL",
+ SND_SEQ_TIME_MODE_REL);
+
+ /* SeqEvent event addresses */
+ TCONSTADD(module, ADDR_CLIENT,
+ "SEQ_CLIENT_SYSTEM",
+ SND_SEQ_CLIENT_SYSTEM);
+ TCONSTADD(module, ADDR_CLIENT,
+ "SEQ_ADDRESS_BROADCAST",
+ SND_SEQ_ADDRESS_BROADCAST);
+ TCONSTADD(module, ADDR_CLIENT,
+ "SEQ_ADDRESS_SUBSCRIBERS",
+ SND_SEQ_ADDRESS_SUBSCRIBERS);
+ TCONSTADD(module, ADDR_CLIENT,
+ "SEQ_ADDRESS_UNKNOWN",
+ SND_SEQ_ADDRESS_UNKNOWN);
+ TCONSTADD(module, ADDR_PORT,
+ "SEQ_PORT_SYSTEM_TIMER",
+ SND_SEQ_PORT_SYSTEM_TIMER);
+ TCONSTADD(module, ADDR_PORT,
+ "SEQ_PORT_SYSTEM_ANNOUNCE",
+ SND_SEQ_PORT_SYSTEM_ANNOUNCE);
+ TCONSTADD(module, ADDR_PORT,
+ "SEQ_ADDRESS_BROADCAST",
+ SND_SEQ_ADDRESS_BROADCAST);
+ TCONSTADD(module, ADDR_PORT,
+ "SEQ_ADDRESS_SUBSCRIBERS",
+ SND_SEQ_ADDRESS_SUBSCRIBERS);
+ TCONSTADD(module, ADDR_PORT,
+ "SEQ_ADDRESS_UNKNOWN",
+ SND_SEQ_ADDRESS_UNKNOWN);
+
+}
diff -r 02b11d9f243d setup.py
--- a/setup.py Tue Jan 22 11:56:20 2008 +0100
+++ b/setup.py Thu Jan 24 05:18:40 2008 -0300
@@ -45,6 +45,11 @@ setup(
include_dirs=[],
library_dirs=[],
libraries=['asound']),
+ Extension('pyalsa.alsaseq',
+ ['pyalsa/alsaseq.c'],
+ include_dirs=[],
+ library_dirs=[],
+ libraries=['asound']),
],
packages=['pyalsa'],
scripts=[]
@@ -52,7 +57,7 @@ setup(
uname = os.uname()
a = 'build/lib.%s-%s-%s' % (uname[0].lower(), uname[4], sys.version[:3])
-for f in ['alsacard.so', 'alsacontrol.so', 'alsahcontrol.so', 'alsamixer.so']:
+for f in ['alsacard.so', 'alsacontrol.so', 'alsahcontrol.so',
'alsamixer.so', 'alsaseq.so']:
if not os.path.exists('pyalsa/%s' % f):
a = '../build/lib.%s-%s-%s/pyalsa/%s' % (uname[0].lower(),
uname[4], sys.version[:3], f)
diff -r 02b11d9f243d test/aconnect.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aconnect.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,205 @@
+#! /usr/bin/python
+
+# aconnect.py -- python port of aconnect
+# Copyright (C) 2008 Aldrin Martoq <amartoq at dcc.uchile.cl>
+#
+# Based on code from aconnect.c from ALSA project
+# Copyright (C) 1999 Takashi Iwai
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+import sys
+sys.path.insert(0, '../pyalsa')
+
+import getopt
+import os
+from alsaseq import *
+
+LIST_INPUT=1
+LIST_OUTPUT=2
+
+def errormsg(msg, *args):
+ """ prints an error message to stderr """
+ sys.stderr.write(msg % args)
+ sys.stderr.write('\n')
+ traceback.print_exc(file=sys.stderr)
+
+def fatal(msg, *args):
+ """ prints an error message to stderr, and dies """
+ errormsg(msg, *args)
+ sys.exit(1)
+
+def init_seq():
+ """ opens an alsa sequencer """
+ try:
+ sequencer = Sequencer(name = 'default',
+ clientname = 'aconnect.py',
+ streams = SEQ_OPEN_DUPLEX,
+ mode = SEQ_BLOCK)
+ return sequencer
+ except SequencerError, e:
+ fatal("open sequencer: %e", e)
+
+
+def usage():
+ print \
+ "aconnect - python ALSA sequencer connection manager\n" \
+ "Copyright (C) 1999-2000 Takashi Iwai\n" \
+ "Copyright (C) 2008 Aldrin Martoq <amartoq at dcc.uchile.cl>\n" \
+ "Usage: \n" \
+ " * Connection/disconnection between ports\n" \
+ " %s [-options] sender receiver\n" \
+ " sender, receiver = client:port pair\n" \
+ " -d,--disconnect disconnect\n" \
+ " -e,--exclusive exclusive connection\n" \
+ " -r,--real # convert real-time-stamp on queue\n" \
+ " -t,--tick # convert tick-time-stamp on queue\n" \
+ " * List connected ports (no subscription action)\n" \
+ " %s -i|-o [-options]\n" \
+ " -i,--input list input (readable) ports\n" \
+ " -o,--output list output (writable) ports\n" \
+ " -l,--list list current connections of each port\n" \
+ " * Remove all exported connections\n" \
+ " -x,--removeall" \
+ % (sys.argv[0], sys.argv[0])
+
+def do_list_subs(conn, text):
+ l = []
+ for c, p, i in conn:
+ s = ""
+ if i['exclusive']:
+ s+= "[ex]"
+ if i['time_update']:
+ if i['time_real']:
+ s += "[%s:%s]" % ("real", i['queue'])
+ else:
+ s += "[%s:%s]" % ("tick", i['queue'])
+ s = "%d:%d%s" % (c, p, s)
+ l.append(s)
+ if len(l):
+ print "\t%s: %s" % (text, ', '.join(l))
+
+
+def do_list_ports(sequencer, list_perm, list_subs):
+ connectionlist = sequencer.connection_list()
+ for connections in connectionlist:
+ clientname, clientid, connectedports = connections
+ clientinfo = sequencer.get_client_info(clientid)
+ type = clientinfo['type']
+ count = []
+ if type == SEQ_USER_CLIENT:
+ type = 'user'
+ else:
+ type = 'kernel'
+ for port in connectedports:
+ portname, portid, portconns = port
+ portinfo = sequencer.get_port_info(portid, clientid)
+ caps = portinfo['capability']
+ if not (caps & SEQ_PORT_CAP_NO_EXPORT):
+ reads = SEQ_PORT_CAP_READ | SEQ_PORT_CAP_SUBS_READ
+ write = SEQ_PORT_CAP_WRITE | SEQ_PORT_CAP_SUBS_WRITE
+ if (list_perm & LIST_INPUT) and (caps & reads == reads):
+ count.append(port)
+ elif (list_perm & LIST_OUTPUT) and (caps & write == write):
+ count.append(port)
+ if len(count) > 0:
+ print "client %d: '%s' [type=%s]" % (clientid, clientname, type)
+ for port in count:
+ portname, portid, portconns = port
+ print " %3d '%-16s'" % (portid, portname)
+ if list_subs:
+ readconn, writeconn = portconns
+ do_list_subs(readconn, "Connecting To")
+ do_list_subs(writeconn, "Connected From")
+
+def do_unsubscribe(sequencer, args):
+ sender = sequencer.parse_address(args[0])
+ dest = sequencer.parse_address(args[1])
+ try:
+ sequencer.get_connect_info(sender, dest)
+ except SequencerError:
+ print 'No subscription is found'
+ return
+ try:
+ sequencer.disconnect_ports(sender, dest)
+ except SequencerError, e:
+ fatal("Failed to disconnect ports %s->%s - %s", sender, dest, e)
+
+def do_subscribe(sequencer, args, queue, exclusive, convert_time,
convert_real):
+ sender = sequencer.parse_address(args[0])
+ dest = sequencer.parse_address(args[1])
+ try:
+ sequencer.get_connect_info(sender, dest)
+ print "Connection is already subscribed"
+ return
+ except SequencerError:
+ pass
+ sequencer.connect_ports(sender, dest, queue, exclusive,
convert_time, convert_real)
+
+def main():
+ sequencer = init_seq()
+ command = 'subscribe'
+ list_perm = 0
+ list_subs = 0
+ exclusive = 0
+ convert_time = 0
+ convert_real = 0
+ queue = 0
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "dior:t:elx",
["disconnect", "input", "output", "real=", "tick=", "exclusive",
"list", "removeall"])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ for o, a in opts:
+ if o in ("-d", "--disconnect"):
+ command = 'unsubscribe'
+ elif o in ("-i", "--input"):
+ command = 'list'
+ list_perm |= LIST_INPUT
+ elif o in ("-o", "--output"):
+ command = 'list'
+ list_perm |= LIST_OUTPUT
+ elif o in ("-e", "--exclusive"):
+ exclusive = 1
+ elif o in ("-r", "--real"):
+ queue = int(a)
+ convert_time = 1
+ convert_real = 1
+ elif o in ("-t", "--tick"):
+ queue = int(a)
+ convert_time = 1
+ convert_real = 0
+ elif o in ("-l", "--list"):
+ list_subs = 1
+ elif o in ("-x", "--removeall"):
+ command = 'removeall'
+
+ if command == 'list':
+ do_list_ports(sequencer, list_perm, list_subs)
+ return
+
+ if len(args) != 2:
+ usage()
+ sys.exit(2)
+
+ if command == 'unsubscribe':
+ do_unsubscribe(sequencer, args)
+ elif command == 'subscribe':
+ do_subscribe(sequencer, args, queue, exclusive, convert_time,
convert_real)
+
+
+if __name__ == '__main__':
+ main()
diff -r 02b11d9f243d test/alsamemdebug.py
--- a/test/alsamemdebug.py Tue Jan 22 11:56:20 2008 +0100
+++ b/test/alsamemdebug.py Thu Jan 24 05:18:40 2008 -0300
@@ -5,7 +5,8 @@ import gc
import gc
def debuginit():
- gc.set_debug(gc.DEBUG_LEAK)
+ gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS)
+ print "GC DEBUG: init."
def debug(what):
from sys import getrefcount
@@ -13,7 +14,9 @@ def debug(what):
for o in what:
if getrefcount(o) - 3 != 1 or \
len(get_referrers(o)) - 2 != 1:
- print 'LEAK:', hex(id(o)), type(o), getrefcount(o)-3,
len(get_referrers(o))-2
+ print 'GD DEBUG LEAK:', o, hex(id(o)), type(o), getrefcount(o)-3,
len(get_referrers(o))-2
def debugdone():
+ gc.collect()
+ print "GC DEBUG LEAK done."
None
diff -r 02b11d9f243d test/aplaymidi.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aplaymidi.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,501 @@
+#! /usr/bin/python
+
+# aplaymidi.py -- python port of aplaymidi
+# Copyright (C) 2008 Aldrin Martoq <amartoq at dcc.uchile.cl>
+#
+# Based on code from aplaymidi.c from ALSA project
+# Copyright (C) 2004-2006 Clemens Ladisch <clemens at ladisch.de>
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+import sys
+sys.path.insert(0, '../pyalsa')
+
+import getopt
+import os
+import struct
+import alsaseq
+import traceback
+import time
+from alsaseq import *
+
+class SMFError(Exception):
+ """ Exception raised for errors while reading a SMF file """
+ pass
+
+
+def errormsg(msg, *args):
+ """ prints an error message to stderr """
+ sys.stderr.write(msg % args)
+ sys.stderr.write('\n')
+ traceback.print_exc(file=sys.stderr)
+
+
+def fatal(msg, *args):
+ """ prints an error message to stderr, and dies """
+ errormsg(msg, *args)
+ sys.exit(1)
+
+
+def init_seq():
+ """ opens an alsa sequencer """
+ try:
+ sequencer = Sequencer(name = 'default',
+ clientname = 'aplaymidi.py',
+ streams = SEQ_OPEN_DUPLEX,
+ mode = SEQ_BLOCK)
+ return sequencer
+ except SequencerError, e:
+ fatal("open sequencer: %e", e)
+
+
+def parse_ports(sequencer, portspec):
+ """ parses one or more port addresses from the string, separated by ','
+ example: 14:0,Timidity
+ """
+ portlist = []
+ if portspec == None:
+ return portlist
+ ports = portspec.split(',')
+ for port in ports:
+ try:
+ client, port = sequencer.parse_address(port)
+ portlist.append((client, port))
+ except SequencerError, e:
+ fatal("Failed to parse port %s - %s", port, e)
+ return portlist
+
+
+def create_source_port(sequencer):
+ try :
+ port = sequencer.create_simple_port(name = 'aplaymidi.py',
+ type = SEQ_PORT_TYPE_MIDI_GENERIC \
+ | SEQ_PORT_TYPE_APPLICATION,
+ caps = SEQ_PORT_CAP_NONE)
+ return port
+ except SequencerError, e:
+ fatal("Failed to create port - %s", e)
+
+
+def create_queue(sequencer):
+ try:
+ queue = sequencer.create_queue(name = 'aplaymidi')
+ return queue
+ except SequencerError, e:
+ fatal("Failed to create queue - %s", e)
+
+
+def connect_ports(sequencer, port_id, ports):
+ client_id = sequencer.client_id
+ for client, port in ports:
+ sequencer.connect_ports((client_id, port_id), (client, port))
+
+
+def read_byte(file):
+ """ read a single byte
+ raises SMFError if end of file was detected
+ """
+ s = file.read(1)
+ if s == '':
+ raise SMFError('End of file reached at position %d' % file.tell())
+ return struct.unpack('B', s)[0]
+
+
+def read_32_le(file):
+ """ reads a little-endian 32-bit integer """
+ value = 0
+ for p in (0, 8, 16, 24):
+ c = read_byte(file)
+ value |= c << p
+ return value
+
+
+def read_id(file):
+ """ reads a 4-char identifier """
+ return file.read(4)
+
+
+def read_int(file, bytes):
+ """ reads a fixed-size big-endian number """
+ value = 0
+ while bytes > 0:
+ c = read_byte(file)
+ value = (value << 8) | c
+ bytes -= 1
+ return value
+
+
+def read_var(file):
+ """ reads a variable-length number """
+ c = read_byte(file)
+ value = c & 0x7f
+ if c & 0x80:
+ c = read_byte(file)
+ value = (value << 7) | (c & 0x7f)
+ if c & 0x80:
+ c = read_byte(file)
+ value = (value << 7) | (c & 0x7f)
+ if c & 0x80:
+ c = read_byte(file)
+ value = (value << 7) | (c & 0x7f)
+ if c & 0x80:
+ raise SMFError('Invalid variable-length number at
file position %d' % file.tell())
+ return value
+
+def skip(file, bytes):
+ """ skip the specified number of bytes """
+ file.read(bytes)
+
+
+def read_track(file, chunk_len, ports, smtpe_timing):
+ """ reads one complete track from the file """
+
+ tick = 0
+ last_cmd = 0
+ port = 0
+ typemap = {}
+ typemap[0x8] = SEQ_EVENT_NOTEOFF
+ typemap[0x9] = SEQ_EVENT_NOTEON
+ typemap[0xa] = SEQ_EVENT_KEYPRESS
+ typemap[0xb] = SEQ_EVENT_CONTROLLER
+ typemap[0xc] = SEQ_EVENT_PGMCHANGE
+ typemap[0xd] = SEQ_EVENT_CHANPRESS
+ typemap[0xe] = SEQ_EVENT_PITCHBEND
+
+ eventlist = []
+
+ track_end = file.tell() + chunk_len
+ while file.tell() < track_end:
+ delta_ticks = read_var(file)
+ if delta_ticks < 0:
+ break
+ tick += delta_ticks
+
+ c = read_byte(file)
+
+ if c < 0:
+ break
+
+ if c & 0x80:
+ cmd = c
+ if cmd < 0xf0:
+ last_cmd = cmd
+ else:
+ # running status
+ cmd = last_cmd
+ file.seek(file.tell() - 1)
+ if not cmd:
+ break
+
+
+ s = cmd >> 4
+ if s >= 0x8 and s <= 0xa:
+ event = SeqEvent(type=typemap[s])
+ event.dest = ports[port]
+ event.time = tick
+ event.set_data({'note.channel' : cmd & 0x0f,
+ 'note.note' : read_byte(file) & 0x7f,
+ 'note.velocity' : read_byte(file) & 0x7f
+ })
+ eventlist.append(event)
+ elif s == 0xb or s == 0xe:
+ event = SeqEvent(type=typemap[s])
+ event.dest = ports[port]
+ event.time = tick
+ event.set_data({'control.channel' : cmd & 0x0f,
+ 'control.param' : read_byte(file) & 0x7f,
+ 'control.value' : read_byte(file) & 0x7f
+ })
+ eventlist.append(event)
+ elif s == 0xc or s == 0xd:
+ event = SeqEvent(type=typemap[s])
+ event.dest = ports[port]
+ event.time = tick
+ event.set_data({'control.channel' : cmd & 0x0f,
+ 'control.value' : read_byte(file) & 0x7f
+ })
+ eventlist.append(event)
+ elif s == 0xf:
+ if cmd == 0xf0 or cmd == 0xf7:
+ # sysex
+ l = read_var(file)
+ if l < 0:
+ break
+ if cmd == 0xf0:
+ l += 1
+ event = SeqEvent(type=SEQ_EVENT_SYSEX)
+ event.dest = ports[port]
+ event.time = tick
+ sysexdata = []
+ if cmd == 0xf0:
+ sysexdata.append(0xf0)
+ while len(sysexdata) < l:
+ sysexdata.append(read_byte(file))
+ event.set_data({'ext' : sysexdata})
+ eventlist.append(event)
+ elif cmd == 0xff:
+ c = read_byte(file)
+ l = read_var(file)
+ if l < 0:
+ break
+ if c == 0x21:
+ # port number
+ port = read_byte() % len(ports)
+ skip(file, l - 1)
+ elif c == 0x2f:
+ # end track
+ track_endtick = tick
+ skip(file, track_end - file.tell())
+ return track_endtick, eventlist
+ elif c == 0x51:
+ # tempo
+ if l < 3:
+ break
+ if smtpe_timing:
+ skip(file, l)
+ else:
+ event = SeqEvent(type=SEQ_EVENT_TEMPO)
+ event.dest = (SEQ_CLIENT_SYSTEM, SEQ_PORT_SYSTEM_TIMER)
+ event.time = tick
+ tempo = read_byte(file) << 16
+ tempo |= read_byte(file) << 8
+ tempo |= read_byte(file)
+ event.set_data({'queue.param.value' : tempo})
+ eventlist.append(event)
+ skip(file, l - 3)
+ else:
+ # ignore all other meta events
+ skip(file, l)
+ else:
+ break
+ else:
+ break
+
+ raise SMFError('Invalid MIDI data at file position (%d)' % file.tell())
+
+def read_smf(file, ports):
+ """ reads an entire MIDI file """
+
+ tempo = 0
+ ppq = 0
+ tracks = []
+
+
+ header_len = read_int(file, 4)
+ if header_len < 6:
+ raise SMFError('Invalid header_len: %d' % header_len)
+
+ type = read_int(file, 2)
+ if type != 0 and type != 1:
+ raise SMFError('Not supported type: %d' % type)
+
+ num_tracks = read_int(file, 2)
+ if num_tracks < 1 or num_tracks > 1000:
+ raise SMFError('Invalid number of tracks: %d' % num_tracks)
+
+ time_division = read_int(file, 2)
+ if time_division < 0:
+ raise SMFError('Invalid time division: %d' % time_division)
+
+ smtpe_timing = time_division & 0x8000
+
+ if not smtpe_timing:
+ # time division is ticks per quarter
+ tempo = 500000
+ ppq = time_division
+ else:
+ i = 0x80 - ((time_division >>8) & 0x7f)
+ time_division &= 0xff
+ if i == 24:
+ tempo = 500000
+ ppq = 12 * time_division
+ elif i == 25:
+ tempo = 400000
+ ppq = 10 * time_division
+ elif i == 29:
+ tempo = 100000000
+ ppq = 2997 * time_division
+ elif i == 30:
+ tempo = 500000
+ ppq = 15 * time_division
+ else:
+ raise SMFError('Invalid number of SMPTE frames per second (%d)'
+ % i)
+
+ # read tracks
+ while num_tracks > 0:
+ # search for MTrk chunk
+ while True:
+ id = read_id(file)
+ chunk_len = read_int(file, 4)
+ if chunk_len < 0 or chunk_len >= 0x10000000:
+ raise SMFError('Invalid chunk length %d' % chunk_len)
+ if id == 'MTrk':
+ break
+ skip(file, chunk_len)
+ trackevents = read_track(file, chunk_len, ports, smtpe_timing)
+ tracks.append(trackevents)
+ num_tracks -= 1
+
+ return tempo, ppq, tracks
+
+def read_riff(file, ports):
+ """ reads an entire RIFF file """
+
+ raise NotImplementedError("Sorry, I couldn't find any RIFF midi
file to implement this! -- Aldrin Martoq")
+
+
+def play(sequencer, filename, end_delay, source_port, queue, ports):
+ file = sys.stdin
+ ok = None
+ if filename != '-':
+ try:
+ file = open(filename, 'rb')
+ except IOError, e:
+ fatal("Cannot open %s - %s", filename, e)
+
+ id = read_id(file)
+ try:
+ if id == 'MThd':
+ ok = read_smf(file, ports)
+ elif id == 'RIFF':
+ ok = read_riff(file, ports)
+ else:
+ raise SMFError('unrecognized id')
+ except SMFError, e:
+ errormsg("%s is not a Standard MIDI File - %s", filename, e)
+
+ # now play!
+ tempo, ppq, tracks = ok
+ sequencer.queue_tempo(queue, tempo, ppq)
+ sequencer.start_queue(queue)
+
+ # add all events from tracks and sort them based on track, then on time
+ itrack = 0
+ allevents = []
+ for track in tracks:
+ endtick, eventlist = track
+ for event in eventlist:
+ d = {'itrack' : itrack, 'event' : event, 'time' : event.time}
+ allevents.append(d)
+ itrack += 1
+ def compare(x, y):
+ ret = x['time'] - y['time']
+ if ret == 0:
+ ret = x['itrack'] - y['itrack']
+ return ret
+ allevents.sort(compare)
+ max_tick = allevents[-1]['time']
+
+ for d in allevents:
+ event = d['event']
+ event.source = (0, 0)
+ event.queue = queue
+ if event.type == SEQ_EVENT_TEMPO:
+ event.set_data({'queue.queue' : queue})
+ sequencer.output_event(event)
+
+ # schedule queue stop at end of song
+ event = SeqEvent(SEQ_EVENT_STOP)
+ event.source = (0, 0)
+ event.queue = queue
+ event.time = max_tick
+ event.dest = (SEQ_CLIENT_SYSTEM, SEQ_PORT_SYSTEM_TIMER)
+ event.set_data({'queue.queue' : queue})
+ sequencer.output_event(event)
+
+ # make sure that the sequencer sees all our events
+ sequencer.drain_output()
+ sequencer.sync_output_queue()
+
+ time.sleep(end_delay)
+
+ if file != sys.stdin:
+ file.close()
+
+
+
+def list_ports():
+ sequencer = init_seq()
+ print " Port Client name Port name";
+ clientports = sequencer.connection_list()
+ for connections in clientports:
+ clientname, clientid, connectedports = connections
+ for port in connectedports:
+ portname, portid, connections = port
+ portinfo = sequencer.get_port_info(portid, clientid)
+ type = portinfo['type']
+ caps = portinfo['capability']
+ if type & SEQ_PORT_TYPE_MIDI_GENERIC and \
+ caps & (SEQ_PORT_CAP_WRITE | SEQ_PORT_CAP_SUBS_WRITE):
+ print "%3d:%-3d %-32.32s %s" % (clientid, portid,
clientname, portname)
+
+def usage():
+ print "Usage: %s -p client:port[,...] [-d delay] midifile ...\n" \
+ "-h, --help this help\n" \
+ "-V, --version print current version\n" \
+ "-l, --list list all possible output ports\n" \
+ "-p, --port=client:port,... set port(s) to play to\n" \
+ "-d, --delay=seconds delay after song ends\n" % (sys.argv[0])
+
+def version():
+ print "aplaymidi.py asoundlib version %s" % (SEQ_LIB_VERSION_STR)
+
+
+def main():
+ sequencer = init_seq()
+ ports = []
+ end_delay = 2
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hVlp:d:", ["help",
"version", "list", "port=", "delay="])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-V", "--version"):
+ version()
+ sys.exit(0)
+ elif o in ("-l", "--list"):
+ list_ports()
+ sys.exit(0)
+ elif o in ("-p", "--port"):
+ ports = parse_ports(sequencer, a)
+ elif o in ("-d", "--delay"):
+ end_delay = int(a)
+
+ if len(ports) < 1:
+ ports = parse_ports(sequencer, os.getenv('ALSA_OUTPUT_PORTS'))
+ if len(ports) < 1:
+ fatal("Please specify at least one port with --port.")
+
+ if len(args) < 1:
+ fatal("Please specify a file to play.")
+
+ source_port = create_source_port(sequencer)
+ queue = create_queue(sequencer)
+ connect_ports(sequencer, source_port, ports)
+
+ for filename in args:
+ play(sequencer, filename, end_delay, source_port, queue, ports)
+
+
+if __name__ == '__main__':
+ main()
diff -r 02b11d9f243d test/aseqdump.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aseqdump.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,193 @@
+#! /usr/bin/python
+
+# aseqdump.py -- python port of aplaymidi
+# Copyright (C) 2008 Aldrin Martoq <amartoq at dcc.uchile.cl>
+#
+# Based on code from aseqdump.c, from ALSA project
+# Copyright (C) 2005 Clemens Ladisch <clemens at ladisch.de>
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+import sys
+sys.path.insert(0, '../pyalsa')
+
+import getopt
+import os
+import struct
+import alsaseq
+import traceback
+import time
+from alsaseq import *
+
+def errormsg(msg, *args):
+ """ prints an error message to stderr """
+ sys.stderr.write(msg % args)
+ sys.stderr.write('\n')
+ traceback.print_exc(file=sys.stderr)
+
+
+def fatal(msg, *args):
+ """ prints an error message to stderr, and dies """
+ errormsg(msg, *args)
+ sys.exit(1)
+
+
+def init_seq():
+ """ opens an alsa sequencer """
+ try:
+ sequencer = Sequencer(name = 'default',
+ clientname = 'aseqdump.py',
+ streams = SEQ_OPEN_DUPLEX,
+ mode = SEQ_BLOCK)
+ return sequencer
+ except SequencerError, e:
+ fatal("open sequencer: %e", e)
+
+
+def parse_ports(sequencer, portspec):
+ """ parses one or more port addresses from the string, separated by ','
+ example: 14:0,Timidity
+ """
+ portlist = []
+ if portspec == None:
+ return portlist
+ ports = portspec.split(',')
+ for port in ports:
+ try:
+ client, port = sequencer.parse_address(port)
+ portlist.append((client, port))
+ except SequencerError, e:
+ fatal("Failed to parse port %s - %s", port, e)
+ return portlist
+
+
+def create_source_port(sequencer):
+ try :
+ port = sequencer.create_simple_port(name = 'aseqdump.py',
+ type = SEQ_PORT_TYPE_MIDI_GENERIC
+ | SEQ_PORT_TYPE_APPLICATION,
+ caps = SEQ_PORT_CAP_WRITE
+ | SEQ_PORT_CAP_SUBS_WRITE)
+ return port
+ except SequencerError, e:
+ fatal("Failed to create port - %s", e)
+
+
+def connect_ports(sequencer, port_id, ports):
+ client_id = sequencer.client_id
+ for client, port in ports:
+ sequencer.connect_ports((client, port),(client_id, port_id))
+
+def dump_event(event):
+ print "%3d:%-3d" % ((event.source)[0], (event.source)[1]),
+ type = event.type
+ data = event.get_data()
+ if type == SEQ_EVENT_NOTEON:
+ print "Note on %2d %3d %3d" % \
+ (data['note.channel'], data['note.note'], data['note.velocity'])
+ elif type == SEQ_EVENT_NOTEOFF:
+ print "Note off %2d %3d %3d" % \
+ (data['note.channel'], data['note.note'], data['note.velocity'])
+ elif type == SEQ_EVENT_KEYPRESS:
+ print "Polyphonic aftertouch %2d %3d %3d" % \
+ (data['note.channel'], data['note.note'], data['note.velocity'])
+ elif type == SEQ_EVENT_CONTROLLER:
+ print "Control change %2d %3d %3d" % \
+ (data['control.channel'], data['control.param'],
data['control.value'])
+ elif type == SEQ_EVENT_PGMCHANGE:
+ print "Program change %2d %3d" % \
+ (data['control.channel'], data['control.value'])
+ else:
+ print "Event type %d" % type
+
+def list_ports():
+ sequencer = init_seq()
+ print " Port Client name Port name";
+ clientports = sequencer.connection_list()
+ for connections in clientports:
+ clientname, clientid, connectedports = connections
+ for port in connectedports:
+ portname, portid, connections = port
+ portinfo = sequencer.get_port_info(portid, clientid)
+ caps = portinfo['capability']
+ if caps & (SEQ_PORT_CAP_READ | SEQ_PORT_CAP_SUBS_READ):
+ print "%3d:%-3d %-32.32s %s" % (clientid, portid,
clientname, portname)
+
+def usage():
+ print "Usage: %s [options]\n" \
+ "\nAvailable options:\n" \
+ "-h, --help this help\n" \
+ "-V, --version show version\n" \
+ "-l, --list list input ports\n" \
+ "-p, --port=client:port,... source port(s)\n" \
+ % (sys.argv[0])
+
+def version():
+ print "aseqdump.py asoundlib version %s" % (SEQ_LIB_VERSION_STR)
+
+
+def main():
+ sequencer = init_seq()
+ ports = []
+ end_delay = 2
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hVlp:", ["help",
"version", "list", "port="])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-V", "--version"):
+ version()
+ sys.exit(0)
+ elif o in ("-l", "--list"):
+ list_ports()
+ sys.exit(0)
+ elif o in ("-p", "--port"):
+ ports = parse_ports(sequencer, a)
+ elif o in ("-d", "--delay"):
+ end_delay = int(a)
+
+ source_port = create_source_port(sequencer)
+ connect_ports(sequencer, source_port, ports)
+
+ sequencer.mode = SEQ_NONBLOCK
+
+ if len(ports) > 0:
+ print "Waiting for data.",
+ else:
+ print "Waiting for data at port %d:0." % sequencer.client_id,
+
+ print "Press Ctrl+C to end."
+ print "Source_ Event_________________ Ch _Data__"
+
+ while True:
+ try:
+ eventlist = sequencer.receive_events(timeout=10069, maxevents = 1)
+ for event in eventlist:
+ dump_event(event)
+ except KeyboardInterrupt:
+ pass
+ break
+
+
+
+if __name__ == '__main__':
+ main()
diff -r 02b11d9f243d test/seqtest1.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/seqtest1.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,189 @@
+#! /usr/bin/python
+# Sample code for pyalsa Sequencer binding
+# by Aldrin Martoq <amartoq at dcc.uchile.cl>
+# version 2008012401 (UTC: 1201153962 secs since the epoch)
+#
+# This code is in the public domain,
+# use it as base for creating your pyalsa
+# sequencer application.
+
+import sys
+sys.path.insert(0, '../pyalsa')
+del sys
+from alsamemdebug import debuginit, debug, debugdone
+import alsaseq
+
+
+def dump_portinfo(dict):
+ def dl(dict, key):
+ if dict.has_key(key):
+ return "'" + str(dict[key]) + "'"
+ return "N/A"
+ def da(dict, key, search):
+ tmp = None
+ if dict.has_key(key):
+ for k in search:
+ if k & dict[key]:
+ if tmp == None:
+ tmp = str(search[k])
+ else:
+ tmp += " " + str(search[k])
+ if tmp == None:
+ tmp = "UNKNOWN(%d)" % (dict[key])
+ else:
+ tmp = "N/A"
+ return tmp
+
+ return "name=%s capability=%s type=%s" % (dl(dict, 'name'),
da(dict, 'capability', alsaseq._dportcap), da(dict, 'type',
alsaseq._dporttype))
+
+def dump_list(connections, simple=True):
+ for clientports in connections:
+ clientname, clientid, portlist = clientports
+ print " client: %3d %s" % (clientid, clientname),
+ if not simple:
+ clientinfo = sequencer.get_client_info(clientid)
+ print "\t[%s]" % clientinfo
+ else:
+ print
+ for port in portlist:
+ portname, portid, connections = port
+ print " port: %3d:%-2d +-%s" % (clientid, portid, portname),
+ if not simple:
+ portinfo = sequencer.get_port_info(portid, clientid)
+ print "\t[%s]" % (dump_portinfo(portinfo))
+ else:
+ print
+ readconn, writeconn = connections
+ for c,p,i in readconn:
+ if not simple:
+ print " connection to: %d:%d %s" % (c,p, i)
+ else:
+ print " connection to: %d:%d" % (c,p)
+ for c,p,i in writeconn:
+ if not simple:
+ print " connection to: %d:%d %s" % (c,p, i)
+ else:
+ print " connection to: %d:%d" % (c,p)
+
+
+debuginit()
+
+print "01:Creating Sequencer =============================="
+sequencer = alsaseq.Sequencer()
+# other examples:
+# sequencer = alsaseq.Sequencer("hw", "myfancyapplication",
alsaseq.SEQ_OPEN_INPUT, alsaseq.SEQ_BLOCK)
+# sequencer = alsaseq.Sequencer(clientname='python-test',
streams=alsaseq.SEQ_OPEN_OUTPUT)
+print " sequencer: %s" % sequencer
+print " name: %s" % sequencer.name
+print " clientname: %s" % sequencer.clientname
+print " streams: %d (%s)" % (sequencer.streams, str(sequencer.streams))
+print " mode: %d (%s)" % (sequencer.mode, str(sequencer.mode))
+print " client_id: %s" % sequencer.client_id
+print
+
+print "02:Changing some parameters ========================"
+sequencer.clientname = 'pepito'
+sequencer.mode = alsaseq.SEQ_BLOCK
+print " clientname: %s" % sequencer.clientname
+print " mode: %d (%s)" % (sequencer.mode, str(sequencer.mode))
+print
+
+print "03:Creating simple port ============================"
+port_id = sequencer.create_simple_port("myport",
alsaseq.SEQ_PORT_TYPE_APPLICATION,alsaseq.SEQ_PORT_CAP_WRITE |
alsaseq.SEQ_PORT_CAP_SUBS_WRITE)
+print " port_id: %s" % port_id
+print
+
+print "04:Getting port info ==============================="
+port_info = sequencer.get_port_info(port_id)
+print " --> %s" % dump_portinfo(port_info)
+print " --> %s" % port_info
+print
+
+print "05:Retrieving clients and connections (as list) ===="
+connections = sequencer.connection_list()
+print " %s" % (connections)
+print
+
+print "06:Retrieving clients and connections (detailed) ==="
+connections = sequencer.connection_list()
+dump_list(connections, False)
+print
+
+print "07:Connecting 'arbitrary' ports... ================="
+source = (alsaseq.SEQ_CLIENT_SYSTEM, alsaseq.SEQ_PORT_SYSTEM_ANNOUNCE)
+dest = (sequencer.client_id, port_id)
+print "%s ---> %s" % (str(source), str(dest))
+sequencer.connect_ports(source, dest)
+print
+
+print "08:Retrieving clients and connections (simple) ====="
+connections = sequencer.connection_list()
+dump_list(connections)
+print
+
+print "09:Disconnecting previous 'arbitrary' port ========="
+print "%s -X-> %s" % (str(source), str(dest))
+sequencer.disconnect_ports(source, dest)
+print
+
+print "10:Retrieving clients and connections (simple) ====="
+connections = sequencer.connection_list()
+dump_list(connections)
+print
+
+print "11:Listing known streams constants ================="
+print "%s" % alsaseq._dstreams.values()
+print
+
+print "12:Listing known mode constants ===================="
+print "%s" % alsaseq._dmode.values()
+print
+
+print "13:Listing known queue constants ==================="
+print "%s" % alsaseq._dqueue.values()
+print
+
+print "14:Listing known client type constants ============="
+print "%s" % alsaseq._dclienttype.values()
+print
+
+print "15:Listing known port caps constants ==============="
+print "%s" % alsaseq._dportcap.values()
+print
+
+print "16:Listing known port types constants =============="
+print "%s" % alsaseq._dporttype.values()
+print
+
+print "17:Listing known event type constants =============="
+print "%s" % alsaseq._deventtype.values()
+print
+
+print "18:Listing known event timestamp constants ========="
+print "%s" % alsaseq._deventtimestamp.values()
+print
+
+print "19:Listing known event timemode constants =========="
+print "%s" % alsaseq._deventtimemode.values()
+print
+
+print "20:Listing known client addresses constants ========"
+print "%s" % alsaseq._dclient.values()
+print
+
+print "21:Listing known port addresses constants =========="
+print "%s" % alsaseq._dport.values()
+print
+
+
+print "98:Removing sequencer =============================="
+debug([sequencer])
+del sequencer
+print
+
+print "99:Listing sequencer (using new one) ==============="
+dump_list(alsaseq.Sequencer().connection_list())
+print
+
+debugdone()
+print "seqtest1.py done."
diff -r 02b11d9f243d test/seqtest2.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/seqtest2.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,62 @@
+#! /usr/bin/python
+# Sample code for pyalsa Sequencer binding
+# by Aldrin Martoq <amartoq at dcc.uchile.cl>
+# version 2008012401 (UTC: 1201153962 secs since the epoch)
+#
+# This code is in the public domain,
+# use it as base for creating your pyalsa
+# sequencer application.
+
+import sys
+sys.path.insert(0, '../pyalsa')
+
+import alsaseq
+import time
+from alsamemdebug import debuginit, debug, debugdone
+
+debuginit()
+
+seq = alsaseq.Sequencer()
+
+def dump(event):
+ print "event: %s" % event
+ print " ",
+ for attr in alsaseq.SeqEvent.__dict__:
+ if attr.startswith('is_'):
+ t = event.__getattribute__(attr)
+ if t:
+ print "%s" % attr,
+ print
+ data = event.get_data()
+ print " data=%s" % data
+
+print "sequencer: %s" % seq
+
+port_id = seq.create_simple_port('hola', alsaseq.SEQ_PORT_TYPE_APPLICATION,
+ alsaseq.SEQ_PORT_CAP_SUBS_READ |
alsaseq.SEQ_PORT_CAP_READ | alsaseq.SEQ_PORT_CAP_WRITE |
alsaseq.SEQ_PORT_CAP_SUBS_WRITE
+ )
+
+print "portid: %d" % port_id
+
+c=-2
+wait = 5000
+
+while True:
+ if c == -1:
+ src = (alsaseq.SEQ_CLIENT_SYSTEM,alsaseq.SEQ_PORT_SYSTEM_ANNOUNCE)
+ dest = (seq.client_id, port_id)
+ print 'connecting %s -> %s' % (src, dest)
+ seq.connect_ports(src, dest)
+ if c == 5:
+ break
+ print 'waiting %s...' % wait
+ events = seq.receive_events(wait)
+ for event in events:
+ c = 0
+ dump(event)
+ del event
+ c += 1
+
+debug([seq])
+
+debugdone()
diff -r 02b11d9f243d test/seqtest3.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/seqtest3.py Thu Jan 24 05:18:40 2008 -0300
@@ -0,0 +1,71 @@
+#! /usr/bin/python
+# Sample code for pyalsa Sequencer binding
+# by Aldrin Martoq <amartoq at dcc.uchile.cl>
+# version 2008012401 (UTC: 1201153962 secs since the epoch)
+#
+# This code is in the public domain,
+# use it as base for creating your pyalsa
+# sequencer application.
+
+import sys
+sys.path.insert(0, '../pyalsa')
+
+from alsaseq import *
+import time
+from alsamemdebug import debuginit, debug, debugdone
+
+debuginit()
+
+def findmidiport():
+ for connections in seq.connection_list():
+ cname, cid, ports = connections
+ # skip midi through
+ if cname == 'Midi Through':
+ continue
+ for port in ports:
+ pname, pid, pconns = port
+ pinfo = seq.get_port_info(pid, cid)
+ type = pinfo['type']
+ caps = pinfo['capability']
+ if type & SEQ_PORT_TYPE_MIDI_GENERIC and caps &
(SEQ_PORT_CAP_WRITE):
+ print "Using port: %s:%s" % (cname, pname)
+ return (cid, pid)
+ print "No midi port found -- install timidity or other software
synth for testing!"
+ sys.exit(0)
+
+# create sequencer
+seq = Sequencer()
+
+# find midi port
+cid, pid = findmidiport()
+
+# create a queue
+queue = seq.create_queue()
+seq.start_queue(queue)
+tempo, ppq = seq.queue_tempo(queue)
+print "tempo: %d ppq: %d" % (tempo, ppq)
+
+# play notes: DO RE MI FA SOL LA
+notes = [0x40, 0x42, 0x44, 0x45, 0x47, 0x49]
+event = SeqEvent(SEQ_EVENT_NOTE)
+for note in notes:
+ event.dest = (cid, pid)
+ event.queue = queue
+ event.time += ppq
+ event.set_data({'note.note' : note, 'note.velocity' : 64,
'note.duration' : ppq , 'note.off_velocity' : 64})
+ print 'event: %s %s' % (event, event.get_data())
+ seq.output_event(event)
+ seq.drain_output()
+ seq.sync_output_queue()
+
+# stop queue and delete queue
+seq.stop_queue(queue)
+seq.delete_queue(queue)
+
+debug([seq])
+
+# close sequencer
+del seq
+
+
+debugdone()
--
Aldrin Martoq
More information about the Alsa-devel
mailing list