[SCM] python-pyo/master: Imported Upstream version 0.7.6+git20150826.1f0dc1aa93
tiago at users.alioth.debian.org
tiago at users.alioth.debian.org
Wed Aug 26 11:03:07 UTC 2015
The following commit has been merged in the master branch:
commit 8d9a1420ee483c0fcd39808871d8752556974af9
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date: Wed Aug 26 00:51:27 2015 -0400
Imported Upstream version 0.7.6+git20150826.1f0dc1aa93
diff --git a/ChangeLog b/ChangeLog
index 73619a4..c933e3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-08-25 belangeo <belangeo at gmail.com>
+
+ * Added new objects: MidiListener and OscListener (self-contained MIDI and OSC servers).
+
-------------------------------------------------------------------------------------
2015-07-27 belangeo <belangeo at gmail.com>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..49b1075
--- /dev/null
+++ b/README.md
@@ -0,0 +1,95 @@
+# Pyo - Python DSP module #
+
+pyo is a Python module written in C to help digital signal processing script
+creation.
+
+pyo is a Python module containing classes for a wide variety of audio signal
+processing types. With pyo, user will be able to include signal processing
+chains directly in Python scripts or projects, and to manipulate them in real
+time through the interpreter. Tools in pyo module offer primitives, like
+mathematical operations on audio signal, basic signal processing (filters,
+delays, synthesis generators, etc.), but also complex algorithms to create
+sound granulation and others creative audio manipulations. pyo supports OSC
+protocol (Open Sound Control), to ease communications between softwares, and
+MIDI protocol, for generating sound events and controlling process parameters.
+pyo allows creation of sophisticated signal processing chains with all the
+benefits of a mature, and widely used, general programming language.
+
+Systems : OS X (10.5 -> 10.10), linux, Windows (XP, Vista, 7, 8)
+
+Python versions : 2.6, 2.7
+
+[PYO OFFICAL WEB SITE](http://ajaxsoundstudio.com/pyo/)
+
+**Download latest binaries, source release and documentation** [HERE](http://ajaxsoundstudio.com/pyo/)!
+
+
+How to get pyo running from sources on OS X and linux:
+[INSTALL Instructions](http://ajaxsoundstudio.com/pyodoc/compiling.html)
+
+pyo was awarded **second prize** in the [Lomus 2012](http://concours.afim-asso.org/2012/) Free Software Competition.
+
+## Radio Pyo ##
+
+If you want to listen to scripts rendered in real-time, just connect to [Radio Pyo](http://radiopyo.acaia.ca/) !
+
+You want to have your script played on the radio ? Follow the instructions on this
+[post](http://acaia.ca/~tiago/posts/introducing-radio-pyo-live-music-in-python/) !
+
+## Softwares using pyo as audio engine ##
+
+[Zyne](https://github.com/belangeo/zyne) : A modular soft synthesizer.
+
+[Soundgrain](http://ajaxsoundstudio.com/software/soundgrain/) : A graphical interface where users can draw and edit trajectories to control granular sound synthesis.
+
+[Cecilia 5](http://ajaxsoundstudio.com/software/cecilia/) : An audio signal processing environment.
+
+[PsychoPy](http://www.psychopy.org/) : An open-source application to allow the presentation of stimuli and collection of data for a wide range of neuroscience, psychology and psychophysics experiments.
+
+## Examples ##
+
+pyo is fully integrated to Python and very simple to use.
+
+Play a sound:
+
+```
+>>> from pyo import *
+>>> s = Server().boot()
+>>> s.start()
+>>> sf = SfPlayer("path/to/your/sound.aif", speed=1, loop=True).out()
+```
+
+Granulate an audio buffer:
+
+```
+>>> s = Server().boot()
+>>> s.start()
+>>> snd = SndTable("path/to/your/sound.aif")
+>>> env = HannTable()
+>>> pos = Phasor(freq=snd.getRate()*.25, mul=snd.getSize())
+>>> dur = Noise(mul=.001, add=.1)
+>>> g = Granulator(snd, env, [1, 1.001], pos, dur, 24, mul=.1).out()
+```
+
+Generate melodies:
+
+```
+>>> s = Server().boot()
+>>> s.start()
+>>> wav = SquareTable()
+>>> env = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
+>>> met = Metro(.125, 12).play()
+>>> amp = TrigEnv(met, table=env, mul=.1)
+>>> pit = TrigXnoiseMidi(met, dist='loopseg', x1=20, scale=1, mrange=(48,84))
+>>> out = Osc(table=wav, freq=pit, mul=amp).out()
+```
+
+## Donation ##
+
+This project is developed by Olivier Bélanger on his free time to provide a
+fully integrated Python dsp module for sound exploration and music composition.
+If you feel this project is useful to you and want to support it and it's
+future development please consider donating money. I only ask for a small
+donation, but of course I appreciate any amount.
+
+[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9CA99DH6ES3HA)
\ No newline at end of file
diff --git a/doc-sphinx/source/api/classes/index.rst b/doc-sphinx/source/api/classes/index.rst
index cf8a2f2..2f5052d 100644
--- a/doc-sphinx/source/api/classes/index.rst
+++ b/doc-sphinx/source/api/classes/index.rst
@@ -5,6 +5,7 @@ Classes by category
:maxdepth: 2
server
+ listener
_core
analysis
arithmetic
diff --git a/doc-sphinx/source/api/classes/index.rst b/doc-sphinx/source/api/classes/listener.rst
similarity index 96%
copy from doc-sphinx/source/api/classes/index.rst
copy to doc-sphinx/source/api/classes/listener.rst
index cf8a2f2..2f5052d 100644
--- a/doc-sphinx/source/api/classes/index.rst
+++ b/doc-sphinx/source/api/classes/listener.rst
@@ -5,6 +5,7 @@ Classes by category
:maxdepth: 2
server
+ listener
_core
analysis
arithmetic
diff --git a/include/pyomodule.h b/include/pyomodule.h
index 32a3f3c..bc385fa 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -201,6 +201,8 @@
#include "externalmodule.h"
#endif
+extern PyTypeObject MidiListenerType;
+extern PyTypeObject OscListenerType;
extern PyTypeObject SineType;
extern PyTypeObject SineLoopType;
extern PyTypeObject FmType;
diff --git a/include/servermodule.h b/include/servermodule.h
index 91e9d22..761529c 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -91,6 +91,7 @@ typedef struct {
int midi_output;
int withPortMidi;
int withPortMidiOut;
+ int midiActive;
int server_started;
int server_stopped; /* for fadeout */
int server_booted;
diff --git a/pyo.py b/pyo.py
index 8c2eb72..187247a 100644
--- a/pyo.py
+++ b/pyo.py
@@ -43,6 +43,7 @@ from pyolib.pattern import *
import pyolib.randoms as randoms
from pyolib.randoms import *
from pyolib.server import *
+from pyolib.listener import *
import pyolib.players as players
from pyolib.players import *
import pyolib.tableprocess as tableprocess
@@ -117,6 +118,8 @@ OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input',
'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb'])}},
'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
'Server': [],
+ 'MidiListener': [],
+ 'OscListener': [],
'Stream': [],
'TableStream': []}
diff --git a/pyolib/listener.py b/pyolib/listener.py
new file mode 100644
index 0000000..7cb9521
--- /dev/null
+++ b/pyolib/listener.py
@@ -0,0 +1,106 @@
+from _core import *
+import time
+import threading
+
+class MidiListener(threading.Thread):
+ """
+ Self-contained midi listener thread.
+
+ This object allows to setup a Midi server that is independent
+ of the audio server (mainly to be able to receive Midi data even
+ when the audio server is stopped). Although it runs in a separated
+ thread, the same device can't be used by this object and the audio
+ server at the same time. It is adviced to call the deactivateMidi()
+ method on the audio server to avoid conflicts.
+
+ :Parent: threading.Thread
+
+ :Args:
+
+ function : Python function (can't be a list)
+ Function that will be called when a new midi event is available.
+ This function is called with the incoming midi data as
+ arguments. The signature of the function must be:
+
+ def myfunc(status, data1, data2)
+
+ mididev : int, optional
+ Sets the midi input device (see `pm_list_devices()` for the
+ available devices). The default, -1, means the system default
+ device. A number greater than the highest portmidi device index
+ will opened all available input devices.
+
+ >>> s = Server().boot()
+ >>> s.deactivateMidi()
+ >>> def midicall(status, data1, data2):
+ ... print status, data1, data2
+ >>> listen = MidiListener(midicall, 5)
+ >>> listen.start()
+
+ """
+ def __init__(self, function, mididev=-1):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self._function = WeakMethod(function)
+ self._mididev = mididev
+ self._listener = MidiListener_base(self._function, self._mididev)
+
+ def run(self):
+ """
+ Starts the process. The thread runs as daemon, so no need to stop it.
+
+ """
+ self._listener.play()
+ while True:
+ time.sleep(0.001)
+
+OscListenerLock = threading.Lock()
+
+class OscListener(threading.Thread):
+ """
+ Self-contained OSC listener thread.
+
+ This object allows to setup an OSC server that is independent
+ of the audio server (mainly to be able to receive OSC data even
+ when the audio server is stopped).
+
+ :Parent: threadind.Thread
+
+ :Args:
+
+ function : Python function (can't be a list)
+ Function that will be called when a new OSC event is available.
+ This function is called with the incoming address and values as
+ arguments. The signature of the function must be:
+
+ def myfunc(address, *args)
+
+ port : int, optional
+ The OSC port on which the values are received. Defaults to 9000.
+
+ >>> s = Server().boot()
+ >>> def call(address, *args):
+ ... print address, args
+ >>> listen = OscListener(call, 9901)
+ >>> listen.start()
+
+ """
+ def __init__(self, function, port=9000):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self._function = WeakMethod(function)
+ self._port = port
+ self._listener = OscListener_base(self._oscrecv, self._port)
+
+ def _oscrecv(self, address, *args):
+ with OscListenerLock:
+ self._function(address, *args)
+
+ def run(self):
+ """
+ Starts the process. The thread runs as daemon, so no need to stop it.
+
+ """
+ while True:
+ self._listener.get()
+ time.sleep(0.001)
diff --git a/pyolib/opensndctrl.py b/pyolib/opensndctrl.py
index 163cd94..6df3d97 100644
--- a/pyolib/opensndctrl.py
+++ b/pyolib/opensndctrl.py
@@ -559,6 +559,7 @@ class OscDataReceive(PyoObject):
path, lmax = convertArgsToLists(path)
for p in path:
if p not in self._address:
+ self._address.append(p)
self._base_objs[0].addAddress(p)
def delAddress(self, path):
diff --git a/pyolib/server.py b/pyolib/server.py
index 148da73..8f211b1 100644
--- a/pyolib/server.py
+++ b/pyolib/server.py
@@ -55,7 +55,7 @@ class Server(object):
duplex : int {0, 1}, optional
Input - output mode. 0 is output only and 1 is both ways.
Defaults to 1.
- audio : string {'portaudio', 'pa', 'jack', 'coreaudio', 'offline', 'offline_nb}, optional
+ audio : string {'portaudio', 'pa', 'jack', 'coreaudio', 'offline', 'offline_nb', 'embedded'}, optional
Audio backend to use. 'pa' is equivalent to 'portaudio'. Default is 'portaudio'.
'offline' save the audio output in a soundfile as fast as possible in blocking mode,
@@ -842,6 +842,13 @@ class Server(object):
"""
return self._server.getIsBooted()
+ def deactivateMidi(self):
+ """
+ Deactivate Midi callback. Must be called before the start() method.
+
+ """
+ self._server.deactivateMidi()
+
def getMidiActive(self):
"""
Returns 1 if Midi callback is active, otherwise returns 0.
diff --git a/setup.py b/setup.py
index 2f2c75f..873ce31 100644
--- a/setup.py
+++ b/setup.py
@@ -66,7 +66,7 @@ if sys.platform == "darwin":
macros.append(('_OSX_', None))
path = 'src/engine/'
-files = ['pyomodule.c', 'servermodule.c', 'pvstreammodule.c', 'streammodule.c', 'dummymodule.c',
+files = ['pyomodule.c', 'listenermodule.c', 'servermodule.c', 'pvstreammodule.c', 'streammodule.c', 'dummymodule.c',
'mixmodule.c', 'inputfadermodule.c', 'interpolation.c', 'fft.c', "wind.c"]
source_files = [path + f for f in files]
diff --git a/src/engine/listenermodule.c b/src/engine/listenermodule.c
new file mode 100644
index 0000000..0a45024
--- /dev/null
+++ b/src/engine/listenermodule.c
@@ -0,0 +1,478 @@
+/**************************************************************************
+ * Copyright 2009-2015 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo 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 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo 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 pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include <Python.h>
+#include "structmember.h"
+#include <math.h>
+#include "pyomodule.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "lo/lo.h"
+
+static void error(int num, const char *msg, const char *path)
+{
+ printf("liblo server error %d in path %s: %s\n", num, path, msg);
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *osccallable;
+ lo_server osc_server;
+ int oscport;
+} OscListener;
+
+static PyObject *
+OscListener_get(OscListener *self)
+{
+ while (lo_server_recv_noblock(self->osc_server, 0) != 0) {};
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+int process_osc(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ OscListener *server = (OscListener *)user_data;
+ PyObject *tup;
+ lo_blob *blob = NULL;
+ char *blobdata = NULL;
+ uint32_t blobsize = 0;
+ PyObject *charlist = NULL;
+ tup = PyTuple_New(argc+1);
+ int i, j = 0;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ PyTuple_SET_ITEM(tup, 0, PyString_FromString(path));
+ for (i=0; i<argc; i++) {
+ switch (types[i]) {
+ case LO_INT32:
+ PyTuple_SET_ITEM(tup, i+1, PyInt_FromLong(argv[i]->i));
+ break;
+ case LO_INT64:
+ PyTuple_SET_ITEM(tup, i+1, PyLong_FromLong(argv[i]->h));
+ break;
+ case LO_FLOAT:
+ PyTuple_SET_ITEM(tup, i+1, PyFloat_FromDouble(argv[i]->f));
+ break;
+ case LO_DOUBLE:
+ PyTuple_SET_ITEM(tup, i+1, PyFloat_FromDouble(argv[i]->d));
+ break;
+ case LO_STRING:
+ PyTuple_SET_ITEM(tup, i+1, PyString_FromString(&argv[i]->s));
+ break;
+ case LO_CHAR:
+ PyTuple_SET_ITEM(tup, i+1, PyString_FromFormat("%c", argv[i]->c));
+ break;
+ case LO_BLOB:
+ blob = (lo_blob)argv[i];
+ blobsize = lo_blob_datasize(blob);
+ blobdata = lo_blob_dataptr(blob);
+ charlist = PyList_New(blobsize);
+ for (j=0; j<blobsize; j++) {
+ PyList_SET_ITEM(charlist, j, PyString_FromFormat("%c", blobdata[j]));
+ }
+ PyTuple_SET_ITEM(tup, i+1, charlist);
+ break;
+ case LO_MIDI:
+ charlist = PyList_New(4);
+ for (j=0; j<4; j++) {
+ PyList_SET_ITEM(charlist, j, PyInt_FromLong(argv[i]->m[j]));
+ }
+ PyTuple_SET_ITEM(tup, i+1, charlist);
+ break;
+ case LO_NIL:
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(tup, i+1, Py_None);
+ break;
+ case LO_TRUE:
+ Py_INCREF(Py_True);
+ PyTuple_SET_ITEM(tup, i+1, Py_True);
+ break;
+ case LO_FALSE:
+ Py_INCREF(Py_False);
+ PyTuple_SET_ITEM(tup, i+1, Py_False);
+ break;
+ default:
+ break;
+ }
+ }
+ PyObject_Call((PyObject *)server->osccallable, tup, NULL);
+ PyGILState_Release(s);
+ Py_XDECREF(tup);
+
+ return 0;
+}
+
+static int
+OscListener_traverse(OscListener *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->osccallable);
+ return 0;
+}
+
+static int
+OscListener_clear(OscListener *self)
+{
+ Py_CLEAR(self->osccallable);
+ return 0;
+}
+
+static void
+OscListener_dealloc(OscListener* self)
+{
+ lo_server_free(self->osc_server);
+ OscListener_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+OscListener_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ char buf[20];
+ PyObject *osccalltmp=NULL;
+ OscListener *self;
+
+ self = (OscListener *)type->tp_alloc(type, 0);
+
+ static char *kwlist[] = {"osccallable", "port", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &osccalltmp, &self->oscport))
+ Py_RETURN_NONE;
+
+ if (osccalltmp) {
+ PyObject_CallMethod((PyObject *)self, "setOscFunction", "O", osccalltmp);
+ }
+
+ sprintf(buf, "%i", self->oscport);
+ self->osc_server = lo_server_new(buf, error);
+ lo_server_add_method(self->osc_server, NULL, NULL, process_osc, (void *)self);
+
+ return (PyObject *)self;
+}
+
+static PyObject *
+OscListener_setOscFunction(OscListener *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg == Py_None) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (! PyCallable_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "The callable attribute must be a valid Python function.");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_XDECREF(self->osccallable);
+ Py_INCREF(tmp);
+ self->osccallable = tmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef OscListener_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef OscListener_methods[] = {
+ {"get", (PyCFunction)OscListener_get, METH_NOARGS, "Check for new osc messages."},
+ {"setOscFunction", (PyCFunction)OscListener_setOscFunction, METH_O, "Sets the function to be called."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject OscListenerType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.OscListener_base", /*tp_name*/
+ sizeof(OscListener), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)OscListener_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "OscListener objects. Calls a function with OSC data as arguments.", /* tp_doc */
+ (traverseproc)OscListener_traverse, /* tp_traverse */
+ (inquiry)OscListener_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ OscListener_methods, /* tp_methods */
+ OscListener_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ OscListener_new, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *midicallable;
+ PmStream *midiin[64];
+ int mididev;
+ int midicount;
+ int active;
+} MidiListener;
+
+void process_midi(PtTimestamp timestamp, void *userData)
+{
+ PmError result;
+ PmEvent buffer; /* just one message at a time */
+ int i, status, data1, data2;
+ PyObject *tup = NULL;
+ MidiListener *server = (MidiListener *)userData;
+
+ if (server->active == 0) return;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ do {
+ for (i=0; i<server->midicount; i++) {
+ result = Pm_Poll(server->midiin[i]);
+ if (result) {
+ if (Pm_Read(server->midiin[i], &buffer, 1) == pmBufferOverflow)
+ continue;
+ status = Pm_MessageStatus(buffer.message);
+ data1 = Pm_MessageData1(buffer.message);
+ data2 = Pm_MessageData2(buffer.message);
+ tup = PyTuple_New(3);
+ PyTuple_SetItem(tup, 0, PyInt_FromLong(status));
+ PyTuple_SetItem(tup, 1, PyInt_FromLong(data1));
+ PyTuple_SetItem(tup, 2, PyInt_FromLong(data2));
+ PyObject_Call((PyObject *)server->midicallable, tup, NULL);
+ }
+ }
+ } while (result);
+
+ PyGILState_Release(s);
+ Py_XDECREF(tup);
+}
+
+static int
+MidiListener_traverse(MidiListener *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->midicallable);
+ return 0;
+}
+
+static int
+MidiListener_clear(MidiListener *self)
+{
+ Py_CLEAR(self->midicallable);
+ return 0;
+}
+
+static void
+MidiListener_dealloc(MidiListener* self)
+{
+ if (self->active == 1)
+ PyObject_CallMethod((PyObject *)self, "stop", NULL);
+ MidiListener_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+MidiListener_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *midicalltmp=NULL;
+ MidiListener *self;
+
+ self = (MidiListener *)type->tp_alloc(type, 0);
+
+ self->active = self->midicount = 0;
+ self->mididev = -1;
+
+ static char *kwlist[] = {"midicallable", "mididevice", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &midicalltmp, &self->mididev))
+ Py_RETURN_NONE;
+
+ if (midicalltmp) {
+ PyObject_CallMethod((PyObject *)self, "setMidiFunction", "O", midicalltmp);
+ }
+
+ return (PyObject *)self;
+}
+
+static PyObject * MidiListener_play(MidiListener *self) {
+ int i, num_devices;
+ PmError pmerr;
+
+ /* always start the timer before you start midi */
+ Pt_Start(1, &process_midi, (void *)self);
+
+ pmerr = Pm_Initialize();
+ if (pmerr) {
+ printf("Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
+ }
+
+ num_devices = Pm_CountDevices();
+ if (num_devices > 0) {
+ if (self->mididev < num_devices) {
+ if (self->mididev == -1)
+ self->mididev = Pm_GetDefaultInputDeviceID();
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(self->mididev);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[0], self->mididev, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ printf("Portmidi warning: could not open midi input %d (%s): %s\n",
+ self->mididev, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ self->midicount = 1;
+ }
+ }
+ }
+ }
+ else if (self->mididev >= num_devices) {
+ self->midicount = 0;
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[self->midicount], i, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ printf("Portmidi warning: could not open midi input %d (%s): %s\n",
+ i, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ self->midicount++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (i=0; i<self->midicount; i++) {
+ Pm_SetFilter(self->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
+ }
+ self->active = 1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+static PyObject * MidiListener_stop(MidiListener *self) {
+ int i;
+ Pt_Stop();
+ for (i=0; i<self->midicount; i++) {
+ Pm_Close(self->midiin[i]);
+ }
+ Pm_Terminate();
+ self->active = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+static PyObject *
+MidiListener_setMidiFunction(MidiListener *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (! PyCallable_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "The callable attribute must be a valid Python function.");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_XDECREF(self->midicallable);
+ Py_INCREF(tmp);
+ self->midicallable = tmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef MidiListener_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef MidiListener_methods[] = {
+ {"play", (PyCFunction)MidiListener_play, METH_NOARGS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)MidiListener_stop, METH_NOARGS, "Stops computing."},
+ {"setMidiFunction", (PyCFunction)MidiListener_setMidiFunction, METH_O, "Sets the function to be called."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject MidiListenerType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.MidiListener_base", /*tp_name*/
+ sizeof(MidiListener), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)MidiListener_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "MidiListener objects. Calls a function with midi data as arguments.", /* tp_doc */
+ (traverseproc)MidiListener_traverse, /* tp_traverse */
+ (inquiry)MidiListener_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ MidiListener_methods, /* tp_methods */
+ MidiListener_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ MidiListener_new, /* tp_new */
+};
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index 88b37e4..3278ba5 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -2261,6 +2261,8 @@ init_pyo64(void)
#endif
module_add_object(m, "Server_base", &ServerType);
+ module_add_object(m, "MidiListener_base", &MidiListenerType);
+ module_add_object(m, "OscListener_base", &OscListenerType);
module_add_object(m, "Stream", &StreamType);
module_add_object(m, "TriggerStream", &TriggerStreamType);
module_add_object(m, "PVStream", &PVStreamType);
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index 26fdb7d..1cbdb51 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -1581,6 +1581,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return Py_False;
}
+ /* TODO: Need some testing to validate that there is no conflict when more than one server are running at the same time. */
+ /*
if (strcmp(audioType, "embedded") != 0)
{
if (PyServer_get_server() != NULL) {
@@ -1588,6 +1590,7 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
}
}
+ */
/* find the first free serverID */
for(serverID = 0; serverID < MAX_NBR_SERVER; serverID++){
@@ -1623,6 +1626,7 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->midiout_count = 0;
self->midi_input = -1;
self->midi_output = -1;
+ self->midiActive = 1;
self->amp = self->resetAmp = 1.;
self->currentAmp = self->lastAmp = 0.;
self->withGUI = 0;
@@ -1781,6 +1785,14 @@ Server_setMidiOutputDevice(Server *self, PyObject *arg)
}
static PyObject *
+Server_deactivateMidi(Server *self)
+{
+ self->midiActive = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
Server_setSamplingRate(Server *self, PyObject *arg)
{
if (self->server_booted) {
@@ -2081,9 +2093,14 @@ int
Server_pm_init(Server *self)
{
int i = 0;
- /* Initializing MIDI */
PmError pmerr;
+ if (self->midiActive == 0) {
+ self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
+ return 0;
+ }
+
pmerr = Pm_Initialize();
if (pmerr) {
Server_warning(self, "Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
@@ -2901,7 +2918,7 @@ static PyObject *
Server_setServer(Server *self)
{
serverID = self->thisServerID;
- /* Should return a more conventional signal, like True or False */
+ /* TODO: Should return a more conventional signal, like True or False */
return PyString_FromString("Server set");
}
@@ -2969,6 +2986,7 @@ static PyMethodDef Server_methods[] = {
{"setInOutDevice", (PyCFunction)Server_setInOutDevice, METH_O, "Sets both audio input and output device."},
{"setMidiInputDevice", (PyCFunction)Server_setMidiInputDevice, METH_O, "Sets MIDI input device."},
{"setMidiOutputDevice", (PyCFunction)Server_setMidiOutputDevice, METH_O, "Sets MIDI output device."},
+ {"deactivateMidi", (PyCFunction)Server_deactivateMidi, METH_NOARGS, "Deactivates midi callback."},
{"setSamplingRate", (PyCFunction)Server_setSamplingRate, METH_O, "Sets the server's sampling rate."},
{"setBufferSize", (PyCFunction)Server_setBufferSize, METH_O, "Sets the server's buffer size."},
{"setNchnls", (PyCFunction)Server_setNchnls, METH_O, "Sets the server's number of output/input channels."},
diff --git a/src/objects/oscmodule.c b/src/objects/oscmodule.c
index e40c8cc..0cf9f58 100644
--- a/src/objects/oscmodule.c
+++ b/src/objects/oscmodule.c
@@ -27,7 +27,7 @@
#include "dummymodule.h"
#include "lo/lo.h"
-void error(int num, const char *msg, const char *path)
+static void error(int num, const char *msg, const char *path)
{
printf("liblo server error %d in path %s: %s\n", num, path, msg);
}
diff --git a/utils/E-Pyo.py b/utils/E-Pyo.py
index 87d556a..011ffad 100755
--- a/utils/E-Pyo.py
+++ b/utils/E-Pyo.py
@@ -2960,6 +2960,9 @@ class MainFrame(wx.Frame):
for file in lines:
self.submenu2.Append(subId2, toSysEncoding(file))
subId2 += 1
+ if subId2 > 2000:
+ for i in range(2000, subId2):
+ self.Bind(wx.EVT_MENU, self.openRecent, id=i)
def openRecent(self, event):
menu = self.GetMenuBar()
@@ -4570,7 +4573,7 @@ class Editor(stc.StyledTextCtrl):
# for i in range(self.GetLineCount()):
# pos = self.GetLineEndPosition(i)
# if self.GetCharAt(pos-1) != 172:
- # self.InsertTextUTF8(pos, "¬")
+ # self.InsertTextUTF8(pos, "¬")
self.moveMarkers()
self.checkScrollbar()
self.OnModified()
--
python-pyo packaging
More information about the pkg-multimedia-commits
mailing list