10 //////////////////////////////////////////////////// PyJackClient
14 typedef std::map
<jack_port_t
*, PyJackPort
*> PortHandleMap
;
16 struct AsyncOperationInfo
18 enum OpCode
{ INVALID_OP
, PORT_REGISTERED
, PORT_UNREGISTERED
, PORTS_CONNECTED
, PORTS_DISCONNECTED
};
21 jack_port_id_t port
, port2
;
23 AsyncOperationInfo() { opcode
= INVALID_OP
; }
24 AsyncOperationInfo(OpCode _opcode
, jack_port_id_t _port
, jack_port_id_t _port2
= 0)
25 : opcode(_opcode
), port(_port
), port2(_port2
) {}
27 if (opcode
== PORT_REGISTERED
|| opcode
== PORT_UNREGISTERED
) return 1;
28 if (opcode
== PORTS_CONNECTED
|| opcode
== PORTS_DISCONNECTED
) return 2;
33 typedef std::list
<AsyncOperationInfo
> PortOperationList
;
38 jack_client_t
*client
;
39 PortHandleMap
*port_handle_map
;
40 pthread_mutex_t port_op_mutex
;
41 PortOperationList
*port_op_queue
;
44 static PyTypeObject jackclient_type
= {
45 PyObject_HEAD_INIT(NULL
)
47 "calfpytools.JackClient", /*tp_name*/
48 sizeof(PyJackClient
), /*tp_basicsize*/
58 static PyTypeObject jackport_type
= {
59 PyObject_HEAD_INIT(NULL
)
61 "calfpytools.JackPort", /*tp_name*/
62 sizeof(PyJackPort
), /*tp_basicsize*/
65 static void register_cb(jack_port_id_t port
, int registered
, void *arg
)
67 PyJackClient
*self
= (PyJackClient
*)arg
;
68 pthread_mutex_lock(&self
->port_op_mutex
);
69 self
->port_op_queue
->push_back(AsyncOperationInfo(registered
? AsyncOperationInfo::PORT_REGISTERED
: AsyncOperationInfo::PORT_UNREGISTERED
, port
));
70 pthread_mutex_unlock(&self
->port_op_mutex
);
73 static void connect_cb(jack_port_id_t port1
, jack_port_id_t port2
, int connected
, void *arg
)
75 PyJackClient
*self
= (PyJackClient
*)arg
;
76 pthread_mutex_lock(&self
->port_op_mutex
);
77 self
->port_op_queue
->push_back(AsyncOperationInfo(connected
? AsyncOperationInfo::PORTS_CONNECTED
: AsyncOperationInfo::PORTS_DISCONNECTED
, port1
, port2
));
78 pthread_mutex_unlock(&self
->port_op_mutex
);
81 static PyObject
*jackclient_open(PyJackClient
*self
, PyObject
*args
)
85 jack_status_t status
= (jack_status_t
)0;
87 if (!PyArg_ParseTuple(args
, "s|i:open", &name
, &options
))
90 self
->client
= jack_client_open(name
, (jack_options_t
)options
, &status
);
91 self
->port_handle_map
= new PortHandleMap
;
92 pthread_mutexattr_t attr
;
93 pthread_mutexattr_init(&attr
);
94 pthread_mutexattr_setprotocol(&attr
, PTHREAD_PRIO_INHERIT
);
95 pthread_mutex_init(&self
->port_op_mutex
, &attr
);
96 self
->port_op_queue
= new PortOperationList
;
98 jack_set_port_registration_callback(self
->client
, register_cb
, self
);
99 jack_set_port_connect_callback(self
->client
, connect_cb
, self
);
100 jack_activate(self
->client
);
102 return Py_BuildValue("i", status
);
105 static int jackclient_dealloc(PyJackPort
*self
)
109 PyObject_CallMethod((PyObject
*)self
, strdup("close"), NULL
);
110 assert(!self
->client
);
116 #define CHECK_CLIENT if (!self->client) { PyErr_SetString(PyExc_ValueError, "Client not opened"); return NULL; }
119 static PyObject
*jackclient_get_name(PyJackClient
*self
, PyObject
*args
)
121 if (!PyArg_ParseTuple(args
, ":get_name"))
126 return Py_BuildValue("s", jack_get_client_name(self
->client
));
129 static PyObject
*create_jack_port(PyJackClient
*client
, jack_port_t
*port
)
131 PortHandleMap::iterator it
= client
->port_handle_map
->find(port
);
132 if (it
!= client
->port_handle_map
->end())
134 Py_INCREF(it
->second
);
135 return Py_BuildValue("O", it
->second
);
139 PyObject
*cobj
= PyCObject_FromVoidPtr(port
, NULL
);
140 PyObject
*args
= Py_BuildValue("OO", client
, cobj
);
141 PyObject
*newobj
= _PyObject_New(&jackport_type
);
142 jackport_type
.tp_init(newobj
, args
, NULL
);
143 (*client
->port_handle_map
)[port
] = (PyJackPort
*)newobj
;
151 static PyObject
*jackclient_register_port(PyJackClient
*self
, PyObject
*args
)
153 const char *name
, *type
= JACK_DEFAULT_AUDIO_TYPE
;
154 unsigned long flags
= 0, buffer_size
= 0;
155 if (!PyArg_ParseTuple(args
, "s|sii:register_port", &name
, &type
, &flags
, &buffer_size
))
160 jack_port_t
*port
= jack_port_register(self
->client
, name
, type
, flags
, buffer_size
);
161 return create_jack_port(self
, port
);
164 static PyObject
*jackclient_get_port(PyJackClient
*self
, PyObject
*args
)
167 if (!PyArg_ParseTuple(args
, "s:get_port", &name
))
172 jack_port_t
*port
= jack_port_by_name(self
->client
, name
);
173 return create_jack_port(self
, port
);
176 static PyObject
*jackclient_get_cobj(PyJackClient
*self
, PyObject
*args
)
178 if (!PyArg_ParseTuple(args
, ":get_cobj"))
183 return PyCObject_FromVoidPtr((void *)self
->client
, NULL
);
186 static PyObject
*jackclient_get_ports(PyJackClient
*self
, PyObject
*args
)
188 const char *name
= NULL
, *type
= NULL
;
189 unsigned long flags
= 0;
190 if (!PyArg_ParseTuple(args
, "|ssi:get_ports", &name
, &type
, &flags
))
195 const char **p
= jack_get_ports(self
->client
, name
, type
, flags
);
196 PyObject
*res
= PyList_New(0);
200 for (const char **q
= p
; *q
; q
++)
202 PyList_Append(res
, PyString_FromString(*q
));
210 static PyObject
*jackclient_connect(PyJackClient
*self
, PyObject
*args
)
212 char *from_port
= NULL
, *to_port
= NULL
;
213 if (!PyArg_ParseTuple(args
, "ss:connect", &from_port
, &to_port
))
218 int result
= jack_connect(self
->client
, from_port
, to_port
);
229 PyErr_SetString(PyExc_RuntimeError
, "Connection error");
234 static PyObject
*create_jack_port_by_id(PyJackClient
*self
, jack_port_id_t id
)
236 return create_jack_port(self
, jack_port_by_id(self
->client
, id
));
239 static PyObject
*jackclient_get_message(PyJackClient
*self
, PyObject
*args
)
241 if (!PyArg_ParseTuple(args
, ":get_message"))
246 PyObject
*obj
= NULL
;
247 AsyncOperationInfo info
;
248 pthread_mutex_lock(&self
->port_op_mutex
);
249 if (self
->port_op_queue
->empty())
256 info
= self
->port_op_queue
->front();
257 self
->port_op_queue
->pop_front();
259 pthread_mutex_unlock(&self
->port_op_mutex
);
262 if (info
.argc() == 1)
263 obj
= Py_BuildValue("iO", info
.opcode
, create_jack_port_by_id(self
, info
.port
));
265 if (info
.argc() == 2)
266 obj
= Py_BuildValue("iOO", info
.opcode
, create_jack_port_by_id(self
, info
.port
), create_jack_port_by_id(self
, info
.port2
));
271 static PyObject
*jackclient_disconnect(PyJackClient
*self
, PyObject
*args
)
273 char *from_port
= NULL
, *to_port
= NULL
;
274 if (!PyArg_ParseTuple(args
, "ss:disconnect", &from_port
, &to_port
))
279 int result
= jack_disconnect(self
->client
, from_port
, to_port
);
287 PyErr_SetString(PyExc_RuntimeError
, "Disconnection error");
292 static PyObject
*jackclient_close(PyJackClient
*self
, PyObject
*args
)
294 if (!PyArg_ParseTuple(args
, ":close"))
299 jack_deactivate(self
->client
);
300 jack_client_close(self
->client
);
302 delete self
->port_handle_map
;
303 delete self
->port_op_queue
;
304 pthread_mutex_destroy(&self
->port_op_mutex
);
310 static PyMethodDef jackclient_methods
[] = {
311 {"open", (PyCFunction
)jackclient_open
, METH_VARARGS
, "Open a client"},
312 {"close", (PyCFunction
)jackclient_close
, METH_VARARGS
, "Close a client"},
313 {"get_name", (PyCFunction
)jackclient_get_name
, METH_VARARGS
, "Retrieve client name"},
314 {"get_port", (PyCFunction
)jackclient_get_port
, METH_VARARGS
, "Create port object from name of existing JACK port"},
315 {"get_ports", (PyCFunction
)jackclient_get_ports
, METH_VARARGS
, "Get a list of port names based on specified name, type and flag filters"},
316 {"register_port", (PyCFunction
)jackclient_register_port
, METH_VARARGS
, "Register a new port and return an object that represents it"},
317 {"get_cobj", (PyCFunction
)jackclient_get_cobj
, METH_VARARGS
, "Retrieve jack_client_t pointer for the client as CObject"},
318 {"get_message", (PyCFunction
)jackclient_get_message
, METH_VARARGS
, "Retrieve next port registration/connection message from the message queue"},
319 {"connect", (PyCFunction
)jackclient_connect
, METH_VARARGS
, "Connect two ports with given names"},
320 {"disconnect", (PyCFunction
)jackclient_disconnect
, METH_VARARGS
, "Disconnect two ports with given names"},
321 {NULL
, NULL
, 0, NULL
}
324 //////////////////////////////////////////////////// PyJackPort
326 static int jackport_init(PyJackPort
*self
, PyObject
*args
, PyObject
*kwds
)
328 PyJackClient
*client
= NULL
;
329 PyObject
*cobj
= NULL
;
331 if (!PyArg_ParseTuple(args
, "O!O:__init__", &jackclient_type
, &client
, &cobj
))
333 if (!PyCObject_Check(cobj
))
335 PyErr_SetString(PyExc_TypeError
, "Port constructor cannot be called explicitly");
340 self
->client
= client
;
341 self
->port
= (jack_port_t
*)PyCObject_AsVoidPtr(cobj
);
346 static int jackport_dealloc(PyJackPort
*self
)
348 // if not unregistered, decref (unregister decrefs automatically)
350 self
->client
->port_handle_map
->erase(self
->port
);
351 Py_DECREF(self
->client
);
357 #define CHECK_PORT_CLIENT if (!self->client || !self->client->client) { PyErr_SetString(PyExc_ValueError, "Client not opened"); return NULL; }
358 #define CHECK_PORT if (!self->port) { PyErr_SetString(PyExc_ValueError, "The port is not valid"); return NULL; }
360 static PyObject
*jackport_strrepr(PyJackPort
*self
, int quotes
)
365 int flags
= jack_port_flags(self
->port
);
366 int flags_io
= flags
& (JackPortIsInput
| JackPortIsOutput
);
367 return PyString_FromFormat("<calfpytools.JackPort, name=%s%s%s, flags=%s%s%s%s>",
369 jack_port_name(self
->port
),
371 (flags_io
== JackPortIsInput
) ? "in" : (flags_io
== JackPortIsOutput
? "out" : "?"),
372 flags
& JackPortIsPhysical
? "|physical" : "",
373 flags
& JackPortCanMonitor
? "|can_monitor" : "",
374 flags
& JackPortIsTerminal
? "|terminal" : "");
377 static PyObject
*jackport_str(PyJackPort
*self
)
379 return jackport_strrepr(self
, 0);
382 static PyObject
*jackport_repr(PyJackPort
*self
)
384 return jackport_strrepr(self
, 1);
387 static PyObject
*jackport_get_full_name(PyJackPort
*self
, PyObject
*args
)
389 if (!PyArg_ParseTuple(args
, ":get_full_name"))
395 return Py_BuildValue("s", jack_port_name(self
->port
));
398 static PyObject
*jackport_get_flags(PyJackPort
*self
, PyObject
*args
)
400 if (!PyArg_ParseTuple(args
, ":get_flags"))
406 return PyInt_FromLong(jack_port_flags(self
->port
));
409 static PyObject
*jackport_is_valid(PyJackPort
*self
, PyObject
*args
)
411 if (!PyArg_ParseTuple(args
, ":is_valid"))
414 return PyBool_FromLong(self
->client
&& self
->client
->client
&& self
->port
);
417 static PyObject
*jackport_is_mine(PyJackPort
*self
, PyObject
*args
)
419 if (!PyArg_ParseTuple(args
, ":is_mine"))
425 return PyBool_FromLong(self
->client
&& self
->client
->client
&& self
->port
&& jack_port_is_mine(self
->client
->client
, self
->port
));
428 static PyObject
*jackport_get_name(PyJackPort
*self
, PyObject
*args
)
430 if (!PyArg_ParseTuple(args
, ":get_name"))
436 return Py_BuildValue("s", jack_port_short_name(self
->port
));
439 static PyObject
*jackport_get_type(PyJackPort
*self
, PyObject
*args
)
441 if (!PyArg_ParseTuple(args
, ":get_type"))
447 return Py_BuildValue("s", jack_port_type(self
->port
));
450 static PyObject
*jackport_get_cobj(PyJackPort
*self
, PyObject
*args
)
452 if (!PyArg_ParseTuple(args
, ":get_cobj"))
458 return PyCObject_FromVoidPtr((void *)self
->port
, NULL
);
461 static PyObject
*jackport_get_aliases(PyJackPort
*self
, PyObject
*args
)
463 if (!PyArg_ParseTuple(args
, ":get_aliases"))
469 char buf1
[256], buf2
[256];
470 char *const aliases
[2] = { buf1
, buf2
};
471 int count
= jack_port_get_aliases(self
->port
, aliases
);
473 PyObject
*alist
= PyList_New(0);
474 for (int i
= 0; i
< count
; i
++)
475 PyList_Append(alist
, PyString_FromString(aliases
[i
]));
479 static PyObject
*jackport_get_connections(PyJackPort
*self
, PyObject
*args
)
481 if (!PyArg_ParseTuple(args
, ":get_aliases"))
487 const char **conns
= jack_port_get_all_connections(self
->client
->client
, self
->port
);
489 PyObject
*res
= PyList_New(0);
492 for (const char **p
= conns
; *p
; p
++)
493 PyList_Append(res
, PyString_FromString(*p
));
499 static PyObject
*jackport_set_name(PyJackPort
*self
, PyObject
*args
)
502 if (!PyArg_ParseTuple(args
, "s:set_name", &name
))
507 jack_port_set_name(self
->port
, name
);
509 return Py_BuildValue("s", jack_port_short_name(self
->port
));
512 static PyObject
*jackport_unregister(PyJackPort
*self
, PyObject
*args
)
514 if (!PyArg_ParseTuple(args
, ":unregister"))
519 PyJackClient
*client
= self
->client
;
521 client
->port_handle_map
->erase(self
->port
);
522 jack_port_unregister(self
->client
->client
, self
->port
);
532 static PyMethodDef jackport_methods
[] = {
533 {"unregister", (PyCFunction
)jackport_unregister
, METH_VARARGS
, "Unregister a port"},
534 {"is_valid", (PyCFunction
)jackport_is_valid
, METH_VARARGS
, "Checks if the port object is valid (registered)"},
535 {"is_mine", (PyCFunction
)jackport_is_mine
, METH_VARARGS
, "Checks if the port object is valid (registered)"},
536 {"get_full_name", (PyCFunction
)jackport_get_full_name
, METH_VARARGS
, "Retrieve full port name (including client name)"},
537 {"get_name", (PyCFunction
)jackport_get_name
, METH_VARARGS
, "Retrieve short port name (without client name)"},
538 {"get_type", (PyCFunction
)jackport_get_type
, METH_VARARGS
, "Retrieve port type name"},
539 {"get_flags", (PyCFunction
)jackport_get_flags
, METH_VARARGS
, "Retrieve port flags (defined in module, ie. calfpytools.JackPortIsInput)"},
540 {"set_name", (PyCFunction
)jackport_set_name
, METH_VARARGS
, "Set short port name"},
541 {"get_aliases", (PyCFunction
)jackport_get_aliases
, METH_VARARGS
, "Retrieve a list of port aliases"},
542 {"get_connections", (PyCFunction
)jackport_get_connections
, METH_VARARGS
, "Retrieve a list of ports the port is connected to"},
543 {"get_cobj", (PyCFunction
)jackport_get_cobj
, METH_VARARGS
, "Retrieve jack_port_t pointer for the port"},
544 {NULL
, NULL
, 0, NULL
}
548 //////////////////////////////////////////////////// calfpytools
550 static PyObject
*calfpytools_scan_ttl_file(PyObject
*self
, PyObject
*args
)
552 char *ttl_name
= NULL
;
553 if (!PyArg_ParseTuple(args
, "s:scan_ttl_file", &ttl_name
))
556 std::ifstream
istr(ttl_name
, std::ifstream::in
);
557 TTLLexer
lexer(&istr
);
562 static PyObject
*calfpytools_scan_ttl_string(PyObject
*self
, PyObject
*args
)
565 if (!PyArg_ParseTuple(args
, "s:scan_ttl_string", &data
))
568 std::string data_str
= data
;
569 std::stringstream
str(data_str
);
570 TTLLexer
lexer(&str
);
575 static PyMethodDef module_methods
[] = {
576 {"scan_ttl_file", calfpytools_scan_ttl_file
, METH_VARARGS
, "Scan a TTL file, return a list of token tuples"},
577 {"scan_ttl_string", calfpytools_scan_ttl_string
, METH_VARARGS
, "Scan a TTL string, return a list of token tuples"},
578 {NULL
, NULL
, 0, NULL
}
581 PyMODINIT_FUNC
initcalfpytools()
583 jackclient_type
.tp_new
= PyType_GenericNew
;
584 jackclient_type
.tp_flags
= Py_TPFLAGS_DEFAULT
;
585 jackclient_type
.tp_doc
= "JACK client object";
586 jackclient_type
.tp_methods
= jackclient_methods
;
587 jackclient_type
.tp_dealloc
= (destructor
)jackclient_dealloc
;
588 if (PyType_Ready(&jackclient_type
) < 0)
591 jackport_type
.tp_new
= PyType_GenericNew
;
592 jackport_type
.tp_flags
= Py_TPFLAGS_DEFAULT
;
593 jackport_type
.tp_doc
= "JACK port object (created by client)";
594 jackport_type
.tp_methods
= jackport_methods
;
595 jackport_type
.tp_init
= (initproc
)jackport_init
;
596 jackport_type
.tp_dealloc
= (destructor
)jackport_dealloc
;
597 jackport_type
.tp_str
= (reprfunc
)jackport_str
;
598 jackport_type
.tp_repr
= (reprfunc
)jackport_repr
;
599 if (PyType_Ready(&jackport_type
) < 0)
602 PyObject
*mod
= Py_InitModule3("calfpytools", module_methods
, "Python utilities for Calf");
603 Py_INCREF(&jackclient_type
);
604 Py_INCREF(&jackport_type
);
605 PyModule_AddObject(mod
, "JackClient", (PyObject
*)&jackclient_type
);
606 PyModule_AddObject(mod
, "JackPort", (PyObject
*)&jackport_type
);
608 PyModule_AddObject(mod
, "JackPortIsInput", PyInt_FromLong(JackPortIsInput
));
609 PyModule_AddObject(mod
, "JackPortIsOutput", PyInt_FromLong(JackPortIsOutput
));
610 PyModule_AddObject(mod
, "JackPortIsPhysical", PyInt_FromLong(JackPortIsPhysical
));
611 PyModule_AddObject(mod
, "JackPortCanMonitor", PyInt_FromLong(JackPortCanMonitor
));
612 PyModule_AddObject(mod
, "JackPortIsTerminal", PyInt_FromLong(JackPortIsTerminal
));
613 PyModule_AddObject(mod
, "JACK_DEFAULT_AUDIO_TYPE", PyString_FromString(JACK_DEFAULT_AUDIO_TYPE
));
614 PyModule_AddObject(mod
, "JACK_DEFAULT_MIDI_TYPE", PyString_FromString(JACK_DEFAULT_MIDI_TYPE
));